I have two traits: Processor
and Persist
. The first one is responsible for processing some entity, the second one is for asynchronous persisting the processed entity.
Given the two traits I want to implement the trait ProcessPersist
taking care of both processing and persisting. Here is how it looks like and compiles fine
use async_trait::*;
trait Processor<T>{
type Output: Send; // <----------------------- Note Send here
fn process(&self, t: T) -> Self::Output;
}
#[async_trait]
trait Persist<T>{
async fn persist(&self, t: T) -> Result<(), ()>;
}
#[async_trait]
trait ProcessPersist<T>{
async fn process_persist(&self, t: T) -> Result<(), ()>;
}
#[async_trait]
impl<T, M> ProcessPersist<T> for M
where
T: Send + 'static,
M: Processor<T> + Send + Sync,
M: Persist<<M as Processor<T>>::Output>
{
async fn process_persist(&self, t: T) -> Result<(), ()> {
let out = self.process(t);
self.persist(out).await
}
}
PROBLEM: The thing that I'm trying to avoid is to remove the context bound type Output: Send
because this looks too restrictive. Instead, I'd like it to be specified in the trait ProcessPersist
implementation somehow.
Is it possible to do?
Simply removing Send
from the type Output
does not compile:
use async_trait::*;
trait Processor<T>{
type Output; // <----------------------- Send is removed
fn process(&self, t: T) -> Self::Output;
}
#[async_trait]
trait Persist<T>{
async fn persist(&self, t: T) -> Result<(), ()>;
}
#[async_trait]
trait ProcessPersist<T>{
async fn process_persist(&self, t: T) -> Result<(), ()>;
}
#[async_trait]
impl<T, M> ProcessPersist<T> for M
where
T: Send + 'static,
M: Processor<T> + Send + Sync,
M: Persist<<M as Processor<T>>::Output>
{
async fn process_persist(&self, t: T) -> Result<(), ()> {
let out = self.process(t);
self.persist(out).await
}
}
Error message:
error: future cannot be sent between threads safely
--> src/main.rs:47:61
|
47 | async fn process_persist(&self, t: T) -> Result<(), ()> {
| _____________________________________________________________^
48 | | let out = self.process(t);
49 | | self.persist(out).await
50 | | }
| |_____^ future returned by `__process_persist` is not `Send`
|
= help: within `impl core::future::future::Future`, the trait `std::marker::Send` is not implemented for `<M as Processor<T>>::Output`
note: future is not `Send` as this value is used across an await
--> src/main.rs:49:9
|
48 | let out = self.process(t);
| --- has type `<M as Processor<T>>::Output` which is not `Send`
49 | self.persist(out).await
| ^^^^^^^^^^^^^^^^^^^^^^^ await occurs here, with `out` maybe used later
50 | }
| - `out` is later dropped here
= note: required for the cast to the object type `dyn core::future::future::Future<Output = std::result::Result<(), ()>> + std::marker::Send`