convert T into signals automatically

This commit is contained in:
Evan Almloff committed 2024-01-29 13:36:39 -06:00
1 parent 1847c737e9
commit 50e3216d8b
14 files changed
+441 -103

No files matched your search

+1 -1
View File
@@ -32,7 +32,7 @@ mod global;
pub use global::*;
mod impls;
pub use generational_box::{Storage, SyncStorage, UnsyncStorage};
pub use generational_box::{AnyStorage, Owner, Storage, SyncStorage, UnsyncStorage};
mod read;
pub use read::*;
+81 -5
View File
@@ -1,8 +1,12 @@
use generational_box::AnyStorage;
use generational_box::GenerationalBoxId;
use generational_box::SyncStorage;
use generational_box::UnsyncStorage;
use std::any::Any;
use std::any::TypeId;
use std::cell::RefCell;
use std::mem::MaybeUninit;
use std::ops::Deref;
use std::rc::Rc;
use dioxus_core::prelude::*;
use dioxus_core::ScopeId;
@@ -13,7 +17,72 @@ use crate::Effect;
use crate::Readable;
use crate::Writable;
fn current_owner<S: Storage<T>, T>() -> Rc<Owner<S>> {
/// Run a closure with the given owner.
pub fn with_owner<S: AnyStorage, F: FnOnce() -> R, R>(owner: Owner<S>, f: F) -> R {
let old_owner = set_owner(Some(owner));
let result = f();
set_owner(old_owner);
result
}
/// Set the owner for the current thread.
fn set_owner<S: AnyStorage>(owner: Option<Owner<S>>) -> Option<Owner<S>> {
let id = TypeId::of::<S>();
if id == TypeId::of::<SyncStorage>() {
SYNC_OWNER.with(|cell| {
std::mem::replace(
&mut *cell.borrow_mut(),
owner.map(|owner| {
*(Box::new(owner) as Box<dyn Any>)
.downcast::<Owner<SyncStorage>>()
.unwrap()
}),
)
.map(|owner| *(Box::new(owner) as Box<dyn Any>).downcast().unwrap())
})
} else {
UNSYNC_OWNER.with(|cell| {
std::mem::replace(
&mut *cell.borrow_mut(),
owner.map(|owner| {
*(Box::new(owner) as Box<dyn Any>)
.downcast::<Owner<UnsyncStorage>>()
.unwrap()
}),
)
.map(|owner| *(Box::new(owner) as Box<dyn Any>).downcast().unwrap())
})
}
}
thread_local! {
static SYNC_OWNER: RefCell<Option<Owner<SyncStorage>>> = RefCell::new(None);
static UNSYNC_OWNER: RefCell<Option<Owner<UnsyncStorage>>> = RefCell::new(None);
}
fn current_owner<S: Storage<T>, T>() -> Owner<S> {
let id = TypeId::of::<S>();
let override_owner = if id == TypeId::of::<SyncStorage>() {
SYNC_OWNER.with(|cell| {
cell.borrow().clone().map(|owner| {
*(Box::new(owner) as Box<dyn Any>)
.downcast::<Owner<S>>()
.unwrap()
})
})
} else {
UNSYNC_OWNER.with(|cell| {
cell.borrow().clone().map(|owner| {
*(Box::new(owner) as Box<dyn Any>)
.downcast::<Owner<S>>()
.unwrap()
})
})
};
if let Some(owner) = override_owner {
return owner;
}
match Effect::current() {
// If we are inside of an effect, we should use the owner of the effect as the owner of the value.
Some(effect) => {
@@ -24,18 +93,18 @@ fn current_owner<S: Storage<T>, T>() -> Rc<Owner<S>> {
None => match has_context() {
Some(rt) => rt,
None => {
let owner = Rc::new(S::owner());
let owner = S::owner();
provide_context(owner)
}
},
}
}
fn owner_in_scope<S: Storage<T>, T>(scope: ScopeId) -> Rc<Owner<S>> {
fn owner_in_scope<S: Storage<T>, T>(scope: ScopeId) -> Owner<S> {
match consume_context_from_scope(scope) {
Some(rt) => rt,
None => {
let owner = Rc::new(S::owner());
let owner = S::owner();
scope.provide_context(owner)
}
}
@@ -128,6 +197,13 @@ impl<T: 'static, S: Storage<T>> CopyValue<T, S> {
}
}
/// Take the value out of the CopyValue, invalidating the value in the process.
pub fn take(&self) -> T {
self.value
.take()
.expect("value is already dropped or borrowed")
}
pub(crate) fn invalid() -> Self {
let owner = current_owner();
+5 -1
View File
@@ -5,7 +5,6 @@ use crate::{
use std::{
any::Any,
cell::RefCell,
mem::MaybeUninit,
ops::{Deref, DerefMut},
rc::Rc,
sync::Arc,
@@ -348,6 +347,11 @@ impl<T: 'static, S: Storage<SignalData<T>>> Signal<T, S> {
}
}
/// Take the value out of the signal, invalidating the signal in the process.
pub fn take(&self) -> T {
self.inner.take().value
}
/// Get the scope the signal was created in.
pub fn origin_scope(&self) -> ScopeId {
self.inner.origin_scope()