create read only signal
This commit is contained in:
1 parent
6ca170453b
commit
646c161c7d
7 files changed
+287
-236
No files matched your search
+2
-2
@@ -25,7 +25,7 @@ members = [
|
|||||||
"packages/native-core",
|
"packages/native-core",
|
||||||
"packages/native-core-macro",
|
"packages/native-core-macro",
|
||||||
"packages/rsx-rosetta",
|
"packages/rsx-rosetta",
|
||||||
"packages/generational_box",
|
"packages/generational-box",
|
||||||
"packages/signals",
|
"packages/signals",
|
||||||
"packages/hot-reload",
|
"packages/hot-reload",
|
||||||
"packages/fullstack",
|
"packages/fullstack",
|
||||||
@@ -77,7 +77,7 @@ dioxus-native-core = { path = "packages/native-core", version = "0.4.0" }
|
|||||||
dioxus-native-core-macro = { path = "packages/native-core-macro", version = "0.4.0" }
|
dioxus-native-core-macro = { path = "packages/native-core-macro", version = "0.4.0" }
|
||||||
rsx-rosetta = { path = "packages/rsx-rosetta", version = "0.4.0" }
|
rsx-rosetta = { path = "packages/rsx-rosetta", version = "0.4.0" }
|
||||||
dioxus-signals = { path = "packages/signals" }
|
dioxus-signals = { path = "packages/signals" }
|
||||||
generational-box = { path = "packages/generational_box" }
|
generational-box = { path = "packages/generational-box" }
|
||||||
dioxus-hot-reload = { path = "packages/hot-reload", version = "0.4.0" }
|
dioxus-hot-reload = { path = "packages/hot-reload", version = "0.4.0" }
|
||||||
dioxus-fullstack = { path = "packages/fullstack", version = "0.4.1" }
|
dioxus-fullstack = { path = "packages/fullstack", version = "0.4.1" }
|
||||||
dioxus_server_macro = { path = "packages/server-macro", version = "0.4.1" }
|
dioxus_server_macro = { path = "packages/server-macro", version = "0.4.1" }
|
||||||
|
|||||||
File renamed without changes.
File renamed without changes.
@@ -1,5 +1,5 @@
|
|||||||
use crate::rt::CopyValue;
|
use crate::rt::CopyValue;
|
||||||
use crate::{Signal, Write};
|
use crate::signal::{ReadOnlySignal, Signal, Write};
|
||||||
|
|
||||||
use std::cell::{Ref, RefMut};
|
use std::cell::{Ref, RefMut};
|
||||||
|
|
||||||
@@ -8,11 +8,11 @@ use std::{
|
|||||||
ops::{Add, Div, Mul, Sub},
|
ops::{Add, Div, Mul, Sub},
|
||||||
};
|
};
|
||||||
|
|
||||||
macro_rules! impls {
|
macro_rules! read_impls {
|
||||||
($ty:ident) => {
|
($ty:ident) => {
|
||||||
impl<T: Default + 'static> Default for $ty<T> {
|
impl<T: Default + 'static> Default for $ty<T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new(T::default())
|
Self::new(Default::default())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,6 +36,29 @@ macro_rules! impls {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: 'static> $ty<Vec<T>> {
|
||||||
|
pub fn get(&self, index: usize) -> Option<Ref<'_, T>> {
|
||||||
|
Ref::filter_map(self.read(), |v| v.get(index)).ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: 'static> $ty<Option<T>> {
|
||||||
|
pub fn unwrap(&self) -> T
|
||||||
|
where
|
||||||
|
T: Clone,
|
||||||
|
{
|
||||||
|
self.with(|v| v.clone()).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_ref(&self) -> Option<Ref<'_, T>> {
|
||||||
|
Ref::filter_map(self.read(), |v| v.as_ref()).ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! write_impls {
|
||||||
|
($ty:ident) => {
|
||||||
impl<T: Add<Output = T> + Copy + 'static> std::ops::AddAssign<T> for $ty<T> {
|
impl<T: Add<Output = T> + Copy + 'static> std::ops::AddAssign<T> for $ty<T> {
|
||||||
fn add_assign(&mut self, rhs: T) {
|
fn add_assign(&mut self, rhs: T) {
|
||||||
self.with_mut(|v| *v = *v + rhs)
|
self.with_mut(|v| *v = *v + rhs)
|
||||||
@@ -100,10 +123,6 @@ macro_rules! impls {
|
|||||||
pub fn split_off(&self, at: usize) -> Vec<T> {
|
pub fn split_off(&self, at: usize) -> Vec<T> {
|
||||||
self.with_mut(|v| v.split_off(at))
|
self.with_mut(|v| v.split_off(at))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, index: usize) -> Option<Ref<'_, T>> {
|
|
||||||
Ref::filter_map(self.read(), |v| v.get(index)).ok()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> $ty<Option<T>> {
|
impl<T: 'static> $ty<Option<T>> {
|
||||||
@@ -115,17 +134,6 @@ macro_rules! impls {
|
|||||||
self.with_mut(|v| v.replace(value))
|
self.with_mut(|v| v.replace(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unwrap(&self) -> T
|
|
||||||
where
|
|
||||||
T: Clone,
|
|
||||||
{
|
|
||||||
self.with(|v| v.clone()).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_ref(&self) -> Option<Ref<'_, T>> {
|
|
||||||
Ref::filter_map(self.read(), |v| v.as_ref()).ok()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_or_insert(&self, default: T) -> Ref<'_, T> {
|
pub fn get_or_insert(&self, default: T) -> Ref<'_, T> {
|
||||||
self.get_or_insert_with(|| default)
|
self.get_or_insert_with(|| default)
|
||||||
}
|
}
|
||||||
@@ -144,8 +152,11 @@ macro_rules! impls {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impls!(CopyValue);
|
read_impls!(CopyValue);
|
||||||
impls!(Signal);
|
write_impls!(CopyValue);
|
||||||
|
read_impls!(Signal);
|
||||||
|
write_impls!(Signal);
|
||||||
|
read_impls!(ReadOnlySignal);
|
||||||
|
|
||||||
pub struct CopyValueIterator<T: 'static> {
|
pub struct CopyValueIterator<T: 'static> {
|
||||||
index: usize,
|
index: usize,
|
||||||
|
|||||||
+2
-209
@@ -1,10 +1,3 @@
|
|||||||
use std::{
|
|
||||||
cell::{Ref, RefCell, RefMut},
|
|
||||||
ops::{Deref, DerefMut},
|
|
||||||
rc::Rc,
|
|
||||||
sync::Arc,
|
|
||||||
};
|
|
||||||
|
|
||||||
mod rt;
|
mod rt;
|
||||||
pub use rt::*;
|
pub use rt::*;
|
||||||
mod effect;
|
mod effect;
|
||||||
@@ -12,205 +5,5 @@ pub use effect::*;
|
|||||||
mod impls;
|
mod impls;
|
||||||
mod memo;
|
mod memo;
|
||||||
pub use memo::*;
|
pub use memo::*;
|
||||||
|
pub(crate) mod signal;
|
||||||
use dioxus_core::{
|
pub use signal::*;
|
||||||
prelude::{current_scope_id, has_context, provide_context, schedule_update_any},
|
|
||||||
ScopeId, ScopeState,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn use_signal<T: 'static>(cx: &ScopeState, f: impl FnOnce() -> T) -> Signal<T> {
|
|
||||||
*cx.use_hook(|| Signal::new(f()))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct Unsubscriber {
|
|
||||||
scope: ScopeId,
|
|
||||||
subscribers: Rc<RefCell<Vec<Rc<RefCell<Vec<ScopeId>>>>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for Unsubscriber {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
for subscribers in self.subscribers.borrow().iter() {
|
|
||||||
subscribers.borrow_mut().retain(|s| *s != self.scope);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn current_unsubscriber() -> Unsubscriber {
|
|
||||||
match has_context() {
|
|
||||||
Some(rt) => rt,
|
|
||||||
None => {
|
|
||||||
let owner = Unsubscriber {
|
|
||||||
scope: current_scope_id().expect("in a virtual dom"),
|
|
||||||
subscribers: Default::default(),
|
|
||||||
};
|
|
||||||
provide_context(owner).expect("in a virtual dom")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SignalData<T> {
|
|
||||||
subscribers: Rc<RefCell<Vec<ScopeId>>>,
|
|
||||||
effect_subscribers: Rc<RefCell<Vec<Effect>>>,
|
|
||||||
update_any: Arc<dyn Fn(ScopeId)>,
|
|
||||||
pub(crate) value: T,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Signal<T: 'static> {
|
|
||||||
pub(crate) inner: CopyValue<SignalData<T>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: 'static> Signal<T> {
|
|
||||||
pub fn new(value: T) -> Self {
|
|
||||||
Self {
|
|
||||||
inner: CopyValue::new(SignalData {
|
|
||||||
subscribers: Default::default(),
|
|
||||||
effect_subscribers: Default::default(),
|
|
||||||
update_any: schedule_update_any().expect("in a virtual dom"),
|
|
||||||
value,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn origin_scope(&self) -> ScopeId {
|
|
||||||
self.inner.origin_scope()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read(&self) -> Ref<T> {
|
|
||||||
let inner = self.inner.read();
|
|
||||||
if let Some(effect) = Effect::current() {
|
|
||||||
let mut effect_subscribers = inner.effect_subscribers.borrow_mut();
|
|
||||||
if !effect_subscribers.contains(&effect) {
|
|
||||||
effect_subscribers.push(effect);
|
|
||||||
}
|
|
||||||
} else if let Some(current_scope_id) = current_scope_id() {
|
|
||||||
log::trace!(
|
|
||||||
"{:?} subscribed to {:?}",
|
|
||||||
self.inner.value,
|
|
||||||
current_scope_id
|
|
||||||
);
|
|
||||||
let mut subscribers = inner.subscribers.borrow_mut();
|
|
||||||
if !subscribers.contains(¤t_scope_id) {
|
|
||||||
subscribers.push(current_scope_id);
|
|
||||||
drop(subscribers);
|
|
||||||
let unsubscriber = current_unsubscriber();
|
|
||||||
inner.subscribers.borrow_mut().push(unsubscriber.scope);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ref::map(inner, |v| &v.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write(&self) -> Write<'_, T> {
|
|
||||||
let inner = self.inner.write();
|
|
||||||
let borrow = RefMut::map(inner, |v| &mut v.value);
|
|
||||||
Write {
|
|
||||||
write: borrow,
|
|
||||||
signal: SignalSubscriberDrop { signal: *self },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_subscribers(&self) {
|
|
||||||
{
|
|
||||||
let inner = self.inner.read();
|
|
||||||
for &scope_id in &*inner.subscribers.borrow() {
|
|
||||||
log::trace!(
|
|
||||||
"Write on {:?} triggered update on {:?}",
|
|
||||||
self.inner.value,
|
|
||||||
scope_id
|
|
||||||
);
|
|
||||||
(inner.update_any)(scope_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let subscribers = {
|
|
||||||
let self_read = self.inner.read();
|
|
||||||
let mut effects = self_read.effect_subscribers.borrow_mut();
|
|
||||||
std::mem::take(&mut *effects)
|
|
||||||
};
|
|
||||||
for effect in subscribers {
|
|
||||||
log::trace!(
|
|
||||||
"Write on {:?} triggered effect {:?}",
|
|
||||||
self.inner.value,
|
|
||||||
effect
|
|
||||||
);
|
|
||||||
effect.try_run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set(&self, value: T) {
|
|
||||||
*self.write() = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with<O>(&self, f: impl FnOnce(&T) -> O) -> O {
|
|
||||||
let write = self.read();
|
|
||||||
f(&*write)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_mut<O>(&self, f: impl FnOnce(&mut T) -> O) -> O {
|
|
||||||
let mut write = self.write();
|
|
||||||
f(&mut *write)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Clone + 'static> Signal<T> {
|
|
||||||
pub fn value(&self) -> T {
|
|
||||||
self.read().clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: 'static> PartialEq for Signal<T> {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.inner == other.inner
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SignalSubscriberDrop<T: 'static> {
|
|
||||||
signal: Signal<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: 'static> Drop for SignalSubscriberDrop<T> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
self.signal.update_subscribers();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Write<'a, T: 'static, I: 'static = T> {
|
|
||||||
write: RefMut<'a, T>,
|
|
||||||
signal: SignalSubscriberDrop<I>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T: 'static, I: 'static> Write<'a, T, I> {
|
|
||||||
pub fn map<O>(myself: Self, f: impl FnOnce(&mut T) -> &mut O) -> Write<'a, O, I> {
|
|
||||||
let Self { write, signal } = myself;
|
|
||||||
Write {
|
|
||||||
write: RefMut::map(write, f),
|
|
||||||
signal,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn filter_map<O>(
|
|
||||||
myself: Self,
|
|
||||||
f: impl FnOnce(&mut T) -> Option<&mut O>,
|
|
||||||
) -> Option<Write<'a, O, I>> {
|
|
||||||
let Self { write, signal } = myself;
|
|
||||||
let write = RefMut::filter_map(write, f).ok();
|
|
||||||
write.map(|write| Write {
|
|
||||||
write,
|
|
||||||
signal: signal,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T: 'static> Deref for Write<'a, T> {
|
|
||||||
type Target = T;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&*self.write
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> DerefMut for Write<'_, T> {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
&mut *self.write
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,15 @@
|
|||||||
use dioxus_core::prelude::*;
|
use dioxus_core::prelude::*;
|
||||||
|
|
||||||
use crate::{get_effect_stack, CopyValue, Effect, Signal, SignalData};
|
use crate::{get_effect_stack, signal::SignalData, CopyValue, Effect, ReadOnlySignal, Signal};
|
||||||
|
|
||||||
pub fn use_memo<R: PartialEq>(cx: &ScopeState, f: impl FnMut() -> R + 'static) -> Signal<R> {
|
pub fn use_selector<R: PartialEq>(
|
||||||
*cx.use_hook(|| memo(f))
|
cx: &ScopeState,
|
||||||
|
f: impl FnMut() -> R + 'static,
|
||||||
|
) -> ReadOnlySignal<R> {
|
||||||
|
*cx.use_hook(|| selector(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn memo<R: PartialEq>(mut f: impl FnMut() -> R + 'static) -> Signal<R> {
|
fn selector<R: PartialEq>(mut f: impl FnMut() -> R + 'static) -> ReadOnlySignal<R> {
|
||||||
let state = Signal::<R> {
|
let state = Signal::<R> {
|
||||||
inner: CopyValue::invalid(),
|
inner: CopyValue::invalid(),
|
||||||
};
|
};
|
||||||
@@ -38,5 +41,5 @@ pub fn memo<R: PartialEq>(mut f: impl FnMut() -> R + 'static) -> Signal<R> {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
state
|
ReadOnlySignal::new(state)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,244 @@
|
|||||||
|
use std::{
|
||||||
|
cell::{Ref, RefCell, RefMut},
|
||||||
|
ops::{Deref, DerefMut},
|
||||||
|
rc::Rc,
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
|
use dioxus_core::{
|
||||||
|
prelude::{current_scope_id, has_context, provide_context, schedule_update_any},
|
||||||
|
ScopeId, ScopeState,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{CopyValue, Effect};
|
||||||
|
|
||||||
|
pub fn use_signal<T: 'static>(cx: &ScopeState, f: impl FnOnce() -> T) -> Signal<T> {
|
||||||
|
*cx.use_hook(|| Signal::new(f()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Unsubscriber {
|
||||||
|
scope: ScopeId,
|
||||||
|
subscribers: Rc<RefCell<Vec<Rc<RefCell<Vec<ScopeId>>>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Unsubscriber {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
for subscribers in self.subscribers.borrow().iter() {
|
||||||
|
subscribers.borrow_mut().retain(|s| *s != self.scope);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current_unsubscriber() -> Unsubscriber {
|
||||||
|
match has_context() {
|
||||||
|
Some(rt) => rt,
|
||||||
|
None => {
|
||||||
|
let owner = Unsubscriber {
|
||||||
|
scope: current_scope_id().expect("in a virtual dom"),
|
||||||
|
subscribers: Default::default(),
|
||||||
|
};
|
||||||
|
provide_context(owner).expect("in a virtual dom")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct SignalData<T> {
|
||||||
|
pub(crate) subscribers: Rc<RefCell<Vec<ScopeId>>>,
|
||||||
|
pub(crate) effect_subscribers: Rc<RefCell<Vec<Effect>>>,
|
||||||
|
pub(crate) update_any: Arc<dyn Fn(ScopeId)>,
|
||||||
|
pub(crate) value: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Signal<T: 'static> {
|
||||||
|
pub(crate) inner: CopyValue<SignalData<T>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: 'static> Signal<T> {
|
||||||
|
pub fn new(value: T) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: CopyValue::new(SignalData {
|
||||||
|
subscribers: Default::default(),
|
||||||
|
effect_subscribers: Default::default(),
|
||||||
|
update_any: schedule_update_any().expect("in a virtual dom"),
|
||||||
|
value,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn origin_scope(&self) -> ScopeId {
|
||||||
|
self.inner.origin_scope()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read(&self) -> Ref<T> {
|
||||||
|
let inner = self.inner.read();
|
||||||
|
if let Some(effect) = Effect::current() {
|
||||||
|
let mut effect_subscribers = inner.effect_subscribers.borrow_mut();
|
||||||
|
if !effect_subscribers.contains(&effect) {
|
||||||
|
effect_subscribers.push(effect);
|
||||||
|
}
|
||||||
|
} else if let Some(current_scope_id) = current_scope_id() {
|
||||||
|
log::trace!(
|
||||||
|
"{:?} subscribed to {:?}",
|
||||||
|
self.inner.value,
|
||||||
|
current_scope_id
|
||||||
|
);
|
||||||
|
let mut subscribers = inner.subscribers.borrow_mut();
|
||||||
|
if !subscribers.contains(¤t_scope_id) {
|
||||||
|
subscribers.push(current_scope_id);
|
||||||
|
drop(subscribers);
|
||||||
|
let unsubscriber = current_unsubscriber();
|
||||||
|
inner.subscribers.borrow_mut().push(unsubscriber.scope);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ref::map(inner, |v| &v.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(&self) -> Write<'_, T> {
|
||||||
|
let inner = self.inner.write();
|
||||||
|
let borrow = RefMut::map(inner, |v| &mut v.value);
|
||||||
|
Write {
|
||||||
|
write: borrow,
|
||||||
|
signal: SignalSubscriberDrop { signal: *self },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_subscribers(&self) {
|
||||||
|
{
|
||||||
|
let inner = self.inner.read();
|
||||||
|
for &scope_id in &*inner.subscribers.borrow() {
|
||||||
|
log::trace!(
|
||||||
|
"Write on {:?} triggered update on {:?}",
|
||||||
|
self.inner.value,
|
||||||
|
scope_id
|
||||||
|
);
|
||||||
|
(inner.update_any)(scope_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let subscribers = {
|
||||||
|
let self_read = self.inner.read();
|
||||||
|
let mut effects = self_read.effect_subscribers.borrow_mut();
|
||||||
|
std::mem::take(&mut *effects)
|
||||||
|
};
|
||||||
|
for effect in subscribers {
|
||||||
|
log::trace!(
|
||||||
|
"Write on {:?} triggered effect {:?}",
|
||||||
|
self.inner.value,
|
||||||
|
effect
|
||||||
|
);
|
||||||
|
effect.try_run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set(&self, value: T) {
|
||||||
|
*self.write() = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with<O>(&self, f: impl FnOnce(&T) -> O) -> O {
|
||||||
|
let write = self.read();
|
||||||
|
f(&*write)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_mut<O>(&self, f: impl FnOnce(&mut T) -> O) -> O {
|
||||||
|
let mut write = self.write();
|
||||||
|
f(&mut *write)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Clone + 'static> Signal<T> {
|
||||||
|
pub fn value(&self) -> T {
|
||||||
|
self.read().clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: 'static> PartialEq for Signal<T> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.inner == other.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SignalSubscriberDrop<T: 'static> {
|
||||||
|
signal: Signal<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: 'static> Drop for SignalSubscriberDrop<T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.signal.update_subscribers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Write<'a, T: 'static, I: 'static = T> {
|
||||||
|
write: RefMut<'a, T>,
|
||||||
|
signal: SignalSubscriberDrop<I>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: 'static, I: 'static> Write<'a, T, I> {
|
||||||
|
pub fn map<O>(myself: Self, f: impl FnOnce(&mut T) -> &mut O) -> Write<'a, O, I> {
|
||||||
|
let Self { write, signal } = myself;
|
||||||
|
Write {
|
||||||
|
write: RefMut::map(write, f),
|
||||||
|
signal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn filter_map<O>(
|
||||||
|
myself: Self,
|
||||||
|
f: impl FnOnce(&mut T) -> Option<&mut O>,
|
||||||
|
) -> Option<Write<'a, O, I>> {
|
||||||
|
let Self { write, signal } = myself;
|
||||||
|
let write = RefMut::filter_map(write, f).ok();
|
||||||
|
write.map(|write| Write {
|
||||||
|
write,
|
||||||
|
signal: signal,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: 'static> Deref for Write<'a, T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&*self.write
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> DerefMut for Write<'_, T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut *self.write
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ReadOnlySignal<T: 'static> {
|
||||||
|
inner: Signal<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: 'static> ReadOnlySignal<T> {
|
||||||
|
pub fn new(signal: Signal<T>) -> Self {
|
||||||
|
Self { inner: signal }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn origin_scope(&self) -> ScopeId {
|
||||||
|
self.inner.origin_scope()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read(&self) -> Ref<T> {
|
||||||
|
self.inner.read()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with<O>(&self, f: impl FnOnce(&T) -> O) -> O {
|
||||||
|
self.inner.with(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Clone + 'static> ReadOnlySignal<T> {
|
||||||
|
pub fn value(&self) -> T {
|
||||||
|
self.read().clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: 'static> PartialEq for ReadOnlySignal<T> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.inner == other.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user