toasty_core/stmt/
entry.rs

1use crate::Result;
2
3use super::{Expr, Input, 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!(!entry.is_expr());
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 to a value using the provided input.
32    ///
33    /// For `Entry::Expr`, evaluates the expression with the given input context.
34    /// For `Entry::Value`, returns a clone of the value directly.
35    ///
36    /// # Examples
37    ///
38    /// ```
39    /// # use toasty_core::stmt::{Entry, Value, ConstInput};
40    /// let value = Value::from(42);
41    /// let entry = Entry::from(&value);
42    ///
43    /// let result = entry.eval(ConstInput::new()).unwrap();
44    /// assert_eq!(result, Value::from(42));
45    /// ```
46    pub fn eval(&self, input: impl Input) -> Result<Value> {
47        match self {
48            Entry::Expr(expr) => expr.eval(input),
49            Entry::Value(value) => Ok((*value).clone()),
50        }
51    }
52
53    /// Evaluates the entry as a constant expression.
54    ///
55    /// For `Entry::Expr`, attempts to evaluate the expression without any input context.
56    /// This only succeeds if the expression is constant (contains no references or arguments).
57    /// For `Entry::Value`, returns a clone of the value directly.
58    ///
59    /// # Errors
60    ///
61    /// Returns an error if the entry contains an expression that cannot be evaluated
62    /// as a constant (e.g., references to columns or arguments).
63    ///
64    /// # Examples
65    ///
66    /// ```
67    /// # use toasty_core::stmt::{Entry, Value};
68    /// let value = Value::from("hello");
69    /// let entry = Entry::from(&value);
70    ///
71    /// let result = entry.eval_const().unwrap();
72    /// assert_eq!(result, Value::from("hello"));
73    /// ```
74    pub fn eval_const(&self) -> Result<Value> {
75        match self {
76            Entry::Expr(expr) => expr.eval_const(),
77            Entry::Value(value) => Ok((*value).clone()),
78        }
79    }
80
81    /// Returns `true` if the entry is a constant expression.
82    ///
83    /// An entry is considered constant if it does not reference any external data:
84    /// - `Entry::Value` is always constant
85    /// - `Entry::Expr` is constant if the expression itself is constant
86    ///   (see [`Expr::is_const`] for details)
87    ///
88    /// Constant entries can be evaluated without any input context.
89    ///
90    /// # Examples
91    ///
92    /// ```
93    /// # use toasty_core::stmt::{Entry, Value, Expr};
94    /// // Values are always constant
95    /// let value = Value::from(42);
96    /// let entry = Entry::from(&value);
97    /// assert!(entry.is_const());
98    ///
99    /// // Constant expressions
100    /// let expr = Expr::from(Value::from("hello"));
101    /// let entry = Entry::from(&expr);
102    /// assert!(entry.is_const());
103    /// ```
104    pub fn is_const(&self) -> bool {
105        match self {
106            Entry::Value(_) => true,
107            Entry::Expr(expr) => expr.is_const(),
108        }
109    }
110
111    /// Returns `true` if this entry contains an expression.
112    pub fn is_expr(&self) -> bool {
113        matches!(self, Entry::Expr(_))
114    }
115
116    /// Converts this entry to an owned [`Expr`] by cloning the contained
117    /// expression or wrapping the value.
118    pub fn to_expr(&self) -> Expr {
119        match *self {
120            Entry::Expr(expr) => expr.clone(),
121            Entry::Value(value) => value.clone().into(),
122        }
123    }
124
125    /// Returns `true` if this entry is `Expr::Default`.
126    pub fn is_expr_default(&self) -> bool {
127        matches!(self, Entry::Expr(Expr::Default))
128    }
129
130    /// Returns `true` if this entry holds a concrete value (either
131    /// `Entry::Value` or `Entry::Expr(Expr::Value(_))`).
132    pub fn is_value(&self) -> bool {
133        matches!(self, Entry::Value(_) | Entry::Expr(Expr::Value(_)))
134    }
135
136    /// Returns `true` if this entry holds a null value.
137    pub fn is_value_null(&self) -> bool {
138        matches!(
139            self,
140            Entry::Value(Value::Null) | Entry::Expr(Expr::Value(Value::Null))
141        )
142    }
143
144    /// Returns a reference to the contained value, or `None` if this entry
145    /// holds a non-value expression.
146    pub fn as_value(&self) -> Option<&Value> {
147        match *self {
148            Entry::Expr(Expr::Value(value)) | Entry::Value(value) => Some(value),
149            _ => None,
150        }
151    }
152
153    /// Returns a reference to the contained value, panicking if this
154    /// entry does not hold a value.
155    ///
156    /// # Panics
157    ///
158    /// Panics if the entry is not a value.
159    #[track_caller]
160    pub fn as_value_unwrap(&self) -> &Value {
161        self.as_value()
162            .unwrap_or_else(|| panic!("expected Entry with value; actual={self:#?}"))
163    }
164
165    /// Extracts an owned [`Value`] from this entry, evaluating constant
166    /// expressions if needed.
167    ///
168    /// # Panics
169    ///
170    /// Panics if the entry contains a non-constant expression.
171    pub fn to_value(&self) -> Value {
172        match *self {
173            Entry::Expr(Expr::Value(value)) | Entry::Value(value) => value.clone(),
174            Entry::Expr(expr) => expr.eval_const().unwrap_or_else(|err| {
175                panic!("not const expression; entry={self:#?}; error={err:#?}")
176            }),
177        }
178    }
179}
180
181impl<'a> From<&'a Expr> for Entry<'a> {
182    fn from(value: &'a Expr) -> Self {
183        Entry::Expr(value)
184    }
185}
186
187impl<'a> From<&'a Value> for Entry<'a> {
188    fn from(value: &'a Value) -> Self {
189        Entry::Value(value)
190    }
191}
192
193impl<'a> From<Entry<'a>> for Expr {
194    fn from(value: Entry<'a>) -> Self {
195        match value {
196            Entry::Expr(expr) => expr.clone(),
197            Entry::Value(value) => value.clone().into(),
198        }
199    }
200}