use std::sync::OnceLock;
use noop::NoopDispatch;
use crate::catalog::CatalogEntry;
pub mod noop;
pub mod test;
#[cfg(feature = "antithesis")]
pub mod antithesis;
pub enum Event {
RegisterEntry(&'static CatalogEntry),
EmitEntry {
entry: &'static CatalogEntry,
condition: bool,
details: serde_json::Value,
},
SetupComplete {
details: serde_json::Value,
},
Custom {
name: &'static str,
value: serde_json::Value,
},
}
pub trait Dispatch: Sync + Send {
fn emit(&self, event: Event);
fn random(&self) -> u64;
}
static DISPATCHER: OnceLock<&'static dyn Dispatch> = OnceLock::new();
#[derive(Debug)]
pub struct SetDispatchError;
impl std::error::Error for SetDispatchError {}
impl std::fmt::Display for SetDispatchError {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
fmt.write_str("attempted to set the dispatcher after it was already set")
}
}
pub fn set_dispatcher(dispatcher: &'static dyn Dispatch) -> Result<(), SetDispatchError> {
DISPATCHER.set(dispatcher).map_err(|_| SetDispatchError)
}
pub fn dispatcher() -> &'static dyn Dispatch {
match DISPATCHER.get() {
Some(dispatch) => *dispatch,
None => {
static NOOP: NoopDispatch = NoopDispatch;
&NOOP
}
}
}
pub fn get_random() -> u64 {
dispatcher().random()
}
pub fn choose<T>(options: &[T]) -> Option<&T> {
if options.is_empty() {
None
} else {
let idx: usize = (get_random() as usize) % options.len();
Some(&options[idx])
}
}
pub fn emit(event: Event) {
dispatcher().emit(event);
}