1use crate::{
2 schema::{
3 app::{Field, FieldId},
4 db::ColumnId,
5 },
6 stmt::{Expr, Value},
7};
8
9use indexmap::Equivalent;
10use std::{
11 fmt,
12 hash::{Hash, Hasher},
13 ops,
14};
15
16#[derive(Clone, PartialEq, Eq)]
17pub struct Projection {
18 steps: Steps,
19}
20
21pub trait Project {
22 fn project(self, projection: &Projection) -> Option<Expr>;
23}
24
25#[derive(Debug, Clone, PartialEq, Eq)]
26enum Steps {
27 Identity,
29
30 Single([usize; 1]),
32
33 Multi(Vec<usize>),
35}
36
37impl Hash for Projection {
42 fn hash<H: Hasher>(&self, state: &mut H) {
43 self.steps.hash(state);
44 }
45}
46
47impl Hash for Steps {
48 fn hash<H: Hasher>(&self, state: &mut H) {
49 match self {
50 Steps::Identity => {
51 0u8.hash(state);
53 }
54 Steps::Single([index]) => {
55 index.hash(state);
58 }
59 Steps::Multi(indices) => {
60 indices.as_slice().hash(state);
63 }
64 }
65 }
66}
67
68pub struct Iter<'a>(std::slice::Iter<'a, usize>);
69
70impl Projection {
71 pub const fn identity() -> Self {
72 Self {
73 steps: Steps::Identity,
74 }
75 }
76
77 pub const fn is_identity(&self) -> bool {
79 matches!(self.steps, Steps::Identity)
80 }
81
82 pub fn single(step: usize) -> Self {
83 Self {
84 steps: Steps::Single([step]),
85 }
86 }
87
88 pub const fn from_index(index: usize) -> Self {
90 Self {
91 steps: Steps::Single([index]),
92 }
93 }
94
95 pub fn as_slice(&self) -> &[usize] {
96 self.steps.as_slice()
97 }
98
99 pub fn push(&mut self, step: usize) {
100 match &mut self.steps {
101 Steps::Identity => {
102 self.steps = Steps::Single([step]);
103 }
104 Steps::Single([first]) => {
105 self.steps = Steps::Multi(vec![*first, step]);
106 }
107 Steps::Multi(steps) => {
108 steps.push(step);
109 }
110 }
111 }
112
113 pub fn resolves_to(&self, other: impl Into<Self>) -> bool {
114 let other = other.into();
115 *self == other
116 }
117}
118
119impl ops::Deref for Projection {
120 type Target = [usize];
121
122 fn deref(&self) -> &Self::Target {
123 self.steps.as_slice()
124 }
125}
126
127impl ops::DerefMut for Projection {
128 fn deref_mut(&mut self) -> &mut Self::Target {
129 match &mut self.steps {
130 Steps::Identity => &mut [],
131 Steps::Single(step) => &mut step[..],
132 Steps::Multi(steps) => &mut steps[..],
133 }
134 }
135}
136
137impl<'a> IntoIterator for &'a Projection {
138 type Item = usize;
139 type IntoIter = Iter<'a>;
140
141 fn into_iter(self) -> Self::IntoIter {
142 Iter(self[..].iter())
143 }
144}
145
146impl From<&Field> for Projection {
147 fn from(value: &Field) -> Self {
148 Self::single(value.id.index)
149 }
150}
151
152impl From<FieldId> for Projection {
153 fn from(value: FieldId) -> Self {
154 Self::single(value.index)
155 }
156}
157
158impl From<ColumnId> for Projection {
159 fn from(value: ColumnId) -> Self {
160 Self::single(value.index)
161 }
162}
163
164impl From<usize> for Projection {
165 fn from(value: usize) -> Self {
166 Self::single(value)
167 }
168}
169
170impl From<&[usize]> for Projection {
171 fn from(value: &[usize]) -> Self {
172 match value {
173 [] => Self::identity(),
174 [value] => Self::single(*value),
175 value => Self {
176 steps: Steps::Multi(value.into()),
177 },
178 }
179 }
180}
181
182impl<const N: usize> From<[usize; N]> for Projection {
183 fn from(value: [usize; N]) -> Self {
184 Self::from(&value[..])
185 }
186}
187
188impl fmt::Debug for Projection {
189 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
190 let mut f = f.debug_tuple("Projection");
191
192 if self.is_identity() {
193 f.field(&"identity");
194 } else {
195 for field in &self[..] {
196 f.field(&field);
197 }
198 }
199
200 f.finish()
201 }
202}
203
204impl Steps {
205 fn as_slice(&self) -> &[usize] {
206 match self {
207 Self::Identity => &[],
208 Self::Single(step) => &step[..],
209 Self::Multi(steps) => &steps[..],
210 }
211 }
212}
213
214impl Iterator for Iter<'_> {
215 type Item = usize;
216
217 fn next(&mut self) -> Option<usize> {
218 self.0.next().copied()
219 }
220}
221
222impl Project for Expr {
223 fn project(self, projection: &Projection) -> Option<Expr> {
224 Some(self.entry(projection)?.to_expr())
225 }
226}
227
228impl Project for &Expr {
229 fn project(self, projection: &Projection) -> Option<Expr> {
230 Some(self.entry(projection)?.to_expr())
231 }
232}
233
234impl Project for &&Expr {
235 fn project(self, projection: &Projection) -> Option<Expr> {
236 Some(self.entry(projection)?.to_expr())
237 }
238}
239
240impl Project for Value {
241 fn project(self, projection: &Projection) -> Option<Expr> {
242 Some(self.entry(projection).to_expr())
243 }
244}
245
246impl Project for &Value {
247 fn project(self, projection: &Projection) -> Option<Expr> {
248 Some(self.entry(projection).to_expr())
249 }
250}
251
252impl Project for &&Value {
253 fn project(self, projection: &Projection) -> Option<Expr> {
254 Some(self.entry(projection).to_expr())
255 }
256}
257
258impl Equivalent<Projection> for usize {
260 fn equivalent(&self, key: &Projection) -> bool {
261 matches!(key.as_slice(), [index] if *index == *self)
262 }
263}
264
265impl Equivalent<Projection> for &Projection {
267 fn equivalent(&self, key: &Projection) -> bool {
268 *self == key
269 }
270}
271
272impl Equivalent<Projection> for [usize] {
274 fn equivalent(&self, key: &Projection) -> bool {
275 self == key.as_slice()
276 }
277}
278
279impl PartialEq<usize> for Projection {
281 fn eq(&self, other: &usize) -> bool {
282 matches!(self.as_slice(), [index] if *index == *other)
283 }
284}
285
286impl PartialEq<Projection> for usize {
287 fn eq(&self, other: &Projection) -> bool {
288 other == self
289 }
290}
291
292impl PartialEq<[usize]> for Projection {
293 fn eq(&self, other: &[usize]) -> bool {
294 self.as_slice() == other
295 }
296}
297
298impl PartialEq<Projection> for [usize] {
299 fn eq(&self, other: &Projection) -> bool {
300 other == self
301 }
302}
303
304#[cfg(test)]
305mod tests {
306 use super::*;
307
308 #[test]
309 fn test_projection_eq_usize() {
310 let proj_single = Projection::from(5);
311 let proj_multi = Projection::from([1, 2]);
312
313 assert_eq!(proj_single, 5);
315 assert_eq!(5, proj_single);
316 assert_ne!(proj_single, 3);
317 assert_ne!(3, proj_single);
318
319 assert_ne!(proj_multi, 1);
321 assert_ne!(1, proj_multi);
322 }
323
324 #[test]
325 fn test_projection_eq_slice() {
326 let proj_single = Projection::from(5);
327 let proj_multi = Projection::from([1, 2, 3]);
328
329 assert_eq!(proj_single, [5][..]);
331 assert_eq!([5][..], proj_single);
332 assert_eq!(proj_multi, [1, 2, 3][..]);
333 assert_eq!([1, 2, 3][..], proj_multi);
334
335 assert_ne!(proj_single, [1, 2][..]);
337 assert_ne!([1, 2][..], proj_single);
338 }
339
340 #[test]
341 fn test_projection_hash_compatibility() {
342 use std::collections::hash_map::DefaultHasher;
343 use std::hash::{Hash, Hasher};
344
345 fn hash<T: Hash + ?Sized>(value: &T) -> u64 {
346 let mut hasher = DefaultHasher::new();
347 value.hash(&mut hasher);
348 hasher.finish()
349 }
350
351 let proj_single = Projection::from(42);
353 assert_eq!(hash(&proj_single), hash(&42_usize));
354
355 let proj_multi = Projection::from([1, 2, 3]);
357 let slice: &[usize] = &[1, 2, 3];
358 assert_eq!(hash(&proj_multi), hash(slice));
359
360 use indexmap::IndexMap;
362 let mut map = IndexMap::new();
363 map.insert(Projection::from(5), "value");
364
365 assert_eq!(map.get(&5_usize), Some(&"value"));
367
368 let slice_single: &[usize] = &[5];
370 assert_eq!(map.get(slice_single), Some(&"value"));
371
372 map.insert(Projection::from([1, 2]), "multi");
374
375 let slice_multi: &[usize] = &[1, 2];
377 assert_eq!(map.get(slice_multi), Some(&"multi"));
378 }
379}