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}