use core::{
cmp::Ordering,
fmt::Debug,
};
use anyhow::bail;
use crate::utility::results::expect_unwrap;
pub fn zspace_partial_cmp<T: PartialOrd>(
a: &[T],
b: &[T],
) -> Option<Ordering> {
assert_eq!(
a.len(),
b.len(),
"length mismatch: {} != {}",
a.len(),
b.len()
);
let mut ord = Ordering::Equal;
for (ai, bi) in a.iter().zip(b.iter()) {
match ai.partial_cmp(bi) {
None => return None,
Some(Ordering::Equal) => (),
Some(Ordering::Less) => {
if ord == Ordering::Greater {
return None;
}
ord = Ordering::Less;
}
Some(Ordering::Greater) => {
if ord == Ordering::Less {
return None;
}
ord = Ordering::Greater;
}
}
}
Some(ord)
}
pub fn try_point_bounds_check<T>(
point: &[T],
start: &[T],
end: &[T],
) -> anyhow::Result<()>
where
T: PartialOrd + Debug,
{
if !matches!(
zspace_partial_cmp(start, point),
Some(Ordering::Less) | Some(Ordering::Equal)
) || zspace_partial_cmp(point, end) != Some(Ordering::Less)
{
bail!("{point:?} is not in [ {start:?}, {end:?} )");
}
Ok(())
}
#[allow(dead_code)]
pub fn expect_point_bounds_check<T>(
point: &[T],
start: &[T],
end: &[T],
) where
T: PartialOrd + Debug,
{
expect_unwrap(try_point_bounds_check(point, start, end))
}
#[cfg(test)]
mod tests {
use super::*;
#[should_panic(expected = "length mismatch: 2 != 3")]
#[test]
fn test_zspace_partial_cmp_panic() {
zspace_partial_cmp(&[2, 3], &[2, 3, 4]);
}
#[test]
fn test_zspace_partial_cmp() {
assert_eq!(zspace_partial_cmp(&[2, 3], &[2, 3]), Some(Ordering::Equal));
assert_eq!(zspace_partial_cmp(&[2, 3], &[2, 4]), Some(Ordering::Less));
assert_eq!(
zspace_partial_cmp(&[2, 3], &[2, 2]),
Some(Ordering::Greater)
);
assert_eq!(zspace_partial_cmp(&[4, 3], &[2, 4]), None);
assert_eq!(
zspace_partial_cmp(&[2.0, 3.0], &[2.0, 3.0]),
Some(Ordering::Equal)
);
assert_eq!(
zspace_partial_cmp(&[2.0, 3.0], &[2.0, 4.0]),
Some(Ordering::Less)
);
assert_eq!(
zspace_partial_cmp(&[2.0, 3.0], &[2.0, 2.0]),
Some(Ordering::Greater)
);
assert_eq!(zspace_partial_cmp(&[4.0, 3.0], &[2.0, 4.0]), None);
}
#[test]
fn test_zspace_bounds_check() {
assert!(try_point_bounds_check(&[0, 0], &[0, 0], &[2, 3]).is_ok());
assert!(try_point_bounds_check(&[0, 1], &[0, 0], &[2, 3]).is_ok());
assert!(try_point_bounds_check(&[1, 0], &[0, 0], &[2, 3]).is_ok());
assert!(try_point_bounds_check(&[1, 2], &[0, 0], &[2, 3]).is_ok());
assert!(
try_point_bounds_check(&[-1, 2], &[0, 0], &[2, 3])
.unwrap_err()
.to_string()
.contains("[-1, 2] is not in [ [0, 0], [2, 3] )")
);
}
}