I am having trouble understanding the exact lifetime issues that are being reported by the compiler here. I have the following playground with the following excerpt that is of interest:
#[async_trait::async_trait]
pub trait EventStore<A>: Clone + Send + EventRepository
where
A: Aggregate,
{async fn get_aggregates(
&self,
stream_ids: &[StreamId]
) -> Result<Vec<A>, EventSourceError<A::DomainError>> {
let mut threads: JoinSet<Result<A, Box<dyn std::error::Error + Send + Sync>>> =
JoinSet::new();
let mut aggs: Vec<A> = Vec::with_capacity(stream_ids.len());
for stream_id in stream_ids {
let event_store = self.clone();
let stream_id = stream_id.clone();
threads.spawn(async move {
event_store.get_aggregate(&stream_id).await.map_err(|x| {
let e: Box<dyn std::error::Error + Send + Sync> = x.into();
e
})
});
}
while let Some(res) = threads.join_next().await {
let result = res.map_err(|err| {
EventSourceError::EventStoreError(
err.into(),
"Couldn't join threads for eventstore reading",
)
})?;
match result {
Ok(paper) => aggs.push(paper),
Err(err) => return Err(EventSourceError::EventStoreError(err.into(), "")),
};
}
Ok(aggs)
}
The problem here is I am getting a bunch of lifetime errors ("&self,
| - the parameter type A
must be valid for the lifetime 'life0
as defined here...") because of the spawned threads.
I am in the middle of trying to create this trait with default implementations as otherwise the concrete implementations are basically always the same. I do not get these compiler issues when removing the default impl and instead manually implementing it.
I suspect it is something to do with the fact that self
in the trait call is similar to dyn EventStore<A>
and cloning is unsized or something but I cant quite get there in understanding the issue.
Is this something that cant have a default impl or otherwise what do I need to understand to get it?