x_bow/
store.rs

1use std::{
2    cell::{Ref, RefCell, RefMut},
3    fmt::Debug,
4};
5
6use crate::{guarantee::PathExtGuaranteed, path::Path, trackable::Trackable, wakers::StoreWakers};
7
8/// A store is where your "state" data lives. It is in essence a big [RefCell].
9/// There are also supporting mechanisms to enable subscriptions and
10/// mutation notifications.
11pub struct Store<S> {
12    data: RefCell<S>,
13    wakers: RefCell<StoreWakers>,
14}
15
16impl<S> Store<S> {
17    /// Create a new store with the given data.
18    /// This puts the data in a [RefCell] and set up all the change listening
19    /// mechanisms.
20    pub fn new(data: S) -> Self {
21        Self {
22            data: RefCell::new(data),
23            wakers: RefCell::new(StoreWakers::new()),
24        }
25    }
26}
27impl<S: Trackable> Store<S> {
28    /// Use this method to create paths to different pieces of your state.
29    ///
30    /// ```
31    /// # use x_bow::{Trackable, Store, PathExt};
32    ///
33    /// #[derive(Trackable)]
34    /// #[track(deep)]
35    /// struct MyStruct<T> {
36    ///     field_1: T,
37    ///     field_2: u64
38    /// }
39    /// let store = Store::new(MyStruct {
40    ///     field_1: MyStruct {
41    ///         field_1: String::new(),
42    ///         field_2: 123
43    ///     },
44    ///     field_2: 456
45    /// });
46    ///
47    /// // path to the root `MyStruct` itself
48    /// let path = store.build_path();
49    ///
50    /// // path to `field_1` in the root `MyStruct`
51    /// let path = store.build_path().field_1();
52    ///
53    /// // path to `field_2` in the root `MyStruct`
54    /// let path = store.build_path().field_2();
55    ///
56    /// // path root -> field_1 -> field_1
57    /// let path = store.build_path().field_1().field_1();
58    ///
59    /// // path root -> field_1 -> field_2
60    /// let path = store.build_path().field_1().field_2();
61    /// ```
62    pub fn build_path(&self) -> StoreRoot<'_, S> {
63        S::new_path_builder(RootPath { store: self })
64    }
65}
66
67/// The PathBuilder pointing to the root data type in the store itself.
68///
69/// This is obtained by [Store::build_path].
70pub type StoreRoot<'s, S> = <S as Trackable>::PathBuilder<RootPath<'s, S>>;
71
72/// The [Path] object to the root of the store.
73pub struct RootPath<'s, S> {
74    store: &'s Store<S>,
75}
76
77impl<'s, S> Clone for RootPath<'s, S> {
78    fn clone(&self) -> Self {
79        Self { store: self.store }
80    }
81}
82impl<'s, S> Copy for RootPath<'s, S> {}
83
84impl<'s, S> Debug for RootPath<'s, S> {
85    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86        f.write_str("Root")
87    }
88}
89
90impl<'s, S> Path for RootPath<'s, S> {
91    type Out = S;
92
93    fn path_borrow(&self) -> Option<Ref<'_, Self::Out>> {
94        Some(self.store.data.borrow())
95    }
96
97    fn path_borrow_mut(&self) -> Option<RefMut<'_, Self::Out>> {
98        Some(self.store.data.borrow_mut())
99    }
100
101    fn visit_hashes(&self, visitor: &mut crate::hash_visitor::HashVisitor) {
102        visitor.finish_one();
103    }
104
105    fn store_wakers(&self) -> &RefCell<StoreWakers> {
106        &self.store.wakers
107    }
108}
109impl<'s, S> PathExtGuaranteed for RootPath<'s, S> {}