@@ -42,6 +42,13 @@ pub fn expand(item: &syn::Item) -> Result<TokenStream> {
42
42
_ => bail ! ( item, "`track` can only be applied to impl blocks and traits" ) ,
43
43
} ;
44
44
45
+ if methods. iter ( ) . any ( |m| m. mutable ) && methods. iter ( ) . any ( |m| !m. mutable ) {
46
+ bail ! (
47
+ item,
48
+ "`track` cannot be applied to a mix of mutable and immutable methods"
49
+ ) ;
50
+ }
51
+
45
52
// Produce the necessary items for the type to become trackable.
46
53
let variants = create_variants ( & methods) ;
47
54
let scope = create ( & ty, generics, trait_, & methods) ?;
@@ -168,6 +175,12 @@ fn prepare_method(vis: syn::Visibility, sig: &syn::Signature) -> Result<Method>
168
175
bail ! ( ty, "tracked methods cannot return mutable references" ) ;
169
176
}
170
177
178
+ if let syn:: ReturnType :: Type ( _, ty) = & sig. output
179
+ && receiver. mutability . is_some ( )
180
+ {
181
+ bail ! ( ty, "mutable tracked methods cannot have a return value" ) ;
182
+ }
183
+
171
184
Ok ( Method {
172
185
vis,
173
186
sig : sig. clone ( ) ,
@@ -225,11 +238,6 @@ fn create(
225
238
let t: syn:: GenericParam = parse_quote ! { ' __comemo_tracked } ;
226
239
let r: syn:: GenericParam = parse_quote ! { ' __comemo_retrack } ;
227
240
let d: syn:: GenericParam = parse_quote ! { ' __comemo_dynamic } ;
228
- let maybe_cloned = if methods. iter ( ) . any ( |it| it. mutable ) {
229
- quote ! { :: core:: clone:: Clone :: clone( self ) }
230
- } else {
231
- quote ! { self }
232
- } ;
233
241
234
242
// Prepare generics.
235
243
let ( impl_gen, type_gen, where_clause) = generics. split_for_impl ( ) ;
@@ -245,37 +253,9 @@ fn create(
245
253
impl_params_t. params . push ( t. clone ( ) ) ;
246
254
type_params_t. params . push ( t. clone ( ) ) ;
247
255
248
- // Prepare validations.
249
256
let prefix = trait_. as_ref ( ) . map ( |name| quote ! { #name for } ) ;
250
- let validations: Vec < _ > = methods. iter ( ) . map ( create_validation) . collect ( ) ;
251
- let validate = if !methods. is_empty ( ) {
252
- quote ! {
253
- let mut this = #maybe_cloned;
254
- constraint. validate( |call| match & call. 0 { #( #validations, ) * } )
255
- }
256
- } else {
257
- quote ! { true }
258
- } ;
259
- let validate_with_id = if !methods. is_empty ( ) {
260
- quote ! {
261
- let mut this = #maybe_cloned;
262
- constraint. validate_with_id(
263
- |call| match & call. 0 { #( #validations, ) * } ,
264
- id,
265
- )
266
- }
267
- } else {
268
- quote ! { true }
269
- } ;
270
-
271
- // Prepare replying.
272
- let immutable = methods. iter ( ) . all ( |m| !m. mutable ) ;
273
- let replays = methods. iter ( ) . map ( create_replay) ;
274
- let replay = ( !immutable) . then ( || {
275
- quote ! {
276
- constraint. replay( |call| match & call. 0 { #( #replays, ) * } ) ;
277
- }
278
- } ) ;
257
+ let calls: Vec < _ > = methods. iter ( ) . map ( create_call) . collect ( ) ;
258
+ let calls_mut: Vec < _ > = methods. iter ( ) . map ( create_call_mut) . collect ( ) ;
279
259
280
260
// Prepare variants and wrapper methods.
281
261
let wrapper_methods = methods
@@ -284,32 +264,18 @@ fn create(
284
264
. map ( |m| create_wrapper ( m, false ) ) ;
285
265
let wrapper_methods_mut = methods. iter ( ) . map ( |m| create_wrapper ( m, true ) ) ;
286
266
287
- let constraint = if immutable {
288
- quote ! { ImmutableConstraint }
289
- } else {
290
- quote ! { MutableConstraint }
291
- } ;
292
-
293
267
Ok ( quote ! {
294
- impl #impl_params :: comemo:: Track for #ty #where_clause { }
295
-
296
- impl #impl_params :: comemo:: Validate for #ty #where_clause {
297
- type Constraint = :: comemo:: internal:: #constraint<__ComemoCall>;
268
+ impl #impl_params :: comemo:: Track for #ty #where_clause {
269
+ type Call = __ComemoCall;
298
270
299
271
#[ inline]
300
- fn validate ( & self , constraint : & Self :: Constraint ) -> bool {
301
- #validate
272
+ fn call ( & self , call : & Self :: Call ) -> u128 {
273
+ match call . 0 { # ( #calls , ) * }
302
274
}
303
275
304
276
#[ inline]
305
- fn validate_with_id( & self , constraint: & Self :: Constraint , id: usize ) -> bool {
306
- #validate_with_id
307
- }
308
-
309
- #[ inline]
310
- #[ allow( unused_variables) ]
311
- fn replay( & mut self , constraint: & Self :: Constraint ) {
312
- #replay
277
+ fn call_mut( & mut self , call: & Self :: Call ) {
278
+ match call. 0 { #( #calls_mut, ) * }
313
279
}
314
280
}
315
281
@@ -363,41 +329,50 @@ fn create(
363
329
} )
364
330
}
365
331
366
- /// Produce a constraint validation for a method.
332
+ /// Produce a call enum variant for a method.
367
333
fn create_variant ( method : & Method ) -> TokenStream {
368
334
let name = & method. sig . ident ;
369
335
let types = & method. types ;
370
336
quote ! { #name( #( <#types as :: std:: borrow:: ToOwned >:: Owned ) , * ) }
371
337
}
372
338
373
- /// Produce a constraint validation for a method.
374
- fn create_validation ( method : & Method ) -> TokenStream {
339
+ /// Produce a call branch for a method.
340
+ fn create_call ( method : & Method ) -> TokenStream {
375
341
let name = & method. sig . ident ;
376
342
let args = & method. args ;
377
343
let prepared = method. args . iter ( ) . zip ( & method. kinds ) . map ( |( arg, kind) | match kind {
378
344
Kind :: Normal => quote ! { #arg. to_owned( ) } ,
379
345
Kind :: Reference => quote ! { #arg } ,
380
346
} ) ;
381
- quote ! {
382
- __ComemoVariant:: #name( #( #args) , * )
383
- => :: comemo:: internal:: hash( & this. #name( #( #prepared) , * ) )
347
+ if method. mutable {
348
+ quote ! {
349
+ __ComemoVariant:: #name( ..) => 0
350
+ }
351
+ } else {
352
+ quote ! {
353
+ __ComemoVariant:: #name( #( ref #args) , * )
354
+ => :: comemo:: internal:: hash( & self . #name( #( #prepared) , * ) )
355
+ }
384
356
}
385
357
}
386
358
387
- /// Produce a constraint validation for a method.
388
- fn create_replay ( method : & Method ) -> TokenStream {
359
+ /// Produce a mutable call branch for a method.
360
+ fn create_call_mut ( method : & Method ) -> TokenStream {
389
361
let name = & method. sig . ident ;
390
362
let args = & method. args ;
391
363
let prepared = method. args . iter ( ) . zip ( & method. kinds ) . map ( |( arg, kind) | match kind {
392
364
Kind :: Normal => quote ! { #arg. to_owned( ) } ,
393
365
Kind :: Reference => quote ! { #arg } ,
394
366
} ) ;
395
- let body = method. mutable . then ( || {
367
+ if method. mutable {
396
368
quote ! {
397
- self . #name( #( #prepared) , * ) ;
369
+ __ComemoVariant :: #name ( # ( ref #args ) , * ) => self . #name( #( #prepared) , * )
398
370
}
399
- } ) ;
400
- quote ! { __ComemoVariant:: #name( #( #args) , * ) => { #body } }
371
+ } else {
372
+ quote ! {
373
+ __ComemoVariant:: #name( ..) => { }
374
+ }
375
+ }
401
376
}
402
377
403
378
/// Produce a wrapped surface method.
@@ -417,16 +392,19 @@ fn create_wrapper(method: &Method, tracked_mut: bool) -> TokenStream {
417
392
#[ track_caller]
418
393
#[ inline]
419
394
#vis #sig {
420
- let __comemo_variant = __ComemoVariant:: #name( #( #args. to_owned( ) ) , * ) ;
421
- let ( __comemo_value, __comemo_constraint) = :: comemo:: internal:: #to_parts;
422
- let output = __comemo_value. #name( #( #args, ) * ) ;
423
- if let Some ( constraint) = __comemo_constraint {
424
- constraint. push(
395
+ let ( __comemo_value, __comemo_sink) = :: comemo:: internal:: #to_parts;
396
+ if let Some ( __comemo_sink) = __comemo_sink {
397
+ let __comemo_variant = __ComemoVariant:: #name( #( #args. to_owned( ) ) , * ) ;
398
+ let output = __comemo_value. #name( #( #args, ) * ) ;
399
+ :: comemo:: internal:: Sink :: emit(
400
+ __comemo_sink,
425
401
__ComemoCall( __comemo_variant) ,
426
402
:: comemo:: internal:: hash( & output) ,
427
403
) ;
404
+ output
405
+ } else {
406
+ __comemo_value. #name( #( #args, ) * )
428
407
}
429
- output
430
408
}
431
409
}
432
410
}
0 commit comments