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
use super::Expr;
/// A map/transform operation over a collection.
///
/// [`ExprMap`] applies a transformation expression to each item in a base
/// collection. Within the `map` expression, `Expr::arg(n)` refers to elements
/// of each item:
///
/// - For simple values, `arg(0)` is the item itself.
/// - For records, `arg(0)` is field 0, `arg(1)` is field 1, etc.
///
/// # Examples
///
/// ## Simple values
///
/// ```text
/// map([1, 2, 3], x => x == field)
/// ```
///
/// Here `base` is `[1, 2, 3]` and `map` is `arg(0) == field`.
///
/// ## Records
///
/// ```text
/// map([{1, 2}, {3, 4}], r => r.0 + r.1)
/// ```
///
/// Here each item is a record with two fields. `arg(0)` refers to the first
/// field and `arg(1)` refers to the second field of each record.
#[derive(Debug, Clone, PartialEq)]
pub struct ExprMap {
/// The collection expression to iterate over.
pub base: Box<Expr>,
/// The transformation to apply to each item. Use `Expr::arg(n)` to
/// reference elements of the current item being mapped.
pub map: Box<Expr>,
}
impl Expr {
/// Creates a map expression that applies `map` to each element of `base`.
pub fn map(base: impl Into<Self>, map: impl Into<Self>) -> Self {
ExprMap {
base: Box::new(base.into()),
map: Box::new(map.into()),
}
.into()
}
/// Returns a reference to the inner [`ExprMap`] if this is a map
/// expression, or `None` otherwise.
pub fn as_map(&self) -> Option<&ExprMap> {
match self {
Self::Map(expr) => Some(expr),
_ => None,
}
}
/// Returns a reference to the inner [`ExprMap`].
///
/// # Panics
///
/// Panics if `self` is not `Expr::Map`.
#[track_caller]
pub fn as_map_unwrap(&self) -> &ExprMap {
self.as_map()
.unwrap_or_else(|| panic!("expected Expr::Map; actual={self:#?}"))
}
}
impl From<ExprMap> for Expr {
fn from(value: ExprMap) -> Self {
Self::Map(value)
}
}