reactive_graph/owner/
storage.rs

1use super::arena::{Arena, NodeId};
2use send_wrapper::SendWrapper;
3
4/// A trait for borrowing and taking data.
5pub trait StorageAccess<T> {
6    /// Borrows the value.
7    fn as_borrowed(&self) -> &T;
8
9    /// Takes the value.
10    fn into_taken(self) -> T;
11}
12
13impl<T> StorageAccess<T> for T {
14    fn as_borrowed(&self) -> &T {
15        self
16    }
17
18    fn into_taken(self) -> T {
19        self
20    }
21}
22
23impl<T> StorageAccess<T> for SendWrapper<T> {
24    fn as_borrowed(&self) -> &T {
25        self
26    }
27
28    fn into_taken(self) -> T {
29        self.take()
30    }
31}
32
33/// A way of storing an [`ArenaItem`](super::arena_item::ArenaItem), either as itself or with a wrapper to make it threadsafe.
34///
35/// This exists because all items stored in the arena must be `Send + Sync`, but in single-threaded
36/// environments you might want or need to use thread-unsafe types.
37pub trait Storage<T>: Send + Sync + 'static {
38    /// The type being stored, once it has been wrapped.
39    type Wrapped: StorageAccess<T> + Send + Sync + 'static;
40
41    /// Adds any needed wrapper to the type.
42    fn wrap(value: T) -> Self::Wrapped;
43
44    /// Applies the given function to the stored value, if it exists and can be accessed from this
45    /// thread.
46    fn try_with<U>(node: NodeId, fun: impl FnOnce(&T) -> U) -> Option<U>;
47
48    /// Applies the given function to a mutable reference to the stored value, if it exists and can be accessed from this
49    /// thread.
50    fn try_with_mut<U>(
51        node: NodeId,
52        fun: impl FnOnce(&mut T) -> U,
53    ) -> Option<U>;
54
55    /// Sets a new value for the stored value. If it has been disposed, returns `Some(T)`.
56    fn try_set(node: NodeId, value: T) -> Option<T>;
57
58    /// Takes an item from the arena if it exists and can be accessed from this thread.
59    /// If it cannot be casted, it will still be removed from the arena.
60    fn take(node: NodeId) -> Option<T>;
61}
62
63/// A form of [`Storage`] that stores the type as itself, with no wrapper.
64#[derive(Debug, Copy, Clone)]
65pub struct SyncStorage;
66
67impl<T> Storage<T> for SyncStorage
68where
69    T: Send + Sync + 'static,
70{
71    type Wrapped = T;
72
73    #[inline(always)]
74    fn wrap(value: T) -> Self::Wrapped {
75        value
76    }
77
78    fn try_with<U>(node: NodeId, fun: impl FnOnce(&T) -> U) -> Option<U> {
79        Arena::try_with(|arena| {
80            let m = arena.get(node);
81            m.and_then(|n| n.downcast_ref::<T>()).map(fun)
82        })
83        .flatten()
84    }
85
86    fn try_with_mut<U>(
87        node: NodeId,
88        fun: impl FnOnce(&mut T) -> U,
89    ) -> Option<U> {
90        Arena::try_with_mut(|arena| {
91            let m = arena.get_mut(node);
92            m.and_then(|n| n.downcast_mut::<T>()).map(fun)
93        })
94        .flatten()
95    }
96
97    fn try_set(node: NodeId, value: T) -> Option<T> {
98        Arena::try_with_mut(|arena| {
99            let m = arena.get_mut(node);
100            match m.and_then(|n| n.downcast_mut::<T>()) {
101                Some(inner) => {
102                    *inner = value;
103                    None
104                }
105                None => Some(value),
106            }
107        })
108        .flatten()
109    }
110
111    fn take(node: NodeId) -> Option<T> {
112        Arena::with_mut(|arena| {
113            let m = arena.remove(node)?;
114            match m.downcast::<T>() {
115                Ok(inner) => Some(*inner),
116                Err(_) => None,
117            }
118        })
119    }
120}
121
122/// A form of [`Storage`] that stores the type with a wrapper that makes it `Send + Sync`, but only
123/// allows it to be accessed from the thread on which it was created.
124#[derive(Debug, Copy, Clone)]
125pub struct LocalStorage;
126
127impl<T> Storage<T> for LocalStorage
128where
129    T: 'static,
130{
131    type Wrapped = SendWrapper<T>;
132
133    fn wrap(value: T) -> Self::Wrapped {
134        SendWrapper::new(value)
135    }
136
137    fn try_with<U>(node: NodeId, fun: impl FnOnce(&T) -> U) -> Option<U> {
138        Arena::with(|arena| {
139            let m = arena.get(node);
140            m.and_then(|n| n.downcast_ref::<SendWrapper<T>>())
141                .map(|inner| fun(inner))
142        })
143    }
144
145    fn try_with_mut<U>(
146        node: NodeId,
147        fun: impl FnOnce(&mut T) -> U,
148    ) -> Option<U> {
149        Arena::with_mut(|arena| {
150            let m = arena.get_mut(node);
151            m.and_then(|n| n.downcast_mut::<SendWrapper<T>>())
152                .map(|inner| fun(&mut *inner))
153        })
154    }
155
156    fn try_set(node: NodeId, value: T) -> Option<T> {
157        Arena::with_mut(|arena| {
158            let m = arena.get_mut(node);
159            match m.and_then(|n| n.downcast_mut::<SendWrapper<T>>()) {
160                Some(inner) => {
161                    *inner = SendWrapper::new(value);
162                    None
163                }
164                None => Some(value),
165            }
166        })
167    }
168
169    fn take(node: NodeId) -> Option<T> {
170        Arena::with_mut(|arena| {
171            let m = arena.remove(node)?;
172            match m.downcast::<SendWrapper<T>>() {
173                Ok(inner) => Some(inner.take()),
174                Err(_) => None,
175            }
176        })
177    }
178}