rustolio_web/hooks/
storage.rs1use std::{rc::Rc, str::FromStr};
12
13use rustolio_utils::{
14 bytes::{
15 Bytes,
16 encoding::{decode_from_bytes, encode_to_bytes},
17 },
18 prelude::{Decode, Encode},
19};
20
21use crate::prelude::*;
22
23use super::SignalBase;
24
25#[derive(Debug, PartialEq, Eq)]
26pub struct StorageSignal<T> {
27 key: Signal<Rc<str>>,
28 signal: Signal<T>,
29}
30
31impl<T> Clone for StorageSignal<T> {
33 fn clone(&self) -> Self {
34 *self
35 }
36}
37impl<T> Copy for StorageSignal<T> {}
38
39impl<T> SignalBase<T> for StorageSignal<T> {
40 fn base(&self) -> Signal<T> {
41 self.signal.base()
42 }
43}
44impl<T> SignalGetter<T> for StorageSignal<T> where T: Clone + 'static {}
45impl<T> SignalSetter<T> for StorageSignal<T> where T: PartialEq + 'static {}
46impl<T> SignalUpdater<T> for StorageSignal<T> where T: 'static {}
47
48impl<T> StorageSignal<T> {
49 pub fn remove(&self) -> rustolio_utils::Result<()> {
54 local_storage()?.delete(&self.key.peek())?;
55 Ok(())
56 }
57}
58
59impl<T> StorageSignal<T>
60where
61 T: ToString + FromStr + Clone + 'static,
62{
63 pub fn new(key: impl ToString, fallback: T) -> rustolio_utils::Result<Self> {
64 let key: Signal<Rc<str>> = Signal::new(key.to_string().into());
65
66 let stored_value = local_storage()?
67 .get(&key.peek())?
68 .and_then(|v| T::from_str(&v).ok())
69 .unwrap_or(fallback);
70
71 let signal = Signal::new(stored_value);
72 Effect::new_result(move || {
73 let key = key.peek();
74 let value = signal.value().to_string();
75 local_storage()?.set(&key, &value)?;
76 Ok(())
77 });
78
79 Ok(Self { signal, key })
80 }
81}
82
83impl<T> StorageSignal<T>
84where
85 T: Decode + Encode + Clone + 'static,
86{
87 pub fn new_encoded(key: impl ToString, fallback: T) -> rustolio_utils::Result<Self> {
88 let key: Signal<Rc<str>> = Signal::new(key.to_string().into());
89
90 let stored_value = local_storage()?
91 .get(&key.peek())?
92 .and_then(|v| decode_from_bytes(Bytes::from_owner(v.into_bytes())).ok())
93 .unwrap_or(fallback);
94
95 let signal = Signal::always_mutable(stored_value);
96 Effect::new_result(move || {
97 let key = key.peek();
98 let value = signal.value();
99 let value = encode_to_bytes(&value)?.into();
100 let value = unsafe { String::from_utf8_unchecked(value) };
101 local_storage()?.set(&key, &value)?;
102 Ok(())
103 });
104
105 Ok(Self { signal, key })
106 }
107}