dioxus_keys/
macros.rs

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