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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
use crate::Result;
use super::{Expr, Input, Value};
/// A borrowed reference to either an [`Expr`] or a [`Value`] within a
/// composite structure.
///
/// `Entry` is returned by navigation methods (e.g., [`Value::entry`],
/// [`Expr::entry`]) and provides a uniform way to inspect or evaluate the
/// referenced data without cloning.
///
/// # Examples
///
/// ```
/// use toasty_core::stmt::{Entry, Value};
///
/// let value = Value::from(42_i64);
/// let entry = Entry::from(&value);
/// assert!(entry.is_value());
/// assert!(!entry.is_expr());
/// ```
#[derive(Debug)]
pub enum Entry<'a> {
/// A reference to an expression.
Expr(&'a Expr),
/// A reference to a value.
Value(&'a Value),
}
impl Entry<'_> {
/// Evaluates the entry to a value using the provided input.
///
/// For `Entry::Expr`, evaluates the expression with the given input context.
/// For `Entry::Value`, returns a clone of the value directly.
///
/// # Examples
///
/// ```
/// # use toasty_core::stmt::{Entry, Value, ConstInput};
/// let value = Value::from(42);
/// let entry = Entry::from(&value);
///
/// let result = entry.eval(ConstInput::new()).unwrap();
/// assert_eq!(result, Value::from(42));
/// ```
pub fn eval(&self, input: impl Input) -> Result<Value> {
match self {
Entry::Expr(expr) => expr.eval(input),
Entry::Value(value) => Ok((*value).clone()),
}
}
/// Evaluates the entry as a constant expression.
///
/// For `Entry::Expr`, attempts to evaluate the expression without any input context.
/// This only succeeds if the expression is constant (contains no references or arguments).
/// For `Entry::Value`, returns a clone of the value directly.
///
/// # Errors
///
/// Returns an error if the entry contains an expression that cannot be evaluated
/// as a constant (e.g., references to columns or arguments).
///
/// # Examples
///
/// ```
/// # use toasty_core::stmt::{Entry, Value};
/// let value = Value::from("hello");
/// let entry = Entry::from(&value);
///
/// let result = entry.eval_const().unwrap();
/// assert_eq!(result, Value::from("hello"));
/// ```
pub fn eval_const(&self) -> Result<Value> {
match self {
Entry::Expr(expr) => expr.eval_const(),
Entry::Value(value) => Ok((*value).clone()),
}
}
/// Returns `true` if the entry is a constant expression.
///
/// An entry is considered constant if it does not reference any external data:
/// - `Entry::Value` is always constant
/// - `Entry::Expr` is constant if the expression itself is constant
/// (see [`Expr::is_const`] for details)
///
/// Constant entries can be evaluated without any input context.
///
/// # Examples
///
/// ```
/// # use toasty_core::stmt::{Entry, Value, Expr};
/// // Values are always constant
/// let value = Value::from(42);
/// let entry = Entry::from(&value);
/// assert!(entry.is_const());
///
/// // Constant expressions
/// let expr = Expr::from(Value::from("hello"));
/// let entry = Entry::from(&expr);
/// assert!(entry.is_const());
/// ```
pub fn is_const(&self) -> bool {
match self {
Entry::Value(_) => true,
Entry::Expr(expr) => expr.is_const(),
}
}
/// Returns `true` if this entry contains an expression.
pub fn is_expr(&self) -> bool {
matches!(self, Entry::Expr(_))
}
/// Converts this entry to an owned [`Expr`] by cloning the contained
/// expression or wrapping the value.
pub fn to_expr(&self) -> Expr {
match *self {
Entry::Expr(expr) => expr.clone(),
Entry::Value(value) => value.clone().into(),
}
}
/// Returns `true` if this entry is `Expr::Default`.
pub fn is_expr_default(&self) -> bool {
matches!(self, Entry::Expr(Expr::Default))
}
/// Returns `true` if this entry holds a concrete value (either
/// `Entry::Value` or `Entry::Expr(Expr::Value(_))`).
pub fn is_value(&self) -> bool {
matches!(self, Entry::Value(_) | Entry::Expr(Expr::Value(_)))
}
/// Returns `true` if this entry holds a null value.
pub fn is_value_null(&self) -> bool {
matches!(
self,
Entry::Value(Value::Null) | Entry::Expr(Expr::Value(Value::Null))
)
}
/// Returns a reference to the contained value, or `None` if this entry
/// holds a non-value expression.
pub fn as_value(&self) -> Option<&Value> {
match *self {
Entry::Expr(Expr::Value(value)) | Entry::Value(value) => Some(value),
_ => None,
}
}
/// Returns a reference to the contained value, panicking if this
/// entry does not hold a value.
///
/// # Panics
///
/// Panics if the entry is not a value.
#[track_caller]
pub fn as_value_unwrap(&self) -> &Value {
self.as_value()
.unwrap_or_else(|| panic!("expected Entry with value; actual={self:#?}"))
}
/// Extracts an owned [`Value`] from this entry, evaluating constant
/// expressions if needed.
///
/// # Panics
///
/// Panics if the entry contains a non-constant expression.
pub fn to_value(&self) -> Value {
match *self {
Entry::Expr(Expr::Value(value)) | Entry::Value(value) => value.clone(),
Entry::Expr(expr) => expr.eval_const().unwrap_or_else(|err| {
panic!("not const expression; entry={self:#?}; error={err:#?}")
}),
}
}
}
impl<'a> From<&'a Expr> for Entry<'a> {
fn from(value: &'a Expr) -> Self {
Entry::Expr(value)
}
}
impl<'a> From<&'a Value> for Entry<'a> {
fn from(value: &'a Value) -> Self {
Entry::Value(value)
}
}
impl<'a> From<Entry<'a>> for Expr {
fn from(value: Entry<'a>) -> Self {
match value {
Entry::Expr(expr) => expr.clone(),
Entry::Value(value) => value.clone().into(),
}
}
}