use core::fmt;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[must_use = "turn observations must be recorded or explicitly discarded"]
pub enum TurnObservation {
CircuitTurnBegan {
circuit: &'static str,
input: &'static str,
},
CircuitTurnCompleted {
circuit: &'static str,
output: &'static str,
},
PipeSendBegan {
participant: &'static str,
input: &'static str,
transport: &'static str,
},
PipeSendCompleted {
participant: &'static str,
transport: &'static str,
outcome: &'static str,
},
ParticipantStepBegan {
participant: &'static str,
input: &'static str,
},
ParticipantStepCompleted {
participant: &'static str,
outcome: &'static str,
},
SwitchboardRouteBegan {
switchboard: &'static str,
input: &'static str,
},
SwitchboardRouteCompleted {
switchboard: &'static str,
output: &'static str,
},
}
pub trait TurnObserver {
fn observe(&mut self, observation: TurnObservation);
}
impl<Observer: TurnObserver + ?Sized> TurnObserver for &mut Observer {
#[inline(always)]
fn observe(&mut self, observation: TurnObservation) {
(**self).observe(observation);
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct NoopTurnObserver;
impl TurnObserver for NoopTurnObserver {
#[inline(always)]
fn observe(&mut self, _observation: TurnObservation) {}
}
impl fmt::Display for TurnObservation {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::CircuitTurnBegan { circuit, input } => write!(
formatter,
"circuit-turn-began circuit={circuit} input={input}"
),
Self::CircuitTurnCompleted { circuit, output } => write!(
formatter,
"circuit-turn-completed circuit={circuit} output={output}"
),
Self::PipeSendBegan {
participant,
input,
transport,
} => write!(
formatter,
"pipe-send-began participant={participant} input={input} transport={transport}"
),
Self::PipeSendCompleted {
participant,
transport,
outcome,
} => write!(
formatter,
"pipe-send-completed participant={participant} transport={transport} outcome={outcome}"
),
Self::ParticipantStepBegan { participant, input } => write!(
formatter,
"participant-step-began participant={participant} input={input}"
),
Self::ParticipantStepCompleted {
participant,
outcome,
} => write!(
formatter,
"participant-step-completed participant={participant} outcome={outcome}"
),
Self::SwitchboardRouteBegan { switchboard, input } => write!(
formatter,
"switchboard-route-began switchboard={switchboard} input={input}"
),
Self::SwitchboardRouteCompleted {
switchboard,
output,
} => write!(
formatter,
"switchboard-route-completed switchboard={switchboard} output={output}"
),
}
}
}
#[cfg(test)]
mod tests {
extern crate alloc;
use alloc::string::ToString as _;
use core::mem::size_of;
use super::*;
use crate::TurnContext;
#[test]
fn every_observation_has_a_flat_display_form() {
let observations = [
TurnObservation::CircuitTurnBegan {
circuit: "circuit",
input: "input",
},
TurnObservation::CircuitTurnCompleted {
circuit: "circuit",
output: "output",
},
TurnObservation::PipeSendBegan {
participant: "machine",
input: "input",
transport: "inline",
},
TurnObservation::PipeSendCompleted {
participant: "machine",
transport: "inline",
outcome: "output",
},
TurnObservation::ParticipantStepBegan {
participant: "machine",
input: "input",
},
TurnObservation::ParticipantStepCompleted {
participant: "machine",
outcome: "output",
},
TurnObservation::SwitchboardRouteBegan {
switchboard: "switchboard",
input: "input",
},
TurnObservation::SwitchboardRouteCompleted {
switchboard: "switchboard",
output: "output",
},
];
let displayed = observations.map(|observation| observation.to_string());
assert_eq!(
[
"circuit-turn-began circuit=circuit input=input",
"circuit-turn-completed circuit=circuit output=output",
"pipe-send-began participant=machine input=input transport=inline",
"pipe-send-completed participant=machine transport=inline outcome=output",
"participant-step-began participant=machine input=input",
"participant-step-completed participant=machine outcome=output",
"switchboard-route-began switchboard=switchboard input=input",
"switchboard-route-completed switchboard=switchboard output=output",
],
displayed
);
}
#[test]
fn borrowed_and_noop_observers_accept_observations() {
let observation = TurnObservation::ParticipantStepCompleted {
participant: "machine",
outcome: "output",
};
let mut noop = NoopTurnObserver;
let borrowed = &mut noop;
borrowed.observe(observation);
}
#[test]
fn noop_turn_observation_carries_no_runtime_state() {
assert_eq!(size_of::<NoopTurnObserver>(), 0);
assert_eq!(size_of::<TurnContext<NoopTurnObserver>>(), 0);
}
}