duat_core/data/
mod.rs

1//! Data types that are meant to be shared and read across Duat.
2//!
3//! The data types revolve around the [`RwLock`] struct from
4//! [`parking_lot`], and are adapters that may block the mutation of
5//! the inner data, for the purpose of making it available for reading
6//! to any extension on Duat.
7//!
8//! The first data type is [`RwData`], which is a read and write
9//! wrapper over information. It should mostly not be shared, being
10//! used instead to write information while making sure that no other
11//! part of the code is still reading it. The second data type is
12//! [`RoData`], or read only data. It is derived from the first
13//! one, and cannot mutate the inner data.
14//!
15//! This type is used internally in order to keep track of state, like
16//! widgets, input methods, etc.
17//!
18//! One of the main external uses for this macro is in creating
19//! automatically update [`StatusLine`] fields.
20//!
21//! [`File`]: crate::widgets::File
22//! [`Text`]: crate::text::Text
23//! [`StatusLine`]: crate::widgets::StatusLine
24pub use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
25
26pub use self::{
27    ro::RoData,
28    rw::{ReadWriteGuard, RwData},
29};
30
31pub mod context;
32mod ro;
33mod rw;
34
35/// Private trait for the [`RwData`] and [`RoData`] structs.
36pub trait Data<T>: private::InnerData<T>
37where
38    T: ?Sized,
39{
40    fn to_ro(&self) -> RoData<T>;
41
42    fn has_changed(&self) -> bool;
43}
44
45pub struct DataMap<I: ?Sized + Send + Sync + 'static, O> {
46    data: RoData<I>,
47    f: Box<dyn FnMut() -> O + Send + Sync>,
48}
49
50impl<I: ?Sized + Send + Sync + 'static, O> DataMap<I, O> {
51    pub fn fns(
52        self,
53    ) -> (
54        Box<dyn FnMut() -> O + Send + Sync>,
55        Box<dyn Fn() -> bool + Send + Sync>,
56    ) {
57        let checker = Box::new(move || self.data.has_changed());
58        (self.f, checker)
59    }
60}
61
62impl<I: ?Sized + Send + Sync + 'static, O: 'static> DataMap<I, O> {
63    pub fn map<O2>(mut self, mut f: impl FnMut(O) -> O2 + Send + Sync + 'static) -> DataMap<I, O2> {
64        DataMap {
65            data: self.data,
66            f: Box::new(move || f((self.f)())),
67        }
68    }
69}
70
71impl<I: ?Sized + Send + Sync + 'static> RwData<I> {
72    pub fn map<O>(&self, mut f: impl FnMut(&I) -> O + Send + Sync + 'static) -> DataMap<I, O> {
73        let data = RoData::from(self);
74        let f = move || f(&*data.read());
75        DataMap { data: RoData::from(self), f: Box::new(f) }
76    }
77}
78
79impl<I: ?Sized + Send + Sync + 'static> RoData<I> {
80    pub fn map<O>(&self, mut f: impl FnMut(&I) -> O + Send + Sync + 'static) -> DataMap<I, O> {
81        let data = self.clone();
82        let f = move || f(&*data.read());
83        DataMap { data: self.clone(), f: Box::new(f) }
84    }
85}
86
87mod private {
88    use std::sync::{Arc, atomic::AtomicUsize};
89
90    use super::RwLockReadGuard;
91
92    pub trait InnerData<T: ?Sized> {
93        /// The data, usually an [`Arc`]
94        fn data(&self) -> RwLockReadGuard<'_, T>;
95
96        /// Attempt to get the data, that is usually an [`Arc`]
97        fn try_data(&self) -> Option<RwLockReadGuard<'_, T>>;
98
99        /// The most up to date state of the data.
100        fn cur_state(&self) -> &Arc<AtomicUsize>;
101
102        /// The last read state of the data.
103        fn read_state(&self) -> &AtomicUsize;
104    }
105}