Some more optimization.

This commit is contained in:
Samuel Guerra 2024-01-04 11:47:03 -03:00
parent d0e0af1e2c
commit cfa41664b7
4 changed files with 197 additions and 52 deletions

View File

@ -175,6 +175,19 @@ impl<T: VarValue> IntoVar<T> for ArcVar<T> {
}
impl<T: VarValue> ArcVar<T> {
#[cfg(dyn_closure)]
fn modify_impl(&self, modify: Box<dyn FnOnce(&mut VarModify<T>) + Send + 'static>) -> Result<(), VarIsReadOnlyError> {
let me = self.clone();
VARS.schedule_update(
Box::new(move || {
me.0.apply_modify(modify);
}),
std::any::type_name::<T>(),
);
Ok(())
}
#[cfg(not(dyn_closure))]
fn modify_impl(&self, modify: impl FnOnce(&mut VarModify<T>) + Send + 'static) -> Result<(), VarIsReadOnlyError> {
let me = self.clone();
VARS.schedule_update(

View File

@ -2784,6 +2784,10 @@ where
if input.capabilities().is_always_static() || output.capabilities().is_always_read_only() {
VarHandle::dummy()
} else {
#[cfg(dyn_closure)]
let update_output: Box<dyn FnMut(&I, &AnyVarHookArgs, <V::Downgrade as WeakVar<O>>::Upgrade) + Send + 'static> =
Box::new(update_output);
var_bind_ok(input, output.downgrade(), update_output)
}
}

View File

@ -158,7 +158,12 @@ impl<T: VarValue> ArcMergeVar<T> {
let mut m = rc_merge.m.lock();
let m = &mut *m;
let new_value = (m.merge)(&m.inputs);
rc_merge.value.apply_modify(|v| v.set(new_value));
{
let modify = |v: &mut VarModify<T>| v.set(new_value);
#[cfg(dyn_closure)]
let modify = Box::new(modify);
rc_merge.value.apply_modify(modify)
};
})
}
}

View File

