use core::convert::Infallible;
use __CRATE___core as app_core;
use __CRATE___pipes as app_pipes;
use __CRATE___switchboard as app_routes;
use app_core::{
domain_primitives::Activation,
state_machines::latch::{Activate, Latch},
};
use app_pipes::{Activator, Client};
use app_routes::{ActivationProgram, From, To};
use pipecircuit::{CircuitSendOutcome, Inline, InstalledPipe};
use pipecircuit_browser::{WorkerExchangeFailure, flow_to_worker_reply};
pub struct WorkerProgram {
switchboard: ActivationProgram,
activator: InstalledPipe<Activator, Inline<Latch, Activator>>,
}
impl WorkerProgram {
pub fn exchange(
&mut self,
command: Activate,
) -> Result<Activation, WorkerExchangeFailure<Infallible, To<'static>>> {
flow_to_worker_reply::<Client, _, _, 0>(
&mut self.switchboard,
command,
&mut pipecircuit::PendingRoutes::new(),
From::Client,
|destination| match destination {
To::Activator(input) => Ok(CircuitSendOutcome::Immediate {
from: From::Activator(self.activator.send(input)),
}),
To::Client(output) => Ok(CircuitSendOutcome::Completed { completion: output }),
},
)
}
}
fn initialize() -> Result<WorkerProgram, Infallible> {
Ok(WorkerProgram {
switchboard: ActivationProgram,
activator: InstalledPipe::new(Inline::for_pipe(Latch::default())),
})
}
pipecircuit_browser::export_web_worker_program!(
pub ActivationWorker,
participant = Client,
program = WorkerProgram,
initialize = initialize,
);
#[cfg(test)]
mod tests {
use super::*;
use pipecircuit_browser::{PostcardByteProgramExchangeError, WorkerBoundary};
#[test]
fn successive_messages_reach_the_same_authority() -> Result<(), Infallible> {
let mut program = initialize()?;
assert!(matches!(
program.exchange(Activate),
Ok(Activation::Activated)
));
assert!(matches!(
program.exchange(Activate),
Ok(Activation::AlreadyActive)
));
Ok(())
}
#[test]
fn invalid_bytes_do_not_mutate_the_worker() -> Result<(), Infallible> {
let mut boundary = WorkerBoundary::<Client, _>::new(initialize()?);
assert!(matches!(
boundary.exchange(&[1], WorkerProgram::exchange),
Err(PostcardByteProgramExchangeError::TrailingCommandBytes { byte_count: 1 })
));
assert!(
matches!(boundary.exchange(&[], WorkerProgram::exchange), Ok(bytes) if bytes == [0])
);
assert!(
matches!(boundary.exchange(&[], WorkerProgram::exchange), Ok(bytes) if bytes == [1])
);
Ok(())
}
}