Closed mhvelplund closed 1 year ago
The error is coming from the fact that the macro needs to define an inner duplicate function so the code can be conditionally executed. In this case, the macro ends up generating something like this
static CACHE = ...;
async fn read_user<D>(client: Arc<D>, user_id: String) -> Result<User, DataStoragePlatformError>
where
D: DynamoDbClient + Send + Sync,
{
async fn read_user_inner<D>(client: Arc<D>, user_id: String) -> Result<User, DataStoragePlatformError>
where
D: DynamoDbClient + Send + Sync,
{
// function logic moved here so it can be conditionally executed
client.read_user(&user_id).await
}
let key = user_id.clone();
if let Some(cached) = CACHE.get(key) {
Ok(cached)
else {
let new = read_user_inner(...).await;
// caching the full result. If you don't want this to happen
// and instead only want to cache `Ok`s, then add `result = true` to macro args
CACHE.insert(key, new.clone());
new
}
}
And that causes the
| | type parameter from outer function
| help: try using a local generic parameter instead: `read_user<D, D>`
I'm not sure if it's possible, but the proc macro may be able to take this into account and use a "local generic parameter" in the inner function definition when the signature has generics defined (https://docs.rs/syn/latest/syn/struct.Signature.html).
Until then, the only solution would be to not use a generic. You could try using a dyn trait instead if you need to support multiple implementations of client
It should be possible to cache generic functions in theory but Rust doesn't yet support generic static items, which is the hold-up here AFAICT. I think Rust might eventually support it natively but for now it's definitely not possible.
In the meantime, I've written a crate that does exactly this with a minor runtime cost. Have a look at generic singleton. It should do exactly what you need.
Thanks for the feedback :)
I have a method that looks roughly like this:
When I compile i get the following error that doesn't make sens to me:
I'm guessing that the macro generates some code that is somehow syntactically incorrect, but I'm uncertain if there is a way to rewrite this so it would work? Stripping generics would be hard since it's supposed to work with both a mock and a real implementation.