pub use crate::{TransportFrom, TransportTo};
use core::marker::PhantomData;
use crate::{Pipe, StateMachine, StepInputOf};
mod private {
use super::{Pipe, StateMachine, StepInputOf};
pub(super) trait StepLaw<'message, Protocol: Pipe> {}
impl<'message, Machine, Protocol> StepLaw<'message, Protocol> for Machine
where
Machine: StateMachine,
Protocol: Pipe,
Protocol::In<'message>: StepInputOf<Machine, Outcome = Protocol::Out<'message>>,
{
}
}
#[doc(hidden)]
#[allow(private_bounds)]
pub trait StepsPipeInputToOutput<'message, Protocol: Pipe>:
StateMachine + private::StepLaw<'message, Protocol>
{
#[must_use = "pipe step outcomes must be routed or settled"]
#[doc(hidden)]
fn step_boundary(&mut self, input: Protocol::In<'message>) -> Protocol::Out<'message>;
}
impl<'message, Machine, Protocol> StepsPipeInputToOutput<'message, Protocol> for Machine
where
Machine: StateMachine,
Protocol: Pipe,
Protocol::In<'message>: StepInputOf<Machine, Outcome = Protocol::Out<'message>>,
{
fn step_boundary(&mut self, input: Protocol::In<'message>) -> Protocol::Out<'message> {
input.step(self)
}
}
pub struct Inline<Implementation, Protocol = Implementation> {
destination: Implementation,
protocol: PhantomData<fn() -> Protocol>,
}
impl<Implementation> Inline<Implementation> {
pub const fn new(destination: Implementation) -> Self {
Self {
destination,
protocol: PhantomData,
}
}
pub const fn for_pipe<Protocol: Pipe>(
destination: Implementation,
) -> Inline<Implementation, Protocol> {
Inline {
destination,
protocol: PhantomData,
}
}
}
impl<Implementation, Protocol> Inline<Implementation, Protocol> {
pub const fn destination(&self) -> &Implementation {
&self.destination
}
pub fn into_destination(self) -> Implementation {
self.destination
}
}
impl<Implementation, Protocol> TransportTo<Protocol> for Inline<Implementation, Protocol>
where
Protocol: Pipe,
Implementation: for<'message> StepsPipeInputToOutput<'message, Protocol>,
{
type Outcome<'transport, 'message>
= Protocol::Out<'message>
where
Self: 'transport;
fn send<'transport, 'message>(
&'transport mut self,
input: Protocol::In<'message>,
) -> Self::Outcome<'transport, 'message> {
self.destination.step_boundary(input)
}
}
#[cfg(test)]
mod tests {
use super::*;
struct Counter(u8);
impl StateMachine for Counter {}
struct Add(u8);
impl Pipe for Counter {
type In<'message> = Add;
type Out<'message> = u8;
}
impl StepInputOf<Counter> for Add {
type Outcome = u8;
fn step(self, counter: &mut Counter) -> Self::Outcome {
counter.0 = counter.0.saturating_add(self.0);
counter.0
}
}
#[test]
fn inline_transport_completes_the_precise_step() {
let mut transport = Inline::new(Counter(3));
assert_eq!(TransportTo::<Counter>::send(&mut transport, Add(4)), 7);
assert_eq!(transport.into_destination().0, 7);
}
}