Skip to content

Commit f0b8ecf

Browse files
committed
Tracked trait objects
1 parent c2e0232 commit f0b8ecf

File tree

7 files changed

+215
-117
lines changed

7 files changed

+215
-117
lines changed

macros/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use syn::{parse_quote, Error, Result};
2222
/// Memoize a pure function.
2323
#[proc_macro_attribute]
2424
pub fn memoize(_: BoundaryStream, stream: BoundaryStream) -> BoundaryStream {
25-
let func = syn::parse_macro_input!(stream as syn::ItemFn);
25+
let func = syn::parse_macro_input!(stream as syn::Item);
2626
memoize::expand(&func)
2727
.unwrap_or_else(|err| err.to_compile_error())
2828
.into()
@@ -31,7 +31,7 @@ pub fn memoize(_: BoundaryStream, stream: BoundaryStream) -> BoundaryStream {
3131
/// Make a type trackable.
3232
#[proc_macro_attribute]
3333
pub fn track(_: BoundaryStream, stream: BoundaryStream) -> BoundaryStream {
34-
let block = syn::parse_macro_input!(stream as syn::ItemImpl);
34+
let block = syn::parse_macro_input!(stream as syn::Item);
3535
track::expand(&block)
3636
.unwrap_or_else(|err| err.to_compile_error())
3737
.into()

macros/src/memoize.rs

Lines changed: 54 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
use super::*;
22

33
/// Memoize a function.
4-
pub fn expand(item: &syn::ItemFn) -> Result<proc_macro2::TokenStream> {
4+
pub fn expand(item: &syn::Item) -> Result<proc_macro2::TokenStream> {
5+
let item = match item {
6+
syn::Item::Fn(item) => item,
7+
_ => bail!(
8+
item,
9+
"`memoize` can only be applied to functions and methods"
10+
),
11+
};
12+
513
// Preprocess and validate the function.
614
let function = prepare(&item)?;
715

@@ -37,43 +45,7 @@ fn prepare(function: &syn::ItemFn) -> Result<Function> {
3745
let mut args = vec![];
3846

3947
for input in &function.sig.inputs {
40-
match input {
41-
syn::FnArg::Receiver(recv) => {
42-
if recv.mutability.is_some() {
43-
bail!(recv, "memoized functions cannot have mutable parameters");
44-
}
45-
46-
args.push(Argument::Receiver(recv.self_token));
47-
}
48-
syn::FnArg::Typed(typed) => {
49-
let name = match typed.pat.as_ref() {
50-
syn::Pat::Ident(syn::PatIdent {
51-
by_ref: None,
52-
mutability: None,
53-
ident,
54-
subpat: None,
55-
..
56-
}) => ident.clone(),
57-
pat => bail!(pat, "only simple identifiers are supported"),
58-
};
59-
60-
let ty = typed.ty.as_ref().clone();
61-
match ty {
62-
syn::Type::Reference(syn::TypeReference {
63-
mutability: Some(_),
64-
..
65-
}) => {
66-
bail!(
67-
typed.ty,
68-
"memoized functions cannot have mutable parameters"
69-
)
70-
}
71-
_ => {}
72-
}
73-
74-
args.push(Argument::Ident(name));
75-
}
76-
}
48+
args.push(prepare_arg(input)?);
7749
}
7850

7951
let output = match &function.sig.output {
@@ -91,6 +63,46 @@ fn prepare(function: &syn::ItemFn) -> Result<Function> {
9163
})
9264
}
9365

66+
/// Preprocess a function argument.
67+
fn prepare_arg(input: &syn::FnArg) -> Result<Argument> {
68+
Ok(match input {
69+
syn::FnArg::Receiver(recv) => {
70+
if recv.mutability.is_some() {
71+
bail!(recv, "memoized functions cannot have mutable parameters");
72+
}
73+
74+
Argument::Receiver(recv.self_token)
75+
}
76+
syn::FnArg::Typed(typed) => {
77+
let name = match typed.pat.as_ref() {
78+
syn::Pat::Ident(syn::PatIdent {
79+
by_ref: None,
80+
mutability: None,
81+
ident,
82+
subpat: None,
83+
..
84+
}) => ident.clone(),
85+
pat => bail!(pat, "only simple identifiers are supported"),
86+
};
87+
88+
let ty = typed.ty.as_ref().clone();
89+
match ty {
90+
syn::Type::Reference(syn::TypeReference {
91+
mutability: Some(_), ..
92+
}) => {
93+
bail!(
94+
typed.ty,
95+
"memoized functions cannot have mutable parameters"
96+
)
97+
}
98+
_ => {}
99+
}
100+
101+
Argument::Ident(name)
102+
}
103+
})
104+
}
105+
94106
/// Rewrite a function's body to memoize it.
95107
fn process(function: &Function) -> Result<TokenStream> {
96108
// Construct assertions that the arguments fulfill the necessary bounds.
@@ -124,12 +136,14 @@ fn process(function: &Function) -> Result<TokenStream> {
124136
// Adjust the function's body.
125137
let mut wrapped = function.item.clone();
126138
let name = function.name.to_string();
139+
let unique = quote! { __ComemoUnique };
140+
127141
wrapped.block = parse_quote! { {
128-
struct __ComemoUnique;
142+
struct #unique;
129143
#(#bounds;)*
130144
::comemo::internal::memoized(
131145
#name,
132-
::core::any::TypeId::of::<__ComemoUnique>(),
146+
::core::any::TypeId::of::<#unique>(),
133147
::comemo::internal::Args(#arg_tuple),
134148
#closure,
135149
)

0 commit comments

Comments
 (0)