dioxus_keys/
macros.rs

1#[macro_export]
2/// Example usage:
3/// ```
4/// struct ExampleKey;
5///
6/// MaybeStoredKey! {
7///     ExampleKey,
8///     Value = i32,
9///     Path = "somedir",
10///     Serialize = |val: &i32| val.to_string().into_bytes(),
11///     Deserialize = |contents: &[u8]| {
12///         String::from_utf8(contents.to_vec())
13///             .unwrap()
14///             .parse()
15///             .unwrap()
16///     }
17/// }
18///
19/// ```
20macro_rules! MaybeStoredKey {
21    ($key_name:ident, Value = $val:ty, Path = $path:expr, Serialize = $serialize:expr, Deserialize = $deserialize:expr) => {
22        use $crate::re_exports::*;
23
24        static DATA: Global<Signal<Option<Option<$val>>, SyncStorage>> =
25            Global::new(|| Signal::new_maybe_sync(None));
26
27        impl DataKey for $key_name {
28            type Value = Option<$val>;
29
30            async fn init() {
31                let path = PathBuf::from($path);
32                if path.try_exists().unwrap() {
33                    let mut file = File::open(path).await.unwrap();
34                    let mut contents = Vec::new();
35                    file.read_to_end(&mut contents).await.unwrap();
36                    *DATA.resolve().write() = Some(Some(($deserialize)(&contents)));
37                } else {
38                    *DATA.resolve().write() = Some(None);
39                }
40            }
41
42            async fn on_change() {
43                let resolve = DATA.resolve();
44                let read = resolve.read();
45                let Some(data) = read.deref().as_ref() else {
46                    return;
47                };
48
49                if let Some(data) = data {
50                    let mut file = File::create(PathBuf::from($path)).await.unwrap();
51                    file.write_all(&($serialize)(data)).await.unwrap();
52                } else {
53                    let _ = remove_file($path).await;
54                }
55            }
56
57            async fn on_drop() {}
58
59            fn try_read() -> Option<impl Deref<Target = Self::Value>> {
60                SyncStorage::try_map(DATA.resolve().read_unchecked(), |v| v.as_ref())
61            }
62
63            fn try_peek() -> Option<impl Deref<Target = Self::Value>> {
64                SyncStorage::try_map(DATA.resolve().peek_unchecked(), |v| v.as_ref())
65            }
66
67            fn try_write() -> Option<impl DerefMut<Target = Self::Value>> {
68                Signal::<Option<Self::Value>, SyncStorage>::try_map_mut(
69                    DATA.resolve().write_unchecked(),
70                    |v| v.as_mut(),
71                )
72            }
73        }
74    };
75}
76
77#[macro_export]
78/// Example usage:
79/// ```
80/// struct ExampleKey;
81///
82/// StoredKey! {
83///     ExampleKey,
84///     Value = i32,
85///     Path = "somedir",
86///     Default = 1111_i32,
87///     Serialize = |val: &i32| val.to_string().into_bytes(),
88///     Deserialize = |contents: &[u8]| {
89///         String::from_utf8(contents.to_vec())
90///             .unwrap()
91///             .parse()
92///             .unwrap()
93///     }
94/// }
95///
96/// ```
97macro_rules! StoredKey {
98    ($key_name:ident, Value = $val:ty, Path = $path:expr, Default = $default:expr, Serialize = $serialize:expr, Deserialize = $deserialize:expr) => {
99        use $crate::re_exports::*;
100
101        static DATA: Global<Signal<Option<$val>, SyncStorage>> =
102            Global::new(|| Signal::new_maybe_sync(None));
103
104        impl DataKey for $key_name {
105            type Value = $val;
106
107            async fn init() {
108                let path = PathBuf::from($path);
109                if path.try_exists().unwrap() {
110                    let mut file = File::open(path).await.unwrap();
111                    let mut contents = Vec::new();
112                    file.read_to_end(&mut contents).await.unwrap();
113                    *DATA.resolve().write() = Some(($deserialize)(&contents));
114                } else {
115                    let default = $default;
116                    let mut file = File::create(path).await.unwrap();
117                    file.write_all(&($serialize)(&default)).await.unwrap();
118                    *DATA.resolve().write() = Some(default);
119                }
120            }
121
122            async fn on_change() {
123                let mut file = File::create(PathBuf::from($path)).await.unwrap();
124                file.write_all(&($serialize)(
125                    DATA.resolve().read().deref().as_ref().unwrap(),
126                ))
127                .await
128                .unwrap();
129            }
130
131            async fn on_drop() {}
132
133            fn try_read() -> Option<impl Deref<Target = Self::Value>> {
134                SyncStorage::try_map(data.resolve().read_unchecked(), |v| v.as_ref())
135            }
136
137            fn try_peek() -> Option<impl Deref<Target = Self::Value>> {
138                SyncStorage::try_map(data.resolve().peek_unchecked(), |v| v.as_ref())
139            }
140
141            fn try_write() -> Option<impl DerefMut<Target = Self::Value>> {
142                Signal::<Option<Self::Value>, SyncStorage>::try_map_mut(
143                    DATA.resolve().write_unchecked(),
144                    |v| v.as_mut(),
145                )
146            }
147        }
148    };
149}