|
@@ -1,5 +1,6 @@
|
|
|
use std::{
|
|
|
cell::{Ref, RefCell, RefMut},
|
|
|
+ mem::MaybeUninit,
|
|
|
ops::{Deref, DerefMut},
|
|
|
rc::Rc,
|
|
|
sync::Arc,
|
|
@@ -43,6 +44,7 @@ use crate::{CopyValue, Effect};
|
|
|
/// }
|
|
|
/// }
|
|
|
/// ```
|
|
|
+#[must_use]
|
|
|
pub fn use_signal<T: 'static>(cx: &ScopeState, f: impl FnOnce() -> T) -> Signal<T> {
|
|
|
*cx.use_hook(|| Signal::new(f()))
|
|
|
}
|
|
@@ -275,6 +277,39 @@ impl<T: 'static> PartialEq for Signal<T> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+impl<T> Deref for Signal<T> {
|
|
|
+ type Target = dyn Fn() -> Ref<'static, T>;
|
|
|
+
|
|
|
+ fn deref(&self) -> &Self::Target {
|
|
|
+ // https://github.com/dtolnay/case-studies/tree/master/callable-types
|
|
|
+
|
|
|
+ // First we create a closure that captures something with the Same in memory layout as Self (MaybeUninit<Self>).
|
|
|
+ let uninit_callable = MaybeUninit::<Self>::uninit();
|
|
|
+ // Then move that value into the closure. We assume that the closure now has a in memory layout of Self.
|
|
|
+ let uninit_closure = move || Self::read(unsafe { &*uninit_callable.as_ptr() });
|
|
|
+
|
|
|
+ // Check that the size of the closure is the same as the size of Self in case the compiler changed the layout of the closure.
|
|
|
+ let size_of_closure = std::mem::size_of_val(&uninit_closure);
|
|
|
+ assert_eq!(size_of_closure, std::mem::size_of::<Self>());
|
|
|
+
|
|
|
+ // Then cast the lifetime of the closure to the lifetime of &self.
|
|
|
+ fn cast_lifetime<'a, T>(_a: &T, b: &'a T) -> &'a T {
|
|
|
+ b
|
|
|
+ }
|
|
|
+ let reference_to_closure = cast_lifetime(
|
|
|
+ {
|
|
|
+ // The real closure that we will never use.
|
|
|
+ &uninit_closure
|
|
|
+ },
|
|
|
+ // We transmute self into a reference to the closure. This is safe because we know that the closure has the same memory layout as Self so &Closure == &Self.
|
|
|
+ unsafe { std::mem::transmute(self) },
|
|
|
+ );
|
|
|
+
|
|
|
+ // Cast the closure to a trait object.
|
|
|
+ reference_to_closure as &Self::Target
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
struct SignalSubscriberDrop<T: 'static> {
|
|
|
signal: Signal<T>,
|
|
|
}
|
|
@@ -312,7 +347,7 @@ impl<'a, T: 'static, I: 'static> Write<'a, T, I> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<'a, T: 'static> Deref for Write<'a, T> {
|
|
|
+impl<'a, T: 'static, I: 'static> Deref for Write<'a, T, I> {
|
|
|
type Target = T;
|
|
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
@@ -320,7 +355,7 @@ impl<'a, T: 'static> Deref for Write<'a, T> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T> DerefMut for Write<'_, T> {
|
|
|
+impl<T, I> DerefMut for Write<'_, T, I> {
|
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
|
&mut self.write
|
|
|
}
|
|
@@ -365,3 +400,36 @@ impl<T: 'static> PartialEq for ReadOnlySignal<T> {
|
|
|
self.inner == other.inner
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+impl<T> Deref for ReadOnlySignal<T> {
|
|
|
+ type Target = dyn Fn() -> Ref<'static, T>;
|
|
|
+
|
|
|
+ fn deref(&self) -> &Self::Target {
|
|
|
+ // https://github.com/dtolnay/case-studies/tree/master/callable-types
|
|
|
+
|
|
|
+ // First we create a closure that captures something with the Same in memory layout as Self (MaybeUninit<Self>).
|
|
|
+ let uninit_callable = MaybeUninit::<Self>::uninit();
|
|
|
+ // Then move that value into the closure. We assume that the closure now has a in memory layout of Self.
|
|
|
+ let uninit_closure = move || Self::read(unsafe { &*uninit_callable.as_ptr() });
|
|
|
+
|
|
|
+ // Check that the size of the closure is the same as the size of Self in case the compiler changed the layout of the closure.
|
|
|
+ let size_of_closure = std::mem::size_of_val(&uninit_closure);
|
|
|
+ assert_eq!(size_of_closure, std::mem::size_of::<Self>());
|
|
|
+
|
|
|
+ // Then cast the lifetime of the closure to the lifetime of &self.
|
|
|
+ fn cast_lifetime<'a, T>(_a: &T, b: &'a T) -> &'a T {
|
|
|
+ b
|
|
|
+ }
|
|
|
+ let reference_to_closure = cast_lifetime(
|
|
|
+ {
|
|
|
+ // The real closure that we will never use.
|
|
|
+ &uninit_closure
|
|
|
+ },
|
|
|
+ // We transmute self into a reference to the closure. This is safe because we know that the closure has the same memory layout as Self so &Closure == &Self.
|
|
|
+ unsafe { std::mem::transmute(self) },
|
|
|
+ );
|
|
|
+
|
|
|
+ // Cast the closure to a trait object.
|
|
|
+ reference_to_closure as &Self::Target
|
|
|
+ }
|
|
|
+}
|