range_traits/
measure.rs

1use core::{
2	mem,
3	ops::{Add, Sub},
4};
5
6/// Distance between singletons.
7#[allow(clippy::len_without_is_empty)]
8pub trait Measure<Rhs: ?Sized = Self> {
9	type Len: Default + Add<Output = Self::Len> + Sub<Output = Self::Len> + PartialEq;
10
11	/// Returns the length of the given element.
12	fn len(&self) -> Self::Len;
13
14	/// Returns the distance to the given other element.
15	fn distance(&self, other: &Rhs) -> Self::Len;
16}
17
18impl Measure for char {
19	type Len = u64;
20
21	fn len(&self) -> u64 {
22		1
23	}
24
25	fn distance(&self, other: &char) -> u64 {
26		let mut a = *self as u64;
27		let mut b = *other as u64;
28
29		if a > b {
30			mem::swap(&mut a, &mut b);
31		}
32
33		if (..=0xd7ff).contains(&a) && (0xe000..).contains(&b) {
34			(b - 0xd000 + 1) + (0xd7ff - a)
35		} else {
36			b - a
37		}
38	}
39}
40
41macro_rules! impl_measure {
42	// Measure for type `$ty`.
43	// `$cast` is a type that can handle the subtraction of two elements
44	// without overflowing.
45	// `$len` is a type that can handle the size of the entire domain of `$ty`.
46	(@refl $ty:ty, $cast:ty, $len:ty) => {
47		impl_measure!($ty, $ty, $cast, $len);
48	};
49	(@both $ty1:ty, $ty2:ty, $cast:ty, $len:ty) => {
50		impl_measure!($ty1, $ty2, $cast, $len);
51		impl_measure!($ty2, $ty1, $cast, $len);
52	};
53	($ty1:ty, $ty2:ty, $cast:ty, $len:ty) => {
54		impl Measure<$ty2> for $ty1 {
55			type Len = $len;
56
57			fn len(&self) -> $len {
58				1
59			}
60
61			fn distance(&self, other: &$ty2) -> $len {
62				let a = *self as $cast;
63				let b = *other as $cast;
64
65				if a > b {
66					(a - b) as $len
67				} else {
68					(b - a) as $len
69				}
70			}
71		}
72	};
73}
74
75// All of those are generated by the `generate-measures.rb` script
76// to avoid mistakes.
77impl_measure!(@refl u8, u8, u16);
78impl_measure!(@refl u16, u16, u32);
79impl_measure!(@refl u32, u32, u64);
80impl_measure!(@refl u64, u64, u128);
81impl_measure!(@refl i8, i16, u8);
82impl_measure!(@refl i16, i32, u16);
83impl_measure!(@refl i32, i64, u32);
84impl_measure!(@refl i64, i128, u64);
85impl_measure!(@both u8, u16, u16, u32);
86impl_measure!(@both u8, u32, u32, u64);
87impl_measure!(@both u8, u64, u64, u128);
88impl_measure!(@both u8, i8, i16, u16);
89impl_measure!(@both u8, i16, i32, u16);
90impl_measure!(@both u8, i32, i64, u32);
91impl_measure!(@both u8, i64, i128, u64);
92impl_measure!(@both u16, u32, u32, u64);
93impl_measure!(@both u16, u64, u64, u128);
94impl_measure!(@both u16, i8, i32, u32);
95impl_measure!(@both u16, i16, i32, u32);
96impl_measure!(@both u16, i32, i64, u32);
97impl_measure!(@both u16, i64, i128, u64);
98impl_measure!(@both u32, u64, u64, u128);
99impl_measure!(@both u32, i8, i64, u64);
100impl_measure!(@both u32, i16, i64, u64);
101impl_measure!(@both u32, i32, i64, u64);
102impl_measure!(@both u32, i64, i128, u64);
103impl_measure!(@both u64, i8, i128, u128);
104impl_measure!(@both u64, i16, i128, u128);
105impl_measure!(@both u64, i32, i128, u128);
106impl_measure!(@both u64, i64, i128, u128);
107impl_measure!(@both i8, i16, i32, u16);
108impl_measure!(@both i8, i32, i64, u32);
109impl_measure!(@both i8, i64, i128, u64);
110impl_measure!(@both i16, i32, i64, u32);
111impl_measure!(@both i16, i64, i128, u64);
112impl_measure!(@both i32, i64, i128, u64);
113#[cfg(target_pointer_width = "8")]
114impl_measure!(@refl usize, u8, u16);
115#[cfg(target_pointer_width = "8")]
116impl_measure!(@both usize, u8, u8, u16);
117#[cfg(target_pointer_width = "8")]
118impl_measure!(@both usize, u16, u16, u32);
119#[cfg(target_pointer_width = "8")]
120impl_measure!(@both usize, u32, u32, u64);
121#[cfg(target_pointer_width = "8")]
122impl_measure!(@both usize, u64, u64, u128);
123#[cfg(target_pointer_width = "8")]
124impl_measure!(@both usize, i8, i16, u16);
125#[cfg(target_pointer_width = "8")]
126impl_measure!(@both usize, i16, i32, u16);
127#[cfg(target_pointer_width = "8")]
128impl_measure!(@both usize, i32, i64, u32);
129#[cfg(target_pointer_width = "8")]
130impl_measure!(@both usize, i64, i128, u64);
131#[cfg(target_pointer_width = "16")]
132impl_measure!(@refl usize, u16, u32);
133#[cfg(target_pointer_width = "16")]
134impl_measure!(@both usize, u8, u16, u32);
135#[cfg(target_pointer_width = "16")]
136impl_measure!(@both usize, u16, u16, u32);
137#[cfg(target_pointer_width = "16")]
138impl_measure!(@both usize, u32, u32, u64);
139#[cfg(target_pointer_width = "16")]
140impl_measure!(@both usize, u64, u64, u128);
141#[cfg(target_pointer_width = "16")]
142impl_measure!(@both usize, i8, i32, u32);
143#[cfg(target_pointer_width = "16")]
144impl_measure!(@both usize, i16, i32, u32);
145#[cfg(target_pointer_width = "16")]
146impl_measure!(@both usize, i32, i64, u32);
147#[cfg(target_pointer_width = "16")]
148impl_measure!(@both usize, i64, i128, u64);
149#[cfg(target_pointer_width = "32")]
150impl_measure!(@refl usize, u32, u64);
151#[cfg(target_pointer_width = "32")]
152impl_measure!(@both usize, u8, u32, u64);
153#[cfg(target_pointer_width = "32")]
154impl_measure!(@both usize, u16, u32, u64);
155#[cfg(target_pointer_width = "32")]
156impl_measure!(@both usize, u32, u32, u64);
157#[cfg(target_pointer_width = "32")]
158impl_measure!(@both usize, u64, u64, u128);
159#[cfg(target_pointer_width = "32")]
160impl_measure!(@both usize, i8, i64, u64);
161#[cfg(target_pointer_width = "32")]
162impl_measure!(@both usize, i16, i64, u64);
163#[cfg(target_pointer_width = "32")]
164impl_measure!(@both usize, i32, i64, u64);
165#[cfg(target_pointer_width = "32")]
166impl_measure!(@both usize, i64, i128, u64);
167#[cfg(target_pointer_width = "64")]
168impl_measure!(@refl usize, u64, u128);
169#[cfg(target_pointer_width = "64")]
170impl_measure!(@both usize, u8, u64, u128);
171#[cfg(target_pointer_width = "64")]
172impl_measure!(@both usize, u16, u64, u128);
173#[cfg(target_pointer_width = "64")]
174impl_measure!(@both usize, u32, u64, u128);
175#[cfg(target_pointer_width = "64")]
176impl_measure!(@both usize, u64, u64, u128);
177#[cfg(target_pointer_width = "64")]
178impl_measure!(@both usize, i8, i128, u128);
179#[cfg(target_pointer_width = "64")]
180impl_measure!(@both usize, i16, i128, u128);
181#[cfg(target_pointer_width = "64")]
182impl_measure!(@both usize, i32, i128, u128);
183#[cfg(target_pointer_width = "64")]
184impl_measure!(@both usize, i64, i128, u128);
185
186macro_rules! impl_f_measure {
187	($ty:ty, $zero:expr, $min:expr, $max:expr) => {
188		impl Measure<$ty> for $ty {
189			type Len = $ty;
190
191			fn len(&self) -> $ty {
192				$zero
193			}
194
195			fn distance(&self, other: &$ty) -> $ty {
196				if self.is_infinite() || other.is_infinite() {
197					$max
198				} else {
199					let a = *self as $ty;
200					let b = *other as $ty;
201
202					if a > b {
203						(a - b) as $ty
204					} else {
205						(b - a) as $ty
206					}
207				}
208			}
209		}
210	};
211}
212
213impl_f_measure!(f32, 0.0f32, f32::NEG_INFINITY, f32::INFINITY);
214impl_f_measure!(f64, 0.0f64, f64::NEG_INFINITY, f64::INFINITY);
215
216#[cfg(feature = "ordered-float")]
217mod ordered_float {
218	use super::Measure;
219	use ordered_float::NotNan;
220
221	impl_f_measure!(
222		NotNan<f32>,
223		unsafe { NotNan::new_unchecked(0.0f32) },
224		unsafe { NotNan::new_unchecked(f32::NEG_INFINITY) },
225		unsafe { NotNan::new_unchecked(f32::INFINITY) }
226	);
227
228	impl_f_measure!(
229		NotNan<f64>,
230		unsafe { NotNan::new_unchecked(0.0f64) },
231		unsafe { NotNan::new_unchecked(f64::NEG_INFINITY) },
232		unsafe { NotNan::new_unchecked(f64::INFINITY) }
233	);
234}