Seregon/StratoSDK

StratoSDK is a framework with a declarative approach similar to Flutter/React, written and designed entirely for Rust.

Rust/27.3 KB/No license
crates/strato-ui-core/src/core/autotracking/tracked.rs
1use super::{track_read, track_update};
2use std::marker::PhantomData;
3use std::ops::{Deref, DerefMut};
4use std::sync::atomic::{AtomicUsize, Ordering};
5 
6/// An autotracked value type
7///
8/// This implements `Deref` and `DerefMut` for the underlying type `T`, so in most cases can be
9/// used as the underlying type without any code changes.
10///
11/// When the underlying data is read or updated, the Autotracking system will be notified so that
12/// it can manage Views' dependencies on `Tracked` values and automatically create invalidations
13/// (effectively calls to `ctx.notify()`) for the appropriate Views.
14///
15/// Note: Since the autotracking system only works on the main thread, `Tracked` does not implement
16/// `Send` or `Sync` and so cannot be shared between threads.
17#[derive(Debug)]
18pub struct Tracked<T> {
19 id: TrackedId,
20 inner: T,
21 _no_send: PhantomData<*const u8>,
22}
23 
24impl<T> Tracked<T> {
25 pub fn new(value: T) -> Self {
26 Tracked {
27 id: TrackedId::next(),
28 inner: value,
29 _no_send: PhantomData,
30 }
31 }
32}
33 
34impl<T> From<T> for Tracked<T> {
35 fn from(value: T) -> Self {
36 Self::new(value)
37 }
38}
39 
40impl<T> Deref for Tracked<T> {
41 type Target = T;
42 
43 fn deref(&self) -> &T {
44 track_read(self.id);
45 &self.inner
46 }
47}
48 
49impl<T> DerefMut for Tracked<T> {
50 fn deref_mut(&mut self) -> &mut Self::Target {
51 track_update(self.id);
52 &mut self.inner
53 }
54}
55 
56impl<T> Default for Tracked<T>
57where
58 T: Default,
59{
60 fn default() -> Self {
61 Tracked {
62 id: TrackedId::next(),
63 inner: T::default(),
64 _no_send: PhantomData,
65 }
66 }
67}
68 
69/// Autoincrementing identifier used to track a given `Tracked` value
70#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
71pub(super) struct TrackedId(usize);
72 
73impl TrackedId {
74 /// Generate the next unique `TrackedId` value
75 fn next() -> Self {
76 static TRACKED_ID: AtomicUsize = AtomicUsize::new(0);
77 let next = TRACKED_ID.fetch_add(1, Ordering::Relaxed);
78 TrackedId(next)
79 }
80}
81