#[allow(clippy::len_without_is_empty)]
pub trait Measure<U = Self> {
type Len: Default
+ std::ops::Add<Output = Self::Len>
+ std::ops::Sub<Output = Self::Len>
+ PartialEq;
fn len(&self) -> Self::Len;
fn distance(&self, other: &U) -> Self::Len;
}
impl Measure for char {
type Len = u64;
fn len(&self) -> u64 {
1
}
fn distance(&self, other: &char) -> u64 {
let mut a = *self as u64;
let mut b = *other as u64;
if a > b {
std::mem::swap(&mut a, &mut b);
}
if (..=0xd7ff).contains(&a) && (0xe000..).contains(&b) {
(b - 0xd000 + 1) + (0xd7ff - a)
} else {
b - a
}
}
}
macro_rules! impl_measure {
(@refl $ty:ty, $cast:ty, $len:ty) => {
impl_measure!($ty, $ty, $cast, $len);
};
(@both $ty1:ty, $ty2:ty, $cast:ty, $len:ty) => {
impl_measure!($ty1, $ty2, $cast, $len);
impl_measure!($ty2, $ty1, $cast, $len);
};
($ty1:ty, $ty2:ty, $cast:ty, $len:ty) => {
impl Measure<$ty2> for $ty1 {
type Len = $len;
fn len(&self) -> $len {
1
}
fn distance(&self, other: &$ty2) -> $len {
let a = *self as $cast;
let b = *other as $cast;
if a > b {
(a - b) as $len
} else {
(b - a) as $len
}
}
}
};
}
impl_measure!(@refl u8, u8, u16);
impl_measure!(@refl u16, u16, u32);
impl_measure!(@refl u32, u32, u64);
impl_measure!(@refl u64, u64, u128);
impl_measure!(@refl i8, i16, u8);
impl_measure!(@refl i16, i32, u16);
impl_measure!(@refl i32, i64, u32);
impl_measure!(@refl i64, i128, u64);
impl_measure!(@both u8, u16, u16, u32);
impl_measure!(@both u8, u32, u32, u64);
impl_measure!(@both u8, u64, u64, u128);
impl_measure!(@both u8, i8, i16, u16);
impl_measure!(@both u8, i16, i32, u16);
impl_measure!(@both u8, i32, i64, u32);
impl_measure!(@both u8, i64, i128, u64);
impl_measure!(@both u16, u32, u32, u64);
impl_measure!(@both u16, u64, u64, u128);
impl_measure!(@both u16, i8, i32, u32);
impl_measure!(@both u16, i16, i32, u32);
impl_measure!(@both u16, i32, i64, u32);
impl_measure!(@both u16, i64, i128, u64);
impl_measure!(@both u32, u64, u64, u128);
impl_measure!(@both u32, i8, i64, u64);
impl_measure!(@both u32, i16, i64, u64);
impl_measure!(@both u32, i32, i64, u64);
impl_measure!(@both u32, i64, i128, u64);
impl_measure!(@both u64, i8, i128, u128);
impl_measure!(@both u64, i16, i128, u128);
impl_measure!(@both u64, i32, i128, u128);
impl_measure!(@both u64, i64, i128, u128);
impl_measure!(@both i8, i16, i32, u16);
impl_measure!(@both i8, i32, i64, u32);
impl_measure!(@both i8, i64, i128, u64);
impl_measure!(@both i16, i32, i64, u32);
impl_measure!(@both i16, i64, i128, u64);
impl_measure!(@both i32, i64, i128, u64);
#[cfg(target_pointer_width = "8")]
impl_measure!(@refl usize, u8, u16);
#[cfg(target_pointer_width = "8")]
impl_measure!(@both usize, u8, u8, u16);
#[cfg(target_pointer_width = "8")]
impl_measure!(@both usize, u16, u16, u32);
#[cfg(target_pointer_width = "8")]
impl_measure!(@both usize, u32, u32, u64);
#[cfg(target_pointer_width = "8")]
impl_measure!(@both usize, u64, u64, u128);
#[cfg(target_pointer_width = "8")]
impl_measure!(@both usize, i8, i16, u16);
#[cfg(target_pointer_width = "8")]
impl_measure!(@both usize, i16, i32, u16);
#[cfg(target_pointer_width = "8")]
impl_measure!(@both usize, i32, i64, u32);
#[cfg(target_pointer_width = "8")]
impl_measure!(@both usize, i64, i128, u64);
#[cfg(target_pointer_width = "16")]
impl_measure!(@refl usize, u16, u32);
#[cfg(target_pointer_width = "16")]
impl_measure!(@both usize, u8, u16, u32);
#[cfg(target_pointer_width = "16")]
impl_measure!(@both usize, u16, u16, u32);
#[cfg(target_pointer_width = "16")]
impl_measure!(@both usize, u32, u32, u64);
#[cfg(target_pointer_width = "16")]
impl_measure!(@both usize, u64, u64, u128);
#[cfg(target_pointer_width = "16")]
impl_measure!(@both usize, i8, i32, u32);
#[cfg(target_pointer_width = "16")]
impl_measure!(@both usize, i16, i32, u32);
#[cfg(target_pointer_width = "16")]
impl_measure!(@both usize, i32, i64, u32);
#[cfg(target_pointer_width = "16")]
impl_measure!(@both usize, i64, i128, u64);
#[cfg(target_pointer_width = "32")]
impl_measure!(@refl usize, u32, u64);
#[cfg(target_pointer_width = "32")]
impl_measure!(@both usize, u8, u32, u64);
#[cfg(target_pointer_width = "32")]
impl_measure!(@both usize, u16, u32, u64);
#[cfg(target_pointer_width = "32")]
impl_measure!(@both usize, u32, u32, u64);
#[cfg(target_pointer_width = "32")]
impl_measure!(@both usize, u64, u64, u128);
#[cfg(target_pointer_width = "32")]
impl_measure!(@both usize, i8, i64, u64);
#[cfg(target_pointer_width = "32")]
impl_measure!(@both usize, i16, i64, u64);
#[cfg(target_pointer_width = "32")]
impl_measure!(@both usize, i32, i64, u64);
#[cfg(target_pointer_width = "32")]
impl_measure!(@both usize, i64, i128, u64);
#[cfg(target_pointer_width = "64")]
impl_measure!(@refl usize, u64, u128);
#[cfg(target_pointer_width = "64")]
impl_measure!(@both usize, u8, u64, u128);
#[cfg(target_pointer_width = "64")]
impl_measure!(@both usize, u16, u64, u128);
#[cfg(target_pointer_width = "64")]
impl_measure!(@both usize, u32, u64, u128);
#[cfg(target_pointer_width = "64")]
impl_measure!(@both usize, u64, u64, u128);
#[cfg(target_pointer_width = "64")]
impl_measure!(@both usize, i8, i128, u128);
#[cfg(target_pointer_width = "64")]
impl_measure!(@both usize, i16, i128, u128);
#[cfg(target_pointer_width = "64")]
impl_measure!(@both usize, i32, i128, u128);
#[cfg(target_pointer_width = "64")]
impl_measure!(@both usize, i64, i128, u128);
macro_rules! impl_f_measure {
($ty:ty, $zero:expr, $min:expr, $max:expr) => {
impl Measure<$ty> for $ty {
type Len = $ty;
fn len(&self) -> $ty {
$zero
}
fn distance(&self, other: &$ty) -> $ty {
if self.is_infinite() || other.is_infinite() {
$max
} else {
let a = *self as $ty;
let b = *other as $ty;
if a > b {
(a - b) as $ty
} else {
(b - a) as $ty
}
}
}
}
};
}
impl_f_measure!(f32, 0.0f32, f32::NEG_INFINITY, f32::INFINITY);
impl_f_measure!(f64, 0.0f64, f64::NEG_INFINITY, f64::INFINITY);
#[cfg(feature = "ordered-float")]
mod ordered_float {
use super::{Measure, PartialEnum};
use ordered_float::NotNan;
impl_f_measure!(
NotNan<f32>,
unsafe { NotNan::new_unchecked(0.0f32) },
unsafe { NotNan::new_unchecked(f32::NEG_INFINITY) },
unsafe { NotNan::new_unchecked(f32::INFINITY) }
);
impl_f_measure!(
NotNan<f64>,
unsafe { NotNan::new_unchecked(0.0f64) },
unsafe { NotNan::new_unchecked(f64::NEG_INFINITY) },
unsafe { NotNan::new_unchecked(f64::INFINITY) }
);
}