1use crate::{
2 schema::{
3 app::{Field, FieldId},
4 db::ColumnId,
5 },
6 stmt::{Expr, Value},
7};
8
9use indexmap::Equivalent;
10use std::{
11 borrow::Borrow,
12 cmp::Ordering,
13 fmt,
14 hash::{Hash, Hasher},
15 ops,
16};
17
18#[derive(Clone, PartialEq, Eq)]
42pub struct Projection {
43 steps: Steps,
44}
45
46impl PartialOrd for Projection {
47 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
48 Some(self.cmp(other))
49 }
50}
51
52impl Ord for Projection {
53 fn cmp(&self, other: &Self) -> Ordering {
54 self.as_slice().cmp(other.as_slice())
55 }
56}
57
58pub trait Project {
63 fn project(self, projection: &Projection) -> Option<Expr>;
65}
66
67#[derive(Debug, Clone, PartialEq, Eq)]
68enum Steps {
69 Identity,
71
72 Single([usize; 1]),
74
75 Multi(Vec<usize>),
77}
78
79impl Hash for Projection {
84 fn hash<H: Hasher>(&self, state: &mut H) {
85 self.steps.hash(state);
86 }
87}
88
89impl Hash for Steps {
90 fn hash<H: Hasher>(&self, state: &mut H) {
91 match self {
92 Steps::Identity => {
93 0u8.hash(state);
95 }
96 Steps::Single([index]) => {
97 index.hash(state);
100 }
101 Steps::Multi(indices) => {
102 indices.as_slice().hash(state);
105 }
106 }
107 }
108}
109
110pub struct Iter<'a>(std::slice::Iter<'a, usize>);
112
113impl Projection {
114 pub const fn identity() -> Self {
116 Self {
117 steps: Steps::Identity,
118 }
119 }
120
121 pub const fn is_identity(&self) -> bool {
123 matches!(self.steps, Steps::Identity)
124 }
125
126 pub fn single(step: usize) -> Self {
128 Self {
129 steps: Steps::Single([step]),
130 }
131 }
132
133 pub const fn from_index(index: usize) -> Self {
135 Self {
136 steps: Steps::Single([index]),
137 }
138 }
139
140 pub fn as_slice(&self) -> &[usize] {
142 self.steps.as_slice()
143 }
144
145 pub fn push(&mut self, step: usize) {
147 match &mut self.steps {
148 Steps::Identity => {
149 self.steps = Steps::Single([step]);
150 }
151 Steps::Single([first]) => {
152 self.steps = Steps::Multi(vec![*first, step]);
153 }
154 Steps::Multi(steps) => {
155 steps.push(step);
156 }
157 }
158 }
159
160 pub fn resolves_to(&self, other: impl Into<Self>) -> bool {
162 let other = other.into();
163 *self == other
164 }
165}
166
167impl AsRef<[usize]> for Projection {
168 fn as_ref(&self) -> &[usize] {
169 self.as_slice()
170 }
171}
172
173impl ops::Deref for Projection {
174 type Target = [usize];
175
176 fn deref(&self) -> &Self::Target {
177 self.steps.as_slice()
178 }
179}
180
181impl ops::DerefMut for Projection {
182 fn deref_mut(&mut self) -> &mut Self::Target {
183 match &mut self.steps {
184 Steps::Identity => &mut [],
185 Steps::Single(step) => &mut step[..],
186 Steps::Multi(steps) => &mut steps[..],
187 }
188 }
189}
190
191impl<'a> IntoIterator for &'a Projection {
192 type Item = usize;
193 type IntoIter = Iter<'a>;
194
195 fn into_iter(self) -> Self::IntoIter {
196 Iter(self[..].iter())
197 }
198}
199
200impl From<&Field> for Projection {
201 fn from(value: &Field) -> Self {
202 Self::single(value.id.index)
203 }
204}
205
206impl From<FieldId> for Projection {
207 fn from(value: FieldId) -> Self {
208 Self::single(value.index)
209 }
210}
211
212impl From<ColumnId> for Projection {
213 fn from(value: ColumnId) -> Self {
214 Self::single(value.index)
215 }
216}
217
218impl From<usize> for Projection {
219 fn from(value: usize) -> Self {
220 Self::single(value)
221 }
222}
223
224impl From<&[usize]> for Projection {
225 fn from(value: &[usize]) -> Self {
226 match value {
227 [] => Self::identity(),
228 [value] => Self::single(*value),
229 value => Self {
230 steps: Steps::Multi(value.into()),
231 },
232 }
233 }
234}
235
236impl<const N: usize> From<[usize; N]> for Projection {
237 fn from(value: [usize; N]) -> Self {
238 Self::from(&value[..])
239 }
240}
241
242impl fmt::Debug for Projection {
243 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244 let mut f = f.debug_tuple("Projection");
245
246 if self.is_identity() {
247 f.field(&"identity");
248 } else {
249 for field in &self[..] {
250 f.field(&field);
251 }
252 }
253
254 f.finish()
255 }
256}
257
258impl Steps {
259 fn as_slice(&self) -> &[usize] {
260 match self {
261 Self::Identity => &[],
262 Self::Single(step) => &step[..],
263 Self::Multi(steps) => &steps[..],
264 }
265 }
266}
267
268impl Iterator for Iter<'_> {
269 type Item = usize;
270
271 fn next(&mut self) -> Option<usize> {
272 self.0.next().copied()
273 }
274}
275
276impl Project for Expr {
277 fn project(self, projection: &Projection) -> Option<Expr> {
278 Some(self.entry(projection)?.to_expr())
279 }
280}
281
282impl Project for &Expr {
283 fn project(self, projection: &Projection) -> Option<Expr> {
284 Some(self.entry(projection)?.to_expr())
285 }
286}
287
288impl Project for &&Expr {
289 fn project(self, projection: &Projection) -> Option<Expr> {
290 Some(self.entry(projection)?.to_expr())
291 }
292}
293
294impl Project for Value {
295 fn project(self, projection: &Projection) -> Option<Expr> {
296 Some(self.entry(projection).to_expr())
297 }
298}
299
300impl Project for &Value {
301 fn project(self, projection: &Projection) -> Option<Expr> {
302 Some(self.entry(projection).to_expr())
303 }
304}
305
306impl Project for &&Value {
307 fn project(self, projection: &Projection) -> Option<Expr> {
308 Some(self.entry(projection).to_expr())
309 }
310}
311
312impl Borrow<[usize]> for Projection {
314 fn borrow(&self) -> &[usize] {
315 self.as_slice()
316 }
317}
318
319impl Equivalent<Projection> for usize {
321 fn equivalent(&self, key: &Projection) -> bool {
322 matches!(key.as_slice(), [index] if *index == *self)
323 }
324}
325
326impl Equivalent<Projection> for &Projection {
328 fn equivalent(&self, key: &Projection) -> bool {
329 *self == key
330 }
331}
332
333impl PartialEq<usize> for Projection {
338 fn eq(&self, other: &usize) -> bool {
339 matches!(self.as_slice(), [index] if *index == *other)
340 }
341}
342
343impl PartialEq<Projection> for usize {
344 fn eq(&self, other: &Projection) -> bool {
345 other == self
346 }
347}
348
349impl PartialEq<[usize]> for Projection {
350 fn eq(&self, other: &[usize]) -> bool {
351 self.as_slice() == other
352 }
353}
354
355impl PartialEq<Projection> for [usize] {
356 fn eq(&self, other: &Projection) -> bool {
357 other == self
358 }
359}
360
361#[cfg(test)]
362mod tests {
363 use super::*;
364
365 #[test]
366 fn test_projection_eq_usize() {
367 let proj_single = Projection::from(5);
368 let proj_multi = Projection::from([1, 2]);
369
370 assert_eq!(proj_single, 5);
372 assert_eq!(5, proj_single);
373 assert_ne!(proj_single, 3);
374 assert_ne!(3, proj_single);
375
376 assert_ne!(proj_multi, 1);
378 assert_ne!(1, proj_multi);
379 }
380
381 #[test]
382 fn test_projection_eq_slice() {
383 let proj_single = Projection::from(5);
384 let proj_multi = Projection::from([1, 2, 3]);
385
386 assert_eq!(proj_single, [5][..]);
388 assert_eq!([5][..], proj_single);
389 assert_eq!(proj_multi, [1, 2, 3][..]);
390 assert_eq!([1, 2, 3][..], proj_multi);
391
392 assert_ne!(proj_single, [1, 2][..]);
394 assert_ne!([1, 2][..], proj_single);
395 }
396
397 #[test]
398 fn test_projection_hash_compatibility() {
399 use std::collections::hash_map::DefaultHasher;
400 use std::hash::{Hash, Hasher};
401
402 fn hash<T: Hash + ?Sized>(value: &T) -> u64 {
403 let mut hasher = DefaultHasher::new();
404 value.hash(&mut hasher);
405 hasher.finish()
406 }
407
408 let proj_single = Projection::from(42);
410 assert_eq!(hash(&proj_single), hash(&42_usize));
411
412 let proj_multi = Projection::from([1, 2, 3]);
414 let slice: &[usize] = &[1, 2, 3];
415 assert_eq!(hash(&proj_multi), hash(slice));
416
417 use indexmap::IndexMap;
419 let mut map = IndexMap::new();
420 map.insert(Projection::from(5), "value");
421
422 assert_eq!(map.get(&5_usize), Some(&"value"));
424
425 let slice_single: &[usize] = &[5];
427 assert_eq!(map.get(slice_single), Some(&"value"));
428
429 map.insert(Projection::from([1, 2]), "multi");
431
432 let slice_multi: &[usize] = &[1, 2];
434 assert_eq!(map.get(slice_multi), Some(&"multi"));
435 }
436}