This, at its core, is an API issue: that (async) .get_or_insert_with() does not allow for a "fallible thunk" (a Result-outputting Future).
One (ugly) option, but which does not require any extra API whatsoever, would be to yield a dummy "successful" value, and expressing the error through a captured flag which is accessible outside. This way you get to know that you have to bail:
let mut errored = None;
let cached_member: GuildMember = MEMBERS_MEM_CACHE
.get()
.unwrap()
.get_or_insert_with((member.guild_id.0, member.user.id.0), async {
match query_db_for_member_or_return_current(&member).await {
Ok(v) => {
if !v.1 { member_was_cached = false; };
v.0
}
Err(e) => {
errored = Some(anyhow!(e));
produce_some_dummy_value()
},
}
})
.await
;
if let Some(e) = errored { return Err(e); }
/* … */
Ok(())
A way cleaner option would be to have the MEMBERS_MEM_CACHE feature a .get_or_try_insert_with kind of API that would allow you to cleanly achieve what you seek.
In order to explore these better solutions, however, we need to know the exact API you are facing: what is the type of MEMBERS_MEM_CACHE? From which crate?
let mut member_was_cached = true;
let cached_member: GuildMember = MEMBERS_MEM_CACHE
.get()
.unwrap()
.get_or_try_insert_with((member.guild_id.0, member.user.id.0), async {
let v = query_db_for_member_or_return_current(&member).await?;
if !v.1 { member_was_cached = false; };
Ok(v.0)
}
)
.await;
It seems to want a result, but when I give it a result then it wants GuildMember. Hmm. Here is the compiler error from this code:
error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> src/lib/member.rs:45:73
|
44 | .get_or_try_insert_with((member.guild_id.0, member.user.id.0), async {
| ______________________________________________________________________________-
45 | | let v = query_db_for_member_or_return_current(&member).await?;
| | ^ cannot use the `?` operator in an async block that returns `GuildMember`
46 | | if !v.1 { member_was_cached = false; };
47 | | v.0
48 | |
49 | | }
| |_________- this function should return `Result` or `Option` to accept `?`
|
= help: the trait `FromResidual<Result<Infallible, anyhow::Error>>` is not implemented for `GuildMember`
= note: required by `from_residual`