@@ -10,39 +10,68 @@ pub fn expand(block: syn::ItemImpl) -> Result<proc_macro2::TokenStream> {
10
10
methods. push ( method ( & item) ?) ;
11
11
}
12
12
13
- let tracked_fields = methods. iter ( ) . map ( |method| {
14
- let name = & method. sig . ident ;
15
- let ty = match & method. sig . output {
16
- syn:: ReturnType :: Default => unreachable ! ( ) ,
17
- syn:: ReturnType :: Type ( _, ty) => ty. as_ref ( ) ,
18
- } ;
19
- quote ! { #name: :: comemo:: internal:: HashConstraint <#ty>, }
13
+ let tracked_valids = methods. iter ( ) . map ( |method| {
14
+ let name = & method. name ;
15
+ let args = & method. args ;
16
+ if args. is_empty ( ) {
17
+ quote ! { constraint. #name. valid( & self . #name( ) ) }
18
+ } else {
19
+ quote ! {
20
+ constraint. #name
21
+ . valid( |( #( #args, ) * ) | self . #name( #( #args. clone( ) , ) * ) )
22
+ }
23
+ }
20
24
} ) ;
21
25
22
26
let tracked_methods = methods. iter ( ) . map ( |method| {
23
- let name = & method. sig . ident ;
24
- let mut method = ( * method) . clone ( ) ;
25
- if matches ! ( method. vis, syn:: Visibility :: Inherited ) {
26
- method. vis = parse_quote ! { pub ( super ) } ;
27
+ let mut wrapper = method. item . clone ( ) ;
28
+ if matches ! ( wrapper. vis, syn:: Visibility :: Inherited ) {
29
+ wrapper. vis = parse_quote ! { pub ( super ) } ;
27
30
}
28
- method. block = parse_quote ! { {
29
- let ( inner, constraint) = :: comemo:: internal:: to_parts( self . 0 ) ;
30
- let output = inner. #name( ) ;
31
+
32
+ let name = & method. name ;
33
+ let args = & method. args ;
34
+ let set = if args. is_empty ( ) {
35
+ quote ! { constraint. #name. set( & output) }
36
+ } else {
37
+ quote ! { constraint. #name. set( ( #( #args, ) * ) , & output) }
38
+ } ;
39
+
40
+ // Construct assertions that the arguments fulfill the necessary bounds.
41
+ let bounds = method. types . iter ( ) . map ( |ty| {
42
+ quote ! {
43
+ :: comemo:: internal:: assert_clone_and_partial_eq:: <#ty>( ) ;
44
+ }
45
+ } ) ;
46
+
47
+ wrapper. block = parse_quote ! { {
48
+ #( #bounds; ) *
49
+ let ( value, constraint) = :: comemo:: internal:: to_parts( self . 0 ) ;
50
+ let output = value. #name( #( #args. clone( ) , ) * ) ;
31
51
if let Some ( constraint) = & constraint {
32
- constraint . #name . set( & output ) ;
52
+ # set;
33
53
}
34
54
output
35
55
} } ;
36
- method
56
+
57
+ wrapper
37
58
} ) ;
38
59
39
- let tracked_valids = methods. iter ( ) . map ( |method| {
40
- let name = & method. sig . ident ;
41
- quote ! {
42
- constraint. #name. valid( & self . #name( ) )
60
+ let tracked_fields = methods. iter ( ) . map ( |method| {
61
+ let name = & method. name ;
62
+ let types = & method. types ;
63
+ if types. is_empty ( ) {
64
+ quote ! { #name: :: comemo:: internal:: HashConstraint , }
65
+ } else {
66
+ quote ! { #name: :: comemo:: internal:: FuncConstraint <( #( #types, ) * ) >, }
43
67
}
44
68
} ) ;
45
69
70
+ let join_calls = methods. iter ( ) . map ( |method| {
71
+ let name = & method. name ;
72
+ quote ! { self . #name. join( & inner. #name) ; }
73
+ } ) ;
74
+
46
75
let track_impl = quote ! {
47
76
use super :: * ;
48
77
@@ -77,6 +106,12 @@ pub fn expand(block: syn::ItemImpl) -> Result<proc_macro2::TokenStream> {
77
106
pub struct Constraint {
78
107
#( #tracked_fields) *
79
108
}
109
+
110
+ impl :: comemo:: internal:: Join for Constraint {
111
+ fn join( & self , inner: & Self ) {
112
+ #( #join_calls) *
113
+ }
114
+ }
80
115
} ;
81
116
82
117
Ok ( quote ! {
@@ -85,8 +120,15 @@ pub fn expand(block: syn::ItemImpl) -> Result<proc_macro2::TokenStream> {
85
120
} )
86
121
}
87
122
123
+ struct Method {
124
+ item : syn:: ImplItemMethod ,
125
+ name : syn:: Ident ,
126
+ args : Vec < syn:: Ident > ,
127
+ types : Vec < syn:: Type > ,
128
+ }
129
+
88
130
/// Extract and validate a method.
89
- fn method ( item : & syn:: ImplItem ) -> Result < & syn :: ImplItemMethod > {
131
+ fn method ( item : & syn:: ImplItem ) -> Result < Method > {
90
132
let method = match item {
91
133
syn:: ImplItem :: Method ( method) => method,
92
134
_ => bail ! ( item, "only methods are supported" ) ,
@@ -98,6 +140,27 @@ fn method(item: &syn::ImplItem) -> Result<&syn::ImplItemMethod> {
98
140
_ => bail ! ( method. vis, "only private and public methods are supported" ) ,
99
141
}
100
142
143
+ if let Some ( unsafety) = method. sig . unsafety {
144
+ bail ! ( unsafety, "unsafe methods are not supported" ) ;
145
+ }
146
+
147
+ if let Some ( asyncness) = method. sig . asyncness {
148
+ bail ! ( asyncness, "async methods are not supported" ) ;
149
+ }
150
+
151
+ if let Some ( constness) = method. sig . constness {
152
+ bail ! ( constness, "const methods are not supported" ) ;
153
+ }
154
+
155
+ for param in method. sig . generics . params . iter ( ) {
156
+ match param {
157
+ syn:: GenericParam :: Const ( _) | syn:: GenericParam :: Type ( _) => {
158
+ bail ! ( param, "method must not be generic" )
159
+ }
160
+ syn:: GenericParam :: Lifetime ( _) => { }
161
+ }
162
+ }
163
+
101
164
let mut inputs = method. sig . inputs . iter ( ) ;
102
165
let receiver = match inputs. next ( ) {
103
166
Some ( syn:: FnArg :: Receiver ( recv) ) => recv,
@@ -108,20 +171,46 @@ fn method(item: &syn::ImplItem) -> Result<&syn::ImplItemMethod> {
108
171
bail ! ( receiver, "must take self by shared reference" ) ;
109
172
}
110
173
111
- if inputs. next ( ) . is_some ( ) {
112
- bail ! (
113
- method. sig,
114
- "currently, only methods without extra arguments are supported"
115
- ) ;
174
+ let mut args = vec ! [ ] ;
175
+ let mut types = vec ! [ ] ;
176
+ for input in inputs {
177
+ let typed = match input {
178
+ syn:: FnArg :: Typed ( typed) => typed,
179
+ syn:: FnArg :: Receiver ( _) => continue ,
180
+ } ;
181
+
182
+ let name = match typed. pat . as_ref ( ) {
183
+ syn:: Pat :: Ident ( syn:: PatIdent {
184
+ by_ref : None ,
185
+ mutability : None ,
186
+ ident,
187
+ subpat : None ,
188
+ ..
189
+ } ) => ident. clone ( ) ,
190
+ pat => bail ! ( pat, "only simple identifiers are supported" ) ,
191
+ } ;
192
+
193
+ let ty = ( * typed. ty ) . clone ( ) ;
194
+ match ty {
195
+ syn:: Type :: ImplTrait ( _) => bail ! ( ty, "method must not be generic" ) ,
196
+ _ => { }
197
+ }
198
+
199
+ args. push ( name) ;
200
+ types. push ( ty) ;
116
201
}
117
202
118
- let output = & method. sig . output ;
119
- match output {
203
+ match method. sig . output {
120
204
syn:: ReturnType :: Default => {
121
205
bail ! ( method. sig, "method must have a return type" )
122
206
}
123
207
syn:: ReturnType :: Type ( ..) => { }
124
208
}
125
209
126
- Ok ( method)
210
+ Ok ( Method {
211
+ item : method. clone ( ) ,
212
+ name : method. sig . ident . clone ( ) ,
213
+ args,
214
+ types,
215
+ } )
127
216
}
0 commit comments