7
7
//! This library provides macros that wrap closures to make them serializable
8
8
//! and debuggable.
9
9
//!
10
- //! See [`serde_closure`](https://docs.rs/serde_closure/ ) for
10
+ //! See [`serde_closure`](https://docs.rs/serde_closure) for
11
11
//! documentation.
12
12
13
- #![ doc( html_root_url = "https://docs.rs/serde_closure_derive/0.2.13" ) ]
14
- #![ feature( proc_macro_diagnostic) ]
13
+ #![ doc( html_root_url = "https://docs.rs/serde_closure_derive/0.2.14" ) ]
15
14
16
15
use proc_macro2:: { Span , TokenStream } ;
17
16
use quote:: { quote, ToTokens } ;
18
17
use std:: { collections:: HashSet , iter, iter:: successors, mem:: take, str} ;
19
18
use syn:: {
20
- parse:: { Parse , ParseStream } , parse2, spanned :: Spanned , token:: Bracket , Arm , Block , Error , Expr , ExprArray , ExprAssign , ExprAssignOp , ExprAsync , ExprAwait , ExprBinary , ExprBlock , ExprBox , ExprBreak , ExprCall , ExprCast , ExprClosure , ExprField , ExprForLoop , ExprGroup , ExprIf , ExprIndex , ExprLet , ExprLoop , ExprMacro , ExprMatch , ExprMethodCall , ExprParen , ExprPath , ExprRange , ExprReference , ExprRepeat , ExprReturn , ExprStruct , ExprTry , ExprTryBlock , ExprTuple , ExprType , ExprUnary , ExprUnsafe , ExprWhile , ExprYield , FieldValue , Ident , Local , Member , Pat , PatBox , PatIdent , PatReference , PatSlice , PatTuple , PatTupleStruct , PatType , Path , PathArguments , PathSegment , Stmt , Type , TypeInfer , TypeReference , UnOp
19
+ parse:: { Parse , ParseStream } , parse2, parse_macro_input , token:: Bracket , visit_mut :: { self , VisitMut } , Arm , AttributeArgs , Block , Error , Expr , ExprArray , ExprAssign , ExprAssignOp , ExprAsync , ExprAwait , ExprBinary , ExprBlock , ExprBox , ExprBreak , ExprCall , ExprCast , ExprClosure , ExprField , ExprForLoop , ExprGroup , ExprIf , ExprIndex , ExprLet , ExprLoop , ExprMacro , ExprMatch , ExprMethodCall , ExprParen , ExprPath , ExprRange , ExprReference , ExprRepeat , ExprReturn , ExprStruct , ExprTry , ExprTryBlock , ExprTuple , ExprType , ExprUnary , ExprUnsafe , ExprWhile , ExprYield , FieldValue , Ident , Item , Lifetime , LifetimeDef , Local , Member , Pat , PatBox , PatIdent , PatReference , PatSlice , PatTuple , PatTupleStruct , PatType , Path , PathArguments , PathSegment , ReturnType , Stmt , TraitBound , Type , TypeInfer , TypeReference , TypeTuple , UnOp
21
20
} ;
22
21
23
22
#[ proc_macro]
@@ -45,6 +44,79 @@ pub fn FnOnce(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
45
44
. into ( )
46
45
}
47
46
47
+ #[ proc_macro_attribute]
48
+ pub fn generalize (
49
+ attr : proc_macro:: TokenStream , item : proc_macro:: TokenStream ,
50
+ ) -> proc_macro:: TokenStream {
51
+ let args: AttributeArgs = parse_macro_input ! ( attr) ;
52
+ assert_eq ! ( args. len( ) , 0 ) ;
53
+ let mut item = match syn:: parse :: < Item > ( item) {
54
+ Err ( err) => return err. to_compile_error ( ) . into ( ) ,
55
+ Ok ( item) => item,
56
+ } ;
57
+ Generalizer . visit_item_mut ( & mut item) ;
58
+ item. into_token_stream ( ) . into ( )
59
+ }
60
+
61
+ struct Generalizer ;
62
+
63
+ impl VisitMut for Generalizer {
64
+ fn visit_trait_bound_mut ( & mut self , i : & mut TraitBound ) {
65
+ if let PathSegment {
66
+ ident,
67
+ arguments : PathArguments :: Parenthesized ( args) ,
68
+ } = i. path . segments . last ( ) . unwrap ( )
69
+ {
70
+ if ident == "FnOnce" || ident == "FnMut" || ident == "Fn" {
71
+ let mut lifetimes = 0 ;
72
+ let mut inputs = args. inputs . clone ( ) ;
73
+ for input in & mut inputs {
74
+ match input {
75
+ Type :: Reference ( TypeReference { lifetime, .. } ) if lifetime. is_none ( ) => {
76
+ * lifetime = Some ( Lifetime :: new (
77
+ & format ! (
78
+ "'__serde_closure_{}" ,
79
+ bijective_base( lifetimes, 26 , alpha_lower)
80
+ ) ,
81
+ Span :: call_site ( ) ,
82
+ ) ) ;
83
+ lifetimes += 1 ;
84
+ }
85
+ _ => ( ) ,
86
+ }
87
+ }
88
+ if !inputs. empty_or_trailing ( ) {
89
+ inputs. push_punct ( Default :: default ( ) ) ;
90
+ }
91
+ let output = match & args. output {
92
+ ReturnType :: Type ( _, type_) => ( & * * type_) . clone ( ) ,
93
+ ReturnType :: Default => Type :: Tuple ( TypeTuple {
94
+ paren_token : Default :: default ( ) ,
95
+ elems : Default :: default ( ) ,
96
+ } ) ,
97
+ } ;
98
+ let empty = syn:: parse2 ( quote ! { for <>} ) . unwrap ( ) ;
99
+ i. lifetimes = Some ( i. lifetimes . clone ( ) . unwrap_or ( empty) ) ;
100
+ i. lifetimes
101
+ . as_mut ( )
102
+ . unwrap ( )
103
+ . lifetimes
104
+ . extend ( ( 0 ..lifetimes) . map ( |i| {
105
+ LifetimeDef :: new ( Lifetime :: new (
106
+ & format ! ( "'__serde_closure_{}" , bijective_base( i, 26 , alpha_lower) ) ,
107
+ Span :: call_site ( ) ,
108
+ ) )
109
+ } ) ) ;
110
+ i. path = syn:: parse2 (
111
+ quote ! { :: serde_closure:: traits:: #ident<( #inputs) , Output = #output> } ,
112
+ )
113
+ . unwrap ( ) ;
114
+ }
115
+ }
116
+ visit_mut:: visit_trait_bound_mut ( self , i)
117
+ }
118
+ }
119
+
48
120
struct Closure {
49
121
env : Option < ExprArray > ,
50
122
closure : ExprClosure ,
@@ -145,12 +217,14 @@ fn impl_fn_once(closure: Closure, kind: Kind) -> Result<TokenStream, Error> {
145
217
pat => ( * pat) . clone ( ) ,
146
218
} ) ;
147
219
let input_types = closure. inputs . iter ( ) . map ( pat_to_type) ;
148
- // let line_number = format!(" {}:{}:{}", closure.span().source_file(), closure.span().start().line, closure.span().start().column);
149
220
150
221
let type_params = & ( 0 ..env_variables. len ( ) )
151
222
. map ( |i| {
152
223
Ident :: new (
153
- & format ! ( "__SERDE_CLOSURE_{}" , bijective_base( i as u64 , 26 , alpha) ) ,
224
+ & format ! (
225
+ "__SERDE_CLOSURE_{}" ,
226
+ bijective_base( i as u64 , 26 , alpha_upper)
227
+ ) ,
154
228
span,
155
229
)
156
230
} )
@@ -268,7 +342,7 @@ fn impl_fn_once(closure: Closure, kind: Kind) -> Result<TokenStream, Error> {
268
342
Ok ( quote ! {
269
343
{
270
344
mod #impls_name {
271
- #![ allow( warnings, unsafe_code ) ]
345
+ #![ allow( warnings) ]
272
346
use :: serde_closure:: {
273
347
internal:: { self , is_phantom, to_phantom} ,
274
348
structs,
@@ -317,11 +391,16 @@ fn impl_fn_once(closure: Closure, kind: Kind) -> Result<TokenStream, Error> {
317
391
}
318
392
impl <#( #type_params, ) * F > #name<#( #type_params, ) * F > {
319
393
fn f( & self ) -> F {
320
- // This is safe as an F has already been materialized (so we
321
- // know it isn't uninhabited), it's Copy, it's not Drop, and
322
- // its size is zero.
394
+ // This is safe as an F has already been materialized (so we know it isn't
395
+ // uninhabited), it's Copy, it's not Drop, its size is zero. Most
396
+ // importantly, thanks to the `use Type` static assertion, we're guaranteed
397
+ // not to be capturing anything other than `env_types_name`. Related:
398
+ // https://internals.rust-lang.org/t/is-synthesizing-zero-sized-values-safe/11506
323
399
unsafe { MaybeUninit :: uninit( ) . assume_init( ) }
324
400
}
401
+ // Strip F due to https://play.rust-lang.org/?edition=2018&gist=a2936c8b5abb13357d97bf835203b153
402
+ // Another struct could hold env vars and avoid these unsafes but that slightly
403
+ // increases complexity?
325
404
fn strip_f( self ) -> #name<#( #type_params, ) * ( ) > {
326
405
#name {
327
406
#( #env_variables: self . #env_variables, ) *
@@ -461,7 +540,7 @@ fn impl_fn_once(closure: Closure, kind: Kind) -> Result<TokenStream, Error> {
461
540
#body
462
541
} ;
463
542
464
- #[ allow( warnings, unsafe_code ) ]
543
+ #[ allow( warnings) ]
465
544
{
466
545
if false {
467
546
let _ = closure( #ret_ref, loop { } ) ;
@@ -742,14 +821,8 @@ impl<'a> State<'a> {
742
821
|| is_func || has_path_arguments)
743
822
{
744
823
let _ = self . env_variables . insert ( ident. clone ( ) ) ;
745
- let mut a = if !self . env_struct {
746
- Expr :: Path ( ExprPath {
747
- attrs : attrs. clone ( ) ,
748
- qself : None ,
749
- path : path. clone ( ) ,
750
- } )
751
- } else {
752
- Expr :: Field ( ExprField {
824
+ if self . env_struct {
825
+ let mut a = Expr :: Field ( ExprField {
753
826
attrs : vec ! [ ] ,
754
827
base : Box :: new ( Expr :: Path ( ExprPath {
755
828
attrs : attrs. clone ( ) ,
@@ -765,20 +838,20 @@ impl<'a> State<'a> {
765
838
} ) ) ,
766
839
dot_token : Default :: default ( ) ,
767
840
member : Member :: Named ( ident. clone ( ) ) ,
768
- } )
769
- } ;
770
- if self . deref {
771
- a = Expr :: Unary ( ExprUnary {
841
+ } ) ;
842
+ if self . deref {
843
+ a = Expr :: Unary ( ExprUnary {
844
+ attrs : vec ! [ ] ,
845
+ op : UnOp :: Deref ( Default :: default ( ) ) ,
846
+ expr : Box :: new ( a) ,
847
+ } ) ;
848
+ }
849
+ * expr = Expr :: Paren ( ExprParen {
772
850
attrs : vec ! [ ] ,
773
- op : UnOp :: Deref ( Default :: default ( ) ) ,
851
+ paren_token : Default :: default ( ) ,
774
852
expr : Box :: new ( a) ,
775
853
} ) ;
776
854
}
777
- * expr = Expr :: Paren ( ExprParen {
778
- attrs : vec ! [ ] ,
779
- paren_token : Default :: default ( ) ,
780
- expr : Box :: new ( a) ,
781
- } ) ;
782
855
} else {
783
856
let _ = self . not_env_variables . insert ( ident. clone ( ) ) ;
784
857
}
@@ -817,10 +890,12 @@ impl<'a> State<'a> {
817
890
} ;
818
891
mac. tokens = expr. args . to_token_stream ( ) ;
819
892
} else {
820
- mac. span ( )
821
- . unwrap ( )
822
- . warning ( "See https://github.com/alecmocatta/serde_closure/issues/16" )
823
- . emit ( )
893
+ panic ! ( "See https://github.com/alecmocatta/serde_closure/issues/16" ) ;
894
+ // proc_macro_diagnostic: https://github.com/rust-lang/rust/issues/54140
895
+ // mac.span()
896
+ // .unwrap()
897
+ // .warning("See https://github.com/alecmocatta/serde_closure/issues/16")
898
+ // .emit()
824
899
}
825
900
}
826
901
_ => ( ) ,
@@ -829,10 +904,15 @@ impl<'a> State<'a> {
829
904
}
830
905
831
906
#[ inline( always) ]
832
- fn alpha ( u : u8 ) -> u8 {
907
+ fn alpha_upper ( u : u8 ) -> u8 {
833
908
assert ! ( u < 26 ) ;
834
909
u + b'A'
835
910
}
911
+ #[ inline( always) ]
912
+ fn alpha_lower ( u : u8 ) -> u8 {
913
+ assert ! ( u < 26 ) ;
914
+ u + b'a'
915
+ }
836
916
const BUF_SIZE : usize = 64 ; // u64::max_value() in base 2
837
917
fn bijective_base ( n : u64 , base : u64 , digits : impl Fn ( u8 ) -> u8 ) -> String {
838
918
let mut buffer = [ 0_u8 ; BUF_SIZE ] ;
@@ -855,18 +935,18 @@ fn bijective_base(n: u64, base: u64, digits: impl Fn(u8) -> u8) -> String {
855
935
#[ test]
856
936
fn bijective_base_test ( ) {
857
937
for i in 0 ..=26 + 26 * 26 + 26 * 26 * 26 {
858
- let _ = bijective_base ( i, 26 , alpha ) ;
938
+ let _ = bijective_base ( i, 26 , alpha_upper ) ;
859
939
}
860
940
assert_eq ! (
861
- bijective_base( 26 + 26 * 26 + 26 * 26 * 26 , 26 , alpha ) ,
941
+ bijective_base( 26 + 26 * 26 + 26 * 26 * 26 , 26 , alpha_upper ) ,
862
942
"AAAA"
863
943
) ;
864
944
assert_eq ! (
865
- bijective_base( u64 :: max_value( ) , 3 , alpha ) ,
945
+ bijective_base( u64 :: max_value( ) , 3 , alpha_upper ) ,
866
946
"AAAABBABCBBABBAABCCAACCCACAACACCACCBAABBA"
867
947
) ;
868
948
assert_eq ! (
869
- bijective_base( u64 :: max_value( ) , 2 , alpha ) ,
949
+ bijective_base( u64 :: max_value( ) , 2 , alpha_upper ) ,
870
950
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB"
871
951
) ;
872
952
}
0 commit comments