Skip to main content

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 [`Buffer`]s, and Duat can know when a [`Buffer`] 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 [`RefCell`] and [`UnsafeCell`].
27//! These are often considered "crutches" by a lot of the Rust
28//! community, but in an environment where most of the code is
29//! supposed to be able to access most of the state, it is impossible
30//! to go without using them.
31//!
32//! The use of [`UnsafeCell`] internally also makes the [`read`] and
33//! [`write`] operations _basically_ 0 cost,
34//!
35//! [read]: RwData::read
36//! [written to]: RwData::write
37//! [`Widget`]: crate::ui::Widget
38//! [`Buffer`]: crate::buffer::Buffer
39//! [`Text`]: crate::text::Text
40//! [`StatusLine`]: https://docs.rs/duat/latest/duat/widgets/struct.StatusLine.html
41//! [`context`]: crate::context
42//! [`Mutex`]: std::sync::Mutex
43//! [`read`]: RwData::read
44//! [`write`]: RwData::write
45//! [updated]: crate::hook::BufferUpdated
46use std::{
47    self,
48    any::TypeId,
49    cell::{RefCell, UnsafeCell},
50    marker::PhantomData,
51    sync::{
52        Arc, LazyLock, Mutex,
53        atomic::{AtomicUsize, Ordering},
54    },
55};
56
57use crate::ui::Widget;
58
59/// A container for shared read/write state
60///
61/// This is the struct used internally (and externally) to allow for
62/// massively shareable state in duat's API. Its main purpose is to
63/// hold all of the [`Widget`]s in Duat, making them available for
64/// usage from any function with access to a [`Pass`]. However, it can
65/// also be used to hold any other type, and also has the ability to
66/// notify when changes have taken place.
67///
68/// # [`Pass`]es
69///
70/// The `Pass` is a sort of "key" for accessing the value within an
71/// `RwData`, its purpose is to maintain Rust's number one rule,
72/// i.e. one exclusive reference or multiple shared references
73/// (mutability XOR aliasing), and that is done by borrowing the
74/// `Pass` mutably or non mutably. That comes with some limitations
75/// on how they can be used, mostly the fact that you must mutably
76/// borrow all `RwData`s that will be used [_at the same time_] in
77/// order to get multiple mutable references at once.
78///
79/// The use of a `Pass` for reading/writing to `RwData`s confers
80/// various benefits:
81///
82/// - Aside from updating an internal update counter, it is truly
83///   _zero cost_, unlike in the case of a [`Mutex`] or [`RefCell`],
84///   which have to do checks at runtime. This happens because the
85///   `Pass` has zero size, i.e. it gets removed at compile time.
86/// - You can't run into deadlocks like you would be able to when
87///   using `Mutex`es. Neither can you run into panics from
88///   reborrowing, like with `RefCell`.
89/// - You don't have to drop a `Guard` type (like [`MutexGuard`]) in
90///   order to reborrow from the `RwData` since borrowing gives you a
91///   first class `&` or `&mut`, which are much easier to work with.
92/// - You can do sub borrowings, like `&mut data.write(pa).field`,
93///   given the `&mut` borrow.
94///
95/// However, there are also a few disadvantages:
96///
97/// - Sometimes, mutably borrowing multiple things in a single
98///   function _can_ be a challenge, although that is mostly mitigated
99///   by [`Pass::write_many`].
100/// - You _cannot_ access the data in a `RwData` from threads other
101///   than the main one, since the `Pass` is only accessible from it.
102///   This isn't _really_ a disadvantage, since it simplifies thought
103///   patterns and eases reasoning about the current state of things.
104///
105/// [`Mutex`]: std::sync::Mutex
106/// [`MutexGuard`]: std::sync::MutexGuard
107/// [`Text`]: crate::text::Text
108/// [_at the same time_]: Pass::write_many
109#[derive(Debug)]
110pub struct RwData<T: ?Sized> {
111    value: Arc<UnsafeCell<T>>,
112    cur_state: Arc<AtomicUsize>,
113    read_state: Arc<AtomicUsize>,
114    ty: TypeId,
115}
116
117impl<T: 'static> RwData<T> {
118    /// Returns a new [`RwData<T>`]
119    ///
120    /// Note that this is only for sized types. For unsized types, the
121    /// process is a little more convoluted, and you need to use
122    /// [`RwData::new_unsized`].
123    pub fn new(value: T) -> Self {
124        Self {
125            value: Arc::new(UnsafeCell::new(value)),
126            ty: TypeId::of::<T>(),
127            cur_state: Arc::new(AtomicUsize::new(1)),
128            read_state: Arc::new(AtomicUsize::new(0)),
129        }
130    }
131}
132
133impl<T: ?Sized> RwData<T> {
134    /// Returns an unsized [`RwData`], such as [`RwData<dyn Trait>`]
135    ///
136    /// # Safety
137    ///
138    /// There is a type argument `SizedT` which _must_ be the exact
139    /// type you are passing to this constructor, i.e., if you are
140    /// creating an [`RwData<dyn Display>`] from a [`String`], you'd
141    /// do this:
142    ///
143    /// ```rust
144    /// # duat_core::doc_duat!(duat);
145    /// use std::{cell::UnsafeCell, fmt::Display, sync::Arc};
146    ///
147    /// use duat::{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<'p>(&'p self, _: &'p Pass) -> &'p T {
181        self.read_state
182            .store(self.cur_state.load(Ordering::Relaxed), Ordering::Relaxed);
183        // SAFETY: If one were to try and write to this value, this reference
184        // would instantly become invalid, and trying to read from it again
185        // would cause a compile error due to a Pass borrowing conflict.
186        unsafe { &*self.value.get() }
187    }
188
189    /// Reads the value within as `U` using a [`Pass`]
190    ///
191    /// The consistent use of a [`Pass`] for the purposes of
192    /// reading/writing to the values of [`RwData`]s ensures that no
193    /// panic or invalid borrow happens at runtime, even while working
194    /// with untrusted code. More importantly, Duat uses these
195    /// guarantees in order to give the end user a ridiculous amount
196    /// of freedom in where they can do things, whilst keeping Rust's
197    /// number one rule and ensuring thread safety, even with a
198    /// relatively large amount of shareable state.
199    pub fn read_as<'p, U: 'static>(&'p self, _: &'p Pass) -> Option<&'p U> {
200        if TypeId::of::<U>() != self.ty {
201            return None;
202        }
203
204        self.read_state
205            .store(self.cur_state.load(Ordering::Relaxed), Ordering::Relaxed);
206
207        let ptr = Arc::as_ptr(&self.value) as *const UnsafeCell<U>;
208
209        // SAFETY: Same as above, but also, the TypeId in the Handle
210        // "guarantees" that this is the correct type.
211        Some(unsafe { &*(&*ptr).get() })
212    }
213
214    /// Simulates a [`read`] without actually reading
215    ///
216    /// This is useful if you want to tell Duat that you don't want
217    /// [`has_changed`] to return `true`, but you don't have a
218    /// [`Pass`] available to [`read`] the value.
219    ///
220    /// [`read`]: Self::read
221    /// [`has_changed`]: Self::has_changed
222    pub fn declare_as_read(&self) {
223        self.read_state
224            .store(self.cur_state.load(Ordering::Relaxed), Ordering::Relaxed);
225    }
226
227    ////////// Writing functions
228
229    /// Writes to the value within using a [`Pass`]
230    ///
231    /// The consistent use of a [`Pass`] for the purposes of
232    /// reading/writing to the values of [`RwData`]s ensures that no
233    /// panic or invalid borrow happens at runtime, even while working
234    /// with untrusted code. More importantly, Duat uses these
235    /// guarantees in order to give the end user a ridiculous amount
236    /// of freedom in where they can do things, whilst keeping Rust's
237    /// number one rule and ensuring thread safety, even with a
238    /// relatively large amount of shareable state.
239    pub fn write<'p>(&'p self, _: &'p mut Pass) -> &'p mut T {
240        let prev = self.cur_state.fetch_add(1, Ordering::Relaxed);
241        self.read_state.store(prev + 1, Ordering::Relaxed);
242        // SAFETY: Again, the mutable reference to the Pass ensures that this
243        // is the only _valid_ mutable reference, if another reference,
244        // created prior to this one, were to be reused, that would be a
245        // compile error.
246        unsafe { &mut *self.value.get() }
247    }
248
249    /// Writes to the value within as `U` using a [`Pass`]
250    ///
251    /// The consistent use of a [`Pass`] for the purposes of
252    /// reading/writing to the values of [`RwData`]s ensures that no
253    /// panic or invalid borrow happens at runtime, even while working
254    /// with untrusted code. More importantly, Duat uses these
255    /// guarantees in order to give the end user a ridiculous amount
256    /// of freedom in where they can do things, whilst keeping Rust's
257    /// number one rule and ensuring thread safety, even with a
258    /// relatively large amount of shareable state.
259    pub fn write_as<'p, U: 'static>(&'p self, _: &'p mut Pass) -> Option<&'p mut U> {
260        if TypeId::of::<U>() != self.ty {
261            return None;
262        }
263
264        let prev = self.cur_state.fetch_add(1, Ordering::Relaxed);
265        self.read_state.store(prev + 1, Ordering::Relaxed);
266
267        let ptr = Arc::as_ptr(&self.value) as *const UnsafeCell<U>;
268
269        // SAFETY: Same as above, but also, the TypeId in the Handle
270        // "guarantees" that this is the correct type.
271        Some(unsafe { &mut *(&*ptr).get() })
272    }
273
274    /// Writes to the value _and_ internal [`RwData`]-like structs
275    ///
276    /// This method takes a function that borrows a [`WriteableTuple`]
277    /// from `self`, letting you write to `self` and the data in the
278    /// tuple (or single element) at the same time.
279    ///
280    /// This is _really_ useful in a scenario where, for example, your
281    /// [`Handle<W>`] for some widget `W` holds a [`Handle<Buffer>`],
282    /// and you wish to access both at the same time, while writing to
283    /// the former:
284    ///
285    /// ```rust
286    /// # duat_core::doc_duat!(duat);
287    /// use duat::prelude::*;
288    ///
289    /// struct MyWidget {
290    ///     text: Text,
291    ///     buf: Handle,
292    /// }
293    ///
294    /// fn add_mywidget_hooks() {
295    ///     hook::add::<KeySent>(|pa, _| {
296    ///         let Some(mywidget) = context::handle_of::<MyWidget>(pa) else {
297    ///             return;
298    ///         };
299    ///         let (wid, buf) = mywidget.write_then(pa, |wid| &wid.buf);
300    ///         // Updating the widget and reading/writing from the Buffer at the same time.
301    ///         // ...
302    ///     });
303    /// }
304    /// # impl Widget for MyWidget {
305    /// #     fn text(&self) -> &Text { &self.text }
306    /// #     fn text_mut(&mut self) -> TextMut { self.text.as_mut() }
307    /// # }
308    /// ```
309    ///
310    /// You can also return tuples from the function, allowing for
311    /// access to up to twelve different [`RwData`]-like structs:
312    ///
313    /// ```rust
314    /// # duat_core::doc_duat!(duat);
315    /// use duat::prelude::*;
316    ///
317    /// struct MyWidget {
318    ///     text: Text,
319    ///     buf1: Handle,
320    ///     buf2: Handle,
321    /// }
322    ///
323    /// fn add_mywidget_hooks() {
324    ///     hook::add::<KeySent>(|pa, _| {
325    ///         let Some(mywidget) = context::handle_of::<MyWidget>(pa) else {
326    ///             return;
327    ///         };
328    ///         let (wid, (b1, b2)) = mywidget.write_then(pa, |wid| (&wid.buf1, &wid.buf2));
329    ///         // ...
330    ///     });
331    /// }
332    /// # impl Widget for MyWidget {
333    /// #     fn text(&self) -> &Text { &self.text }
334    /// #     fn text_mut(&mut self) -> TextMut { self.text.as_mut() }
335    /// # }
336    /// ```
337    ///
338    /// # Panics
339    ///
340    /// This function will panic if any of the elements of the tuple
341    /// point to the same data as any other element or `self`, see
342    /// [`Pass::write_many`] for more information.
343    ///
344    /// [`Handle<W>`]: crate::context::Handle
345    /// [`Handle<Buffer>`]: crate::context::Handle
346    #[track_caller]
347    #[allow(static_mut_refs)]
348    pub fn write_then<'p, Tup: WriteableTuple<'p, impl std::any::Any>>(
349        &'p self,
350        pa: &'p mut Pass,
351        tup_fn: impl FnOnce(&'p T) -> Tup,
352    ) -> (&'p mut T, Tup::Return) {
353        let tup = tup_fn(self.read(pa));
354        if tup
355            .state_ptrs()
356            .into_iter()
357            .any(|ptr| ptr == CurStatePtr(&self.cur_state))
358        {
359            panic!("Tried writing to the same data multiple times at the same time");
360        }
361
362        /// SAFETY: The ptrs are already verifiably not pointing to
363        /// the data of self.
364        static PASS: Pass = unsafe { Pass::new() };
365
366        let tup_ret = unsafe { (&raw const PASS as *mut Pass).as_mut() }
367            .unwrap()
368            .write_many(tup);
369
370        let value = self.write(unsafe { (&raw const PASS as *mut Pass).as_mut() }.unwrap());
371
372        (value, tup_ret)
373    }
374
375    /// Simulates a [`write`] without actually writing
376    ///
377    /// This is useful if you want to tell Duat that you want
378    /// [`has_changed`] to return `true`, but you don't have a
379    /// [`Pass`] available to [`write`] the value with.
380    ///
381    /// [`write`]: Self::write
382    /// [`has_changed`]: Self::has_changed
383    pub fn declare_written(&self) {
384        let prev = self.cur_state.fetch_add(1, Ordering::Relaxed);
385        self.read_state.store(prev + 1, Ordering::Relaxed);
386    }
387
388    /// Takes the value within, replacing it with the default
389    pub fn take(&self, pa: &mut Pass) -> T
390    where
391        T: Default,
392    {
393        std::mem::take(self.write(pa))
394    }
395
396    ////////// Mapping of the inner value
397
398    /// Maps the value to another value with a function
399    ///
400    /// This function will return a struct that acts like a "read
401    /// only" version of [`RwData`], which also maps the value to
402    /// a return type.
403    pub fn map<Ret: 'static>(&self, map: impl FnMut(&T) -> Ret + 'static) -> DataMap<T, Ret> {
404        let RwData { value, cur_state, .. } = self.clone();
405        let data = RwData {
406            value,
407            cur_state,
408            read_state: Arc::new(AtomicUsize::new(self.cur_state.load(Ordering::Relaxed))),
409            ty: TypeId::of::<T>(),
410        };
411
412        DataMap { data, map: Arc::new(RefCell::new(map)) }
413    }
414
415    /// Maps the value to another value with a mutating function
416    ///
417    /// This is useful if you want to repeat a function over and over
418    /// again in order to get a new different result, whilst mutating
419    /// the data within.
420    pub fn map_mut<Ret: 'static>(
421        &self,
422        map: impl FnMut(&mut T) -> Ret + 'static,
423    ) -> MutDataMap<T, Ret> {
424        let RwData { value, cur_state, .. } = self.clone();
425        let data = RwData {
426            value,
427            cur_state,
428            read_state: Arc::new(AtomicUsize::new(self.cur_state.load(Ordering::Relaxed))),
429            ty: TypeId::of::<T>(),
430        };
431
432        MutDataMap { data, map: Arc::new(RefCell::new(map)) }
433    }
434
435    /// Attempts to downcast an [`RwData`] to a concrete type
436    ///
437    /// Returns [`Some(RwData<U>)`] if the value within is of type
438    /// `U`. For unsized types, `U` is the type parameter
439    /// passed when calling [`RwData::new_unsized`].
440    ///
441    /// [`Some(RwData<U>)`]: Some
442    pub fn try_downcast<U: 'static>(&self) -> Option<RwData<U>> {
443        if TypeId::of::<U>() != self.ty {
444            return None;
445        }
446
447        let ptr = Arc::into_raw(self.value.clone());
448        // SAFETY: TypeId argument "guarantees" this
449        let value = unsafe { Arc::from_raw(ptr as *const UnsafeCell<U>) };
450        Some(RwData {
451            value,
452            cur_state: self.cur_state.clone(),
453            read_state: Arc::new(AtomicUsize::new(self.cur_state.load(Ordering::Relaxed) - 1)),
454            ty: TypeId::of::<U>(),
455        })
456    }
457
458    ////////// Querying functions
459
460    /// Wether this [`RwData`] and another point to the same value
461    pub fn ptr_eq<U: ?Sized>(&self, other: &RwData<U>) -> bool {
462        Arc::ptr_eq(&self.cur_state, &other.cur_state)
463    }
464
465    /// The [`TypeId`] of the concrete type within
466    pub fn type_id(&self) -> TypeId {
467        self.ty
468    }
469
470    /// Wether the concrete [`TypeId`] matches that of `U`
471    pub fn is<U: 'static>(&self) -> bool {
472        self.ty == TypeId::of::<U>()
473    }
474
475    /// Wether someone else called [`write`] or [`write_as`] since the
476    /// last [`read`] or `write`
477    ///
478    /// Do note that this *DOES NOT* mean that the value inside has
479    /// actually been changed, it just means a mutable reference was
480    /// acquired after the last call to [`has_changed`].
481    ///
482    /// [`write`]: Self::write
483    /// [`write_as`]: Self::write_as
484    /// [`read`]: Self::read
485    /// [`has_changed`]: Self::has_changed
486    pub fn has_changed(&self) -> bool {
487        self.read_state.load(Ordering::Relaxed) < self.cur_state.load(Ordering::Relaxed)
488    }
489
490    /// A function that checks if the data has been updated
491    ///
492    /// Do note that this function will check for the specific
493    /// [`RwData`] that was used in its creation, so if you call
494    /// [`read`] on that specific [`RwData`] for example, this
495    /// function will start returning `false`.
496    ///
497    /// [`read`]: Self::read
498    pub fn checker(&self) -> impl Fn() -> bool + Send + Sync + 'static {
499        let (read, cur) = (self.read_state.clone(), self.cur_state.clone());
500        move || read.load(Ordering::Relaxed) < cur.load(Ordering::Relaxed)
501    }
502}
503
504impl<W: Widget> RwData<W> {
505    /// Downcasts [`RwData<impl Widget>`] to [`RwData<dyn Widget>`]
506    pub fn to_dyn_widget(&self) -> RwData<dyn Widget> {
507        let ptr = Arc::into_raw(self.value.clone());
508        // SAFETY: Implements Widget
509        let value = unsafe { Arc::from_raw(ptr as *const UnsafeCell<dyn Widget>) };
510        RwData {
511            value,
512            cur_state: self.cur_state.clone(),
513            read_state: Arc::new(AtomicUsize::new(self.cur_state.load(Ordering::Relaxed) - 1)),
514            ty: self.ty,
515        }
516    }
517}
518
519// SAFETY: The only parts that are accessible from other threads are
520// the atomic counters from the Arcs. Everything else can only be
521// acquired when there is a Pass, i.e., on the main thread.
522unsafe impl<T: ?Sized + Send> Send for RwData<T> {}
523unsafe impl<T: ?Sized + Send> Sync for RwData<T> {}
524
525impl<T: ?Sized> Clone for RwData<T> {
526    fn clone(&self) -> Self {
527        Self {
528            value: self.value.clone(),
529            ty: self.ty,
530            cur_state: self.cur_state.clone(),
531            read_state: Arc::new(AtomicUsize::new(self.cur_state.load(Ordering::Relaxed) - 1)),
532        }
533    }
534}
535
536impl<T: Default + 'static> Default for RwData<T> {
537    fn default() -> Self {
538        Self {
539            value: Arc::default(),
540            cur_state: Arc::new(AtomicUsize::new(1)),
541            read_state: Arc::new(AtomicUsize::new(0)),
542            ty: TypeId::of::<T>(),
543        }
544    }
545}
546
547/// A mapping of an [`RwData`]
548pub struct DataMap<I: ?Sized + 'static, O: 'static> {
549    data: RwData<I>,
550    map: Arc<RefCell<dyn FnMut(&I) -> O>>,
551}
552
553impl<I: ?Sized, O> DataMap<I, O> {
554    /// Call this `DataMap`'s mapping function, returning the output
555    pub fn call(&self, pa: &Pass) -> O {
556        self.map.borrow_mut()(self.data.read(pa))
557    }
558
559    /// Maps the value within, works just like [`RwData::map`]
560    pub fn map<O2>(self, mut f: impl FnMut(O) -> O2 + 'static) -> DataMap<I, O2> {
561        self.data.map(move |input| f(self.map.borrow_mut()(input)))
562    }
563
564    /// Wether someone else called [`write`] or [`write_as`] since the
565    /// last [`read`] or [`write`]
566    ///
567    /// Do note that this *DOES NOT* mean that the value inside has
568    /// actually been changed, it just means a mutable reference was
569    /// acquired after the last call to [`has_changed`].
570    ///
571    /// Some types like [`Text`], and traits like [`Widget`] offer
572    /// [`needs_update`] methods, you should try to determine what
573    /// parts to look for changes.
574    ///
575    /// Generally though, you can use this method to gauge that.
576    ///
577    /// [`write`]: RwData::write
578    /// [`write_as`]: RwData::write_as
579    /// [`read`]: RwData::read
580    /// [`has_changed`]: RwData::has_changed
581    /// [`Text`]: crate::text::Text
582    /// [`Widget`]: crate::ui::Widget
583    /// [`needs_update`]: crate::ui::Widget::needs_update
584    pub fn has_changed(&self) -> bool {
585        self.data.has_changed()
586    }
587
588    /// A function that checks if the data has been updated
589    ///
590    /// Do note that this function will check for the specific
591    /// [`RwData`] that was used in its creation, so if you call
592    /// [`read`] on that specific [`RwData`] for example, this
593    /// function will start returning `false`.
594    ///
595    /// [`read`]: RwData::read
596    pub fn checker(&self) -> impl Fn() -> bool + Send + Sync + 'static {
597        self.data.checker()
598    }
599}
600
601// SAFETY: The only parts that are accessible from other threads are
602// the atomic counters from the Arcs. Everything else can only be
603// acquired when there is a Pass, i.e., on the main thread.
604unsafe impl<I: ?Sized + 'static, O: 'static> Send for DataMap<I, O> {}
605unsafe impl<I: ?Sized + 'static, O: 'static> Sync for DataMap<I, O> {}
606
607/// A mutable mapping of an [`RwData`]
608///
609/// This works very similarly to the [`DataMap`], except the function
610/// is allowed to mutate the data, so it takes a `&mut Pass` instead
611/// of a regular `&Pass`.
612pub struct MutDataMap<I: ?Sized + 'static, O: 'static> {
613    data: RwData<I>,
614    map: Arc<RefCell<dyn FnMut(&mut I) -> O>>,
615}
616
617impl<I: ?Sized, O> MutDataMap<I, O> {
618    /// Call this `DataMap`'s mapping function, returning the output
619    pub fn call(&self, pa: &mut Pass) -> O {
620        self.map.borrow_mut()(self.data.write(pa))
621    }
622
623    /// Maps the value within, works just like [`RwData::map`]
624    pub fn map<O2>(self, mut f: impl FnMut(O) -> O2 + 'static) -> MutDataMap<I, O2> {
625        self.data
626            .map_mut(move |input| f(self.map.borrow_mut()(input)))
627    }
628
629    /// Wether someone else called [`write`] or [`write_as`] since the
630    /// last [`read`] or [`write`]
631    ///
632    /// Do note that this *DOES NOT* mean that the value inside has
633    /// actually been changed, it just means a mutable reference was
634    /// acquired after the last call to [`has_changed`].
635    ///
636    /// [`write`]: RwData::write
637    /// [`write_as`]: RwData::write_as
638    /// [`read`]: RwData::read
639    /// [`has_changed`]: RwData::has_changed
640    /// [`Text`]: crate::text::Text
641    /// [`Widget`]: crate::ui::Widget
642    pub fn has_changed(&self) -> bool {
643        self.data.has_changed()
644    }
645
646    /// A function that checks if the data has been updated
647    ///
648    /// Do note that this function will check for the specific
649    /// [`RwData`] that was used in its creation, so if you call
650    /// [`read`] on that specific [`RwData`] for example, this
651    /// function will start returning `false`.
652    ///
653    /// [`read`]: RwData::read
654    pub fn checker(&self) -> impl Fn() -> bool + Send + Sync + 'static {
655        self.data.checker()
656    }
657}
658
659// SAFETY: The only parts that are accessible from other threads are
660// the atomic counters from the Arcs. Everything else can only be
661// acquired when there is a Pass, i.e., on the main thread.
662unsafe impl<I: ?Sized + 'static, O: 'static> Send for MutDataMap<I, O> {}
663unsafe impl<I: ?Sized + 'static, O: 'static> Sync for MutDataMap<I, O> {}
664
665/// A struct used for asynchronously mutating [`RwData`]s without a
666/// [`Pass`]
667///
668/// This works by wrapping the `RwData` and collecting every mutating
669/// function inside a separate [`Mutex`]. Whenever you access the
670/// `Data`, the changes are applied to it.
671///
672/// With this in mind, one limitation of this type is that every
673/// access must make use of a `&mut Pass`, with the exception of
674/// [`BulkDataWriter::try_read`], which returns `Some` only when there
675/// have been no changes to the `Data`.
676#[derive(Default)]
677pub struct BulkDataWriter<Data: Default + 'static> {
678    actions: LazyLock<Arc<Mutex<Vec<Box<dyn FnOnce(&mut Data) + Send + 'static>>>>>,
679    data: LazyLock<RwData<Data>>,
680}
681
682impl<Data: Default + 'static> BulkDataWriter<Data> {
683    /// Returns a new `BulkDataWriter`
684    ///
685    /// Considering the fact that this struct is almost exclusively
686    /// used in `static` variables, I have decided to make its
687    /// constructor `const`, to facilitate its usage.
688    #[allow(clippy::new_without_default)]
689    pub const fn new() -> Self {
690        Self {
691            actions: LazyLock::new(|| Arc::new(Mutex::new(Vec::new()))),
692            data: LazyLock::new(|| RwData::new(Data::default())),
693        }
694    }
695
696    /// Adds a mutating function to the list of functions to call upon
697    /// accessing the `Data`
698    ///
699    /// This is useful for allowing mutation from any thread, and
700    /// without needing [`Pass`]es. `duat-core` makes extensive use of
701    /// this function in order to provide pleasant to use APIs.
702    pub fn mutate(&self, f: impl FnOnce(&mut Data) + Send + 'static) {
703        self.actions.lock().unwrap().push(Box::new(f));
704    }
705
706    /// Accesses the `Data`, calling all added actions
707    ///
708    /// This function will call all actions that were sent by the
709    /// [`BulkDataWriter::mutate`] function in order to write to the
710    /// `Data` asynchronously.
711    pub fn write<'p>(&'p self, pa: &'p mut Pass) -> &'p mut Data {
712        let data = self.data.write(pa);
713        for action in self.actions.lock().unwrap().drain(..) {
714            action(data);
715        }
716        data
717    }
718
719    /// Attempts to read the `Data`
720    ///
721    /// This function will return [`None`] if there are pending
722    /// actions that need to happen before reading/writing. You should
723    /// almost always prefer calling [`BulkDataWriter::write`]
724    /// instead.
725    pub fn try_read<'p>(&'p self, pa: &'p Pass) -> Option<&'p Data> {
726        self.actions
727            .lock()
728            .unwrap()
729            .is_empty()
730            .then(|| self.data.read(pa))
731    }
732
733    /// Maps the value to another value with a mutating function
734    ///
735    /// This will apply the delayed updting of
736    /// [`BulkDataWriter::write`] every time the mapping is called, so
737    /// the value always stays up to date.
738    pub fn map_mut<Ret: 'static>(
739        &self,
740        mut map: impl FnMut(&mut Data) -> Ret + 'static,
741    ) -> MutDataMap<Data, Ret> {
742        let actions = self.actions.clone();
743        self.data.map_mut(move |data| {
744            for action in actions.lock().unwrap().drain(..) {
745                action(data);
746            }
747            map(data)
748        })
749    }
750}
751
752/// A key for reading/writing to [`RwData`]
753///
754/// This key is necessary in order to prevent breakage of the number
755/// one rule of Rust: any number of shared references, or one
756/// exclusive reference.
757///
758/// When you call [`RwData::read`], any call to [`RwData::write`] may
759/// end up breaking this rule, and vice-versa, which is why this
760/// struct is necessary.
761///
762/// One downside of this approach is that it is even more restrictive
763/// than Rust's rule of thumb, since that one is enforced on
764/// individual instances, while this one is enforced on all
765/// [`RwData`]s. This (as far as i know) cannot be circumvented, as a
766/// more advanced compile time checker (that distinguishes
767/// [`RwData<T>`]s of different `T`s, for example) does not seem
768/// feasible without the use of unfinished features, which I am not
769/// willing to use.
770pub struct Pass(PhantomData<()>);
771
772impl Pass {
773    /// Returns a new instance of [`Pass`]
774    ///
775    /// Be careful when using this!
776    pub(crate) const unsafe fn new() -> Self {
777        Pass(PhantomData)
778    }
779
780    /// Writes to many [`RwData`]-like structs at once
781    ///
782    /// This function accepts tuples (or a single element) of
783    /// references to types that implement the [`WriteableData`]
784    /// trait, which is one of the following:
785    ///
786    /// - [`RwData`]: Duat's regular smart pointer.
787    /// - [`BulkDataWriter`]: A pointer to lazyly updated data.
788    /// - [`Handle`]: A handle for a [`Widget`]
789    /// - [`RwArea`]: A handle for a `Widget`'s [`Area`]
790    ///
791    /// Here's an example, which writes to two `RwData`s at the same
792    /// time as a `Handle`:
793    ///
794    /// ```rust
795    /// # duat_core::doc_duat!(duat);
796    /// use duat::{data::RwData, prelude::*};
797    /// setup_duat!(setup);
798    ///
799    /// fn setup() {
800    ///     let (num1, num2) = (RwData::new(0), RwData::new(0));
801    ///     hook::add::<BufferOpened>(move |pa, handle: &Handle| {
802    ///         let (num1, num2, buf) = pa.write_many((&num1, &num2, handle));
803    ///         // Rest of the function writes to all of them at the same time.
804    ///     });
805    /// }
806    /// ```
807    ///
808    /// This allows for much more flexibility when writing to global
809    /// state, which should hopefully lead to more streamlined
810    /// functions
811    ///
812    /// # Panics
813    ///
814    /// This function will panic if any of the elements of the tuple
815    /// point to the same data as any other element, for example, with
816    /// the earlier code snippet:
817    ///
818    /// ```rust
819    /// # duat_core::doc_duat!(duat);
820    /// use duat::{data::RwData, prelude::*};
821    /// setup_duat!(setup);
822    ///
823    /// fn setup() {
824    ///     let num1 = RwData::new(0);
825    ///     // num2 is now a clone of num1
826    ///     let num2 = num1.clone();
827    ///     hook::add::<BufferOpened>(move |pa, handle: &Handle| {
828    ///         let (num1, num2, buf) = pa.write_many((&num1, &num2, handle));
829    ///         // Rest of the function writes to all of them at the same time.
830    ///     });
831    /// }
832    /// ```
833    ///
834    /// Since `num1` and `num2` point to the same data, you'd be
835    /// getting two `&mut i32` for the same variable, which violates
836    /// rust's "mutability xor aliasing" rule. This is why this will
837    /// panic. If you want a non-panicking version of this function,
838    /// check out [`Pass::try_write_many`], which returns a [`Result`]
839    /// instead.
840    ///
841    /// [`Handle`]: crate::context::Handle
842    /// [`RwArea`]: crate::ui::RwArea
843    /// [`Area`]: crate::ui::Area
844    #[track_caller]
845    pub fn write_many<'p, Tup: WriteableTuple<'p, impl std::any::Any>>(
846        &'p mut self,
847        tup: Tup,
848    ) -> Tup::Return {
849        if let Some(ret) = tup.write_all(self) {
850            ret
851        } else {
852            panic!("Tried writing to the same data multiple times");
853        }
854    }
855
856    /// Tries writing to many [`RwData`]-like structs at once
857    ///
858    /// This function accepts tuples (or a single element) of
859    /// references to types that implement the [`WriteableData`]
860    /// trait, which is one of the following:
861    ///
862    /// - [`RwData`]: Duat's regular smart pointer.
863    /// - [`BulkDataWriter`]: A pointer to lazyly updated data.
864    /// - [`Handle`]: A handle for a [`Widget`]
865    /// - [`RwArea`]: A handle for a `Widget`'s [`Area`]
866    ///
867    /// This function works exactly like [`Pass::write_many`],
868    /// however, instead of panicking, this function returns a
869    /// [`Result`], returning an [`Err`] if any of the tuple's
870    /// elements point to the same data as any of the other elements.
871    ///
872    /// [`Handle`]: crate::context::Handle
873    /// [`RwArea`]: crate::ui::RwArea
874    /// [`Area`]: crate::ui::Area
875    pub fn try_write_many<'p, Tup: WriteableTuple<'p, impl std::any::Any>>(
876        &'p mut self,
877        tup: Tup,
878    ) -> Option<Tup::Return> {
879        tup.write_all(self)
880    }
881}
882
883/// A tuple of [`WriteableData`], used for writing to many things at
884/// once
885#[doc(hidden)]
886pub trait WriteableTuple<'p, _Dummy> {
887    type Return;
888
889    #[doc(hidden)]
890    fn write_all(self, pa: &'p mut Pass) -> Option<Self::Return>;
891
892    #[doc(hidden)]
893    fn state_ptrs(&self) -> impl IntoIterator<Item = CurStatePtr<'_>>;
894}
895
896macro_rules! implWriteableTuple {
897    ($(($tup:ident, $dummy:ident)),+) => {
898        #[allow(non_snake_case)]
899        impl<'p, $($tup),+, $($dummy),+> WriteableTuple<'p, ($(&mut $dummy),+)> for ($($tup),+)
900        where
901            $($tup: WriteableTuple<'p, $dummy>),+
902        {
903            type Return = ($($tup::Return),+);
904
905            fn write_all(self, _: &'p mut Pass) -> Option<Self::Return> {
906                if self.state_ptrs().into_iter().enumerate().any(|(lhs, i)| {
907                    self.state_ptrs()
908                        .into_iter()
909                        .enumerate()
910                        .any(|(rhs, j)| lhs == rhs && i != j)
911                }) {
912                    return None;
913                }
914
915                let ($($tup),+) = self;
916
917				/// SAFETY: The ptrs are already verifiably not pointing to the same data.
918                static PASS: Pass = unsafe { Pass::new() };
919
920                Some(($(
921                    $tup.write_all(
922                        unsafe { (&raw const PASS as *mut Pass).as_mut() }.unwrap()
923                    )
924                    .unwrap()
925                ),+))
926            }
927
928            fn state_ptrs(&self) -> impl IntoIterator<Item = CurStatePtr<'_>> {
929                let ($($tup),+) = self;
930
931                implWriteableTuple!(@chain $($tup),+)
932            }
933        }
934    };
935
936    (@chain $tup:ident $(, $rest:ident)*) => {
937        $tup.state_ptrs().into_iter().chain(implWriteableTuple!(@chain $($rest),*))
938    };
939    (@chain ) => { [] };
940}
941
942impl<'p, Data, T> WriteableTuple<'p, (&mut T,)> for &'p Data
943where
944    Data: WriteableData<'p, T>,
945    T: ?Sized + 'p,
946{
947    type Return = &'p mut T;
948
949    fn write_all(self, pa: &'p mut Pass) -> Option<Self::Return> {
950        Some(self.write_one_of_many(pa))
951    }
952
953    fn state_ptrs(&self) -> impl IntoIterator<Item = CurStatePtr<'_>> {
954        [self.cur_state_ptr()]
955    }
956}
957
958implWriteableTuple!((D0, T0), (D1, T1));
959implWriteableTuple!((D0, T0), (D1, T1), (D2, T2));
960implWriteableTuple!((D0, T0), (D1, T1), (D2, T2), (D3, T3));
961implWriteableTuple!((D0, T0), (D1, T1), (D2, T2), (D3, T3), (D4, T4));
962implWriteableTuple!((D0, T0), (D1, T1), (D2, T2), (D3, T3), (D4, T4), (D5, T5));
963#[rustfmt::skip]
964implWriteableTuple!((D0, T0), (D1, T1), (D2, T2), (D3, T3), (D4, T4), (D5, T5), (D6, T6));
965#[rustfmt::skip]
966implWriteableTuple!((D0, T0), (D1, T1), (D2, T2), (D3, T3), (D4, T4), (D5, T5), (D6, T6), (D7, T7));
967#[rustfmt::skip]
968implWriteableTuple!(
969    (D0, T0), (D1, T1), (D2, T2), (D3, T3), (D4, T4), (D5, T5), (D6, T6), (D7, T7) , (D8, T8)
970);
971#[rustfmt::skip]
972implWriteableTuple!(
973    (D0, T0), (D1, T1), (D2, T2), (D3, T3), (D4, T4), (D5, T5), (D6, T6), (D7, T7) , (D8, T8),
974    (D9, T9)
975);
976#[rustfmt::skip]
977implWriteableTuple!(
978    (D0, T0), (D1, T1), (D2, T2), (D3, T3), (D4, T4), (D5, T5), (D6, T6), (D7, T7) , (D8, T8),
979    (D9, T9), (D10, T10)
980);
981#[rustfmt::skip]
982implWriteableTuple!(
983    (D0, T0), (D1, T1), (D2, T2), (D3, T3), (D4, T4), (D5, T5), (D6, T6), (D7, T7) , (D8, T8),
984    (D9, T9), (D10, T10), (D11, T11)
985);
986
987impl<'p, const N: usize, Tup, Dummy> WriteableTuple<'p, [Dummy; N]> for [Tup; N]
988where
989    Tup: WriteableTuple<'p, Dummy> + 'p,
990{
991    type Return = [Tup::Return; N];
992
993    fn write_all(self, _: &'p mut Pass) -> Option<Self::Return> {
994        if self.state_ptrs().into_iter().enumerate().any(|(lhs, i)| {
995            self.state_ptrs()
996                .into_iter()
997                .enumerate()
998                .any(|(rhs, j)| lhs == rhs && i != j)
999        }) {
1000            return None;
1001        }
1002
1003        static PASS: Pass = unsafe { Pass::new() };
1004
1005        Some(self.map(|tup| {
1006            let pa = &raw const PASS as *mut Pass;
1007            tup.write_all(unsafe { pa.as_mut() }.unwrap()).unwrap()
1008        }))
1009    }
1010
1011    fn state_ptrs(&self) -> impl IntoIterator<Item = CurStatePtr<'_>> {
1012        self.iter().flat_map(|tup| tup.state_ptrs())
1013    }
1014}
1015
1016/// A trait for writing to multiple [`RwData`]-like structs at once
1017#[doc(hidden)]
1018pub trait WriteableData<'p, T: ?Sized + 'p>: InnerWriteableData {
1019    /// Just like [`RwData::write`]
1020    #[doc(hidden)]
1021    fn write_one_of_many(&'p self, pa: &'p mut Pass) -> &'p mut T;
1022
1023    /// A pointer for [`Pass::try_write_many`]
1024    #[doc(hidden)]
1025    fn cur_state_ptr(&self) -> CurStatePtr<'_>;
1026}
1027
1028impl<'p, T: ?Sized + 'p> WriteableData<'p, T> for RwData<T> {
1029    fn write_one_of_many(&'p self, pa: &'p mut Pass) -> &'p mut T {
1030        self.write(pa)
1031    }
1032
1033    fn cur_state_ptr(&self) -> CurStatePtr<'_> {
1034        CurStatePtr(&self.cur_state)
1035    }
1036}
1037
1038impl<'p, T: Default> WriteableData<'p, T> for BulkDataWriter<T> {
1039    fn write_one_of_many(&'p self, pa: &'p mut Pass) -> &'p mut T {
1040        self.write(pa)
1041    }
1042
1043    fn cur_state_ptr(&self) -> CurStatePtr<'_> {
1044        CurStatePtr(&self.data.cur_state)
1045    }
1046}
1047
1048impl<'p, W: Widget> WriteableData<'p, W> for crate::context::Handle<W> {
1049    fn write_one_of_many(&'p self, pa: &'p mut Pass) -> &'p mut W {
1050        self.write(pa)
1051    }
1052
1053    fn cur_state_ptr(&self) -> CurStatePtr<'_> {
1054        CurStatePtr(&self.widget().cur_state)
1055    }
1056}
1057
1058impl<'p> WriteableData<'p, crate::ui::Area> for crate::ui::RwArea {
1059    fn write_one_of_many(&'p self, pa: &'p mut Pass) -> &'p mut crate::ui::Area {
1060        self.write(pa)
1061    }
1062
1063    fn cur_state_ptr(&self) -> CurStatePtr<'_> {
1064        CurStatePtr(&self.0.cur_state)
1065    }
1066}
1067
1068/// To prevent outside implementations
1069trait InnerWriteableData {}
1070impl<T: ?Sized> InnerWriteableData for RwData<T> {}
1071impl<T: Default> InnerWriteableData for BulkDataWriter<T> {}
1072impl<W: Widget> InnerWriteableData for crate::context::Handle<W> {}
1073impl InnerWriteableData for crate::ui::RwArea {}
1074
1075/// A struct for comparison when calling [`Pass::write_many`]
1076#[doc(hidden)]
1077#[derive(Clone, Copy)]
1078pub struct CurStatePtr<'p>(&'p Arc<AtomicUsize>);
1079
1080impl std::cmp::PartialEq for CurStatePtr<'_> {
1081    fn eq(&self, other: &Self) -> bool {
1082        Arc::ptr_eq(self.0, other.0)
1083    }
1084}