copy_value.rs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. #![allow(clippy::unnecessary_operation)]
  2. #![allow(clippy::no_effect)]
  3. use generational_box::UnsyncStorage;
  4. use generational_box::{BorrowResult, GenerationalBoxId};
  5. use std::ops::Deref;
  6. use dioxus_core::prelude::*;
  7. use generational_box::{GenerationalBox, Storage};
  8. use crate::read_impls;
  9. use crate::Readable;
  10. use crate::ReadableRef;
  11. use crate::Writable;
  12. use crate::WritableRef;
  13. use crate::{default_impl, write_impls};
  14. /// CopyValue is a wrapper around a value to make the value mutable and Copy.
  15. ///
  16. /// It is internally backed by [`generational_box::GenerationalBox`].
  17. pub struct CopyValue<T: 'static, S: Storage<T> = UnsyncStorage> {
  18. pub(crate) value: GenerationalBox<T, S>,
  19. pub(crate) origin_scope: ScopeId,
  20. }
  21. #[cfg(feature = "serialize")]
  22. impl<T: 'static, Store: Storage<T>> serde::Serialize for CopyValue<T, Store>
  23. where
  24. T: serde::Serialize,
  25. {
  26. fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
  27. self.value.read().serialize(serializer)
  28. }
  29. }
  30. #[cfg(feature = "serialize")]
  31. impl<'de, T: 'static, Store: Storage<T>> serde::Deserialize<'de> for CopyValue<T, Store>
  32. where
  33. T: serde::Deserialize<'de>,
  34. {
  35. fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
  36. let value = T::deserialize(deserializer)?;
  37. Ok(Self::new_maybe_sync(value))
  38. }
  39. }
  40. impl<T: 'static> CopyValue<T> {
  41. /// Create a new CopyValue. The value will be stored in the current component.
  42. ///
  43. /// Once the component this value is created in is dropped, the value will be dropped.
  44. #[track_caller]
  45. pub fn new(value: T) -> Self {
  46. Self::new_maybe_sync(value)
  47. }
  48. /// Create a new CopyValue. The value will be stored in the given scope. When the specified scope is dropped, the value will be dropped.
  49. #[track_caller]
  50. pub fn new_in_scope(value: T, scope: ScopeId) -> Self {
  51. Self::new_maybe_sync_in_scope(value, scope)
  52. }
  53. }
  54. impl<T: 'static, S: Storage<T>> CopyValue<T, S> {
  55. /// Create a new CopyValue. The value will be stored in the current component.
  56. ///
  57. /// Once the component this value is created in is dropped, the value will be dropped.
  58. #[track_caller]
  59. pub fn new_maybe_sync(value: T) -> Self {
  60. Self::new_with_caller(value, std::panic::Location::caller())
  61. }
  62. /// Create a new CopyValue without an owner. This will leak memory if you don't manually drop it.
  63. pub fn leak_with_caller(value: T, caller: &'static std::panic::Location<'static>) -> Self {
  64. Self {
  65. value: GenerationalBox::leak(value, caller),
  66. origin_scope: current_scope_id().expect("in a virtual dom"),
  67. }
  68. }
  69. /// Point to another copy value
  70. pub fn point_to(&mut self, other: Self) -> BorrowResult {
  71. self.value.point_to(other.value)
  72. }
  73. pub(crate) fn new_with_caller(
  74. value: T,
  75. caller: &'static std::panic::Location<'static>,
  76. ) -> Self {
  77. let owner = current_owner();
  78. Self {
  79. value: owner.insert_rc_with_caller(value, caller),
  80. origin_scope: current_scope_id().expect("in a virtual dom"),
  81. }
  82. }
  83. /// Create a new CopyValue. The value will be stored in the given scope. When the specified scope is dropped, the value will be dropped.
  84. #[track_caller]
  85. pub fn new_maybe_sync_in_scope(value: T, scope: ScopeId) -> Self {
  86. Self::new_maybe_sync_in_scope_with_caller(value, scope, std::panic::Location::caller())
  87. }
  88. /// Create a new CopyValue with a custom caller. The value will be stored in the given scope. When the specified scope is dropped, the value will be dropped.
  89. #[track_caller]
  90. pub fn new_maybe_sync_in_scope_with_caller(
  91. value: T,
  92. scope: ScopeId,
  93. caller: &'static std::panic::Location<'static>,
  94. ) -> Self {
  95. let owner = scope.owner();
  96. Self {
  97. value: owner.insert_rc_with_caller(value, caller),
  98. origin_scope: scope,
  99. }
  100. }
  101. /// Manually drop the value in the CopyValue, invalidating the value in the process.
  102. pub fn manually_drop(&self) {
  103. self.value.manually_drop()
  104. }
  105. /// Get the scope this value was created in.
  106. pub fn origin_scope(&self) -> ScopeId {
  107. self.origin_scope
  108. }
  109. /// Get the generational id of the value.
  110. pub fn id(&self) -> GenerationalBoxId {
  111. self.value.id()
  112. }
  113. /// Get the underlying [`GenerationalBox`] value.
  114. pub fn value(&self) -> GenerationalBox<T, S> {
  115. self.value
  116. }
  117. }
  118. impl<T: 'static, S: Storage<T>> Readable for CopyValue<T, S> {
  119. type Target = T;
  120. type Storage = S;
  121. #[track_caller]
  122. fn try_read_unchecked(
  123. &self,
  124. ) -> Result<ReadableRef<'static, Self>, generational_box::BorrowError> {
  125. crate::warnings::copy_value_hoisted(self, std::panic::Location::caller());
  126. self.value.try_read()
  127. }
  128. #[track_caller]
  129. fn try_peek_unchecked(&self) -> BorrowResult<ReadableRef<'static, Self>> {
  130. crate::warnings::copy_value_hoisted(self, std::panic::Location::caller());
  131. self.value.try_read()
  132. }
  133. }
  134. impl<T: 'static, S: Storage<T>> Writable for CopyValue<T, S> {
  135. type Mut<'a, R: ?Sized + 'static> = S::Mut<'a, R>;
  136. fn map_mut<I: ?Sized, U: ?Sized, F: FnOnce(&mut I) -> &mut U>(
  137. mut_: Self::Mut<'_, I>,
  138. f: F,
  139. ) -> Self::Mut<'_, U> {
  140. S::map_mut(mut_, f)
  141. }
  142. fn try_map_mut<I: ?Sized, U: ?Sized, F: FnOnce(&mut I) -> Option<&mut U>>(
  143. mut_: Self::Mut<'_, I>,
  144. f: F,
  145. ) -> Option<Self::Mut<'_, U>> {
  146. S::try_map_mut(mut_, f)
  147. }
  148. fn downcast_lifetime_mut<'a: 'b, 'b, R: ?Sized + 'static>(
  149. mut_: Self::Mut<'a, R>,
  150. ) -> Self::Mut<'b, R> {
  151. S::downcast_lifetime_mut(mut_)
  152. }
  153. #[track_caller]
  154. fn try_write_unchecked(
  155. &self,
  156. ) -> Result<WritableRef<'static, Self>, generational_box::BorrowMutError> {
  157. crate::warnings::copy_value_hoisted(self, std::panic::Location::caller());
  158. self.value.try_write()
  159. }
  160. #[track_caller]
  161. fn set(&mut self, value: T) {
  162. crate::warnings::copy_value_hoisted(self, std::panic::Location::caller());
  163. self.value.set(value);
  164. }
  165. }
  166. impl<T: 'static, S: Storage<T>> PartialEq for CopyValue<T, S> {
  167. fn eq(&self, other: &Self) -> bool {
  168. self.value.ptr_eq(&other.value)
  169. }
  170. }
  171. impl<T: 'static, S: Storage<T>> Eq for CopyValue<T, S> {}
  172. impl<T: Copy, S: Storage<T>> Deref for CopyValue<T, S> {
  173. type Target = dyn Fn() -> T;
  174. fn deref(&self) -> &Self::Target {
  175. unsafe { Readable::deref_impl(self) }
  176. }
  177. }
  178. impl<T, S: Storage<T>> Clone for CopyValue<T, S> {
  179. fn clone(&self) -> Self {
  180. *self
  181. }
  182. }
  183. impl<T, S: Storage<T>> Copy for CopyValue<T, S> {}
  184. read_impls!(CopyValue<T, S: Storage<T>>);
  185. default_impl!(CopyValue<T, S: Storage<T>>);
  186. write_impls!(CopyValue<T, S: Storage<T>>);