use crate::{InPipe, OutPipe, StateMachine, StepInputOf};
mod private {
use super::{InPipe, OutPipe, StateMachine, StepInputOf};
pub(super) trait TurnLaw<'message, Input: InPipe, Output: OutPipe> {}
impl<'message, Machine, Input, Output> TurnLaw<'message, Input, Output> for Machine
where
Machine: StateMachine,
Input: InPipe,
Output: OutPipe,
Input::In<'message>: StepInputOf<Machine, Outcome = Output::Out<'message>>,
{
}
}
#[doc(hidden)]
#[allow(private_bounds)]
pub trait TurnsCircuitInPipeToOutPipe<'message, Input: InPipe, Output: OutPipe>:
StateMachine + private::TurnLaw<'message, Input, Output>
{
#[must_use = "circuit turn outcomes must be delivered or settled"]
#[doc(hidden)]
fn turn_boundary(&mut self, input: Input::In<'message>) -> Output::Out<'message>;
}
impl<'message, Machine, Input, Output> TurnsCircuitInPipeToOutPipe<'message, Input, Output>
for Machine
where
Machine: StateMachine,
Input: InPipe,
Output: OutPipe,
Input::In<'message>: StepInputOf<Machine, Outcome = Output::Out<'message>>,
{
#[inline(always)]
fn turn_boundary(&mut self, input: Input::In<'message>) -> Output::Out<'message> {
self.step(input)
}
}
pub trait Circuit:
StateMachine + for<'message> TurnsCircuitInPipeToOutPipe<'message, Self::InPipe, Self::OutPipe>
{
type InPipe: InPipe;
type OutPipe: OutPipe;
#[must_use = "circuit turn outcomes must be delivered or settled"]
#[inline(always)]
fn turn<'message>(
&mut self,
input: <Self::InPipe as InPipe>::In<'message>,
) -> <Self::OutPipe as OutPipe>::Out<'message> {
<Self as TurnsCircuitInPipeToOutPipe<'message, Self::InPipe, Self::OutPipe>>::turn_boundary(
self, input,
)
}
}
#[cfg(test)]
mod tests {
use super::*;
struct TestCircuit;
struct TestInPipe;
struct TestOutPipe;
impl StateMachine for TestCircuit {}
impl InPipe for TestInPipe {
type In<'message> = u8;
}
impl OutPipe for TestOutPipe {
type Out<'message> = u16;
}
impl StepInputOf<TestCircuit> for u8 {
type Outcome = u16;
fn step(self, _circuit: &mut TestCircuit) -> Self::Outcome {
u16::from(self)
}
}
impl Circuit for TestCircuit {
type InPipe = TestInPipe;
type OutPipe = TestOutPipe;
}
#[test]
fn circuit_turn_steps_between_its_declared_boundary_pipes() {
assert_eq!(TestCircuit.turn(7), 7);
}
}