#![doc(html_favicon_url = "https://raw.githubusercontent.com/zng-ui/zng/master/examples/res/image/zng-logo-icon.png")]
#![doc(html_logo_url = "https://raw.githubusercontent.com/zng-ui/zng/master/examples/res/image/zng-logo.png")]
#![doc = include_str!(concat!("../", std::env!("CARGO_PKG_README")))]
#![allow(clippy::type_complexity)]
#![warn(unused_extern_crates)]
#![warn(missing_docs)]
#![deny(clippy::future_not_send)]
use animation::{
easing::{EasingStep, EasingTime},
Transitionable,
};
use bitflags::bitflags;
use parking_lot::Mutex;
use std::{
any::{Any, TypeId},
borrow::Cow,
fmt,
future::Future,
marker::PhantomData,
ops,
sync::{
atomic::{AtomicBool, Ordering::Relaxed},
Arc,
},
time::Duration,
};
use zng_app_context::ContextLocal;
use zng_clone_move::clmv;
use zng_txt::{formatx, ToTxt, Txt};
use zng_unit::{Factor, FactorUnits};
pub mod animation;
mod arc;
mod boxed;
mod impls;
mod context;
mod contextualized;
mod cow;
mod expr;
mod flat_map;
mod future;
mod local;
mod map_ref;
mod merge;
mod read_only;
mod response;
mod vars;
mod vec;
mod when;
#[macro_use]
mod util;
pub use arc::{getter_var, state_var, var, var_default, var_from, ArcVar};
pub use boxed::{BoxedAnyVar, BoxedAnyWeakVar, BoxedVar, BoxedWeakVar};
#[doc(inline)]
pub use context::{ContextInitHandle, ContextVar, ReadOnlyContextVar};
pub use local::LocalVar;
#[doc(inline)]
pub use merge::MergeVarBuilder;
pub use read_only::ReadOnlyArcVar;
pub use response::{response_done_var, response_var, ResponderVar, ResponseVar};
pub use vars::*;
pub use vec::ObservableVec;
pub mod types {
use std::marker::PhantomData;
#[doc(hidden)]
pub use zng_app_context::context_local;
pub use impls::*;
pub use super::arc::WeakArcVar;
pub use super::boxed::{VarBoxed, WeakVarBoxed};
pub use super::context::{context_var_init, WeakContextInitHandle};
pub use super::contextualized::{ContextualizedVar, WeakContextualizedVar};
pub use super::cow::{ArcCowVar, WeakCowVar};
pub use super::expr::{__expr_var, expr_var_as, expr_var_into, expr_var_map};
pub use super::flat_map::{ArcFlatMapVar, WeakFlatMapVar};
pub use super::map_ref::{MapRef, MapRefBidi, WeakMapRef, WeakMapRefBidi};
pub use super::merge::{ArcMergeVar, ArcMergeVarInput, MergeVarInputs, WeakMergeVar, __merge_var};
pub use super::read_only::{ReadOnlyVar, WeakReadOnlyVar};
pub use super::response::Response;
pub use super::vec::VecChange;
pub use super::when::{AnyWhenVarBuilder, ArcWhenVar, ContextualizedArcWhenVar, WeakWhenVar, WhenVarBuilder, __when_var};
use super::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SourceVarTag(usize);
impl SourceVarTag {
pub fn new(source: &impl AnyVar) -> Self {
SourceVarTag(source.var_ptr().raw_pointer() as _)
}
}
pub struct VarDebug<'a, T: VarValue, V: Var<T>> {
pub(super) var: &'a V,
pub(super) _t: PhantomData<fn() -> T>,
}
impl<'a, T: VarValue, V: Var<T>> fmt::Debug for VarDebug<'a, T, V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.var.with(|t| fmt::Debug::fmt(t, f))
}
}
pub struct VarDisplay<'a, T: VarValue + fmt::Display, V: Var<T>> {
pub(super) var: &'a V,
pub(super) _t: PhantomData<fn() -> T>,
}
impl<'a, T: VarValue + fmt::Display, V: Var<T>> fmt::Display for VarDisplay<'a, T, V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.var.with(|t| fmt::Display::fmt(t, f))
}
}
}
mod private {
pub trait Sealed {}
}
pub trait VarValue: fmt::Debug + Clone + PartialEq + Any + Send + Sync {}
impl<T: fmt::Debug + Clone + Any + PartialEq + Send + Sync> VarValue for T {}
pub trait AnyVarValue: fmt::Debug + Any + Send + Sync {
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
fn into_any(self: Box<Self>) -> Box<dyn Any>;
fn clone_boxed(&self) -> Box<dyn AnyVarValue>;
fn clone_boxed_var(&self) -> BoxedAnyVar;
}
impl<T: VarValue> AnyVarValue for T {
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
fn clone_boxed(&self) -> Box<dyn AnyVarValue> {
Box::new(self.clone())
}
fn clone_boxed_var(&self) -> BoxedAnyVar {
Box::new(LocalVar(self.clone()))
}
fn into_any(self: Box<Self>) -> Box<dyn Any> {
self
}
}
pub trait IntoValue<T: VarValue>: Into<T> {}
impl<T: VarValue> IntoValue<T> for T {}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct VarCapability: u8 {
const NEW = 0b0000_0010;
const MODIFY = 0b0000_0011;
const CAPS_CHANGE = 0b1000_0000;
}
}
impl VarCapability {
pub fn as_read_only(self) -> Self {
Self::from_bits_truncate(self.bits() & 0b1111_1110)
}
pub fn is_always_read_only(self) -> bool {
!self.contains(Self::MODIFY) && !self.contains(Self::CAPS_CHANGE)
}
pub fn is_always_static(self) -> bool {
self.is_empty()
}
pub fn can_modify(self) -> bool {
self.contains(Self::MODIFY)
}
}
#[derive(Debug, Clone, Copy)]
pub struct VarIsReadOnlyError {
pub capabilities: VarCapability,
}
impl fmt::Display for VarIsReadOnlyError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "cannot modify variable")
}
}
impl std::error::Error for VarIsReadOnlyError {}
struct VarHandleData {
perm: AtomicBool,
action: Box<dyn Fn(&AnyVarHookArgs) -> bool + Send + Sync>,
}
struct VarHook(Arc<VarHandleData>);
impl VarHook {
pub fn call(&self, args: &AnyVarHookArgs) -> bool {
self.is_alive() && (self.0.action)(args)
}
pub fn is_alive(&self) -> bool {
Arc::strong_count(&self.0) > 1 || self.0.perm.load(Relaxed)
}
}
#[derive(Clone)]
#[must_use = "var handle stops the behavior it represents on drop"]
pub struct VarHandle(Option<Arc<VarHandleData>>);
impl VarHandle {
fn new(action: Box<dyn Fn(&AnyVarHookArgs) -> bool + Send + Sync>) -> (VarHandle, VarHook) {
let c = Arc::new(VarHandleData {
perm: AtomicBool::new(false),
action,
});
(VarHandle(Some(c.clone())), VarHook(c))
}
pub fn dummy() -> Self {
VarHandle(None)
}
pub fn is_dummy(&self) -> bool {
self.0.is_none()
}
pub fn perm(self) {
if let Some(s) = &self.0 {
s.perm.store(true, Relaxed);
}
}
pub fn with(self, other: Self) -> VarHandles {
[self, other].into()
}
}
impl PartialEq for VarHandle {
fn eq(&self, other: &Self) -> bool {
match (&self.0, &other.0) {
(None, None) => true,
(None, Some(_)) | (Some(_), None) => false,
(Some(a), Some(b)) => Arc::ptr_eq(a, b),
}
}
}
impl Eq for VarHandle {}
impl std::hash::Hash for VarHandle {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
let i = match &self.0 {
Some(rc) => Arc::as_ptr(rc) as usize,
None => 0,
};
state.write_usize(i);
}
}
impl fmt::Debug for VarHandle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let i = match &self.0 {
Some(rc) => Arc::as_ptr(rc) as usize,
None => 0,
};
f.debug_tuple("VarHandle").field(&i).finish()
}
}
impl Default for VarHandle {
fn default() -> Self {
Self::dummy()
}
}
#[must_use = "var handles stops the behavior they represents on drop"]
#[derive(Clone, Default)]
pub struct VarHandles(pub Vec<VarHandle>);
impl VarHandles {
pub const fn dummy() -> Self {
VarHandles(vec![])
}
pub fn is_dummy(&self) -> bool {
self.0.is_empty() || self.0.iter().all(VarHandle::is_dummy)
}
pub fn perm(self) {
for handle in self.0 {
handle.perm()
}
}
pub fn push(&mut self, other: VarHandle) -> &mut Self {
if !other.is_dummy() {
self.0.push(other);
}
self
}
pub fn clear(&mut self) {
self.0.clear()
}
}
impl FromIterator<VarHandle> for VarHandles {
fn from_iter<T: IntoIterator<Item = VarHandle>>(iter: T) -> Self {
VarHandles(iter.into_iter().filter(|h| !h.is_dummy()).collect())
}
}
impl<const N: usize> From<[VarHandle; N]> for VarHandles {
fn from(handles: [VarHandle; N]) -> Self {
handles.into_iter().collect()
}
}
impl Extend<VarHandle> for VarHandles {
fn extend<T: IntoIterator<Item = VarHandle>>(&mut self, iter: T) {
for handle in iter {
self.push(handle);
}
}
}
impl IntoIterator for VarHandles {
type Item = VarHandle;
type IntoIter = std::vec::IntoIter<VarHandle>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
pub struct ArcEq<T: fmt::Debug + Send + Sync>(pub Arc<T>);
impl<T: fmt::Debug + Send + Sync> ops::Deref for ArcEq<T> {
type Target = Arc<T>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T: fmt::Debug + Send + Sync> ArcEq<T> {
pub fn new(value: T) -> Self {
Self(Arc::new(value))
}
}
impl<T: fmt::Debug + Send + Sync> PartialEq for ArcEq<T> {
fn eq(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.0, &other.0)
}
}
impl<T: fmt::Debug + Send + Sync> Eq for ArcEq<T> {}
impl<T: fmt::Debug + Send + Sync> Clone for ArcEq<T> {
fn clone(&self) -> Self {
Self(Arc::clone(&self.0))
}
}
impl<T: fmt::Debug + Send + Sync> fmt::Debug for ArcEq<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&*self.0, f)
}
}
pub trait AnyVar: Any + Send + Sync + crate::private::Sealed {
fn clone_any(&self) -> BoxedAnyVar;
fn as_any(&self) -> &dyn Any;
fn as_unboxed_any(&self) -> &dyn Any;
fn double_boxed_any(self: Box<Self>) -> Box<dyn Any>;
fn var_type_id(&self) -> TypeId;
fn get_any(&self) -> Box<dyn AnyVarValue>;
fn with_any(&self, read: &mut dyn FnMut(&dyn AnyVarValue));
fn with_new_any(&self, read: &mut dyn FnMut(&dyn AnyVarValue)) -> bool;
fn set_any(&self, value: Box<dyn AnyVarValue>) -> Result<(), VarIsReadOnlyError>;
fn last_update(&self) -> VarUpdateId;
fn is_contextual(&self) -> bool;
fn capabilities(&self) -> VarCapability;
fn is_new(&self) -> bool {
VARS.update_id() == self.last_update()
}
fn is_animating(&self) -> bool;
fn modify_importance(&self) -> usize;
fn hook_any(&self, pos_modify_action: Box<dyn Fn(&AnyVarHookArgs) -> bool + Send + Sync>) -> VarHandle;
fn hook_animation_stop(&self, handler: Box<dyn FnOnce() + Send>) -> Result<(), Box<dyn FnOnce() + Send>>;
fn strong_count(&self) -> usize;
fn weak_count(&self) -> usize;
fn actual_var_any(&self) -> BoxedAnyVar;
fn downgrade_any(&self) -> BoxedAnyWeakVar;
fn var_ptr(&self) -> VarPtr;
fn get_debug(&self) -> Txt;
fn update(&self) -> Result<(), VarIsReadOnlyError>;
fn map_debug(&self) -> BoxedVar<Txt>;
}
#[derive(Debug)]
enum VarPtrData {
Static(*const ()),
Arc(*const ()),
NeverEq,
}
impl PartialEq for VarPtrData {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Static(l0), Self::Static(r0)) => l0 == r0,
(Self::Arc(l0), Self::Arc(r0)) => l0 == r0,
_ => false,
}
}
}
pub struct VarPtr<'a> {
_lt: std::marker::PhantomData<&'a ()>,
eq: VarPtrData,
}
impl<'a> VarPtr<'a> {
pub fn raw_pointer(&self) -> *const () {
match self.eq {
VarPtrData::Arc(p) => p,
VarPtrData::Static(p) => p,
VarPtrData::NeverEq => std::ptr::null(),
}
}
fn new_arc<T: ?Sized>(rc: &'a Arc<T>) -> Self {
Self {
_lt: std::marker::PhantomData,
eq: VarPtrData::Arc(Arc::as_ptr(rc) as _),
}
}
fn new_ctx_local<T: Send + Sync>(tl: &'static ContextLocal<T>) -> Self {
Self {
_lt: std::marker::PhantomData,
eq: VarPtrData::Static((tl as *const ContextLocal<T>) as _),
}
}
fn new_never_eq(_: &'a impl Any) -> Self {
Self {
_lt: std::marker::PhantomData,
eq: VarPtrData::NeverEq,
}
}
}
impl<'a> PartialEq for VarPtr<'a> {
fn eq(&self, other: &Self) -> bool {
self.eq == other.eq
}
}
impl<'a> fmt::Debug for VarPtr<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
f.debug_tuple("VarPtr").field(&self.eq).finish()
} else {
fmt::Debug::fmt(&self.eq, f)
}
}
}
pub trait AnyWeakVar: Any + Send + Sync + crate::private::Sealed {
fn clone_any(&self) -> BoxedAnyWeakVar;
fn as_any(&self) -> &dyn Any;
fn strong_count(&self) -> usize;
fn weak_count(&self) -> usize;
fn upgrade_any(&self) -> Option<BoxedAnyVar>;
}
pub trait WeakVar<T: VarValue>: AnyWeakVar + Clone {
type Upgrade: Var<T>;
fn upgrade(&self) -> Option<Self::Upgrade>;
fn boxed(self) -> BoxedWeakVar<T>
where
Self: Sized,
{
Box::new(self)
}
}
pub trait IntoVar<T: VarValue> {
type Var: Var<T>;
fn into_var(self) -> Self::Var;
fn into_boxed_var(self) -> BoxedVar<T>
where
Self: Sized,
{
self.into_var().boxed()
}
}
pub struct VarModify<'a, T: VarValue> {
current_value: &'a T,
value: Cow<'a, T>,
update: bool,
tags: Vec<Box<dyn AnyVarValue>>,
custom_importance: Option<usize>,
}
impl<'a, T: VarValue> VarModify<'a, T> {
pub fn set(&mut self, new_value: T) {
self.value = Cow::Owned(new_value);
}
pub fn update(&mut self) {
self.update = true;
}
pub fn to_mut(&mut self) -> &mut T {
self.value.to_mut()
}
pub fn tags(&self) -> &[Box<dyn AnyVarValue>] {
&self.tags
}
pub fn push_tag(&mut self, tag: impl AnyVarValue) {
self.tags.push(Box::new(tag));
}
pub fn push_tags(&mut self, tags: Vec<Box<dyn AnyVarValue>>) {
if self.tags.is_empty() {
self.tags = tags;
} else {
self.tags.extend(tags);
}
}
pub fn set_modify_importance(&mut self, importance: usize) {
self.custom_importance = Some(importance);
}
pub fn new(current_value: &'a T) -> Self {
Self {
current_value,
value: Cow::Borrowed(current_value),
update: false,
tags: vec![],
custom_importance: None,
}
}
pub fn finish(self) -> (bool, Option<T>, bool, Vec<Box<dyn AnyVarValue>>, Option<usize>) {
match self.value {
Cow::Borrowed(_) => {
if self.update {
return (true, None, true, self.tags, self.custom_importance);
}
}
Cow::Owned(v) => {
if self.update || self.current_value != &v {
return (true, Some(v), self.update, self.tags, self.custom_importance);
}
}
}
(false, None, false, vec![], self.custom_importance)
}
}
impl<'a, T: VarValue> ops::Deref for VarModify<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.as_ref()
}
}
impl<'a, T: VarValue> std::convert::AsRef<T> for VarModify<'a, T> {
fn as_ref(&self) -> &T {
&self.value
}
}
pub struct AnyVarHookArgs<'a> {
value: &'a dyn AnyVarValue,
update: bool,
tags: &'a [Box<dyn AnyVarValue>],
}
impl<'a> AnyVarHookArgs<'a> {
pub fn new(value: &'a dyn AnyVarValue, update: bool, tags: &'a [Box<dyn AnyVarValue>]) -> Self {
Self { value, update, tags }
}
pub fn value(&self) -> &'a dyn AnyVarValue {
self.value
}
pub fn update(&self) -> bool {
self.update
}
pub fn value_type(&self) -> TypeId {
self.value.as_any().type_id()
}
pub fn tags(&self) -> &[Box<dyn AnyVarValue>] {
self.tags
}
pub fn tags_vec(&self) -> Vec<Box<dyn AnyVarValue>> {
self.tags.iter().map(|t| (*t).clone_boxed()).collect()
}
pub fn downcast_value<T: VarValue>(&self) -> Option<&T> {
self.value.as_any().downcast_ref()
}
pub fn downcast_tags<T: VarValue>(&self) -> impl Iterator<Item = &T> + '_ {
self.tags.iter().filter_map(|t| (*t).as_any().downcast_ref::<T>())
}
pub fn as_strong<T: VarValue>(&self) -> Option<VarHookArgs<T>> {
if TypeId::of::<T>() == self.value_type() {
Some(VarHookArgs {
any: self,
_t: PhantomData,
})
} else {
None
}
}
}
pub struct VarHookArgs<'a, T: VarValue> {
any: &'a AnyVarHookArgs<'a>,
_t: PhantomData<&'a T>,
}
impl<'a, T: VarValue> VarHookArgs<'a, T> {
pub fn value(&self) -> &'a T {
self.any.value.as_any().downcast_ref::<T>().unwrap()
}
}
impl<'a, T: VarValue> ops::Deref for VarHookArgs<'a, T> {
type Target = AnyVarHookArgs<'a>;
fn deref(&self) -> &Self::Target {
self.any
}
}
pub struct TraceValueArgs<'a, T: VarValue> {
args: &'a AnyVarHookArgs<'a>,
_type: PhantomData<&'a T>,
}
impl<'a, T: VarValue> ops::Deref for TraceValueArgs<'a, T> {
type Target = AnyVarHookArgs<'a>;
fn deref(&self) -> &Self::Target {
self.args
}
}
impl<'a, T: VarValue> TraceValueArgs<'a, T> {
pub fn value(&self) -> &'a T {
self.args.downcast_value::<T>().unwrap()
}
}
pub trait Var<T: VarValue>: IntoVar<T, Var = Self> + AnyVar + Clone {
type ReadOnly: Var<T>;
type ActualVar: Var<T>;
type Downgrade: WeakVar<T>;
type Map<O: VarValue>: Var<O>;
type MapBidi<O: VarValue>: Var<O>;
type FlatMap<O: VarValue, V: Var<O>>: Var<O>;
type FilterMap<O: VarValue>: Var<O>;
type FilterMapBidi<O: VarValue>: Var<O>;
type MapRef<O: VarValue>: Var<O>;
type MapRefBidi<O: VarValue>: Var<O>;
type Easing: Var<T>;
fn with<R, F>(&self, read: F) -> R
where
F: FnOnce(&T) -> R;
fn modify<F>(&self, modify: F) -> Result<(), VarIsReadOnlyError>
where
F: FnOnce(&mut VarModify<T>) + Send + 'static;
fn boxed(self) -> BoxedVar<T>
where
Self: Sized,
{
Box::new(self)
}
fn boxed_any(self) -> BoxedAnyVar
where
Self: Sized,
{
Box::new(self)
}
fn actual_var(self) -> Self::ActualVar;
fn downgrade(&self) -> Self::Downgrade;
fn into_value(self) -> T;
fn read_only(&self) -> Self::ReadOnly;
fn hook(&self, pos_modify_action: impl Fn(&VarHookArgs<T>) -> bool + Send + Sync + 'static) -> VarHandle {
self.hook_any(Box::new(move |a| pos_modify_action(&a.as_strong().unwrap())))
}
fn wait_update(&self) -> impl Future<Output = VarUpdateId> + Send + Sync {
crate::future::WaitUpdateFut::new(self)
}
fn wait_animation(&self) -> impl Future<Output = ()> + Send + Sync {
crate::future::WaitIsNotAnimatingFut::new(self)
}
fn wait_value(&self, predicate: impl Fn(&T) -> bool + Send + Sync) -> impl Future<Output = ()> + Send + Sync {
async move {
while !self.with(&predicate) {
let future = self.wait_update();
if self.with(&predicate) {
break;
}
future.await;
}
}
}
fn with_new<R, F>(&self, read: F) -> Option<R>
where
F: FnOnce(&T) -> R,
{
if self.is_new() {
Some(self.with(read))
} else {
None
}
}
fn get(&self) -> T {
self.with(Clone::clone)
}
fn get_text(&self) -> Txt
where
T: fmt::Display,
{
self.with(ToTxt::to_txt)
}
fn get_string(&self) -> String
where
T: fmt::Display,
{
self.with(ToString::to_string)
}
fn get_into(&self, value: &mut T) {
self.with(var_get_into(value))
}
fn get_ne(&self, value: &mut T) -> bool {
self.with(var_get_ne(value))
}
fn get_new(&self) -> Option<T> {
if self.is_new() {
Some(self.with(Clone::clone))
} else {
None
}
}
fn get_new_into(&self, value: &mut T) -> bool {
let is_new = self.is_new();
if is_new {
self.with(var_get_into(value));
}
is_new
}
fn get_new_ne(&self, value: &mut T) -> bool {
self.is_new() && self.get_ne(value)
}
fn set<I>(&self, value: I) -> Result<(), VarIsReadOnlyError>
where
I: Into<T>,
{
self.modify(var_set(value.into()))
}
fn set_from<I>(&self, other: &I) -> Result<(), VarIsReadOnlyError>
where
I: Var<T>,
{
if other.capabilities().is_always_static() {
self.set(other.get())
} else {
self.modify(var_set_from(other.clone().actual_var()))
}
}
fn set_from_map<Iv, I, M>(&self, other: &I, map: M) -> Result<(), VarIsReadOnlyError>
where
Iv: VarValue,
I: Var<Iv>,
M: FnOnce(&Iv) -> T + Send + 'static,
{
if other.capabilities().is_always_static() {
self.set(other.with(map))
} else {
self.modify(var_set_from_map(other.clone().actual_var(), map))
}
}
fn cow(&self) -> types::ArcCowVar<T, Self> {
types::ArcCowVar::new(self.clone())
}
fn map<O, M>(&self, map: M) -> Self::Map<O>
where
O: VarValue,
M: FnMut(&T) -> O + Send + 'static;
fn map_into<O>(&self) -> Self::Map<O>
where
O: VarValue,
T: Into<O>,
{
self.map(|v| v.clone().into())
}
fn map_to_txt(&self) -> Self::Map<Txt>
where
T: ToTxt,
{
self.map(ToTxt::to_txt)
}
fn map_to_string(&self) -> Self::Map<String>
where
T: ToString,
{
self.map(ToString::to_string)
}
fn map_bidi<O, M, B>(&self, map: M, map_back: B) -> Self::MapBidi<O>
where
O: VarValue,
M: FnMut(&T) -> O + Send + 'static,
B: FnMut(&O) -> T + Send + 'static;
fn flat_map<O, V, M>(&self, map: M) -> Self::FlatMap<O, V>
where
O: VarValue,
V: Var<O>,
M: FnMut(&T) -> V + Send + 'static;
fn filter_map<O, M, I>(&self, map: M, fallback: I) -> Self::FilterMap<O>
where
O: VarValue,
M: FnMut(&T) -> Option<O> + Send + 'static,
I: Fn() -> O + Send + Sync + 'static;
fn filter_try_into<O, I>(&self, fallback: I) -> Self::FilterMap<O>
where
O: VarValue,
T: TryInto<O>,
I: Fn() -> O + Send + Sync + 'static,
{
self.filter_map(|v| v.clone().try_into().ok(), fallback)
}
fn filter_parse<O, I>(&self, fallback: I) -> Self::FilterMap<O>
where
O: VarValue + std::str::FromStr,
T: AsRef<str>,
I: Fn() -> O + Send + Sync + 'static,
{
self.filter_map(|v| v.as_ref().parse().ok(), fallback)
}
fn filter_map_bidi<O, M, B, I>(&self, map: M, map_back: B, fallback: I) -> Self::FilterMapBidi<O>
where
O: VarValue,
M: FnMut(&T) -> Option<O> + Send + 'static,
B: FnMut(&O) -> Option<T> + Send + 'static,
I: Fn() -> O + Send + Sync + 'static;
fn map_ref<O, M>(&self, map: M) -> Self::MapRef<O>
where
O: VarValue,
M: Fn(&T) -> &O + Send + Sync + 'static;
fn map_ref_bidi<O, M, B>(&self, map: M, map_mut: B) -> Self::MapRefBidi<O>
where
O: VarValue,
M: Fn(&T) -> &O + Send + Sync + 'static,
B: Fn(&mut T) -> &mut O + Send + Sync + 'static;
fn bind_map<T2, V2, M>(&self, other: &V2, map: M) -> VarHandle
where
T2: VarValue,
V2: Var<T2>,
M: FnMut(&T) -> T2 + Send + 'static,
{
var_bind_map(self, other, map)
}
fn bind_filter_map<T2, V2, F>(&self, other: &V2, map: F) -> VarHandle
where
T2: VarValue,
V2: Var<T2>,
F: FnMut(&T) -> Option<T2> + Send + 'static,
{
var_bind_filter_map(self, other, map)
}
fn bind_map_bidi<T2, V2, M, B>(&self, other: &V2, map: M, map_back: B) -> VarHandles
where
T2: VarValue,
V2: Var<T2>,
M: FnMut(&T) -> T2 + Send + 'static,
B: FnMut(&T2) -> T + Send + 'static,
{
var_bind_map_bidi(self, other, map, map_back)
}
fn bind_filter_map_bidi<T2, V2, M, B>(&self, other: &V2, map: M, map_back: B) -> VarHandles
where
T2: VarValue,
V2: Var<T2>,
M: FnMut(&T) -> Option<T2> + Send + 'static,
B: FnMut(&T2) -> Option<T> + Send + 'static,
{
var_bind_filter_map_bidi(self, other, map, map_back)
}
fn bind<V2>(&self, other: &V2) -> VarHandle
where
V2: Var<T>,
{
self.bind_map(other, Clone::clone)
}
fn set_bind<V2>(&self, other: &V2) -> VarHandle
where
V2: Var<T>,
{
let _ = other.set_from(self);
self.bind(other)
}
fn bind_bidi<V2>(&self, other: &V2) -> VarHandles
where
V2: Var<T>,
{
self.bind_map_bidi(other, Clone::clone, Clone::clone)
}
fn trace_value<E, S>(&self, mut enter_value: E) -> VarHandle
where
E: FnMut(&TraceValueArgs<T>) -> S + Send + 'static,
S: Send + 'static,
{
let span = self.with(|v| {
enter_value(&TraceValueArgs {
args: &AnyVarHookArgs::new(v, false, &[]),
_type: PhantomData,
})
});
let data = Mutex::new((Some(span), enter_value));
self.hook_any(Box::new(move |args| {
let mut data = data.lock();
let (span, enter_value) = &mut *data;
let _ = span.take();
*span = Some(enter_value(&TraceValueArgs { args, _type: PhantomData }));
true
}))
}
fn animate<A>(&self, animate: A) -> animation::AnimationHandle
where
A: FnMut(&animation::Animation, &mut VarModify<T>) + Send + 'static,
{
animation::var_animate(self, animate)
}
fn sequence<A>(&self, animate: A) -> VarHandle
where
A: FnMut(&<<Self::ActualVar as Var<T>>::Downgrade as WeakVar<T>>::Upgrade) -> animation::AnimationHandle + Send + 'static,
{
animation::var_sequence(self, animate)
}
fn set_ease<S, E, F>(&self, start_value: S, end_value: E, duration: Duration, easing: F) -> animation::AnimationHandle
where
T: Transitionable,
S: Into<T>,
E: Into<T>,
F: Fn(EasingTime) -> EasingStep + Send + 'static,
{
self.set_ease_with(start_value, end_value, duration, easing, animation::Transition::sample)
}
fn set_ease_oci<S, E, F>(&self, start_value: S, end_value: E, duration: Duration, easing: F) -> animation::AnimationHandle
where
T: Transitionable,
S: Into<T>,
E: Into<T>,
F: Fn(EasingTime) -> EasingStep + Send + 'static,
{
self.set_ease_oci_with(start_value, end_value, duration, easing, animation::Transition::sample)
}
fn set_ease_with<S, E, F, Sa>(
&self,
start_value: S,
end_value: E,
duration: Duration,
easing: F,
sampler: Sa,
) -> animation::AnimationHandle
where
T: Transitionable,
S: Into<T>,
E: Into<T>,
F: Fn(EasingTime) -> EasingStep + Send + 'static,
Sa: Fn(&animation::Transition<T>, EasingStep) -> T + Send + 'static,
{
self.animate(animation::var_set_ease_with(
start_value.into(),
end_value.into(),
duration,
easing,
999.fct(),
sampler,
))
}
fn set_ease_oci_with<S, E, F, Sa>(
&self,
start_value: S,
end_value: E,
duration: Duration,
easing: F,
sampler: Sa,
) -> animation::AnimationHandle
where
T: Transitionable,
S: Into<T>,
E: Into<T>,
F: Fn(EasingTime) -> EasingStep + Send + 'static,
Sa: Fn(&animation::Transition<T>, EasingStep) -> T + Send + 'static,
{
self.animate(animation::var_set_ease_oci_with(
start_value.into(),
end_value.into(),
duration,
easing,
999.fct(),
sampler,
))
}
fn ease<E, F>(&self, new_value: E, duration: Duration, easing: F) -> animation::AnimationHandle
where
T: Transitionable,
E: Into<T>,
F: Fn(EasingTime) -> EasingStep + Send + 'static,
{
self.ease_with(new_value, duration, easing, animation::Transition::sample)
}
fn ease_oci<E, F>(&self, new_value: E, duration: Duration, easing: F) -> animation::AnimationHandle
where
T: Transitionable,
E: Into<T>,
F: Fn(EasingTime) -> EasingStep + Send + 'static,
{
self.ease_oci_with(new_value, duration, easing, animation::Transition::sample)
}
fn ease_with<E, F, S>(&self, new_value: E, duration: Duration, easing: F, sampler: S) -> animation::AnimationHandle
where
T: Transitionable,
E: Into<T>,
F: Fn(EasingTime) -> EasingStep + Send + 'static,
S: Fn(&animation::Transition<T>, EasingStep) -> T + Send + 'static,
{
self.animate(animation::var_set_ease_with(
self.get(),
new_value.into(),
duration,
easing,
0.fct(),
sampler,
))
}
fn ease_oci_with<E, F, S>(&self, new_value: E, duration: Duration, easing: F, sampler: S) -> animation::AnimationHandle
where
T: Transitionable,
E: Into<T>,
F: Fn(EasingTime) -> EasingStep + Send + 'static,
S: Fn(&animation::Transition<T>, EasingStep) -> T + Send + 'static,
{
self.animate(animation::var_set_ease_oci_with(
self.get(),
new_value.into(),
duration,
easing,
0.fct(),
sampler,
))
}
fn set_ease_keyed<F>(&self, keys: Vec<(Factor, T)>, duration: Duration, easing: F) -> animation::AnimationHandle
where
T: Transitionable,
F: Fn(EasingTime) -> EasingStep + Send + 'static,
{
self.set_ease_keyed_with(keys, duration, easing, animation::TransitionKeyed::sample)
}
fn set_ease_keyed_with<F, S>(&self, keys: Vec<(Factor, T)>, duration: Duration, easing: F, sampler: S) -> animation::AnimationHandle
where
T: Transitionable,
F: Fn(EasingTime) -> EasingStep + Send + 'static,
S: Fn(&animation::TransitionKeyed<T>, EasingStep) -> T + Send + 'static,
{
if let Some(transition) = animation::TransitionKeyed::new(keys) {
self.animate(animation::var_set_ease_keyed_with(transition, duration, easing, 999.fct(), sampler))
} else {
animation::AnimationHandle::dummy()
}
}
fn ease_keyed<F>(&self, keys: Vec<(Factor, T)>, duration: Duration, easing: F) -> animation::AnimationHandle
where
T: Transitionable,
F: Fn(EasingTime) -> EasingStep + Send + 'static,
{
self.ease_keyed_with(keys, duration, easing, animation::TransitionKeyed::sample)
}
fn ease_keyed_with<F, S>(&self, mut keys: Vec<(Factor, T)>, duration: Duration, easing: F, sampler: S) -> animation::AnimationHandle
where
T: Transitionable,
F: Fn(EasingTime) -> EasingStep + Send + 'static,
S: Fn(&animation::TransitionKeyed<T>, EasingStep) -> T + Send + 'static,
{
keys.insert(0, (0.fct(), self.get()));
let transition = animation::TransitionKeyed::new(keys).unwrap();
self.animate(animation::var_set_ease_keyed_with(transition, duration, easing, 0.fct(), sampler))
}
fn step<N>(&self, new_value: N, delay: Duration) -> animation::AnimationHandle
where
N: Into<T>,
{
self.animate(animation::var_step(new_value.into(), delay))
}
fn step_oci<N>(&self, new_value: N, delay: Duration) -> animation::AnimationHandle
where
N: Into<T>,
{
self.animate(animation::var_step_oci([self.get(), new_value.into()], delay, false))
}
fn set_step_oci<V0, V1>(&self, from: V0, to: V1, delay: Duration) -> animation::AnimationHandle
where
V0: Into<T>,
V1: Into<T>,
{
self.animate(animation::var_step_oci([from.into(), to.into()], delay, true))
}
fn steps<F>(&self, steps: Vec<(Factor, T)>, duration: Duration, easing: F) -> animation::AnimationHandle
where
F: Fn(EasingTime) -> EasingStep + Send + 'static,
{
self.animate(animation::var_steps(steps, duration, easing))
}
fn chase<N, F>(&self, first_target: N, duration: Duration, easing: F) -> animation::ChaseAnimation<T>
where
N: Into<T>,
F: Fn(EasingTime) -> EasingStep + Send + 'static,
T: Transitionable,
{
animation::var_chase(self.clone().boxed(), first_target.into(), duration, easing)
}
fn easing<F>(&self, duration: Duration, easing: F) -> Self::Easing
where
T: Transitionable,
F: Fn(EasingTime) -> EasingStep + Send + Sync + 'static;
fn easing_with<F, S>(&self, duration: Duration, easing: F, sampler: S) -> Self::Easing
where
T: Transitionable,
F: Fn(EasingTime) -> EasingStep + Send + Sync + 'static,
S: Fn(&animation::Transition<T>, EasingStep) -> T + Send + Sync + 'static;
fn debug(&self) -> types::VarDebug<T, Self> {
types::VarDebug {
var: self,
_t: PhantomData,
}
}
fn display(&self) -> types::VarDisplay<T, Self>
where
T: fmt::Display,
{
types::VarDisplay {
var: self,
_t: PhantomData,
}
}
}
fn var_bind_map<T, T2, V2, M>(source: &impl Var<T>, other: &V2, map: M) -> VarHandle
where
T: VarValue,
T2: VarValue,
V2: Var<T2>,
M: FnMut(&T) -> T2 + Send + 'static,
{
#[cfg(feature = "dyn_closure")]
let map: Box<dyn FnMut(&T) -> T2 + Send> = Box::new(map);
var_bind_map_impl(source, other, map)
}
fn var_bind_map_impl<T, T2, V2, M>(source: &impl Var<T>, other: &V2, mut map: M) -> VarHandle
where
T: VarValue,
T2: VarValue,
V2: Var<T2>,
M: FnMut(&T) -> T2 + Send + 'static,
{
var_bind(source, 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();
}
});
})
}
fn var_bind_filter_map<T, T2, V2, F>(source: &impl Var<T>, other: &V2, map: F) -> VarHandle
where
T: VarValue,
T2: VarValue,
V2: Var<T2>,
F: FnMut(&T) -> Option<T2> + Send + 'static,
{
#[cfg(feature = "dyn_closure")]
let map: Box<dyn FnMut(&T) -> Option<T2> + Send> = Box::new(map);
var_bind_filter_map_impl(source, other, map)
}
fn var_bind_filter_map_impl<T, T2, V2, F>(source: &impl Var<T>, other: &V2, mut map: F) -> VarHandle
where
T: VarValue,
T2: VarValue,
V2: Var<T2>,
F: FnMut(&T) -> Option<T2> + Send + 'static,
{
var_bind(source, other, move |value, args, other| {
if let Some(value) = map(value) {
let update = args.update;
let _ = other.modify(move |vm| {
vm.set(value);
if update {
vm.update();
}
});
}
})
}
fn var_bind_map_bidi<T, T2, V2, M, B>(source: &impl Var<T>, other: &V2, map: M, map_back: B) -> VarHandles
where
T: VarValue,
T2: VarValue,
V2: Var<T2>,
M: FnMut(&T) -> T2 + Send + 'static,
B: FnMut(&T2) -> T + Send + 'static,
{
#[cfg(feature = "dyn_closure")]
let map: Box<dyn FnMut(&T) -> T2 + Send + 'static> = Box::new(map);
#[cfg(feature = "dyn_closure")]
let map_back: Box<dyn FnMut(&T2) -> T + Send + 'static> = Box::new(map_back);
var_bind_map_bidi_impl(source, other, map, map_back)
}
fn var_bind_map_bidi_impl<T, T2, V2, M, B>(source: &impl Var<T>, other: &V2, mut map: M, mut map_back: B) -> VarHandles
where
T: VarValue,
T2: VarValue,
V2: Var<T2>,
M: FnMut(&T) -> T2 + Send + 'static,
B: FnMut(&T2) -> T + Send + 'static,
{
let source_tag = types::SourceVarTag::new(source);
let source_to_other = var_bind(source, other, move |value, args, other| {
let is_from_other = args
.downcast_tags::<types::SourceVarTag>()
.any(|&b| b == types::SourceVarTag::new(&other));
if !is_from_other {
let value = map(value);
let update = args.update;
let _ = other.modify(move |vm| {
vm.set(value);
vm.push_tag(source_tag);
if update {
vm.update();
}
});
}
});
let other_tag = types::SourceVarTag::new(other);
let other_to_source = var_bind(other, source, move |value, args, source| {
let is_from_source = args
.downcast_tags::<types::SourceVarTag>()
.any(|&b| b == types::SourceVarTag::new(&source));
if !is_from_source {
let value = map_back(value);
let update = args.update;
let _ = source.modify(move |vm| {
vm.set(value);
vm.push_tag(other_tag);
if update {
vm.update();
}
});
}
});
[source_to_other, other_to_source].into_iter().collect()
}
fn var_bind_filter_map_bidi<T, T2, V2, M, B>(source: &impl Var<T>, other: &V2, map: M, map_back: B) -> VarHandles
where
T: VarValue,
T2: VarValue,
V2: Var<T2>,
M: FnMut(&T) -> Option<T2> + Send + 'static,
B: FnMut(&T2) -> Option<T> + Send + 'static,
{
#[cfg(feature = "dyn_closure")]
let map: Box<dyn FnMut(&T) -> Option<T2> + Send + 'static> = Box::new(map);
#[cfg(feature = "dyn_closure")]
let map_back: Box<dyn FnMut(&T2) -> Option<T> + Send + 'static> = Box::new(map_back);
var_bind_filter_map_bidi_impl(source, other, map, map_back)
}
fn var_bind_filter_map_bidi_impl<T, T2, V2, M, B>(source: &impl Var<T>, other: &V2, mut map: M, mut map_back: B) -> VarHandles
where
T: VarValue,
T2: VarValue,
V2: Var<T2>,
M: FnMut(&T) -> Option<T2> + Send + 'static,
B: FnMut(&T2) -> Option<T> + Send + 'static,
{
let source_tag = types::SourceVarTag::new(source);
let source_to_other = var_bind(source, other, move |value, args, other| {
let is_from_other = args
.downcast_tags::<types::SourceVarTag>()
.any(|&b| b == types::SourceVarTag::new(&other));
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(source_tag);
if update {
vm.update();
}
});
}
}
});
let other_tag = types::SourceVarTag::new(other);
let other_to_source = var_bind(other, source, move |value, args, source| {
let is_from_source = args
.downcast_tags::<types::SourceVarTag>()
.any(|&b| b == types::SourceVarTag::new(&source));
if !is_from_source {
if let Some(value) = map_back(value) {
let update = args.update;
let _ = source.modify(move |vm| {
vm.set(value);
vm.push_tag(other_tag);
if update {
vm.update();
}
});
}
}
});
[source_to_other, other_to_source].into_iter().collect()
}
fn var_hold_hook(source: &dyn AnyVar) -> Box<dyn Fn(&AnyVarHookArgs) -> bool + Send + Sync> {
let source = source.clone_any();
Box::new(move |_| {
let _hold = &source;
true
})
}
fn var_map<T: VarValue, O: VarValue>(source: &impl Var<T>, map: impl FnMut(&T) -> O + Send + 'static) -> ReadOnlyArcVar<O> {
#[cfg(feature = "dyn_closure")]
let map: Box<dyn FnMut(&T) -> O + Send> = Box::new(map);
var_map_impl(source, map)
}
fn var_map_impl<T: VarValue, O: VarValue>(source: &impl Var<T>, mut map: impl FnMut(&T) -> O + Send + 'static) -> ReadOnlyArcVar<O> {
let mapped = var(source.with(&mut map));
var_bind_map_impl(source, &mapped, map).perm();
mapped.hook_any(var_hold_hook(source)).perm();
mapped.read_only()
}
fn var_map_ctx<T: VarValue, O: VarValue>(
source: &impl Var<T>,
map: impl FnMut(&T) -> O + Send + 'static,
) -> contextualized::ContextualizedVar<O> {
#[cfg(feature = "dyn_closure")]
let map: Box<dyn FnMut(&T) -> O + Send> = Box::new(map);
var_map_ctx_impl(source, map)
}
fn var_map_ctx_impl<T: VarValue, O: VarValue>(
source: &impl Var<T>,
map: impl FnMut(&T) -> O + Send + 'static,
) -> contextualized::ContextualizedVar<O> {
let source = source.clone();
let map = Arc::new(Mutex::new(map));
types::ContextualizedVar::new(move || {
let other = var(source.with(&mut *map.lock()));
let map = map.clone();
source.bind_map(&other, move |t| map.lock()(t)).perm();
other.read_only()
})
}
fn var_map_mixed<T: VarValue, O: VarValue>(source: &impl Var<T>, map: impl FnMut(&T) -> O + Send + 'static) -> BoxedVar<O> {
#[cfg(feature = "dyn_closure")]
let map: Box<dyn FnMut(&T) -> O + Send> = Box::new(map);
if source.is_contextual() {
var_map_ctx_impl(source, map).boxed()
} else if source.capabilities().is_always_static() {
LocalVar(source.with(map)).boxed()
} else {
var_map_impl(source, map).boxed()
}
}
fn var_map_bidi<T, O, M, B>(source: &impl Var<T>, map: M, map_back: B) -> ArcVar<O>
where
T: VarValue,
O: VarValue,
M: FnMut(&T) -> O + Send + 'static,
B: FnMut(&O) -> T + Send + 'static,
{
#[cfg(feature = "dyn_closure")]
let map: Box<dyn FnMut(&T) -> O + Send> = Box::new(map);
#[cfg(feature = "dyn_closure")]
let map_back: Box<dyn FnMut(&O) -> T + Send> = Box::new(map_back);
var_map_bidi_impl(source, map, map_back)
}
fn var_map_bidi_impl<T, O, M, B>(source: &impl Var<T>, mut map: M, map_back: B) -> ArcVar<O>
where
T: VarValue,
O: VarValue,
M: FnMut(&T) -> O + Send + 'static,
B: FnMut(&O) -> T + Send + 'static,
{
let mapped = var(source.with(&mut map));
var_bind_map_bidi_impl(source, &mapped, map, map_back).perm();
mapped.hook_any(var_hold_hook(source)).perm();
mapped
}
fn var_map_bidi_ctx<T, O, M, B>(source: &impl Var<T>, map: M, map_back: B) -> types::ContextualizedVar<O>
where
T: VarValue,
O: VarValue,
M: FnMut(&T) -> O + Send + 'static,
B: FnMut(&O) -> T + Send + 'static,
{
#[cfg(feature = "dyn_closure")]
let map: Box<dyn FnMut(&T) -> O + Send> = Box::new(map);
#[cfg(feature = "dyn_closure")]
let map_back: Box<dyn FnMut(&O) -> T + Send> = Box::new(map_back);
var_map_bidi_ctx_impl(source, map, map_back)
}
fn var_map_bidi_ctx_impl<T, O, M, B>(source: &impl Var<T>, map: M, map_back: B) -> types::ContextualizedVar<O>
where
T: VarValue,
O: VarValue,
M: FnMut(&T) -> O + Send + 'static,
B: FnMut(&O) -> T + Send + 'static,
{
let me = source.clone();
let map = Arc::new(Mutex::new(map));
let map_back = Arc::new(Mutex::new(map_back));
types::ContextualizedVar::new(move || {
let other = var(me.with(&mut *map.lock()));
let map = map.clone();
let map_back = map_back.clone();
me.bind_map_bidi(&other, move |i| map.lock()(i), move |o| map_back.lock()(o)).perm();
other
})
}
fn var_map_bidi_mixed<T, O, M, B>(source: &impl Var<T>, map: M, map_back: B) -> BoxedVar<O>
where
T: VarValue,
O: VarValue,
M: FnMut(&T) -> O + Send + 'static,
B: FnMut(&O) -> T + Send + 'static,
{
#[cfg(feature = "dyn_closure")]
let map: Box<dyn FnMut(&T) -> O + Send> = Box::new(map);
#[cfg(feature = "dyn_closure")]
let map_back: Box<dyn FnMut(&O) -> T + Send> = Box::new(map_back);
if source.is_contextual() {
var_map_bidi_ctx_impl(source, map, map_back).boxed()
} else if source.capabilities().is_always_static() {
LocalVar(source.with(map)).boxed()
} else {
var_map_bidi_impl(source, map, map_back).boxed()
}
}
fn var_flat_map<T, O, V, M>(source: &impl Var<T>, map: M) -> types::ArcFlatMapVar<O, V>
where
T: VarValue,
O: VarValue,
V: Var<O>,
M: FnMut(&T) -> V + Send + 'static,
{
#[cfg(feature = "dyn_closure")]
let map: Box<dyn FnMut(&T) -> V + Send + 'static> = Box::new(map);
var_flat_map_impl(source, map)
}
fn var_flat_map_impl<T, O, V, M>(source: &impl Var<T>, map: M) -> types::ArcFlatMapVar<O, V>
where
T: VarValue,
O: VarValue,
V: Var<O>,
M: FnMut(&T) -> V + Send + 'static,
{
types::ArcFlatMapVar::new(source, map)
}
fn var_flat_map_ctx<T, O, V, M>(source: &impl Var<T>, map: M) -> types::ContextualizedVar<O>
where
T: VarValue,
O: VarValue,
V: Var<O>,
M: FnMut(&T) -> V + Send + 'static,
{
#[cfg(feature = "dyn_closure")]
let map: Box<dyn FnMut(&T) -> V + Send + 'static> = Box::new(map);
var_flat_map_ctx_impl(source, map)
}
fn var_flat_map_ctx_impl<T, O, V, M>(source: &impl Var<T>, map: M) -> types::ContextualizedVar<O>
where
T: VarValue,
O: VarValue,
V: Var<O>,
M: FnMut(&T) -> V + Send + 'static,
{
let me = source.clone();
let map = Arc::new(Mutex::new(map));
types::ContextualizedVar::new(move || {
let map = map.clone();
types::ArcFlatMapVar::new(&me, move |i| map.lock()(i))
})
}
fn var_flat_map_mixed<T, O, V, M>(source: &impl Var<T>, map: M) -> BoxedVar<O>
where
T: VarValue,
O: VarValue,
V: Var<O>,
M: FnMut(&T) -> V + Send + 'static,
{
#[cfg(feature = "dyn_closure")]
let map: Box<dyn FnMut(&T) -> V + Send + 'static> = Box::new(map);
if source.is_contextual() {
var_flat_map_ctx_impl(source, map).boxed()
} else if source.capabilities().is_always_static() {
source.with(map).boxed()
} else {
var_flat_map_impl(source, map).boxed()
}
}
fn var_filter_map<T, O, M, I>(source: &impl Var<T>, map: M, fallback: I) -> ReadOnlyArcVar<O>
where
T: VarValue,
O: VarValue,
M: FnMut(&T) -> Option<O> + Send + 'static,
I: Fn() -> O + Send + Sync + 'static,
{
#[cfg(feature = "dyn_closure")]
let map: Box<dyn FnMut(&T) -> Option<O> + Send + 'static> = Box::new(map);
#[cfg(feature = "dyn_closure")]
let fallback: Box<dyn Fn() -> O + Send + Sync + 'static> = Box::new(fallback);
var_filter_map_impl(source, map, fallback)
}
fn var_filter_map_impl<T, O, M, I>(source: &impl Var<T>, mut map: M, fallback: I) -> ReadOnlyArcVar<O>
where
T: VarValue,
O: VarValue,
M: FnMut(&T) -> Option<O> + Send + 'static,
I: Fn() -> O + Send + Sync + 'static,
{
let mapped = var(source.with(&mut map).unwrap_or_else(&fallback));
source.bind_filter_map(&mapped, map).perm();
mapped.hook_any(var_hold_hook(source)).perm();
mapped.read_only()
}
fn var_filter_map_ctx<T, O, M, I>(source: &impl Var<T>, map: M, fallback: I) -> types::ContextualizedVar<O>
where
T: VarValue,
O: VarValue,
M: FnMut(&T) -> Option<O> + Send + 'static,
I: Fn() -> O + Send + Sync + 'static,
{
#[cfg(feature = "dyn_closure")]
let map: Box<dyn FnMut(&T) -> Option<O> + Send + 'static> = Box::new(map);
#[cfg(feature = "dyn_closure")]
let fallback: Box<dyn Fn() -> O + Send + Sync + 'static> = Box::new(fallback);
var_filter_map_ctx_impl(source, map, fallback)
}
fn var_filter_map_ctx_impl<T, O, M, I>(source: &impl Var<T>, map: M, fallback: I) -> types::ContextualizedVar<O>
where
T: VarValue,
O: VarValue,
M: FnMut(&T) -> Option<O> + Send + 'static,
I: Fn() -> O + Send + Sync + 'static,
{
let me = source.clone();
let map = Arc::new(Mutex::new(map));
types::ContextualizedVar::new(move || {
let other = var(me.with(&mut *map.lock()).unwrap_or_else(&fallback));
let map = map.clone();
me.bind_filter_map(&other, move |i| map.lock()(i)).perm();
other.read_only()
})
}
fn var_filter_map_mixed<T, O, M, I>(source: &impl Var<T>, map: M, fallback: I) -> BoxedVar<O>
where
T: VarValue,
O: VarValue,
M: FnMut(&T) -> Option<O> + Send + 'static,
I: Fn() -> O + Send + Sync + 'static,
{
#[cfg(feature = "dyn_closure")]
let map: Box<dyn FnMut(&T) -> Option<O> + Send + 'static> = Box::new(map);
#[cfg(feature = "dyn_closure")]
let fallback: Box<dyn Fn() -> O + Send + Sync + 'static> = Box::new(fallback);
if source.is_contextual() {
var_filter_map_ctx_impl(source, map, fallback).boxed()
} else if source.capabilities().is_always_static() {
LocalVar(source.with(map).unwrap_or_else(fallback)).boxed()
} else {
var_filter_map_impl(source, map, fallback).boxed()
}
}
fn var_filter_map_bidi<T, O, M, B, I>(source: &impl Var<T>, map: M, map_back: B, fallback: I) -> ArcVar<O>
where
T: VarValue,
O: VarValue,
M: FnMut(&T) -> Option<O> + Send + 'static,
B: FnMut(&O) -> Option<T> + Send + 'static,
I: Fn() -> O + Send + Sync + 'static,
{
#[cfg(feature = "dyn_closure")]
let map: Box<dyn FnMut(&T) -> Option<O> + Send + 'static> = Box::new(map);
#[cfg(feature = "dyn_closure")]
let map_back: Box<dyn FnMut(&O) -> Option<T> + Send + 'static> = Box::new(map_back);
#[cfg(feature = "dyn_closure")]
let fallback: Box<dyn Fn() -> O + Send + Sync + 'static> = Box::new(fallback);
var_filter_map_bidi_impl(source, map, map_back, fallback)
}
fn var_filter_map_bidi_impl<T, O, M, B, I>(source: &impl Var<T>, mut map: M, map_back: B, fallback: I) -> ArcVar<O>
where
T: VarValue,
O: VarValue,
M: FnMut(&T) -> Option<O> + Send + 'static,
B: FnMut(&O) -> Option<T> + Send + 'static,
I: Fn() -> O + Send + Sync + 'static,
{
let mapped = var(source.with(&mut map).unwrap_or_else(&fallback));
source.bind_filter_map_bidi(&mapped, map, map_back).perm();
mapped.hook_any(var_hold_hook(source)).perm();
mapped
}
fn var_filter_map_bidi_ctx<T, O, M, B, I>(source: &impl Var<T>, map: M, map_back: B, fallback: I) -> types::ContextualizedVar<O>
where
T: VarValue,
O: VarValue,
M: FnMut(&T) -> Option<O> + Send + 'static,
B: FnMut(&O) -> Option<T> + Send + 'static,
I: Fn() -> O + Send + Sync + 'static,
{
#[cfg(feature = "dyn_closure")]
let map: Box<dyn FnMut(&T) -> Option<O> + Send + 'static> = Box::new(map);
#[cfg(feature = "dyn_closure")]
let map_back: Box<dyn FnMut(&O) -> Option<T> + Send + 'static> = Box::new(map_back);
#[cfg(feature = "dyn_closure")]
let fallback: Box<dyn Fn() -> O + Send + Sync + 'static> = Box::new(fallback);
var_filter_map_bidi_ctx_impl(source, map, map_back, fallback)
}
fn var_filter_map_bidi_ctx_impl<T, O, M, B, I>(source: &impl Var<T>, map: M, map_back: B, fallback: I) -> types::ContextualizedVar<O>
where
T: VarValue,
O: VarValue,
M: FnMut(&T) -> Option<O> + Send + 'static,
B: FnMut(&O) -> Option<T> + Send + 'static,
I: Fn() -> O + Send + Sync + 'static,
{
let me = source.clone();
let map = Arc::new(Mutex::new(map));
let map_back = Arc::new(Mutex::new(map_back));
types::ContextualizedVar::new(move || {
let other = var(me.with(&mut *map.lock()).unwrap_or_else(&fallback));
let map = map.clone();
let map_back = map_back.clone();
me.bind_filter_map_bidi(&other, move |i| map.lock()(i), move |o| map_back.lock()(o))
.perm();
other
})
}
fn var_filter_map_bidi_mixed<T, O, M, B, I>(source: &impl Var<T>, map: M, map_back: B, fallback: I) -> BoxedVar<O>
where
T: VarValue,
O: VarValue,
M: FnMut(&T) -> Option<O> + Send + 'static,
B: FnMut(&O) -> Option<T> + Send + 'static,
I: Fn() -> O + Send + Sync + 'static,
{
#[cfg(feature = "dyn_closure")]
let map: Box<dyn FnMut(&T) -> Option<O> + Send + 'static> = Box::new(map);
#[cfg(feature = "dyn_closure")]
let map_back: Box<dyn FnMut(&O) -> Option<T> + Send + 'static> = Box::new(map_back);
#[cfg(feature = "dyn_closure")]
let fallback: Box<dyn Fn() -> O + Send + Sync + 'static> = Box::new(fallback);
if source.is_contextual() {
var_filter_map_bidi_ctx_impl(source, map, map_back, fallback).boxed()
} else if source.capabilities().is_always_static() {
LocalVar(source.with(map).unwrap_or_else(fallback)).boxed()
} else {
var_filter_map_bidi_impl(source, map, map_back, fallback).boxed()
}
}
fn var_map_ref<T, S, O, M>(source: &S, map: M) -> types::MapRef<T, O, S>
where
T: VarValue,
S: Var<T>,
O: VarValue,
M: Fn(&T) -> &O + Send + Sync + 'static,
{
types::MapRef::new(source.clone(), Arc::new(map))
}
fn var_map_ref_bidi<T, S, O, M, B>(source: &S, map: M, map_mut: B) -> types::MapRefBidi<T, O, S>
where
T: VarValue,
S: Var<T>,
O: VarValue,
M: Fn(&T) -> &O + Send + Sync + 'static,
B: Fn(&mut T) -> &mut O + Send + Sync + 'static,
{
types::MapRefBidi::new(source.clone(), Arc::new(map), Arc::new(map_mut))
}
fn var_easing<T, F>(source: &impl Var<T>, duration: Duration, easing: F) -> ReadOnlyArcVar<T>
where
T: VarValue + Transitionable,
F: Fn(EasingTime) -> EasingStep + Send + Sync + 'static,
{
let easing_fn = Arc::new(easing);
let easing_var = var(source.get());
let mut _anim_handle = animation::AnimationHandle::dummy();
var_bind(source, &easing_var, move |value, args, easing_var| {
_anim_handle = easing_var.ease(value.clone(), duration, clmv!(easing_fn, |t| easing_fn(t)));
if args.update {
easing_var.update();
}
})
.perm();
easing_var.hook_any(var_hold_hook(source)).perm();
easing_var.read_only()
}
fn var_easing_ctx<T, F>(source: &impl Var<T>, duration: Duration, easing: F) -> types::ContextualizedVar<T>
where
T: VarValue + Transitionable,
F: Fn(EasingTime) -> EasingStep + Send + Sync + 'static,
{
let source = source.clone();
let easing_fn = Arc::new(easing);
types::ContextualizedVar::new(move || {
let easing_var = var(source.get());
let easing_fn = easing_fn.clone();
let mut _anim_handle = animation::AnimationHandle::dummy();
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()
})
}
fn var_easing_mixed<T, F>(source: &impl Var<T>, duration: Duration, easing: F) -> BoxedVar<T>
where
T: VarValue + Transitionable,
F: Fn(EasingTime) -> EasingStep + Send + Sync + 'static,
{
if source.is_contextual() {
var_easing_ctx(source, duration, easing).boxed()
} else if source.capabilities().is_always_static() {
source.clone().boxed()
} else {
var_easing(source, duration, easing).boxed()
}
}
fn var_easing_with<T, F, S>(source: &impl Var<T>, duration: Duration, easing: F, sampler: S) -> ReadOnlyArcVar<T>
where
T: VarValue + Transitionable,
F: Fn(EasingTime) -> EasingStep + Send + Sync + 'static,
S: Fn(&animation::Transition<T>, EasingStep) -> T + Send + Sync + 'static,
{
let fns = Arc::new((easing, sampler));
let easing_var = var(source.get());
let mut _anim_handle = animation::AnimationHandle::dummy();
var_bind(source, &easing_var, move |value, args, easing_var| {
_anim_handle = easing_var.ease_with(
value.clone(),
duration,
clmv!(fns, |t| (fns.0)(t)),
clmv!(fns, |t, s| (fns.1)(t, s)),
);
if args.update {
easing_var.update();
}
})
.perm();
easing_var.hook_any(var_hold_hook(source)).perm();
easing_var.read_only()
}
fn var_easing_with_ctx<T, F, S>(source: &impl Var<T>, duration: Duration, easing: F, sampler: S) -> types::ContextualizedVar<T>
where
T: VarValue + Transitionable,
F: Fn(EasingTime) -> EasingStep + Send + Sync + 'static,
S: Fn(&animation::Transition<T>, EasingStep) -> T + Send + Sync + 'static,
{
let source = source.clone();
let fns = Arc::new((easing, sampler));
types::ContextualizedVar::new(move || {
let easing_var = var(source.get());
let fns = fns.clone();
let mut _anim_handle = animation::AnimationHandle::dummy();
var_bind(&source, &easing_var, move |value, args, easing_var| {
_anim_handle = easing_var.ease_with(
value.clone(),
duration,
clmv!(fns, |t| (fns.0)(t)),
clmv!(fns, |t, s| (fns.1)(t, s)),
);
if args.update {
easing_var.update();
}
})
.perm();
easing_var.read_only()
})
}
fn var_easing_with_mixed<T, F, S>(source: &impl Var<T>, duration: Duration, easing: F, sampler: S) -> BoxedVar<T>
where
T: VarValue + Transitionable,
F: Fn(EasingTime) -> EasingStep + Send + Sync + 'static,
S: Fn(&animation::Transition<T>, EasingStep) -> T + Send + Sync + 'static,
{
if source.is_contextual() {
var_easing_with_ctx(source, duration, easing, sampler).boxed()
} else if source.capabilities().is_always_static() {
source.clone().boxed()
} else {
var_easing_with(source, duration, easing, sampler).boxed()
}
}
fn var_get_into<T>(value: &mut T) -> impl FnOnce(&T) + '_
where
T: VarValue,
{
move |var_value| value.clone_from(var_value)
}
fn var_get_ne<T>(value: &mut T) -> impl FnOnce(&T) -> bool + '_
where
T: VarValue + PartialEq,
{
move |var_value| {
let ne = var_value != value;
if ne {
value.clone_from(var_value);
}
ne
}
}
fn var_set<T>(value: T) -> impl FnOnce(&mut VarModify<T>)
where
T: VarValue,
{
move |var_value| {
var_value.set(value);
}
}
fn var_set_from<T, I>(other: I) -> impl FnOnce(&mut VarModify<T>)
where
T: VarValue,
I: Var<T>,
{
move |vm| {
let other_tag = types::SourceVarTag::new(&other);
let importance = other.modify_importance();
other.with(|other| {
if vm.as_ref() != other {
vm.set(other.clone());
vm.push_tag(other_tag);
}
vm.set_modify_importance(importance);
})
}
}
fn var_set_from_map<T, Iv, I, M>(other: I, map: M) -> impl FnOnce(&mut VarModify<T>)
where
Iv: VarValue,
I: Var<Iv>,
M: FnOnce(&Iv) -> T + Send + 'static,
T: VarValue,
{
move |vm| {
let value = other.with(map);
if vm.as_ref() != &value {
vm.set(value);
vm.push_tag(types::SourceVarTag::new(&other));
}
vm.set_modify_importance(other.modify_importance());
}
}
fn var_set_any<T>(value: Box<dyn AnyVarValue>) -> impl FnOnce(&mut VarModify<T>)
where
T: VarValue,
{
match value.into_any().downcast::<T>() {
Ok(value) => var_set(*value),
Err(_) => panic!("cannot `set_any`, incompatible type"),
}
}
fn var_update<T>(var_value: &mut VarModify<T>)
where
T: VarValue,
{
var_value.update();
}
fn var_debug<T>(value: &T) -> Txt
where
T: VarValue,
{
formatx!("{value:?}")
}
fn var_bind<I, O, V>(
input: &impl Var<I>,
output: &V,
update_output: impl FnMut(&I, &AnyVarHookArgs, <V::Downgrade as WeakVar<O>>::Upgrade) + Send + 'static,
) -> VarHandle
where
I: VarValue,
O: VarValue,
V: Var<O>,
{
if input.capabilities().is_always_static() || output.capabilities().is_always_read_only() {
VarHandle::dummy()
} else {
#[cfg(feature = "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)
}
}
fn var_bind_ok<I, O, W>(
input: &impl Var<I>,
wk_output: W,
update_output: impl FnMut(&I, &AnyVarHookArgs, W::Upgrade) + Send + 'static,
) -> VarHandle
where
I: VarValue,
O: VarValue,
W: WeakVar<O>,
{
let update_output = Mutex::new(update_output);
input.hook_any(Box::new(move |args| {
if let Some(output) = wk_output.upgrade() {
if output.capabilities().contains(VarCapability::MODIFY) {
if let Some(value) = args.downcast_value::<I>() {
update_output.lock()(value, args, output);
}
}
true
} else {
false
}
}))
}
macro_rules! impl_infallible_write {
(for<$T:ident>) => {
pub fn modify(&self, modify: impl FnOnce(&mut $crate::VarModify<$T>) + Send + 'static) {
Var::modify(self, modify).unwrap()
}
pub fn set(&self, value: impl Into<$T>) {
Var::set(self, value).unwrap()
}
pub fn update(&self) {
AnyVar::update(self).unwrap()
}
pub fn set_from<I: Var<$T>>(&self, other: &I) {
Var::set_from(self, other).unwrap()
}
pub fn set_from_map<Iv, I, M>(&self, other: &I, map: M)
where
Iv: VarValue,
I: Var<Iv>,
M: FnOnce(&Iv) -> $T + Send + 'static,
{
Var::set_from_map(self, other, map).unwrap()
}
};
}
use impl_infallible_write;