toasty_core/stmt/
expr_record.rs

1use super::{Expr, Node, Visit, VisitMut};
2use crate::stmt::{self, Value};
3
4use std::{fmt, ops};
5
6/// A record of expressions.
7///
8/// Represents a fixed-size, heterogeneous collection of expressions accessed by
9/// position. Like Rust tuples, each field can have a different type.
10///
11/// # Examples
12///
13/// ```text
14/// record(a, b, c)  // a record with three fields
15/// record[0]        // access the first field
16/// ```
17#[derive(Clone, Default, PartialEq)]
18pub struct ExprRecord {
19    /// The field expressions in positional order.
20    pub fields: Vec<Expr>,
21}
22
23impl Expr {
24    /// Creates a record expression from an iterator of items convertible to [`Expr`].
25    pub fn record<T>(items: impl IntoIterator<Item = T>) -> Self
26    where
27        T: Into<Self>,
28    {
29        Self::Record(ExprRecord::from_iter(items))
30    }
31
32    /// Creates a record expression from a pre-built vector of field expressions.
33    pub fn record_from_vec(fields: Vec<Self>) -> Self {
34        Self::Record(ExprRecord::from_vec(fields))
35    }
36
37    /// Returns `true` if this expression is a record.
38    pub fn is_record(&self) -> bool {
39        matches!(self, Self::Record(_))
40    }
41
42    /// Returns a reference to the inner [`ExprRecord`] if this is a record,
43    /// or `None` otherwise.
44    pub fn as_record(&self) -> Option<&ExprRecord> {
45        match self {
46            Self::Record(expr_record) => Some(expr_record),
47            _ => None,
48        }
49    }
50
51    /// Returns a reference to the inner [`ExprRecord`].
52    ///
53    /// # Panics
54    ///
55    /// Panics if `self` is not `Expr::Record`.
56    #[track_caller]
57    pub fn as_record_unwrap(&self) -> &ExprRecord {
58        self.as_record()
59            .unwrap_or_else(|| panic!("expected Expr::Record; actual={self:#?}"))
60    }
61
62    /// Returns a mutable reference to the inner [`ExprRecord`] if this is a
63    /// record, or `None` otherwise.
64    pub fn as_record_mut(&mut self) -> Option<&mut ExprRecord> {
65        match self {
66            Self::Record(expr_record) => Some(expr_record),
67            _ => None,
68        }
69    }
70
71    /// Returns a mutable reference to the inner [`ExprRecord`].
72    ///
73    /// # Panics
74    ///
75    /// Panics if `self` is not `Expr::Record`.
76    #[track_caller]
77    pub fn as_record_mut_unwrap(&mut self) -> &mut ExprRecord {
78        match self {
79            Self::Record(expr_record) => expr_record,
80            _ => panic!("expected Expr::Record"),
81        }
82    }
83
84    /// Consumes the expression and returns the inner [`ExprRecord`].
85    ///
86    /// # Panics
87    ///
88    /// Panics if `self` is not `Expr::Record`.
89    pub fn into_record(self) -> ExprRecord {
90        match self {
91            Self::Record(expr_record) => expr_record,
92            _ => panic!(),
93        }
94    }
95
96    /// Returns the number of fields if this expression is a record (either
97    /// `Expr::Record` or `Expr::Value(Value::Record(...))`), or `None`
98    /// otherwise.
99    pub fn record_len(&self) -> Option<usize> {
100        match self {
101            Expr::Record(expr_record) => Some(expr_record.len()),
102            Expr::Value(Value::Record(value_record)) => Some(value_record.len()),
103            _ => None,
104        }
105    }
106
107    /// Consumes the expression and returns an iterator over the record's
108    /// fields if this is a record expression or value, or `None` otherwise.
109    pub fn into_record_items(self) -> Option<impl Iterator<Item = Expr>> {
110        let ret: Option<Box<dyn Iterator<Item = Expr>>> = match self {
111            Expr::Record(expr_record) => Some(Box::new(expr_record.into_iter())),
112            Expr::Value(Value::Record(value_record)) => {
113                Some(Box::new(value_record.into_iter().map(Expr::Value)))
114            }
115            _ => None,
116        };
117
118        ret
119    }
120}
121
122impl ExprRecord {
123    /// Creates a record from a pre-built vector of field expressions.
124    pub fn from_vec(fields: Vec<Expr>) -> Self {
125        Self { fields }
126    }
127
128    /// Appends an expression as a new field at the end of the record.
129    pub fn push(&mut self, expr: Expr) {
130        self.fields.push(expr)
131    }
132
133    /// Resizes the record to `new_len` fields, filling new slots with `value`.
134    pub fn resize(&mut self, new_len: usize, value: impl Into<stmt::Expr>) {
135        self.fields.resize(new_len, value.into());
136    }
137}
138
139impl<A> FromIterator<A> for ExprRecord
140where
141    A: Into<Expr>,
142{
143    fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self {
144        Self::from_vec(iter.into_iter().map(Into::into).collect())
145    }
146}
147
148impl ops::Deref for ExprRecord {
149    type Target = [Expr];
150
151    fn deref(&self) -> &Self::Target {
152        &self.fields[..]
153    }
154}
155
156impl ops::DerefMut for ExprRecord {
157    fn deref_mut(&mut self) -> &mut Self::Target {
158        &mut self.fields[..]
159    }
160}
161
162impl ops::Index<usize> for ExprRecord {
163    type Output = Expr;
164
165    fn index(&self, index: usize) -> &Self::Output {
166        &self.fields[index]
167    }
168}
169
170impl ops::IndexMut<usize> for ExprRecord {
171    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
172        &mut self.fields[index]
173    }
174}
175
176impl IntoIterator for ExprRecord {
177    type Item = Expr;
178    type IntoIter = std::vec::IntoIter<Expr>;
179
180    fn into_iter(self) -> Self::IntoIter {
181        self.fields.into_iter()
182    }
183}
184
185impl<'a> IntoIterator for &'a ExprRecord {
186    type Item = &'a Expr;
187    type IntoIter = std::slice::Iter<'a, Expr>;
188
189    fn into_iter(self) -> Self::IntoIter {
190        self.fields.iter()
191    }
192}
193
194impl<'a> IntoIterator for &'a mut ExprRecord {
195    type Item = &'a mut Expr;
196    type IntoIter = std::slice::IterMut<'a, Expr>;
197
198    fn into_iter(self) -> Self::IntoIter {
199        self.fields.iter_mut()
200    }
201}
202
203impl AsRef<[Expr]> for ExprRecord {
204    fn as_ref(&self) -> &[Expr] {
205        self.fields.as_ref()
206    }
207}
208
209impl From<ExprRecord> for Expr {
210    fn from(value: ExprRecord) -> Self {
211        Self::Record(value)
212    }
213}
214
215macro_rules! impl_for_tuple {
216    ( $len:literal; $(($T:ident, $idx:tt)),+ ) => {
217        impl<$($T),+> From<($($T,)+)> for ExprRecord
218        where
219            $($T: Into<Expr>,)+
220        {
221            fn from(src: ($($T,)+)) -> Self {
222                Self {
223                    fields: vec![$(src.$idx.into()),+],
224                }
225            }
226        }
227
228        impl<$($T),+> PartialEq<($($T,)+)> for Expr
229        where
230            $(Expr: PartialEq<$T>,)+
231            $(Value: PartialEq<$T>,)+
232        {
233            fn eq(&self, other: &($($T,)+)) -> bool {
234                match self {
235                    Expr::Record(r) => {
236                        r.fields.len() == $len
237                            $(&& r.fields[$idx].eq(&other.$idx))+
238                    }
239                    Expr::Value(Value::Record(r)) => {
240                        r.fields.len() == $len
241                            $(&& r.fields[$idx].eq(&other.$idx))+
242                    }
243                    _ => false,
244                }
245            }
246        }
247
248        impl<$($T),+> PartialEq<Expr> for ($($T,)+)
249        where
250            Expr: PartialEq<($($T,)+)>,
251        {
252            fn eq(&self, other: &Expr) -> bool {
253                other.eq(self)
254            }
255        }
256    };
257}
258
259impl_for_tuple!(1; (T0, 0));
260impl_for_tuple!(2; (T0, 0), (T1, 1));
261impl_for_tuple!(3; (T0, 0), (T1, 1), (T2, 2));
262impl_for_tuple!(4; (T0, 0), (T1, 1), (T2, 2), (T3, 3));
263impl_for_tuple!(5; (T0, 0), (T1, 1), (T2, 2), (T3, 3), (T4, 4));
264impl_for_tuple!(6; (T0, 0), (T1, 1), (T2, 2), (T3, 3), (T4, 4), (T5, 5));
265impl_for_tuple!(7; (T0, 0), (T1, 1), (T2, 2), (T3, 3), (T4, 4), (T5, 5), (T6, 6));
266impl_for_tuple!(8; (T0, 0), (T1, 1), (T2, 2), (T3, 3), (T4, 4), (T5, 5), (T6, 6), (T7, 7));
267impl_for_tuple!(9; (T0, 0), (T1, 1), (T2, 2), (T3, 3), (T4, 4), (T5, 5), (T6, 6), (T7, 7), (T8, 8));
268impl_for_tuple!(10; (T0, 0), (T1, 1), (T2, 2), (T3, 3), (T4, 4), (T5, 5), (T6, 6), (T7, 7), (T8, 8), (T9, 9));
269impl_for_tuple!(11; (T0, 0), (T1, 1), (T2, 2), (T3, 3), (T4, 4), (T5, 5), (T6, 6), (T7, 7), (T8, 8), (T9, 9), (T10, 10));
270impl_for_tuple!(12; (T0, 0), (T1, 1), (T2, 2), (T3, 3), (T4, 4), (T5, 5), (T6, 6), (T7, 7), (T8, 8), (T9, 9), (T10, 10), (T11, 11));
271
272impl Node for ExprRecord {
273    fn visit<V: Visit>(&self, mut visit: V) {
274        visit.visit_expr_record(self);
275    }
276
277    fn visit_mut<V: VisitMut>(&mut self, mut visit: V) {
278        visit.visit_expr_record_mut(self);
279    }
280}
281
282impl fmt::Debug for ExprRecord {
283    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
284        self.fields.as_slice().fmt(f)
285    }
286}