@@ -9,17 +9,38 @@ use syn::parse::{Parse, ParseStream};
99use syn:: { Block , Error , ExprClosure , Pat , Result , Stmt , Token , parse_macro_input} ;
1010
1111struct Lambda {
12+ is_generic : bool ,
1213 captures : Block ,
13- closure : ExprClosure ,
14+ closures : Vec < ExprClosure > ,
1415}
1516
1617impl Parse for Lambda {
1718 fn parse ( input : ParseStream ) -> Result < Self > {
19+ let is_generic = input. peek ( syn:: Ident ) ;
20+ if is_generic {
21+ let marker: Ident = input. parse ( ) ?;
22+ if marker != "Generic" {
23+ return Err ( Error :: new ( marker. span ( ) , "expected `Generic`" ) ) ;
24+ }
25+ input. parse :: < Token ! [ , ] > ( ) ?;
26+ }
1827 let captures = input. parse ( ) ?;
1928 input. parse :: < Token ! [ , ] > ( ) ?;
20- let closure = input. parse ( ) ?;
21- input. parse :: < Option < Token ! [ , ] > > ( ) ?;
22- Ok ( Lambda { captures, closure } )
29+ let mut closures = vec ! [ input. parse( ) ?] ;
30+ while input. parse :: < Option < Token ! [ , ] > > ( ) ?. is_some ( ) && !input. is_empty ( ) {
31+ closures. push ( input. parse ( ) ?) ;
32+ }
33+ if !is_generic && closures. len ( ) != 1 {
34+ return Err ( Error :: new_spanned (
35+ & closures[ 1 ] ,
36+ "a non-generic lambda has one closure" ,
37+ ) ) ;
38+ }
39+ Ok ( Lambda {
40+ is_generic,
41+ captures,
42+ closures,
43+ } )
2344 }
2445}
2546
@@ -137,28 +158,49 @@ fn expand_lambda(lambda: Lambda, is_unsafe: bool) -> Result<proc_macro2::TokenSt
137158 inits. push ( & init. expr ) ;
138159 }
139160
140- let mut params = Vec :: new ( ) ;
141- let mut param_types = Vec :: new ( ) ;
142- for input in & lambda. closure . inputs {
143- let Pat :: Type ( pat) = input else {
144- return Err ( Error :: new_spanned ( input, "expected a typed parameter" ) ) ;
161+ let captured: HashSet < String > = names. iter ( ) . map ( |name| name. to_string ( ) ) . collect ( ) ;
162+ let mut calls = Vec :: new ( ) ;
163+ let mut sigs = Vec :: new ( ) ;
164+ let mut call_names = Vec :: new ( ) ;
165+ for ( i, closure) in lambda. closures . iter ( ) . enumerate ( ) {
166+ let mut params = Vec :: new ( ) ;
167+ let mut param_types = Vec :: new ( ) ;
168+ for input in & closure. inputs {
169+ let Pat :: Type ( pat) = input else {
170+ return Err ( Error :: new_spanned ( input, "expected a typed parameter" ) ) ;
171+ } ;
172+ params. push ( pat) ;
173+ param_types. push ( & pat. ty ) ;
174+ }
175+ let output = & closure. output ;
176+ let body = & closure. body ;
177+ let body = rewrite_captures ( quote ! { #body } , & captured, false ) ?;
178+ let ( receiver, body) = if is_unsafe {
179+ ( quote ! { & mut self } , quote ! { unsafe { #body } } )
180+ } else {
181+ ( quote ! { & self } , body)
145182 } ;
146- params. push ( pat) ;
147- param_types. push ( & pat. ty ) ;
183+ let call_name = if lambda. is_generic {
184+ Ident :: new ( & format ! ( "call_{i}" ) , proc_macro2:: Span :: call_site ( ) )
185+ } else {
186+ Ident :: new ( "call" , proc_macro2:: Span :: call_site ( ) )
187+ } ;
188+ calls. push ( quote ! {
189+ #[ allow( unused_unsafe, clippy:: too_many_arguments) ]
190+ fn #call_name( #receiver #( , #params) * ) #output {
191+ #body
192+ }
193+ } ) ;
194+ sigs. push ( quote ! { fn ( #( #param_types) , * ) #output } ) ;
195+ call_names. push ( ( call_name, closure. inputs . len ( ) ) ) ;
148196 }
149-
150- let output = & lambda. closure . output ;
151- let body = & lambda. closure . body ;
152- let captured = names. iter ( ) . map ( |name| name. to_string ( ) ) . collect ( ) ;
153- let body = rewrite_captures ( quote ! { #body } , & captured, false ) ?;
154197 // The copy and move constructors of the lambda copy and move each
155198 // capture, and its destructor destroys them in reverse order, as chosen
156199 // from their types by the traits in libcc2rs::__capture.
157200 let reversed: Vec < _ > = names. iter ( ) . rev ( ) . collect ( ) ;
158- let ( receiver, body , destroy, constructor, copy_from, move_from) = if is_unsafe {
201+ let ( receiver, destroy, constructor, copy_from, move_from) = if is_unsafe {
159202 (
160203 quote ! { & mut self } ,
161- quote ! { unsafe { #body } } ,
162204 quote ! {
163205 use :: libcc2rs:: __capture:: { DestroyNoneUnsafe as _, DestroyWithDtorUnsafe as _} ;
164206 unsafe {
@@ -192,7 +234,6 @@ fn expand_lambda(lambda: Lambda, is_unsafe: bool) -> Result<proc_macro2::TokenSt
192234 } else {
193235 (
194236 quote ! { & self } ,
195- body,
196237 quote ! {
197238 use :: libcc2rs:: __capture:: {
198239 DestroyElems as _, DestroyNone as _, DestroyWithDtor as _,
@@ -217,15 +258,12 @@ fn expand_lambda(lambda: Lambda, is_unsafe: bool) -> Result<proc_macro2::TokenSt
217258 )
218259 } ;
219260
220- Ok ( quote ! { {
261+ let lambda_struct = quote ! {
221262 struct __Lambda {
222263 #( #names: #types, ) *
223264 }
224265 impl __Lambda {
225- #[ allow( unused_unsafe, clippy:: too_many_arguments) ]
226- fn call( #receiver #( , #params) * ) #output {
227- #body
228- }
266+ #( #calls) *
229267 #[ allow( unused_imports, unused_unsafe) ]
230268 fn copy_from( #receiver) -> Self {
231269 #copy_from
@@ -239,12 +277,76 @@ fn expand_lambda(lambda: Lambda, is_unsafe: bool) -> Result<proc_macro2::TokenSt
239277 #destroy
240278 }
241279 }
242- :: libcc2rs:: FnPtr :: <fn ( #( #param_types) , * ) #output>:: #constructor(
243- __Lambda { #( #names: #inits, ) * } ,
244- __Lambda:: call,
245- __Lambda:: copy_from,
246- __Lambda:: move_from,
247- __Lambda:: destroy,
280+ } ;
281+ let lambda_init = quote ! { __Lambda { #( #names: #inits, ) * } } ;
282+
283+ if !lambda. is_generic {
284+ let sig = & sigs[ 0 ] ;
285+ return Ok ( quote ! { {
286+ #lambda_struct
287+ :: libcc2rs:: FnPtr :: <#sig>:: #constructor(
288+ #lambda_init,
289+ __Lambda:: call,
290+ __Lambda:: copy_from,
291+ __Lambda:: move_from,
292+ __Lambda:: destroy,
293+ )
294+ } } ) ;
295+ }
296+
297+ let mut specs = Vec :: new ( ) ;
298+ for ( sig, ( call_name, arity) ) in sigs. iter ( ) . zip ( & call_names) {
299+ let args: Vec < Ident > = ( 0 ..* arity)
300+ . map ( |i| Ident :: new ( & format ! ( "__a{i}" ) , proc_macro2:: Span :: call_site ( ) ) )
301+ . collect ( ) ;
302+ let call = if is_unsafe {
303+ quote ! {
304+ |__l: & mut :: std:: rc:: Rc <:: std:: cell:: UnsafeCell <__Lambda>> #( , #args) * | {
305+ unsafe { & mut * __l. get( ) } . #call_name( #( #args) , * )
306+ }
307+ }
308+ } else {
309+ quote ! {
310+ |__l: & :: std:: rc:: Rc <__Lambda> #( , #args) * | __l. #call_name( #( #args) , * )
311+ }
312+ } ;
313+ specs. push ( quote ! {
314+ :: std:: rc:: Rc :: new( :: libcc2rs:: FnPtr :: <#sig>:: #constructor(
315+ :: std:: rc:: Rc :: clone( __l) ,
316+ #call,
317+ |__l| :: std:: rc:: Rc :: clone( __l) ,
318+ |__l| :: std:: rc:: Rc :: clone( __l) ,
319+ |_| { } ,
320+ ) ) as :: std:: rc:: Rc <dyn :: std:: any:: Any >
321+ } ) ;
322+ }
323+ let ( shared, copy_from, move_from, destroy) = if is_unsafe {
324+ (
325+ quote ! { :: std:: rc:: Rc :: new( :: std:: cell:: UnsafeCell :: new( #lambda_init) ) } ,
326+ quote ! { |__l| :: std:: rc:: Rc :: new( :: std:: cell:: UnsafeCell :: new(
327+ unsafe { & mut * __l. get( ) } . copy_from( )
328+ ) ) } ,
329+ quote ! { |__l| :: std:: rc:: Rc :: new( :: std:: cell:: UnsafeCell :: new(
330+ unsafe { & mut * __l. get( ) } . move_from( )
331+ ) ) } ,
332+ quote ! { |__l| unsafe { & mut * __l. get( ) } . destroy( ) } ,
333+ )
334+ } else {
335+ (
336+ quote ! { :: std:: rc:: Rc :: new( #lambda_init) } ,
337+ quote ! { |__l| :: std:: rc:: Rc :: new( __l. copy_from( ) ) } ,
338+ quote ! { |__l| :: std:: rc:: Rc :: new( __l. move_from( ) ) } ,
339+ quote ! { |__l| __l. destroy( ) } ,
340+ )
341+ } ;
342+ Ok ( quote ! { {
343+ #lambda_struct
344+ :: libcc2rs:: FnPtr :: <:: libcc2rs:: Generic >:: from_generic_lambda(
345+ #shared,
346+ |__l| vec![ #( #specs) , * ] ,
347+ #copy_from,
348+ #move_from,
349+ #destroy,
248350 )
249351 } } )
250352}
0 commit comments