1use crate::{FromEncodedStr, IntoEncodedString};
2#[cfg(feature = "rkyv")]
3use codee::binary::RkyvCodec;
4#[cfg(feature = "serde-wasm-bindgen")]
5use codee::string::JsonSerdeWasmCodec;
6#[cfg(feature = "miniserde")]
7use codee::string::MiniserdeCodec;
8#[cfg(feature = "serde-lite")]
9use codee::SerdeLite;
10use codee::{
11 string::{FromToStringCodec, JsonSerdeCodec},
12 Decoder, Encoder,
13};
14use std::{
15 fmt::{Debug, Display},
16 hash::Hash,
17 marker::PhantomData,
18 ops::{Deref, DerefMut},
19};
20
21#[derive(Debug)]
28pub struct SharedValue<T, Ser = JsonSerdeCodec> {
29 value: T,
30 ser: PhantomData<Ser>,
31}
32
33impl<T, Ser> SharedValue<T, Ser> {
34 pub fn into_inner(self) -> T {
36 self.value
37 }
38}
39
40impl<T> SharedValue<T, JsonSerdeCodec>
41where
42 JsonSerdeCodec: Encoder<T> + Decoder<T>,
43 <JsonSerdeCodec as Encoder<T>>::Error: Debug,
44 <JsonSerdeCodec as Decoder<T>>::Error: Debug,
45 <JsonSerdeCodec as Encoder<T>>::Encoded: IntoEncodedString,
46 <JsonSerdeCodec as Decoder<T>>::Encoded: FromEncodedStr,
47 <<JsonSerdeCodec as codee::Decoder<T>>::Encoded as FromEncodedStr>::DecodingError:
48 Debug,
49{
50 pub fn new(initial: impl FnOnce() -> T) -> Self {
57 SharedValue::new_with_encoding(initial)
58 }
59}
60
61impl<T> SharedValue<T, FromToStringCodec>
62where
63 FromToStringCodec: Encoder<T> + Decoder<T>,
64 <FromToStringCodec as Encoder<T>>::Error: Debug,
65 <FromToStringCodec as Decoder<T>>::Error: Debug,
66 <FromToStringCodec as Encoder<T>>::Encoded: IntoEncodedString,
67 <FromToStringCodec as Decoder<T>>::Encoded: FromEncodedStr,
68 <<FromToStringCodec as codee::Decoder<T>>::Encoded as FromEncodedStr>::DecodingError:
69 Debug,
70{
71 pub fn new_str(initial: impl FnOnce() -> T) -> Self {
78 SharedValue::new_with_encoding(initial)
79 }
80}
81
82#[cfg(feature = "serde-lite")]
83impl<T> SharedValue<T, SerdeLite<JsonSerdeCodec>>
84where
85 SerdeLite<JsonSerdeCodec>: Encoder<T> + Decoder<T>,
86 <SerdeLite<JsonSerdeCodec> as Encoder<T>>::Error: Debug,
87 <SerdeLite<JsonSerdeCodec> as Decoder<T>>::Error: Debug,
88 <SerdeLite<JsonSerdeCodec> as Encoder<T>>::Encoded: IntoEncodedString,
89 <SerdeLite<JsonSerdeCodec> as Decoder<T>>::Encoded: FromEncodedStr,
90 <<SerdeLite<JsonSerdeCodec> as codee::Decoder<T>>::Encoded as FromEncodedStr>::DecodingError:
91 Debug,
92{
93 pub fn new_serde_lite(initial: impl FnOnce() -> T) -> Self {
100 SharedValue::new_with_encoding(initial)
101 }
102}
103
104#[cfg(feature = "serde-wasm-bindgen")]
105impl<T> SharedValue<T, JsonSerdeWasmCodec>
106where
107 JsonSerdeWasmCodec: Encoder<T> + Decoder<T>,
108 <JsonSerdeWasmCodec as Encoder<T>>::Error: Debug,
109 <JsonSerdeWasmCodec as Decoder<T>>::Error: Debug,
110 <JsonSerdeWasmCodec as Encoder<T>>::Encoded: IntoEncodedString,
111 <JsonSerdeWasmCodec as Decoder<T>>::Encoded: FromEncodedStr,
112 <<JsonSerdeWasmCodec as codee::Decoder<T>>::Encoded as FromEncodedStr>::DecodingError:
113 Debug,
114{
115 pub fn new_serde_wb(initial: impl FnOnce() -> T) -> Self {
122 SharedValue::new_with_encoding(initial)
123 }
124}
125
126#[cfg(feature = "miniserde")]
127impl<T> SharedValue<T, MiniserdeCodec>
128where
129 MiniserdeCodec: Encoder<T> + Decoder<T>,
130 <MiniserdeCodec as Encoder<T>>::Error: Debug,
131 <MiniserdeCodec as Decoder<T>>::Error: Debug,
132 <MiniserdeCodec as Encoder<T>>::Encoded: IntoEncodedString,
133 <MiniserdeCodec as Decoder<T>>::Encoded: FromEncodedStr,
134 <<MiniserdeCodec as codee::Decoder<T>>::Encoded as FromEncodedStr>::DecodingError:
135 Debug,
136{
137 pub fn new_miniserde(initial: impl FnOnce() -> T) -> Self {
144 SharedValue::new_with_encoding(initial)
145 }
146}
147
148#[cfg(feature = "rkyv")]
149impl<T> SharedValue<T, RkyvCodec>
150where
151 RkyvCodec: Encoder<T> + Decoder<T>,
152 <RkyvCodec as Encoder<T>>::Error: Debug,
153 <RkyvCodec as Decoder<T>>::Error: Debug,
154 <RkyvCodec as Encoder<T>>::Encoded: IntoEncodedString,
155 <RkyvCodec as Decoder<T>>::Encoded: FromEncodedStr,
156 <<RkyvCodec as codee::Decoder<T>>::Encoded as FromEncodedStr>::DecodingError:
157 Debug,
158{
159 pub fn new_rkyv(initial: impl FnOnce() -> T) -> Self {
166 SharedValue::new_with_encoding(initial)
167 }
168}
169
170impl<T, Ser> SharedValue<T, Ser>
171where
172 Ser: Encoder<T> + Decoder<T>,
173 <Ser as Encoder<T>>::Error: Debug,
174 <Ser as Decoder<T>>::Error: Debug,
175 <Ser as Encoder<T>>::Encoded: IntoEncodedString,
176 <Ser as Decoder<T>>::Encoded: FromEncodedStr,
177 <<Ser as codee::Decoder<T>>::Encoded as FromEncodedStr>::DecodingError:
178 Debug,
179{
180 pub fn new_with_encoding(initial: impl FnOnce() -> T) -> Self {
187 let value: T;
188 #[cfg(feature = "hydration")]
189 {
190 use reactive_graph::owner::Owner;
191 use std::borrow::Borrow;
192
193 let sc = Owner::current_shared_context();
194 let id = sc.as_ref().map(|sc| sc.next_id()).unwrap_or_default();
195 let serialized = sc.as_ref().and_then(|sc| sc.read_data(&id));
196 let hydrating =
197 sc.as_ref().map(|sc| sc.during_hydration()).unwrap_or(false);
198 value = if hydrating {
199 let value = match serialized {
200 None => {
201 #[cfg(feature = "tracing")]
202 tracing::error!("couldn't deserialize");
203 None
204 }
205 Some(data) => {
206 match <Ser as Decoder<T>>::Encoded::from_encoded_str(
207 &data,
208 ) {
209 #[allow(unused_variables)] Err(e) => {
211 #[cfg(feature = "tracing")]
212 tracing::error!(
213 "couldn't deserialize from {data:?}: {e:?}"
214 );
215 None
216 }
217 Ok(encoded) => {
218 let decoded = Ser::decode(encoded.borrow());
219 #[cfg(feature = "tracing")]
220 let decoded = decoded
221 .inspect_err(|e| tracing::error!("{e:?}"));
222 decoded.ok()
223 }
224 }
225 }
226 };
227 value.unwrap_or_else(initial)
228 } else {
229 let init = initial();
230 #[cfg(feature = "ssr")]
231 if let Some(sc) = sc {
232 if sc.get_is_hydrating() {
233 match Ser::encode(&init)
234 .map(IntoEncodedString::into_encoded_string)
235 {
236 Ok(value) => sc.write_async(
237 id,
238 Box::pin(async move { value }),
239 ),
240 #[allow(unused_variables)] Err(e) => {
242 #[cfg(feature = "tracing")]
243 tracing::error!("couldn't serialize: {e:?}");
244 }
245 }
246 }
247 }
248 init
249 }
250 }
251 #[cfg(not(feature = "hydration"))]
252 {
253 value = initial();
254 }
255 Self {
256 value,
257 ser: PhantomData,
258 }
259 }
260}
261
262impl<T, Ser> Deref for SharedValue<T, Ser> {
263 type Target = T;
264
265 fn deref(&self) -> &Self::Target {
266 &self.value
267 }
268}
269
270impl<T, Ser> DerefMut for SharedValue<T, Ser> {
271 fn deref_mut(&mut self) -> &mut Self::Target {
272 &mut self.value
273 }
274}
275
276impl<T, Ser> PartialEq for SharedValue<T, Ser>
277where
278 T: PartialEq,
279{
280 fn eq(&self, other: &Self) -> bool {
281 self.value == other.value
282 }
283}
284
285impl<T, Ser> Eq for SharedValue<T, Ser> where T: Eq {}
286
287impl<T, Ser> Display for SharedValue<T, Ser>
288where
289 T: Display,
290{
291 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
292 write!(f, "{}", self.value)
293 }
294}
295
296impl<T, Ser> Hash for SharedValue<T, Ser>
297where
298 T: Hash,
299{
300 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
301 self.value.hash(state);
302 }
303}
304
305impl<T, Ser> PartialOrd for SharedValue<T, Ser>
306where
307 T: PartialOrd,
308{
309 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
310 self.value.partial_cmp(&other.value)
311 }
312}
313
314impl<T, Ser> Ord for SharedValue<T, Ser>
315where
316 T: Ord,
317{
318 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
319 self.value.cmp(&other.value)
320 }
321}