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
use super::{LVar, Val};
use std::fmt::Debug;
use std::rc::Rc;

/// Helper for converting into [`Val<T>`](crate::value::Val).
///
/// In order to be able to mix [resolved values](crate::value::Val) and [logical
/// variables](crate::value::LVar) in the same [state](crate::state), they need
/// to be contained in the shared [`Val`](crate::value::Val) enum. This trait
/// provides a standard way to convert various types of values into this
/// container enum without manual wrapping.
///
/// # TLDR: If you see a function that takes `IntoVal<T>`
/// ```
/// # use canrun::{Val, IntoVal};
/// # use std::fmt::Debug;
/// fn foo<T: Debug, TV: IntoVal<T>>(bar: TV) -> Val<T> {
///      bar.into_val()
/// }
/// ```
/// That means it can take any of these types and will take care of converting
/// them into a `Val<T>` for you:
/// ```
/// # use canrun::{Val, var, IntoVal};
/// # use std::fmt::Debug;
/// # fn foo<T: Debug, TV: IntoVal<T>>(bar: TV) -> Val<T> {
/// #     bar.into_val()
/// # }
/// let a: Val<i32> = foo(1); // a plain value of type `T`
/// let b: Val<i32> = foo(var()); // an `LVar<T>`
/// let c: Val<i32> = foo(a); // a `Val<T>`
/// ```
pub trait IntoVal<T: Debug> {
    /// Convert various `T` related values into a [`Val<T>`](crate::value::Val).
    ///
    /// # Example:
    /// ```
    /// use canrun::{var, IntoVal, Val, LVar};
    ///
    /// let x: LVar<i32> = var();
    /// let x_val: Val<i32> = x.into_val();
    ///
    /// let y: i32 = 1;
    /// let y_val: Val<i32> = y.into_val();
    /// ```
    fn into_val(self) -> Val<T>;
}

impl<T: Debug> IntoVal<T> for T {
    fn into_val(self) -> Val<T> {
        Val::Resolved(Rc::new(self))
    }
}

impl<T: Debug> IntoVal<T> for Val<T> {
    fn into_val(self) -> Val<T> {
        self
    }
}

impl<T: Debug> IntoVal<T> for &Val<T> {
    fn into_val(self) -> Val<T> {
        self.clone()
    }
}

impl<T: Clone + Debug> IntoVal<T> for &T {
    fn into_val(self) -> Val<T> {
        Val::Resolved(Rc::new(self.clone()))
    }
}

impl<T: Debug> IntoVal<T> for LVar<T> {
    fn into_val(self) -> Val<T> {
        Val::Var(self)
    }
}
impl<T: Debug> IntoVal<T> for &LVar<T> {
    fn into_val(self) -> Val<T> {
        Val::Var(*self)
    }
}