dioxus_signals/
copy_value.rs1#![allow(clippy::unnecessary_operation)]
2#![allow(clippy::no_effect)]
3
4use dioxus_core::{current_owner, current_scope_id, ScopeId};
5use dioxus_core::{Runtime, Subscribers};
6use generational_box::{
7 AnyStorage, BorrowResult, GenerationalBox, GenerationalBoxId, Storage, UnsyncStorage,
8};
9use std::ops::Deref;
10
11use crate::read_impls;
12use crate::Readable;
13use crate::ReadableExt;
14use crate::ReadableRef;
15use crate::Writable;
16use crate::WritableRef;
17use crate::WriteLock;
18use crate::{default_impl, write_impls, WritableExt};
19
20pub struct CopyValue<T, S: 'static = UnsyncStorage> {
24 pub(crate) value: GenerationalBox<T, S>,
25 pub(crate) origin_scope: ScopeId,
26}
27
28#[cfg(feature = "serialize")]
29impl<T, Store: Storage<T>> serde::Serialize for CopyValue<T, Store>
30where
31 T: serde::Serialize + 'static,
32{
33 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
34 self.value.read().serialize(serializer)
35 }
36}
37
38#[cfg(feature = "serialize")]
39impl<'de, T, Store: Storage<T>> serde::Deserialize<'de> for CopyValue<T, Store>
40where
41 T: serde::Deserialize<'de> + 'static,
42{
43 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
44 let value = T::deserialize(deserializer)?;
45
46 Ok(Self::new_maybe_sync(value))
47 }
48}
49
50impl<T: 'static> CopyValue<T> {
51 #[track_caller]
55 pub fn new(value: T) -> Self {
56 Self::new_maybe_sync(value)
57 }
58
59 #[track_caller]
61 pub fn new_in_scope(value: T, scope: ScopeId) -> Self {
62 Self::new_maybe_sync_in_scope(value, scope)
63 }
64}
65
66impl<T, S: Storage<T>> CopyValue<T, S> {
67 #[track_caller]
71 pub fn new_maybe_sync(value: T) -> Self
72 where
73 T: 'static,
74 {
75 Self::new_with_caller(value, std::panic::Location::caller())
76 }
77
78 pub fn leak_with_caller(value: T, caller: &'static std::panic::Location<'static>) -> Self
80 where
81 T: 'static,
82 {
83 Self {
84 value: GenerationalBox::leak(value, caller),
85 origin_scope: current_scope_id(),
86 }
87 }
88
89 pub fn point_to(&self, other: Self) -> BorrowResult {
91 self.value.point_to(other.value)
92 }
93
94 pub(crate) fn new_with_caller(
95 value: T,
96 caller: &'static std::panic::Location<'static>,
97 ) -> Self {
98 let owner = current_owner();
99
100 Self {
101 value: owner.insert_rc_with_caller(value, caller),
102 origin_scope: current_scope_id(),
103 }
104 }
105
106 #[track_caller]
108 pub fn new_maybe_sync_in_scope(value: T, scope: ScopeId) -> Self {
109 Self::new_maybe_sync_in_scope_with_caller(value, scope, std::panic::Location::caller())
110 }
111
112 #[track_caller]
114 pub fn new_maybe_sync_in_scope_with_caller(
115 value: T,
116 scope: ScopeId,
117 caller: &'static std::panic::Location<'static>,
118 ) -> Self {
119 let owner = Runtime::current().scope_owner(scope);
120 Self {
121 value: owner.insert_rc_with_caller(value, caller),
122 origin_scope: scope,
123 }
124 }
125
126 pub fn manually_drop(&self)
128 where
129 T: 'static,
130 {
131 self.value.manually_drop()
132 }
133
134 pub fn origin_scope(&self) -> ScopeId {
136 self.origin_scope
137 }
138
139 pub fn id(&self) -> GenerationalBoxId {
141 self.value.id()
142 }
143
144 pub fn value(&self) -> GenerationalBox<T, S> {
146 self.value
147 }
148}
149
150impl<T, S: Storage<T>> Readable for CopyValue<T, S> {
151 type Target = T;
152 type Storage = S;
153
154 #[track_caller]
155 fn try_read_unchecked(
156 &self,
157 ) -> Result<ReadableRef<'static, Self>, generational_box::BorrowError> {
158 crate::warnings::copy_value_hoisted(self, std::panic::Location::caller());
159 self.value.try_read()
160 }
161
162 #[track_caller]
163 fn try_peek_unchecked(&self) -> BorrowResult<ReadableRef<'static, Self>> {
164 crate::warnings::copy_value_hoisted(self, std::panic::Location::caller());
165 self.value.try_read()
166 }
167
168 fn subscribers(&self) -> Subscribers {
169 Subscribers::new_noop()
170 }
171}
172
173impl<T, S: Storage<T>> Writable for CopyValue<T, S> {
174 type WriteMetadata = ();
175
176 #[track_caller]
177 fn try_write_unchecked(
178 &self,
179 ) -> Result<WritableRef<'static, Self>, generational_box::BorrowMutError> {
180 crate::warnings::copy_value_hoisted(self, std::panic::Location::caller());
181 self.value.try_write().map(WriteLock::new)
182 }
183}
184
185impl<T, S: AnyStorage> PartialEq for CopyValue<T, S> {
186 fn eq(&self, other: &Self) -> bool {
187 self.value.ptr_eq(&other.value)
188 }
189}
190impl<T, S: AnyStorage> Eq for CopyValue<T, S> {}
191
192impl<T: Copy + 'static, S: Storage<T>> Deref for CopyValue<T, S> {
193 type Target = dyn Fn() -> T;
194
195 fn deref(&self) -> &Self::Target {
196 unsafe { ReadableExt::deref_impl(self) }
197 }
198}
199
200impl<T, S> Clone for CopyValue<T, S> {
201 fn clone(&self) -> Self {
202 *self
203 }
204}
205
206impl<T, S> Copy for CopyValue<T, S> {}
207
208read_impls!(CopyValue<T, S: Storage<T>>);
209default_impl!(CopyValue<T, S: Storage<T>>);
210write_impls!(CopyValue<T, S: Storage<T>>);