pub use crate::Transport;
use crate::{
Circuit, Participant, StateMachine, StepInputOf, Switchboard, TurnContext, TurnObserver,
};
mod private {
use super::{Participant, StateMachine, StepInputOf};
pub(super) trait StepLaw<'message> {}
impl<'message, Machine> StepLaw<'message> for Machine
where
Machine: StateMachine + Participant,
Machine::In<'message>: StepInputOf<Machine, Outcome = Machine::Out<'message>>,
{
}
}
#[doc(hidden)]
#[allow(private_bounds)]
pub trait StepsParticipantInputToOutput<'message>:
StateMachine + Participant + private::StepLaw<'message>
{
#[must_use = "participant step outcomes must be routed or settled"]
#[doc(hidden)]
fn step_boundary<Observer: TurnObserver>(
&mut self,
input: Self::In<'message>,
turn: &mut TurnContext<Observer>,
) -> Self::Out<'message>;
}
impl<'message, Machine> StepsParticipantInputToOutput<'message> for Machine
where
Machine: StateMachine + Participant,
Machine::In<'message>: StepInputOf<Machine, Outcome = Machine::Out<'message>>,
{
#[inline(always)]
fn step_boundary<Observer: TurnObserver>(
&mut self,
input: Self::In<'message>,
turn: &mut TurnContext<Observer>,
) -> Self::Out<'message> {
turn.step(self, input)
}
}
pub struct Inline<Machine> {
destination: Machine,
}
impl<Machine> Inline<Machine> {
#[inline(always)]
pub const fn new(destination: Machine) -> Self {
Self { destination }
}
#[inline(always)]
pub const fn destination(&self) -> &Machine {
&self.destination
}
#[inline(always)]
pub fn into_destination(self) -> Machine {
self.destination
}
}
impl<Machine> Transport<Machine> for Inline<Machine>
where
Machine: for<'message> StepsParticipantInputToOutput<'message>,
{
type Outcome<'transport, 'message>
= Machine::Out<'message>
where
Self: 'transport;
#[inline(always)]
fn transport<'transport, 'message>(
&'transport mut self,
input: Machine::In<'message>,
turn: &mut TurnContext<impl TurnObserver>,
) -> Self::Outcome<'transport, 'message> {
self.destination.step_boundary(input, turn)
}
}
pub struct InlineSwitchboard<Board> {
destination: Board,
}
impl<Board> InlineSwitchboard<Board> {
#[inline(always)]
pub const fn new(destination: Board) -> Self {
Self { destination }
}
#[inline(always)]
pub const fn destination(&self) -> &Board {
&self.destination
}
#[inline(always)]
pub fn into_destination(self) -> Board {
self.destination
}
}
impl<Board: Switchboard> Transport<Board> for InlineSwitchboard<Board> {
type Outcome<'transport, 'message>
= Board::Out<'message>
where
Self: 'transport;
#[inline(always)]
fn transport<'transport, 'message>(
&'transport mut self,
input: Board::In<'message>,
turn: &mut TurnContext<impl TurnObserver>,
) -> Self::Outcome<'transport, 'message> {
turn.route(&mut self.destination, input)
}
}
pub struct InlineCircuit<InstalledCircuit> {
destination: InstalledCircuit,
}
impl<InstalledCircuit> InlineCircuit<InstalledCircuit> {
#[inline(always)]
pub const fn new(destination: InstalledCircuit) -> Self {
Self { destination }
}
#[inline(always)]
pub const fn destination(&self) -> &InstalledCircuit {
&self.destination
}
#[inline(always)]
pub fn into_destination(self) -> InstalledCircuit {
self.destination
}
}
impl<InstalledCircuit: Circuit> Transport<InstalledCircuit> for InlineCircuit<InstalledCircuit> {
type Outcome<'transport, 'message>
= InstalledCircuit::Out<'message>
where
Self: 'transport;
#[inline(always)]
fn transport<'transport, 'message>(
&'transport mut self,
input: InstalledCircuit::In<'message>,
turn: &mut TurnContext<impl TurnObserver>,
) -> Self::Outcome<'transport, 'message> {
self.destination.turn_in_context(input, turn)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{NoopTurnObserver, TurnContext};
struct Counter(u8);
impl StateMachine for Counter {}
struct Add(u8);
impl Participant 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));
let mut turn = TurnContext::new(NoopTurnObserver);
assert_eq!(
Transport::<Counter>::transport(&mut transport, Add(4), &mut turn),
7
);
assert_eq!(transport.into_destination().0, 7);
}
}