mirror of
https://github.com/Zenithsiz/dynatos.git
synced 2026-02-03 18:13:04 +00:00
Derived now uses a custom trait instead of DerivedRun to allow unsizing.
Added `Derived::unsize`.
This commit is contained in:
parent
b783ea1636
commit
b45359038a
43
Cargo.toml
43
Cargo.toml
@ -105,27 +105,28 @@ clippy.panic = "allow"
|
||||
clippy.unreachable = "allow"
|
||||
|
||||
# Misc.
|
||||
clippy.arbitrary_source_item_ordering = "allow"
|
||||
clippy.arithmetic_side_effects = "allow"
|
||||
clippy.exhaustive_enums = "allow"
|
||||
clippy.exhaustive_structs = "allow"
|
||||
clippy.expect_used = "allow"
|
||||
clippy.impl_trait_in_params = "allow"
|
||||
clippy.indexing_slicing = "allow"
|
||||
clippy.mem_forget = "allow"
|
||||
clippy.min_ident_chars = "allow"
|
||||
clippy.missing_docs_in_private_items = "allow"
|
||||
clippy.module_name_repetitions = "allow"
|
||||
clippy.pub_use = "allow"
|
||||
clippy.pub_with_shorthand = "allow"
|
||||
clippy.question_mark_used = "allow"
|
||||
clippy.self_named_module_files = "allow"
|
||||
clippy.separated_literal_suffix = "allow"
|
||||
clippy.single_call_fn = "allow"
|
||||
clippy.single_char_lifetime_names = "allow"
|
||||
clippy.string_slice = "allow"
|
||||
clippy.unused_trait_names = "allow"
|
||||
clippy.wildcard_enum_match_arm = "allow"
|
||||
clippy.arbitrary_source_item_ordering = "allow"
|
||||
clippy.arithmetic_side_effects = "allow"
|
||||
clippy.exhaustive_enums = "allow"
|
||||
clippy.exhaustive_structs = "allow"
|
||||
clippy.expect_used = "allow"
|
||||
clippy.field_scoped_visibility_modifiers = "allow"
|
||||
clippy.impl_trait_in_params = "allow"
|
||||
clippy.indexing_slicing = "allow"
|
||||
clippy.mem_forget = "allow"
|
||||
clippy.min_ident_chars = "allow"
|
||||
clippy.missing_docs_in_private_items = "allow"
|
||||
clippy.module_name_repetitions = "allow"
|
||||
clippy.pub_use = "allow"
|
||||
clippy.pub_with_shorthand = "allow"
|
||||
clippy.question_mark_used = "allow"
|
||||
clippy.self_named_module_files = "allow"
|
||||
clippy.separated_literal_suffix = "allow"
|
||||
clippy.single_call_fn = "allow"
|
||||
clippy.single_char_lifetime_names = "allow"
|
||||
clippy.string_slice = "allow"
|
||||
clippy.unused_trait_names = "allow"
|
||||
clippy.wildcard_enum_match_arm = "allow"
|
||||
|
||||
# False positives for tests in `tests/`.
|
||||
clippy.tests_outside_test_module = "allow"
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
// Imports
|
||||
use {
|
||||
crate::{
|
||||
effect,
|
||||
Effect,
|
||||
EffectRun,
|
||||
EffectRunCtx,
|
||||
@ -49,6 +50,7 @@ use {
|
||||
marker::{PhantomData, Unsize},
|
||||
ops::{CoerceUnsized, Deref},
|
||||
},
|
||||
std::rc::Rc,
|
||||
};
|
||||
|
||||
/// Derived signal.
|
||||
@ -65,7 +67,7 @@ impl<T, F> Derived<T, F> {
|
||||
pub fn new(f: F) -> Self
|
||||
where
|
||||
T: 'static,
|
||||
F: Fn() -> T + 'static,
|
||||
F: DerivedRun<T> + 'static,
|
||||
{
|
||||
let value = RefCell::new(None);
|
||||
let effect = Effect::new(EffectFn {
|
||||
@ -78,6 +80,25 @@ impl<T, F> Derived<T, F> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, F: ?Sized> Derived<T, F> {
|
||||
/// Unsizes this value into a `Derived<dyn DerivedRun<T>>`.
|
||||
// Note: This is necessary for unsizing from `!Sized` to `dyn DerivedRun`,
|
||||
// since those coercions only work for `Sized` types.
|
||||
// TODO: Once we can unsize from `?Sized` to `dyn DerivedRun`,
|
||||
// remove this.
|
||||
#[must_use]
|
||||
pub fn unsize(self) -> Derived<T, dyn DerivedRun<T>>
|
||||
where
|
||||
F: DerivedRun<T>,
|
||||
{
|
||||
Derived {
|
||||
effect: Effect {
|
||||
inner: self.effect.inner.unsize_inner_derived(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Reference type for [`SignalBorrow`] impl
|
||||
pub struct BorrowRef<'a, T: 'a, F: ?Sized>(cell::Ref<'a, Option<T>>, PhantomData<fn(F)>);
|
||||
|
||||
@ -148,7 +169,8 @@ where
|
||||
}
|
||||
|
||||
/// Effect function
|
||||
struct EffectFn<T, F: ?Sized> {
|
||||
#[doc(hidden)]
|
||||
pub struct EffectFn<T, F: ?Sized> {
|
||||
/// Trigger
|
||||
trigger: Trigger,
|
||||
|
||||
@ -159,16 +181,77 @@ struct EffectFn<T, F: ?Sized> {
|
||||
f: F,
|
||||
}
|
||||
|
||||
// Note: This is necessary to use `EffectFn` as a receiver
|
||||
// for unsizing in `DerivedRun`.
|
||||
impl<T, F: ?Sized> Deref for EffectFn<T, F> {
|
||||
type Target = F;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.f
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, F> EffectRun for EffectFn<T, F>
|
||||
where
|
||||
T: 'static,
|
||||
F: ?Sized + DerivedRun<T> + 'static,
|
||||
{
|
||||
fn run(&self, _ctx: EffectRunCtx<'_>) {
|
||||
*self.value.borrow_mut() = Some(self.f.run());
|
||||
self.trigger.exec();
|
||||
}
|
||||
|
||||
fn unsize_inner(self: Rc<effect::Inner<Self>>) -> Rc<effect::Inner<dyn EffectRun>> {
|
||||
DerivedRun::unsize_inner_effect(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Derived run
|
||||
///
|
||||
/// # Implementation
|
||||
/// To implement this trait, you must implement the [`run`](DerivedRun::run) function,
|
||||
/// and then use the macro [`derived_run_impl_inner`] to implement some details.
|
||||
pub trait DerivedRun<T> {
|
||||
/// Runs the derived function, yielding a value
|
||||
fn run(&self) -> T;
|
||||
|
||||
|
||||
// Implementation details.
|
||||
|
||||
|
||||
/// Unsizes the inner field of the effect to a `dyn EffectRun`
|
||||
#[doc(hidden)]
|
||||
fn unsize_inner_effect(self: Rc<effect::Inner<EffectFn<T, Self>>>) -> Rc<effect::Inner<dyn EffectRun>>;
|
||||
|
||||
/// Unsizes the inner field of the effect to an effect fn to a `dyn DerivedRun`.
|
||||
#[doc(hidden)]
|
||||
fn unsize_inner_derived(
|
||||
self: Rc<effect::Inner<EffectFn<T, Self>>>,
|
||||
) -> Rc<effect::Inner<EffectFn<T, dyn DerivedRun<T>>>>;
|
||||
}
|
||||
|
||||
/// Implementation detail for the [`EffectRun`] trait
|
||||
pub macro derived_run_impl_inner($T:ty) {
|
||||
fn unsize_inner_effect(self: Rc<effect::Inner<EffectFn<$T, Self>>>) -> Rc<effect::Inner<dyn EffectRun>> {
|
||||
self
|
||||
}
|
||||
|
||||
fn unsize_inner_derived(
|
||||
self: Rc<effect::Inner<EffectFn<$T, Self>>>,
|
||||
) -> Rc<effect::Inner<EffectFn<$T, dyn DerivedRun<$T>>>> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, F> DerivedRun<T> for F
|
||||
where
|
||||
T: 'static,
|
||||
F: Fn() -> T + 'static,
|
||||
{
|
||||
crate::effect_run_impl_inner! {}
|
||||
derived_run_impl_inner! { T }
|
||||
|
||||
fn run(&self, _ctx: EffectRunCtx<'_>) {
|
||||
*self.value.borrow_mut() = Some((self.f)());
|
||||
self.trigger.exec();
|
||||
fn run(&self) -> T {
|
||||
self()
|
||||
}
|
||||
}
|
||||
|
||||
@ -179,9 +262,12 @@ mod tests {
|
||||
#[test]
|
||||
fn unsize() {
|
||||
let f1 = Derived::new(|| 1_usize);
|
||||
let f2: Derived<usize, dyn Fn() -> usize> = f1.clone();
|
||||
let f2: Derived<usize, dyn DerivedRun<usize>> = f1.clone();
|
||||
let f3: Derived<usize, dyn Fn() -> usize> = f1.clone();
|
||||
|
||||
assert_eq!(&f1.effect, &f2.effect);
|
||||
assert_eq!(&f1.effect, &f3.effect);
|
||||
assert_eq!(*f2.borrow(), 1);
|
||||
assert_eq!(*f3.borrow(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,7 +56,7 @@ impl<F: ?Sized> Deref for Inner<F> {
|
||||
/// Effect
|
||||
pub struct Effect<F: ?Sized = dyn EffectRun> {
|
||||
/// Inner
|
||||
inner: Rc<Inner<F>>,
|
||||
pub(crate) inner: Rc<Inner<F>>,
|
||||
}
|
||||
|
||||
impl<F> Effect<F> {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user