1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use crate::{Manager, Mode};
use std::{cell::RefCell, rc::Rc};

/// A collection of channels to which [Node]s can [subscribe](Anchor::subscribe).
///
/// Anchors must be organized by a [Manager], this is done by implementing a data structure
/// containing various channels together with this trait.
///
/// A typical implementation may look like this:
/// ```
/// use revent::{Anchor, feed::Feed, Manager, Single, Slot};
/// use std::{cell::RefCell, rc::Rc};
///
/// struct MyAnchor {
///     a: Slot<()>,
///     b: Single<()>,
///     c: Feed<()>,
///     // more channels...
///     manager: Manager,
/// }
///
/// impl Anchor for MyAnchor {
///     fn manager(&self) -> &Manager {
///         &self.manager
///     }
/// }
/// ```
pub trait Anchor
where
    Self: Sized,
{
    /// Get the [Manager] of this anchor.
    fn manager(&self) -> &Manager;

    /// Add a node to this anchor.
    ///
    /// Uses [Node::register_listens] to figure out which slots to attach to.
    /// [Node::register_emits] is used to construct a struct that is given to `create`.
    fn subscribe<R, T, F>(&mut self, create: F) -> Rc<RefCell<T>>
    where
        T: Node<Self, R>,
        F: FnOnce(R) -> T,
    {
        let manager = self.manager().clone();
        crate::STACK.with(|x| {
            x.borrow_mut().push((Mode::Adding, manager.clone()));
        });

        manager.prepare_construction(T::NAME);

        let register_emits = T::register_emits(self);
        let item = Rc::new(RefCell::new(create(register_emits)));
        T::register_listens(self, item.clone());

        manager.finish_construction();
        crate::STACK.with(|x| {
            x.borrow_mut().pop();
        });
        item
    }

    /// Remove a node from this anchor.
    ///
    /// Uses [Node::register_listens] to figure out which slots to detach from.
    fn unsubscribe<T, R>(&mut self, input: &Rc<RefCell<T>>)
    where
        T: Node<Self, R>,
    {
        let manager = self.manager();
        crate::STACK.with(|x| {
            x.borrow_mut().push((Mode::Removing, manager.clone()));
        });

        T::register_listens(self, input.clone());

        crate::STACK.with(|x| {
            x.borrow_mut().pop();
        });
    }
}

/// Describes a subscriber that can subscribe to [Anchor].
/// ```
/// use revent::{Anchor, Manager, Slot, Node};
/// use std::{cell::RefCell, rc::Rc};
///
/// trait A {}
///
/// struct MyAnchor {
///     a: Slot<dyn A>,
///     manager: Manager,
/// }
///
/// impl Anchor for MyAnchor {
///     fn manager(&self) -> &Manager {
///         &self.manager
///     }
/// }
///
/// // ---
///
/// struct MyNode;
///
/// impl Node<MyAnchor, ()> for MyNode {
///     fn register_emits(_: &MyAnchor) -> () { () }
///
///     fn register_listens(slots: &mut MyAnchor, item: Rc<RefCell<Self>>) {
///         slots.a.register(item);
///     }
///
///     const NAME: &'static str = "MyNode";
/// }
///
/// impl A for MyNode {}
/// ```
pub trait Node<A: Anchor, T> {
    /// Create an object containing clones of the anchor's signals.
    ///
    /// Typically constructs a struct which is stored in `Self`. This struct is given
    /// [Anchor::subscribe]'s create function.
    /// May return `()` if no further signals are sent from this node.
    fn register_emits(anchor: &A) -> T;
    /// Register to various channels inside an [Anchor].
    ///
    /// Note that this function is used for both [subscribe](Anchor::subscribe) as well as
    /// [unsubscribe](Anchor::unsubscribe). So this function ought to not depend on the state of the
    /// item. If it does, then a node may still be subscribed to some channels after
    /// `unsubscribe` has been called.
    fn register_listens(anchor: &mut A, item: Rc<RefCell<Self>>);
    /// Unique name of the node.
    ///
    /// Used for figuring out recursions and graphing channel dependencies.
    const NAME: &'static str;
}