use core::any::type_name;
use crate::{
Participant, Pipe, StateMachine, StepInputOf, Switchboard, Transport, TurnObservation,
TurnObserver,
};
pub struct TurnContext<Observer> {
observer: Observer,
}
impl<Observer> TurnContext<Observer> {
pub const fn new(observer: Observer) -> Self {
Self { observer }
}
pub const fn observer(&self) -> &Observer {
&self.observer
}
pub const fn observer_mut(&mut self) -> &mut Observer {
&mut self.observer
}
pub fn into_observer(self) -> Observer {
self.observer
}
}
impl<Observer: TurnObserver> TurnContext<Observer> {
#[must_use = "pipe outcomes must be routed or settled"]
#[inline(always)]
pub fn send<'transport, 'message, Destination, InstalledTransport>(
&mut self,
pipe: &'transport mut Pipe<Destination, InstalledTransport>,
input: Destination::In<'message>,
) -> InstalledTransport::Outcome<'transport, 'message>
where
Destination: Participant,
InstalledTransport: Transport<Destination>,
{
self.observer.observe(TurnObservation::PipeSendBegan {
participant: type_name::<Destination>(),
input: type_name::<Destination::In<'message>>(),
transport: type_name::<InstalledTransport>(),
});
let outcome = pipe.installed_transport_mut().transport(input, self);
self.observer.observe(TurnObservation::PipeSendCompleted {
participant: type_name::<Destination>(),
transport: type_name::<InstalledTransport>(),
outcome: type_name::<InstalledTransport::Outcome<'transport, 'message>>(),
});
outcome
}
#[must_use = "participant step outcomes must be routed or settled"]
#[inline(always)]
pub fn step<Machine, Input>(&mut self, machine: &mut Machine, input: Input) -> Input::Outcome
where
Machine: StateMachine,
Input: StepInputOf<Machine>,
{
self.observer
.observe(TurnObservation::ParticipantStepBegan {
participant: type_name::<Machine>(),
input: type_name::<Input>(),
});
let outcome = machine.step(input);
self.observer
.observe(TurnObservation::ParticipantStepCompleted {
participant: type_name::<Machine>(),
outcome: type_name::<Input::Outcome>(),
});
outcome
}
#[must_use = "switchboard route outcomes must be routed or settled"]
#[inline(always)]
pub fn route<'message, Board: Switchboard>(
&mut self,
switchboard: &mut Board,
input: <Board as Participant>::In<'message>,
) -> <Board as Participant>::Out<'message> {
self.observer
.observe(TurnObservation::SwitchboardRouteBegan {
switchboard: type_name::<Board>(),
input: type_name::<<Board as Participant>::In<'message>>(),
});
let output = switchboard.route(input);
self.observer
.observe(TurnObservation::SwitchboardRouteCompleted {
switchboard: type_name::<Board>(),
output: type_name::<<Board as Participant>::Out<'message>>(),
});
output
}
}