Future is not Send, only when from async Trait - rust

I have a trait Serializer:
trait Serializer {
fn serialize(&self, data: Rc<()>) -> Result<(), Error>;
}
And some Foo which implements it. Notably, data is not Send.
The actual implementation requires an async context to execute, so I've split the creation of an async runtime away from the actual implementation, like so:
struct Foo {}
impl Foo {
async fn async_serialize(&self, _data: Rc<()>) -> Result<(), Error> {
unimplemented!();
}
}
impl Serializer for Foo {
fn serialize(&self, data: Rc<()>) -> Result<(), Error> {
let runtime = Builder::new_current_thread().enable_all().build().unwrap();
runtime.block_on(async move { self.async_serialize(data).await })
}
}
This compiles and works how I would expect.
Playground link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=04171e7fb65a9e158903978fd19ef8ac
If I refactor the code such that the async Runtime creation is done by way of a trait:
#[async_trait]
trait AsyncSerializer {
async fn async_serialize(&self, data: Rc<()>) -> Result<(), Error>;
}
#[async_trait]
impl AsyncSerializer for Foo {
async fn async_serialize(&self, _data: Rc<()>) -> Result<(), Error> {
unimplemented!();
}
}
This does not compile, now complaining that Rc<()> isn't Send:
error: future cannot be sent between threads safely
--> src/main.rs:19:73
|
19 | async fn async_serialize(&self, _data: Rc<()>) -> Result<(), Error> {
| _________________________________________________________________________^
20 | | unimplemented!();
21 | | }
| |_____^ future created by async block is not `Send`
|
= help: within `impl Future<Output = Result<(), anyhow::Error>>`, the trait `Send` is not implemented for `Rc<()>`
note: captured value is not `Send`
Playground link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=23f61162b5be8384092888635d8daacc
This error message makes sense to me, Rc is not Send, but:
Why was this not a problem before? The prior implementations (impl on Foo versus impl AsyncSerializer for Foo) look analogous to me.
Can I wrap data in some way to avoid this?

The way that #[async_trait] de-sugars your code requires your futures to be send, as explained here. To fix that change the attribute macro to be #[async_trait(?Send)].

Related

How to implement the same trait in multiple files/mods avoiding "conflicting implementations of trait" error?

