Merge branch 'master' into signal-read-untracked

This commit is contained in:
ealmloff authored and GitHub committed 2023-12-07 07:12:30 -06:00
commit c67e0705ea
99 files changed
+1545 -355

No files matched your search

+1 -1
View File
@@ -100,7 +100,7 @@ impl Effect {
/// Run the effect callback immediately. Returns `true` if the effect was run. Returns `false` is the effect is dead.
pub fn try_run(&self) {
if let Some(mut callback) = self.callback.try_write() {
if let Ok(mut callback) = self.callback.try_write() {
{
self.effect_stack.effects.write().push(*self);
}
+17 -17
View File
@@ -1,7 +1,7 @@
use crate::rt::CopyValue;
use crate::signal::{ReadOnlySignal, Signal, Write};
use std::cell::{Ref, RefMut};
use generational_box::GenerationalRef;
use generational_box::GenerationalRefMut;
use std::{
fmt::{Debug, Display},
@@ -38,8 +38,8 @@ macro_rules! read_impls {
impl<T: 'static> $ty<Vec<T>> {
/// Read a value from the inner vector.
pub fn get(&self, index: usize) -> Option<Ref<'_, T>> {
Ref::filter_map(self.read(), |v| v.get(index)).ok()
pub fn get(&self, index: usize) -> Option<GenerationalRef<T>> {
GenerationalRef::filter_map(self.read(), |v| v.get(index))
}
}
@@ -52,9 +52,9 @@ macro_rules! read_impls {
self.with(|v| v.clone()).unwrap()
}
/// Attemps to read the inner value of the Option.
pub fn as_ref(&self) -> Option<Ref<'_, T>> {
Ref::filter_map(self.read(), |v| v.as_ref()).ok()
/// Attempts to read the inner value of the Option.
pub fn as_ref(&self) -> Option<GenerationalRef<T>> {
GenerationalRef::filter_map(self.read(), |v| v.as_ref())
}
}
};
@@ -182,19 +182,19 @@ macro_rules! write_impls {
}
/// Gets the value out of the Option, or inserts the given value if the Option is empty.
pub fn get_or_insert(&self, default: T) -> Ref<'_, T> {
pub fn get_or_insert(&self, default: T) -> GenerationalRef<T> {
self.get_or_insert_with(|| default)
}
/// Gets the value out of the Option, or inserts the value returned by the given function if the Option is empty.
pub fn get_or_insert_with(&self, default: impl FnOnce() -> T) -> Ref<'_, T> {
pub fn get_or_insert_with(&self, default: impl FnOnce() -> T) -> GenerationalRef<T> {
let borrow = self.read();
if borrow.is_none() {
drop(borrow);
self.with_mut(|v| *v = Some(default()));
Ref::map(self.read(), |v| v.as_ref().unwrap())
GenerationalRef::map(self.read(), |v| v.as_ref().unwrap())
} else {
Ref::map(borrow, |v| v.as_ref().unwrap())
GenerationalRef::map(borrow, |v| v.as_ref().unwrap())
}
}
}
@@ -238,15 +238,15 @@ impl<T: Clone + 'static> IntoIterator for CopyValue<Vec<T>> {
impl<T: 'static> CopyValue<Vec<T>> {
/// Write to an element in the inner vector.
pub fn get_mut(&self, index: usize) -> Option<RefMut<'_, T>> {
RefMut::filter_map(self.write(), |v| v.get_mut(index)).ok()
pub fn get_mut(&self, index: usize) -> Option<GenerationalRefMut<T>> {
GenerationalRefMut::filter_map(self.write(), |v| v.get_mut(index))
}
}
impl<T: 'static> CopyValue<Option<T>> {
/// Deref the inner value mutably.
pub fn as_mut(&self) -> Option<RefMut<'_, T>> {
RefMut::filter_map(self.write(), |v| v.as_mut()).ok()
pub fn as_mut(&self) -> Option<GenerationalRefMut<T>> {
GenerationalRefMut::filter_map(self.write(), |v| v.as_mut())
}
}
@@ -281,14 +281,14 @@ impl<T: Clone + 'static> IntoIterator for Signal<Vec<T>> {
impl<T: 'static> Signal<Vec<T>> {
/// Returns a reference to an element or `None` if out of bounds.
pub fn get_mut(&self, index: usize) -> Option<Write<'_, T, Vec<T>>> {
pub fn get_mut(&self, index: usize) -> Option<Write<T, Vec<T>>> {
Write::filter_map(self.write(), |v| v.get_mut(index))
}
}
impl<T: 'static> Signal<Option<T>> {
/// Returns a reference to an element or `None` if out of bounds.
pub fn as_mut(&self) -> Option<Write<'_, T, Option<T>>> {
pub fn as_mut(&self) -> Option<Write<T, Option<T>>> {
Write::filter_map(self.write(), |v| v.as_mut())
}
}
+29 -8
View File
@@ -1,5 +1,3 @@
use std::cell::{Ref, RefMut};
use std::mem::MaybeUninit;
use std::ops::Deref;
use std::rc::Rc;
@@ -7,7 +5,9 @@ use std::rc::Rc;
use dioxus_core::prelude::*;
use dioxus_core::ScopeId;
use generational_box::{GenerationalBox, Owner, Store};
use generational_box::{
BorrowError, BorrowMutError, GenerationalBox, GenerationalRef, GenerationalRefMut, Owner, Store,
};
use crate::Effect;
@@ -83,6 +83,7 @@ impl<T: 'static> CopyValue<T> {
/// Create a new CopyValue. The value will be stored in the current component.
///
/// Once the component this value is created in is dropped, the value will be dropped.
#[track_caller]
pub fn new(value: T) -> Self {
let owner = current_owner();
@@ -92,6 +93,22 @@ impl<T: 'static> CopyValue<T> {
}
}
pub(crate) fn new_with_caller(
value: T,
#[cfg(debug_assertions)] caller: &'static std::panic::Location<'static>,
) -> Self {
let owner = current_owner();
Self {
value: owner.insert_with_caller(
value,
#[cfg(debug_assertions)]
caller,
),
origin_scope: current_scope_id().expect("in a virtual dom"),
}
}
/// Create a new CopyValue. The value will be stored in the given scope. When the specified scope is dropped, the value will be dropped.
pub fn new_in_scope(value: T, scope: ScopeId) -> Self {
let owner = owner_in_scope(scope);
@@ -117,22 +134,26 @@ impl<T: 'static> CopyValue<T> {
}
/// Try to read the value. If the value has been dropped, this will return None.
pub fn try_read(&self) -> Option<Ref<'_, T>> {
#[track_caller]
pub fn try_read(&self) -> Result<GenerationalRef<T>, BorrowError> {
self.value.try_read()
}
/// Read the value. If the value has been dropped, this will panic.
pub fn read(&self) -> Ref<'static, T> {
#[track_caller]
pub fn read(&self) -> GenerationalRef<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<'static, T>> {
#[track_caller]
pub fn try_write(&self) -> Result<GenerationalRefMut<T>, BorrowMutError> {
self.value.try_write()
}
/// Write the value. If the value has been dropped, this will panic.
pub fn write(&self) -> RefMut<'static, T> {
#[track_caller]
pub fn write(&self) -> GenerationalRefMut<T> {
self.value.write()
}
@@ -168,7 +189,7 @@ impl<T: 'static> PartialEq for CopyValue<T> {
}
impl<T> Deref for CopyValue<T> {
type Target = dyn Fn() -> Ref<'static, T>;
type Target = dyn Fn() -> GenerationalRef<T>;
fn deref(&self) -> &Self::Target {
// https://github.com/dtolnay/case-studies/tree/master/callable-types
+58 -18
View File
@@ -1,5 +1,5 @@
use std::{
cell::{Ref, RefCell, RefMut},
cell::RefCell,
mem::MaybeUninit,
ops::{Deref, DerefMut},
rc::Rc,
@@ -10,6 +10,7 @@ use dioxus_core::{
prelude::{current_scope_id, has_context, provide_context, schedule_update_any},
ScopeId, ScopeState,
};
use generational_box::{GenerationalRef, GenerationalRefMut};
use crate::{get_effect_stack, CopyValue, Effect, EffectStack};
@@ -44,9 +45,19 @@ use crate::{get_effect_stack, CopyValue, Effect, EffectStack};
/// }
/// }
/// ```
#[track_caller]
#[must_use]
pub fn use_signal<T: 'static>(cx: &ScopeState, f: impl FnOnce() -> T) -> Signal<T> {
*cx.use_hook(|| Signal::new(f()))
#[cfg(debug_assertions)]
let caller = std::panic::Location::caller();
*cx.use_hook(|| {
Signal::new_with_caller(
f(),
#[cfg(debug_assertions)]
caller,
)
})
}
#[derive(Clone)]
@@ -138,6 +149,7 @@ impl<'de, T: serde::Deserialize<'de> + 'static> serde::Deserialize<'de> for Sign
impl<T: 'static> Signal<T> {
/// Creates a new Signal. Signals are a Copy state management solution with automatic dependency tracking.
#[track_caller]
pub fn new(value: T) -> Self {
Self {
inner: CopyValue::new(SignalData {
@@ -150,6 +162,26 @@ impl<T: 'static> Signal<T> {
}
}
/// Creates a new Signal. Signals are a Copy state management solution with automatic dependency tracking.
fn new_with_caller(
value: T,
#[cfg(debug_assertions)] caller: &'static std::panic::Location<'static>,
) -> Self {
Self {
inner: CopyValue::new_with_caller(
SignalData {
subscribers: Default::default(),
effect_subscribers: Default::default(),
update_any: schedule_update_any().expect("in a virtual dom"),
value,
effect_stack: get_effect_stack(),
},
#[cfg(debug_assertions)]
caller,
),
}
}
/// Create a new signal with a custom owner scope. The signal will be dropped when the owner scope is dropped instead of the current scope.
pub fn new_in_scope(value: T, owner: ScopeId) -> Self {
Self {
@@ -174,7 +206,8 @@ impl<T: 'static> Signal<T> {
/// Get the current value of the signal. This will subscribe the current scope to the signal. If you would like to read the signal without subscribing to it, you can use [`Self::peak`] instead.
///
/// If the signal has been dropped, this will panic.
pub fn read(&self) -> Ref<T> {
#[track_caller]
pub fn read(&self) -> GenerationalRef<T> {
let inner = self.inner.read();
if let Some(effect) = inner.effect_stack.current() {
let mut effect_subscribers = inner.effect_subscribers.borrow_mut();
@@ -198,7 +231,7 @@ impl<T: 'static> Signal<T> {
}
}
}
Ref::map(inner, |v| &v.value)
GenerationalRef::map(inner, |v| &v.value)
}
/// Get the current value of the signal. **Unlike read, this will not subscribe the current scope to the signal which can cause parts of your UI to not update.**
@@ -212,9 +245,10 @@ impl<T: 'static> Signal<T> {
/// Get a mutable reference to the signal's value.
///
/// If the signal has been dropped, this will panic.
pub fn write(&self) -> Write<'_, T> {
#[track_caller]
pub fn write(&self) -> Write<T> {
let inner = self.inner.write();
let borrow = RefMut::map(inner, |v| &mut v.value);
let borrow = GenerationalRefMut::map(inner, |v| &mut v.value);
Write {
write: borrow,
signal: SignalSubscriberDrop { signal: *self },
@@ -250,12 +284,14 @@ impl<T: 'static> Signal<T> {
}
/// Set the value of the signal. This will trigger an update on all subscribers.
#[track_caller]
pub fn set(&self, value: T) {
*self.write() = value;
}
/// Run a closure with a reference to the signal's value.
/// If the signal has been dropped, this will panic.
#[track_caller]
pub fn with<O>(&self, f: impl FnOnce(&T) -> O) -> O {
let write = self.read();
f(&*write)
@@ -263,6 +299,7 @@ impl<T: 'static> Signal<T> {
/// Run a closure with a mutable reference to the signal's value.
/// If the signal has been dropped, this will panic.
#[track_caller]
pub fn with_mut<O>(&self, f: impl FnOnce(&mut T) -> O) -> O {
let mut write = self.write();
f(&mut *write)
@@ -272,6 +309,7 @@ impl<T: 'static> Signal<T> {
impl<T: Clone + 'static> Signal<T> {
/// Get the current value of the signal. This will subscribe the current scope to the signal.
/// If the signal has been dropped, this will panic.
#[track_caller]
pub fn value(&self) -> T {
self.read().clone()
}
@@ -291,7 +329,7 @@ impl<T: 'static> PartialEq for Signal<T> {
}
impl<T> Deref for Signal<T> {
type Target = dyn Fn() -> Ref<'static, T>;
type Target = dyn Fn() -> GenerationalRef<T>;
fn deref(&self) -> &Self::Target {
// https://github.com/dtolnay/case-studies/tree/master/callable-types
@@ -334,17 +372,17 @@ impl<T: 'static> Drop for SignalSubscriberDrop<T> {
}
/// A mutable reference to a signal's value.
pub struct Write<'a, T: 'static, I: 'static = T> {
write: RefMut<'a, T>,
pub struct Write<T: 'static, I: 'static = T> {
write: GenerationalRefMut<T>,
signal: SignalSubscriberDrop<I>,
}
impl<'a, T: 'static, I: 'static> Write<'a, T, I> {
impl<T: 'static, I: 'static> Write<T, I> {
/// Map the mutable reference to the signal's value to a new type.
pub fn map<O>(myself: Self, f: impl FnOnce(&mut T) -> &mut O) -> Write<'a, O, I> {
pub fn map<O>(myself: Self, f: impl FnOnce(&mut T) -> &mut O) -> Write<O, I> {
let Self { write, signal } = myself;
Write {
write: RefMut::map(write, f),
write: GenerationalRefMut::map(write, f),
signal,
}
}
@@ -353,14 +391,14 @@ impl<'a, T: 'static, I: 'static> Write<'a, T, I> {
pub fn filter_map<O>(
myself: Self,
f: impl FnOnce(&mut T) -> Option<&mut O>,
) -> Option<Write<'a, O, I>> {
) -> Option<Write<O, I>> {
let Self { write, signal } = myself;
let write = RefMut::filter_map(write, f).ok();
let write = GenerationalRefMut::filter_map(write, f);
write.map(|write| Write { write, signal })
}
}
impl<'a, T: 'static, I: 'static> Deref for Write<'a, T, I> {
impl<T: 'static, I: 'static> Deref for Write<T, I> {
type Target = T;
fn deref(&self) -> &Self::Target {
@@ -368,7 +406,7 @@ impl<'a, T: 'static, I: 'static> Deref for Write<'a, T, I> {
}
}
impl<T, I> DerefMut for Write<'_, T, I> {
impl<T, I> DerefMut for Write<T, I> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.write
}
@@ -393,7 +431,8 @@ impl<T: 'static> ReadOnlySignal<T> {
/// Get the current value of the signal. This will subscribe the current scope to the signal. If you would like to read the signal without subscribing to it, you can use [`Self::peak`] instead.
///
/// If the signal has been dropped, this will panic.
pub fn read(&self) -> Ref<T> {
#[track_caller]
pub fn read(&self) -> GenerationalRef<T> {
self.inner.read()
}
@@ -405,6 +444,7 @@ impl<T: 'static> ReadOnlySignal<T> {
}
/// Run a closure with a reference to the signal's value.
#[track_caller]
pub fn with<O>(&self, f: impl FnOnce(&T) -> O) -> O {
self.inner.with(f)
}
@@ -424,7 +464,7 @@ impl<T: 'static> PartialEq for ReadOnlySignal<T> {
}
impl<T> Deref for ReadOnlySignal<T> {
type Target = dyn Fn() -> Ref<'static, T>;
type Target = dyn Fn() -> GenerationalRef<T>;
fn deref(&self) -> &Self::Target {
// https://github.com/dtolnay/case-studies/tree/master/callable-types