duat_core/
data.rs

1//! Duat's way of sharing and updating state
2//!
3//! This module consists primarily of the [`RwData`] struct, which
4//! holds state that can be [read] or [written to]. When it is
5//! modified, other holders of a clone of [`RwData`] will know that
6//! the data within has been modified.
7//!
8//! This is used in many places, for example, [`Widget`]s can read
9//! from [`File`]s, and Duat can know when a [`File`] has been
10//! altered, so these [`Widget`]s may be [updated] automatically.
11//!
12//! Another struct from this module is [`DataMap`]. This is
13//! essentially a mapping for a [`RwData`]. It is created via
14//! [`RwData::map`], and both it and [`RwData`] can be very useful in,
15//! for example, a [`StatusLine`], since it will be updated
16//! automatically whenever the [`RwData`] is altered.
17//!
18//! One thing to note however is that [`RwData`] is a type mostly used
19//! by Duat itself, inside APIs like those of [`context`], so if you
20//! want information to be shared across threads and you don't need
21//! others to be able to reach it, you should prefer using more
22//! conventional locking mechanisms, like those of [`parking_lot`],
23//! which are exported by Duat.
24//!
25//! [read]: RwData::read
26//! [written to]: RwData::write
27//! [`Widget`]: crate::widgets::Widget
28//! [`File`]: crate::widgets::File
29//! [updated]: crate::widgets::Widget::update
30//! [`Text`]: crate::text::Text
31//! [`StatusLine`]: crate::widgets::StatusLine
32//! [`context`]: crate::context
33use std::{
34    any::TypeId,
35    sync::{
36        Arc,
37        atomic::{AtomicUsize, Ordering},
38    },
39};
40
41use parking_lot::{Mutex, MutexGuard};
42
43/// A read write shared reference to data
44pub struct RwData<T: ?Sized + 'static> {
45    // The `Box` is to allow for downcasting.
46    pub(super) data: Arc<Mutex<T>>,
47    pub(super) cur_state: Arc<AtomicUsize>,
48    read_state: AtomicUsize,
49    pub(super) type_id: TypeId,
50}
51
52impl<T> RwData<T> {
53    /// Returns a new instance of a [`RwData`], assuming that it is
54    /// sized.
55    ///
56    /// This has to be sized because of some Rust limitations, as you
57    /// can`t really pass an unsized argument to a function (for now).
58    /// If you're looking to store unsized types (`dyn Trait`,
59    /// `\[Type\]`, etc) on an [`RwData`], see
60    /// [`RwData::new_unsized`].
61    pub fn new(data: T) -> Self {
62        Self {
63            data: Arc::new(Mutex::new(data)),
64            cur_state: Arc::new(AtomicUsize::new(1)),
65            read_state: AtomicUsize::new(1),
66            type_id: TypeId::of::<T>(),
67        }
68    }
69}
70
71impl<T: ?Sized> RwData<T> {
72    /// Returns a new instance of [`RwData`], assuming that it is
73    /// unsized.
74    ///
75    /// This method is only required if you're dealing with types that
76    /// may not be [`Sized`] (`dyn Trait`, `[Type]`, etc). If the type
77    /// in question is sized, use [`RwData::new`] instead.
78    pub fn new_unsized<SizedT: 'static>(data: Arc<Mutex<T>>) -> Self {
79        Self {
80            data,
81            cur_state: Arc::new(AtomicUsize::new(1)),
82            read_state: AtomicUsize::new(1),
83            type_id: TypeId::of::<SizedT>(),
84        }
85    }
86
87    /// Blocking reference to the information
88    ///
89    /// Also makes it so that [`has_changed`] returns `false`.
90    ///
91    /// # Examples
92    ///
93    /// Since this is a blocking read, the thread will hault while the
94    /// data is being written to:
95    ///
96    /// ```rust
97    /// # use std::{thread, time::{Duration, Instant}};
98    /// # use duat_core::data::RwData;
99    /// let data = RwData::new("☹️");
100    /// let data_clone = data.clone();
101    /// let instant = Instant::now();
102    /// thread::scope(|scope| {
103    ///     scope.spawn(|| {
104    ///         let mut read_write = data.write();
105    ///         // Supposedly long computations.
106    ///         thread::sleep(Duration::from_millis(150));
107    ///         *read_write = "☺️";
108    ///     });
109    ///
110    ///     // Just making sure that the read happens slightly after the write.
111    ///     thread::sleep(Duration::from_millis(10));
112    ///
113    ///     let read_only = data_clone.read();
114    ///     let time_elapsed = Instant::now().duration_since(instant);
115    ///     assert!(time_elapsed >= Duration::from_millis(100));
116    ///     assert!(*read_only == "☺️");
117    /// });
118    /// ```
119    ///
120    /// [`has_changed`]: Self::has_changed
121    pub fn read(&self) -> ReadDataGuard<'_, T> {
122        let cur_state = self.cur_state.load(Ordering::Acquire);
123        self.read_state.store(cur_state, Ordering::Release);
124        ReadDataGuard(self.data.lock())
125    }
126
127    /// Non blocking reference to the information
128    ///
129    /// If successful, also makes it so that [`has_changed`] returns
130    /// `false`.
131    ///
132    /// # Examples
133    ///
134    /// Unlike [`read`], can fail to return a reference to the
135    /// underlying data:
136    ///
137    /// ```rust
138    /// # use std::{sync::TryLockError};
139    /// # use duat_core::data::RwData;
140    /// let new_data = RwData::new("hello 👋");
141    ///
142    /// let mut blocking_write = new_data.write();
143    /// *blocking_write = "bye 👋";
144    ///
145    /// let try_read = new_data.try_read();
146    /// assert!(matches!(try_read, None));
147    /// ```
148    ///
149    /// [`has_changed`]: Self::has_changed
150    /// [`read`]: Self::read
151    pub fn try_read(&self) -> Option<ReadDataGuard<'_, T>> {
152        self.data.try_lock().map(|guard| {
153            let cur_state = self.cur_state.load(Ordering::Acquire);
154            self.read_state.store(cur_state, Ordering::Release);
155            ReadDataGuard(guard)
156        })
157    }
158
159    /// Whether or not it has changed since it was last read
160    ///
161    /// A "change" is defined as any time the methods [`write`]
162    /// or [`try_write`] are called on an [`RwData`]. Once
163    /// `has_changed` is called, the data will be considered
164    /// unchanged since the last `has_changed` call, for
165    /// that specific instance of a [`RwData`].
166    ///
167    /// When first creating a [`RwData`] `has_changed` will return
168    /// `false`, but clones of that [`RwData`] will have `has_changed`
169    /// initially return `true`.
170    ///
171    /// # Examples
172    ///
173    /// ```rust
174    /// use duat_core::data::RwData;
175    /// let data = RwData::new("Initial text");
176    /// assert!(!data.has_changed());
177    ///
178    /// *data.write() = "Almost final text";
179    ///
180    /// let data_clone1 = data.clone();
181    ///
182    /// assert!(data_clone1.has_changed());
183    ///
184    /// *data.write() = "Final text";
185    ///
186    /// assert!(data_clone1.has_changed());
187    /// assert!(!data_clone1.has_changed());
188    /// ```
189    ///
190    /// [`write`]: RwData::write
191    /// [`try_write`]: RwData::try_write
192    pub fn has_changed(&self) -> bool {
193        let cur_state = self.cur_state.load(Ordering::Acquire);
194        let read_state = self.read_state.swap(cur_state, Ordering::Acquire);
195        cur_state > read_state
196    }
197
198    /// A function that returns true if the data has changed
199    ///
200    /// This is essentially a faster way of writing
201    ///
202    /// ```rust
203    /// # use duat_core::data::RwData;
204    /// let my_data = RwData::new(42);
205    /// let checker = {
206    ///     let my_data = my_data.clone();
207    ///     move || my_data.has_changed()
208    /// };
209    /// ```
210    ///
211    /// [`Widget`]: crate::widgets::Widget
212    pub fn checker(&self) -> impl Fn() -> bool + Send + Sync + 'static + use<T> {
213        let cur_state = self.cur_state.clone();
214        let read_state = AtomicUsize::new(self.read_state.load(Ordering::Relaxed));
215        move || {
216            let cur_state = cur_state.load(Ordering::Acquire);
217            let read_state = read_state.swap(cur_state, Ordering::Acquire);
218            cur_state > read_state
219        }
220    }
221
222    /// Returns `true` if both [`RwData`]s point to the same data
223    ///
224    /// # Examples
225    /// ```rust
226    /// # use duat_core::data::{RwData};
227    /// let data_1 = RwData::new(false);
228    /// let data_1_clone = data_1.clone();
229    ///
230    /// let data_2 = RwData::new(true);
231    ///
232    /// assert!(data_1.ptr_eq(&data_1_clone));
233    /// assert!(!data_1.ptr_eq(&data_2));
234    /// ```
235    pub fn ptr_eq<U: ?Sized>(&self, other: &RwData<U>) -> bool {
236        Arc::ptr_eq(&self.cur_state, &other.cur_state)
237    }
238
239    /// Blocking exclusive reference to the information
240    ///
241    /// Also makes it so that [`has_changed`] returns true for any of
242    /// the clones made from `self`, but **NOT** `self`.
243    ///
244    /// # Safety
245    ///
246    /// Since this is a blocking function, you should be careful about
247    /// the prevention of deadlocks, one of the few unsafe aspects of
248    /// code that Rust doesn't prevent.
249    ///
250    /// As an example, this code will deadlock indefinitely:
251    /// ```no_run
252    /// # use std::{mem, thread, time::Duration};
253    /// # use duat_core::data::RwData;
254    /// let data_1 = RwData::new('😟');
255    /// let data_2 = RwData::new('😭');
256    ///
257    /// thread::scope(|scope| {
258    ///     scope.spawn(|| {
259    ///         let mut data_1 = data_1.write();
260    ///         thread::sleep(Duration::from_millis(100));
261    ///         let mut data_2 = data_2.write();
262    ///         mem::swap(&mut data_1, &mut data_2);
263    ///     });
264    ///
265    ///     scope.spawn(|| {
266    ///         let mut data_2 = data_2.write();
267    ///         thread::sleep(Duration::from_millis(100));
268    ///         let mut data_1 = data_1.write();
269    ///         mem::swap(&mut data_1, &mut data_2);
270    ///     });
271    /// });
272    /// ```
273    ///
274    /// [`has_changed`]: RwData::has_changed
275    pub fn write(&self) -> WriteDataGuard<T> {
276        let guard = self.data.lock();
277        WriteDataGuard {
278            guard,
279            cur_state: &self.cur_state,
280            read_state: &self.read_state,
281        }
282    }
283
284    /// Non Blocking mutable reference to the information
285    ///
286    /// Also makes it so that [`has_changed`] returns true for any of
287    /// the clones made from `self`, but **NOT** `self`.
288    ///
289    /// # Safety
290    ///
291    /// Unlike [`RwData::write`], this method cannot cause deadlocks,
292    /// returning an [`Err`] instead.
293    /// ```
294    /// # use std::{mem, thread, time::Duration};
295    /// # use duat_core::data::RwData;
296    /// let data_1 = RwData::new('😀');
297    /// let data_2 = RwData::new('😁');
298    ///
299    /// thread::scope(|scope| {
300    ///     scope.spawn(|| {
301    ///         let mut data_1 = data_1.try_write();
302    ///         thread::sleep(Duration::from_millis(100));
303    ///         let mut data_2 = data_2.try_write();
304    ///         if let (Some(mut data_1), Some(mut data_2)) = (data_1, data_2) {
305    ///             mem::swap(&mut data_1, &mut data_2);
306    ///         }
307    ///     });
308    ///
309    ///     scope.spawn(|| {
310    ///         let mut data_2 = data_2.try_write();
311    ///         thread::sleep(Duration::from_millis(100));
312    ///         let mut data_1 = data_1.try_write();
313    ///         if let (Some(mut data_1), Some(mut data_2)) = (data_1, data_2) {
314    ///             mem::swap(&mut data_1, &mut data_2);
315    ///         }
316    ///     });
317    /// });
318    ///
319    /// // Two swaps will happen.
320    /// assert_eq!(*data_1.read(), '😀');
321    /// assert_eq!(*data_2.read(), '😁');
322    /// ```
323    /// The downside is that you may not want it to fail ever, in
324    /// which case, you should probably use [`RwData::write`].
325    ///
326    /// [`has_changed`]: RwData::has_changed
327    pub fn try_write(&self) -> Option<WriteDataGuard<'_, T>> {
328        self.data.try_lock().map(|guard| WriteDataGuard {
329            guard,
330            cur_state: &self.cur_state,
331            read_state: &self.read_state,
332        })
333    }
334
335    /// Blocking reference to the information
336    ///
337    /// Unlike [`read`], *DOES NOT* make it so
338    /// [`has_changed`] returns `false`.
339    ///
340    /// This method should only be used in very specific
341    /// circumstances, such as when multiple owners have nested
342    /// [`RwData`]s, thus referencing the same inner [`RwData`], in
343    /// a way that reading from one point would interfere in the
344    /// update detection of the other point.
345    ///
346    /// [`read`]: Self::read,
347    /// [`has_changed`]: Self::has_changed
348    pub(crate) fn raw_read(&self) -> ReadDataGuard<'_, T> {
349        ReadDataGuard(self.data.lock())
350    }
351
352    /// Returns `true` if the data is of the concrete type `T`
353    ///
354    /// # Examples
355    ///
356    /// You may want this method if you're storing a list of
357    /// [`RwData<dyn Trait>`], and want to know, at runtime, what type
358    /// each element is:
359    /// ```rust
360    /// # use std::{any::Any, fmt::Display, sync::Arc};
361    /// # use duat_core::{Mutex, data::RwData};
362    /// let list: [RwData<dyn Display>; 3] = [
363    ///     RwData::new_unsized::<String>(Arc::new(Mutex::new(String::from(
364    ///         "I can show you the world",
365    ///     )))),
366    ///     RwData::new_unsized::<String>(Arc::new(Mutex::new(String::from(
367    ///         "Shining, shimmering, splendid",
368    ///     )))),
369    ///     RwData::new_unsized::<char>(Arc::new(Mutex::new('🧞'))),
370    /// ];
371    ///
372    /// assert!(list[0].data_is::<String>());
373    /// assert!(list[1].data_is::<String>());
374    /// assert!(list[2].data_is::<char>());
375    /// ```
376    ///
377    /// [`RwData<dyn Trait>`]: RwData
378    pub fn data_is<U: ?Sized + 'static>(&self) -> bool {
379        self.type_id == TypeId::of::<U>()
380    }
381
382    /// Tries to downcast to a concrete type
383    ///
384    /// # Examples
385    ///
386    /// You may want this method if you're storing a list of
387    /// [`RwData<dyn Trait>`], and want to know, at runtime, what type
388    /// each element is:
389    /// ```rust
390    /// # use std::{fmt::Display, sync::Arc};
391    /// # use duat_core::{Mutex, data::RwData};
392    /// let list: [RwData<dyn Display>; 3] = [
393    ///     RwData::new_unsized::<String>(Arc::new(Mutex::new(String::from(
394    ///         "I can show you the world",
395    ///     )))),
396    ///     RwData::new_unsized::<String>(Arc::new(Mutex::new(String::from(
397    ///         "Shining, shimmering, splendid",
398    ///     )))),
399    ///     RwData::new_unsized::<char>(Arc::new(Mutex::new('🧞'))),
400    /// ];
401    ///
402    /// let maybe_char = list[2].clone().try_downcast::<char>();
403    /// assert!(maybe_char.is_some());
404    /// *maybe_char.unwrap().write() = '👳';
405    ///
406    /// let maybe_string = list[0].clone().try_downcast::<char>();
407    /// assert!(maybe_string.is_none());
408    /// ```
409    /// If you don't need to keep a [`RwData<U>`], consider just using
410    /// [`RwData::read_as`]. If you only need to know if the type
411    /// matches, consider using [`RwData::data_is`].
412    ///
413    /// [`RwData<dyn Trait>`]: RwData
414    pub fn try_downcast<U: 'static>(&self) -> Option<RwData<U>> {
415        if self.data_is::<U>() {
416            let Self { data, cur_state, read_state, .. } = self.clone();
417            let ptr = Arc::into_raw(data);
418            let data = unsafe { Arc::from_raw(ptr as *const Mutex<U>) };
419            Some(RwData {
420                data,
421                cur_state,
422                read_state,
423                type_id: self.type_id,
424            })
425        } else {
426            None
427        }
428    }
429
430    /// Blocking inspection of the inner data
431    ///
432    /// # Examples
433    ///
434    /// You may want this method if you're storing a list of
435    /// [`RwData<dyn Trait>`], and want to know, at runtime, what type
436    /// each element is:
437    /// ```rust
438    /// # use std::{any::Any, fmt::Display, sync::Arc};
439    /// # use duat_core::{Mutex, data::RwData};
440    /// let list: [RwData<dyn Display>; 3] = [
441    ///     RwData::new_unsized::<String>(Arc::new(Mutex::new(String::from(
442    ///         "I can show you the world",
443    ///     )))),
444    ///     RwData::new_unsized::<String>(Arc::new(Mutex::new(String::from(
445    ///         "Shining, shimmering, splendid",
446    ///     )))),
447    ///     RwData::new_unsized::<char>(Arc::new(Mutex::new('🧞'))),
448    /// ];
449    ///
450    /// assert!(matches!(
451    ///     list[2].read_as::<char>().map(|c| c.len_utf8()),
452    ///     Some(4)
453    /// ));
454    /// assert!(matches!(
455    ///     list[1].read_as::<char>().map(|c| c.to_ascii_uppercase()),
456    ///     None
457    /// ));
458    /// ```
459    ///
460    /// [`RwData<dyn Trait>`]: RwData
461    pub fn read_as<U: 'static>(&self) -> Option<ReadDataGuard<'_, U>> {
462        if !self.data_is::<U>() {
463            return None;
464        }
465
466        self.read_state
467            .store(self.cur_state.load(Ordering::Acquire), Ordering::Release);
468        let ptr = Arc::as_ptr(&self.data) as *const Mutex<U>;
469        // SAFETY: Since this borrows this RwData, the Arc shouldn't be
470        // dropped while this guard exists
471        Some(ReadDataGuard(unsafe { ptr.as_ref().unwrap().lock() }))
472    }
473
474    pub fn write_as<U: 'static>(&self) -> Option<WriteDataGuard<'_, U>> {
475        if !self.data_is::<U>() {
476            return None;
477        }
478
479        let ptr = Arc::as_ptr(&self.data) as *const Mutex<U>;
480        Some(WriteDataGuard {
481            // SAFETY: Since this borrows this RwData, the Arc shouldn't
482            // be dropped while this guard exists
483            guard: unsafe { ptr.as_ref().unwrap().lock() },
484            cur_state: &self.cur_state,
485            read_state: &self.read_state,
486        })
487    }
488
489    pub(crate) fn raw_write(&self) -> MutexGuard<'_, T> {
490        self.data.lock()
491    }
492}
493
494impl<T: ?Sized + std::fmt::Debug> std::fmt::Debug for RwData<T> {
495    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
496        std::fmt::Debug::fmt(&*self.data.lock(), f)
497    }
498}
499
500impl<T: ?Sized> Clone for RwData<T> {
501    fn clone(&self) -> Self {
502        Self {
503            data: self.data.clone(),
504            cur_state: self.cur_state.clone(),
505            read_state: AtomicUsize::new(self.cur_state.load(Ordering::Relaxed) - 1),
506            type_id: self.type_id,
507        }
508    }
509}
510
511impl<T: Default> Default for RwData<T> {
512    fn default() -> Self {
513        Self {
514            data: Arc::new(Mutex::new(T::default())),
515            cur_state: Arc::new(AtomicUsize::new(1)),
516            read_state: AtomicUsize::new(1),
517            type_id: TypeId::of::<T>(),
518        }
519    }
520}
521
522pub struct ReadDataGuard<'a, T: ?Sized>(MutexGuard<'a, T>);
523
524impl<T: ?Sized> std::ops::Deref for ReadDataGuard<'_, T> {
525    type Target = T;
526
527    fn deref(&self) -> &Self::Target {
528        &self.0
529    }
530}
531
532pub struct WriteDataGuard<'a, T: ?Sized> {
533    guard: MutexGuard<'a, T>,
534    cur_state: &'a Arc<AtomicUsize>,
535    read_state: &'a AtomicUsize,
536}
537
538impl<T: ?Sized> std::ops::Deref for WriteDataGuard<'_, T> {
539    type Target = T;
540
541    fn deref(&self) -> &Self::Target {
542        &self.guard
543    }
544}
545
546impl<T: ?Sized> std::ops::DerefMut for WriteDataGuard<'_, T> {
547    fn deref_mut(&mut self) -> &mut Self::Target {
548        &mut self.guard
549    }
550}
551
552impl<T: ?Sized> Drop for WriteDataGuard<'_, T> {
553    fn drop(&mut self) {
554        let prev = self.cur_state.fetch_add(1, Ordering::Acquire);
555        self.read_state.store(prev + 1, Ordering::Release)
556    }
557}
558
559pub struct DataMap<I: ?Sized + Send + 'static, O> {
560    data: RwData<I>,
561    f: Box<dyn FnMut() -> O + Send>,
562}
563
564impl<I: ?Sized + Send + 'static, O> DataMap<I, O> {
565    pub fn fns(
566        self,
567    ) -> (
568        Box<dyn FnMut() -> O + Send>,
569        Box<dyn Fn() -> bool + Send + Sync>,
570    ) {
571        (self.f, Box::new(self.data.checker()))
572    }
573}
574
575impl<I: ?Sized + Send + 'static, O> FnOnce<()> for DataMap<I, O> {
576    type Output = O;
577
578    extern "rust-call" fn call_once(mut self, _: ()) -> Self::Output {
579        (self.f)()
580    }
581}
582
583impl<I: ?Sized + Send + 'static, O> FnMut<()> for DataMap<I, O> {
584    extern "rust-call" fn call_mut(&mut self, _: ()) -> Self::Output {
585        (self.f)()
586    }
587}
588
589impl<I: ?Sized + Send + 'static> RwData<I> {
590    pub fn map<O>(&self, mut f: impl FnMut(&I) -> O + Send + 'static) -> DataMap<I, O> {
591        let data = self.clone();
592        let f = move || f(&*data.read());
593        DataMap { data: self.clone(), f: Box::new(f) }
594    }
595}
596
597impl<I: ?Sized + Send + 'static, O: 'static> DataMap<I, O> {
598    pub fn map<O2>(mut self, mut f: impl FnMut(O) -> O2 + Send + 'static) -> DataMap<I, O2> {
599        DataMap {
600            data: self.data,
601            f: Box::new(move || f((self.f)())),
602        }
603    }
604}