use std::{ops::Deref, vec::Vec};
use smallvec::SmallVec;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Point(pub SmallVec<[u32; 8]>);
impl Point {
pub fn new(vec: impl Into<SmallVec<[u32; 8]>>) -> Self {
Self(vec.into())
}
pub fn new_with_dimension(dimension: u32, vec: impl Into<SmallVec<[u32; 8]>>) -> Self {
let coords = vec.into();
debug_assert_eq!(
coords.len() as u32,
dimension,
"Point dimension mismatch: expected {dimension}, got {}",
coords.len()
);
Self(coords)
}
pub fn distance(&self, p2: &Self) -> f64 {
debug_assert!(
self.len() == p2.len(),
"Point::distance called with differing dimensions: {} vs {}",
self.len(),
p2.len()
);
let mut tot: u128 = 0;
for (a, b) in self.0.iter().zip(p2.0.iter()) {
let d = (*a as i128 - *b as i128).abs();
tot += (d * d) as u128;
}
(tot as f64).sqrt()
}
pub fn as_slice(&self) -> &[u32] {
&self.0
}
pub fn dimension(&self) -> u32 {
self.0.len() as u32
}
}
impl From<Point> for Vec<u32> {
fn from(val: Point) -> Self {
val.0.to_vec()
}
}
impl From<&Point> for Vec<u32> {
fn from(val: &Point) -> Self {
val.0.to_vec()
}
}
impl Deref for Point {
type Target = [u32];
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error;
#[test]
fn point() -> error::Result<()> {
let v = Point::new(vec![2, 2]);
assert_eq!(v.len(), 2);
Ok(())
}
#[test]
fn distance() -> error::Result<()> {
let a = Point::new(vec![2, 2]);
let b = Point::new(vec![2, 1]);
assert_eq!(a.distance(&b), 1.0);
let a = Point::new(vec![2, 2]);
let b = Point::new(vec![0, 2]);
assert_eq!(a.distance(&b), 2.0);
let a = Point::new(vec![0, 2]);
let b = Point::new(vec![0, 0]);
assert_eq!(a.distance(&b), 2.0);
let a = Point::new(vec![0, 2]);
let b = Point::new(vec![0, 2]);
assert_eq!(a.distance(&b), 0.0);
Ok(())
}
}