use crate::datum::DatumLower;
use crate::{Bag, List, Tuple, Value, Variant};
use std::cmp::Ordering;
#[derive(Eq, PartialEq)]
pub struct NullSortedValue<'a, const NULLS_FIRST: bool, T>(pub &'a T);
impl<'a, const NULLS_FIRST: bool, T> PartialOrd for NullSortedValue<'a, NULLS_FIRST, T>
where
T: PartialOrd,
NullSortedValue<'a, NULLS_FIRST, T>: Ord,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<const NULLS_FIRST: bool> Ord for NullSortedValue<'_, NULLS_FIRST, Value> {
fn cmp(&self, other: &Self) -> Ordering {
let wrap_list = NullSortedValue::<'_, { NULLS_FIRST }, List>;
let wrap_tuple = NullSortedValue::<'_, { NULLS_FIRST }, Tuple>;
let wrap_bag = NullSortedValue::<'_, { NULLS_FIRST }, Bag>;
let wrap_var = NullSortedValue::<'_, { NULLS_FIRST }, Variant>;
let wrap_value = NullSortedValue::<'_, { NULLS_FIRST }, Value>;
let null_cond = |order: Ordering| {
if NULLS_FIRST {
order
} else {
order.reverse()
}
};
match (self.0, other.0) {
(Value::Null, Value::Null) => Ordering::Equal,
(Value::Missing, Value::Null) => Ordering::Equal,
(Value::Null, Value::Missing) => Ordering::Equal,
(Value::Null, _) => null_cond(Ordering::Less),
(_, Value::Null) => null_cond(Ordering::Greater),
(Value::Missing, Value::Missing) => Ordering::Equal,
(Value::Missing, _) => null_cond(Ordering::Less),
(_, Value::Missing) => null_cond(Ordering::Greater),
(Value::List(l), Value::List(r)) => wrap_list(l.as_ref()).cmp(&wrap_list(r.as_ref())),
(Value::Tuple(l), Value::Tuple(r)) => {
wrap_tuple(l.as_ref()).cmp(&wrap_tuple(r.as_ref()))
}
(Value::Bag(l), Value::Bag(r)) => wrap_bag(l.as_ref()).cmp(&wrap_bag(r.as_ref())),
(Value::Variant(l), Value::Variant(r)) => wrap_var(l).cmp(&wrap_var(r)),
(Value::Variant(var), _) => {
let l_val = var.lower().expect("variant lower");
wrap_value(l_val.as_ref()).cmp(other)
}
(_, Value::Variant(var)) => {
let r_val = var.lower().expect("variant lower");
self.cmp(&wrap_value(r_val.as_ref()))
}
(l, r) => l.cmp(r),
}
}
}