@@ -42,6 +42,13 @@ pub fn expand(item: &syn::Item) -> Result<TokenStream> {
4242 _ => bail ! ( item, "`track` can only be applied to impl blocks and traits" ) ,
4343 } ;
4444
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+
4552 // Produce the necessary items for the type to become trackable.
4653 let variants = create_variants ( & methods) ;
4754 let scope = create ( & ty, generics, trait_, & methods) ?;
@@ -168,6 +175,12 @@ fn prepare_method(vis: syn::Visibility, sig: &syn::Signature) -> Result<Method>
168175 bail ! ( ty, "tracked methods cannot return mutable references" ) ;
169176 }
170177
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+
171184 Ok ( Method {
172185 vis,
173186 sig : sig. clone ( ) ,
@@ -225,11 +238,6 @@ fn create(
225238 let t: syn:: GenericParam = parse_quote ! { ' __comemo_tracked } ;
226239 let r: syn:: GenericParam = parse_quote ! { ' __comemo_retrack } ;
227240 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- } ;
233241
234242 // Prepare generics.
235243 let ( impl_gen, type_gen, where_clause) = generics. split_for_impl ( ) ;
@@ -245,37 +253,9 @@ fn create(
245253 impl_params_t. params . push ( t. clone ( ) ) ;
246254 type_params_t. params . push ( t. clone ( ) ) ;
247255
248- // Prepare validations.
249256 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 ( ) ;
279259
280260 // Prepare variants and wrapper methods.
281261 let wrapper_methods = methods
@@ -284,32 +264,18 @@ fn create(
284264 . map ( |m| create_wrapper ( m, false ) ) ;
285265 let wrapper_methods_mut = methods. iter ( ) . map ( |m| create_wrapper ( m, true ) ) ;
286266
287- let constraint = if immutable {
288- quote ! { ImmutableConstraint }
289- } else {
290- quote ! { MutableConstraint }
291- } ;
292-
293267 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;
298270
299271 #[ inline]
300- fn validate ( & self , constraint : & Self :: Constraint ) -> bool {
301- #validate
272+ fn call ( & self , call : & Self :: Call ) -> u128 {
273+ match call . 0 { # ( #calls , ) * }
302274 }
303275
304276 #[ 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, ) * }
313279 }
314280 }
315281
@@ -363,41 +329,50 @@ fn create(
363329 } )
364330}
365331
366- /// Produce a constraint validation for a method.
332+ /// Produce a call enum variant for a method.
367333fn create_variant ( method : & Method ) -> TokenStream {
368334 let name = & method. sig . ident ;
369335 let types = & method. types ;
370336 quote ! { #name( #( <#types as :: std:: borrow:: ToOwned >:: Owned ) , * ) }
371337}
372338
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 {
375341 let name = & method. sig . ident ;
376342 let args = & method. args ;
377343 let prepared = method. args . iter ( ) . zip ( & method. kinds ) . map ( |( arg, kind) | match kind {
378344 Kind :: Normal => quote ! { #arg. to_owned( ) } ,
379345 Kind :: Reference => quote ! { #arg } ,
380346 } ) ;
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+ }
384356 }
385357}
386358
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 {
389361 let name = & method. sig . ident ;
390362 let args = & method. args ;
391363 let prepared = method. args . iter ( ) . zip ( & method. kinds ) . map ( |( arg, kind) | match kind {
392364 Kind :: Normal => quote ! { #arg. to_owned( ) } ,
393365 Kind :: Reference => quote ! { #arg } ,
394366 } ) ;
395- let body = method. mutable . then ( || {
367+ if method. mutable {
396368 quote ! {
397- self . #name( #( #prepared) , * ) ;
369+ __ComemoVariant :: #name ( # ( ref #args ) , * ) => self . #name( #( #prepared) , * )
398370 }
399- } ) ;
400- quote ! { __ComemoVariant:: #name( #( #args) , * ) => { #body } }
371+ } else {
372+ quote ! {
373+ __ComemoVariant:: #name( ..) => { }
374+ }
375+ }
401376}
402377
403378/// Produce a wrapped surface method.
@@ -417,16 +392,19 @@ fn create_wrapper(method: &Method, tracked_mut: bool) -> TokenStream {
417392 #[ track_caller]
418393 #[ inline]
419394 #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,
425401 __ComemoCall( __comemo_variant) ,
426402 :: comemo:: internal:: hash( & output) ,
427403 ) ;
404+ output
405+ } else {
406+ __comemo_value. #name( #( #args, ) * )
428407 }
429- output
430408 }
431409 }
432410}
0 commit comments