standing_relations/feedback/
context.rs

1use std::{
2    cell::RefCell,
3    hash::Hash,
4    ops::{Deref, DerefMut},
5    rc::Rc,
6    sync::{Arc, RwLock},
7};
8
9use crate::{
10    core::{
11        self,
12        pipes::{self, Receiver, Sender},
13        TrackingIndex,
14    },
15    Input, InputRelation,
16};
17
18use self::{
19    input_change_tracker::{InputChangeTracker, IsInputChangeTracker},
20    pq_receiver::PQReceiver,
21};
22
23use super::op::{Instruct, IsFeedback, IsFeeder};
24
25pub use self::tracker::ContextTracker;
26
27mod input_change_tracker;
28mod pq_receiver;
29mod tracker;
30
31pub struct CreationContext<'a, I = ()> {
32    inner: core::CreationContext<'a>,
33    feeders: Vec<Box<dyn IsFeeder<'a, I> + 'a>>,
34    input_trackers: Vec<Rc<RefCell<dyn IsInputChangeTracker<I> + 'a>>>,
35    extra_edges: Arc<RwLock<Vec<(TrackingIndex, TrackingIndex)>>>,
36    dirty_send: Sender<usize>,
37    dirty_receive: Receiver<usize>,
38}
39
40impl<I> Default for CreationContext<'_, I> {
41    fn default() -> Self {
42        let (dirty_send, dirty_receive) = pipes::new();
43        Self {
44            inner: Default::default(),
45            feeders: Default::default(),
46            input_trackers: Default::default(),
47            extra_edges: Default::default(),
48            dirty_send,
49            dirty_receive,
50        }
51    }
52}
53
54pub struct ExecutionContext<'a, I = ()> {
55    inner: core::ExecutionContext<'a>,
56    feeders: Vec<Box<dyn IsFeeder<'a, I> + 'a>>,
57    input_trackers: Vec<Rc<RefCell<dyn IsInputChangeTracker<I> + 'a>>>,
58    extra_edges: Arc<RwLock<Vec<(TrackingIndex, TrackingIndex)>>>,
59    dirty: PQReceiver,
60}
61
62impl<'a, I> ExecutionContext<'a, I> {
63    pub fn commit(&mut self) -> Option<I> {
64        loop {
65            self.inner.commit();
66            match self.dirty.pop_min() {
67                Some(feeder_index) => match self.feeders[feeder_index].feed(&self.inner) {
68                    Instruct::Unchanged => (),
69                    Instruct::Changed => self.dirty.insert(feeder_index),
70                    Instruct::Interrupt(interrupted) => return Some(interrupted),
71                },
72                None => return None,
73            }
74        }
75    }
76    pub fn tracker(&self) -> ContextTracker {
77        ContextTracker::new(self.inner.tracker().clone(), self.extra_edges.clone())
78    }
79    pub fn in_frame<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
80        for input_tracker in self.input_trackers.iter() {
81            input_tracker.borrow_mut().push_frame();
82        }
83        let result = f(self);
84        for input_tracker in self.input_trackers.iter() {
85            input_tracker.borrow_mut().pop_frame(self);
86        }
87        result
88    }
89}
90
91impl<'a, I> CreationContext<'a, I> {
92    pub fn new_() -> Self {
93        Default::default()
94    }
95    pub fn new_trackable_input<D: Eq + Hash + Clone + 'a>(
96        &mut self,
97    ) -> (Input<'a, D>, InputRelation<D>) {
98        let (mut input, relation) = self.inner.new_input_::<(D, isize)>();
99        let tracker: Rc<RefCell<InputChangeTracker<D>>> =
100            Rc::new(RefCell::new(InputChangeTracker::new(input.clone())));
101        {
102            let tracker = Rc::clone(&tracker);
103            input.add_listener(&self.inner, move |kvs| {
104                tracker.borrow_mut().add_changes(kvs)
105            });
106        }
107        self.input_trackers.push(tracker);
108        (input, relation)
109    }
110    pub fn begin(self) -> ExecutionContext<'a, I> {
111        ExecutionContext {
112            inner: self.inner.begin(),
113            feeders: self.feeders,
114            input_trackers: self.input_trackers,
115            extra_edges: self.extra_edges,
116            dirty: PQReceiver::new(self.dirty_receive),
117        }
118    }
119    pub(super) fn add_feeder(
120        &mut self,
121        mut feeder: impl IsFeedback<'a, I> + 'a,
122        extra_edge: Option<(TrackingIndex, TrackingIndex)>,
123    ) {
124        let mut dirty_send = self.dirty_send.clone();
125        let i = self.feeders.len();
126        feeder.add_listener(self, move || dirty_send.send(i));
127        self.feeders.push(Box::new(feeder));
128        if let Some(edge) = extra_edge {
129            self.extra_edges.write().unwrap().push(edge);
130        }
131    }
132    pub fn tracker(&self) -> ContextTracker {
133        ContextTracker::new(self.inner.tracker().clone(), self.extra_edges.clone())
134    }
135}
136
137impl<'a, I> Deref for CreationContext<'a, I> {
138    type Target = core::CreationContext<'a>;
139
140    fn deref(&self) -> &Self::Target {
141        &self.inner
142    }
143}
144
145impl<'a, I> DerefMut for CreationContext<'a, I> {
146    fn deref_mut(&mut self) -> &mut Self::Target {
147        &mut self.inner
148    }
149}
150
151impl<'a, I> Deref for ExecutionContext<'a, I> {
152    type Target = core::ExecutionContext<'a>;
153
154    fn deref(&self) -> &Self::Target {
155        &self.inner
156    }
157}
158
159impl<'a, I> DerefMut for ExecutionContext<'a, I> {
160    fn deref_mut(&mut self) -> &mut Self::Target {
161        &mut self.inner
162    }
163}