Refactored explicit var update requests to propagate across bindings.

This commit is contained in:
Samuel Guerra 2023-06-20 00:21:59 -03:00
parent 00948e3763
commit b38aa79124
7 changed files with 74 additions and 35 deletions

View File

@ -64,9 +64,6 @@
# Vars
* Previous value in hook?
- We are cloning anyway, could have the prev-value in a Cow.
- Owned if actually changed.
* Merge.
* Config example and tests with errors.

View File

@ -969,21 +969,21 @@ impl<'a, T: VarValue> VarModify<'a, T> {
}
}
/// Returns `(notify, new_value, tags)`.
pub fn finish(self) -> (bool, Option<T>, Vec<Box<dyn AnyVarValue>>) {
/// Returns `(notify, new_value, update, tags)`.
pub fn finish(self) -> (bool, Option<T>, bool, Vec<Box<dyn AnyVarValue>>) {
match self.value {
Cow::Borrowed(_) => {
if self.update {
return (true, None, self.tags);
return (true, None, true, self.tags);
}
}
Cow::Owned(v) => {
if self.update || self.current_value != &v {
return (true, Some(v), self.tags);
return (true, Some(v), self.update, self.tags);
}
}
}
(false, None, vec![])
(false, None, false, vec![])
}
}
impl<'a, T: VarValue> ops::Deref for VarModify<'a, T> {
@ -1002,19 +1002,27 @@ impl<'a, T: VarValue> std::convert::AsRef<T> for VarModify<'a, T> {
/// Arguments for [`AnyVar::hook`].
pub struct VarHookArgs<'a> {
value: &'a dyn AnyVarValue,
update: bool,
tags: &'a [Box<dyn AnyVarValue>],
}
impl<'a> VarHookArgs<'a> {
/// New from updated value and custom tag.
pub fn new(value: &'a dyn AnyVarValue, tags: &'a [Box<dyn AnyVarValue>]) -> Self {
Self { value, tags }
pub fn new(value: &'a dyn AnyVarValue, update: bool, tags: &'a [Box<dyn AnyVarValue>]) -> Self {
Self { value, update, tags }
}
/// Reference the updated value.
pub fn value(&self) -> &dyn AnyVarValue {
pub fn value(&self) -> &'a dyn AnyVarValue {
self.value
}
/// If update was explicitly requested.
///
/// Note that bindings/mappings propagate this update request.
pub fn update(&self) -> bool {
self.update
}
/// Value type ID.
pub fn value_type(&self) -> TypeId {
self.value.as_any().type_id()
@ -1604,8 +1612,15 @@ pub trait Var<T: VarValue>: IntoVar<T, Var = Self> + AnyVar + Clone {
#[cfg(not(dyn_closure))]
let mut map = map;
var_bind(self, other, move |value, _, other| {
let _ = other.set(map(value));
var_bind(self, other, move |value, args, other| {
let value = map(value);
let update = args.update;
let _ = other.modify(move |vm| {
vm.set(value);
if update {
vm.update();
}
});
})
}
@ -1627,9 +1642,15 @@ pub trait Var<T: VarValue>: IntoVar<T, Var = Self> + AnyVar + Clone {
#[cfg(not(dyn_closure))]
let mut map = map;
var_bind(self, other, move |value, _, other| {
var_bind(self, other, move |value, args, other| {
if let Some(value) = map(value) {
let _ = other.set(value);
let update = args.update;
let _ = other.modify(move |vm| {
vm.set(value);
if update {
vm.update();
}
});
}
})
}
@ -1655,9 +1676,13 @@ pub trait Var<T: VarValue>: IntoVar<T, Var = Self> + AnyVar + Clone {
let is_from_other = args.downcast_tags::<BindMapBidiTag>().any(|&b| b == binding_tag);
if !is_from_other {
let value = map(value);
let update = args.update;
let _ = other.modify(move |vm| {
vm.set(value);
vm.push_tag(binding_tag);
if update {
vm.update();
}
});
}
});
@ -1666,9 +1691,13 @@ pub trait Var<T: VarValue>: IntoVar<T, Var = Self> + AnyVar + Clone {
let is_from_self = args.downcast_tags::<BindMapBidiTag>().any(|&b| b == binding_tag);
if !is_from_self {
let value = map_back(value);
let update = args.update;
let _ = self_.modify(move |vm| {
vm.set(value);
vm.push_tag(binding_tag);
if update {
vm.update();
}
});
}
});
@ -1696,9 +1725,13 @@ pub trait Var<T: VarValue>: IntoVar<T, Var = Self> + AnyVar + Clone {
let is_from_other = args.downcast_tags::<BindMapBidiTag>().any(|&b| b == binding_tag);
if !is_from_other {
if let Some(value) = map(value) {
let update = args.update;
let _ = other.modify(move |vm| {
vm.set(value);
vm.push_tag(binding_tag);
if update {
vm.update();
}
});
}
}
@ -1708,9 +1741,13 @@ pub trait Var<T: VarValue>: IntoVar<T, Var = Self> + AnyVar + Clone {
let is_from_self = args.downcast_tags::<BindMapBidiTag>().any(|&b| b == binding_tag);
if !is_from_self {
if let Some(value) = map_back(value) {
let update = args.update;
let _ = self_.modify(move |vm| {
vm.set(value);
vm.push_tag(binding_tag);
if update {
vm.update();
}
});
}
}
@ -2039,9 +2076,12 @@ pub trait Var<T: VarValue>: IntoVar<T, Var = Self> + AnyVar + Clone {
let easing_fn = easing_fn.clone();
let mut _anim_handle = animation::AnimationHandle::dummy();
var_bind(&source, &easing_var, move |value, _, easing_var| {
var_bind(&source, &easing_var, move |value, args, easing_var| {
let easing_fn = easing_fn.clone();
_anim_handle = easing_var.ease(value.clone(), duration, move |t| easing_fn(t));
if args.update {
easing_var.update();
}
})
.perm();
easing_var.read_only()

View File

@ -66,20 +66,20 @@ impl<T: VarValue, S: Var<T>> ArcCowVar<T, S> {
match data {
Data::Source { source, hooks, .. } => {
let (update, new_value, tags) = source.with(|val| {
let (notify, new_value, update, tags) = source.with(|val| {
let mut vm = VarModify::new(val);
modify(&mut vm);
vm.finish()
});
let value = new_value.unwrap_or_else(|| source.get());
if update {
let hook_args = VarHookArgs::new(&value, &tags);
if notify {
let hook_args = VarHookArgs::new(&value, update, &tags);
hooks.retain(|h| h.call(&hook_args));
UPDATES.update(None);
}
*data = Data::Owned {
value,
last_update: if update { VARS.update_id() } else { source.last_update() },
last_update: if notify { VARS.update_id() } else { source.last_update() },
hooks: mem::take(hooks),
animation: VARS.current_modify(),
};
@ -98,18 +98,18 @@ impl<T: VarValue, S: Var<T>> ArcCowVar<T, S> {
*animation = curr_anim;
}
let (update, new_value, tags) = {
let (notify, new_value, update, tags) = {
let mut vm = VarModify::new(value);
modify(&mut vm);
vm.finish()
};
if update {
if notify {
if let Some(nv) = new_value {
*value = nv;
}
*last_update = VARS.update_id();
let hook_args = VarHookArgs::new(value, &tags);
let hook_args = VarHookArgs::new(value, update, &tags);
hooks.retain(|h| h.call(&hook_args));
UPDATES.update(None);
}

View File

@ -52,7 +52,7 @@ where
data.var_handle = data.var.hook(ArcFlatMapVar::on_var_hook(weak_flat.clone()));
data.last_update = VARS.update_id();
data.var.with(|value| {
let args = VarHookArgs::new(value, args.tags());
let args = VarHookArgs::new(value, args.update(), args.tags());
data.hooks.retain(|h| h.call(&args));
});
}

View File

@ -79,7 +79,7 @@ impl<I: VarValue, O: VarValue, S: Var<I>> AnyVar for MapRef<I, O, S> {
self.source.hook(Box::new(move |args| {
if let Some(value) = args.downcast_value() {
let value = map(value);
pos_modify_action(&VarHookArgs::new(value, args.tags()))
pos_modify_action(&VarHookArgs::new(value, args.update(), args.tags()))
} else {
true
}
@ -301,7 +301,7 @@ impl<I: VarValue, O: VarValue, S: Var<I>> AnyVar for MapRefBidi<I, O, S> {
self.source.hook(Box::new(move |args| {
if let Some(value) = args.downcast_value() {
let value = map(value);
pos_modify_action(&VarHookArgs::new(value, args.tags()))
pos_modify_action(&VarHookArgs::new(value, args.update(), args.tags()))
} else {
true
}
@ -406,13 +406,15 @@ impl<I: VarValue, O: VarValue, S: Var<I>> Var<O> for MapRefBidi<I, O, S> {
let map = self.map.clone();
let map_mut = self.map_mut.clone();
self.source.modify(move |vm| {
let (update, new_value, tags) = {
let (notify, new_value, update, tags) = {
let mut vm = VarModify::new(map(vm.as_ref()));
modify(&mut vm);
vm.finish()
};
if update {
vm.update();
if notify {
if update {
vm.update();
}
if let Some(nv) = new_value {
*map_mut(vm.to_mut()) = nv;
}

View File

@ -320,7 +320,7 @@ impl<T: VarValue> VarData<T> {
meta.animation = curr_anim;
}
let (notify, new_value, tags) = self.with(|value| {
let (notify, new_value, update, tags) = self.with(|value| {
let mut value = VarModify::new(value);
modify(&mut value);
value.finish()
@ -334,7 +334,7 @@ impl<T: VarValue> VarData<T> {
meta.last_update = VARS.update_id();
self.with(|val| {
let args = VarHookArgs::new(val, &tags);
let args = VarHookArgs::new(val, update, &tags);
meta.hooks.retain(|h| h.call(&args));
});
UPDATES.update(None);

View File

@ -317,7 +317,7 @@ impl<T: VarValue> ArcWhenVar<T> {
if update {
drop(data);
VARS.schedule_update(ArcWhenVar::apply_update(rc_when, args.tags_vec()));
VARS.schedule_update(ArcWhenVar::apply_update(rc_when, false, args.tags_vec()));
}
true
@ -333,7 +333,7 @@ impl<T: VarValue> ArcWhenVar<T> {
let data = rc_when.w.lock();
if data.active == i {
drop(data);
VARS.schedule_update(ArcWhenVar::apply_update(rc_when, args.tags_vec()));
VARS.schedule_update(ArcWhenVar::apply_update(rc_when, args.update(), args.tags_vec()));
}
true
} else {
@ -342,7 +342,7 @@ impl<T: VarValue> ArcWhenVar<T> {
})
}
fn apply_update(rc_merge: Arc<Data<T>>, tags: Vec<Box<dyn AnyVarValue>>) -> VarUpdateFn {
fn apply_update(rc_merge: Arc<Data<T>>, update: bool, tags: Vec<Box<dyn AnyVarValue>>) -> VarUpdateFn {
Box::new(move || {
let mut data = rc_merge.w.lock();
let data = &mut *data;
@ -363,7 +363,7 @@ impl<T: VarValue> ArcWhenVar<T> {
};
active.with(|value| {
let args = VarHookArgs::new(value, &tags);
let args = VarHookArgs::new(value, update, &tags);
data.hooks.retain(|h| h.call(&args));
});
UPDATES.update(None);