1#![allow(clippy::unnecessary_operation)]
2#![allow(clippy::no_effect)]
3
4use generational_box::UnsyncStorage;
5use generational_box::{BorrowResult, GenerationalBoxId};
6use std::ops::Deref;
7
8use dioxus_core::prelude::*;
9
10use generational_box::{GenerationalBox, Storage};
11
12use crate::read_impls;
13use crate::Readable;
14use crate::ReadableRef;
15use crate::Writable;
16use crate::WritableRef;
17use crate::{default_impl, write_impls};
18
19pub struct CopyValue<T: 'static, S: Storage<T> = UnsyncStorage> {
23 pub(crate) value: GenerationalBox<T, S>,
24 pub(crate) origin_scope: ScopeId,
25}
26
27#[cfg(feature = "serialize")]
28impl<T: 'static, Store: Storage<T>> serde::Serialize for CopyValue<T, Store>
29where
30 T: serde::Serialize,
31{
32 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
33 self.value.read().serialize(serializer)
34 }
35}
36
37#[cfg(feature = "serialize")]
38impl<'de, T: 'static, Store: Storage<T>> serde::Deserialize<'de> for CopyValue<T, Store>
39where
40 T: serde::Deserialize<'de>,
41{
42 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
43 let value = T::deserialize(deserializer)?;
44
45 Ok(Self::new_maybe_sync(value))
46 }
47}
48
49impl<T: 'static> CopyValue<T> {
50 #[track_caller]
54 pub fn new(value: T) -> Self {
55 Self::new_maybe_sync(value)
56 }
57
58 #[track_caller]
60 pub fn new_in_scope(value: T, scope: ScopeId) -> Self {
61 Self::new_maybe_sync_in_scope(value, scope)
62 }
63}
64
65impl<T: 'static, S: Storage<T>> CopyValue<T, S> {
66 #[track_caller]
70 pub fn new_maybe_sync(value: T) -> Self {
71 Self::new_with_caller(value, std::panic::Location::caller())
72 }
73
74 pub fn leak_with_caller(value: T, caller: &'static std::panic::Location<'static>) -> Self {
76 Self {
77 value: GenerationalBox::leak(value, caller),
78 origin_scope: current_scope_id().expect("in a virtual dom"),
79 }
80 }
81
82 pub fn point_to(&self, other: Self) -> BorrowResult {
84 self.value.point_to(other.value)
85 }
86
87 pub(crate) fn new_with_caller(
88 value: T,
89 caller: &'static std::panic::Location<'static>,
90 ) -> Self {
91 let owner = current_owner();
92
93 Self {
94 value: owner.insert_rc_with_caller(value, caller),
95 origin_scope: current_scope_id().expect("in a virtual dom"),
96 }
97 }
98
99 #[track_caller]
101 pub fn new_maybe_sync_in_scope(value: T, scope: ScopeId) -> Self {
102 Self::new_maybe_sync_in_scope_with_caller(value, scope, std::panic::Location::caller())
103 }
104
105 #[track_caller]
107 pub fn new_maybe_sync_in_scope_with_caller(
108 value: T,
109 scope: ScopeId,
110 caller: &'static std::panic::Location<'static>,
111 ) -> Self {
112 let owner = scope.owner();
113
114 Self {
115 value: owner.insert_rc_with_caller(value, caller),
116 origin_scope: scope,
117 }
118 }
119
120 pub fn manually_drop(&self) {
122 self.value.manually_drop()
123 }
124
125 pub fn origin_scope(&self) -> ScopeId {
127 self.origin_scope
128 }
129
130 pub fn id(&self) -> GenerationalBoxId {
132 self.value.id()
133 }
134
135 pub fn value(&self) -> GenerationalBox<T, S> {
137 self.value
138 }
139}
140
141impl<T: 'static, S: Storage<T>> Readable for CopyValue<T, S> {
142 type Target = T;
143 type Storage = S;
144
145 #[track_caller]
146 fn try_read_unchecked(
147 &self,
148 ) -> Result<ReadableRef<'static, Self>, generational_box::BorrowError> {
149 crate::warnings::copy_value_hoisted(self, std::panic::Location::caller());
150 self.value.try_read()
151 }
152
153 #[track_caller]
154 fn try_peek_unchecked(&self) -> BorrowResult<ReadableRef<'static, Self>> {
155 crate::warnings::copy_value_hoisted(self, std::panic::Location::caller());
156 self.value.try_read()
157 }
158}
159
160impl<T: 'static, S: Storage<T>> Writable for CopyValue<T, S> {
161 type Mut<'a, R: ?Sized + 'static> = S::Mut<'a, R>;
162
163 fn map_mut<I: ?Sized, U: ?Sized, F: FnOnce(&mut I) -> &mut U>(
164 mut_: Self::Mut<'_, I>,
165 f: F,
166 ) -> Self::Mut<'_, U> {
167 S::map_mut(mut_, f)
168 }
169
170 fn try_map_mut<I: ?Sized, U: ?Sized, F: FnOnce(&mut I) -> Option<&mut U>>(
171 mut_: Self::Mut<'_, I>,
172 f: F,
173 ) -> Option<Self::Mut<'_, U>> {
174 S::try_map_mut(mut_, f)
175 }
176
177 fn downcast_lifetime_mut<'a: 'b, 'b, R: ?Sized + 'static>(
178 mut_: Self::Mut<'a, R>,
179 ) -> Self::Mut<'b, R> {
180 S::downcast_lifetime_mut(mut_)
181 }
182
183 #[track_caller]
184 fn try_write_unchecked(
185 &self,
186 ) -> Result<WritableRef<'static, Self>, generational_box::BorrowMutError> {
187 crate::warnings::copy_value_hoisted(self, std::panic::Location::caller());
188 self.value.try_write()
189 }
190
191 #[track_caller]
192 fn set(&mut self, value: T) {
193 crate::warnings::copy_value_hoisted(self, std::panic::Location::caller());
194 self.value.set(value);
195 }
196}
197
198impl<T: 'static, S: Storage<T>> PartialEq for CopyValue<T, S> {
199 fn eq(&self, other: &Self) -> bool {
200 self.value.ptr_eq(&other.value)
201 }
202}
203impl<T: 'static, S: Storage<T>> Eq for CopyValue<T, S> {}
204
205impl<T: Copy, S: Storage<T>> Deref for CopyValue<T, S> {
206 type Target = dyn Fn() -> T;
207
208 fn deref(&self) -> &Self::Target {
209 unsafe { Readable::deref_impl(self) }
210 }
211}
212
213impl<T, S: Storage<T>> Clone for CopyValue<T, S> {
214 fn clone(&self) -> Self {
215 *self
216 }
217}
218
219impl<T, S: Storage<T>> Copy for CopyValue<T, S> {}
220
221read_impls!(CopyValue<T, S: Storage<T>>);
222default_impl!(CopyValue<T, S: Storage<T>>);
223write_impls!(CopyValue<T, S: Storage<T>>);