Skip to main content

node_flow/context/storage/shared_storage/
design.rs

1use std::ops::{Deref, DerefMut};
2
3/// Provides type-based shared storage for concurrent environments.
4///
5/// `SharedStorage` is a type-based shared storage.
6/// Items in this storage are be shared with all other branches.
7/// It allows storing and retrieving values by their type.
8/// Each type `T` has at most **one instance** stored at a time.
9///
10/// This trait is designed for use in systems that require shared, concurrent
11/// access to arbitrary state.
12///
13/// Unlike [`LocalStorage`](crate::context::storage::LocalStorage) implementors of this trait
14/// are able to safely manage data shared across branches.
15///
16/// # Design
17///
18/// Implementations are expected to handle concurrency correctly (for example via
19/// `RwLock`, `Mutex`, or some lock-free data structure) and to return appropriate
20/// guard objects implementing [`Deref`] or [`DerefMut`] for temporary access.
21///
22/// # Examples
23/// ```
24/// use std::future::Future;
25/// use std::ops::{Deref, DerefMut};
26/// use node_flow::context::storage::SharedStorage;
27///
28/// // Always empty storage (example only)
29/// struct ExampleSharedStorage;
30/// // Guard for get and get_mut
31/// struct Guard<T>(T);
32/// impl<T> Deref for Guard<T> // ...
33/// # {
34/// #     type Target = T;
35/// #
36/// #     fn deref(&self) -> &Self::Target {
37/// #         unreachable!()
38/// #     }
39/// # }
40/// impl<T> DerefMut for Guard<T> // ...
41/// # {
42/// #     fn deref_mut(&mut self) -> &mut Self::Target {
43/// #         unreachable!()
44/// #     }
45/// # }
46///
47/// impl SharedStorage for ExampleSharedStorage {
48///     fn get<T>(&self) -> impl Future<Output = Option<impl Deref<Target = T>>> + Send {
49///         async { None::<Guard<T>> }
50///     }
51///
52///     fn get_mut<T>(&mut self) -> impl Future<Output = Option<impl DerefMut<Target = T>>> + Send {
53///         async { None::<Guard<T>> }
54///     }
55///
56///     fn insert<T>(&mut self, _val: T) -> impl Future<Output = Option<T>> + Send {
57///         async { None }
58///     }
59///
60///     fn insert_with_if_absent<T, E>(
61///         &self,
62///         fut: impl Future<Output = Result<T, E>> + Send,
63///     ) -> impl Future<Output = Result<(), E>> + Send {
64///         async {
65///             let _ = fut.await;
66///             Ok(())
67///         }
68///     }
69///
70///     fn remove<T>(&mut self) -> impl Future<Output = Option<T>> + Send {
71///         async { None }
72///     }
73/// }
74/// ```
75pub trait SharedStorage {
76    /// Gets reference of a value with type `T` from storage if it is present.
77    ///
78    /// # Examples
79    /// ```
80    /// # tokio::runtime::Builder::new_current_thread()
81    /// #     .enable_all()
82    /// #     .build()
83    /// #     .unwrap()
84    /// #     .block_on(async {
85    /// # use node_flow::context::storage::{SharedStorage, shared_storage::SharedStorageImpl};
86    /// # type ExampleStorage = SharedStorageImpl;
87    /// use std::ops::Deref;
88    /// #[derive(Debug, PartialEq, Eq)]
89    /// struct ExampleValue(u8);
90    /// let mut storage = ExampleStorage::new();
91    ///
92    /// let _ = storage.insert(ExampleValue(5u8)).await;
93    /// let guard = storage.get().await;
94    /// let result: Option<&ExampleValue> = guard.as_deref();
95    /// assert_eq!(result, Some(&ExampleValue(5u8)));
96    /// let guard = storage.get().await;
97    /// let result: Option<&u16> = guard.as_deref();
98    /// assert_eq!(result, None);
99    /// # });
100    /// ```
101    fn get<T>(&self) -> impl Future<Output = Option<impl Deref<Target = T>>> + Send
102    where
103        T: 'static;
104
105    /// Gets mutable reference of a value with type `T` from storage if it is present.
106    ///
107    /// # Examples
108    /// ```
109    /// # tokio::runtime::Builder::new_current_thread()
110    /// #     .enable_all()
111    /// #     .build()
112    /// #     .unwrap()
113    /// #     .block_on(async {
114    /// # use node_flow::context::storage::{SharedStorage, shared_storage::SharedStorageImpl};
115    /// # type ExampleStorage = SharedStorageImpl;
116    /// use std::ops::Deref;
117    /// #[derive(Debug, PartialEq, Eq)]
118    /// struct ExampleValue(u8);
119    /// let mut storage = ExampleStorage::new();
120    ///
121    /// let _ = storage.insert(ExampleValue(5u8)).await;
122    /// if let Some(mut val) = storage.get_mut::<ExampleValue>().await {
123    ///     val.0 = 15u8;
124    /// }
125    /// let guard = storage.get().await;
126    /// let result: Option<&ExampleValue> = guard.as_deref();
127    /// assert_eq!(result, Some(&ExampleValue(15u8)));
128    /// # });
129    /// ```
130    fn get_mut<T>(&mut self) -> impl Future<Output = Option<impl DerefMut<Target = T>>> + Send
131    where
132        T: 'static;
133
134    /// Inserts value with type `T` to storage and returns the value that was there previously if it was there.
135    ///
136    /// # Examples
137    /// ```
138    /// # tokio::runtime::Builder::new_current_thread()
139    /// #     .enable_all()
140    /// #     .build()
141    /// #     .unwrap()
142    /// #     .block_on(async {
143    /// # use node_flow::context::storage::{SharedStorage, shared_storage::SharedStorageImpl};
144    /// # type ExampleStorage = SharedStorageImpl;
145    /// use std::ops::Deref;
146    /// #[derive(Debug, PartialEq, Eq)]
147    /// struct ExampleValue(u8);
148    /// let mut storage = ExampleStorage::new();
149    ///
150    /// let result = storage.insert(ExampleValue(5u8)).await;
151    /// assert_eq!(result, None);
152    /// let _ = storage.insert(ExampleValue(15u8)).await;
153    /// let result = storage.insert(ExampleValue(25u8)).await;
154    /// assert_eq!(result, Some(ExampleValue(15u8)));
155    /// let guard = storage.get().await;
156    /// let result: Option<&ExampleValue> = guard.as_deref();
157    /// assert_eq!(result, Some(&ExampleValue(25u8)));
158    /// # });
159    /// ```
160    fn insert<T>(&mut self, val: T) -> impl Future<Output = Option<T>> + Send
161    where
162        T: Send + Sync + 'static;
163
164    /// Inserts value with type `T` to storage if it doesn't contain it.
165    ///
166    /// # Examples
167    /// ```
168    /// # tokio::runtime::Builder::new_current_thread()
169    /// #     .enable_all()
170    /// #     .build()
171    /// #     .unwrap()
172    /// #     .block_on(async {
173    /// # use node_flow::context::storage::{SharedStorage, shared_storage::SharedStorageImpl};
174    /// # type ExampleStorage = SharedStorageImpl;
175    /// use std::ops::Deref;
176    /// #[derive(Debug, PartialEq, Eq)]
177    /// struct ExampleValue(u8);
178    /// let mut storage = ExampleStorage::new();
179    ///
180    /// storage.insert_with_if_absent(async { Ok::<_, ()>(ExampleValue(5u8)) }).await.unwrap();
181    /// storage.insert_with_if_absent(async { Ok::<_, ()>(ExampleValue(15u8)) }).await.unwrap();
182    /// let result = storage.remove().await;
183    /// assert_eq!(result, Some(ExampleValue(5u8)));
184    /// storage.insert_with_if_absent(async { Ok::<_, ()>(ExampleValue(25u8)) }).await.unwrap();
185    /// let result = storage.remove().await;
186    /// assert_eq!(result, Some(ExampleValue(25u8)));
187    /// # });
188    /// ```
189    fn insert_with_if_absent<T, E>(
190        &self,
191        fut: impl Future<Output = Result<T, E>> + Send,
192    ) -> impl Future<Output = Result<(), E>> + Send
193    where
194        T: Send + Sync + 'static,
195        E: Send;
196
197    /// Removes and returns value with type `T` from storage if it is present.
198    ///
199    /// # Examples
200    /// ```
201    /// # tokio::runtime::Builder::new_current_thread()
202    /// #     .enable_all()
203    /// #     .build()
204    /// #     .unwrap()
205    /// #     .block_on(async {
206    /// # use node_flow::context::storage::{SharedStorage, shared_storage::SharedStorageImpl};
207    /// # type ExampleStorage = SharedStorageImpl;
208    /// use std::ops::Deref;
209    /// #[derive(Debug, PartialEq, Eq)]
210    /// struct ExampleValue(u8);
211    /// let mut storage = ExampleStorage::new();
212    ///
213    /// let result = storage.insert(ExampleValue(5u8)).await;
214    /// assert_eq!(result, None);
215    /// let result = storage.remove().await;
216    /// assert_eq!(result, Some(ExampleValue(5u8)));
217    /// let result = storage.remove::<ExampleValue>().await;
218    /// assert_eq!(result, None);
219    /// # });
220    /// ```
221    fn remove<T>(&mut self) -> impl Future<Output = Option<T>> + Send
222    where
223        T: 'static;
224}