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 is that these structs are only meant to exist
19//! and be used in the main thread of execution in Duat. In fact, it
20//! should be impossible to acquire them outside of this main thread
21//! without use of unsafe code. If it is still possible, report that
22//! as a bug.
23//!
24//! The reason why these structs should only be valid in the main
25//! thread is because, internally, they use non [`Send`]/[`Sync`]
26//! structs, specifically [`Arc`] and [`RefCell`]. These are often
27//! considered "crutches" by a lot of the Rust community, but in an
28//! environment where most of the code is supposed to be able to
29//! access most of the state, it is impossible to go without using
30//! them.
31//!
32//! As well as not having the problem of deadlocks that [`Mutex`]es
33//! would have, [`Arc<RefCell>`] is way faster to clone and lock than
34//! its [`Sync`] equivalents [`Arc<Mutex>`] or [`Arc<RwLock>`].
35//!
36//! [read]: RwData::read
37//! [written to]: RwData::write
38//! [`Widget`]: crate::ui::Widget
39//! [`File`]: crate::file::File
40//! [updated]: crate::ui::Widget::update
41//! [`Text`]: crate::text::Text
42//! [`StatusLine`]: https://docs.rs/duat-utils/latest/duat_utils/widgets/struct.StatusLine.html
43//! [`context`]: crate::context
44//! [`Mutex`]: std::sync::Mutex
45//! [`Arc<Mutex>`]: std::sync::Arc
46//! [`Arc<RwLock>`]: std::sync::Arc
47use std::{
48    self,
49    any::TypeId,
50    cell::{RefCell, UnsafeCell},
51    marker::PhantomData,
52    sync::{
53        Arc,
54        atomic::{AtomicBool, AtomicUsize, Ordering},
55    },
56    time::Duration,
57};
58
59use crate::ui::{Ui, Widget};
60
61/// A container for shared read/write state
62///
63/// This is the struct used internally (and externally) to allow for
64/// massively shareable state in duat's API. Its main purpose is to
65/// hold all of the [`Widget`]s in Duat, making them available for
66/// usage from any function with access to a [`Pass`].
67///
68/// # [`Pass`]es
69///
70/// The [`Pass`] is a sort of "key" for accessing the value within an
71/// [`RwData`], it's purpose is to maintain Rust's number one rule,
72/// i.e. one exclusive reference or multiple shared references, and
73/// that is done by borrowing the [`Pass`] mutably or non mutably.
74/// That comes with some limitations, of course, mainly that you can't
75/// really mutate two [`RwData`]s at the same time, even if it is
76/// known that they don't point to the same data.
77///
78/// There are some common exceptions to this, where Duat provides some
79/// safe way to do that when it is known that the two types are not
80/// the same.
81///
82/// # Not [`Send`]/[`Sync`]
83///
84/// Internally, the [`RwData`] makes use of an [`Arc<RefCell>`]. The
85/// usage of an [`Arc<RefCell>`] over an [`Arc<Mutex>`] is, i've
86/// assumed, a necessary evil in order to preserve the aforementioned
87/// rule. But the lack of [`Send`]/[`Sync`] does confer the [`RwData`]
88/// some advantages:
89///
90/// * Deadlocks are impossible, being replaced by much easier to debug
91///   panics.
92/// * The order in which data is accessed doesn't matter, unlike with
93///   [`Mutex`]es.
94/// * Performance of unlocking and cloning should generally be better,
95///   since no atomic operations are done (I actually managed to
96///   observe this, where in my rudimentary benchmarks against neovim,
97///   the [`Arc<Mutex>`] version was very frequently losing to a
98///   comparable neovim build.
99///
100/// However, I admit that there are also some drawbacks, the most
101/// notable being the difficulty of reading or writing to [`Text`]
102/// from outside of the main thread. But for the most common usecase
103/// where that will be needed ([`Parser`]s), a [`Send`]/[`Sync`]
104/// solution will be provided soon.
105///
106/// [`Arc<Mutex>`]: std::sync::Arc
107/// [`Mutex`]: std::sync::Mutex
108/// [`Parser`]: crate::file::Parser
109/// [`Text`]: crate::text::Text
110#[derive(Debug)]
111pub struct RwData<T: ?Sized> {
112    value: Arc<UnsafeCell<T>>,
113    cur_state: Arc<AtomicUsize>,
114    read_state: Arc<AtomicUsize>,
115    ty: TypeId,
116}
117
118impl<T: 'static> RwData<T> {
119    /// Returns a new [`RwData<T>`]
120    ///
121    /// Note that this is only for sized types. For unsized types, the
122    /// process is a little more convoluted, and you need to use
123    /// [`RwData::new_unsized`].
124    pub fn new(value: T) -> Self {
125        Self {
126            value: Arc::new(UnsafeCell::new(value)),
127            ty: TypeId::of::<T>(),
128            cur_state: Arc::new(AtomicUsize::new(1)),
129            read_state: Arc::new(AtomicUsize::new(0)),
130        }
131    }
132}
133
134impl<T: ?Sized> RwData<T> {
135    /// Returns an unsized [`RwData`], such as [`RwData<dyn Trait>`]
136    ///
137    /// # Safety
138    ///
139    /// There is a type argument `SizedT` which _must_ be the exact
140    /// type you are passing to this constructor, i.e., if you are
141    /// creating an [`RwData<dyn Display>`] from a [`String`], you'd
142    /// do this:
143    ///
144    /// ```rust
145    /// use std::{cell::UnsafeCell, fmt::Display, sync::Arc};
146    ///
147    /// use duat_core::{data::RwData, prelude::*};
148    /// let rw_data: RwData<dyn Display> =
149    ///     unsafe { RwData::new_unsized::<String>(Arc::new(UnsafeCell::new("test".to_string()))) };
150    /// ```
151    ///
152    /// This ensures that methods such as [`read_as`] and [`write_as`]
153    /// will correctly identify such [`RwData<dyn Display>`] as a
154    /// [`String`].
155    ///
156    /// [`read_as`]: Self::read_as
157    /// [`write_as`]: Self::write_as
158    #[doc(hidden)]
159    pub unsafe fn new_unsized<SizedT: 'static>(value: Arc<UnsafeCell<T>>) -> Self {
160        Self {
161            value,
162            ty: TypeId::of::<SizedT>(),
163            cur_state: Arc::new(AtomicUsize::new(1)),
164            read_state: Arc::new(AtomicUsize::new(0)),
165        }
166    }
167
168    ////////// Reading functions
169
170    /// Reads the value within using a [`Pass`]
171    ///
172    /// The consistent use of a [`Pass`] for the purposes of
173    /// reading/writing to the values of [`RwData`]s ensures that no
174    /// panic or invalid borrow happens at runtime, even while working
175    /// with untrusted code. More importantly, Duat uses these
176    /// guarantees in order to give the end user a ridiculous amount
177    /// of freedom in where they can do things, whilst keeping Rust's
178    /// number one rule and ensuring thread safety, even with a
179    /// relatively large amount of shareable state.
180    pub fn read<'a>(&'a self, _: &'a Pass) -> &'a T {
181        update_read_state(&self.read_state, &self.cur_state);
182        // SAFETY: If one were to try and write to this value, this reference
183        // would instantly become invalid, and trying to read from it again
184        // would cause a compile error due to a Pass borrowing conflict.
185        unsafe { &*self.value.get() }
186    }
187
188    /// Reads the value within as `U` using a [`Pass`]
189    ///
190    /// The consistent use of a [`Pass`] for the purposes of
191    /// reading/writing to the values of [`RwData`]s ensures that no
192    /// panic or invalid borrow happens at runtime, even while working
193    /// with untrusted code. More importantly, Duat uses these
194    /// guarantees in order to give the end user a ridiculous amount
195    /// of freedom in where they can do things, whilst keeping Rust's
196    /// number one rule and ensuring thread safety, even with a
197    /// relatively large amount of shareable state.
198    pub fn read_as<'a, U: 'static>(&'a self, _: &'a Pass) -> Option<&'a U> {
199        if TypeId::of::<U>() != self.ty {
200            return None;
201        }
202
203        self.read_state
204            .store(self.cur_state.load(Ordering::Relaxed), Ordering::Relaxed);
205
206        let ptr = Arc::as_ptr(&self.value) as *const UnsafeCell<U>;
207
208        // SAFETY: Same as above, but also, the TypeId in the Handle
209        // "guarantees" that this is the correct type.
210        Some(unsafe { &*(&*ptr).get() })
211    }
212
213    /// Simulates a [`read`] without actually reading
214    ///
215    /// This is useful if you want to tell Duat that you don't want
216    /// [`has_changed`] to return `true`, but you don't have a
217    /// [`Pass`] available to [`read`] the value.
218    ///
219    /// [`read`]: Self::read
220    /// [`has_changed`]: Self::has_changed
221    pub fn declare_as_read(&self) {
222        self.read_state
223            .store(self.cur_state.load(Ordering::Relaxed), Ordering::Relaxed);
224    }
225
226    ////////// Writing functions
227
228    /// Writes to the value within using a [`Pass`]
229    ///
230    /// The consistent use of a [`Pass`] for the purposes of
231    /// reading/writing to the values of [`RwData`]s ensures that no
232    /// panic or invalid borrow happens at runtime, even while working
233    /// with untrusted code. More importantly, Duat uses these
234    /// guarantees in order to give the end user a ridiculous amount
235    /// of freedom in where they can do things, whilst keeping Rust's
236    /// number one rule and ensuring thread safety, even with a
237    /// relatively large amount of shareable state.
238    pub fn write<'a>(&'a self, _: &'a mut Pass) -> &'a mut T {
239        update_cur_state(&self.read_state, &self.cur_state);
240        // SAFETY: Again, the mutable reference to the Pass ensures that this
241        // is the only _valid_ mutable reference, if another reference,
242        // created prior to this one, were to be reused, that would be a
243        // compile error.
244        unsafe { &mut *self.value.get() }
245    }
246
247    /// Writes to the value within as `U` using a [`Pass`]
248    ///
249    /// The consistent use of a [`Pass`] for the purposes of
250    /// reading/writing to the values of [`RwData`]s ensures that no
251    /// panic or invalid borrow happens at runtime, even while working
252    /// with untrusted code. More importantly, Duat uses these
253    /// guarantees in order to give the end user a ridiculous amount
254    /// of freedom in where they can do things, whilst keeping Rust's
255    /// number one rule and ensuring thread safety, even with a
256    /// relatively large amount of shareable state.
257    pub fn write_as<'a, U: 'static>(&'a self, _: &'a mut Pass) -> Option<&'a mut U> {
258        if TypeId::of::<U>() != self.ty {
259            return None;
260        }
261
262        let prev = self.cur_state.fetch_add(1, Ordering::Relaxed);
263        self.read_state.store(prev + 1, Ordering::Relaxed);
264
265        let ptr = Arc::as_ptr(&self.value) as *const UnsafeCell<U>;
266
267        // SAFETY: Same as above, but also, the TypeId in the Handle
268        // "guarantees" that this is the correct type.
269        Some(unsafe { &mut *(&*ptr).get() })
270    }
271
272    /// Simulates a [`write`] without actually writing
273    ///
274    /// This is useful if you want to tell Duat that you want
275    /// [`has_changed`] to return `true`, but you don't have a
276    /// [`Pass`] available to [`write`] the value with.
277    ///
278    /// [`write`]: Self::write
279    /// [`has_changed`]: Self::has_changed
280    pub fn declare_written(&self) {
281        update_cur_state(&self.read_state, &self.cur_state);
282    }
283
284    ////////// Mapping of the inner value
285
286    /// Maps the value to another value with a function
287    ///
288    /// This function will return a struct that acts like a "read
289    /// only" version of [`RwData`], which also maps the value to
290    /// a return type.
291    pub fn map<Ret: 'static>(
292        &self,
293        _: &Pass,
294        map: impl FnMut(&T) -> Ret + 'static,
295    ) -> DataMap<T, Ret> {
296        let RwData { value, cur_state, read_state, .. } = self.clone();
297        let data = RwData {
298            value,
299            cur_state,
300            read_state,
301            ty: TypeId::of::<T>(),
302        };
303
304        DataMap { data, map: Arc::new(RefCell::new(map)) }
305    }
306
307    /// Attempts to downcast an [`RwData`] to a concrete type
308    ///
309    /// Returns [`Some(RwData<U>)`] if the value within was of type
310    /// `U`, i.e., for unsized types, `U` was the type parameter
311    /// passed when calling [`RwData::new_unsized`].
312    ///
313    /// [`Some(RwData<U>)`]: Some
314    pub fn try_downcast<U: 'static>(&self) -> Option<RwData<U>> {
315        if TypeId::of::<U>() != self.ty {
316            return None;
317        }
318
319        let ptr = Arc::into_raw(self.value.clone());
320        // SAFETY: TypeId argument "guarantees" this
321        let value = unsafe { Arc::from_raw(ptr as *const UnsafeCell<U>) };
322        Some(RwData {
323            value,
324            cur_state: self.cur_state.clone(),
325            read_state: Arc::new(AtomicUsize::new(self.cur_state.load(Ordering::Relaxed) - 1)),
326            ty: TypeId::of::<U>(),
327        })
328    }
329
330    ////////// Querying functions
331
332    /// Wether this [`RwData`] and another point to the same value
333    pub fn ptr_eq<U: ?Sized>(&self, other: &RwData<U>) -> bool {
334        Arc::as_ptr(&self.value).addr() == Arc::as_ptr(&other.value).addr()
335    }
336
337    /// The [`TypeId`] of the concrete type within
338    pub fn type_id(&self) -> TypeId {
339        self.ty
340    }
341
342    /// Wether the concrete [`TypeId`] matches that of `U`
343    pub fn data_is<U: 'static>(&self) -> bool {
344        self.ty == TypeId::of::<U>()
345    }
346
347    /// Wether someone else called [`write`] or [`write_as`] since the
348    /// last [`read`] or [`write`]
349    ///
350    /// Do note that this *DOES NOT* mean that the value inside has
351    /// actually been changed, it just means a mutable reference was
352    /// acquired after the last call to [`has_changed`].
353    ///
354    /// Some types like [`Text`], and traits like [`Widget`] offer
355    /// [`has_changed`](crate::ui::Widget::needs_update) methods,
356    /// you should try to determine what parts to look for changes.
357    ///
358    /// Generally though, you can use this method to gauge that.
359    ///
360    /// [`write`]: Self::write
361    /// [`write_as`]: Self::write_as
362    /// [`read`]: Self::read
363    /// [`has_changed`]: Self::has_changed
364    /// [`Text`]: crate::text::Text
365    /// [`Widget`]: crate::ui::Widget
366    pub fn has_changed(&self) -> bool {
367        self.read_state.load(Ordering::Relaxed) < self.cur_state.load(Ordering::Relaxed)
368    }
369
370    /// A function that checks if the data has been updated
371    ///
372    /// Do note that this function will check for the specific
373    /// [`RwData`] that was used in its creation, so if you call
374    /// [`read`] on that specific [`RwData`] for example, this
375    /// function will start returning `false`.
376    ///
377    /// [`read`]: Self::read
378    pub fn checker(&self) -> impl Fn() -> bool + Send + Sync + 'static {
379        let (cur, read) = (self.cur_state.clone(), self.read_state.clone());
380        move || read.load(Ordering::Relaxed) < cur.load(Ordering::Relaxed)
381    }
382}
383
384impl<W> RwData<W> {
385    /// Downcasts [`RwData<impl Widget<U>>`] to [`RwData<dyn
386    /// Widget<U>>`]
387    pub fn to_dyn_widget<U: Ui>(&self) -> RwData<dyn Widget<U>>
388    where
389        W: Widget<U>,
390    {
391        let ptr = Arc::into_raw(self.value.clone());
392        // SAFETY: Implements Widget<U>
393        let value = unsafe { Arc::from_raw(ptr as *const UnsafeCell<dyn Widget<U>>) };
394        RwData {
395            value,
396            cur_state: self.cur_state.clone(),
397            read_state: Arc::new(AtomicUsize::new(self.cur_state.load(Ordering::Relaxed) - 1)),
398            ty: self.ty,
399        }
400    }
401}
402
403// SAFETY: The only parts that are accessible from other threads are
404// the atomic counters from the Arcs. Everything else can only be
405// acquired when there is a Pass, i.e., on the main thread.
406unsafe impl<T: ?Sized + 'static> Send for RwData<T> {}
407unsafe impl<T: ?Sized + 'static> Sync for RwData<T> {}
408
409impl<T: ?Sized + 'static> RwData<T> {}
410
411impl<T: ?Sized> Clone for RwData<T> {
412    fn clone(&self) -> Self {
413        Self {
414            value: self.value.clone(),
415            ty: self.ty,
416            cur_state: self.cur_state.clone(),
417            read_state: Arc::new(AtomicUsize::new(self.cur_state.load(Ordering::Relaxed))),
418        }
419    }
420}
421
422impl<T: Default + 'static> Default for RwData<T> {
423    fn default() -> Self {
424        Self {
425            value: Arc::default(),
426            cur_state: Arc::new(AtomicUsize::new(1)),
427            read_state: Arc::default(),
428            ty: TypeId::of::<T>(),
429        }
430    }
431}
432
433/// A mapping of an [`RwData`]
434pub struct DataMap<I: ?Sized + 'static, O: 'static> {
435    data: RwData<I>,
436    map: Arc<RefCell<dyn FnMut(&I) -> O>>,
437}
438
439impl<I: ?Sized, O> DataMap<I, O> {
440    /// Maps the value within, works just like [`RwData::map`]
441    pub fn map<O2>(&self, pa: &Pass, mut f: impl FnMut(O) -> O2 + 'static) -> DataMap<I, O2> {
442        let data_map = self.clone();
443        data_map
444            .data
445            .clone()
446            .map(pa, move |input| f(data_map.map.borrow_mut()(input)))
447    }
448
449    /// Wether someone else called [`write`] or [`write_as`] since the
450    /// last [`read`] or [`write`]
451    ///
452    /// Do note that this *DOES NOT* mean that the value inside has
453    /// actually been changed, it just means a mutable reference was
454    /// acquired after the last call to [`has_changed`].
455    ///
456    /// Some types like [`Text`], and traits like [`Widget`] offer
457    /// [`needs_update`] methods, you should try to determine what
458    /// parts to look for changes.
459    ///
460    /// Generally though, you can use this method to gauge that.
461    ///
462    /// [`write`]: RwData::write
463    /// [`write_as`]: RwData::write_as
464    /// [`read`]: RwData::read
465    /// [`has_changed`]: RwData::has_changed
466    /// [`Text`]: crate::text::Text
467    /// [`Widget`]: crate::ui::Widget
468    /// [`needs_update`]: crate::ui::Widget::needs_update
469    pub fn has_changed(&self) -> bool {
470        self.data.has_changed()
471    }
472
473    /// A function that checks if the data has been updated
474    ///
475    /// Do note that this function will check for the specific
476    /// [`RwData`] that was used in its creation, so if you call
477    /// [`read`] on that specific [`RwData`] for example, this
478    /// function will start returning `false`.
479    ///
480    /// [`read`]: RwData::read
481    pub fn checker(&self) -> impl Fn() -> bool + Send + Sync + 'static {
482        self.data.checker()
483    }
484}
485
486// SAFETY: The only parts that are accessible from other threads are
487// the atomic counters from the Arcs. Everything else can only be
488// acquired when there is a Pass, i.e., on the main thread.
489unsafe impl<I: ?Sized + 'static, O: 'static> Send for DataMap<I, O> {}
490unsafe impl<I: ?Sized + 'static, O: 'static> Sync for DataMap<I, O> {}
491
492impl<I: ?Sized + 'static, O> Clone for DataMap<I, O> {
493    fn clone(&self) -> Self {
494        Self {
495            data: self.data.clone(),
496            map: self.map.clone(),
497        }
498    }
499}
500
501impl<I: ?Sized + 'static, O: 'static> DataMap<I, O> {}
502
503impl<I: ?Sized + 'static, O: 'static> FnOnce<(&Pass,)> for DataMap<I, O> {
504    type Output = O;
505
506    extern "rust-call" fn call_once(self, (key,): (&Pass,)) -> Self::Output {
507        self.map.borrow_mut()(self.data.read(key))
508    }
509}
510
511impl<I: ?Sized + 'static, O: 'static> FnMut<(&Pass,)> for DataMap<I, O> {
512    extern "rust-call" fn call_mut(&mut self, (key,): (&Pass,)) -> Self::Output {
513        self.map.borrow_mut()(self.data.read(key))
514    }
515}
516
517impl<I: ?Sized + 'static, O: 'static> Fn<(&Pass,)> for DataMap<I, O> {
518    extern "rust-call" fn call(&self, (key,): (&Pass,)) -> Self::Output {
519        self.map.borrow_mut()(self.data.read(key))
520    }
521}
522
523/// A checking struct that periodically returns `true`
524pub struct PeriodicChecker(Arc<AtomicBool>);
525
526impl PeriodicChecker {
527    /// Returns a new [`PeriodicChecker`]
528    pub fn new(duration: Duration) -> Self {
529        let has_elapsed = Arc::new(AtomicBool::new(false));
530        std::thread::spawn({
531            let has_elapsed = has_elapsed.clone();
532            move || {
533                while !crate::context::will_reload_or_quit() {
534                    std::thread::sleep(duration);
535                    has_elapsed.store(true, Ordering::Relaxed);
536                }
537            }
538        });
539
540        Self(has_elapsed)
541    }
542
543    /// Checks if the requested [`Duration`] has elapsed
544    pub fn check(&self) -> bool {
545        self.0.fetch_and(false, Ordering::Relaxed)
546    }
547}
548
549/// A key for reading/writing to [`RwData`]
550///
551/// This key is necessary in order to prevent breakage of the number
552/// one rule of Rust: any number of shared references, or one
553/// exclusive reference.
554///
555/// When you call [`RwData::read`], any call to [`RwData::write`] may
556/// end up breaking this rule, and vice-versa, which is why this
557/// struct is necessary.
558///
559/// One downside of this approach is that it is even more restrictive
560/// than Rust's rule of thumb, since that one is enforced on
561/// individual instances, while this one is enforced on all
562/// [`RwData`]s. This (as far as i know) cannot be circumvented, as a
563/// more advanced compile time checker (that distinguishes
564/// [`RwData<T>`]s of different `T`s, for example) does not seem
565/// feasible without the use of unfinished features, which I am not
566/// willing to use.
567pub struct Pass(PhantomData<()>);
568
569impl Pass {
570    /// Returns a new instance of [`Pass`]
571    ///
572    /// Be careful when using this!
573    pub(crate) const unsafe fn new() -> Self {
574        Pass(PhantomData)
575    }
576}
577
578fn update_read_state(read_state: &Arc<AtomicUsize>, cur_state: &Arc<AtomicUsize>) {
579    read_state.store(cur_state.load(Ordering::Relaxed), Ordering::Relaxed);
580}
581
582fn update_cur_state(read_state: &Arc<AtomicUsize>, cur_state: &Arc<AtomicUsize>) {
583    let prev = cur_state.fetch_add(1, Ordering::Relaxed);
584    read_state.store(prev + 1, Ordering::Relaxed);
585}