1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
///<span data-del-macro-root></span> New variable from an expression with interpolated vars.
///
/// # Interpolation
///
/// Other variables can be interpolated by quoting the var with `#{..}`. When
/// an expression contains other interpolated vars the expression var updates when
/// any of the interpolated vars update.
///
/// # Examples
///
/// ```
/// # use zng_var::*;
/// let var_a = var(10);
/// let var_b = var(10);
/// let name = "var_eq";
/// let var_eq = expr_var! {
///     let eq = #{var_a} == #{var_b};
///     println!("{} updated: {} == {}: {}", name, #{var_a}, #{var_b}, eq);
///     eq
/// };
/// ```
///
/// In the example a `var_eq` var of type `impl Var<bool>` is created. When either `var_a` or `var_b` are set
/// the value of `var_eq` is updated. Normal variables like `name` are moved in, like a closure capture.
///
/// # Capture Mode
///
/// The expression operates like a closure that captures by `move`. Both the interpolated variables and any
/// other `let` binding referenced from the scope are moved into the resulting variable.
///
/// # Interpolation
///
/// Variable interpolation is done by quoting the variable with `#{<var-expr>}`, the braces are required.
///
/// The `<var-expr>` is evaluated before *capturing* starts so if you interpolate `#{var_a.clone()}` `var_a`
/// will still be available after the `expr_var` call. Equal `<var-expr>` only evaluate once.
///
/// # Expansion
///
/// The expression is transformed into different types of vars depending on the number of interpolated variables.
///
/// ##### No Variables
///
/// An expression with no interpolation is simply evaluated into a var using [`IntoVar`].
///
/// ##### Single Variable
///
/// An expression with a single variable is transformed in a [`map`] operation, unless the expression
/// is only the variable without any extra operation.
///
/// ##### Multiple Variables
///
/// An expression with multiple variables is transformed into a [`merge_var!`] call.
///
/// [`Var::get`]: crate::Var::get
/// [`map`]: crate::Var::map
/// [`IntoVar`]: crate::IntoVar
/// [`merge_var!`]: crate::merge_var
#[macro_export]
macro_rules! expr_var {
    ($($expr:tt)+) => {
        $crate::types::__expr_var! { $crate, $($expr)+ }
    };
}

#[doc(hidden)]
pub use zng_var_proc_macros::expr_var as __expr_var;

use super::{IntoVar, Var, VarValue};

#[doc(hidden)]
pub fn expr_var_into<T: VarValue>(expr: impl IntoVar<T>) -> impl Var<T> {
    expr.into_var()
}

#[doc(hidden)]
pub fn expr_var_as<T: VarValue>(var: impl Var<T>) -> impl Var<T> {
    var
}

#[doc(hidden)]
pub fn expr_var_map<I: VarValue, O: VarValue>(input: impl Var<I>, map: impl FnMut(&I) -> O + Send + 'static) -> impl Var<O> {
    input.map(map)
}