partiql_value/
sort.rs

1use crate::datum::DatumLower;
2use crate::{Bag, List, Tuple, Value, Variant};
3use std::cmp::Ordering;
4
5/// A wrapper on [`T`] that specifies if a null or missing value should be ordered before
6/// ([`NULLS_FIRST`] is true) or after ([`NULLS_FIRST`] is false) other values.
7#[derive(Eq, PartialEq)]
8pub struct NullSortedValue<'a, const NULLS_FIRST: bool, T>(pub &'a T);
9
10impl<'a, const NULLS_FIRST: bool, T> PartialOrd for NullSortedValue<'a, NULLS_FIRST, T>
11where
12    T: PartialOrd,
13    NullSortedValue<'a, NULLS_FIRST, T>: Ord,
14{
15    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
16        Some(self.cmp(other))
17    }
18}
19
20impl<const NULLS_FIRST: bool> Ord for NullSortedValue<'_, NULLS_FIRST, Value> {
21    fn cmp(&self, other: &Self) -> Ordering {
22        let wrap_list = NullSortedValue::<'_, { NULLS_FIRST }, List>;
23        let wrap_tuple = NullSortedValue::<'_, { NULLS_FIRST }, Tuple>;
24        let wrap_bag = NullSortedValue::<'_, { NULLS_FIRST }, Bag>;
25        let wrap_var = NullSortedValue::<'_, { NULLS_FIRST }, Variant>;
26        let wrap_value = NullSortedValue::<'_, { NULLS_FIRST }, Value>;
27        let null_cond = |order: Ordering| {
28            if NULLS_FIRST {
29                order
30            } else {
31                order.reverse()
32            }
33        };
34
35        match (self.0, other.0) {
36            (Value::Null, Value::Null) => Ordering::Equal,
37            (Value::Missing, Value::Null) => Ordering::Equal,
38
39            (Value::Null, Value::Missing) => Ordering::Equal,
40            (Value::Null, _) => null_cond(Ordering::Less),
41            (_, Value::Null) => null_cond(Ordering::Greater),
42
43            (Value::Missing, Value::Missing) => Ordering::Equal,
44            (Value::Missing, _) => null_cond(Ordering::Less),
45            (_, Value::Missing) => null_cond(Ordering::Greater),
46
47            (Value::List(l), Value::List(r)) => wrap_list(l.as_ref()).cmp(&wrap_list(r.as_ref())),
48
49            (Value::Tuple(l), Value::Tuple(r)) => {
50                wrap_tuple(l.as_ref()).cmp(&wrap_tuple(r.as_ref()))
51            }
52
53            (Value::Bag(l), Value::Bag(r)) => wrap_bag(l.as_ref()).cmp(&wrap_bag(r.as_ref())),
54
55            (Value::Variant(l), Value::Variant(r)) => wrap_var(l).cmp(&wrap_var(r)),
56            (Value::Variant(var), _) => {
57                let l_val = var.lower().expect("variant lower");
58                wrap_value(l_val.as_ref()).cmp(other)
59            }
60            (_, Value::Variant(var)) => {
61                let r_val = var.lower().expect("variant lower");
62                self.cmp(&wrap_value(r_val.as_ref()))
63            }
64
65            (l, r) => l.cmp(r),
66        }
67    }
68}