Skip to content

Instantly share code, notes, and snippets.

@McGittyHub
Created September 22, 2017 08:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save McGittyHub/cd8e52bfd0c4bf253f213c1b6923745d to your computer and use it in GitHub Desktop.
Save McGittyHub/cd8e52bfd0c4bf253f213c1b6923745d to your computer and use it in GitHub Desktop.
#[allow(unused_variables)]
use std::collections::HashMap;
use std::collections::hash_map::Entry;
pub type CellID = (usize);
pub type CallbackID = (usize);
struct ComputeCell<T> {
pub dependencies: Vec<CellID>,
pub compute_func: Box<Fn(&[T]) -> T>,
}
struct Callback<T> {
pub source: CellID,
pub callback_func: Box<FnMut(T) -> ()>,
}
pub struct Reactor<T> {
map: HashMap<CellID, T>,
compute_cells: HashMap<CellID, ComputeCell<T>>,
callbacks: HashMap<CallbackID, Callback<T>>,
next_callback_id: CallbackID,
next_id: CellID,
}
impl<T: Copy + PartialEq> Reactor<T> {
pub fn new() -> Self {
Reactor {
map: HashMap::new(),
compute_cells: HashMap::new(),
callbacks: HashMap::new(),
next_callback_id: 0,
next_id: 0,
}
}
pub fn create_input(&mut self, initial: T) -> CellID {
let created_id = self.next_id;
self.next_id += 1;
self.map.insert(created_id, initial);
created_id
}
pub fn create_compute<F: Fn(&[T]) -> T + 'static>(
&mut self,
dependencies: &[CellID],
compute_func: F,
) -> Result<CellID, ()> {
if dependencies.iter().any(|dep| {
!(self.map.contains_key(dep) || self.compute_cells.contains_key(dep))
}) {
return Err(());
}
let created_id = self.next_id;
self.next_id += 1;
self.compute_cells.insert(
created_id,
ComputeCell {
dependencies: dependencies.to_vec(),
compute_func: Box::new(compute_func),
},
);
Ok(created_id)
}
pub fn value(&self, id: CellID) -> Option<T> {
if let Some(compute_cell) = self.compute_cells.get(&id) {
let compute_input_values = compute_cell
.dependencies
.iter()
.map(|dep| self.value(*dep).unwrap())
.collect::<Vec<_>>();
let compute_result = (*compute_cell.compute_func)(&compute_input_values);
Some(compute_result)
} else if let Some(&input_cell) = self.map.get(&id) {
Some(input_cell)
} else {
None
}
}
pub fn set_value(&mut self, id: CellID, new_value: T) -> Result<(), ()> {
match self.map.entry(id) {
Entry::Occupied(mut e) => {
*e.get_mut() = new_value;
Ok(())
}
Entry::Vacant(_) => Err(()),
}
}
pub fn add_callback<F: FnMut(T) -> () + Clone>(
&mut self,
id: CellID,
callback: F,
) -> Result<CallbackID, ()> {
let id = self.next_callback_id;
self.next_callback_id += 1;
self.callbacks.insert(
id,
Callback {
source: id,
callback_func: Box::new(callback),
},
);
Ok(id)
}
pub fn remove_callback(&mut self, cell: CellID, callback: CallbackID) -> Result<(), ()> {
Ok(())
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment