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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
//! Common code used between different engines.
//!
//! Unless you're implementing your own generic `AnchorInner`s or your own execution engine,
//! you should never need to import things from here. `singlethread` should re-export anything
//! you need to use `anchors`!

use std::marker::PhantomData;
use std::panic::Location;

mod ext;
pub use ext::{AnchorExt, AnchorSplit};
mod constant;
mod var;
pub use constant::Constant;
pub use var::{Var, VarSetter};

/// Indicates whether a value is ready for reading, and if it is, whether it's changed
/// since the last read.
#[derive(Debug, PartialEq, Eq)]
pub enum Poll {
    /// Indicates the polled value is ready for reading. Either this is the first read,
    /// or the value has changed since the last read.
    Updated,

    /// Indicates the polled value is ready for reading. This is not the first read, and
    /// the value is unchanged since the previous read.
    Unchanged,

    /// Indicates the polled value is not ready for reading, but has been queued for recalculation.
    /// The output value will eventually switch to Updated or Unchanged.
    Pending,
}

/// The main struct of the Anchors library. Represents a single value on the recomputation graph.
///
/// This doesn't contain the particular Anchor implementation directly, but instead contains an
/// engine-specific `AnchorHandle` which allows the recalculation engine to identify which
/// internal recomputation graph node this corresponds to. You should rarely create Anchors yourself;
/// instead use one of the built-in functions like `Var::new` to create one, or create derivative Anchors
/// with one of the `AnchorExt` methods.
pub struct Anchor<O, E: Engine + ?Sized> {
    data: E::AnchorHandle,
    phantom: PhantomData<O>,
}

impl<O, E: Engine> Anchor<O, E> {
    pub fn new(data: E::AnchorHandle) -> Self {
        Self {
            data,
            phantom: PhantomData,
        }
    }

    /// Returns the immutable, copyable, hashable, comparable engine-specific ID for this Anchor.
    pub fn token(&self) -> <E::AnchorHandle as AnchorHandle>::Token {
        self.data.token()
    }
}

impl<O, E: Engine> Clone for Anchor<O, E> {
    fn clone(&self) -> Self {
        Self {
            data: self.data.clone(),
            phantom: PhantomData,
        }
    }
}

impl<O, E: Engine> PartialEq for Anchor<O, E> {
    fn eq(&self, other: &Self) -> bool {
        self.token() == other.token()
    }
}
impl<O, E: Engine> Eq for Anchor<O, E> {}

/// A reference to a particular `AnchorInner`. Each engine implements its own.
pub trait AnchorHandle: Sized + Clone {
    type Token: Sized + Clone + Copy + PartialEq + Eq + std::hash::Hash;

    /// Returns a Copyable, comparable, hashable ID corresponding to this AnchorHandle.
    /// Some engines may garbage collect an AnchorInner when no more AnchorHandles pointing
    /// to it exist, which means it's possible to have a Token pointing to a since-deleted
    /// Anchor.
    fn token(&self) -> Self::Token;
}

/// The core engine trait implemented by each recalculation engine. Allows mounting an `AnchorInner`
/// into an actual `Anchor`, although this mounting should usually be done by each `AnchorInner`
/// implementation directly.
pub trait Engine: 'static {
    type AnchorHandle: AnchorHandle;
    type DirtyHandle: DirtyHandle;

    fn mount<I: AnchorInner<Self> + 'static>(inner: I) -> Anchor<I::Output, Self>;
}

/// Allows a node with non-Anchors inputs to manually mark itself as dirty. Each engine implements its own.
pub trait DirtyHandle {
    /// Indicates that the Anchor associated with this `DirtyHandle` may have a changed its output, and should
    /// be repolled.
    fn mark_dirty(&self);
}

/// The context passed to an `AnchorInner` when its `output` method is called.
pub trait OutputContext<'eng> {
    type Engine: Engine + ?Sized;

    /// If another Anchor during polling indicated its value was ready, the previously
    /// calculated value can be accessed with this method. Its implementation is virtually
    /// identical to `UpdateContext`'s `get`. This is mostly used by AnchorInner implementations
    /// that want to return a reference to some other Anchor's output without cloning.
    fn get<'out, O: 'static>(&self, anchor: &Anchor<O, Self::Engine>) -> &'out O
    where
        'eng: 'out;
}

/// The context passed to an `AnchorInner` when its `poll_updated` method is called.
pub trait UpdateContext {
    type Engine: Engine + ?Sized;

    /// If `request` indicates another Anchor's value is ready, the previously
    /// calculated value can be accessed with this method.
    fn get<'out, 'slf, O: 'static>(&'slf self, anchor: &Anchor<O, Self::Engine>) -> &'out O
    where
        'slf: 'out;

    /// If `anchor`'s output is ready, indicates whether the output has changed since this `AnchorInner`
    /// last called `request` on it. If `anchor`'s output is not ready, it is queued for recalculation and
    /// this returns Poll::Pending.
    ///
    /// `necessary` is a bit that indicates if we are necessary, `anchor` should be marked as necessary
    /// as well. If you don't know what this bit should be set to, you probably want a value of `true`.
    fn request<'out, O: 'static>(
        &mut self,
        anchor: &Anchor<O, Self::Engine>,
        necessary: bool,
    ) -> Poll;

    /// If `anchor` was previously passed to `request` and you no longer care about its output, you can
    /// pass it to `unrequest` so the engine will stop calling your `dirty` method when `anchor` changes.
    /// If `self` is necessary, this is also critical for ensuring `anchor` is no longer marked as necessary.
    fn unrequest<'out, O: 'static>(&mut self, anchor: &Anchor<O, Self::Engine>);

    /// Returns a new dirty handle, used for marking that `self`'s output may have changed through some
    /// non incremental means. For instance, perhaps this `AnchorInner`s value represents the current time, or
    /// it's a `Var` that has a setter function.
    fn dirty_handle(&mut self) -> <Self::Engine as Engine>::DirtyHandle;
}

/// The engine-agnostic implementation of each type of Anchor. You likely don't need to implement your own
/// `AnchorInner`; instead use one of the built-in implementations.
pub trait AnchorInner<E: Engine + ?Sized> {
    type Output;

    /// Called by the engine to indicate some input may have changed.
    /// If this `AnchorInner` still cares about `child`'s value, it should re-request
    /// it next time `poll_updated` is called.
    fn dirty(&mut self, child: &<E::AnchorHandle as AnchorHandle>::Token);

    /// Called by the engine when it wants to know if this value has changed or
    /// not. If some requested value from `ctx` is `Pending`, this method should
    /// return `Poll::Pending`; otherwise it must finish recalculation and report
    /// either `Poll::Updated` or `Poll::Unchanged`.
    fn poll_updated<G: UpdateContext<Engine = E>>(&mut self, ctx: &mut G) -> Poll;

    /// Called by the engine to get the current output value of this `AnchorInner`. This
    /// is *only* called after this `AnchorInner` reported in the return value from
    /// `poll_updated` the value was ready. If `dirty` is called, this function will not
    /// be called until `poll_updated` returns a non-Pending value.
    fn output<'slf, 'out, G: OutputContext<'out, Engine = E>>(
        &'slf self,
        ctx: &mut G,
    ) -> &'out Self::Output
    where
        'slf: 'out;

    /// An optional function to report the track_caller-derived callsite where
    /// this Anchor was created. Useful for debugging purposes.
    fn debug_location(&self) -> Option<(&'static str, &'static Location<'static>)> {
        None
    }
}