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> {}