Skip to main content

atomic_hooks/
state_access.rs

1use crate::hooks_state_functions::*;
2use std::marker::PhantomData;
3use crate::store::TopoKey;
4
5///  Accessor struct that provides access to getting and setting the
6///  state of the stored type
7///
8// #[derive(Debug)]
9pub struct StateAccess<T> {
10    pub id: TopoKey,
11    _phantom_data: PhantomData<T>,
12}
13
14impl<T> std::fmt::Debug for StateAccess<T> {
15    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16        write!(f, "({:#?})", self.id)
17    }
18}
19
20impl<T> Copy for StateAccess<T> {}
21impl<T> Clone for StateAccess<T> {
22    fn clone(&self) -> StateAccess<T> {
23        StateAccess::<T> {
24            id: self.id,
25            _phantom_data: PhantomData::<T>,
26        }
27    }
28}
29
30impl<T> StateAccess<T>
31where
32    T: 'static,
33{
34    pub fn new(id:TopoKey) -> StateAccess<T> {
35        StateAccess {
36            id,
37            _phantom_data: PhantomData,
38        }
39    }
40
41    // stores a value of type T in a backing Store
42    pub fn set(self, value: T) {
43        set_state_with_topo_id(value, self.id);
44    }
45
46    pub fn remove(self) -> Option<T> {
47        remove_state_with_topo_id(self.id)
48    }
49
50    pub fn delete(self) {
51        self.remove();
52    }
53
54    pub fn reset_on_unmount(self) -> Self {
55        on_unmount(move || self.delete());
56        self
57    }
58
59    /// updates the stored state in place
60    /// using the provided function
61    pub fn update<F: FnOnce(&mut T) -> ()>(self, func: F) {
62        update_state_with_topo_id(self.id, func);
63    }
64
65    pub fn state_exists(self) -> bool {
66        state_exists_for_topo_id::<T>(self.id)
67    }
68
69    pub fn get_with<F: FnOnce(&T) -> R, R>(self, func: F) -> R {
70        read_state_with_topo_id(self.id, func)
71    }
72}
73
74pub trait CloneState<T>
75where
76    T: Clone + 'static,
77{
78    fn get(&self) -> T;
79
80    fn soft_get(&self) -> Option<T>;
81}
82
83impl<T> CloneState<T> for StateAccess<T>
84where
85    T: Clone + 'static,
86{
87    /// returns a clone of the stored state panics if not stored.
88    fn get(&self) -> T {
89        clone_state_with_topo_id::<T>(self.id).expect("state should be present")
90    }
91
92    fn soft_get(&self) -> Option<T> {
93        clone_state_with_topo_id::<T>(self.id)
94    }
95}
96
97#[derive(Clone)]
98struct ChangedWrapper<T>(T);
99
100pub trait ChangedState {
101    fn changed(&self) -> bool;
102}
103
104impl<T> ChangedState for StateAccess<T>
105where
106    T: Clone + 'static + PartialEq,
107{
108    fn changed(&self) -> bool {
109        if let Some(old_state) = clone_state_with_topo_id::<ChangedWrapper<T>>(self.id) {
110            old_state.0 != self.get()
111        } else {
112            set_state_with_topo_id(ChangedWrapper(self.get()), self.id);
113            true
114        }
115    }
116}
117
118impl<T> std::fmt::Display for StateAccess<T>
119where
120    T: std::fmt::Display + 'static,
121{
122    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
123        write!(f, "{}", self.get_with(|t| format!("{}", t)))
124    }
125}
126
127use std::ops::Add;
128use std::ops::Div;
129use std::ops::Mul;
130use std::ops::Sub;
131
132impl<T> Add for StateAccess<T>
133where
134    T: Copy + Add<Output = T> + 'static,
135{
136    type Output = T;
137
138    fn add(self, other: Self) -> Self::Output {
139        self.get_with(|s| other.get_with(|o| *o + *s))
140    }
141}
142
143impl<T> Mul for StateAccess<T>
144where
145    T: Copy + Mul<Output = T> + 'static,
146{
147    type Output = T;
148
149    fn mul(self, other: Self) -> Self::Output {
150        self.get_with(|s| other.get_with(|o| *o * *s))
151    }
152}
153
154impl<T> Div for StateAccess<T>
155where
156    T: Copy + Div<Output = T> + 'static,
157{
158    type Output = T;
159
160    fn div(self, other: Self) -> Self::Output {
161        self.get_with(|s| other.get_with(|o| *o / *s))
162    }
163}
164
165impl<T> Sub for StateAccess<T>
166where
167    T: Copy + Sub<Output = T> + 'static,
168{
169    type Output = T;
170
171    fn sub(self, other: Self) -> Self::Output {
172        self.get_with(|s| other.get_with(|o| *o - *s))
173    }
174}