duat_core/data/mod.rs
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
//! Data types that are meant to be shared and read across Duat.
//!
//! The data types revolve around the [`RwLock`] struct from
//! [`parking_lot`], and are adapters that may block the mutation of
//! the inner data, for the purpose of making it available for reading
//! to any extension on Duat.
//!
//! The first data type is [`RwData`], which is a read and write
//! wrapper over information. It should mostly not be shared, being
//! used instead to write information while making sure that no other
//! part of the code is still reading it. The second data type is
//! [`RoData`], or read only data. It is derived from the first
//! one, and cannot mutate the inner data.
//!
//! This type is used internally in order to keep track of state, like
//! widgets, input methods, etc.
//!
//! One of the main external uses for this macro is in creating
//! automatically update [`StatusLine`] fields.
//!
//! [`File`]: crate::widgets::File
//! [`Text`]: crate::text::Text
//! [`StatusLine`]: crate::widgets::StatusLine
pub use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
pub use self::{
ro::RoData,
rw::{ReadWriteGuard, RwData},
};
pub mod context;
mod ro;
mod rw;
/// Private trait for the [`RwData`] and [`RoData`] structs.
pub trait Data<T>: private::InnerData<T>
where
T: ?Sized,
{
fn to_ro(&self) -> RoData<T>;
fn has_changed(&self) -> bool;
}
pub struct DataMap<I: ?Sized + Send + Sync + 'static, O> {
data: RoData<I>,
f: Box<dyn FnMut() -> O + Send + Sync>,
}
impl<I: ?Sized + Send + Sync + 'static, O> DataMap<I, O> {
pub fn fns(
self,
) -> (
Box<dyn FnMut() -> O + Send + Sync>,
Box<dyn Fn() -> bool + Send + Sync>,
) {
let checker = Box::new(move || self.data.has_changed());
(self.f, checker)
}
}
impl<I: ?Sized + Send + Sync + 'static, O: 'static> DataMap<I, O> {
pub fn map<O2>(mut self, mut f: impl FnMut(O) -> O2 + Send + Sync + 'static) -> DataMap<I, O2> {
DataMap {
data: self.data,
f: Box::new(move || f((self.f)())),
}
}
}
impl<I: ?Sized + Send + Sync + 'static> RwData<I> {
pub fn map<O>(&self, mut f: impl FnMut(&I) -> O + Send + Sync + 'static) -> DataMap<I, O> {
let data = RoData::from(self);
let f = move || f(&*data.read());
DataMap { data: RoData::from(self), f: Box::new(f) }
}
}
impl<I: ?Sized + Send + Sync + 'static> RoData<I> {
pub fn map<O>(&self, mut f: impl FnMut(&I) -> O + Send + Sync + 'static) -> DataMap<I, O> {
let data = self.clone();
let f = move || f(&*data.read());
DataMap { data: self.clone(), f: Box::new(f) }
}
}
mod private {
use std::sync::{Arc, atomic::AtomicUsize};
use super::RwLockReadGuard;
pub trait InnerData<T: ?Sized> {
/// The data, usually an [`Arc`]
fn data(&self) -> RwLockReadGuard<'_, T>;
/// Attempt to get the data, that is usually an [`Arc`]
fn try_data(&self) -> Option<RwLockReadGuard<'_, T>>;
/// The most up to date state of the data.
fn cur_state(&self) -> &Arc<AtomicUsize>;
/// The last read state of the data.
fn read_state(&self) -> &AtomicUsize;
}
}