zng_var/
lib.rs

1#![doc(html_favicon_url = "https://zng-ui.github.io/res/zng-logo-icon.png")]
2#![doc(html_logo_url = "https://zng-ui.github.io/res/zng-logo.png")]
3//!
4//! Batch updated variables in an app context.
5//!
6//! # Crate
7//!
8#![doc = include_str!(concat!("../", std::env!("CARGO_PKG_README")))]
9// suppress nag about very simple boxed closure signatures.
10#![warn(unused_extern_crates)]
11#![warn(missing_docs)]
12#![deny(clippy::future_not_send)]
13
14macro_rules! trace_debug_error {
15    ($result:expr) => {
16        if let Err(e) = $result {
17            tracing::debug!("{e}")
18        }
19    };
20}
21
22mod var_value;
23pub use var_value::*;
24
25mod var_any;
26pub use var_any::*;
27
28mod var;
29pub use var::*;
30
31pub(crate) mod var_impl;
32pub use var_impl::*;
33
34pub mod animation;
35
36mod vars;
37pub use vars::*;
38
39mod vec;
40pub use vec::*;
41
42mod impls;
43
44pub(crate) mod future;
45
46///Implements `T: IntoVar<U>`, `T: IntoValue<U>` and optionally `U: From<T>` without boilerplate.
47///
48/// The macro syntax is one or more functions with signature `fn from(t: T) -> U`. The [`const_var`]
49/// kind is used for variables. The syntax also supports generic types and constraints, but not `where` constraints.
50/// You can also destructure the input if it is a tuple using the pattern `fn from((a, b): (A, B)) -> U`, but no other pattern
51/// matching in the input is supported.
52///
53/// The `U: From<T>` implement is optional, you can use the syntax `fn from(t: T) -> U;` to only generate
54/// the `T: IntoVar<U>` and `T: IntoValue<U>` implementations using an already implemented `U: From<T>`.
55///
56/// # Examples
57///
58/// The example declares an `enum` that represents the values possible in a property `foo` and
59/// then implements conversions from literals the user may want to type in a widget:
60///
61/// ```
62/// # use zng_var::*;
63/// #[derive(Debug, Clone, PartialEq)]
64/// pub enum FooValue {
65///     On,
66///     Off,
67///     NotSet,
68/// }
69///
70/// impl_from_and_into_var! {
71///     fn from(b: bool) -> FooValue {
72///         if b { FooValue::On } else { FooValue::Off }
73///     }
74///
75///     fn from(s: &str) -> FooValue {
76///         match s {
77///             "on" => FooValue::On,
78///             "off" => FooValue::Off,
79///             _ => FooValue::NotSet,
80///         }
81///     }
82///
83///     fn from(f: Foo) -> FooValue;
84/// }
85///
86/// impl From<Foo> for FooValue {
87///     fn from(foo: Foo) -> Self {
88///         Self::On
89///     }
90/// }
91/// # pub struct Foo;
92/// # fn assert(_: impl IntoVar<FooValue> + IntoValue<FooValue>) { }
93/// # assert(true);
94/// # assert("on");
95/// ```
96#[macro_export]
97macro_rules! impl_from_and_into_var {
98    ($($tt:tt)+) => {
99        $crate::__impl_from_and_into_var! { $($tt)* }
100    };
101}
102
103#[doc(hidden)]
104#[macro_export]
105macro_rules! __impl_from_and_into_var {
106    // START:
107    (
108        $(#[$docs:meta])*
109        fn from ( $($input:tt)+ )
110        $($rest:tt)+
111    ) => {
112        $crate::__impl_from_and_into_var! {
113            =input=>
114            [
115                input { $($input)+ }
116                generics { }
117                docs { $(#[$docs])* }
118            ]
119            ( $($input)+ ) $($rest)+
120        }
121    };
122    // GENERICS START:
123    (
124        $(#[$docs:meta])*
125        fn from <
126        $($rest:tt)+
127    ) => {
128        $crate::__impl_from_and_into_var! {
129            =generics=>
130            [
131                generics { < }
132                docs { $(#[$docs])* }
133            ]
134            $($rest)+
135        }
136    };
137    // GENERICS END `>`:
138    (
139        =generics=>
140        [
141            generics { $($generics:tt)+ }
142            $($config:tt)*
143        ]
144
145        >( $($input:tt)+ ) $($rest:tt)+
146    ) => {
147        $crate::__impl_from_and_into_var! {
148            =input=>
149            [
150                input { $($input)+ }
151                generics { $($generics)+ > }
152                $($config)*
153            ]
154            ( $($input)+ ) $($rest)+
155        }
156    };
157    // GENERICS END `>>`:
158    (
159        =generics=>
160        [
161            generics { $($generics:tt)+ }
162            $($config:tt)*
163        ]
164
165        >>( $($input:tt)+ ) $($rest:tt)+
166    ) => {
167        $crate::__impl_from_and_into_var! {
168            =input=>
169            [
170                input { $($input)+ }
171                generics { $($generics)+ >> }
172                $($config)*
173            ]
174            ( $($input)+ ) $($rest)+
175        }
176    };
177    // collect generics:
178    (
179        =generics=>
180        [
181            generics { $($generics:tt)+ }
182            $($config:tt)*
183        ]
184
185        $tt:tt $($rest:tt)+
186    ) => {
187        //zng_proc_macros::trace! {
188        $crate::__impl_from_and_into_var! {
189            =generics=>
190            [
191                generics { $($generics)+ $tt }
192                $($config)*
193            ]
194            $($rest)*
195        }
196        //}
197    };
198    // INPUT SIMPLE:
199    (
200        =input=>
201        [$($config:tt)*]
202        ($ident:ident : $Input:ty $(,)?) $($rest:tt)+
203    ) => {
204        $crate::__impl_from_and_into_var! {
205            =output=>
206            [
207                input_type { $Input }
208                $($config)*
209            ]
210            $($rest)+
211        }
212    };
213    // INPUT TUPLE:
214    (
215        =input=>
216        [$($config:tt)*]
217        (( $($destructure:tt)+ ) : $Input:ty $(,)?) $($rest:tt)+
218    ) => {
219        $crate::__impl_from_and_into_var! {
220            =output=>
221            [
222                input_type { $Input }
223                $($config)*
224            ]
225            $($rest)+
226        }
227    };
228    // INPUT ARRAY:
229    (
230        =input=>
231        [$($config:tt)*]
232        ([ $($destructure:tt)+ ] : $Input:ty $(,)?) $($rest:tt)+
233    ) => {
234        $crate::__impl_from_and_into_var! {
235            =output=>
236            [
237                input_type { $Input }
238                $($config)*
239            ]
240            $($rest)+
241        }
242    };
243
244    // OUTPUT (without From):
245    (
246        =output=>
247        [
248            input_type { $Input:ty }
249            input { $($input:tt)+ }
250            generics { $($generics:tt)* }
251            docs { $($docs:tt)* }
252        ]
253        -> $Output:ty
254        ;
255
256        $($rest:tt)*
257    ) => {
258        impl $($generics)* $crate::IntoVar<$Output> for $Input {
259            $($docs)*
260
261            fn into_var(self) -> $crate::Var<$Output> {
262                $crate::IntoVar::into_var(<$Output as From<$Input>>::from(self))
263            }
264        }
265
266        impl $($generics)* $crate::IntoValue<$Output> for $Input { }
267
268        // NEXT CONVERSION:
269        $crate::__impl_from_and_into_var! {
270            $($rest)*
271        }
272    };
273
274    // OUTPUT (with From):
275    (
276        =output=>
277        [
278            input_type { $Input:ty }
279            input { $($input:tt)+ }
280            generics { $($generics:tt)* }
281            docs { $($docs:tt)* }
282        ]
283        -> $Output:ty
284        $convert:block
285
286        $($rest:tt)*
287    ) => {
288        impl $($generics)* From<$Input> for $Output {
289            $($docs)*
290
291            fn from($($input)+) -> Self
292            $convert
293        }
294
295        impl $($generics)* $crate::IntoVar<$Output> for $Input {
296            $($docs)*
297
298            fn into_var(self) -> $crate::Var<$Output> {
299                $crate::IntoVar::into_var(<$Output as From<$Input>>::from(self))
300            }
301        }
302
303        impl $($generics)* $crate::IntoValue<$Output> for $Input { }
304
305        // NEXT CONVERSION:
306        $crate::__impl_from_and_into_var! {
307            $($rest)*
308        }
309    };
310
311    () => {
312        // END
313    };
314}