In Golang I can define an interface like this:
type DBRepo interface {
PlayerByID(id uint64) (*domain.Player, error)
TeamByID(id uint64) (*domain.Team, error)
// many others
and I can implement them like this using different files:
// file: real_db.go
type RealDB struct {
db *realDB
}
// file: player.go
func (r RealDB) PlayerByID(id uint64) (*domain.Player, error) {
return r.db... // get from DB
}
// file: team.go
func (r RealDB) TeamByID(id uint64) (*domain.Team, error) {
return r.db... // get from DB
}
// many others (files and methods)
I cannot undestand how to do the same in Rust:
#[async_trait::async_trait]
pub trait DBRepo: Send + Sync {
async fn player_by_id(&self, id: i64) -> Result<()>;
async fn team_by_id(&self, id: i64) -> Result<()>;
}
but if I write the below code in different files (and different mods too):
// file: player.rs
#[async_trait::async_trait]
impl DBRepo for Repo {
async fn player_by_id(&self, id: i64) -> Result<()> {
Ok(()) // get from DB
}
}
// file: team.rs
#[async_trait::async_trait]
impl DBRepo for Repo {
async fn team_by_id(&self, id: i64) -> Result<()> {
Ok(()) // get from DB
}
}
I get from the compiler:
error[E0119]: conflicting implementations of trait `DBRepo` for type `Repo`
--> src\team.rs:22:1
|
22 | impl DBRepo for Repo {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Repo`
|
::: src\player.rs:22:1
|
22 | impl DBRepo for Repo {
| ----------------------------------- first implementation here
For more information about this error, try `rustc --explain E0119`.
How can I fix this?
I need to use all the methods on trait DBRepo, I cannot split it in many traits.
You could split up your DBRepo trait into multiple traits and define the DBRepo trait to require all the other traits.
#[async_trait::async_trait]
pub trait DBRepoPlayer: Send + Sync {
async fn player_by_id(&self, id: i64) -> Result<()>;
}
#[async_trait::async_trait]
pub trait DBRepoTeam: Send + Sync {
async fn team_by_id(&self, id: i64) -> Result<()>;
}
pub trait DBRepo: DBRepoPlayer + DBRepoTeam {}
impl<T: DBRepoPlayer + DBRepoTeam> DBRepo for T {}
then you implement the sub traits on the types:
// file: player.rs
#[async_trait::async_trait]
impl DBRepoPlayer for Repo {
async fn player_by_id(&self, id: i64) -> Result<()> {
Ok(()) // get from DB
}
}
// file: team.rs
#[async_trait::async_trait]
impl DBRepoTeam for Repo {
async fn team_by_id(&self, id: i64) -> Result<()> {
Ok(()) // get from DB
}
}
I know you said not to split up the trait but implementing the same trait for the same type multiple times is not possible in rust, neither is partial trait implementation.
You cannot partially implement a trait in rust. If you have some type Repo and want to implement DBRepo for that type, the entire trait implementation must be defined in the impl block.
For example, this example will fail even if you don't split it across files:
struct A;
trait Foo {
fn fn_1();
fn fn_2();
}
impl Foo for A {
fn fn_1() {}
}
impl Foo for A {
fn fn_2() {}
}
This fails with the error "conflicting implementation for A" as you are seeing in your example with multiple files. Even in the same file, this does not work.
If you just do:
struct A;
trait Foo {
fn fn_1();
fn fn_2();
}
impl Foo for A {
fn fn_1() {}
}
you will see you also get a compiler error: 'missing fn_2 in implementation".
Without splitting the trait into multiple traits, the only way to implement this is include the entire trait impl in one file:
#[async_trait::async_trait]
impl DBRepo for Repo {
async fn player_by_id(&self, id: i64) -> Result<()> {
Ok(()) // get from DB
}
async fn team_by_id(&self, id: i64) -> Result<()> {
Ok(()) // get from DB
}
}

Convert object from one trait to another with generics

The code I'm working on implements multiple traits for a few structs. There's a factory method that generates an object of one of these structs and returns it to my code. The object is returned as one of these traits, but I want to use a method of a trait that has a generic in it.
This code illustrates my problem:
struct Data {
some_data: String
}
struct Data2 {
some_data: i32
}
trait PrintableData {
fn print(&mut self);
}
trait ConsumableData {
fn consume<Callback>(&self, callback: Callback)
where
Callback: FnMut(String);
}
impl Data {
fn new(data: String) -> Self {
Data {
some_data: data
}
}
}
impl Data2 {
fn new(data: i32) -> Self {
Data2 {
some_data: data
}
}
}
impl PrintableData for Data {
fn print(&mut self) {
println!("{}", self.some_data);
}
}
impl PrintableData for Data2 {
fn print(&mut self) {
println!("{}", self.some_data);
}
}
impl ConsumableData for Data {
fn consume<Callback>(&self, mut callback: Callback) where Callback: FnMut(String) {
callback(self.some_data.clone());
}
}
impl ConsumableData for Data2 {
fn consume<Callback>(&self, mut callback: Callback) where Callback: FnMut(String) {
callback(self.some_data.to_string());
}
}
fn factory(data_type: i32) -> Box<dyn PrintableData> {
match data_type {
1 => Box::new(Data::new(String::from("123"))),
2 => Box::new(Data2::new(123)),
_ => panic!("panic")
}
}
fn main() {
let callback = |s: String| {};
for data_type in 1..3 {
let d = factory(data_type);
(d as Box<dyn ConsumableData>).consume(callback);
}
}
In short, the factory function returns either Data or Data2 as PrintableData, but I need to use the object as ConsumableData, which has a generic method implemented in it.
Running this code generates the following error:
error[E0038]: the trait `ConsumableData` cannot be made into an object
--> src/main.rs:72:15
|
72 | (d as Box<dyn ConsumableData>).consume(callback);
| ^^^^^^^^^^^^^^^^^^^^^^^ `ConsumableData` 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/main.rs:14:8
|
13 | trait ConsumableData {
| -------------- this trait cannot be made into an object...
14 | fn consume<Callback>(&self, callback: Callback)
| ^^^^^^^ ...because method `consume` has generic type parameters
= help: consider moving `consume` to another trait
First you need to make ConsumableData object safe, so you will be able to work with it.
We can take a lesson from Iterator here: it has some non-object-safe methods that take self, for example map(). Still, it is object safe and you can work with dyn Iterator pretty conveniently. The secret sauce is three-staged:
Have a core method that is object-safe (Iterator::next()).
Implement all other methods in terms of it (possibly allow to specialize them for optimization, too).
Have a blanket implementation that forwards the implementation on references (and Box).
Now, for regular objects you can just call the non-object-safe methods directly. But when working with dyn Iterator, you don't call, say, <dyn Iterator>::map(), because it is not object safe - rather, you call <&mut dyn Iterator>::map(). This is perfectly fine, since &mut dyn Iterator is Sized. This method forwards the actual work to <&mut dyn Iterator>::next() (by its default implementation), and it in turn forwards it into the actual <dyn Iterator>::next() - which it can, since next() is object safe!
We can make consume() object safe by changing it from taking a generic to take &mut dyn FnMut:
trait ConsumableData {
fn consume_dyn(&self, callback: &mut dyn FnMut(String));
fn consume<Callback>(&self, mut callback: Callback)
where
Callback: FnMut(String),
Self: Sized,
{
self.consume_dyn(&mut callback)
}
}
And the blanket implementations:
impl<T: ?Sized + ConsumableData> ConsumableData for &'_ T {
fn consume_dyn(&self, callback: &mut dyn FnMut(String)) {
T::consume_dyn(&**self, callback)
}
}
impl<T: ?Sized + ConsumableData> ConsumableData for &'_ mut T {
fn consume_dyn(&self, callback: &mut dyn FnMut(String)) {
T::consume_dyn(&**self, callback)
}
}
impl<T: ?Sized + ConsumableData> ConsumableData for Box<T> {
fn consume_dyn(&self, callback: &mut dyn FnMut(String)) {
T::consume_dyn(&**self, callback)
}
}
Now implementors should implement (only or not, depends on the require performance characteristics) consume_dyn(), but they get consume() for free.
The last component is how to convert from Box<dyn PrintableData> to Box<dyn ConsumableData>. This can be done by providing a method in the PrintableData trait for that:
trait PrintableData {
// ...
fn into_consumable_data(self: Box<Self>) -> Box<dyn ConsumableData>;
}
impl PrintableData for Data {
// ...
fn into_consumable_data(self: Box<Self>) -> Box<dyn ConsumableData> {
self
}
}
impl PrintableData for Data2 {
// ...
fn into_consumable_data(self: Box<Self>) -> Box<dyn ConsumableData> {
self
}
}
Then finally:
let d = factory(data_type);
d.into_consumable_data().consume(callback);
Playground.

How to downcast mutable structs not as references

I have this trait and implementation:
#[async_trait]
pub trait AsyncKeyProvider {
async fn get_key_async(&mut self, key_id: &str) -> Result<Option<Jwk>, ()>;
fn as_any(&self) -> &dyn Any;
}
#[async_trait]
impl AsyncKeyProvider for GoogleKeyProvider {
async fn get_key_async(&mut self, key_id: &str) -> Result<Option<Jwk>, ()> {
{...}
}
fn as_any(&self) -> &dyn Any {
self
}
}
In order to pass it into my handler in actix-web, I'm passing through a GoogleKeyProvider like this:
let key_provider = web::Data::from(Arc::new(GoogleKeyProvider::default()));
let server = HttpServer::new(move || {
App::new()
.app_data(key_provider.clone())
.route("/validate", web::post().to(validate))
})
With the handler doing this:
pub async fn validate(jwt_body: web::Json<JwtBody>, provider: web::Data<Box<dyn AsyncKeyProvider>>) -> impl Responder {
let provider_object: &GoogleKeyProvider = provider.as_any().downcast_ref::<GoogleKeyProvider>().expect("Wasn't a GoogleKeyProvider");
match validate_jwt(&jwt_body.jwt, provider_object).await {
{...}
}
}
validate_jwt then tries to call a method on the provider struct like this:
async fn validate_jwt(jwt: &String, provider: &GoogleKeyProvider) -> Result<bool, Box<dyn std::error::Error>> {
let key_to_use = provider.get_key_async(<thing>).await.unwrap();
}
Which presents me with this error:
error[E0596]: cannot borrow `*provider` as mutable, as it is behind a `&` reference
--> src\routes\validate.rs:48:22
|
48 | let key_to_use = provider.get_key_async(<thing>).await.unwrap();
| ^^^^^^^^ `provider` is a `&` reference, so the data it refers to cannot be borrowed as mutable
As far as I can understand, this is happening because the result of my downcasting is a reference (due to downcast_ref), but I think I'd be wanting the plain GoogleKeyProvider type instead - I'm not sure on that though. I believe the provider needs to be mutable as the values inside it (see below) can change during the lifetime of the provider (it's intended to provide a temporary cache for some keys, and automatically update them if they're out of date)
#[derive(Clone)]
pub struct GoogleKeyProvider {
cached: Option<JwkSet>,
expiration_time: Instant,
}
I'm not sure how to get this working with downcasting, though. Is anyone able to help me see where I've gone wrong?
You have to choice if get_key_async update somme thing at the struct.
The simple code below show you the error
trait Atrait {
fn afn(&mut self) -> i32;
}
struct Astruct {}
impl Atrait for Astruct {
fn afn(&mut self) -> i32 {
2
}
}
fn main()
{
// test should be mutable
let test = Astruct{};
let value = test.afn();
println!("Value {}", value);
}
This work because afn(self) is not declared mutable afn(&mut self)
trait Atrait {
fn afn(&self) -> i32;
}
struct Astruct {}
impl Atrait for Astruct {
fn afn(&self) -> i32 {
2
}
}
fn main()
{
let test = Astruct{};
let value = test.afn();
println!("Value {}", value);
}

How to tell the compiler a value is not used after awaiting in an async_trait method?

In the example code below, a non-send value, Vec<T>, is moved into a function that returns something else. At this point, I no longer care about that vector. The returned object stores no reference to it, it no longer exists.
However, when I .await on the next line I get the error "captured value is not Send". Which it isn't, but since it should have been destroyed when vector_as_string exited, it doesn't need to send it across threads when the future restarts, because that variable is never used again.
use async_trait::async_trait;
async fn write_value(value: Vec<u8>) {
println!("something")
}
fn vector_as_string<T>(vec: Vec<T>) -> Vec<u8> {
Vec::new()
}
#[async_trait]
trait Writer {
async fn write_array<T>(&mut self, value: Vec<T>);
}
pub struct WriterImplementation {}
#[async_trait]
impl Writer for WriterImplementation {
async fn write_array<T>(&mut self, value: Vec<T>) {
let string = vector_as_string(value);
write_value(string).await
}
}
#[tokio::main]
async fn main() {
println!("Hi");
}
Dependencies:
[dependencies]
tokio = { version = "1.9.0", features = ["full"]}
async-trait = "0.1.51"
Error:
error: future cannot be sent between threads safely
--> src/main.rs:20:55
|
20 | async fn write_array<T>(&mut self, value: Vec<T>) {
| _______________________________________________________^
21 | | let string = vector_as_string(value);
22 | |
23 | | write_value(string).await
24 | | }
| |_____^ future created by async block is not `Send`
|
note: captured value is not `Send`
--> src/main.rs:20:40
|
20 | async fn write_array<T>(&mut self, value: Vec<T>) {
| ^^^^^ has type `Vec<T>` which is not `Send`
= note: required for the cast to the object type `dyn Future<Output = ()> + Send`
help: consider further restricting this bound
|
20 | async fn write_array<T + std::marker::Send>(&mut self, value: Vec<T>) {
| ^^^^^^^^^^^^^^^^^^^
Adding T: Send as it suggests allows it to compile, but why does T need to be Send if we aren't holding any T's across the await, as it has already been moved?
From the async_trait documentation:
Async fns get transformed into methods that return Pin<Box<dyn Future + Send + 'async>> and delegate to a private async freestanding function.
Not all async traits need futures that are dyn Future + Send. To avoid having Send and Sync bounds placed on the async trait methods, invoke the async trait macro as #[async_trait(?Send)] on both the trait and the impl blocks.
Applied to your case:
#[async_trait(?Send)]
trait Writer {
async fn write_array<T>(&mut self, value: Vec<T>);
}
#[async_trait(?Send)]
impl Writer for WriterImplementation {
async fn write_array<T>(&mut self, value: Vec<T>) {
let string = vector_as_string(value);
write_value(string).await
}
}

How to implement an error wrapper for all existing Errors?

I want to use my customised error type in all functions and I need to wrap the existing standard errors so that the ? operator will succeed.
Here is what I am doing:
use std::{error::Error, fmt, fs};
#[derive(Debug)]
enum MyError {
A,
B,
}
impl fmt::Display for MyError {
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
Ok(())
}
}
impl Error for MyError {
fn description(&self) -> &str {
""
}
}
trait NotMyError {}
impl<T: NotMyError + Error> From<T> for MyError {
fn from(_: T) -> MyError {
MyError::A
}
}
fn test() -> Result<(), MyError> {
fs::read_dir("test")?;
Ok(())
}
fn main() {}
The compiler complains:
error[E0277]: the trait bound `std::io::Error: NotMyError` is not satisfied
--> src/main.rs:30:5
|
30 | fs::read_dir("test")?;
| ^^^^^^^^^^^^^^^^^^^^^ the trait `NotMyError` is not implemented for `std::io::Error`
|
= note: required because of the requirements on the impl of `std::convert::From<std::io::Error>` for `MyError`
= note: required by `std::convert::From::from`
There's an excellent post about it. To get first-class support for your error you need to do two things:
Implement the Error trait for your type.
Implement std::convert::From for error types you want to use seamlessly with the ? operator (the quick_error crate helps automate this).

Resources