@@ -6,11 +6,19 @@ use proc_macro2::{Group, Ident, Punct, Spacing, TokenTree};
66use quote:: quote;
77use std:: collections:: HashSet ;
88use syn:: parse:: { Parse , ParseStream } ;
9- use syn:: { Block , Error , ExprClosure , Pat , Result , Stmt , Token , parse_macro_input} ;
9+ use syn:: punctuated:: Punctuated ;
10+ use syn:: {
11+ Block , Error , ExprClosure , FieldValue , Pat , Result , Stmt , Token , braced, parse_macro_input,
12+ } ;
13+
14+ type CaptureInits = Punctuated < FieldValue , Token ! [ , ] > ;
1015
1116struct Lambda {
1217 captures : Block ,
1318 closure : ExprClosure ,
19+ copy_from : Option < CaptureInits > ,
20+ move_from : Option < CaptureInits > ,
21+ destroy : Option < proc_macro2:: TokenStream > ,
1422}
1523
1624impl Parse for Lambda {
@@ -19,7 +27,37 @@ impl Parse for Lambda {
1927 input. parse :: < Token ! [ , ] > ( ) ?;
2028 let closure = input. parse ( ) ?;
2129 input. parse :: < Option < Token ! [ , ] > > ( ) ?;
22- Ok ( Lambda { captures, closure } )
30+ let mut copy_from = None ;
31+ let mut move_from = None ;
32+ let mut destroy = None ;
33+ while !input. is_empty ( ) {
34+ let name: Ident = input. parse ( ) ?;
35+ if name == "destroy" {
36+ input. parse :: < Token ! [ =] > ( ) ?;
37+ }
38+ let body;
39+ braced ! ( body in input) ;
40+ if name == "copy_from" {
41+ copy_from = Some ( body. parse_terminated ( FieldValue :: parse, Token ! [ , ] ) ?) ;
42+ } else if name == "move_from" {
43+ move_from = Some ( body. parse_terminated ( FieldValue :: parse, Token ! [ , ] ) ?) ;
44+ } else if name == "destroy" {
45+ destroy = Some ( body. parse ( ) ?) ;
46+ } else {
47+ return Err ( Error :: new (
48+ name. span ( ) ,
49+ "expected `copy_from`, `move_from` or `destroy`" ,
50+ ) ) ;
51+ }
52+ input. parse :: < Option < Token ! [ , ] > > ( ) ?;
53+ }
54+ Ok ( Lambda {
55+ captures,
56+ closure,
57+ copy_from,
58+ move_from,
59+ destroy,
60+ } )
2361 }
2462}
2563
@@ -115,6 +153,29 @@ fn rewrite_captures(
115153 Ok ( out. into_iter ( ) . collect ( ) )
116154}
117155
156+ fn expand_constructor (
157+ inits : & Option < CaptureInits > ,
158+ names : & HashSet < String > ,
159+ is_unsafe : bool ,
160+ ) -> Result < proc_macro2:: TokenStream > {
161+ let Some ( inits) = inits else {
162+ return Ok ( quote ! { unreachable!( "the lambda has no such constructor" ) } ) ;
163+ } ;
164+ let mut fields = Vec :: new ( ) ;
165+ for init in inits {
166+ let member = & init. member ;
167+ let expr = & init. expr ;
168+ let expr = rewrite_captures ( quote ! { #expr } , names, false ) ?;
169+ fields. push ( quote ! { #member: #expr } ) ;
170+ }
171+ let body = quote ! { __Lambda { #( #fields, ) * } } ;
172+ Ok ( if is_unsafe {
173+ quote ! { unsafe { #body } }
174+ } else {
175+ body
176+ } )
177+ }
178+
118179fn expand_lambda ( lambda : Lambda , is_unsafe : bool ) -> Result < proc_macro2:: TokenStream > {
119180 let mut names = Vec :: new ( ) ;
120181 let mut types = Vec :: new ( ) ;
@@ -151,14 +212,23 @@ fn expand_lambda(lambda: Lambda, is_unsafe: bool) -> Result<proc_macro2::TokenSt
151212 let body = & lambda. closure . body ;
152213 let captured = names. iter ( ) . map ( |name| name. to_string ( ) ) . collect ( ) ;
153214 let body = rewrite_captures ( quote ! { #body } , & captured, false ) ?;
154- let ( receiver, body, constructor) = if is_unsafe {
215+ let copy_from = expand_constructor ( & lambda. copy_from , & captured, is_unsafe) ?;
216+ let move_from = expand_constructor ( & lambda. move_from , & captured, is_unsafe) ?;
217+ let destroy = & lambda. destroy ;
218+ let ( receiver, body, destroy, constructor) = if is_unsafe {
155219 (
156220 quote ! { & mut self } ,
157221 quote ! { unsafe { #body } } ,
222+ quote ! { unsafe { #destroy } } ,
158223 quote ! { from_lambda_unsafe } ,
159224 )
160225 } else {
161- ( quote ! { & self } , body, quote ! { from_lambda } )
226+ (
227+ quote ! { & self } ,
228+ body,
229+ quote ! { #destroy } ,
230+ quote ! { from_lambda } ,
231+ )
162232 } ;
163233
164234 Ok ( quote ! { {
@@ -170,10 +240,25 @@ fn expand_lambda(lambda: Lambda, is_unsafe: bool) -> Result<proc_macro2::TokenSt
170240 fn call( #receiver #( , #params) * ) #output {
171241 #body
172242 }
243+ #[ allow( unused_unsafe) ]
244+ fn copy_from( #receiver) -> Self {
245+ #copy_from
246+ }
247+ #[ allow( unused_unsafe) ]
248+ fn move_from( #receiver) -> Self {
249+ #move_from
250+ }
251+ #[ allow( unused_unsafe) ]
252+ fn destroy( #receiver) {
253+ #destroy
254+ }
173255 }
174256 :: libcc2rs:: FnPtr :: <fn ( #( #param_types) , * ) #output>:: #constructor(
175257 __Lambda { #( #names: #inits, ) * } ,
176258 __Lambda:: call,
259+ __Lambda:: copy_from,
260+ __Lambda:: move_from,
261+ __Lambda:: destroy,
177262 )
178263 } } )
179264}
0 commit comments