use std::future::Future;
use crate::{ConnectionTo, role::Role};
pub trait RunWithConnectionTo<Counterpart: Role>: Send {
fn run_with_connection_to(
self,
cx: ConnectionTo<Counterpart>,
) -> impl Future<Output = Result<(), crate::Error>> + Send;
}
#[derive(Debug, Default)]
pub struct NullRun;
impl<Counterpart: Role> RunWithConnectionTo<Counterpart> for NullRun {
async fn run_with_connection_to(
self,
_cx: ConnectionTo<Counterpart>,
) -> Result<(), crate::Error> {
Ok(())
}
}
#[derive(Debug)]
pub struct ChainRun<A, B> {
a: A,
b: B,
}
impl<A, B> ChainRun<A, B> {
pub fn new(a: A, b: B) -> Self {
Self { a, b }
}
}
impl<Counterpart: Role, A, B> RunWithConnectionTo<Counterpart> for ChainRun<A, B>
where
A: RunWithConnectionTo<Counterpart>,
B: RunWithConnectionTo<Counterpart>,
{
async fn run_with_connection_to(
self,
cx: ConnectionTo<Counterpart>,
) -> Result<(), crate::Error> {
let a_fut = Box::pin(self.a.run_with_connection_to(cx.clone()));
let b_fut = Box::pin(self.b.run_with_connection_to(cx.clone()));
let ((), ()) = futures::future::try_join(a_fut, b_fut).await?;
Ok(())
}
}
pub struct SpawnedRun<F> {
task_fn: F,
location: &'static std::panic::Location<'static>,
}
impl<F> SpawnedRun<F> {
pub fn new(location: &'static std::panic::Location<'static>, task_fn: F) -> Self {
Self { task_fn, location }
}
}
impl<Counterpart, F, Fut> RunWithConnectionTo<Counterpart> for SpawnedRun<F>
where
Counterpart: Role,
F: FnOnce(ConnectionTo<Counterpart>) -> Fut + Send,
Fut: Future<Output = Result<(), crate::Error>> + Send,
{
async fn run_with_connection_to(
self,
connection: ConnectionTo<Counterpart>,
) -> Result<(), crate::Error> {
let location = self.location;
(self.task_fn)(connection).await.map_err(|err| {
let data = err.data.clone();
err.data(serde_json::json! {
{
"spawned_at": format!("{}:{}:{}", location.file(), location.line(), location.column()),
"data": data,
}
})
})
}
}