Merge branch 'master' into jk/loop-allocation-strategy

This commit is contained in:
Jonathan Kelley committed 2023-10-17 15:27:20 -07:00
commit 55ad41b392
25 files changed
+160 -11

No files matched your search

+38 -3
View File
@@ -1,5 +1,7 @@
use std::cell::{Ref, RefMut};
use std::mem::MaybeUninit;
use std::ops::Deref;
use std::rc::Rc;
use dioxus_core::prelude::*;
@@ -120,17 +122,17 @@ impl<T: 'static> CopyValue<T> {
}
/// Read the value. If the value has been dropped, this will panic.
pub fn read(&self) -> Ref<'_, T> {
pub fn read(&self) -> Ref<'static, T> {
self.value.read()
}
/// Try to write the value. If the value has been dropped, this will return None.
pub fn try_write(&self) -> Option<RefMut<'_, T>> {
pub fn try_write(&self) -> Option<RefMut<'static, T>> {
self.value.try_write()
}
/// Write the value. If the value has been dropped, this will panic.
pub fn write(&self) -> RefMut<'_, T> {
pub fn write(&self) -> RefMut<'static, T> {
self.value.write()
}
@@ -164,3 +166,36 @@ impl<T: 'static> PartialEq for CopyValue<T> {
self.value.ptr_eq(&other.value)
}
}
impl<T> Deref for CopyValue<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
}
}
+2
View File
@@ -21,6 +21,7 @@ use crate::{get_effect_stack, signal::SignalData, CopyValue, Effect, ReadOnlySig
/// render! { "{double}" }
/// }
/// ```
#[must_use = "Consider using `use_effect` to rerun a callback when dependencies change"]
pub fn use_selector<R: PartialEq>(
cx: &ScopeState,
f: impl FnMut() -> R + 'static,
@@ -44,6 +45,7 @@ pub fn use_selector<R: PartialEq>(
/// render! { "{double}" }
/// }
/// ```
#[must_use = "Consider using `use_effect` to rerun a callback when dependencies change"]
pub fn use_selector_with_dependencies<R: PartialEq, D: Dependency>(
cx: &ScopeState,
dependencies: D,
+70 -2
View File
@@ -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
}
}