dioxus_keys/
macros.rs

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