@@ -12,6 +12,7 @@ use super::item::{Item, ItemCanonicalName, ItemId};
12
12
use super :: item_kind:: ItemKind ;
13
13
use super :: module:: Module ;
14
14
use super :: ty:: { FloatKind , Type , TypeKind } ;
15
+ use super :: type_collector:: { ItemSet , TypeCollector } ;
15
16
use syntax:: ast:: Ident ;
16
17
use syntax:: codemap:: { DUMMY_SP , Span } ;
17
18
use syntax:: ext:: base:: ExtCtxt ;
@@ -814,4 +815,119 @@ impl<'ctx> BindgenContext<'ctx> {
814
815
815
816
self . current_module = previous_id;
816
817
}
818
+
819
+ /// Iterate over all (explicitly or transitively) whitelisted items.
820
+ ///
821
+ /// If no items are explicitly whitelisted, then all items are considered
822
+ /// whitelisted.
823
+ pub fn whitelisted_items < ' me > ( & ' me self )
824
+ -> WhitelistedItemsIter < ' me , ' ctx > {
825
+ assert ! ( self . in_codegen_phase( ) ) ;
826
+ assert ! ( self . current_module == self . root_module) ;
827
+
828
+ let roots = self . items ( )
829
+ . filter ( |& ( _, item) | {
830
+ // If nothing is explicitly whitelisted, then everything is fair
831
+ // game.
832
+ if self . options ( ) . whitelisted_types . is_empty ( ) &&
833
+ self . options ( ) . whitelisted_functions . is_empty ( ) &&
834
+ self . options ( ) . whitelisted_vars . is_empty ( ) {
835
+ return true ;
836
+ }
837
+
838
+ let name = item. canonical_name ( self ) ;
839
+ match * item. kind ( ) {
840
+ ItemKind :: Module ( ..) => false ,
841
+ ItemKind :: Function ( _) => {
842
+ self . options ( ) . whitelisted_functions . matches ( & name)
843
+ }
844
+ ItemKind :: Var ( _) => {
845
+ self . options ( ) . whitelisted_vars . matches ( & name)
846
+ }
847
+ ItemKind :: Type ( ref ty) => {
848
+ if self . options ( ) . whitelisted_types . matches ( & name) {
849
+ return true ;
850
+ }
851
+
852
+ // Unnamed top-level enums are special and we whitelist
853
+ // them via the `whitelisted_vars` filter, since they're
854
+ // effectively top-level constants, and there's no way
855
+ // for them to be referenced consistently.
856
+ if let TypeKind :: Enum ( ref enum_) = * ty. kind ( ) {
857
+ if ty. name ( ) . is_none ( ) &&
858
+ enum_. variants ( ) . iter ( ) . any ( |variant| {
859
+ self . options ( )
860
+ . whitelisted_vars
861
+ . matches ( & variant. name ( ) )
862
+ } ) {
863
+ return true ;
864
+ }
865
+ }
866
+
867
+ false
868
+ }
869
+ }
870
+ } )
871
+ . map ( |( & id, _) | id) ;
872
+
873
+ let seen: ItemSet = roots. collect ( ) ;
874
+
875
+ // The .rev() preserves the expected ordering traversal, resulting in
876
+ // more stable-ish bindgen-generated names for anonymous types (like
877
+ // unions).
878
+ let to_iterate = seen. iter ( ) . cloned ( ) . rev ( ) . collect ( ) ;
879
+
880
+ WhitelistedItemsIter {
881
+ ctx : self ,
882
+ seen : seen,
883
+ to_iterate : to_iterate,
884
+ }
885
+ }
886
+ }
887
+
888
+ /// An iterator over whitelisted items.
889
+ ///
890
+ /// See `BindgenContext::whitelisted_items` for more information.
891
+ pub struct WhitelistedItemsIter < ' ctx , ' gen >
892
+ where ' gen : ' ctx ,
893
+ {
894
+ ctx : & ' ctx BindgenContext < ' gen > ,
895
+
896
+ // The set of whitelisted items we have seen. If you think of traversing
897
+ // whitelisted items like GC tracing, this is the mark bits, and contains
898
+ // both black and gray items.
899
+ seen : ItemSet ,
900
+
901
+ // The set of whitelisted items that we have seen but have yet to iterate
902
+ // over and collect transitive references from. To return to the GC analogy,
903
+ // this is the mark stack, containing the set of gray items which we have
904
+ // not finished tracing yet.
905
+ to_iterate : Vec < ItemId > ,
906
+ }
907
+
908
+ impl < ' ctx , ' gen > Iterator for WhitelistedItemsIter < ' ctx , ' gen >
909
+ where ' gen : ' ctx ,
910
+ {
911
+ type Item = ItemId ;
912
+
913
+ fn next ( & mut self ) -> Option < Self :: Item > {
914
+ let id = match self . to_iterate . pop ( ) {
915
+ None => return None ,
916
+ Some ( id) => id,
917
+ } ;
918
+
919
+ debug_assert ! ( self . seen. contains( & id) ) ;
920
+
921
+ let mut sub_types = ItemSet :: new ( ) ;
922
+ id. collect_types ( self . ctx , & mut sub_types, & ( ) ) ;
923
+
924
+ for id in sub_types {
925
+ if !self . seen . contains ( & id) {
926
+ self . to_iterate . push ( id) ;
927
+ self . seen . insert ( id) ;
928
+ }
929
+ }
930
+
931
+ Some ( id)
932
+ }
817
933
}
0 commit comments