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 however is that [`RwData`] is a type mostly used
19//! by Duat itself, inside APIs like those of [`context`], so if you
20//! want information to be shared across threads and you don't need
21//! others to be able to reach it, you should prefer using more
22//! conventional locking mechanisms, like those of [`parking_lot`],
23//! which are exported by Duat.
24//!
25//! [read]: RwData::read
26//! [written to]: RwData::write
27//! [`Widget`]: crate::widgets::Widget
28//! [`File`]: crate::widgets::File
29//! [updated]: crate::widgets::Widget::update
30//! [`Text`]: crate::text::Text
31//! [`StatusLine`]: crate::widgets::StatusLine
32//! [`context`]: crate::context
33use std::{
34 any::TypeId,
35 sync::{
36 Arc,
37 atomic::{AtomicUsize, Ordering},
38 },
39};
40
41use parking_lot::{Mutex, MutexGuard};
42
43/// A read write shared reference to data
44pub struct RwData<T: ?Sized + 'static> {
45 // The `Box` is to allow for downcasting.
46 pub(super) data: Arc<Mutex<T>>,
47 pub(super) cur_state: Arc<AtomicUsize>,
48 read_state: AtomicUsize,
49 pub(super) type_id: TypeId,
50}
51
52impl<T> RwData<T> {
53 /// Returns a new instance of a [`RwData`], assuming that it is
54 /// sized.
55 ///
56 /// This has to be sized because of some Rust limitations, as you
57 /// can`t really pass an unsized argument to a function (for now).
58 /// If you're looking to store unsized types (`dyn Trait`,
59 /// `\[Type\]`, etc) on an [`RwData`], see
60 /// [`RwData::new_unsized`].
61 pub fn new(data: T) -> Self {
62 Self {
63 data: Arc::new(Mutex::new(data)),
64 cur_state: Arc::new(AtomicUsize::new(1)),
65 read_state: AtomicUsize::new(1),
66 type_id: TypeId::of::<T>(),
67 }
68 }
69}
70
71impl<T: ?Sized> RwData<T> {
72 /// Returns a new instance of [`RwData`], assuming that it is
73 /// unsized.
74 ///
75 /// This method is only required if you're dealing with types that
76 /// may not be [`Sized`] (`dyn Trait`, `[Type]`, etc). If the type
77 /// in question is sized, use [`RwData::new`] instead.
78 pub fn new_unsized<SizedT: 'static>(data: Arc<Mutex<T>>) -> Self {
79 Self {
80 data,
81 cur_state: Arc::new(AtomicUsize::new(1)),
82 read_state: AtomicUsize::new(1),
83 type_id: TypeId::of::<SizedT>(),
84 }
85 }
86
87 /// Blocking reference to the information
88 ///
89 /// Also makes it so that [`has_changed`] returns `false`.
90 ///
91 /// # Examples
92 ///
93 /// Since this is a blocking read, the thread will hault while the
94 /// data is being written to:
95 ///
96 /// ```rust
97 /// # use std::{thread, time::{Duration, Instant}};
98 /// # use duat_core::data::RwData;
99 /// let data = RwData::new("☹️");
100 /// let data_clone = data.clone();
101 /// let instant = Instant::now();
102 /// thread::scope(|scope| {
103 /// scope.spawn(|| {
104 /// let mut read_write = data.write();
105 /// // Supposedly long computations.
106 /// thread::sleep(Duration::from_millis(150));
107 /// *read_write = "☺️";
108 /// });
109 ///
110 /// // Just making sure that the read happens slightly after the write.
111 /// thread::sleep(Duration::from_millis(10));
112 ///
113 /// let read_only = data_clone.read();
114 /// let time_elapsed = Instant::now().duration_since(instant);
115 /// assert!(time_elapsed >= Duration::from_millis(100));
116 /// assert!(*read_only == "☺️");
117 /// });
118 /// ```
119 ///
120 /// [`has_changed`]: Self::has_changed
121 pub fn read(&self) -> ReadDataGuard<'_, T> {
122 let cur_state = self.cur_state.load(Ordering::Acquire);
123 self.read_state.store(cur_state, Ordering::Release);
124 ReadDataGuard(self.data.lock())
125 }
126
127 /// Non blocking reference to the information
128 ///
129 /// If successful, also makes it so that [`has_changed`] returns
130 /// `false`.
131 ///
132 /// # Examples
133 ///
134 /// Unlike [`read`], can fail to return a reference to the
135 /// underlying data:
136 ///
137 /// ```rust
138 /// # use std::{sync::TryLockError};
139 /// # use duat_core::data::RwData;
140 /// let new_data = RwData::new("hello 👋");
141 ///
142 /// let mut blocking_write = new_data.write();
143 /// *blocking_write = "bye 👋";
144 ///
145 /// let try_read = new_data.try_read();
146 /// assert!(matches!(try_read, None));
147 /// ```
148 ///
149 /// [`has_changed`]: Self::has_changed
150 /// [`read`]: Self::read
151 pub fn try_read(&self) -> Option<ReadDataGuard<'_, T>> {
152 self.data.try_lock().map(|guard| {
153 let cur_state = self.cur_state.load(Ordering::Acquire);
154 self.read_state.store(cur_state, Ordering::Release);
155 ReadDataGuard(guard)
156 })
157 }
158
159 /// Whether or not it has changed since it was last read
160 ///
161 /// A "change" is defined as any time the methods [`write`]
162 /// or [`try_write`] are called on an [`RwData`]. Once
163 /// `has_changed` is called, the data will be considered
164 /// unchanged since the last `has_changed` call, for
165 /// that specific instance of a [`RwData`].
166 ///
167 /// When first creating a [`RwData`] `has_changed` will return
168 /// `false`, but clones of that [`RwData`] will have `has_changed`
169 /// initially return `true`.
170 ///
171 /// # Examples
172 ///
173 /// ```rust
174 /// use duat_core::data::RwData;
175 /// let data = RwData::new("Initial text");
176 /// assert!(!data.has_changed());
177 ///
178 /// *data.write() = "Almost final text";
179 ///
180 /// let data_clone1 = data.clone();
181 ///
182 /// assert!(data_clone1.has_changed());
183 ///
184 /// *data.write() = "Final text";
185 ///
186 /// assert!(data_clone1.has_changed());
187 /// assert!(!data_clone1.has_changed());
188 /// ```
189 ///
190 /// [`write`]: RwData::write
191 /// [`try_write`]: RwData::try_write
192 pub fn has_changed(&self) -> bool {
193 let cur_state = self.cur_state.load(Ordering::Acquire);
194 let read_state = self.read_state.swap(cur_state, Ordering::Acquire);
195 cur_state > read_state
196 }
197
198 /// A function that returns true if the data has changed
199 ///
200 /// This is essentially a faster way of writing
201 ///
202 /// ```rust
203 /// # use duat_core::data::RwData;
204 /// let my_data = RwData::new(42);
205 /// let checker = {
206 /// let my_data = my_data.clone();
207 /// move || my_data.has_changed()
208 /// };
209 /// ```
210 ///
211 /// [`Widget`]: crate::widgets::Widget
212 pub fn checker(&self) -> impl Fn() -> bool + Send + Sync + 'static + use<T> {
213 let cur_state = self.cur_state.clone();
214 let read_state = AtomicUsize::new(self.read_state.load(Ordering::Relaxed));
215 move || {
216 let cur_state = cur_state.load(Ordering::Acquire);
217 let read_state = read_state.swap(cur_state, Ordering::Acquire);
218 cur_state > read_state
219 }
220 }
221
222 /// Returns `true` if both [`RwData`]s point to the same data
223 ///
224 /// # Examples
225 /// ```rust
226 /// # use duat_core::data::{RwData};
227 /// let data_1 = RwData::new(false);
228 /// let data_1_clone = data_1.clone();
229 ///
230 /// let data_2 = RwData::new(true);
231 ///
232 /// assert!(data_1.ptr_eq(&data_1_clone));
233 /// assert!(!data_1.ptr_eq(&data_2));
234 /// ```
235 pub fn ptr_eq<U: ?Sized>(&self, other: &RwData<U>) -> bool {
236 Arc::ptr_eq(&self.cur_state, &other.cur_state)
237 }
238
239 /// Blocking exclusive reference to the information
240 ///
241 /// Also makes it so that [`has_changed`] returns true for any of
242 /// the clones made from `self`, but **NOT** `self`.
243 ///
244 /// # Safety
245 ///
246 /// Since this is a blocking function, you should be careful about
247 /// the prevention of deadlocks, one of the few unsafe aspects of
248 /// code that Rust doesn't prevent.
249 ///
250 /// As an example, this code will deadlock indefinitely:
251 /// ```no_run
252 /// # use std::{mem, thread, time::Duration};
253 /// # use duat_core::data::RwData;
254 /// let data_1 = RwData::new('😟');
255 /// let data_2 = RwData::new('😭');
256 ///
257 /// thread::scope(|scope| {
258 /// scope.spawn(|| {
259 /// let mut data_1 = data_1.write();
260 /// thread::sleep(Duration::from_millis(100));
261 /// let mut data_2 = data_2.write();
262 /// mem::swap(&mut data_1, &mut data_2);
263 /// });
264 ///
265 /// scope.spawn(|| {
266 /// let mut data_2 = data_2.write();
267 /// thread::sleep(Duration::from_millis(100));
268 /// let mut data_1 = data_1.write();
269 /// mem::swap(&mut data_1, &mut data_2);
270 /// });
271 /// });
272 /// ```
273 ///
274 /// [`has_changed`]: RwData::has_changed
275 pub fn write(&self) -> WriteDataGuard<T> {
276 let guard = self.data.lock();
277 WriteDataGuard {
278 guard,
279 cur_state: &self.cur_state,
280 read_state: &self.read_state,
281 }
282 }
283
284 /// Non Blocking mutable reference to the information
285 ///
286 /// Also makes it so that [`has_changed`] returns true for any of
287 /// the clones made from `self`, but **NOT** `self`.
288 ///
289 /// # Safety
290 ///
291 /// Unlike [`RwData::write`], this method cannot cause deadlocks,
292 /// returning an [`Err`] instead.
293 /// ```
294 /// # use std::{mem, thread, time::Duration};
295 /// # use duat_core::data::RwData;
296 /// let data_1 = RwData::new('😀');
297 /// let data_2 = RwData::new('😁');
298 ///
299 /// thread::scope(|scope| {
300 /// scope.spawn(|| {
301 /// let mut data_1 = data_1.try_write();
302 /// thread::sleep(Duration::from_millis(100));
303 /// let mut data_2 = data_2.try_write();
304 /// if let (Some(mut data_1), Some(mut data_2)) = (data_1, data_2) {
305 /// mem::swap(&mut data_1, &mut data_2);
306 /// }
307 /// });
308 ///
309 /// scope.spawn(|| {
310 /// let mut data_2 = data_2.try_write();
311 /// thread::sleep(Duration::from_millis(100));
312 /// let mut data_1 = data_1.try_write();
313 /// if let (Some(mut data_1), Some(mut data_2)) = (data_1, data_2) {
314 /// mem::swap(&mut data_1, &mut data_2);
315 /// }
316 /// });
317 /// });
318 ///
319 /// // Two swaps will happen.
320 /// assert_eq!(*data_1.read(), '😀');
321 /// assert_eq!(*data_2.read(), '😁');
322 /// ```
323 /// The downside is that you may not want it to fail ever, in
324 /// which case, you should probably use [`RwData::write`].
325 ///
326 /// [`has_changed`]: RwData::has_changed
327 pub fn try_write(&self) -> Option<WriteDataGuard<'_, T>> {
328 self.data.try_lock().map(|guard| WriteDataGuard {
329 guard,
330 cur_state: &self.cur_state,
331 read_state: &self.read_state,
332 })
333 }
334
335 /// Blocking reference to the information
336 ///
337 /// Unlike [`read`], *DOES NOT* make it so
338 /// [`has_changed`] returns `false`.
339 ///
340 /// This method should only be used in very specific
341 /// circumstances, such as when multiple owners have nested
342 /// [`RwData`]s, thus referencing the same inner [`RwData`], in
343 /// a way that reading from one point would interfere in the
344 /// update detection of the other point.
345 ///
346 /// [`read`]: Self::read,
347 /// [`has_changed`]: Self::has_changed
348 pub(crate) fn raw_read(&self) -> ReadDataGuard<'_, T> {
349 ReadDataGuard(self.data.lock())
350 }
351
352 /// Returns `true` if the data is of the concrete type `T`
353 ///
354 /// # Examples
355 ///
356 /// You may want this method if you're storing a list of
357 /// [`RwData<dyn Trait>`], and want to know, at runtime, what type
358 /// each element is:
359 /// ```rust
360 /// # use std::{any::Any, fmt::Display, sync::Arc};
361 /// # use duat_core::{Mutex, data::RwData};
362 /// let list: [RwData<dyn Display>; 3] = [
363 /// RwData::new_unsized::<String>(Arc::new(Mutex::new(String::from(
364 /// "I can show you the world",
365 /// )))),
366 /// RwData::new_unsized::<String>(Arc::new(Mutex::new(String::from(
367 /// "Shining, shimmering, splendid",
368 /// )))),
369 /// RwData::new_unsized::<char>(Arc::new(Mutex::new('🧞'))),
370 /// ];
371 ///
372 /// assert!(list[0].data_is::<String>());
373 /// assert!(list[1].data_is::<String>());
374 /// assert!(list[2].data_is::<char>());
375 /// ```
376 ///
377 /// [`RwData<dyn Trait>`]: RwData
378 pub fn data_is<U: ?Sized + 'static>(&self) -> bool {
379 self.type_id == TypeId::of::<U>()
380 }
381
382 /// Tries to downcast to a concrete type
383 ///
384 /// # Examples
385 ///
386 /// You may want this method if you're storing a list of
387 /// [`RwData<dyn Trait>`], and want to know, at runtime, what type
388 /// each element is:
389 /// ```rust
390 /// # use std::{fmt::Display, sync::Arc};
391 /// # use duat_core::{Mutex, data::RwData};
392 /// let list: [RwData<dyn Display>; 3] = [
393 /// RwData::new_unsized::<String>(Arc::new(Mutex::new(String::from(
394 /// "I can show you the world",
395 /// )))),
396 /// RwData::new_unsized::<String>(Arc::new(Mutex::new(String::from(
397 /// "Shining, shimmering, splendid",
398 /// )))),
399 /// RwData::new_unsized::<char>(Arc::new(Mutex::new('🧞'))),
400 /// ];
401 ///
402 /// let maybe_char = list[2].clone().try_downcast::<char>();
403 /// assert!(maybe_char.is_some());
404 /// *maybe_char.unwrap().write() = '👳';
405 ///
406 /// let maybe_string = list[0].clone().try_downcast::<char>();
407 /// assert!(maybe_string.is_none());
408 /// ```
409 /// If you don't need to keep a [`RwData<U>`], consider just using
410 /// [`RwData::read_as`]. If you only need to know if the type
411 /// matches, consider using [`RwData::data_is`].
412 ///
413 /// [`RwData<dyn Trait>`]: RwData
414 pub fn try_downcast<U: 'static>(&self) -> Option<RwData<U>> {
415 if self.data_is::<U>() {
416 let Self { data, cur_state, read_state, .. } = self.clone();
417 let ptr = Arc::into_raw(data);
418 let data = unsafe { Arc::from_raw(ptr as *const Mutex<U>) };
419 Some(RwData {
420 data,
421 cur_state,
422 read_state,
423 type_id: self.type_id,
424 })
425 } else {
426 None
427 }
428 }
429
430 /// Blocking inspection of the inner data
431 ///
432 /// # Examples
433 ///
434 /// You may want this method if you're storing a list of
435 /// [`RwData<dyn Trait>`], and want to know, at runtime, what type
436 /// each element is:
437 /// ```rust
438 /// # use std::{any::Any, fmt::Display, sync::Arc};
439 /// # use duat_core::{Mutex, data::RwData};
440 /// let list: [RwData<dyn Display>; 3] = [
441 /// RwData::new_unsized::<String>(Arc::new(Mutex::new(String::from(
442 /// "I can show you the world",
443 /// )))),
444 /// RwData::new_unsized::<String>(Arc::new(Mutex::new(String::from(
445 /// "Shining, shimmering, splendid",
446 /// )))),
447 /// RwData::new_unsized::<char>(Arc::new(Mutex::new('🧞'))),
448 /// ];
449 ///
450 /// assert!(matches!(
451 /// list[2].read_as::<char>().map(|c| c.len_utf8()),
452 /// Some(4)
453 /// ));
454 /// assert!(matches!(
455 /// list[1].read_as::<char>().map(|c| c.to_ascii_uppercase()),
456 /// None
457 /// ));
458 /// ```
459 ///
460 /// [`RwData<dyn Trait>`]: RwData
461 pub fn read_as<U: 'static>(&self) -> Option<ReadDataGuard<'_, U>> {
462 if !self.data_is::<U>() {
463 return None;
464 }
465
466 self.read_state
467 .store(self.cur_state.load(Ordering::Acquire), Ordering::Release);
468 let ptr = Arc::as_ptr(&self.data) as *const Mutex<U>;
469 // SAFETY: Since this borrows this RwData, the Arc shouldn't be
470 // dropped while this guard exists
471 Some(ReadDataGuard(unsafe { ptr.as_ref().unwrap().lock() }))
472 }
473
474 pub fn write_as<U: 'static>(&self) -> Option<WriteDataGuard<'_, U>> {
475 if !self.data_is::<U>() {
476 return None;
477 }
478
479 let ptr = Arc::as_ptr(&self.data) as *const Mutex<U>;
480 Some(WriteDataGuard {
481 // SAFETY: Since this borrows this RwData, the Arc shouldn't
482 // be dropped while this guard exists
483 guard: unsafe { ptr.as_ref().unwrap().lock() },
484 cur_state: &self.cur_state,
485 read_state: &self.read_state,
486 })
487 }
488
489 pub(crate) fn raw_write(&self) -> MutexGuard<'_, T> {
490 self.data.lock()
491 }
492}
493
494impl<T: ?Sized + std::fmt::Debug> std::fmt::Debug for RwData<T> {
495 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
496 std::fmt::Debug::fmt(&*self.data.lock(), f)
497 }
498}
499
500impl<T: ?Sized> Clone for RwData<T> {
501 fn clone(&self) -> Self {
502 Self {
503 data: self.data.clone(),
504 cur_state: self.cur_state.clone(),
505 read_state: AtomicUsize::new(self.cur_state.load(Ordering::Relaxed) - 1),
506 type_id: self.type_id,
507 }
508 }
509}
510
511impl<T: Default> Default for RwData<T> {
512 fn default() -> Self {
513 Self {
514 data: Arc::new(Mutex::new(T::default())),
515 cur_state: Arc::new(AtomicUsize::new(1)),
516 read_state: AtomicUsize::new(1),
517 type_id: TypeId::of::<T>(),
518 }
519 }
520}
521
522pub struct ReadDataGuard<'a, T: ?Sized>(MutexGuard<'a, T>);
523
524impl<T: ?Sized> std::ops::Deref for ReadDataGuard<'_, T> {
525 type Target = T;
526
527 fn deref(&self) -> &Self::Target {
528 &self.0
529 }
530}
531
532pub struct WriteDataGuard<'a, T: ?Sized> {
533 guard: MutexGuard<'a, T>,
534 cur_state: &'a Arc<AtomicUsize>,
535 read_state: &'a AtomicUsize,
536}
537
538impl<T: ?Sized> std::ops::Deref for WriteDataGuard<'_, T> {
539 type Target = T;
540
541 fn deref(&self) -> &Self::Target {
542 &self.guard
543 }
544}
545
546impl<T: ?Sized> std::ops::DerefMut for WriteDataGuard<'_, T> {
547 fn deref_mut(&mut self) -> &mut Self::Target {
548 &mut self.guard
549 }
550}
551
552impl<T: ?Sized> Drop for WriteDataGuard<'_, T> {
553 fn drop(&mut self) {
554 let prev = self.cur_state.fetch_add(1, Ordering::Acquire);
555 self.read_state.store(prev + 1, Ordering::Release)
556 }
557}
558
559pub struct DataMap<I: ?Sized + Send + 'static, O> {
560 data: RwData<I>,
561 f: Box<dyn FnMut() -> O + Send>,
562}
563
564impl<I: ?Sized + Send + 'static, O> DataMap<I, O> {
565 pub fn fns(
566 self,
567 ) -> (
568 Box<dyn FnMut() -> O + Send>,
569 Box<dyn Fn() -> bool + Send + Sync>,
570 ) {
571 (self.f, Box::new(self.data.checker()))
572 }
573}
574
575impl<I: ?Sized + Send + 'static, O> FnOnce<()> for DataMap<I, O> {
576 type Output = O;
577
578 extern "rust-call" fn call_once(mut self, _: ()) -> Self::Output {
579 (self.f)()
580 }
581}
582
583impl<I: ?Sized + Send + 'static, O> FnMut<()> for DataMap<I, O> {
584 extern "rust-call" fn call_mut(&mut self, _: ()) -> Self::Output {
585 (self.f)()
586 }
587}
588
589impl<I: ?Sized + Send + 'static> RwData<I> {
590 pub fn map<O>(&self, mut f: impl FnMut(&I) -> O + Send + 'static) -> DataMap<I, O> {
591 let data = self.clone();
592 let f = move || f(&*data.read());
593 DataMap { data: self.clone(), f: Box::new(f) }
594 }
595}
596
597impl<I: ?Sized + Send + 'static, O: 'static> DataMap<I, O> {
598 pub fn map<O2>(mut self, mut f: impl FnMut(O) -> O2 + Send + 'static) -> DataMap<I, O2> {
599 DataMap {
600 data: self.data,
601 f: Box::new(move || f((self.f)())),
602 }
603 }
604}