use super::*;
trait AsyncOp<K: FutureForm> {
fn run<'a>(&'a self, input: &'a str) -> K::Future<'a, String>;
}
struct EchoOp;
impl AsyncOp<Sendable> for EchoOp {
fn run<'a>(&'a self, input: &'a str) -> BoxFuture<'a, String> {
let s = input.to_string();
Sendable::from_future(async move { s })
}
}
impl AsyncOp<Local> for EchoOp {
fn run<'a>(&'a self, input: &'a str) -> LocalBoxFuture<'a, String> {
let s = input.to_string();
Local::from_future(async move { s })
}
}
trait Pipeline<K: FutureForm> {
fn execute<'a>(&'a self, input: &'a str) -> K::Future<'a, String>;
}
struct SimplePipeline<S> {
op: S,
}
#[future_form(Sendable, Local)]
impl<K: FutureForm, S: AsyncOp<K>> Pipeline<K> for SimplePipeline<S> {
fn execute<'a>(&'a self, input: &'a str) -> K::Future<'a, String> {
self.op.run(input)
}
}
#[tokio::test]
async fn test_inline_k_bound_sendable() {
let pipeline = SimplePipeline { op: EchoOp };
let result = <SimplePipeline<EchoOp> as Pipeline<Sendable>>::execute(&pipeline, "hello").await;
assert_eq!(result, "hello");
}
#[tokio::test]
async fn test_inline_k_bound_local() {
let pipeline = SimplePipeline { op: EchoOp };
let result = <SimplePipeline<EchoOp> as Pipeline<Local>>::execute(&pipeline, "hello").await;
assert_eq!(result, "hello");
}
trait Listener<K: FutureForm> {
#[allow(dead_code)]
fn notify(&self) -> K::Future<'_, ()>;
}
struct NoopListener;
impl Listener<Sendable> for NoopListener {
fn notify(&self) -> BoxFuture<'_, ()> {
Sendable::from_future(async {})
}
}
impl Listener<Local> for NoopListener {
fn notify(&self) -> LocalBoxFuture<'_, ()> {
Local::from_future(async {})
}
}
trait Orchestrator<K: FutureForm> {
fn process<'a>(&'a self, input: &'a str) -> K::Future<'a, String>;
}
struct FullOrchestrator<S, L> {
op: S,
_listener: L,
}
#[future_form(Sendable, Local)]
impl<K: FutureForm, S: AsyncOp<K>, L: Listener<K>> Orchestrator<K> for FullOrchestrator<S, L> {
fn process<'a>(&'a self, input: &'a str) -> K::Future<'a, String> {
self.op.run(input)
}
}
#[tokio::test]
async fn test_multiple_inline_k_bounds_sendable() {
let orch = FullOrchestrator {
op: EchoOp,
_listener: NoopListener,
};
let result =
<FullOrchestrator<EchoOp, NoopListener> as Orchestrator<Sendable>>::process(&orch, "world")
.await;
assert_eq!(result, "world");
}
#[tokio::test]
async fn test_multiple_inline_k_bounds_local() {
let orch = FullOrchestrator {
op: EchoOp,
_listener: NoopListener,
};
let result =
<FullOrchestrator<EchoOp, NoopListener> as Orchestrator<Local>>::process(&orch, "world")
.await;
assert_eq!(result, "world");
}
trait MixedBounds<K: FutureForm> {
fn run<'a>(&'a self, input: &'a str) -> K::Future<'a, String>;
}
struct MixedPipeline<S, L> {
op: S,
_listener: L,
}
#[future_form(Sendable, Local)]
impl<K: FutureForm, S: AsyncOp<K>, L> MixedBounds<K> for MixedPipeline<S, L>
where
L: Listener<K>,
{
fn run<'a>(&'a self, input: &'a str) -> K::Future<'a, String> {
self.op.run(input)
}
}
#[tokio::test]
async fn test_mixed_inline_and_where_k_bounds_sendable() {
let p = MixedPipeline {
op: EchoOp,
_listener: NoopListener,
};
let result =
<MixedPipeline<EchoOp, NoopListener> as MixedBounds<Sendable>>::run(&p, "mixed").await;
assert_eq!(result, "mixed");
}
#[tokio::test]
async fn test_mixed_inline_and_where_k_bounds_local() {
let p = MixedPipeline {
op: EchoOp,
_listener: NoopListener,
};
let result =
<MixedPipeline<EchoOp, NoopListener> as MixedBounds<Local>>::run(&p, "mixed").await;
assert_eq!(result, "mixed");
}