@@ -5,6 +5,7 @@ use super::item::{Item, ItemCanonicalName, ItemId};
5
5
use super :: item_kind:: ItemKind ;
6
6
use super :: int:: IntKind ;
7
7
use super :: module:: Module ;
8
+ use super :: type_collector:: { ItemSet , TypeCollector } ;
8
9
use clang:: { self , Cursor } ;
9
10
use std:: borrow:: { Cow , Borrow } ;
10
11
use std:: collections:: btree_map:: { self , BTreeMap } ;
@@ -772,4 +773,108 @@ impl<'ctx> BindgenContext<'ctx> {
772
773
773
774
self . current_module = previous_id;
774
775
}
776
+
777
+ /// Iterate over all (explicitly or transitively) whitelisted items.
778
+ ///
779
+ /// If no items are explicitly whitelisted, then all items are considered
780
+ /// whitelisted.
781
+ pub fn whitelisted_items < ' me > ( & ' me self ) -> WhitelistedItemsIter < ' me , ' ctx > {
782
+ assert ! ( self . in_codegen_phase( ) ) ;
783
+ assert ! ( self . current_module == self . root_module) ;
784
+
785
+ let roots = self . items ( )
786
+ . filter ( |& ( _, item) | {
787
+ // If nothing is explicitly whitelisted, then everything is fair
788
+ // game.
789
+ if self . options ( ) . whitelisted_types . is_empty ( ) &&
790
+ self . options ( ) . whitelisted_functions . is_empty ( ) &&
791
+ self . options ( ) . whitelisted_vars . is_empty ( ) {
792
+ return true ;
793
+ }
794
+
795
+ let name = item. canonical_name ( self ) ;
796
+ match * item. kind ( ) {
797
+ ItemKind :: Module ( ..) => false ,
798
+ ItemKind :: Function ( _) => self . options ( ) . whitelisted_functions . matches ( & name) ,
799
+ ItemKind :: Var ( _) => self . options ( ) . whitelisted_vars . matches ( & name) ,
800
+ ItemKind :: Type ( ref ty) => {
801
+ if self . options ( ) . whitelisted_types . matches ( & name) {
802
+ return true ;
803
+ }
804
+
805
+ // Unnamed top-level enums are special and we whitelist
806
+ // them via the `whitelisted_vars` filter, since they're
807
+ // effectively top-level constants, and there's no way
808
+ // for them to be referenced consistently.
809
+ if let TypeKind :: Enum ( ref enum_) = * ty. kind ( ) {
810
+ if ty. name ( ) . is_none ( ) &&
811
+ enum_. variants ( ) . iter ( ) . any ( |variant| {
812
+ self . options ( ) . whitelisted_vars . matches ( & variant. name ( ) )
813
+ } ) {
814
+ return true ;
815
+ }
816
+ }
817
+
818
+ false
819
+ }
820
+ }
821
+ } )
822
+ . map ( |( & id, _) | id) ;
823
+
824
+ let seen: ItemSet = roots. collect ( ) ;
825
+ let to_iterate = seen. iter ( ) . cloned ( ) . collect ( ) ;
826
+
827
+ WhitelistedItemsIter {
828
+ ctx : self ,
829
+ seen : seen,
830
+ to_iterate : to_iterate,
831
+ }
832
+ }
833
+ }
834
+
835
+ /// An iterator over whitelisted items.
836
+ ///
837
+ /// See `BindgenContext::whitelisted_items` for more information.
838
+ pub struct WhitelistedItemsIter < ' ctx , ' gen >
839
+ where ' gen : ' ctx
840
+ {
841
+ ctx : & ' ctx BindgenContext < ' gen > ,
842
+
843
+ // The set of whitelisted items we have seen. If you think of traversing
844
+ // whitelisted items like GC tracing, this is the mark bits, and contains
845
+ // both black and gray items.
846
+ seen : ItemSet ,
847
+
848
+ // The set of whitelisted items that we have seen but have yet to iterate
849
+ // over and collect transitive references from. To return to the GC analogy,
850
+ // this is the mark stack, containing the set of gray items which we have
851
+ // not finished tracing yet.
852
+ to_iterate : Vec < ItemId > ,
853
+ }
854
+
855
+ impl < ' ctx , ' gen > Iterator for WhitelistedItemsIter < ' ctx , ' gen >
856
+ where ' gen : ' ctx
857
+ {
858
+ type Item = ItemId ;
859
+
860
+ fn next ( & mut self ) -> Option < Self :: Item > {
861
+ let id = match self . to_iterate . pop ( ) {
862
+ None => return None ,
863
+ Some ( id) => id,
864
+ } ;
865
+
866
+ debug_assert ! ( self . seen. contains( & id) ) ;
867
+
868
+ let mut sub_types = ItemSet :: new ( ) ;
869
+ id. collect_types ( self . ctx , & mut sub_types, & ( ) ) ;
870
+
871
+ for id in sub_types {
872
+ if !self . seen . contains ( & id) {
873
+ self . to_iterate . push ( id) ;
874
+ self . seen . insert ( id) ;
875
+ }
876
+ }
877
+
878
+ return Some ( id) ;
879
+ }
775
880
}
0 commit comments