Skip to main content

toasty_core/stmt/
entry.rs

1use crate::Result;
2
3use super::{Expr, Value};
4
5/// A borrowed reference to either an [`Expr`] or a [`Value`] within a
6/// composite structure.
7///
8/// `Entry` is returned by navigation methods (e.g., [`Value::entry`],
9/// [`Expr::entry`]) and provides a uniform way to inspect or evaluate the
10/// referenced data without cloning.
11///
12/// # Examples
13///
14/// ```
15/// use toasty_core::stmt::{Entry, Value};
16///
17/// let value = Value::from(42_i64);
18/// let entry = Entry::from(&value);
19/// assert!(entry.is_value());
20/// assert!(matches!(entry, Entry::Value(_)));
21/// ```
22#[derive(Debug)]
23pub enum Entry<'a> {
24    /// A reference to an expression.
25    Expr(&'a Expr),
26    /// A reference to a value.
27    Value(&'a Value),
28}
29
30impl Entry<'_> {
31    /// Evaluates the entry as a constant expression.
32    ///
33    /// For `Entry::Expr`, attempts to evaluate the expression without any input context.
34    /// This only succeeds if the expression is constant (contains no references or arguments).
35    /// For `Entry::Value`, returns a clone of the value directly.
36    ///
37    /// # Errors
38    ///
39    /// Returns an error if the entry contains an expression that cannot be evaluated
40    /// as a constant (e.g., references to columns or arguments).
41    ///
42    /// # Examples
43    ///
44    /// ```
45    /// # use toasty_core::stmt::{Entry, Value};
46    /// let value = Value::from("hello");
47    /// let entry = Entry::from(&value);
48    ///
49    /// let result = entry.eval_const().unwrap();
50    /// assert_eq!(result, Value::from("hello"));
51    /// ```
52    pub fn eval_const(&self) -> Result<Value> {
53        match self {
54            Entry::Expr(expr) => expr.eval_const(),
55            Entry::Value(value) => Ok((*value).clone()),
56        }
57    }
58
59    /// Returns `true` if the entry is a constant expression.
60    ///
61    /// An entry is considered constant if it does not reference any external data:
62    /// - `Entry::Value` is always constant
63    /// - `Entry::Expr` is constant if the expression itself is constant
64    ///   (see [`Expr::is_const`] for details)
65    ///
66    /// Constant entries can be evaluated without any input context.
67    ///
68    /// # Examples
69    ///
70    /// ```
71    /// # use toasty_core::stmt::{Entry, Value, Expr};
72    /// // Values are always constant
73    /// let value = Value::from(42);
74    /// let entry = Entry::from(&value);
75    /// assert!(entry.is_const());
76    ///
77    /// // Constant expressions
78    /// let expr = Expr::from(Value::from("hello"));
79    /// let entry = Entry::from(&expr);
80    /// assert!(entry.is_const());
81    /// ```
82    pub fn is_const(&self) -> bool {
83        match self {
84            Entry::Value(_) => true,
85            Entry::Expr(expr) => expr.is_const(),
86        }
87    }
88
89    /// Converts this entry to an owned [`Expr`] by cloning the contained
90    /// expression or wrapping the value.
91    pub fn to_expr(&self) -> Expr {
92        match *self {
93            Entry::Expr(expr) => expr.clone(),
94            Entry::Value(value) => value.clone().into(),
95        }
96    }
97
98    /// Returns `true` if this entry is `Expr::Default`.
99    pub fn is_expr_default(&self) -> bool {
100        matches!(self, Entry::Expr(Expr::Default))
101    }
102
103    /// Returns `true` if this entry holds a concrete value (either
104    /// `Entry::Value` or `Entry::Expr(Expr::Value(_))`).
105    pub fn is_value(&self) -> bool {
106        matches!(self, Entry::Value(_) | Entry::Expr(Expr::Value(_)))
107    }
108
109    /// Returns `true` if this entry holds a null value.
110    pub fn is_value_null(&self) -> bool {
111        matches!(
112            self,
113            Entry::Value(Value::Null) | Entry::Expr(Expr::Value(Value::Null))
114        )
115    }
116
117    /// Returns a reference to the contained value, or `None` if this entry
118    /// holds a non-value expression.
119    pub fn as_value(&self) -> Option<&Value> {
120        match *self {
121            Entry::Expr(Expr::Value(value)) | Entry::Value(value) => Some(value),
122            _ => None,
123        }
124    }
125
126    /// Returns a reference to the contained value, panicking if this
127    /// entry does not hold a value.
128    ///
129    /// # Panics
130    ///
131    /// Panics if the entry is not a value.
132    #[track_caller]
133    pub fn as_value_unwrap(&self) -> &Value {
134        self.as_value()
135            .unwrap_or_else(|| panic!("expected Entry with value; actual={self:#?}"))
136    }
137
138    /// Extracts an owned [`Value`] from this entry, evaluating constant
139    /// expressions if needed.
140    ///
141    /// # Panics
142    ///
143    /// Panics if the entry contains a non-constant expression.
144    pub fn to_value(&self) -> Value {
145        match *self {
146            Entry::Expr(Expr::Value(value)) | Entry::Value(value) => value.clone(),
147            Entry::Expr(expr) => expr.eval_const().unwrap_or_else(|err| {
148                panic!("not const expression; entry={self:#?}; error={err:#?}")
149            }),
150        }
151    }
152}
153
154impl<'a> From<&'a Expr> for Entry<'a> {
155    fn from(value: &'a Expr) -> Self {
156        Entry::Expr(value)
157    }
158}
159
160impl<'a> From<&'a Value> for Entry<'a> {
161    fn from(value: &'a Value) -> Self {
162        Entry::Value(value)
163    }
164}
165
166impl<'a> From<Entry<'a>> for Expr {
167    fn from(value: Entry<'a>) -> Self {
168        match value {
169            Entry::Expr(expr) => expr.clone(),
170            Entry::Value(value) => value.clone().into(),
171        }
172    }
173}