@@ -3,6 +3,7 @@ use crate::syntax::attrs::{self, OtherAttrs};
33use crate :: syntax:: cfg:: { CfgExpr , ComputedCfg } ;
44use crate :: syntax:: file:: Module ;
55use crate :: syntax:: instantiate:: { ImplKey , NamedImplKey } ;
6+ use crate :: syntax:: map:: OrderedMap ;
67use crate :: syntax:: message:: Message ;
78use crate :: syntax:: namespace:: Namespace ;
89use crate :: syntax:: qualified:: QualifiedName ;
@@ -70,6 +71,7 @@ fn expand(ffi: Module, doc: Doc, attrs: OtherAttrs, apis: &[Api], types: &Types)
7071 Api :: Include ( _) | Api :: Impl ( _) => { }
7172 Api :: Struct ( strct) => {
7273 expanded. extend ( expand_struct ( strct) ) ;
74+ expanded. extend ( expand_associated_functions ( & strct. name . rust , types) ) ;
7375 hidden. extend ( expand_struct_nonempty ( strct) ) ;
7476 hidden. extend ( expand_struct_operators ( strct) ) ;
7577 forbid. extend ( expand_struct_forbid_drop ( strct) ) ;
@@ -81,19 +83,24 @@ fn expand(ffi: Module, doc: Doc, attrs: OtherAttrs, apis: &[Api], types: &Types)
8183 hidden. extend ( expand_extern_shared_struct ( ety, & ffi) ) ;
8284 } else if !types. enums . contains_key ( ident) {
8385 expanded. extend ( expand_cxx_type ( ety) ) ;
86+ expanded. extend ( expand_associated_functions ( & ety. name . rust , types) ) ;
8487 hidden. extend ( expand_cxx_type_assert_pinned ( ety, types) ) ;
8588 }
8689 }
8790 Api :: CxxFunction ( efn) => {
88- expanded. extend ( expand_cxx_function_shim ( efn, types) ) ;
91+ if efn. self_type ( ) . is_none ( ) {
92+ expanded. extend ( expand_cxx_function_shim ( efn, types) ) ;
93+ }
8994 }
9095 Api :: RustType ( ety) => {
9196 expanded. extend ( expand_rust_type_impl ( ety) ) ;
97+ expanded. extend ( expand_associated_functions ( & ety. name . rust , types) ) ;
9298 hidden. extend ( expand_rust_type_layout ( ety, types) ) ;
9399 }
94100 Api :: RustFunction ( efn) => hidden. extend ( expand_rust_function_shim ( efn, types) ) ,
95101 Api :: TypeAlias ( alias) => {
96102 expanded. extend ( expand_type_alias ( alias) ) ;
103+ expanded. extend ( expand_associated_functions ( & alias. name . rust , types) ) ;
97104 hidden. extend ( expand_type_alias_verify ( alias, types) ) ;
98105 }
99106 }
@@ -586,6 +593,85 @@ fn expand_extern_shared_struct(ety: &ExternType, ffi: &Module) -> TokenStream {
586593 }
587594}
588595
596+ fn expand_associated_functions ( self_type : & Ident , types : & Types ) -> TokenStream {
597+ let Some ( functions) = types. associated_fn . get ( self_type) else {
598+ return TokenStream :: new ( ) ;
599+ } ;
600+
601+ let resolve = types. resolve ( self_type) ;
602+ let self_type_cfg_attrs = resolve. attrs . cfg ( ) ;
603+ let elided_lifetime = Lifetime :: new ( "'_" , Span :: call_site ( ) ) ;
604+ let mut group_by_lifetimes = OrderedMap :: new ( ) ;
605+ let mut tokens = TokenStream :: new ( ) ;
606+
607+ for efn in functions {
608+ match efn. lang {
609+ Lang :: Cxx | Lang :: CxxUnwind => { }
610+ Lang :: Rust => continue ,
611+ }
612+ let mut impl_lifetimes = Vec :: new ( ) ;
613+ let mut self_type_lifetimes = Vec :: new ( ) ;
614+ let self_lt_token;
615+ let self_gt_token;
616+ match & efn. kind {
617+ FnKind :: Method ( receiver) if receiver. ty . generics . lt_token . is_some ( ) => {
618+ for lifetime in & receiver. ty . generics . lifetimes {
619+ if lifetime. ident != "_"
620+ && efn
621+ . generics
622+ . lifetimes ( )
623+ . any ( |param| param. lifetime == * lifetime)
624+ {
625+ impl_lifetimes. push ( lifetime) ;
626+ }
627+ self_type_lifetimes. push ( lifetime) ;
628+ }
629+ self_lt_token = receiver. ty . generics . lt_token ;
630+ self_gt_token = receiver. ty . generics . gt_token ;
631+ }
632+ _ => {
633+ self_type_lifetimes. resize ( resolve. generics . lifetimes . len ( ) , & elided_lifetime) ;
634+ self_lt_token = resolve. generics . lt_token ;
635+ self_gt_token = resolve. generics . gt_token ;
636+ }
637+ }
638+ if efn. undeclared_lifetimes ( ) . is_empty ( )
639+ && self_type_lifetimes. len ( ) == resolve. generics . lifetimes . len ( )
640+ {
641+ group_by_lifetimes
642+ . entry ( ( impl_lifetimes, self_type_lifetimes) )
643+ . or_insert_with ( Vec :: new)
644+ . push ( efn) ;
645+ } else {
646+ let impl_token = Token ! [ impl ] ( efn. name . rust . span ( ) ) ;
647+ let impl_lt_token = efn. generics . lt_token ;
648+ let impl_gt_token = efn. generics . gt_token ;
649+ let self_type = efn. self_type ( ) . unwrap ( ) ;
650+ let function = expand_cxx_function_shim ( efn, types) ;
651+ tokens. extend ( quote ! {
652+ #self_type_cfg_attrs
653+ #impl_token #impl_lt_token #( #impl_lifetimes) , * #impl_gt_token #self_type #self_lt_token #( #self_type_lifetimes) , * #self_gt_token {
654+ #function
655+ }
656+ } ) ;
657+ }
658+ }
659+
660+ for ( ( impl_lifetimes, self_type_lifetimes) , functions) in & group_by_lifetimes {
661+ let functions = functions
662+ . iter ( )
663+ . map ( |efn| expand_cxx_function_shim ( efn, types) ) ;
664+ tokens. extend ( quote ! {
665+ #self_type_cfg_attrs
666+ impl <#( #impl_lifetimes) , * > #self_type <#( #self_type_lifetimes) , * > {
667+ #( #functions) *
668+ }
669+ } ) ;
670+ }
671+
672+ tokens
673+ }
674+
589675fn expand_cxx_function_decl ( efn : & ExternFn , types : & Types ) -> TokenStream {
590676 let receiver = efn. receiver ( ) . into_iter ( ) . map ( |receiver| {
591677 if types. is_considered_improper_ctype ( & receiver. ty ) {
@@ -897,7 +983,6 @@ fn expand_cxx_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
897983 Some ( self_type) => {
898984 let elided_generics;
899985 let resolve = types. resolve ( self_type) ;
900- let self_type_cfg_attrs = resolve. attrs . cfg ( ) ;
901986 let self_type_generics = match & efn. kind {
902987 FnKind :: Method ( receiver) if receiver. ty . generics . lt_token . is_some ( ) => {
903988 & receiver. ty . generics
@@ -926,21 +1011,15 @@ fn expand_cxx_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
9261011 self_type_lifetimes. insert ( lifetime) ;
9271012 }
9281013 }
929- let impl_lifetimes = generics
930- . lifetimes ( )
931- . filter ( |param| self_type_lifetimes. contains ( & param. lifetime ) ) ;
9321014 let fn_lifetimes = generics
9331015 . lifetimes ( )
9341016 . filter ( |param| !self_type_lifetimes. contains ( & param. lifetime ) ) ;
9351017 let lt_token = generics. lt_token ;
9361018 let gt_token = generics. gt_token ;
9371019 quote_spanned ! { ident. span( ) =>
938- #self_type_cfg_attrs
939- impl #lt_token #( #impl_lifetimes) , * #gt_token #self_type #self_type_generics {
940- #doc
941- #all_attrs
942- #visibility #unsafety #fn_token #ident #lt_token #( #fn_lifetimes) , * #gt_token #arg_list #ret #fn_body
943- }
1020+ #doc
1021+ #all_attrs
1022+ #visibility #unsafety #fn_token #ident #lt_token #( #fn_lifetimes) , * #gt_token #arg_list #ret #fn_body
9441023 }
9451024 }
9461025 }
0 commit comments