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}