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    pub fn record<T>(items: impl IntoIterator<Item = T>) -> Self
25    where
26        T: Into<Self>,
27    {
28        Self::Record(ExprRecord::from_iter(items))
29    }
30
31    pub fn record_from_vec(fields: Vec<Self>) -> Self {
32        Self::Record(ExprRecord::from_vec(fields))
33    }
34
35    pub fn is_record(&self) -> bool {
36        matches!(self, Self::Record(_))
37    }
38
39    pub fn as_record(&self) -> Option<&ExprRecord> {
40        match self {
41            Self::Record(expr_record) => Some(expr_record),
42            _ => None,
43        }
44    }
45
46    pub fn as_record_unwrap(&self) -> &ExprRecord {
47        match self {
48            Self::Record(expr_record) => expr_record,
49            _ => panic!("self={self:#?}"),
50        }
51    }
52
53    pub fn as_record_mut(&mut self) -> &mut ExprRecord {
54        match self {
55            Self::Record(expr_record) => expr_record,
56            _ => panic!(),
57        }
58    }
59
60    pub fn into_record(self) -> ExprRecord {
61        match self {
62            Self::Record(expr_record) => expr_record,
63            _ => panic!(),
64        }
65    }
66
67    pub fn record_len(&self) -> Option<usize> {
68        match self {
69            Expr::Record(expr_record) => Some(expr_record.len()),
70            Expr::Value(Value::Record(value_record)) => Some(value_record.len()),
71            _ => None,
72        }
73    }
74
75    pub fn into_record_items(self) -> Option<impl Iterator<Item = Expr>> {
76        let ret: Option<Box<dyn Iterator<Item = Expr>>> = match self {
77            Expr::Record(expr_record) => Some(Box::new(expr_record.into_iter())),
78            Expr::Value(Value::Record(value_record)) => {
79                Some(Box::new(value_record.into_iter().map(Expr::Value)))
80            }
81            _ => None,
82        };
83
84        ret
85    }
86}
87
88impl ExprRecord {
89    pub fn from_vec(fields: Vec<Expr>) -> Self {
90        Self { fields }
91    }
92
93    pub fn push(&mut self, expr: Expr) {
94        self.fields.push(expr)
95    }
96
97    pub fn resize(&mut self, new_len: usize, value: impl Into<stmt::Expr>) {
98        self.fields.resize(new_len, value.into());
99    }
100}
101
102impl<A> FromIterator<A> for ExprRecord
103where
104    A: Into<Expr>,
105{
106    fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self {
107        Self::from_vec(iter.into_iter().map(Into::into).collect())
108    }
109}
110
111impl ops::Deref for ExprRecord {
112    type Target = [Expr];
113
114    fn deref(&self) -> &Self::Target {
115        &self.fields[..]
116    }
117}
118
119impl ops::DerefMut for ExprRecord {
120    fn deref_mut(&mut self) -> &mut Self::Target {
121        &mut self.fields[..]
122    }
123}
124
125impl ops::Index<usize> for ExprRecord {
126    type Output = Expr;
127
128    fn index(&self, index: usize) -> &Self::Output {
129        &self.fields[index]
130    }
131}
132
133impl ops::IndexMut<usize> for ExprRecord {
134    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
135        &mut self.fields[index]
136    }
137}
138
139impl IntoIterator for ExprRecord {
140    type Item = Expr;
141    type IntoIter = std::vec::IntoIter<Expr>;
142
143    fn into_iter(self) -> Self::IntoIter {
144        self.fields.into_iter()
145    }
146}
147
148impl<'a> IntoIterator for &'a ExprRecord {
149    type Item = &'a Expr;
150    type IntoIter = std::slice::Iter<'a, Expr>;
151
152    fn into_iter(self) -> Self::IntoIter {
153        self.fields.iter()
154    }
155}
156
157impl<'a> IntoIterator for &'a mut ExprRecord {
158    type Item = &'a mut Expr;
159    type IntoIter = std::slice::IterMut<'a, Expr>;
160
161    fn into_iter(self) -> Self::IntoIter {
162        self.fields.iter_mut()
163    }
164}
165
166impl AsRef<[Expr]> for ExprRecord {
167    fn as_ref(&self) -> &[Expr] {
168        self.fields.as_ref()
169    }
170}
171
172impl From<ExprRecord> for Expr {
173    fn from(value: ExprRecord) -> Self {
174        Self::Record(value)
175    }
176}
177
178macro_rules! impl_for_tuple {
179    ( $len:literal; $(($T:ident, $idx:tt)),+ ) => {
180        impl<$($T),+> From<($($T,)+)> for ExprRecord
181        where
182            $($T: Into<Expr>,)+
183        {
184            fn from(src: ($($T,)+)) -> Self {
185                Self {
186                    fields: vec![$(src.$idx.into()),+],
187                }
188            }
189        }
190
191        impl<$($T),+> PartialEq<($($T,)+)> for Expr
192        where
193            $(Expr: PartialEq<$T>,)+
194            $(Value: PartialEq<$T>,)+
195        {
196            fn eq(&self, other: &($($T,)+)) -> bool {
197                match self {
198                    Expr::Record(r) => {
199                        r.fields.len() == $len
200                            $(&& r.fields[$idx].eq(&other.$idx))+
201                    }
202                    Expr::Value(Value::Record(r)) => {
203                        r.fields.len() == $len
204                            $(&& r.fields[$idx].eq(&other.$idx))+
205                    }
206                    _ => false,
207                }
208            }
209        }
210
211        impl<$($T),+> PartialEq<Expr> for ($($T,)+)
212        where
213            Expr: PartialEq<($($T,)+)>,
214        {
215            fn eq(&self, other: &Expr) -> bool {
216                other.eq(self)
217            }
218        }
219    };
220}
221
222impl_for_tuple!(1; (T0, 0));
223impl_for_tuple!(2; (T0, 0), (T1, 1));
224impl_for_tuple!(3; (T0, 0), (T1, 1), (T2, 2));
225impl_for_tuple!(4; (T0, 0), (T1, 1), (T2, 2), (T3, 3));
226impl_for_tuple!(5; (T0, 0), (T1, 1), (T2, 2), (T3, 3), (T4, 4));
227impl_for_tuple!(6; (T0, 0), (T1, 1), (T2, 2), (T3, 3), (T4, 4), (T5, 5));
228impl_for_tuple!(7; (T0, 0), (T1, 1), (T2, 2), (T3, 3), (T4, 4), (T5, 5), (T6, 6));
229impl_for_tuple!(8; (T0, 0), (T1, 1), (T2, 2), (T3, 3), (T4, 4), (T5, 5), (T6, 6), (T7, 7));
230impl_for_tuple!(9; (T0, 0), (T1, 1), (T2, 2), (T3, 3), (T4, 4), (T5, 5), (T6, 6), (T7, 7), (T8, 8));
231impl_for_tuple!(10; (T0, 0), (T1, 1), (T2, 2), (T3, 3), (T4, 4), (T5, 5), (T6, 6), (T7, 7), (T8, 8), (T9, 9));
232impl_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));
233impl_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));
234
235impl Node for ExprRecord {
236    fn visit<V: Visit>(&self, mut visit: V) {
237        visit.visit_expr_record(self);
238    }
239
240    fn visit_mut<V: VisitMut>(&mut self, mut visit: V) {
241        visit.visit_expr_record_mut(self);
242    }
243}
244
245impl fmt::Debug for ExprRecord {
246    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
247        self.fields.as_slice().fmt(f)
248    }
249}