zng_state_map/
lib.rs

1#![doc(html_favicon_url = "https://raw.githubusercontent.com/zng-ui/zng/main/examples/image/res/zng-logo-icon.png")]
2#![doc(html_logo_url = "https://raw.githubusercontent.com/zng-ui/zng/main/examples/image/res/zng-logo.png")]
3//!
4//! Hash-map of type erased values, useful for storing assorted dynamic state.
5//!
6//! # Crate
7//!
8#![doc = include_str!(concat!("../", std::env!("CARGO_PKG_README")))]
9#![warn(unused_extern_crates)]
10#![warn(missing_docs)]
11
12use std::{any::Any, fmt, marker::PhantomData};
13
14use zng_unique_id::unique_id_64;
15
16pub use zng_unique_id::static_id;
17
18/// Represents a type that can be a [`StateId`] value.
19///
20/// # Trait Alias
21///
22/// This trait is used like a type alias for traits and is
23/// already implemented for all types it applies to.
24#[diagnostic::on_unimplemented(note = "`StateValue` is implemented for all `T: Any + Send + Sync`")]
25pub trait StateValue: Any + Send + Sync {}
26impl<T: Any + Send + Sync> StateValue for T {}
27
28unique_id_64! {
29    /// Unique identifier of a value in a state map.
30    ///
31    /// The type `T` is the value type.
32    ///
33    /// ```
34    /// # use zng_state_map::*;
35    /// static_id! {
36    ///     static ref FOO_ID: StateId<bool>;
37    /// }
38    ///
39    /// # fn demo() {
40    /// let mut owned_state = OwnedStateMap::<()>::default();
41    /// let foo = owned_state.borrow_mut().set(*FOO_ID, true);
42    /// # ; }
43    /// ```
44    pub struct StateId<T: (StateValue)>;
45}
46zng_unique_id::impl_unique_id_bytemuck!(StateId<T: (StateValue)>);
47impl<T: StateValue> fmt::Debug for StateId<T> {
48    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49        #[cfg(debug_assertions)]
50        let t = pretty_type_name::pretty_type_name::<T>();
51        #[cfg(not(debug_assertions))]
52        let t = "$T";
53
54        if f.alternate() {
55            writeln!(f, "StateId<{t} {{")?;
56            writeln!(f, "   id: {},", self.get())?;
57            writeln!(f, "   sequential: {}", self.sequential())?;
58            writeln!(f, "}}")
59        } else {
60            write!(f, "StateId<{t}>({})", self.sequential())
61        }
62    }
63}
64
65/// Read-only state map.
66///
67/// The `U` parameter is tag type that represents the map's *context*.
68pub struct StateMapRef<'a, U>(&'a state_map::StateMap, PhantomData<U>);
69impl<U> Clone for StateMapRef<'_, U> {
70    fn clone(&self) -> Self {
71        *self
72    }
73}
74impl<U> Copy for StateMapRef<'_, U> {}
75impl<U> fmt::Debug for StateMapRef<'_, U> {
76    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77        write!(
78            f,
79            "StateMapRef<{}>({} entries);",
80            pretty_type_name::pretty_type_name::<U>(),
81            self.0.len()
82        )
83    }
84}
85impl<U> StateMapRef<'static, U> {
86    /// Static empty map.
87    pub fn empty() -> Self {
88        static EMPTY: state_map::StateMap = state_map::StateMap::new();
89        Self(&EMPTY, PhantomData)
90    }
91}
92impl<'a, U> StateMapRef<'a, U> {
93    /// Gets if the ID is set in this map.
94    pub fn contains<T: StateValue>(self, id: impl Into<StateId<T>>) -> bool {
95        self.0.contains(id.into())
96    }
97
98    /// Reference the ID's value set in this map.
99    pub fn get<T: StateValue>(self, id: impl Into<StateId<T>>) -> Option<&'a T> {
100        self.0.get(id.into())
101    }
102
103    /// Copy the ID's value set in this map.
104    pub fn copy<T: StateValue + Copy>(self, id: impl Into<StateId<T>>) -> Option<T> {
105        self.get(id.into()).copied()
106    }
107
108    /// Clone the ID's value set in this map.
109    pub fn get_clone<T: StateValue + Clone>(self, id: impl Into<StateId<T>>) -> Option<T> {
110        self.get(id.into()).cloned()
111    }
112
113    /// Reference the ID's value set in this map or panics if the key is not set.
114    pub fn req<T: StateValue>(self, id: impl Into<StateId<T>>) -> &'a T {
115        self.0.req(id.into())
116    }
117
118    /// Gets if a state ID without value is set.
119    pub fn flagged(self, id: impl Into<StateId<()>>) -> bool {
120        self.0.flagged(id.into())
121    }
122
123    /// If no state is set.
124    pub fn is_empty(self) -> bool {
125        self.0.is_empty()
126    }
127
128    /// Returns `true` if self and other reference the same map.
129    pub fn ptr_eq(self, other: Self) -> bool {
130        std::ptr::eq(self.0, other.0)
131    }
132}
133
134/// Mutable state map.
135///
136/// The `U` parameter is tag type that represents the map's *context*.
137pub struct StateMapMut<'a, U>(&'a mut state_map::StateMap, PhantomData<U>);
138impl<U> fmt::Debug for StateMapMut<'_, U> {
139    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140        write!(f, "StateMapMut<{}>({} entries);", std::any::type_name::<U>(), self.0.len())
141    }
142}
143impl<'a, U> StateMapMut<'a, U> {
144    /// Gets if the ID is set in this map.
145    pub fn contains<T: StateValue>(&self, id: impl Into<StateId<T>>) -> bool {
146        self.0.contains(id.into())
147    }
148
149    /// Reference the ID's value set in this map.
150    pub fn get<T: StateValue>(&self, id: impl Into<StateId<T>>) -> Option<&T> {
151        self.0.get(id.into())
152    }
153
154    /// Consume the mutable reference to the map and returns a reference to the value in the parent lifetime `'a`.
155    pub fn into_get<T: StateValue>(self, id: impl Into<StateId<T>>) -> Option<&'a T> {
156        self.0.get(id.into())
157    }
158
159    /// Copy the ID's value set in this map.
160    pub fn copy<T: StateValue + Copy>(&self, id: impl Into<StateId<T>>) -> Option<T> {
161        self.get(id.into()).copied()
162    }
163
164    /// Clone the ID's value set in this map.
165    pub fn get_clone<T: StateValue + Clone>(&self, id: impl Into<StateId<T>>) -> Option<T> {
166        self.get(id).cloned()
167    }
168
169    /// Reference the ID's value set in this map or panics if the ID is not set.
170    pub fn req<T: StateValue>(&self, id: impl Into<StateId<T>>) -> &T {
171        self.0.req(id.into())
172    }
173
174    /// Consume the mutable reference to the map and returns a reference to the value in the parent lifetime `'a`.
175    pub fn into_req<T: StateValue>(self, id: impl Into<StateId<T>>) -> &'a T {
176        self.0.req(id.into())
177    }
178
179    /// Gets if a state ID without value is set.
180    pub fn flagged(&self, id: impl Into<StateId<()>>) -> bool {
181        self.0.flagged(id.into())
182    }
183
184    /// If no state is set.
185    pub fn is_empty(&self) -> bool {
186        self.0.is_empty()
187    }
188
189    /// Set the ID's `value`.
190    pub fn set<T: StateValue>(&mut self, id: impl Into<StateId<T>>, value: impl Into<T>) -> Option<T> {
191        self.0.set(id.into(), value.into())
192    }
193
194    /// Mutable borrow the ID's value set in this map.
195    pub fn get_mut<T: StateValue>(&mut self, id: impl Into<StateId<T>>) -> Option<&mut T> {
196        self.0.get_mut(id.into())
197    }
198
199    /// Consume the mutable reference to the map and mutable borrow the ID's value in the parent lifetime `'a`.
200    pub fn into_get_mut<T: StateValue>(self, id: impl Into<StateId<T>>) -> Option<&'a mut T> {
201        self.0.get_mut(id.into())
202    }
203
204    /// Mutable borrow the key value set in this map or panics if the ID is not set.
205    pub fn req_mut<T: StateValue>(&mut self, id: impl Into<StateId<T>>) -> &mut T {
206        self.0.req_mut(id.into())
207    }
208
209    /// Consume the mutable reference to the map and mutable borrow the ID value in the parent lifetime `'a`.
210    pub fn into_req_mut<T: StateValue>(self, id: impl Into<StateId<T>>) -> &'a mut T {
211        self.0.req_mut(id.into())
212    }
213
214    /// Gets the given ID's corresponding entry in the map for in-place manipulation.
215    pub fn entry<T: StateValue>(&mut self, id: impl Into<StateId<T>>) -> state_map::StateMapEntry<T> {
216        self.0.entry(id.into())
217    }
218
219    /// Consume the mutable reference to the map and returns a given ID's corresponding entry in the map with the parent lifetime `'a`.
220    pub fn into_entry<T: StateValue>(self, id: impl Into<StateId<T>>) -> state_map::StateMapEntry<'a, T> {
221        self.0.entry(id.into())
222    }
223
224    /// Sets a state ID without value.
225    ///
226    /// Returns if the state ID was already flagged.
227    pub fn flag(&mut self, id: impl Into<StateId<()>>) -> bool {
228        self.0.flag(id.into())
229    }
230
231    /// Reborrow the mutable reference.
232    pub fn reborrow(&mut self) -> StateMapMut<U> {
233        StateMapMut(self.0, PhantomData)
234    }
235
236    /// Reborrow the reference as read-only.
237    pub fn as_ref(&self) -> StateMapRef<U> {
238        StateMapRef(self.0, PhantomData)
239    }
240}
241
242/// Private state map.
243///
244/// The owner of a state map has full access including to the `remove` and `clear` methods that are not
245/// provided in the [`StateMapMut`] type. All mutable references borrowed from this map are also protected to
246/// not allow replacement.
247///
248/// The `U` parameter is tag type that represents the map's *context*.
249pub struct OwnedStateMap<U>(state_map::StateMap, PhantomData<U>);
250impl<U> fmt::Debug for OwnedStateMap<U> {
251    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
252        write!(
253            f,
254            "OwnedStateMap<{}>({} entries);",
255            pretty_type_name::pretty_type_name::<U>(),
256            self.0.len()
257        )
258    }
259}
260impl<U> Default for OwnedStateMap<U> {
261    fn default() -> Self {
262        Self::new()
263    }
264}
265impl<U> OwnedStateMap<U> {
266    /// New default, empty.
267    pub const fn new() -> Self {
268        OwnedStateMap(state_map::StateMap::new(), PhantomData)
269    }
270
271    /// Remove the key.
272    pub fn remove<T: StateValue>(&mut self, id: impl Into<StateId<T>>) -> Option<T> {
273        self.0.remove(id.into())
274    }
275
276    /// Removes all entries.
277    pub fn clear(&mut self) {
278        self.0.clear()
279    }
280
281    /// Create tagged read-only reference to the map.
282    pub fn borrow(&self) -> StateMapRef<U> {
283        StateMapRef(&self.0, PhantomData)
284    }
285
286    /// Crate tagged mutable reference to the map.
287    pub fn borrow_mut(&mut self) -> StateMapMut<U> {
288        StateMapMut(&mut self.0, PhantomData)
289    }
290}
291
292/// State map helper types.
293pub mod state_map {
294    use std::any::Any;
295
296    use zng_unique_id::*;
297
298    use super::*;
299
300    type AnyMap = IdMap<u64, Box<dyn Any + Send + Sync>>;
301
302    pub(super) struct StateMap {
303        map: AnyMap,
304    }
305    impl StateMap {
306        pub(super) const fn new() -> Self {
307            StateMap { map: AnyMap::new() }
308        }
309
310        pub(super) fn len(&self) -> usize {
311            self.map.len()
312        }
313
314        pub(super) fn remove<T: StateValue>(&mut self, id: StateId<T>) -> Option<T> {
315            self.map.remove(&id.get()).map(|a| *a.downcast().unwrap())
316        }
317
318        pub(super) fn clear(&mut self) {
319            self.map.clear()
320        }
321
322        pub fn set<T: StateValue>(&mut self, id: StateId<T>, value: T) -> Option<T> {
323            self.map.insert(id.get(), Box::new(value)).map(|any| *any.downcast().unwrap())
324        }
325
326        pub fn contains<T: StateValue>(&self, id: StateId<T>) -> bool {
327            self.map.contains_key(&id.get())
328        }
329
330        pub fn get<T: StateValue>(&self, id: StateId<T>) -> Option<&T> {
331            self.map.get(&id.get()).map(|any| any.downcast_ref().unwrap())
332        }
333
334        pub fn get_mut<T: StateValue>(&mut self, id: StateId<T>) -> Option<&mut T> {
335            self.map.get_mut(&id.get()).map(|any| any.downcast_mut().unwrap())
336        }
337
338        pub fn req<T: StateValue>(&self, id: StateId<T>) -> &T {
339            self.get(id).unwrap_or_else(move || panic!("expected `{id:?}` in state map"))
340        }
341
342        pub fn req_mut<T: StateValue>(&mut self, id: StateId<T>) -> &mut T {
343            self.get_mut(id).unwrap_or_else(move || panic!("expected `{id:?}` in state map"))
344        }
345
346        pub fn entry<T: StateValue>(&mut self, id: StateId<T>) -> StateMapEntry<T> {
347            match self.map.entry(id.get()) {
348                IdEntry::Occupied(e) => StateMapEntry::Occupied(OccupiedStateMapEntry {
349                    _type: PhantomData,
350                    entry: e,
351                }),
352                IdEntry::Vacant(e) => StateMapEntry::Vacant(VacantStateMapEntry {
353                    _type: PhantomData,
354                    entry: e,
355                }),
356            }
357        }
358
359        pub fn flag(&mut self, id: StateId<()>) -> bool {
360            self.set(id, ()).is_some()
361        }
362
363        pub fn flagged(&self, id: StateId<()>) -> bool {
364            self.map.contains_key(&id.get())
365        }
366
367        pub fn is_empty(&self) -> bool {
368            self.map.is_empty()
369        }
370    }
371
372    /// A view into an occupied entry in a state map.
373    ///
374    /// This struct is part of [`StateMapEntry`].
375    pub struct OccupiedStateMapEntry<'a, T: StateValue> {
376        _type: PhantomData<T>,
377        entry: IdOccupiedEntry<'a, u64, Box<dyn Any + Send + Sync>>,
378    }
379    impl<'a, T: StateValue> OccupiedStateMapEntry<'a, T> {
380        /// Gets a reference to the value in the entry.
381        pub fn get(&self) -> &T {
382            self.entry.get().downcast_ref().unwrap()
383        }
384
385        /// Gets a mutable reference to the value in the entry.
386        ///
387        /// See also [`into_mut`] to get a reference tied to the lifetime of the map directly.
388        ///
389        /// [`into_mut`]: Self::into_mut
390        pub fn get_mut(&mut self) -> &mut T {
391            self.entry.get_mut().downcast_mut().unwrap()
392        }
393
394        /// Converts the entry into a mutable reference to the value in the entry with a lifetime bound to the map itself.
395        pub fn into_mut(self) -> &'a mut T {
396            self.entry.into_mut().downcast_mut().unwrap()
397        }
398
399        /// Sets the value of the entry, and returns the entry’s old value.
400        pub fn insert(&mut self, value: T) -> T {
401            *self.entry.insert(Box::new(value)).downcast().unwrap()
402        }
403
404        /// Takes the value out of the entry, and returns it.
405        pub fn remove(self) -> T {
406            *self.entry.remove().downcast().unwrap()
407        }
408    }
409    impl<T: StateValue + fmt::Debug> fmt::Debug for OccupiedStateMapEntry<'_, T> {
410        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
411            let id = StateId::<T>::from_raw(*self.entry.key());
412            f.debug_struct("OccupiedStateMapEntry")
413                .field("key", &id)
414                .field("value", self.get())
415                .finish()
416        }
417    }
418
419    /// A view into a vacant entry in a state map.
420    ///
421    /// This struct is part of [`StateMapEntry`].
422    pub struct VacantStateMapEntry<'a, T: StateValue> {
423        _type: PhantomData<T>,
424        entry: IdVacantEntry<'a, u64, Box<dyn Any + Send + Sync>>,
425    }
426    impl<'a, T: StateValue> VacantStateMapEntry<'a, T> {
427        /// Sets the value of the entry and returns a mutable reference to it.
428        pub fn insert(self, value: impl Into<T>) -> &'a mut T {
429            self.entry.insert(Box::new(value.into())).downcast_mut().unwrap()
430        }
431    }
432    impl<T: StateValue + fmt::Debug> fmt::Debug for VacantStateMapEntry<'_, T> {
433        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
434            let id = StateId::<T>::from_raw(*self.entry.key());
435            f.debug_struct("VacantStateMapEntry").field("key", &id).finish_non_exhaustive()
436        }
437    }
438
439    /// A view into a single entry in a state map, which may either be vacant or occupied.
440    ///
441    /// This `enum` is constructed from the [`entry`] method on [`StateMapMut`].
442    ///
443    /// [`entry`]: StateMapMut::entry
444    pub enum StateMapEntry<'a, T: StateValue> {
445        /// An occupied entry.
446        Occupied(OccupiedStateMapEntry<'a, T>),
447        /// A vacant entry.
448        Vacant(VacantStateMapEntry<'a, T>),
449    }
450    impl<'a, T: StateValue> StateMapEntry<'a, T> {
451        /// Ensures a value is in the entry by inserting the default if empty, and
452        /// returns a mutable reference to the value in the entry.
453        pub fn or_insert(self, default: impl Into<T>) -> &'a mut T {
454            match self {
455                StateMapEntry::Occupied(e) => e.into_mut(),
456                StateMapEntry::Vacant(e) => e.insert(default),
457            }
458        }
459
460        /// Ensures a value is in the entry by inserting the result of the
461        /// default function if empty, and returns a mutable reference to the value in the entry.
462        pub fn or_insert_with<F: FnOnce() -> T>(self, default: F) -> &'a mut T {
463            match self {
464                StateMapEntry::Occupied(e) => e.into_mut(),
465                StateMapEntry::Vacant(e) => e.insert(default()),
466            }
467        }
468
469        /// Provides in-place mutable access to an occupied entry before any potential inserts into the map.
470        pub fn and_modify<F: FnOnce(&mut T)>(mut self, f: F) -> Self {
471            if let StateMapEntry::Occupied(e) = &mut self {
472                f(e.get_mut())
473            }
474            self
475        }
476    }
477    impl<'a, T: StateValue> StateMapEntry<'a, T>
478    where
479        T: Default,
480    {
481        /// Ensures a value is in the entry by inserting the default value if empty,
482        /// and returns a mutable reference to the value in the entry.
483        pub fn or_default(self) -> &'a mut T {
484            self.or_insert_with(Default::default)
485        }
486    }
487    impl<T: StateValue + fmt::Debug> fmt::Debug for StateMapEntry<'_, T> {
488        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
489            match self {
490                Self::Occupied(arg0) => f.debug_tuple("Occupied").field(arg0).finish(),
491                Self::Vacant(arg0) => f.debug_tuple("Vacant").field(arg0).finish(),
492            }
493        }
494    }
495}