iron_ingot/any/
reactive.rs

1use crate::{IDManager, Shared};
2
3use std::{
4  any::type_name,
5  cell::{Ref, RefCell, RefMut},
6  fmt::{self, Debug, Formatter},
7  marker::PhantomData,
8  mem::transmute,
9  rc::Rc,
10};
11
12struct Child<T: ?Sized, R: ?Sized + Debug = dyn Debug> {
13  reactive: Shared<Reactive<R>>,
14  on_change: Box<dyn FnMut(&T) -> Box<R>>,
15}
16
17impl<T: ?Sized, R: ?Sized + Debug> Debug for Child<T, R> {
18  fn fmt(&self, formatter: &mut Formatter<'_>) -> Result<(), fmt::Error> {
19    formatter
20      .debug_struct(&format!(
21        "Child<{}, {}>",
22        type_name::<T>(),
23        type_name::<R>()
24      ))
25      .field("reactive", &self.reactive)
26      .finish_non_exhaustive()
27  }
28}
29
30#[derive(Debug)]
31pub struct Handle<T: ?Sized>(Shared<Reactive<dyn Debug>>, PhantomData<T>);
32
33impl<T: ?Sized> Handle<T> {
34  fn new(value: Shared<Reactive<dyn Debug>>) -> Self {
35    Self(value, PhantomData)
36  }
37
38  pub fn borrow(&self) -> Ref<Reactive<T>> {
39    // SAFETY: Reactive object has been created with a value of type T and has implicitly coerced into a trait object,
40    // therefore it is safe to transmute the trait object back into a reactive object with a value of type T.
41    unsafe { transmute::<_, &Shared<_>>(&self.0) }.borrow()
42  }
43
44  pub fn borrow_mut(&self) -> RefMut<Reactive<T>> {
45    // SAFETY: Reactive object has been created with a value of type T and has implicitly coerced into a trait object,
46    // therefore it is safe to transmute the trait object back into a reactive object with a value of type T.
47    unsafe { transmute::<_, &Shared<_>>(&self.0) }.borrow_mut()
48  }
49}
50
51impl<T: ?Sized> Clone for Handle<T> {
52  fn clone(&self) -> Self {
53    Self(Rc::clone(&self.0), PhantomData)
54  }
55}
56
57impl<T: Debug + 'static> Handle<T> {
58  pub fn from(value: T) -> Self {
59    Self(
60      Rc::new(RefCell::new(Reactive::new(Box::new(value), None))),
61      PhantomData,
62    )
63  }
64}
65
66impl<T: ?Sized> From<Shared<Reactive<dyn Debug>>> for Handle<T> {
67  fn from(value: Shared<Reactive<dyn Debug>>) -> Self {
68    Self(value, PhantomData)
69  }
70}
71
72impl<T: ?Sized> From<Reactive<dyn Debug>> for Handle<T> {
73  fn from(value: Reactive<dyn Debug>) -> Self {
74    Self(Rc::new(RefCell::new(value)), PhantomData)
75  }
76}
77
78/// A wrapper that listens for changes to the value being held and automatically notifies all registered watchers
79/// about the new value given. It is used to establish communications between multiple modules to achieve loose coupling
80/// between the modules involved.
81#[derive(Debug)]
82pub struct Reactive<T: ?Sized> {
83  watcher_id_manager: IDManager,
84  id: usize,
85  watcher_id: Option<usize>,
86  children: Vec<Option<Child<T>>>,
87  value: Box<T>,
88}
89
90impl<T: ?Sized> Reactive<T> {
91  fn new(value: Box<T>, watcher_id: Option<usize>) -> Self {
92    static mut ID_MANAGER: IDManager = IDManager::new();
93    Self {
94      watcher_id_manager: IDManager::new(),
95
96      // SAFETY: This function is only called by the main thread.
97      id: unsafe { ID_MANAGER.next() }.unwrap(),
98
99      watcher_id,
100      children: vec![],
101      value,
102    }
103  }
104
105  pub fn get_id(&self) -> usize {
106    self.id
107  }
108
109  pub fn get_value(&self) -> &T {
110    &self.value
111  }
112
113  /// Retrieves a mutable reference to the inner value of this object to allow direct manipulation of the reactive
114  /// value.
115  ///
116  /// # Safety
117  /// Users who have called this function and have modified tha inner value of this object must ensure they
118  /// call `self.wake_children()` so that all watchers registered to this object will be notified with an updated value.
119  ///
120  /// It returns a mutable reference to the inner value of this object.
121  pub(crate) unsafe fn get_value_mut(&mut self) -> &mut T {
122    &mut self.value
123  }
124
125  /// Notifies all other reactive objects associated with their watchers about the new value given just now.
126  ///
127  /// # Safety
128  /// Users should only call this function after they have changed the inner value of this object through a
129  /// mutable reference received through `self.get_value_mut()` function. Calling this function prematurely when the
130  /// inner value has not changed might cause watcher functions that produce side effects to introduce unexpected
131  /// behaviors or errors for the program in the future.
132  pub(crate) unsafe fn wake_children(&mut self) {
133    for child in &mut self.children.iter_mut().flatten() {
134      child
135        .reactive
136        .borrow_mut()
137        .set_boxed_value((child.on_change)(&*self.value));
138    }
139  }
140
141  /// Registers a new watcher that transforms this reactive object into a new reactive object that holds a different
142  /// type.
143  ///
144  /// `on_change`: It is a watcher that listens for new value and processes it.
145  ///
146  /// It returns a transformed reactive object that can be unwatched on in the future.
147  pub fn watch<U: Debug + 'static>(
148    &mut self,
149    mut on_change: impl FnMut(&T) -> U + 'static,
150  ) -> Handle<U> {
151    let watcher_id = self.watcher_id_manager.next().unwrap();
152    let reactive: Shared<Reactive<dyn Debug>> = Rc::new(RefCell::new(Reactive::new(
153      Box::new(on_change(&self.value)),
154      Some(watcher_id),
155    )));
156    let child: Child<_, dyn Debug> = Child {
157      on_change: Box::new(move |value| Box::new(on_change(value))),
158      reactive: Rc::clone(&reactive),
159    };
160    if watcher_id == self.children.len() {
161      self.children.push(Some(child));
162    } else {
163      self.children[watcher_id] = Some(child);
164    }
165    Handle::new(reactive)
166  }
167
168  /// Detaches the registered watcher associated with the `reactive` given so the watcher no longer reacts to
169  /// changes of the value held by this reactive object.
170  ///
171  /// `reactive`: The transformed reactive that is associated with the watcher to be unwatched.
172  pub fn unwatch<U: ?Sized + Debug>(&mut self, reactive: Handle<U>) {
173    let watcher_id = reactive.borrow().watcher_id.unwrap();
174    self.children[watcher_id] = None;
175    self.watcher_id_manager.free(watcher_id).unwrap();
176  }
177}
178
179impl<T: ?Sized + Debug> Reactive<T> {
180  fn set_boxed_value(&mut self, value: Box<T>) {
181    if format!("{:?}", &*self.value) == format!("{:?}", &*value) {
182      return;
183    }
184    self.value = value;
185
186    // SAFETY: The inner value has already changed.
187    unsafe { self.wake_children() };
188  }
189}
190
191impl<T> Reactive<T> {
192  pub fn into_value(self) -> T {
193    *self.value
194  }
195}
196
197impl<T: Debug> Reactive<T> {
198  pub fn set_value(&mut self, value: T) {
199    self.set_boxed_value(Box::new(value));
200  }
201}
202
203impl<T: ?Sized> From<Handle<T>> for Shared<Reactive<dyn Debug>> {
204  fn from(value: Handle<T>) -> Self {
205    value.0
206  }
207}
208
209impl<T: ?Sized> From<Handle<T>> for Reactive<dyn Debug> {
210  fn from(value: Handle<T>) -> Self {
211    Rc::try_unwrap(value.0)
212      .expect(
213        "value should be the only reactive handle instance to a particular reactive object exists at the current moment!"
214      )
215      .into_inner()
216  }
217}
218
219impl<T: Debug> From<Handle<T>> for Reactive<T> {
220  fn from(value: Handle<T>) -> Self {
221    // SAFETY: Reactive object has been created with a value of type T and has implicitly coerced into a trait object,
222    // therefore it is safe to transmute the trait object back into a reactive object with a value of type T.
223    Rc::try_unwrap(unsafe { transmute::<_, Shared<_>>(value.0) })
224      .expect(
225        "value should be the only reactive handle instance to a particular reactive object exists at the current moment!"
226      )
227      .into_inner()
228  }
229}