fgr 0.3.1

Fine-grained reactivity for Rust
Documentation
use super::context::{batch, clear_dirty_flag_at_end, mark_nodes_to_be_updated, outer_node};
use std::cell::{Cell, RefCell, Ref, RefMut};
use std::ops::{Deref, DerefMut};
use std::rc::{Rc, Weak};

pub struct Node {
    pub this: Rc<RefCell<Option<Weak<dyn HasNode>>>>,
    pub update_op: RefCell<Option<Box<dyn FnMut()->bool>>>,
    pub visited: Cell<bool>,
    pub dirty: Cell<bool>,
    pub dependencies: RefCell<Vec<Rc<dyn HasNode>>>,
    pub dependents: RefCell<Vec<Weak<dyn HasNode>>>,
}

pub trait HasNode {
    fn node(&self) -> &Node;
}

impl HasNode for Node {
    fn node(&self) -> &Node {
        self
    }
}

impl Node {
    pub fn new(this: Rc<RefCell<Option<Weak<dyn HasNode>>>>) -> Node {
        Node {
            this,
            update_op: RefCell::new(None),
            visited: Cell::new(false),
            dirty: Cell::new(false),
            dependencies: RefCell::new(Vec::new()),
            dependents: RefCell::new(Vec::new()),
        }
    }
}

impl Drop for Node {
    fn drop(&mut self) {
        let this = self.this.borrow();
        let this = this.as_ref().unwrap();
        for dependency in &*self.dependencies.borrow() {
            dependency.node().dependents.borrow_mut().retain(|x| !x.ptr_eq(this));
        }
    }
}

pub struct NodeWithValue<A> {
    pub value: RefCell<Option<A>>,
    pub node: Node,
}

impl<A> NodeWithValue<A> {
    pub fn new(this: Rc<RefCell<Option<Weak<dyn HasNode>>>>, value: A) -> NodeWithValue<A> {
        NodeWithValue {
            value: RefCell::new(Some(value)),
            node: Node::new(this),
        }
    }

    pub fn new2(node: Node) -> NodeWithValue<A> {
        NodeWithValue {
            value: RefCell::new(None),
            node,
        }
    }
}

impl<A> HasNode for NodeWithValue<A> {
    fn node(&self) -> &Node {
        &self.node
    }
}

pub struct NodeValRef<'a,A> {
    x: Ref<'a,Option<A>>,
    read: Cell<bool>,
    node: Rc<dyn HasNode>,
}

impl<'a,A> NodeValRef<'a,A> {
    pub fn new(node_with_value: &'a NodeWithValue<A>, node: Rc<dyn HasNode>) -> NodeValRef<'a,A> {
        NodeValRef {
            x: node_with_value.value.borrow(),
            read: Cell::new(false),
            node
        }
    }
}

impl<'a,A> Deref for NodeValRef<'a,A> {
    type Target = A;

    fn deref(&self) -> &Self::Target {
        self.read.set(true);
        self.x.deref().as_ref().unwrap()
    }
}

impl<'a,A> Drop for NodeValRef<'a,A> {
    fn drop(&mut self) {
        if self.read.get() {
            if let Some(outer_node) = outer_node() {
                outer_node.node().dependencies.borrow_mut().push(self.node.clone());
                self.node.node().dependents.borrow_mut().push(Rc::downgrade(&outer_node));
            }
        }
    }
}

pub struct NodeValRefMut<'a,A> {
    x: Option<RefMut<'a,Option<A>>>,
    written: Cell<bool>,
    node: Rc<dyn HasNode>,
}

impl<'a,A> NodeValRefMut<'a,A> {
    pub fn new(node_with_value: &'a NodeWithValue<A>, node: Rc<dyn HasNode>) -> NodeValRefMut<'a,A> {
        NodeValRefMut {
            x: Some(node_with_value.value.borrow_mut()),
            written: Cell::new(false),
            node
        }
    }
}

impl<'a,A> Deref for NodeValRefMut<'a,A> {
    type Target = A;

    fn deref(&self) -> &Self::Target {
        self.x.as_ref().unwrap().deref().as_ref().unwrap()
    }
}

impl<'a,A> DerefMut for NodeValRefMut<'a,A> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.written.set(true);
        self.x.as_mut().unwrap().deref_mut().as_mut().unwrap()
    }
}

impl<'a,A> Drop for NodeValRefMut<'a,A> {
    fn drop(&mut self) {
        self.x = None;
        if self.written.get() {
            batch(|| {
                self.node.node().dirty.set(true);
                clear_dirty_flag_at_end(Rc::downgrade(&self.node));
                mark_nodes_to_be_updated([Rc::downgrade(&self.node)].iter().cloned());
            });
        }
    }
}