boomerang 0.3.0

Deterministic Middleware for Robotics
Documentation
use boomerang::{builder::prelude::*, runtime, Reaction, Reactor};

#[derive(Reactor)]
#[reactor(state = "()", reaction = "SourceReactionT")]
struct SourceBuilder {
    y: TypedPortKey<i32, Output>,
    #[reactor(timer())]
    t: TimerActionKey,
}

#[derive(Reaction)]
#[reaction(reactor = "SourceBuilder", triggers(action = "t"))]
struct SourceReactionT<'a> {
    y: runtime::OutputRef<'a, i32>,
}

impl Trigger<SourceBuilder> for SourceReactionT<'_> {
    fn trigger(mut self, _ctx: &mut runtime::Context, _state: &mut ()) {
        *self.y = Some(1);
    }
}

#[derive(Reactor)]
#[reactor(state = "()", reaction = "DestReactionXY")]
struct DestinationBuilder {
    x: TypedPortKey<i32, Input>,
    y: TypedPortKey<i32, Input>,
}

#[derive(Reaction)]
#[reaction(reactor = "DestinationBuilder")]
struct DestReactionXY<'a> {
    x: runtime::InputRef<'a, i32>,
    y: runtime::InputRef<'a, i32>,
}

impl Trigger<DestinationBuilder> for DestReactionXY<'_> {
    fn trigger(self, _ctx: &mut runtime::Context, _state: &mut ()) {
        let mut sum = 0;
        if let Some(x) = *self.x {
            sum += x;
        }
        if let Some(y) = *self.y {
            sum += y;
        }
        println!("Received {}", sum);
        assert_eq!(sum, 2, "FAILURE: Expected 2.");
    }
}

#[derive(Reactor)]
#[reactor(state = "()", reaction = "PassReactionX")]
struct PassBuilder {
    x: TypedPortKey<i32, Input>,
    y: TypedPortKey<i32, Output>,
}

#[derive(Reaction)]
#[reaction(reactor = "PassBuilder")]
struct PassReactionX<'a> {
    x: runtime::InputRef<'a, i32>,
    y: runtime::OutputRef<'a, i32>,
}

impl Trigger<PassBuilder> for PassReactionX<'_> {
    fn trigger(mut self, _ctx: &mut runtime::Context, _state: &mut ()) {
        *self.y = *self.x;
    }
}

#[derive(Reactor)]
#[reactor(
    state = "()",
    connection(from = "s.y", to = "d.y"),
    connection(from = "s.y", to = "p1.x"),
    connection(from = "p1.y", to = "p2.x"),
    connection(from = "p2.y", to = "d.x")
)]
#[allow(dead_code)]
struct DeterminismBuilder {
    #[reactor(child = "()")]
    s: SourceBuilder,
    #[reactor(child = "()")]
    d: DestinationBuilder,
    #[reactor(child = "()")]
    p1: PassBuilder,
    #[reactor(child = "()")]
    p2: PassBuilder,
}

#[test]
fn determinism() {
    tracing_subscriber::fmt::init();
    let _ = boomerang_util::runner::build_and_test_reactor::<DeterminismBuilder>(
        "determinism",
        (),
        true,
        false,
    )
    .unwrap();
}