@@ -5,18 +5,26 @@ pub fn expand(item: &syn::Item) -> Result<TokenStream> {
55 // Preprocess and validate the methods.
66 let mut methods = vec ! [ ] ;
77
8- let ( ty, trait_) = match item {
8+ let ( ty, generics , trait_) = match item {
99 syn:: Item :: Impl ( item) => {
1010 for param in item. generics . params . iter ( ) {
11- bail ! ( param, "tracked impl blocks cannot be generic" )
11+ match param {
12+ syn:: GenericParam :: Lifetime ( _) => { }
13+ syn:: GenericParam :: Type ( _) => {
14+ bail ! ( param, "tracked impl blocks cannot use type generics" )
15+ }
16+ syn:: GenericParam :: Const ( _) => {
17+ bail ! ( param, "tracked impl blocks cannot use const generics" )
18+ }
19+ }
1220 }
1321
1422 for item in & item. items {
1523 methods. push ( prepare_impl_method ( & item) ?) ;
1624 }
1725
1826 let ty = item. self_ty . as_ref ( ) . clone ( ) ;
19- ( ty, None )
27+ ( ty, & item . generics , None )
2028 }
2129 syn:: Item :: Trait ( item) => {
2230 for param in item. generics . params . iter ( ) {
@@ -28,17 +36,14 @@ pub fn expand(item: &syn::Item) -> Result<TokenStream> {
2836 }
2937
3038 let name = & item. ident ;
31- let ty = parse_quote ! { dyn #name } ;
32- ( ty, Some ( name. clone ( ) ) )
39+ let ty = parse_quote ! { dyn #name + ' __comemo_dynamic } ;
40+ ( ty, & item . generics , Some ( name. clone ( ) ) )
3341 }
34- _ => bail ! (
35- item,
36- "`track` can only be applied to impl blocks and traits"
37- ) ,
42+ _ => bail ! ( item, "`track` can only be applied to impl blocks and traits" ) ,
3843 } ;
3944
4045 // Produce the necessary items for the type to become trackable.
41- let scope = create ( & ty, trait_, & methods) ?;
46+ let scope = create ( & ty, generics , trait_, & methods) ?;
4247
4348 Ok ( quote ! {
4449 #item
@@ -172,104 +177,152 @@ fn prepare_method(vis: syn::Visibility, sig: &syn::Signature) -> Result<Method>
172177/// Produce the necessary items for a type to become trackable.
173178fn create (
174179 ty : & syn:: Type ,
180+ generics : & syn:: Generics ,
175181 trait_ : Option < syn:: Ident > ,
176182 methods : & [ Method ] ,
177183) -> Result < TokenStream > {
178- let prefix = trait_. map ( |name| quote ! { #name for } ) ;
179- let variants = methods. iter ( ) . map ( create_variant) ;
180- let validations = methods. iter ( ) . map ( create_validation) ;
184+ let t: syn:: GenericParam = parse_quote ! { ' __comemo_tracked } ;
185+ let r: syn:: GenericParam = parse_quote ! { ' __comemo_retrack } ;
186+ let d: syn:: GenericParam = parse_quote ! { ' __comemo_dynamic } ;
187+ let maybe_cloned = if methods. iter ( ) . any ( |it| it. mutable ) {
188+ quote ! { :: core:: clone:: Clone :: clone( self ) }
189+ } else {
190+ quote ! { self }
191+ } ;
192+
193+ // Prepare generics.
194+ let ( impl_gen, type_gen, where_clause) = generics. split_for_impl ( ) ;
195+ let mut impl_params: syn:: Generics = parse_quote ! { #impl_gen } ;
196+ let mut type_params: syn:: Generics = parse_quote ! { #type_gen } ;
197+ if trait_. is_some ( ) {
198+ impl_params. params . push ( d. clone ( ) ) ;
199+ type_params. params . push ( d. clone ( ) ) ;
200+ }
201+
202+ let mut impl_params_t: syn:: Generics = impl_params. clone ( ) ;
203+ let mut type_params_t: syn:: Generics = type_params. clone ( ) ;
204+ impl_params_t. params . push ( t. clone ( ) ) ;
205+ type_params_t. params . push ( t. clone ( ) ) ;
206+
207+ // Prepare validations.
208+ let prefix = trait_. as_ref ( ) . map ( |name| quote ! { #name for } ) ;
209+ let validations: Vec < _ > = methods. iter ( ) . map ( create_validation) . collect ( ) ;
210+ let validate = if !methods. is_empty ( ) {
211+ quote ! {
212+ let mut this = #maybe_cloned;
213+ constraint. validate( |call| match & call. 0 { #( #validations, ) * } )
214+ }
215+ } else {
216+ quote ! { true }
217+ } ;
218+ let validate_with_id = if !methods. is_empty ( ) {
219+ quote ! {
220+ let mut this = #maybe_cloned;
221+ constraint. validate_with_id(
222+ |call| match & call. 0 { #( #validations, ) * } ,
223+ id,
224+ )
225+ }
226+ } else {
227+ quote ! { true }
228+ } ;
229+
230+ // Prepare replying.
181231 let replays = methods. iter ( ) . map ( create_replay) ;
232+ let replay = methods. iter ( ) . any ( |m| m. mutable ) . then ( || {
233+ quote ! {
234+ constraint. replay( |call| match & call. 0 { #( #replays, ) * } ) ;
235+ }
236+ } ) ;
237+
238+ // Prepare variants and wrapper methods.
239+ let variants = methods. iter ( ) . map ( create_variant) ;
182240 let wrapper_methods = methods
183241 . iter ( )
184242 . filter ( |m| !m. mutable )
185243 . map ( |m| create_wrapper ( m, false ) ) ;
186244 let wrapper_methods_mut = methods. iter ( ) . map ( |m| create_wrapper ( m, true ) ) ;
187- let maybe_cloned = if methods. iter ( ) . any ( |it| it. mutable ) {
188- quote ! { :: std:: clone:: Clone :: clone( self ) }
189- } else {
190- quote ! { self }
191- } ;
192245
193246 Ok ( quote ! {
194- #[ derive( Clone , PartialEq ) ]
195- pub struct __ComemoCall( __ComemoVariant) ;
247+ impl #impl_params :: comemo:: Track for #ty #where_clause { }
196248
197- #[ derive( Clone , PartialEq ) ]
198- #[ allow( non_camel_case_types) ]
199- enum __ComemoVariant {
200- #( #variants, ) *
201- }
249+ impl #impl_params :: comemo:: Validate for #ty #where_clause {
250+ type Constraint = :: comemo:: internal:: Constraint <__ComemoCall>;
202251
203- impl :: comemo:: Track for #ty {
204252 #[ inline]
205- fn valid( & self , constraint: & :: comemo:: Constraint <Self >) -> bool {
206- let mut this = #maybe_cloned;
207- constraint. valid( |call| match & call. 0 { #( #validations, ) * } )
253+ fn validate( & self , constraint: & Self :: Constraint ) -> bool {
254+ #validate
208255 }
209- }
210256
211- #[ doc( hidden) ]
212- impl :: comemo:: internal:: Trackable for #ty {
213- type Call = __ComemoCall;
214- type Surface = __ComemoSurfaceFamily;
215- type SurfaceMut = __ComemoSurfaceMutFamily;
257+ #[ inline]
258+ fn validate_with_id( & self , constraint: & Self :: Constraint , id: usize ) -> bool {
259+ #validate_with_id
260+ }
216261
217262 #[ inline]
218263 #[ allow( unused_variables) ]
219- fn replay( & mut self , constraint: & :: comemo :: Constraint < Self > ) {
220- constraint . replay ( |call| match & call . 0 { # ( #replays , ) * } ) ;
264+ fn replay( & mut self , constraint: & Self :: Constraint ) {
265+ #replay
221266 }
267+ }
268+
269+ #[ derive( Clone , PartialEq , Hash ) ]
270+ pub struct __ComemoCall( __ComemoVariant) ;
271+
272+ #[ derive( Clone , PartialEq , Hash ) ]
273+ #[ allow( non_camel_case_types) ]
274+ enum __ComemoVariant {
275+ #( #variants, ) *
276+ }
277+
278+ #[ doc( hidden) ]
279+ impl #impl_params :: comemo:: internal:: Surfaces for #ty #where_clause {
280+ type Surface <#t> = __ComemoSurface #type_params_t where Self : #t;
281+ type SurfaceMut <#t> = __ComemoSurfaceMut #type_params_t where Self : #t;
222282
223283 #[ inline]
224- fn surface_ref<' a , ' r>(
225- tracked: & ' r :: comemo:: Tracked <' a , Self >,
226- ) -> & ' r __ComemoSurface< ' a > {
284+ fn surface_ref<#t , # r>(
285+ tracked: & # r :: comemo:: Tracked <#t , Self >,
286+ ) -> & #r Self :: Surface <#t > {
227287 // Safety: __ComemoSurface is repr(transparent).
228288 unsafe { & * ( tracked as * const _ as * const _) }
229289 }
230290
231291 #[ inline]
232- fn surface_mut_ref<' a , ' r>(
233- tracked: & ' r :: comemo:: TrackedMut <' a , Self >,
234- ) -> & ' r __ComemoSurfaceMut< ' a > {
292+ fn surface_mut_ref<#t , # r>(
293+ tracked: & # r :: comemo:: TrackedMut <#t , Self >,
294+ ) -> & #r Self :: SurfaceMut <#t > {
235295 // Safety: __ComemoSurfaceMut is repr(transparent).
236296 unsafe { & * ( tracked as * const _ as * const _) }
237297 }
238298
239299 #[ inline]
240- fn surface_mut_mut<' a , ' r>(
241- tracked: & ' r mut :: comemo:: TrackedMut <' a , Self >,
242- ) -> & ' r mut __ComemoSurfaceMut< ' a > {
300+ fn surface_mut_mut<#t , # r>(
301+ tracked: & # r mut :: comemo:: TrackedMut <#t , Self >,
302+ ) -> & # r mut Self :: SurfaceMut <#t > {
243303 // Safety: __ComemoSurfaceMut is repr(transparent).
244304 unsafe { & mut * ( tracked as * mut _ as * mut _) }
245305 }
246306 }
247307
248308 #[ repr( transparent) ]
249- pub struct __ComemoSurface<' a>( :: comemo:: Tracked <' a, #ty>) ;
309+ pub struct __ComemoSurface #impl_params_t( :: comemo:: Tracked <#t, #ty>)
310+ #where_clause;
250311
251312 #[ allow( dead_code) ]
252- impl #prefix __ComemoSurface< ' _> {
313+ impl #impl_params_t # prefix __ComemoSurface #type_params_t {
253314 #( #wrapper_methods) *
254315 }
255316
256- pub enum __ComemoSurfaceFamily { }
257- impl <' a> :: comemo:: internal:: Family <' a> for __ComemoSurfaceFamily {
258- type Out = __ComemoSurface<' a>;
259- }
260-
261317 #[ repr( transparent) ]
262- pub struct __ComemoSurfaceMut<' a>( :: comemo:: TrackedMut <' a, #ty>) ;
318+ pub struct __ComemoSurfaceMut #impl_params_t( :: comemo:: TrackedMut <#t, #ty>)
319+ #where_clause;
263320
264321 #[ allow( dead_code) ]
265- impl #prefix __ComemoSurfaceMut< ' _> {
322+ impl #impl_params_t # prefix __ComemoSurfaceMut #type_params_t {
266323 #( #wrapper_methods_mut) *
267324 }
268325
269- pub enum __ComemoSurfaceMutFamily { }
270- impl <' a> :: comemo:: internal:: Family <' a> for __ComemoSurfaceMutFamily {
271- type Out = __ComemoSurfaceMut<' a>;
272- }
273326 } )
274327}
275328
@@ -328,12 +381,12 @@ fn create_wrapper(method: &Method, tracked_mut: bool) -> TokenStream {
328381 #[ track_caller]
329382 #[ inline]
330383 #vis #sig {
331- let call = __ComemoVariant:: #name( #( #args. to_owned( ) ) , * ) ;
332- let ( value , constraint ) = :: comemo:: internal:: #to_parts;
333- let output = value . #name( #( #args, ) * ) ;
334- if let Some ( constraint) = constraint {
384+ let __comemo_variant = __ComemoVariant:: #name( #( #args. to_owned( ) ) , * ) ;
385+ let ( __comemo_value , __comemo_constraint ) = :: comemo:: internal:: #to_parts;
386+ let output = __comemo_value . #name( #( #args, ) * ) ;
387+ if let Some ( constraint) = __comemo_constraint {
335388 constraint. push(
336- __ComemoCall( call ) ,
389+ __ComemoCall( __comemo_variant ) ,
337390 :: comemo:: internal:: hash( & output) ,
338391 #mutable,
339392 ) ;
0 commit comments