use crate::Control;
use crate::prelude::{Executor, Node, NodeBuilder};
pub fn and_node(executor: &mut Executor, left: Node<bool>, right: Node<bool>) -> Node<bool> {
and_node_with_init(executor, left, right, false)
}
pub fn and_node_with_init(
executor: &mut Executor,
left: Node<bool>,
right: Node<bool>,
init: bool,
) -> Node<bool> {
NodeBuilder::new(init)
.triggered_by(&left)
.triggered_by(&right)
.build(executor, move |this, _| {
let new_value = *left.borrow() && *right.borrow();
let is_different = new_value ^ *this;
*this = new_value;
Control::from(is_different)
})
}
pub fn and_node_with_bootstrap(
executor: &mut Executor,
left: Node<bool>,
right: Node<bool>,
) -> Node<bool> {
NodeBuilder::new(false)
.triggered_by(&left)
.triggered_by(&right)
.on_init(|ex, _, current| {
ex.yield_driver().yield_now(current);
})
.build(executor, move |this, _| {
let new_value = *left.borrow() && *right.borrow();
let is_different = new_value ^ *this;
*this = new_value;
Control::from(is_different)
})
}
pub fn or_node(executor: &mut Executor, left: Node<bool>, right: Node<bool>) -> Node<bool> {
or_node_with_init(executor, left, right, false)
}
pub fn or_node_with_init(
executor: &mut Executor,
left: Node<bool>,
right: Node<bool>,
init: bool,
) -> Node<bool> {
NodeBuilder::new(init)
.triggered_by(&left)
.triggered_by(&right)
.build(executor, move |this, _| {
let new_value = *left.borrow() || *right.borrow();
let is_different = new_value ^ *this;
*this = new_value;
Control::from(is_different)
})
}
pub fn or_node_with_bootstrap(
executor: &mut Executor,
left: Node<bool>,
right: Node<bool>,
) -> Node<bool> {
NodeBuilder::new(false)
.triggered_by(&left)
.triggered_by(&right)
.on_init(|ex, _, current| {
ex.yield_driver().yield_now(current);
})
.build(executor, move |this, _| {
let new_value = *left.borrow() || *right.borrow();
let is_different = new_value ^ *this;
*this = new_value;
Control::from(is_different)
})
}
pub fn xor_node(executor: &mut Executor, left: Node<bool>, right: Node<bool>) -> Node<bool> {
xor_node_with_init(executor, left, right, false)
}
pub fn xor_node_with_init(
executor: &mut Executor,
left: Node<bool>,
right: Node<bool>,
init: bool,
) -> Node<bool> {
NodeBuilder::new(init)
.triggered_by(&left)
.triggered_by(&right)
.build(executor, move |this, _| {
let new_value = *left.borrow() ^ *right.borrow();
let is_different = new_value ^ *this;
*this = new_value;
Control::from(is_different)
})
}
pub fn xor_node_with_bootstrap(
executor: &mut Executor,
left: Node<bool>,
right: Node<bool>,
) -> Node<bool> {
NodeBuilder::new(false)
.triggered_by(&left)
.triggered_by(&right)
.on_init(|ex, _, current| {
ex.yield_driver().yield_now(current);
})
.build(executor, move |this, _| {
let new_value = *left.borrow() ^ *right.borrow();
let is_different = new_value ^ *this;
*this = new_value;
Control::from(is_different)
})
}
#[cfg(test)]
mod tests {
use super::*;
use crate::prelude::TestRuntime;
use crate::prelude::*;
use crate::testing::push_node;
use std::cell::RefCell;
use std::rc::Rc;
#[test]
fn test_and_node_basic() {
let mut runtime = TestRuntime::new();
let (left_node, left_push) = push_node(runtime.executor(), false);
let (right_node, right_push) = push_node(runtime.executor(), false);
let and = and_node(runtime.executor(), left_node, right_node);
assert_eq!(*and.borrow(), false);
left_push.push(true);
runtime.run_one_cycle();
assert_eq!(*and.borrow(), false);
right_push.push(true);
runtime.run_one_cycle();
assert_eq!(*and.borrow(), true);
left_push.push(false);
runtime.run_one_cycle();
assert_eq!(*and.borrow(), false);
right_push.push(false);
runtime.run_one_cycle();
assert_eq!(*and.borrow(), false);
}
#[test]
fn test_and_node_with_init() {
let mut runtime = TestRuntime::new();
let (left_node, left_push) = push_node(runtime.executor(), true);
let (right_node, _right_push) = push_node(runtime.executor(), true);
let and = and_node_with_init(
runtime.executor(),
left_node.clone(),
right_node.clone(),
true,
);
assert_eq!(*and.borrow(), true);
left_push.push(true);
runtime.run_one_cycle();
assert_eq!(*and.borrow(), true);
let and2 = and_node_with_init(runtime.executor(), left_node, right_node, false);
assert_eq!(*and2.borrow(), false);
left_push.push(true);
runtime.run_one_cycle();
assert_eq!(*and2.borrow(), true); }
#[test]
fn test_and_node_with_bootstrap() {
let mut runtime = TestRuntime::new();
let (left_node, _left_push) = push_node(runtime.executor(), true);
let (right_node, _right_push) = push_node(runtime.executor(), true);
let and = and_node_with_bootstrap(runtime.executor(), left_node, right_node);
assert_eq!(*and.borrow(), false);
runtime.run_one_cycle();
assert_eq!(*and.borrow(), true); }
#[test]
fn test_or_node_basic() {
let mut runtime = TestRuntime::new();
let (left_node, left_push) = push_node(runtime.executor(), false);
let (right_node, right_push) = push_node(runtime.executor(), false);
let or = or_node(runtime.executor(), left_node, right_node);
assert_eq!(*or.borrow(), false);
left_push.push(true);
runtime.run_one_cycle();
assert_eq!(*or.borrow(), true);
right_push.push(true);
runtime.run_one_cycle();
assert_eq!(*or.borrow(), true);
left_push.push(false);
runtime.run_one_cycle();
assert_eq!(*or.borrow(), true);
right_push.push(false);
runtime.run_one_cycle();
assert_eq!(*or.borrow(), false);
}
#[test]
fn test_or_node_with_init() {
let mut runtime = TestRuntime::new();
let (left_node, left_push) = push_node(runtime.executor(), false);
let (right_node, _right_push) = push_node(runtime.executor(), false);
let or = or_node_with_init(
runtime.executor(),
left_node.clone(),
right_node.clone(),
true,
);
assert_eq!(*or.borrow(), true);
left_push.push(false);
runtime.run_one_cycle();
assert_eq!(*or.borrow(), false);
let or2 = or_node_with_init(runtime.executor(), left_node, right_node, false);
assert_eq!(*or2.borrow(), false); }
#[test]
fn test_or_node_with_bootstrap() {
let mut runtime = TestRuntime::new();
let (left_node, _left_push) = push_node(runtime.executor(), false);
let (right_node, _right_push) = push_node(runtime.executor(), true);
let or = or_node_with_bootstrap(runtime.executor(), left_node, right_node);
assert_eq!(*or.borrow(), false);
runtime.run_one_cycle();
assert_eq!(*or.borrow(), true); }
#[test]
fn test_xor_node_basic() {
let mut runtime = TestRuntime::new();
let (left_node, left_push) = push_node(runtime.executor(), false);
let (right_node, right_push) = push_node(runtime.executor(), false);
let xor = xor_node(runtime.executor(), left_node, right_node);
assert_eq!(*xor.borrow(), false);
left_push.push(true);
runtime.run_one_cycle();
assert_eq!(*xor.borrow(), true);
right_push.push(true);
runtime.run_one_cycle();
assert_eq!(*xor.borrow(), false);
left_push.push(false);
runtime.run_one_cycle();
assert_eq!(*xor.borrow(), true);
right_push.push(false);
runtime.run_one_cycle();
assert_eq!(*xor.borrow(), false);
}
#[test]
fn test_xor_node_with_init() {
let mut runtime = TestRuntime::new();
let (left_node, _left_push) = push_node(runtime.executor(), true);
let (right_node, right_push) = push_node(runtime.executor(), false);
let xor = xor_node_with_init(
runtime.executor(),
left_node.clone(),
right_node.clone(),
true,
);
assert_eq!(*xor.borrow(), true);
runtime.run_one_cycle();
assert_eq!(*xor.borrow(), true);
let xor2 = xor_node_with_init(runtime.executor(), left_node, right_node, false);
assert_eq!(*xor2.borrow(), false);
right_push.push(false);
runtime.run_one_cycle();
assert_eq!(*xor2.borrow(), true); }
#[test]
fn test_xor_node_with_bootstrap() {
let mut runtime = TestRuntime::new();
let (left_node, _left_push) = push_node(runtime.executor(), true);
let (right_node, _right_push) = push_node(runtime.executor(), true);
let xor = xor_node_with_bootstrap(runtime.executor(), left_node, right_node);
assert_eq!(*xor.borrow(), false);
runtime.run_one_cycle();
assert_eq!(*xor.borrow(), false); }
#[test]
fn test_propagation_only_on_change() {
let mut runtime = TestRuntime::new();
let (left_node, left_push) = push_node(runtime.executor(), true);
let (right_node, right_push) = push_node(runtime.executor(), false);
let and = and_node(runtime.executor(), left_node, right_node);
let trigger_count = Rc::new(RefCell::new(0));
let cloned = trigger_count.clone();
let counter =
NodeBuilder::new(0)
.triggered_by(&and)
.build(runtime.executor(), move |this, _| {
*cloned.borrow_mut() += 1;
*this += 1;
Control::Broadcast
});
assert_eq!(*and.borrow(), false);
assert_eq!(*counter.borrow(), 0);
assert_eq!(*trigger_count.borrow(), 0);
right_push.push(false);
runtime.run_one_cycle();
assert_eq!(*and.borrow(), false);
assert_eq!(*trigger_count.borrow(), 0);
right_push.push(true);
runtime.run_one_cycle();
assert_eq!(*and.borrow(), true);
assert_eq!(*trigger_count.borrow(), 1);
left_push.push(true);
right_push.push(true);
runtime.run_one_cycle();
assert_eq!(*and.borrow(), true);
assert_eq!(*trigger_count.borrow(), 1); }
#[test]
fn test_complex_logic_chain() {
let mut runtime = TestRuntime::new();
let (a_node, a_push) = push_node(runtime.executor(), true);
let (b_node, b_push) = push_node(runtime.executor(), false);
let (c_node, c_push) = push_node(runtime.executor(), true);
let (d_node, d_push) = push_node(runtime.executor(), true);
let and_ab = and_node(runtime.executor(), a_node, b_node);
let xor_cd = xor_node(runtime.executor(), c_node, d_node);
let final_or = or_node(runtime.executor(), and_ab, xor_cd);
runtime.run_one_cycle();
assert_eq!(*final_or.borrow(), false);
b_push.push(true);
runtime.run_one_cycle();
assert_eq!(*final_or.borrow(), true);
d_push.push(false);
runtime.run_one_cycle();
assert_eq!(*final_or.borrow(), true);
a_push.push(false);
b_push.push(false);
runtime.run_one_cycle();
assert_eq!(*final_or.borrow(), true);
c_push.push(false);
runtime.run_one_cycle();
assert_eq!(*final_or.borrow(), false);
}
#[test]
fn test_bootstrap_scheduling() {
let mut runtime = TestRuntime::new();
let (left_node, _left_push) = push_node(runtime.executor(), true);
let (right_node, _right_push) = push_node(runtime.executor(), true);
let and =
and_node_with_bootstrap(runtime.executor(), left_node.clone(), right_node.clone());
let or = or_node_with_bootstrap(runtime.executor(), left_node.clone(), right_node.clone());
let xor = xor_node_with_bootstrap(runtime.executor(), left_node, right_node);
assert_eq!(*and.borrow(), false);
assert_eq!(*or.borrow(), false);
assert_eq!(*xor.borrow(), false);
runtime.run_one_cycle();
assert_eq!(*and.borrow(), true); assert_eq!(*or.borrow(), true); assert_eq!(*xor.borrow(), false); }
}