duat_core/data/ro.rs
1use std::{
2 any::TypeId,
3 sync::{
4 Arc,
5 atomic::{AtomicUsize, Ordering},
6 },
7};
8
9use super::{Data, RwData, private::InnerData};
10// use parking_lot::{RwLock, RwLockReadGuard};
11use super::{RwLock, RwLockReadGuard};
12
13/// A read-only reference to information.
14///
15/// A data type that can read, but not write, the inner data. If you
16/// wish to get a read write struct, see [`RwData`]. This struct is
17/// usually what you will get as a readable handle from structs
18/// containing [`RwData`]. For example, when opening a new file, we
19/// use a hook, called the `constructor_hook`, to do certain actions
20/// to that file, like opening surrounding [`Widget`]s. This hook can
21/// provide an [`RoData`], which is then queryed by the
22/// widget for information about the file. This also prevents the
23/// modification of data by third parties which shouldn`t be able to
24/// do so.
25///
26/// Can only be created by cloning the [`Arc<RwLock<T>>`] from a
27/// [`RwData`], or through cloning.
28///
29/// [`Widget`]: crate::widgets::Widget
30/// [`RoData`]: RoData
31pub struct RoData<T>
32where
33 T: ?Sized + 'static,
34{
35 data: Arc<RwLock<T>>,
36 cur_state: Arc<AtomicUsize>,
37 read_state: AtomicUsize,
38 type_id: TypeId,
39}
40
41impl<T> RoData<T> {
42 /// Returns a new instance of a [`RoData`], assuming that it is
43 /// sized.
44 ///
45 /// This has to be sized because of some Rust limitations, as you
46 /// can`t really pass an unsized argument to a function (for now).
47 /// If you're looking to store unsized types (`dyn Trait`,
48 /// `\[Type\]`, etc) on a [`RwData`], see [`RwData::new_unsized`].
49 pub fn new(data: T) -> Self {
50 Self {
51 data: Arc::new(RwLock::new(data)),
52 cur_state: Arc::new(AtomicUsize::new(1)),
53 read_state: AtomicUsize::new(1),
54 type_id: TypeId::of::<T>(),
55 }
56 }
57}
58
59impl<T> RoData<T>
60where
61 T: ?Sized,
62{
63 /// Returns a new instance of [`RoData`], assuming that it is
64 /// unsized.
65 ///
66 /// This method is only required if you're dealing with types that
67 /// may not be [`Sized`] (`dyn Trait`, `[Type]`, etc). If the type
68 /// in question is sized, use [`RwData::new`] instead.
69 pub fn new_unsized<SizedT: 'static>(data: Arc<RwLock<T>>) -> Self {
70 // It's 1 here so that any `RoState`s created from this will have
71 // `has_changed()` return `true` at least once, by copying the
72 // second value - 1.
73 Self {
74 data,
75 cur_state: Arc::new(AtomicUsize::new(1)),
76 read_state: AtomicUsize::new(1),
77 type_id: TypeId::of::<SizedT>(),
78 }
79 }
80
81 /// Blocking reference to the information.
82 ///
83 /// Also makes it so that [`has_changed`] returns `false`.
84 ///
85 /// # Examples
86 ///
87 /// Since this is a blocking read, the thread will hault while the
88 /// data is being written to:
89 /// ```rust
90 /// # use std::{thread, time::{Duration, Instant}};
91 /// # use duat_core::data::{Data, RoData, RwData};
92 /// let read_write_data = RwData::new("☹️");
93 /// let read_only_data = RoData::from(&read_write_data);
94 /// let instant = Instant::now();
95 /// thread::scope(|scope| {
96 /// scope.spawn(|| {
97 /// let mut read_write = read_write_data.write();
98 /// // Supposedly long computations.
99 /// thread::sleep(Duration::from_millis(150));
100 /// *read_write = "☺️";
101 /// });
102 ///
103 /// // Just making sure that the read happens slightly after the write.
104 /// thread::sleep(Duration::from_millis(10));
105 ///
106 /// let read_only = read_only_data.read();
107 /// let time_elapsed = Instant::now().duration_since(instant);
108 /// assert!(time_elapsed >= Duration::from_millis(100));
109 /// assert!(*read_only == "☺️");
110 /// });
111 /// ```
112 /// Note that other reads will **NOT** block reading in this way,
113 /// only writes:
114 /// ```rust
115 /// # use std::{thread, time::{Duration, Instant} };
116 /// # use duat_core::data::{Data, RoData, RwData};
117 /// let read_write_data = RwData::new("☹️");
118 /// let read_only_data = RoData::from(&read_write_data);
119 /// let instant = Instant::now();
120 /// thread::scope(|scope| {
121 /// scope.spawn(|| {
122 /// let read_only = read_write_data.read();
123 /// // The thread hangs, but reading is still possible.
124 /// thread::sleep(Duration::from_millis(100));
125 /// });
126 ///
127 /// // Just making sure that this read happens slightly after the last one.
128 /// thread::sleep(Duration::from_millis(1));
129 ///
130 /// let read_only = read_only_data.read();
131 /// let time_elapsed = Instant::now().duration_since(instant);
132 /// assert!(time_elapsed < Duration::from_millis(100));
133 /// });
134 /// ```
135 /// [`has_changed`]: Self::has_changed
136 pub fn read(&self) -> RwLockReadGuard<'_, T> {
137 let cur_state = self.cur_state().load(Ordering::Acquire);
138 self.read_state().store(cur_state, Ordering::Release);
139 self.data()
140 }
141
142 /// Blocking inspection of the inner data.
143 ///
144 /// Also makes it so that [`has_changed`] returns `false`.
145 ///
146 /// # Examples
147 ///
148 /// This method is useful if you want to scope the reading, or
149 /// need to drop the reference quickly, so it can be written to.
150 ///
151 /// You can do this:
152 /// ```rust
153 /// # use duat_core::data::{Data, RoData, RwData};
154 /// # fn add_to_count(count: &mut usize) {}
155 /// # fn new_count() -> usize {
156 /// # 0
157 /// # }
158 /// let count = RwData::new(31);
159 /// let count_reader = RoData::from(&count);
160 ///
161 /// // The read write counterpart to `inspect`.
162 /// count.mutate(|count| {
163 /// *count += 5;
164 /// add_to_count(count)
165 /// });
166 ///
167 /// count_reader.inspect(|count| { /* reading operations */ });
168 ///
169 /// *count.write() = new_count();
170 /// ```
171 /// Instead of this:
172 /// ```rust
173 /// # use duat_core::data::{Data, RoData, RwData};
174 /// # fn add_to_count(count: &mut usize) {}
175 /// # fn new_count() -> usize {
176 /// # 0
177 /// # }
178 /// let count = RwData::new(31);
179 /// let count_reader = RoData::from(&count);
180 ///
181 /// // The read write counterpart to `inspect`.
182 /// let mut count_write = count.write();
183 /// *count_write += 5;
184 /// add_to_count(&mut *count_write);
185 /// drop(count_write);
186 ///
187 /// let count_read = count_reader.read();
188 /// // reading operations
189 /// drop(count_read);
190 ///
191 /// *count.write() = new_count();
192 /// ```
193 /// Or this:
194 /// ```rust
195 /// # use duat_core::data::{Data, RoData, RwData};
196 /// # fn add_to_count(count: &mut usize) {}
197 /// # fn new_count() -> usize {
198 /// # 0
199 /// # }
200 /// let count = RwData::new(31);
201 /// let count_reader = RoData::from(&count);
202 ///
203 /// // The read write counterpart to `inspect`.
204 /// {
205 /// let mut count = count.write();
206 /// *count += 5;
207 /// add_to_count(&mut count)
208 /// }
209 ///
210 /// {
211 /// let count = count.read();
212 /// // reading operations
213 /// }
214 ///
215 /// *count.write() = new_count();
216 /// ```
217 /// [`has_changed`]: Self::has_changed
218 pub fn inspect<U>(&self, f: impl FnOnce(&T) -> U) -> U {
219 let cur_state = self.cur_state().load(Ordering::Acquire);
220 self.read_state().store(cur_state, Ordering::Release);
221 f(&self.data())
222 }
223
224 /// Non blocking reference to the information.
225 ///
226 /// If successful, also makes it so that [`has_changed`] returns
227 /// `false`.
228 ///
229 /// # Examples
230 ///
231 /// Unlike [`read`], can fail to return a reference to the
232 /// underlying data:
233 /// ```rust
234 /// # use duat_core::data::{Data, RwData};
235 /// let new_data = RwData::new("hello 👋");
236 ///
237 /// let mut blocking_write = new_data.write();
238 /// *blocking_write = "bye 👋";
239 ///
240 /// let try_read = new_data.try_read();
241 /// assert!(matches!(try_read, None));
242 /// ```
243 ///
244 /// [`has_changed`]: Self::has_changed
245 /// [`read`]: Self::read
246 pub fn try_read(&self) -> Option<RwLockReadGuard<'_, T>> {
247 self.try_data().inspect(|_| {
248 let cur_state = self.cur_state().load(Ordering::Acquire);
249 self.read_state().store(cur_state, Ordering::Release);
250 })
251 }
252
253 /// Non blocking inspection of the inner data.
254 ///
255 /// If successful, also makes it so that [`has_changed`] returns
256 /// `false`.
257 ///
258 /// # Examples
259 ///
260 /// Unlike [`inspect`], can fail to return a reference to the
261 /// underlying data:
262 /// ```rust
263 /// # use duat_core::data::{Data, RwData};
264 /// let new_data = RwData::new("hello 👋");
265 ///
266 /// let try_inspect = new_data.mutate(|blocking_mutate| {
267 /// *blocking_mutate = "bye 👋";
268 ///
269 /// new_data.try_inspect(|try_inspect| *try_inspect == "bye 👋")
270 /// });
271 ///
272 /// assert!(matches!(try_inspect, None));
273 /// ```
274 ///
275 /// [`has_changed`]: Self::has_changed
276 /// [`inspect`]: Self::inspect
277 pub fn try_inspect<U>(&self, f: impl FnOnce(&T) -> U) -> Option<U> {
278 self.try_data().map(|data| {
279 let cur_state = self.cur_state().load(Ordering::Acquire);
280 self.read_state().store(cur_state, Ordering::Release);
281 f(&data)
282 })
283 }
284
285 /// Whether or not it has changed since it was last read.
286 ///
287 /// A "change" is defined as any time the methods [`write`],
288 /// [`mutate`], [`try_write`], or [`try_mutate`], are called on an
289 /// [`RwData`]. Once `has_changed` is called, the data will be
290 /// considered unchanged since the last `has_changed` call, for
291 /// that specific instance of a [`Data`].
292 ///
293 /// When first creating a [`Data`] type, `has_changed`
294 /// will return `false`;
295 ///
296 /// # Examples
297 /// ```rust
298 /// use duat_core::data::{Data, RoData, RwData};
299 /// let new_data = RwData::new("Initial text");
300 /// assert!(!new_data.has_changed());
301 ///
302 /// let first_reader = RoData::from(&new_data);
303 ///
304 /// *new_data.write() = "Final text";
305 ///
306 /// let second_reader = RoData::from(&new_data);
307 ///
308 /// assert!(first_reader.has_changed());
309 /// assert!(!second_reader.has_changed());
310 /// ```
311 ///
312 /// [`write`]: RwData::write
313 /// [`mutate`]: RwData::mutate
314 /// [`try_write`]: RwData::try_write
315 /// [`try_mutate`]: RwData::try_mutate
316 pub fn has_changed(&self) -> bool {
317 let cur_state = self.cur_state().load(Ordering::Relaxed);
318 let read_state = self.read_state().swap(cur_state, Ordering::Relaxed);
319 cur_state > read_state
320 }
321
322 /// Returns `true` if both [`Data<T>`]s point to the same
323 /// data.
324 ///
325 /// # Examples
326 /// ```rust
327 /// # use duat_core::data::{Data, RwData};
328 /// let data_1 = RwData::new(false);
329 /// let data_1_clone = data_1.clone();
330 ///
331 /// let data_2 = RwData::new(true);
332 ///
333 /// assert!(data_1.ptr_eq(&data_1_clone));
334 /// assert!(!data_1.ptr_eq(&data_2));
335 /// ```
336 pub fn ptr_eq<U>(&self, other: &impl Data<U>) -> bool
337 where
338 U: ?Sized,
339 {
340 Arc::as_ptr(self.cur_state()) as usize == Arc::as_ptr(other.cur_state()) as usize
341 }
342
343 /// Blocking inspection of the inner data.
344 ///
345 /// # Examples
346 ///
347 /// You may want this method if you're storing a list of
348 /// [`RwData`]s, and want to know, at runtime, what type
349 /// each element is:
350 ///
351 /// ```rust
352 /// # use std::{any::Any, fmt::Display, sync::Arc};
353 /// # use duat_core::data::{RwData, RwLock};
354 /// let list: [RwData<dyn Display>; 3] = [
355 /// RwData::new_unsized::<String>(Arc::new(RwLock::new(String::from(
356 /// "I can show you the world",
357 /// )))),
358 /// RwData::new_unsized::<String>(Arc::new(RwLock::new(String::from(
359 /// "Shining, shimmering, splendid",
360 /// )))),
361 /// RwData::new_unsized::<char>(Arc::new(RwLock::new('🧞'))),
362 /// ];
363 ///
364 /// assert!(matches!(
365 /// list[2].inspect_as::<char, bool>(|char| char.is_ascii()),
366 /// Some(false)
367 /// ));
368 /// assert!(matches!(
369 /// list[1].inspect_as::<char, bool>(|char| char.is_ascii()),
370 /// None
371 /// ));
372 /// ```
373 ///
374 /// [`RwData`]: RwData
375 pub fn inspect_as<U: 'static, R>(&self, f: impl FnOnce(&U) -> R) -> Option<R> {
376 self.data_is::<U>().then(|| {
377 let ptr = Arc::as_ptr(&self.data);
378 let cast = unsafe { ptr.cast::<RwLock<U>>().as_ref().unwrap() };
379
380 self.read_state
381 .store(self.cur_state.load(Ordering::Acquire), Ordering::Release);
382
383 f(&cast.read())
384 })
385 }
386
387 pub fn data_is<U>(&self) -> bool
388 where
389 U: 'static,
390 {
391 self.type_id == TypeId::of::<U>()
392 }
393
394 /// Tries to downcast to a concrete type.
395 pub fn try_downcast<U>(&self) -> Option<RoData<U>>
396 where
397 U: 'static,
398 {
399 if self.data_is::<U>() {
400 let Self { data, cur_state, read_state, .. } = self.clone();
401 let raw_data_pointer = Arc::into_raw(data);
402 let data = unsafe { Arc::from_raw(raw_data_pointer.cast::<RwLock<U>>()) };
403 Some(RoData {
404 data,
405 cur_state,
406 read_state,
407 type_id: TypeId::of::<U>(),
408 })
409 } else {
410 None
411 }
412 }
413}
414
415impl<T> Default for RoData<T>
416where
417 T: Default,
418{
419 fn default() -> Self {
420 Self {
421 data: Arc::new(RwLock::new(T::default())),
422 cur_state: Arc::new(AtomicUsize::new(0)),
423 read_state: AtomicUsize::new(0),
424 type_id: TypeId::of::<T>(),
425 }
426 }
427}
428
429impl<T> std::fmt::Debug for RoData<T>
430where
431 T: ?Sized + std::fmt::Debug,
432{
433 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
434 std::fmt::Debug::fmt(&*self.data.read(), f)
435 }
436}
437
438impl<T> From<&RwData<T>> for RoData<T>
439where
440 T: ?Sized,
441{
442 fn from(value: &RwData<T>) -> Self {
443 RoData {
444 data: value.data.clone(),
445 cur_state: value.cur_state.clone(),
446 read_state: AtomicUsize::new(value.cur_state.load(Ordering::Relaxed)),
447 type_id: value.type_id,
448 }
449 }
450}
451
452impl<T> InnerData<T> for RoData<T>
453where
454 T: ?Sized,
455{
456 fn data(&self) -> RwLockReadGuard<'_, T> {
457 self.data.read()
458 }
459
460 fn try_data(&self) -> Option<RwLockReadGuard<'_, T>> {
461 self.data.try_read()
462 }
463
464 fn cur_state(&self) -> &Arc<AtomicUsize> {
465 &self.cur_state
466 }
467
468 fn read_state(&self) -> &AtomicUsize {
469 &self.read_state
470 }
471}
472
473// NOTE: Each `RoState` of a given state will have its own internal
474// update counter.
475impl<T> Clone for RoData<T>
476where
477 T: ?Sized,
478{
479 fn clone(&self) -> Self {
480 RoData {
481 data: self.data.clone(),
482 cur_state: self.cur_state.clone(),
483 read_state: AtomicUsize::new(self.cur_state.load(Ordering::Relaxed)),
484 type_id: self.type_id,
485 }
486 }
487}
488
489impl<T: ?Sized> Data<T> for RoData<T> {
490 fn to_ro(&self) -> RoData<T> {
491 self.clone()
492 }
493
494 fn has_changed(&self) -> bool {
495 self.has_changed()
496 }
497}