diff --git a/exercises/react/example.rs b/exercises/react/example.rs index 096426960..892e10e18 100644 --- a/exercises/react/example.rs +++ b/exercises/react/example.rs @@ -1,12 +1,31 @@ use std::collections::HashMap; -pub type CellID = usize; -pub type CallbackID = usize; - -#[derive(Debug, PartialEq)] -pub enum SetValueError { - NonexistentCell, - ComputeCell, +/// `InputCellID` is a unique identifier for an input cell. +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct InputCellID(usize); +/// `ComputeCellID` is a unique identifier for a compute cell. +/// Values of type `InputCellID` and `ComputeCellID` should not be mutually assignable, +/// demonstrated by the following tests: +/// +/// ```compile_fail +/// let mut r = react::Reactor::new(); +/// let input: react::ComputeCellID = r.create_input(111); +/// ``` +/// +/// ```compile_fail +/// let mut r = react::Reactor::new(); +/// let input = r.create_input(111); +/// let compute: react::InputCellID = r.create_compute(&[react::CellID::Input(input)], |_| 222).unwrap(); +/// ``` +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct ComputeCellID(usize); +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct CallbackID(usize); + +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum CellID { + Input(InputCellID), + Compute(ComputeCellID), } #[derive(Debug, PartialEq)] @@ -15,27 +34,38 @@ pub enum RemoveCallbackError { NonexistentCallback, } -struct Cell<'a, T: Copy> { +struct Cell { value: T, last_value: T, - dependents: Vec, - cell_type: CellType<'a, T>, - callbacks_issued: usize, - callbacks: HashMap () + 'a>>, + dependents: Vec, } -enum CellType<'a, T: Copy> { - Input, - Compute(Vec, Box T + 'a>), +struct ComputeCell<'a, T: Copy> { + cell: Cell, + + dependencies: Vec, + f: Box T + 'a>, + callbacks_issued: usize, + callbacks: HashMap () + 'a>>, } -impl <'a, T: Copy> Cell<'a, T> { - fn new(initial: T, cell_type: CellType<'a, T>) -> Self { +impl Cell { + fn new(initial: T) -> Self { Cell { value: initial, last_value: initial, dependents: Vec::new(), - cell_type: cell_type, + } + } +} + +impl <'a, T: Copy> ComputeCell<'a, T> { + fn new T + 'a>(initial: T, dependencies: Vec, f: F) -> Self { + ComputeCell { + cell: Cell::new(initial), + + dependencies, + f: Box::new(f), callbacks_issued: 0, callbacks: HashMap::new(), } @@ -43,52 +73,58 @@ impl <'a, T: Copy> Cell<'a, T> { } pub struct Reactor<'a, T: Copy> { - cells: Vec>, + inputs: Vec>, + computes: Vec>, } impl <'a, T: Copy + PartialEq> Reactor<'a, T> { pub fn new() -> Self { Reactor{ - cells: Vec::new(), + inputs: Vec::new(), + computes: Vec::new(), } } - pub fn create_input(&mut self, initial: T) -> CellID { - self.cells.push(Cell::new(initial, CellType::Input)); - self.cells.len() - 1 + pub fn create_input(&mut self, initial: T) -> InputCellID { + self.inputs.push(Cell::new(initial)); + InputCellID(self.inputs.len() - 1) } - pub fn create_compute T + 'a>(&mut self, dependencies: &[CellID], compute_func: F) -> Result { + pub fn create_compute T + 'a>(&mut self, dependencies: &[CellID], compute_func: F) -> Result { // Check all dependencies' validity before modifying any of them, // so that we don't perform an incorrect partial write. - if let Some(&invalid) = dependencies.iter().find(|&dep| *dep >= self.cells.len()) { - return Err(invalid); + for &dep in dependencies { + match dep { + CellID::Input(InputCellID(id)) => if id >= self.inputs.len() { return Err(dep) }, + CellID::Compute(ComputeCellID(id)) => if id >= self.computes.len() { return Err(dep) }, + } } - let new_id = self.cells.len(); - for &id in dependencies { - self.cells.get_mut(id).unwrap().dependents.push(new_id); + let new_id = ComputeCellID(self.computes.len()); + for &dep in dependencies { + match dep { + CellID::Input(InputCellID(id)) => self.inputs[id].dependents.push(new_id), + CellID::Compute(ComputeCellID(id)) => self.computes[id].cell.dependents.push(new_id), + } } let inputs: Vec<_> = dependencies.iter().map(|&id| self.value(id).unwrap()).collect(); let initial = compute_func(&inputs); - self.cells.push(Cell::new(initial, CellType::Compute(dependencies.iter().cloned().collect(), Box::new(compute_func)))); + self.computes.push(ComputeCell::new(initial, dependencies.to_vec(), compute_func)); Ok(new_id) } pub fn value(&self, id: CellID) -> Option { - self.cells.get(id).map(|c| c.value) + match id { + CellID::Input(InputCellID(id)) => self.inputs.get(id).map(|c| c.value), + CellID::Compute(ComputeCellID(id)) => self.computes.get(id).map(|c| c.cell.value), + } } - pub fn set_value(&mut self, id: CellID, new_value: T) -> Result<(), SetValueError> { - match self.cells.get_mut(id) { - Some(c) => match c.cell_type { - CellType::Input => { - c.value = new_value; - Ok(c.dependents.clone()) - }, - CellType::Compute(_, _) => Err(SetValueError::ComputeCell), - }, - None => Err(SetValueError::NonexistentCell), - }.map(|deps| { + pub fn set_value(&mut self, id: InputCellID, new_value: T) -> bool { + let InputCellID(id) = id; + self.inputs.get_mut(id).map(|c| { + c.value = new_value; + c.dependents.clone() + }).map(|deps| { for &d in deps.iter() { self.update_dependent(d); } @@ -97,19 +133,22 @@ impl <'a, T: Copy + PartialEq> Reactor<'a, T> { for d in deps { self.fire_callbacks(d); } - }) + }).is_some() } - pub fn add_callback () + 'a>(&mut self, id: CellID, callback: F) -> Option { - self.cells.get_mut(id).map(|c| { + pub fn add_callback () + 'a>(&mut self, id: ComputeCellID, callback: F) -> Option { + let ComputeCellID(id) = id; + self.computes.get_mut(id).map(|c| { c.callbacks_issued += 1; - c.callbacks.insert(c.callbacks_issued, Box::new(callback)); - c.callbacks_issued + let cbid = CallbackID(c.callbacks_issued); + c.callbacks.insert(cbid, Box::new(callback)); + cbid }) } - pub fn remove_callback(&mut self, cell: CellID, callback: CallbackID) -> Result<(), RemoveCallbackError> { - match self.cells.get_mut(cell) { + pub fn remove_callback(&mut self, cell: ComputeCellID, callback: CallbackID) -> Result<(), RemoveCallbackError> { + let ComputeCellID(cell) = cell; + match self.computes.get_mut(cell) { Some(c) => match c.callbacks.remove(&callback) { Some(_) => Ok(()), None => Err(RemoveCallbackError::NonexistentCallback), @@ -118,29 +157,28 @@ impl <'a, T: Copy + PartialEq> Reactor<'a, T> { } } - fn update_dependent(&mut self, id: CellID) { + fn update_dependent(&mut self, id: ComputeCellID) { + let ComputeCellID(id) = id; + let (new_value, dependents) = { // This block limits the scope of the self.cells borrow. // This is necessary becaue we borrow it mutably below. - let (dependencies, f, dependents) = match self.cells.get(id) { - Some(c) => match c.cell_type { - CellType::Input => panic!("Input cell can't be a dependent"), - CellType::Compute(ref dependencies, ref f) => (dependencies, f, c.dependents.clone()), - }, + let (dependencies, f, dependents) = match self.computes.get(id) { + Some(c) => (&c.dependencies, &c.f, c.cell.dependents.clone()), None => panic!("Cell to update disappeared while querying"), }; let inputs: Vec<_> = dependencies.iter().map(|&id| self.value(id).unwrap()).collect(); (f(&inputs), dependents) }; - match self.cells.get_mut(id) { + match self.computes.get_mut(id) { Some(c) => { - if c.value == new_value { + if c.cell.value == new_value { // No change here, we don't need to update our dependents. // (It wouldn't hurt to, but it would be unnecessary work) return; } - c.value = new_value; + c.cell.value = new_value; }, None => panic!("Cell to update disappeared while updating"), } @@ -150,19 +188,20 @@ impl <'a, T: Copy + PartialEq> Reactor<'a, T> { } } - fn fire_callbacks(&mut self, id: CellID) { - let dependents = match self.cells.get_mut(id) { + fn fire_callbacks(&mut self, id: ComputeCellID) { + let ComputeCellID(id) = id; + let dependents = match self.computes.get_mut(id) { Some(c) => { - if c.value == c.last_value { + if c.cell.value == c.cell.last_value { // Value hasn't changed since last callback fire. // We thus shouldn't fire the callbacks. return } for cb in c.callbacks.values_mut() { - cb(c.value); + cb(c.cell.value); } - c.last_value = c.value; - c.dependents.clone() + c.cell.last_value = c.cell.value; + c.cell.dependents.clone() }, None => panic!("Callback cell disappeared"), }; diff --git a/exercises/react/src/lib.rs b/exercises/react/src/lib.rs index 40e442629..e65b4f5f2 100644 --- a/exercises/react/src/lib.rs +++ b/exercises/react/src/lib.rs @@ -1,12 +1,29 @@ -// Because these are passed without & to some functions, -// it will probably be necessary for these two types to be Copy. -pub type CellID = (); -pub type CallbackID = (); +/// `InputCellID` is a unique identifier for an input cell. +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct InputCellID(); +/// `ComputeCellID` is a unique identifier for a compute cell. +/// Values of type `InputCellID` and `ComputeCellID` should not be mutually assignable, +/// demonstrated by the following tests: +/// +/// ```compile_fail +/// let mut r = react::Reactor::new(); +/// let input: react::ComputeCellID = r.create_input(111); +/// ``` +/// +/// ```compile_fail +/// let mut r = react::Reactor::new(); +/// let input = r.create_input(111); +/// let compute: react::InputCellID = r.create_compute(&[react::CellID::Input(input)], |_| 222).unwrap(); +/// ``` +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct ComputeCellID(); +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct CallbackID(); -#[derive(Debug, PartialEq)] -pub enum SetValueError { - NonexistentCell, - ComputeCell, +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum CellID { + Input(InputCellID), + Compute(ComputeCellID), } #[derive(Debug, PartialEq)] @@ -28,7 +45,7 @@ impl Reactor { } // Creates an input cell with the specified initial value, returning its ID. - pub fn create_input(&mut self, _initial: T) -> CellID { + pub fn create_input(&mut self, _initial: T) -> InputCellID { unimplemented!() } @@ -45,7 +62,7 @@ impl Reactor { // Notice that there is no way to *remove* a cell. // This means that you may assume, without checking, that if the dependencies exist at creation // time they will continue to exist as long as the Reactor exists. - pub fn create_compute T>(&mut self, _dependencies: &[CellID], _compute_func: F) -> Result { + pub fn create_compute T>(&mut self, _dependencies: &[CellID], _compute_func: F) -> Result { unimplemented!() } @@ -62,16 +79,13 @@ impl Reactor { // Sets the value of the specified input cell. // - // Returns an Err if either: - // * the cell does not exist - // * the specified cell is a compute cell, since compute cells cannot have their values - // directly set. + // Returns false if the cell does not exist. // // Similarly, you may wonder about `get_mut(&mut self, id: CellID) -> Option<&mut Cell>`, with // a `set_value(&mut self, new_value: T)` method on `Cell`. // // As before, that turned out to add too much extra complexity. - pub fn set_value(&mut self, _id: CellID, _new_value: T) -> Result<(), SetValueError> { + pub fn set_value(&mut self, _id: InputCellID, _new_value: T) -> bool { unimplemented!() } @@ -87,7 +101,7 @@ impl Reactor { // * Exactly once if the compute cell's value changed as a result of the set_value call. // The value passed to the callback should be the final value of the compute cell after the // set_value call. - pub fn add_callback ()>(&mut self, _id: CellID, _callback: F) -> Option { + pub fn add_callback ()>(&mut self, _id: ComputeCellID, _callback: F) -> Option { unimplemented!() } @@ -96,7 +110,7 @@ impl Reactor { // Returns an Err if either the cell or callback does not exist. // // A removed callback should no longer be called. - pub fn remove_callback(&mut self, cell: CellID, callback: CallbackID) -> Result<(), RemoveCallbackError> { + pub fn remove_callback(&mut self, cell: ComputeCellID, callback: CallbackID) -> Result<(), RemoveCallbackError> { unimplemented!( "Remove the callback identified by the CallbackID {:?} from the cell {:?}", callback, diff --git a/exercises/react/tests/react.rs b/exercises/react/tests/react.rs index 95ab71613..8e0128b04 100644 --- a/exercises/react/tests/react.rs +++ b/exercises/react/tests/react.rs @@ -6,7 +6,7 @@ use react::*; fn input_cells_have_a_value() { let mut reactor = Reactor::new(); let input = reactor.create_input(10); - assert_eq!(reactor.value(input), Some(10)); + assert_eq!(reactor.value(CellID::Input(input)), Some(10)); } #[test] @@ -14,8 +14,8 @@ fn input_cells_have_a_value() { fn an_input_cells_value_can_be_set() { let mut reactor = Reactor::new(); let input = reactor.create_input(4); - assert!(reactor.set_value(input, 20).is_ok()); - assert_eq!(reactor.value(input), Some(20)); + assert!(reactor.set_value(input, 20)); + assert_eq!(reactor.value(CellID::Input(input)), Some(20)); } #[test] @@ -23,7 +23,7 @@ fn an_input_cells_value_can_be_set() { fn error_setting_a_nonexistent_input_cell() { let mut dummy_reactor = Reactor::new(); let input = dummy_reactor.create_input(1); - assert_eq!(Reactor::new().set_value(input, 0), Err(SetValueError::NonexistentCell)); + assert!(!Reactor::new().set_value(input, 0)); } #[test] @@ -31,8 +31,8 @@ fn error_setting_a_nonexistent_input_cell() { fn compute_cells_calculate_initial_value() { let mut reactor = Reactor::new(); let input = reactor.create_input(1); - let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap(); - assert_eq!(reactor.value(output), Some(2)); + let output = reactor.create_compute(&[CellID::Input(input)], |v| v[0] + 1).unwrap(); + assert_eq!(reactor.value(CellID::Compute(output)), Some(2)); } #[test] @@ -41,8 +41,8 @@ fn compute_cells_take_inputs_in_the_right_order() { let mut reactor = Reactor::new(); let one = reactor.create_input(1); let two = reactor.create_input(2); - let output = reactor.create_compute(&[one, two], |v| v[0] + v[1] * 10).unwrap(); - assert_eq!(reactor.value(output), Some(21)); + let output = reactor.create_compute(&[CellID::Input(one), CellID::Input(two)], |v| v[0] + v[1] * 10).unwrap(); + assert_eq!(reactor.value(CellID::Compute(output)), Some(21)); } #[test] @@ -50,7 +50,7 @@ fn compute_cells_take_inputs_in_the_right_order() { fn error_creating_compute_cell_if_input_doesnt_exist() { let mut dummy_reactor = Reactor::new(); let input = dummy_reactor.create_input(1); - assert_eq!(Reactor::new().create_compute(&[input], |_| 0), Err(input)); + assert_eq!(Reactor::new().create_compute(&[CellID::Input(input)], |_| 0), Err(CellID::Input(input))); } #[test] @@ -61,9 +61,9 @@ fn do_not_break_cell_if_creating_compute_cell_with_valid_and_invalid_input() { let dummy_cell = dummy_reactor.create_input(2); let mut reactor = Reactor::new(); let input = reactor.create_input(1); - assert_eq!(reactor.create_compute(&[input, dummy_cell], |_| 0), Err(dummy_cell)); - assert!(reactor.set_value(input, 5).is_ok()); - assert_eq!(reactor.value(input), Some(5)); + assert_eq!(reactor.create_compute(&[CellID::Input(input), CellID::Input(dummy_cell)], |_| 0), Err(CellID::Input(dummy_cell))); + assert!(reactor.set_value(input, 5)); + assert_eq!(reactor.value(CellID::Input(input)), Some(5)); } #[test] @@ -71,10 +71,10 @@ fn do_not_break_cell_if_creating_compute_cell_with_valid_and_invalid_input() { fn compute_cells_update_value_when_dependencies_are_changed() { let mut reactor = Reactor::new(); let input = reactor.create_input(1); - let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap(); - assert_eq!(reactor.value(output), Some(2)); - assert!(reactor.set_value(input, 3).is_ok()); - assert_eq!(reactor.value(output), Some(4)); + let output = reactor.create_compute(&[CellID::Input(input)], |v| v[0] + 1).unwrap(); + assert_eq!(reactor.value(CellID::Compute(output)), Some(2)); + assert!(reactor.set_value(input, 3)); + assert_eq!(reactor.value(CellID::Compute(output)), Some(4)); } #[test] @@ -82,21 +82,12 @@ fn compute_cells_update_value_when_dependencies_are_changed() { fn compute_cells_can_depend_on_other_compute_cells() { let mut reactor = Reactor::new(); let input = reactor.create_input(1); - let times_two = reactor.create_compute(&[input], |v| v[0] * 2).unwrap(); - let times_thirty = reactor.create_compute(&[input], |v| v[0] * 30).unwrap(); - let output = reactor.create_compute(&[times_two, times_thirty], |v| v[0] + v[1]).unwrap(); - assert_eq!(reactor.value(output), Some(32)); - assert!(reactor.set_value(input, 3).is_ok()); - assert_eq!(reactor.value(output), Some(96)); -} - -#[test] -#[ignore] -fn error_setting_a_compute_cell() { - let mut reactor = Reactor::new(); - let input = reactor.create_input(1); - let output = reactor.create_compute(&[input], |_| 0).unwrap(); - assert_eq!(reactor.set_value(output, 3), Err(SetValueError::ComputeCell)); + let times_two = reactor.create_compute(&[CellID::Input(input)], |v| v[0] * 2).unwrap(); + let times_thirty = reactor.create_compute(&[CellID::Input(input)], |v| v[0] * 30).unwrap(); + let output = reactor.create_compute(&[CellID::Compute(times_two), CellID::Compute(times_thirty)], |v| v[0] + v[1]).unwrap(); + assert_eq!(reactor.value(CellID::Compute(output)), Some(32)); + assert!(reactor.set_value(input, 3)); + assert_eq!(reactor.value(CellID::Compute(output)), Some(96)); } /// A CallbackRecorder helps tests whether callbacks get called correctly. @@ -138,9 +129,9 @@ fn compute_cells_fire_callbacks() { let cb = CallbackRecorder::new(); let mut reactor = Reactor::new(); let input = reactor.create_input(1); - let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap(); + let output = reactor.create_compute(&[CellID::Input(input)], |v| v[0] + 1).unwrap(); assert!(reactor.add_callback(output, |v| cb.callback_called(v)).is_some()); - assert!(reactor.set_value(input, 3).is_ok()); + assert!(reactor.set_value(input, 3)); cb.expect_to_have_been_called_with(4); } @@ -149,7 +140,7 @@ fn compute_cells_fire_callbacks() { fn error_adding_callback_to_nonexistent_cell() { let mut dummy_reactor = Reactor::new(); let input = dummy_reactor.create_input(1); - let output = dummy_reactor.create_compute(&[input], |_| 0).unwrap(); + let output = dummy_reactor.create_compute(&[CellID::Input(input)], |_| 0).unwrap(); assert_eq!(Reactor::new().add_callback(output, |_: usize| println!("hi")), None); } @@ -159,12 +150,12 @@ fn callbacks_only_fire_on_change() { let cb = CallbackRecorder::new(); let mut reactor = Reactor::new(); let input = reactor.create_input(1); - let output = reactor.create_compute(&[input], |v| if v[0] < 3 { 111 } else { 222 }).unwrap(); + let output = reactor.create_compute(&[CellID::Input(input)], |v| if v[0] < 3 { 111 } else { 222 }).unwrap(); assert!(reactor.add_callback(output, |v| cb.callback_called(v)).is_some()); - assert!(reactor.set_value(input, 2).is_ok()); + assert!(reactor.set_value(input, 2)); cb.expect_not_to_have_been_called(); - assert!(reactor.set_value(input, 4).is_ok()); + assert!(reactor.set_value(input, 4)); cb.expect_to_have_been_called_with(222); } @@ -177,19 +168,19 @@ fn callbacks_can_be_added_and_removed() { let mut reactor = Reactor::new(); let input = reactor.create_input(11); - let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap(); + let output = reactor.create_compute(&[CellID::Input(input)], |v| v[0] + 1).unwrap(); let callback = reactor.add_callback(output, |v| cb1.callback_called(v)).unwrap(); assert!(reactor.add_callback(output, |v| cb2.callback_called(v)).is_some()); - assert!(reactor.set_value(input, 31).is_ok()); + assert!(reactor.set_value(input, 31)); cb1.expect_to_have_been_called_with(32); cb2.expect_to_have_been_called_with(32); assert!(reactor.remove_callback(output, callback).is_ok()); assert!(reactor.add_callback(output, |v| cb3.callback_called(v)).is_some()); - assert!(reactor.set_value(input, 41).is_ok()); + assert!(reactor.set_value(input, 41)); cb1.expect_not_to_have_been_called(); cb2.expect_to_have_been_called_with(42); cb3.expect_to_have_been_called_with(42); @@ -203,7 +194,7 @@ fn removing_a_callback_multiple_times_doesnt_interfere_with_other_callbacks() { let mut reactor = Reactor::new(); let input = reactor.create_input(1); - let output = reactor.create_compute(&[input], |v| v[0] + 1).unwrap(); + let output = reactor.create_compute(&[CellID::Input(input)], |v| v[0] + 1).unwrap(); let callback = reactor.add_callback(output, |v| cb1.callback_called(v)).unwrap(); assert!(reactor.add_callback(output, |v| cb2.callback_called(v)).is_some()); // We want the first remove to be Ok, but the others should be errors. @@ -212,7 +203,7 @@ fn removing_a_callback_multiple_times_doesnt_interfere_with_other_callbacks() { assert_eq!(reactor.remove_callback(output, callback), Err(RemoveCallbackError::NonexistentCallback)); } - assert!(reactor.set_value(input, 2).is_ok()); + assert!(reactor.set_value(input, 2)); cb1.expect_not_to_have_been_called(); cb2.expect_to_have_been_called_with(3); } @@ -223,12 +214,12 @@ fn callbacks_should_only_be_called_once_even_if_multiple_dependencies_change() { let cb = CallbackRecorder::new(); let mut reactor = Reactor::new(); let input = reactor.create_input(1); - let plus_one = reactor.create_compute(&[input], |v| v[0] + 1).unwrap(); - let minus_one1 = reactor.create_compute(&[input], |v| v[0] - 1).unwrap(); - let minus_one2 = reactor.create_compute(&[minus_one1], |v| v[0] - 1).unwrap(); - let output = reactor.create_compute(&[plus_one, minus_one2], |v| v[0] * v[1]).unwrap(); + let plus_one = reactor.create_compute(&[CellID::Input(input)], |v| v[0] + 1).unwrap(); + let minus_one1 = reactor.create_compute(&[CellID::Input(input)], |v| v[0] - 1).unwrap(); + let minus_one2 = reactor.create_compute(&[CellID::Compute(minus_one1)], |v| v[0] - 1).unwrap(); + let output = reactor.create_compute(&[CellID::Compute(plus_one), CellID::Compute(minus_one2)], |v| v[0] * v[1]).unwrap(); assert!(reactor.add_callback(output, |v| cb.callback_called(v)).is_some()); - assert!(reactor.set_value(input, 4).is_ok()); + assert!(reactor.set_value(input, 4)); cb.expect_to_have_been_called_with(10); } @@ -238,12 +229,12 @@ fn callbacks_should_not_be_called_if_dependencies_change_but_output_value_doesnt let cb = CallbackRecorder::new(); let mut reactor = Reactor::new(); let input = reactor.create_input(1); - let plus_one = reactor.create_compute(&[input], |v| v[0] + 1).unwrap(); - let minus_one = reactor.create_compute(&[input], |v| v[0] - 1).unwrap(); - let always_two = reactor.create_compute(&[plus_one, minus_one], |v| v[0] - v[1]).unwrap(); + let plus_one = reactor.create_compute(&[CellID::Input(input)], |v| v[0] + 1).unwrap(); + let minus_one = reactor.create_compute(&[CellID::Input(input)], |v| v[0] - 1).unwrap(); + let always_two = reactor.create_compute(&[CellID::Compute(plus_one), CellID::Compute(minus_one)], |v| v[0] - v[1]).unwrap(); assert!(reactor.add_callback(always_two, |v| cb.callback_called(v)).is_some()); for i in 2..5 { - assert!(reactor.set_value(input, i).is_ok()); + assert!(reactor.set_value(input, i)); cb.expect_not_to_have_been_called(); } } @@ -258,12 +249,12 @@ fn test_adder_with_boolean_values() { let b = reactor.create_input(false); let carry_in = reactor.create_input(false); - let a_xor_b = reactor.create_compute(&[a, b], |v| v[0] ^ v[1]).unwrap(); - let sum = reactor.create_compute(&[a_xor_b, carry_in], |v| v[0] ^ v[1]).unwrap(); + let a_xor_b = reactor.create_compute(&[CellID::Input(a), CellID::Input(b)], |v| v[0] ^ v[1]).unwrap(); + let sum = reactor.create_compute(&[CellID::Compute(a_xor_b), CellID::Input(carry_in)], |v| v[0] ^ v[1]).unwrap(); - let a_xor_b_and_cin = reactor.create_compute(&[a_xor_b, carry_in], |v| v[0] && v[1]).unwrap(); - let a_and_b = reactor.create_compute(&[a, b], |v| v[0] && v[1]).unwrap(); - let carry_out = reactor.create_compute(&[a_xor_b_and_cin, a_and_b], |v| v[0] || v[1]).unwrap(); + let a_xor_b_and_cin = reactor.create_compute(&[CellID::Compute(a_xor_b), CellID::Input(carry_in)], |v| v[0] && v[1]).unwrap(); + let a_and_b = reactor.create_compute(&[CellID::Input(a), CellID::Input(b)], |v| v[0] && v[1]).unwrap(); + let carry_out = reactor.create_compute(&[CellID::Compute(a_xor_b_and_cin), CellID::Compute(a_and_b)], |v| v[0] || v[1]).unwrap(); let tests = &[ (false, false, false, false, false), @@ -277,11 +268,11 @@ fn test_adder_with_boolean_values() { ]; for &(aval, bval, cinval, expected_cout, expected_sum) in tests { - assert!(reactor.set_value(a, aval).is_ok()); - assert!(reactor.set_value(b, bval).is_ok()); - assert!(reactor.set_value(carry_in, cinval).is_ok()); + assert!(reactor.set_value(a, aval)); + assert!(reactor.set_value(b, bval)); + assert!(reactor.set_value(carry_in, cinval)); - assert_eq!(reactor.value(sum), Some(expected_sum)); - assert_eq!(reactor.value(carry_out), Some(expected_cout)); + assert_eq!(reactor.value(CellID::Compute(sum)), Some(expected_sum)); + assert_eq!(reactor.value(CellID::Compute(carry_out)), Some(expected_cout)); } }