@ -80,9 +80,11 @@ macro_rules! impl_from_and_into_var {
};
}
use std::marker::PhantomData;
use parking_lot::RwLock;
use crate::AnyVarHookArgs;
use crate::{AnyVarHookArgs, AnyVarValue};
use super::{animation::ModifyInfo, VarHandle, VarHook, VarModify, VarUpdateId, VarValue, VARS};
@ -288,95 +290,216 @@ macro_rules! __impl_from_and_into_var {
};
}
struct VarDataInner<T> {
value: T,
struct VarMeta {
last_update: VarUpdateId,
hooks: Vec<VarHook>,
animation: ModifyInfo,
}
impl VarMeta {
fn push_hook(&mut self, pos_modify_action: Box<dyn Fn(&AnyVarHookArgs) -> bool + Send + Sync>) -> VarHandle {
let (hook, weak) = VarHandle::new(pos_modify_action);
self.hooks.push(weak);
hook
}
fn skip_modify(&mut self) -> bool {
let curr_anim = VARS.current_modify();
if curr_anim.importance() < self.animation.importance() {
return true;
}
self.animation = curr_anim;
false
}
}
#[cfg(dyn_closure)]
struct VarDataInner {
value: Box<dyn AnyVarValue>,
meta: VarMeta,
}
#[cfg(not(dyn_closure))]
struct VarDataInner<T> {
value: T,
meta: VarMeta,
}
#[cfg(dyn_closure)]
pub(super) struct VarData<T: VarValue>(RwLock<VarDataInner>, PhantomData<T>);
#[cfg(not(dyn_closure))]
pub(super) struct VarData<T: VarValue>(RwLock<VarDataInner<T>>);
impl<T: VarValue> VarData<T> {
pub fn new(value: T) -> Self {
Self(RwLock::new(VarDataInner {
#[cfg(dyn_closure)]
let value = Box::new(value);
let inner = RwLock::new(VarDataInner {
value,
last_update: VarUpdateId::never(),
hooks: vec![],
animation: ModifyInfo::never(),
}))
meta: VarMeta {
last_update: VarUpdateId::never(),
hooks: vec![],
animation: ModifyInfo::never(),
},
});
#[cfg(dyn_closure)]
{
Self(inner, PhantomData)
}
#[cfg(not(dyn_closure))]
{
Self(inner)
}
}
pub fn into_value(self) -> T {
self.0.into_inner().value
#[cfg(dyn_closure)]
{
*self.0.into_inner().value.into_any().downcast::<T>().unwrap()
}
#[cfg(not(dyn_closure))]
{
self.0.into_inner().value
}
}
/// Read the value.
pub fn with<R>(&self, f: impl FnOnce(&T) -> R) -> R {
f(&self.0.read().value)
#[cfg(dyn_closure)]
{
f(self.0.read().value.as_any().downcast_ref::<T>().unwrap())
}
#[cfg(not(dyn_closure))]
{
f(&self.0.read().value)
}
}
pub fn last_update(&self) -> VarUpdateId {
self.0.read().last_update
self.0.read().meta.last_update
}
pub fn is_animating(&self) -> bool {
self.0.read().animation.is_animating()
self.0.read().meta.animation.is_animating()
}
pub fn modify_importance(&self) -> usize {
self.0.read().animation.importance()
self.0.read().meta.animation.importance()
}
pub fn push_hook(&self, pos_modify_action: Box<dyn Fn(&AnyVarHookArgs) -> bool + Send + Sync>) -> VarHandle {
let (hook, weak) = VarHandle::new(pos_modify_action);
self.0.write().hooks.push(weak);
hook
self.0.write().meta.push_hook(pos_modify_action)
}
pub fn push_animation_hook(&self, handler: Box<dyn FnOnce() + Send>) -> Result<(), Box<dyn FnOnce() + Send>> {
self.0.write().animation.hook_animation_stop(handler)
self.0.write().meta.animation.hook_animation_stop(handler)
}
/// Calls `modify` on the value.
pub fn apply_modify(&self, modify: impl FnOnce(&mut VarModify<T>)) {
let mut meta = self.0.write();
let curr_anim = VARS.current_modify();
if curr_anim.importance() < meta.animation.importance() {
return;
#[cfg(dyn_closure)]
pub fn apply_modify(&self, modify: Box<dyn FnOnce(&mut VarModify<T>) + 'static>) {
apply_modify(
&self.0,
Box::new(move |v| {
let mut value = VarModify::new(v.as_any().downcast_ref::<T>().unwrap());
modify(&mut value);
let (notify, new_value, update, tags) = value.finish();
(
notify,
match new_value {
Some(v) => Some(Box::new(v)),
None => None,
},
update,
tags,
)
}),
)
}
#[cfg(not(dyn_closure))]
pub fn apply_modify(&self, modify: impl FnOnce(&mut VarModify<T>) + 'static) {
apply_modify(&self.0, modify)
}
}
#[cfg(dyn_closure)]
fn apply_modify(
inner: &RwLock<VarDataInner>,
modify: Box<dyn FnOnce(&dyn AnyVarValue) -> (bool, Option<Box<dyn AnyVarValue>>, bool, Vec<Box<dyn AnyVarValue>>)>,
) {
let mut data = inner.write();
if data.meta.skip_modify() {
return;
}
let data = parking_lot::RwLockWriteGuard::downgrade(data);
let (notify, new_value, update, tags) = modify(&*data.value);
if notify {
drop(data);
let mut data = inner.write();
if let Some(nv) = new_value {
data.value = nv;
}
meta.animation = curr_anim;
data.meta.last_update = VARS.update_id();
let meta = parking_lot::RwLockWriteGuard::downgrade(meta);
let mut value = VarModify::new(&meta.value);
modify(&mut value);
let (notify, new_value, update, tags) = value.finish();
if !data.meta.hooks.is_empty() {
let mut hooks = std::mem::take(&mut data.meta.hooks);
if notify {
let meta = parking_lot::RwLockWriteGuard::downgrade(data);
let args = AnyVarHookArgs::new(&*meta.value, update, &tags);
call_hooks(&mut hooks, args);
drop(meta);
let mut meta = self.0.write();
if let Some(nv) = new_value {
meta.value = nv;
}
meta.last_update = VARS.update_id();
let mut hooks = std::mem::take(&mut meta.hooks);
if !hooks.is_empty() {
let meta = parking_lot::RwLockWriteGuard::downgrade(meta);
let args = AnyVarHookArgs::new(&meta.value, update, &tags);
call_hooks(&mut hooks, args);
drop(meta);
let mut meta = self.0.write();
hooks.append(&mut meta.hooks);
meta.hooks = hooks;
} else {
meta.hooks = hooks;
}
VARS.wake_app();
let mut data = inner.write();
hooks.append(&mut data.meta.hooks);
data.meta.hooks = hooks;
}
VARS.wake_app();
}
}
#[cfg(not(dyn_closure))]
fn apply_modify<T: VarValue>(inner: &RwLock<VarDataInner>, modify: impl FnOnce(&mut VarModify<T>)) {
let mut data = inner.write();
if data.meta.skip_modify() {
return;
}
let meta = parking_lot::RwLockWriteGuard::downgrade(data);
let mut value = VarModify::new(&meta.value);
modify(&mut value);
let (notify, new_value, update, tags) = value.finish();
if notify {
drop(meta);
let mut data = inner.write();
if let Some(nv) = new_value {
data.value = nv;
}
data.meta.last_update = VARS.update_id();
if !data.meta.hooks.is_empty() {
let mut hooks = std::mem::take(&mut data.meta.hooks);
let meta = parking_lot::RwLockWriteGuard::downgrade(data);
let args = AnyVarHookArgs::new(&meta.value, update, &tags);
call_hooks(&mut hooks, args);
drop(meta);
let mut data = inner.write();
hooks.append(&mut data.meta.hooks);
data.meta.hooks = hooks;
}
VARS.wake_app();
}
}