use core::fmt::Debug;
use num_traits::{Bounded, Num, Signed, Zero};
pub trait RTreeNum: Bounded + Num + Clone + Copy + Signed + PartialOrd + Debug {}
impl<S> RTreeNum for S where S: Bounded + Num + Clone + Copy + Signed + PartialOrd + Debug {}
pub trait Point: Clone + PartialEq + Debug {
type Scalar: RTreeNum;
const DIMENSIONS: usize;
fn generate(generator: impl FnMut(usize) -> Self::Scalar) -> Self;
fn nth(&self, index: usize) -> Self::Scalar;
fn nth_mut(&mut self, index: usize) -> &mut Self::Scalar;
}
impl<T> PointExt for T where T: Point {}
pub trait PointExt: Point {
fn new() -> Self {
Self::from_value(Zero::zero())
}
fn component_wise(
&self,
other: &Self,
mut f: impl FnMut(Self::Scalar, Self::Scalar) -> Self::Scalar,
) -> Self {
Self::generate(|i| f(self.nth(i), other.nth(i)))
}
fn all_component_wise(
&self,
other: &Self,
mut f: impl FnMut(Self::Scalar, Self::Scalar) -> bool,
) -> bool {
(0..Self::DIMENSIONS).all(|i| f(self.nth(i), other.nth(i)))
}
fn dot(&self, rhs: &Self) -> Self::Scalar {
self.component_wise(rhs, |l, r| l * r)
.fold(Zero::zero(), |acc, val| acc + val)
}
fn fold<T>(&self, start_value: T, mut f: impl FnMut(T, Self::Scalar) -> T) -> T {
(0..Self::DIMENSIONS).fold(start_value, |accumulated, i| f(accumulated, self.nth(i)))
}
fn from_value(value: Self::Scalar) -> Self {
Self::generate(|_| value)
}
fn min_point(&self, other: &Self) -> Self {
self.component_wise(other, min_inline)
}
fn max_point(&self, other: &Self) -> Self {
self.component_wise(other, max_inline)
}
fn length_2(&self) -> Self::Scalar {
self.fold(Zero::zero(), |acc, cur| cur * cur + acc)
}
fn sub(&self, other: &Self) -> Self {
self.component_wise(other, |l, r| l - r)
}
fn add(&self, other: &Self) -> Self {
self.component_wise(other, |l, r| l + r)
}
fn mul(&self, scalar: Self::Scalar) -> Self {
self.map(|coordinate| coordinate * scalar)
}
fn map(&self, mut f: impl FnMut(Self::Scalar) -> Self::Scalar) -> Self {
Self::generate(|i| f(self.nth(i)))
}
fn distance_2(&self, other: &Self) -> Self::Scalar {
self.sub(other).length_2()
}
}
#[inline]
pub fn min_inline<S>(a: S, b: S) -> S
where
S: RTreeNum,
{
if a < b {
a
} else {
b
}
}
#[inline]
pub fn max_inline<S>(a: S, b: S) -> S
where
S: RTreeNum,
{
if a > b {
a
} else {
b
}
}
impl<S, const N: usize> Point for [S; N]
where
S: RTreeNum,
{
type Scalar = S;
const DIMENSIONS: usize = N;
fn generate(mut generator: impl FnMut(usize) -> S) -> Self {
let mut idx = 0;
[(); N].map(|_| {
let res = generator(idx);
idx += 1;
res
})
}
#[inline]
fn nth(&self, index: usize) -> Self::Scalar {
self[index]
}
#[inline]
fn nth_mut(&mut self, index: usize) -> &mut Self::Scalar {
&mut self[index]
}
}
macro_rules! count_exprs {
() => (0);
($head:expr) => (1);
($head:expr, $($tail:expr),*) => (1 + count_exprs!($($tail),*));
}
macro_rules! fixed_type {
($expr:expr, $type:ty) => {
$type
};
}
macro_rules! impl_point_for_tuple {
($($index:expr => $name:ident),+) => {
impl<S> Point for ($(fixed_type!($index, S),)+)
where
S: RTreeNum
{
type Scalar = S;
const DIMENSIONS: usize = count_exprs!($($index),*);
fn generate(mut generator: impl FnMut(usize) -> S) -> Self {
($(generator($index),)+)
}
#[inline]
fn nth(&self, index: usize) -> Self::Scalar {
let ($($name,)+) = self;
match index {
$($index => *$name,)+
_ => unreachable!("index {} out of bounds for tuple", index),
}
}
#[inline]
fn nth_mut(&mut self, index: usize) -> &mut Self::Scalar {
let ($($name,)+) = self;
match index {
$($index => $name,)+
_ => unreachable!("index {} out of bounds for tuple", index),
}
}
}
};
}
impl_point_for_tuple!(0 => a);
impl_point_for_tuple!(0 => a, 1 => b);
impl_point_for_tuple!(0 => a, 1 => b, 2 => c);
impl_point_for_tuple!(0 => a, 1 => b, 2 => c, 3 => d);
impl_point_for_tuple!(0 => a, 1 => b, 2 => c, 3 => d, 4 => e);
impl_point_for_tuple!(0 => a, 1 => b, 2 => c, 3 => d, 4 => e, 5 => f);
impl_point_for_tuple!(0 => a, 1 => b, 2 => c, 3 => d, 4 => e, 5 => f, 6 => g);
impl_point_for_tuple!(0 => a, 1 => b, 2 => c, 3 => d, 4 => e, 5 => f, 6 => g, 7 => h);
impl_point_for_tuple!(0 => a, 1 => b, 2 => c, 3 => d, 4 => e, 5 => f, 6 => g, 7 => h, 8 => i);
impl_point_for_tuple!(0 => a, 1 => b, 2 => c, 3 => d, 4 => e, 5 => f, 6 => g, 7 => h, 8 => i, 9 => j);
#[cfg(test)]
mod tests {
use super::*;
use core::num::Wrapping;
#[test]
fn test_types() {
fn assert_impl_rtreenum<S: RTreeNum>() {}
assert_impl_rtreenum::<i8>();
assert_impl_rtreenum::<i16>();
assert_impl_rtreenum::<i32>();
assert_impl_rtreenum::<i64>();
assert_impl_rtreenum::<i128>();
assert_impl_rtreenum::<isize>();
assert_impl_rtreenum::<Wrapping<i8>>();
assert_impl_rtreenum::<Wrapping<i16>>();
assert_impl_rtreenum::<Wrapping<i32>>();
assert_impl_rtreenum::<Wrapping<i64>>();
assert_impl_rtreenum::<Wrapping<i128>>();
assert_impl_rtreenum::<Wrapping<isize>>();
assert_impl_rtreenum::<f32>();
assert_impl_rtreenum::<f64>();
}
macro_rules! test_tuple_configuration {
($($index:expr),*) => {
let a = ($($index),*);
$(assert_eq!(a.nth($index), $index));*
}
}
#[test]
fn test_tuples() {
let simple_int = (0, 1, 2);
assert_eq!(simple_int.nth(2), 2);
let simple_float = (0.5, 0.67, 1234.56);
assert_eq!(simple_float.nth(2), 1234.56);
let long_int = (0, 1, 2, 3, 4, 5, 6, 7, 8);
assert_eq!(long_int.nth(8), 8);
test_tuple_configuration!(0, 1);
test_tuple_configuration!(0, 1, 2);
test_tuple_configuration!(0, 1, 2, 3);
test_tuple_configuration!(0, 1, 2, 3, 4);
test_tuple_configuration!(0, 1, 2, 3, 4, 5);
test_tuple_configuration!(0, 1, 2, 3, 4, 5, 6);
test_tuple_configuration!(0, 1, 2, 3, 4, 5, 6, 7);
test_tuple_configuration!(0, 1, 2, 3, 4, 5, 6, 7, 8);
}
}