made sync_signal more robust

This commit is contained in:
Maccesch 2024-08-26 21:38:41 +01:00
parent 26938f8e52
commit 04bcb6b319

View file

@ -150,7 +150,7 @@ pub fn sync_signal<T>(
where where
T: Clone + 'static, T: Clone + 'static,
{ {
sync_signal_with_options(left, right, SyncSignalOptions::default()) sync_signal_with_options(left, right, SyncSignalOptions::<T, T>::default())
} }
/// Version of [`sync_signal`] that takes a `SyncSignalOptions`. See [`sync_signal`] for how to use. /// Version of [`sync_signal`] that takes a `SyncSignalOptions`. See [`sync_signal`] for how to use.
@ -166,12 +166,11 @@ where
let SyncSignalOptions { let SyncSignalOptions {
immediate, immediate,
direction, direction,
transform_ltr, transforms
transform_rtl,
assign_ltr,
assign_rtl,
} = options; } = options;
let (assign_ltr, assign_rtl) = transforms.assigns();
let left = left.into(); let left = left.into();
let right = right.into(); let right = right.into();
@ -184,8 +183,6 @@ where
stop_watch_left = Some(watch( stop_watch_left = Some(watch(
move || left.get(), move || left.get(),
move |new_value, _, _| { move |new_value, _, _| {
let new_value = (*transform_ltr)(new_value);
if !is_sync_update.get_value() { if !is_sync_update.get_value() {
is_sync_update.set_value(true); is_sync_update.set_value(true);
right.update(|right| assign_ltr(right, new_value)); right.update(|right| assign_ltr(right, new_value));
@ -200,8 +197,6 @@ where
stop_watch_right = Some(watch( stop_watch_right = Some(watch(
move || right.get(), move || right.get(),
move |new_value, _, _| { move |new_value, _, _| {
let new_value = (*transform_rtl)(new_value);
if !is_sync_update.get_value() { if !is_sync_update.get_value() {
is_sync_update.set_value(true); is_sync_update.set_value(true);
left.update(|left| assign_rtl(left, new_value)); left.update(|left| assign_rtl(left, new_value));
@ -223,13 +218,60 @@ where
} }
/// Direction of syncing. /// Direction of syncing.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub enum SyncDirection { pub enum SyncDirection {
LeftToRight, LeftToRight,
RightToLeft, RightToLeft,
#[default]
Both, Both,
} }
pub type AssignFn<T> = Rc<dyn Fn(&mut T, T)>; pub type AssignFn<T, S> = Rc<dyn Fn(&mut T, &S)>;
pub enum SyncTransforms<L, R> {
Transforms {
/// Transforms the left signal into the right signal.
ltr: Rc<dyn Fn(&L) -> R>,
/// Transforms the right signal into the left signal.
rtl: Rc<dyn Fn(&R) -> L>,
},
Assigns {
/// Assigns the left signal to the right signal.
ltr: AssignFn<R, L>,
/// Assigns the right signal to the left signal.
rtl: AssignFn<L, R>,
},
}
impl<T> Default for SyncTransforms<T, T>
where
T: Clone,
{
fn default() -> Self {
Self::Assigns {
ltr: Rc::new(|right, left| *right = left.clone()),
rtl: Rc::new(|left, right| *left = right.clone()),
}
}
}
impl<L, R> SyncTransforms<L, R>
where L: 'static, R: 'static
{
pub fn assigns(&self) -> (AssignFn<R, L>, AssignFn<L, R>) {
match self {
SyncTransforms::Transforms { ltr, rtl } => {
let ltr = Rc::clone(&ltr);
let rtl = Rc::clone(&rtl);
(
Rc::new(move |right, left| *right = ltr(left)),
Rc::new(move |left, right| *left = rtl(right)),
)
}
SyncTransforms::Assigns { ltr, rtl } => (Rc::clone(ltr), Rc::clone(rtl)),
}
}
}
/// Options for [`sync_signal_with_options`]. /// Options for [`sync_signal_with_options`].
#[derive(DefaultBuilder)] #[derive(DefaultBuilder)]
@ -242,63 +284,13 @@ pub struct SyncSignalOptions<L, R> {
/// Direction of syncing. Defaults to `SyncDirection::Both`. /// Direction of syncing. Defaults to `SyncDirection::Both`.
direction: SyncDirection, direction: SyncDirection,
/// Transforms the left signal into the right signal. /// How to transform or assign the values to each other
/// Defaults to identity. /// Defaults to identity.
#[builder(skip)] #[builder(skip)]
transform_ltr: Rc<dyn Fn(&L) -> R>, transforms: SyncTransforms<L, R>,
/// Transforms the right signal into the left signal.
/// Defaults to identity.
#[builder(skip)]
transform_rtl: Rc<dyn Fn(&R) -> L>,
/// Assigns the left signal to the right signal.
/// Defaults to `*r = l`.
#[builder(skip)]
assign_ltr: AssignFn<R>,
/// Assigns the right signal to the left signal.
/// Defaults to `*l = r`.
#[builder(skip)]
assign_rtl: AssignFn<L>,
} }
impl<L, R> SyncSignalOptions<L, R> { impl<L, R> SyncSignalOptions<L, R> {
/// Transforms the left signal into the right signal.
/// Defaults to identity.
pub fn transform_ltr(self, transform_ltr: impl Fn(&L) -> R + 'static) -> Self {
Self {
transform_ltr: Rc::new(transform_ltr),
..self
}
}
/// Transforms the right signal into the left signal.
/// Defaults to identity.
pub fn transform_rtl(self, transform_rtl: impl Fn(&R) -> L + 'static) -> Self {
Self {
transform_rtl: Rc::new(transform_rtl),
..self
}
}
/// Assigns the left signal to the right signal.
/// Defaults to `*r = l`.
pub fn assign_ltr(self, assign_ltr: impl Fn(&mut R, R) + 'static) -> Self {
Self {
assign_ltr: Rc::new(assign_ltr),
..self
}
}
/// Assigns the right signal to the left signal.
/// Defaults to `*l = r`.
pub fn assign_rtl(self, assign_rtl: impl Fn(&mut L, L) + 'static) -> Self {
Self {
assign_rtl: Rc::new(assign_rtl),
..self
}
}
/// Initializes options with transforms /// Initializes options with transforms
pub fn with_transforms( pub fn with_transforms(
transform_ltr: impl Fn(&L) -> R + 'static, transform_ltr: impl Fn(&L) -> R + 'static,
@ -307,27 +299,37 @@ impl<L, R> SyncSignalOptions<L, R> {
Self { Self {
immediate: true, immediate: true,
direction: SyncDirection::Both, direction: SyncDirection::Both,
transform_ltr: Rc::new(transform_ltr), transforms: SyncTransforms::Transforms {
transform_rtl: Rc::new(transform_rtl), ltr: Rc::new(transform_ltr),
assign_ltr: Rc::new(|right, left| *right = left), rtl: Rc::new(transform_rtl),
assign_rtl: Rc::new(|left, right| *left = right), },
}
}
pub fn with_assigns(
assign_ltr: impl Fn(&mut R, &L) + 'static,
assign_rtl: impl Fn(&mut L, &R) + 'static,
) -> Self {
Self {
immediate: true,
direction: SyncDirection::Both,
transforms: SyncTransforms::Assigns {
ltr: Rc::new(assign_ltr),
rtl: Rc::new(assign_rtl),
},
} }
} }
} }
impl<L, R> Default for SyncSignalOptions<L, R> impl<T> Default for SyncSignalOptions<T, T>
where where
L: Clone + From<R>, T: Clone,
R: Clone + From<L>,
{ {
fn default() -> Self { fn default() -> Self {
Self { Self {
immediate: true, immediate: true,
direction: SyncDirection::Both, direction: Default::default(),
transform_ltr: Rc::new(|x| x.clone().into()), transforms: Default::default(),
transform_rtl: Rc::new(|x| x.clone().into()),
assign_ltr: Rc::new(|right, left| *right = left),
assign_rtl: Rc::new(|left, right| *left = right),
} }
} }
} }