I have a backend component that can be one of any number of persistent and durable storage. That looks like a good candidate for a trait. However, one of the storages can be indexDB, and it looks like the APIs are either an async/await (rexie crate) or callback (web-sys crate).
Looks like async in traits is not a feature in stable.
I'm trying out #![feature(async_fn_in_trait)]
in nightly, and according to this announcement post, I should be able to do this:
// storage/mod.rs
pub trait Adaptor {
async fn fetch_data(&self) -> String;
}
// storage/indexeddb.rs
pub struct IndexedDb {
// ...some fields
}
impl Adaptor for IndexedDb {
async fn fetch_data(&self) -> String {
format!("Hello from IndexedDb")
}
}
However, when I compile, I get:
error[E0038]: the trait `Adaptor` cannot be made into an object
--> src/indicies.rs:123:16
|
123 | store: Box<dyn Adaptor>,
| ^^^^^^^^^^^ `Adaptor` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> src/storage/mod.rs:14:14
|
13 | pub trait Adaptor {
| ------- this trait cannot be made into an object...
14 | async fn fetch_data(&self) -> String;
| ^^^^^^^^^^ ...because method `fetch_data` is `async`
= help: consider moving `fetch_data` to another trait
For more information about this error, try `rustc --explain E0038`.
I'm running
➜ rustc --version
rustc 1.70.0-nightly (39f2657d1 2023-03-09)
➜ rustup default
nightly-aarch64-apple-darwin (default)
However, I was able to get a static method on the trait to compile if it had where Self: Sized
bound is attached to the method.
Question 1: Is async_fn_in_trait
only working for static async methods? Or should it be working for regular methods as well? According to the announcement post, it seems like it should be.
Question 2: Taking a step back, is there a way around this without async traits?