use std::time::Duration;
#[doc(hidden)]
pub mod sealing {
pub trait Sealed {}
}
#[diagnostic::on_unimplemented(
message = "`{Self}` is a tool, which is a thin raw-bus runner and has no typed-graph surface",
label = "`#[step]` / `#[reset]` / `#[server]` is not allowed here; use the raw bus (`phoxal::raw`) instead"
)]
pub trait TypedGraphSurface {}
#[doc(hidden)]
pub trait IsDriver: sealing::Sealed {}
#[doc(hidden)]
pub trait IsTool: sealing::Sealed {}
#[doc(hidden)]
pub trait IsSimulator: sealing::Sealed {}
#[derive(Clone, Copy, Debug)]
pub struct StepSchedule {
pub hz: f64,
pub missed_tick: MissedTick,
}
impl StepSchedule {
pub const fn hz(hz: f64) -> Self {
StepSchedule {
hz,
missed_tick: MissedTick::Collapse,
}
}
pub fn period(&self) -> Duration {
std::cmp::max(
Duration::from_secs_f64(1.0 / self.hz),
Duration::from_nanos(1),
)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MissedTick {
Collapse,
CatchUp,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::prelude::*;
#[test]
fn step_schedule_period_never_rounds_to_zero() {
assert_eq!(StepSchedule::hz(f64::MAX).period(), Duration::from_nanos(1));
}
#[phoxal::simulator(id = "marker-simulator", config = (), api = ())]
struct MarkerSimulator;
#[phoxal::behavior]
impl MarkerSimulator {
#[setup]
async fn setup(_ctx: &mut SetupContext<Self>) -> Result<(Self, Self::Api)> {
Ok((Self, ()))
}
#[step(hz = 20)]
async fn step(&mut self, _api: &mut Self::Api, _step: StepContext) -> Result<()> {
Ok(())
}
}
#[phoxal::tool(id = "marker-tool")]
struct MarkerTool;
#[phoxal::behavior]
impl MarkerTool {
#[setup]
async fn setup(_ctx: &mut SetupContext<Self>) -> Result<(Self, Self::Api)> {
Ok((Self, ()))
}
}
#[test]
fn kind_macros_emit_their_markers() {
fn assert_simulator<T: IsSimulator + TypedGraphSurface>() {}
fn assert_tool<T: IsTool>() {}
assert_simulator::<MarkerSimulator>();
assert_tool::<MarkerTool>();
}
}