vek/
ops.rs

1//! Operations defined by this crate, such as `MulAdd`, `Lerp`, `Clamp`, and `Wrap`.
2
3use std::num::Wrapping;
4use std::ops::*;
5use std::cmp;
6use num_traits::{Zero, One, FloatConst};
7
8pub use num_traits::ops::mul_add::MulAdd;
9
10// On no_std targets, we have to import the Real trait, but on std targets it will use the built-in primitive methods instead and warn that Real is unused.
11#[allow(unused_imports)]
12use num_traits::real::Real;
13
14/// Compares and returns the minimum of two values, using partial ordering.
15pub fn partial_min<T: PartialOrd + Sized>(a: T, b: T) -> T {
16    if a <= b { a } else { b }
17}
18/// Compares and returns the maximum of two values, using partial ordering.
19pub fn partial_max<T: PartialOrd + Sized>(a: T, b: T) -> T {
20    if a >= b { a } else { b }
21}
22
23/// A value that can tell whether or not it is between two bounds (inclusive).
24pub trait IsBetween<Bound=Self>: Sized {
25    /// `bool` for scalars, or vector of `bool`s for vectors.
26    type Output;
27    /// Returns whether this value is between `lower` and `upper` (inclusive).
28    ///
29    /// # Panics
30    /// Panics if `lower` is greater than `upper`. Swap the values yourself if necessary.
31    ///
32    /// ```
33    /// use vek::ops::IsBetween;
34    ///
35    /// assert!(5_i32 .is_between(5, 10));
36    /// assert!(7_i32 .is_between(5, 10));
37    /// assert!(10_i32.is_between(5, 10));
38    /// assert!(!(4_i32 .is_between(5, 10)));
39    /// assert!(!(11_i32.is_between(5, 10)));
40    /// ```
41    fn is_between(self, lower: Bound, upper: Bound) -> Self::Output;
42    /// Returns whether this value is between 0 and 1 (inclusive).
43    fn is_between01(self) -> Self::Output where Bound: Zero + One {
44        self.is_between(Bound::zero(), Bound::one())
45    }
46    /// Returns whether this value is between the lower and upper bounds of this inclusive range.
47    /// This is redundant with `RangeInclusive::contains()`, but is still useful for generics that use the `IsBetween` trait.
48    fn is_between_inclusive_range_bounds(self, range: RangeInclusive<Bound>) -> Self::Output {
49        let (start, end) = range.into_inner();
50        self.is_between(start, end)
51    }
52}
53
54/// A value that can tell whether or not it is between 0 and 1 (inclusive).
55pub trait IsBetween01: IsBetween + Zero + One {}
56impl<T: IsBetween + Zero + One> IsBetween01 for T {}
57
58
59/// A scalar or vector that can be constrained to be between two values (inclusive).
60pub trait Clamp<Bound=Self>: Sized {
61    /// Constrains this value to be between `lower` and `upper` (inclusive).
62    ///
63    /// # Panics
64    /// Panics if `lower` is greater than `upper`. Swap the values yourself if necessary.
65    ///
66    /// ```
67    /// use vek::ops::Clamp;
68    ///
69    /// assert_eq!(7.clamped(5, 10), 7);
70    /// assert_eq!(4.clamped(5, 10), 5);
71    /// assert_eq!(5.clamped(5, 10), 5);
72    /// assert_eq!(10.clamped(5, 10), 10);
73    /// assert_eq!(11.clamped(5, 10), 10);
74    /// ```
75    fn clamped(self, lower: Bound, upper: Bound) -> Self;
76    /// Alias to `clamped`, which accepts a `RangeInclusive` parameter instead of two values.
77    fn clamped_to_inclusive_range(self, range: RangeInclusive<Bound>) -> Self {
78        let (start, end) = range.into_inner();
79        self.clamped(start, end)
80    }
81    /// Alias to `clamped`, which doesn't take `self`.
82    ///
83    /// # Panics
84    /// Panics if `lower` is greater than `upper`. Swap the values yourself if necessary.
85    fn clamp(val: Self, lower: Bound, upper: Bound) -> Self {
86        val.clamped(lower, upper)
87    }
88    /// Alias to `clamp`, which accepts a `RangeInclusive` parameter instead of two values.
89    fn clamp_to_inclusive_range(val: Self, range: RangeInclusive<Bound>) -> Self {
90        let (start, end) = range.into_inner();
91        Self::clamp(val, start, end)
92    }
93    /// Constrains this value to be between 0 and 1 (inclusive).
94    fn clamped01(self) -> Self where Bound: Zero + One {
95        self.clamped(Bound::zero(), Bound::one())
96    }
97    /// Alias to `clamped01`, which doesn't take `self`.
98    fn clamp01(val: Self) -> Self where Bound: Zero + One {
99        Self::clamp(val, Bound::zero(), Bound::one())
100    }
101    /// Constrains this value to be between -1 and 1 (inclusive).
102    fn clamped_minus1_1(self) -> Self where Bound: One + Neg<Output=Bound> {
103        self.clamped(-Bound::one(), Bound::one())
104    }
105    /// Alias to `clamped_minus1_1`, which doesn't take `self`.
106    fn clamp_minus1_1(val: Self) -> Self where Bound: One + Neg<Output=Bound> {
107        Self::clamp(val, -Bound::one(), Bound::one())
108    }
109}
110
111/// A scalar or vector that can be constrained to be between 0 and 1 (inclusive).
112pub trait Clamp01: Clamp + Zero + One {}
113impl<T: Clamp + Zero + One> Clamp01 for T {}
114
115/// A scalar or vector that can be constrained to be between -1 and 1 (inclusive).
116pub trait ClampMinus1: Clamp + One + Neg<Output=Self> {}
117impl<T: Clamp + One + Neg<Output=T>> ClampMinus1 for T {}
118
119macro_rules! impl_clamp_float {
120    ($($T:ty)+) => {
121        $(
122            impl Clamp for $T {
123                fn clamped(self, lower: Self, upper: Self) -> Self {
124                    assert!(lower <= upper);
125                    partial_min(partial_max(self, lower), upper)
126                }
127            }
128            impl IsBetween for $T {
129                type Output = bool;
130                fn is_between(self, lower: Self, upper: Self) -> bool {
131                    assert!(lower <= upper);
132                    lower <= self && self <= upper
133                }
134            }
135        )+
136    }
137}
138macro_rules! impl_clamp_integer {
139    ($($T:ty)+) => {
140        $(
141            impl Clamp for $T {
142                fn clamped(self, lower: Self, upper: Self) -> Self {
143                    assert!(lower <= upper);
144                    cmp::min(cmp::max(self, lower), upper)
145                }
146            }
147            impl IsBetween for $T {
148                type Output = bool;
149                fn is_between(self, lower: Self, upper: Self) -> bool {
150                    assert!(lower <= upper);
151                    lower <= self && self <= upper
152                }
153            }
154        )+
155    }
156}
157
158impl_clamp_float!{
159    f32 f64
160}
161impl_clamp_integer!{
162    i8 i16 i32 i64 isize u8 u16 u32 u64 usize
163    Wrapping<i8>
164    Wrapping<i16>
165    Wrapping<i32>
166    Wrapping<i64>
167    Wrapping<isize>
168    Wrapping<u8>
169    Wrapping<u16>
170    Wrapping<u32>
171    Wrapping<u64>
172    Wrapping<usize>
173}
174
175
176/// Returns `(val * mul) + add`.
177#[deprecated(since = "0.15.0", note = "This is redundant with num-trait's MulAdd trait and std's mul_add operation")]
178pub fn mul_add<Output,V,M,A>(val: V, mul: M, add: A) -> Output where V: MulAdd<M,A,Output=Output> {
179    val.mul_add(mul, add)
180}
181
182
183/// A value that can be linearly interpolated.
184///
185/// Note that, like standard operators, this can be implement for `T` and `&T`.
186/// You would make the difference like so:
187///
188/// ```
189/// use vek::ops::Lerp;
190///
191/// let a = Lerp::lerp(0, 10, 0.5_f32);
192/// let b = Lerp::lerp(&0, &10, 0.5_f32);
193/// let c = i32::lerp(0, 10, 0.5_f32);
194/// let d = <&i32>::lerp(&0, &10, 0.5_f32);
195/// assert_eq!(a, b);
196/// assert_eq!(a, c);
197/// assert_eq!(a, d);
198/// ```
199///
200/// This is made possible thanks to the explicit `Output` type.
201/// Therefore, it's also convenient for `GameState` structures, which you might
202/// prefer to interpolate by reference instead of consuming them.
203/// The interpolation of two `&GameState`s would produce a new `GameState` value.
204///
205/// ```
206/// use vek::{Lerp, Vec3};
207///
208/// /// A data-heavy structure that represents a current game state.
209/// /// It's neither Copy and nor even Clone!
210/// struct GameState {
211///     pub camera_position: Vec3<f32>,
212///     // ... obviously a lot of other members following ...
213/// }
214/// // We can select the Progress type. I chose f64; the default is f32.
215/// impl<'a> Lerp<f64> for &'a GameState {
216///     type Output = GameState;
217///     fn lerp_unclamped(a: Self, b: Self, t: f64) -> GameState {
218///         GameState {
219///             camera_position: Lerp::lerp(a.camera_position, b.camera_position, t as f32),
220///             // ... etc for all relevant members...
221///         }
222///     }
223/// }
224/// let a = GameState { camera_position: Vec3::zero() };
225/// let b = GameState { camera_position: Vec3::unit_x() };
226/// let c = Lerp::lerp(&a, &b, 0.5);
227/// // Hurray! We've got an interpolated state without consuming the two previous ones.
228/// # let _ = c;
229/// ```
230pub trait Lerp<Factor=f32>: Sized
231{
232    /// The resulting type after performing the LERP operation.
233    type Output;
234    /// Returns the linear interpolation of `from` to `to` with `factor` unconstrained,
235    /// using the supposedly fastest but less precise implementation.
236    ///
237    /// A possible implementation is `from + factor * (to - from)`, a.k.a
238    /// `factor.mul_add(to - from, from)`.
239    ///
240    /// ```
241    /// use vek::ops::Lerp;
242    ///
243    /// assert_eq!(Lerp::lerp_unclamped(10, 20, -1.0_f32),  0);
244    /// assert_eq!(Lerp::lerp_unclamped(10, 20, -0.5_f32),  5);
245    /// assert_eq!(Lerp::lerp_unclamped(10, 20,  0.0_f32), 10);
246    /// assert_eq!(Lerp::lerp_unclamped(10, 20,  0.5_f32), 15);
247    /// assert_eq!(Lerp::lerp_unclamped(10, 20,  1.0_f32), 20);
248    /// assert_eq!(Lerp::lerp_unclamped(10, 20,  1.5_f32), 25);
249    /// ```
250    fn lerp_unclamped(from: Self, to: Self, factor: Factor) -> Self::Output;
251
252    /// Version of `lerp_unclamped()` that used a single `RangeInclusive` parameter instead of two values.
253    fn lerp_unclamped_inclusive_range(range: RangeInclusive<Self>, factor: Factor) -> Self::Output {
254        let (from, to) = range.into_inner();
255        Self::lerp_unclamped(from, to, factor)
256    }
257
258    /// Returns the linear interpolation of `from` to `to` with `factor` unconstrained,
259    /// using a possibly slower but more precise operation.
260    ///
261    /// A possible implementation is `from*(1-factor) + to*factor`, a.k.a
262    /// `from.mul_add(1-factor, to*factor)`.
263    ///
264    /// ```
265    /// use vek::ops::Lerp;
266    ///
267    /// assert_eq!(Lerp::lerp_unclamped_precise(10, 20, -1.0_f32),  0);
268    /// assert_eq!(Lerp::lerp_unclamped_precise(10, 20, -0.5_f32),  5);
269    /// assert_eq!(Lerp::lerp_unclamped_precise(10, 20,  0.0_f32), 10);
270    /// assert_eq!(Lerp::lerp_unclamped_precise(10, 20,  0.5_f32), 15);
271    /// assert_eq!(Lerp::lerp_unclamped_precise(10, 20,  1.0_f32), 20);
272    /// assert_eq!(Lerp::lerp_unclamped_precise(10, 20,  1.5_f32), 25);
273    /// ```
274    fn lerp_unclamped_precise(from: Self, to: Self, factor: Factor) -> Self::Output {
275        Self::lerp_unclamped(from, to, factor)
276    }
277
278    /// Version of `lerp_unclamped_precise()` that used a single `RangeInclusive` parameter instead of two values.
279    fn lerp_unclamped_precise_inclusive_range(range: RangeInclusive<Self>, factor: Factor) -> Self::Output {
280        let (from, to) = range.into_inner();
281        Self::lerp_unclamped_precise(from, to, factor)
282    }
283
284    /// Alias to `lerp_unclamped` which constrains `factor` to be between 0 and 1
285    /// (inclusive).
286    ///
287    /// ```
288    /// use vek::ops::Lerp;
289    ///
290    /// assert_eq!(Lerp::lerp(10, 20, -1.0_f32), 10);
291    /// assert_eq!(Lerp::lerp(10, 20, -0.5_f32), 10);
292    /// assert_eq!(Lerp::lerp(10, 20,  0.0_f32), 10);
293    /// assert_eq!(Lerp::lerp(10, 20,  0.5_f32), 15);
294    /// assert_eq!(Lerp::lerp(10, 20,  1.0_f32), 20);
295    /// assert_eq!(Lerp::lerp(10, 20,  1.5_f32), 20);
296    /// ```
297    fn lerp(from: Self, to: Self, factor: Factor) -> Self::Output where Factor: Clamp + Zero + One {
298        Self::lerp_unclamped(from, to, factor.clamped01())
299    }
300
301    /// Version of `lerp()` that used a single `RangeInclusive` parameter instead of two values.
302    fn lerp_inclusive_range(range: RangeInclusive<Self>, factor: Factor) -> Self::Output where Factor: Clamp + Zero + One {
303        let (from, to) = range.into_inner();
304        Self::lerp(from, to, factor)
305    }
306
307    /// Alias to `lerp_unclamped_precise` which constrains `factor` to be between 0 and 1
308    /// (inclusive).
309    ///
310    /// ```
311    /// use vek::ops::Lerp;
312    ///
313    /// assert_eq!(Lerp::lerp_precise(10, 20, -1.0_f32), 10);
314    /// assert_eq!(Lerp::lerp_precise(10, 20, -0.5_f32), 10);
315    /// assert_eq!(Lerp::lerp_precise(10, 20,  0.0_f32), 10);
316    /// assert_eq!(Lerp::lerp_precise(10, 20,  0.5_f32), 15);
317    /// assert_eq!(Lerp::lerp_precise(10, 20,  1.0_f32), 20);
318    /// assert_eq!(Lerp::lerp_precise(10, 20,  1.5_f32), 20);
319    /// ```
320    fn lerp_precise(from: Self, to: Self, factor: Factor) -> Self::Output where Factor: Clamp + Zero + One {
321        Self::lerp_unclamped_precise(from, to, factor.clamped01())
322    }
323
324    /// Version of `lerp_precise()` that used a single `RangeInclusive` parameter instead of two values.
325    fn lerp_precise_inclusive_range(range: RangeInclusive<Self>, factor: Factor) -> Self::Output where Factor: Clamp + Zero + One {
326        let (from, to) = range.into_inner();
327        Self::lerp_precise(from, to, factor)
328    }
329}
330
331macro_rules! lerp_impl_float {
332    ($($T:ty)+) => {
333        $(
334            impl Lerp<$T> for $T {
335                type Output = $T;
336                fn lerp_unclamped_precise(from: Self, to: Self, factor: Self) -> Self {
337                    from*(Self::one()-factor) + to*factor
338                }
339                fn lerp_unclamped(from: Self, to: Self, factor: Self) -> Self {
340                    self::MulAdd::mul_add(factor, to - from, from)
341                }
342            }
343            impl<'a> Lerp<$T> for &'a $T {
344                type Output = $T;
345                fn lerp_unclamped_precise(from: Self, to: Self, factor: $T) -> $T {
346                    Lerp::lerp_unclamped_precise(*from, *to, factor)
347                }
348                fn lerp_unclamped(from: Self, to: Self, factor: $T) -> $T {
349                    Lerp::lerp_unclamped(*from, *to, factor)
350                }
351            }
352        )+
353    }
354}
355macro_rules! lerp_impl_integer {
356    ($($T:ty)+) => {
357        $(
358            impl Lerp<f32> for $T {
359                type Output = $T;
360                fn lerp_unclamped_precise(from: Self, to: Self, factor: f32) -> Self {
361                    num_traits::Float::round((from as f32)*((1f32)-factor) + (to as f32)*factor) as Self
362                }
363                fn lerp_unclamped(from: Self, to: Self, factor: f32) -> Self {
364                    num_traits::Float::round(self::MulAdd::mul_add(factor, (to - from) as f32, from as f32)) as Self
365                }
366            }
367            impl Lerp<f64> for $T {
368                type Output = $T;
369                fn lerp_unclamped_precise(from: Self, to: Self, factor: f64) -> Self {
370                    num_traits::Float::round((from as f64)*((1f64)-factor) + (to as f64)*factor) as Self
371                }
372                fn lerp_unclamped(from: Self, to: Self, factor: f64) -> Self {
373                    num_traits::Float::round(self::MulAdd::mul_add(factor, (to - from) as f64, from as f64)) as Self
374                }
375            }
376            impl<'a> Lerp<f32> for &'a $T {
377                type Output = $T;
378                fn lerp_unclamped_precise(from: Self, to: Self, factor: f32) -> $T {
379                    Lerp::lerp_unclamped_precise(*from, *to, factor)
380                }
381                fn lerp_unclamped(from: Self, to: Self, factor: f32) -> $T {
382                    Lerp::lerp_unclamped(*from, *to, factor)
383                }
384            }
385            impl<'a> Lerp<f64> for &'a $T {
386                type Output = $T;
387                fn lerp_unclamped_precise(from: Self, to: Self, factor: f64) -> $T {
388                    Lerp::lerp_unclamped_precise(*from, *to, factor)
389                }
390                fn lerp_unclamped(from: Self, to: Self, factor: f64) -> $T {
391                    Lerp::lerp_unclamped(*from, *to, factor)
392                }
393            }
394        )+
395    }
396}
397
398lerp_impl_float!{f32 f64}
399lerp_impl_integer!{
400    i8 i16 i32 i64 isize u8 u16 u32 u64 usize
401    /*
402    Wrapping<i8>
403    Wrapping<i16>
404    Wrapping<i32>
405    Wrapping<i64>
406    Wrapping<isize>
407    Wrapping<u8>
408    Wrapping<u16>
409    Wrapping<u32>
410    Wrapping<u64>
411    Wrapping<usize>
412    */
413}
414
415/// A value that can be Spherically Linearly interpolated.
416///
417/// The `Output` type allows this trait to be meaningfully implemented for `&T` as well as `T`.
418pub trait Slerp<Factor=f32>: Sized {
419    /// The resulting type after performing the SLERP operation.
420    type Output;
421    /// Performs spherical linear interpolation without implictly constraining `factor` to
422    /// be between 0 and 1.
423    fn slerp_unclamped(from: Self, to: Self, factor: Factor) -> Self::Output;
424    /// Performs spherical linear interpolation, constraining `factor` to
425    /// be between 0 and 1.
426    fn slerp(from: Self, to: Self, factor: Factor) -> Self::Output where Factor: Clamp + Zero + One {
427        Self::slerp_unclamped(from, to, factor.clamped01())
428    }
429}
430
431/// A value that can wrap itself around given bounds.
432pub trait Wrap<Bound=Self>: Sized {
433    /// Returns this value, wrapped between zero and some `upper` bound (both inclusive).
434    ///
435    /// The computation is `self - (self/upper).floor() * upper`.
436    ///
437    /// This might look like the remainder (`%`) operator, but behaves differently with negative
438    /// values.
439    ///
440    /// If you're familiar with Unity, this is the `Mathf.Repeat()` function.
441    ///
442    /// # Panics
443    /// Panics if `upper <= 0`. Reasons include :
444    ///
445    /// - Some types may implement it as `self.wrapped_between(zero, upper)`.
446    ///   A negative `upper` would violate the `lower <= upper` requirement in this case;
447    /// - On unsigned integers, this just resolves to `self % upper`,
448    ///   and integer division by zero is forbidden. Testing for `i==0` incurs unnecessary overhead.
449    /// - Handling negative `upper` values would double the number of test cases
450    ///   and increases implementation complexity;
451    ///
452    /// ```
453    /// use vek::ops::Wrap;
454    ///
455    /// assert_eq!((-5_i32).wrapped(3), 1);
456    /// assert_eq!((-4_i32).wrapped(3), 2);
457    /// assert_eq!((-3_i32).wrapped(3), 0);
458    /// assert_eq!((-2_i32).wrapped(3), 1);
459    /// assert_eq!((-1_i32).wrapped(3), 2);
460    /// assert_eq!(0_i32.wrapped(3), 0);
461    /// assert_eq!(1_i32.wrapped(3), 1);
462    /// assert_eq!(2_i32.wrapped(3), 2);
463    /// assert_eq!(3_i32.wrapped(3), 0);
464    /// assert_eq!(4_i32.wrapped(3), 1);
465    /// assert_eq!(5_i32.wrapped(3), 2);
466    /// ```
467    fn wrapped(self, upper: Bound) -> Self;
468    /// Alias to `wrapped()` which doesn't take `self`.
469    ///
470    /// # Panics
471    /// Panics if `upper <= 0`. See `wrapped()` for a rationale.
472    fn wrap(val: Self, upper: Bound) -> Self {
473        val.wrapped(upper)
474    }
475    /// Returns this value, wrapped between zero and two times 𝛑 (inclusive).
476    ///
477    /// This ought to be named `wrapped_tau`, but I assume people are
478    /// more familiar with 𝛑, and `2pi` is therefore more evocative.
479    fn wrapped_2pi(self) -> Self where Bound: FloatConst + Add<Output=Bound> {
480        self.wrapped(Bound::PI() + Bound::PI())
481    }
482    /// Alias to `wrapped_2pi` which doesn't take `self`.
483    ///
484    /// This ought to be named `wrap_tau`, but I assume people are
485    /// more familiar with 𝛑, and `2pi` is therefore more evocative.
486    fn wrap_2pi(val: Self) -> Self where Bound: FloatConst + Add<Output=Bound> {
487        val.wrapped_2pi()
488    }
489
490    /// Returns this value, wrapped between `lower` (inclusive) and `upper` (exclusive).
491    ///
492    /// # Panics
493    /// Panics if `lower >= upper`. Swap the values yourself if necessary.
494    ///
495    /// Also panics if `lower < 0` or `upper <= 0`. See `wrapped()` for a rationale.
496    /// Forcing `lower` and `upper` to be positive allows implementations to be simpler and faster.
497    ///
498    /// ```
499    /// use vek::ops::Wrap;
500    ///
501    /// assert_eq!((-4_i32).wrapped_between(2, 5), 2);
502    /// assert_eq!((-3_i32).wrapped_between(2, 5), 3);
503    /// assert_eq!((-2_i32).wrapped_between(2, 5), 4);
504    /// assert_eq!((-1_i32).wrapped_between(2, 5), 2);
505    /// assert_eq!(  0_i32 .wrapped_between(2, 5), 3);
506    /// assert_eq!(  1_i32 .wrapped_between(2, 5), 4);
507    /// assert_eq!(  2_i32 .wrapped_between(2, 5), 2);
508    /// assert_eq!(  3_i32 .wrapped_between(2, 5), 3);
509    /// assert_eq!(  4_i32 .wrapped_between(2, 5), 4);
510    /// assert_eq!(  5_i32 .wrapped_between(2, 5), 2);
511    /// assert_eq!(  6_i32 .wrapped_between(2, 5), 3);
512    /// ```
513    fn wrapped_between(self, lower: Bound, upper: Bound) -> Self;
514    /// Alias to `wrapped_between` which doesn't take `self`.
515    ///
516    /// # Panics
517    /// Panics if `lower` is greater than `upper`. Swap the values yourself if necessary.
518    fn wrap_between(val: Self, lower: Bound, upper: Bound) -> Self
519        where Self: Sub<Output=Self> + Add<Output=Self> + From<Bound>,
520              Bound: Copy + Sub<Output=Bound> + PartialOrd
521    {
522        val.wrapped_between(lower, upper)
523    }
524    /// Wraps a value such that it goes back and forth from zero to `upper` (inclusive) as it increases.
525    ///
526    /// # Panics
527    /// Panics if `upper <= 0`. See `wrapped()` for a rationale.
528    ///
529    /// ```
530    /// use vek::ops::Wrap;
531    ///
532    /// assert_eq!((-4_i32).pingpong(3), 2);
533    /// assert_eq!((-3_i32).pingpong(3), 3);
534    /// assert_eq!((-2_i32).pingpong(3), 2);
535    /// assert_eq!((-1_i32).pingpong(3), 1);
536    /// assert_eq!(  0_i32 .pingpong(3), 0);
537    /// assert_eq!(  1_i32 .pingpong(3), 1);
538    /// assert_eq!(  2_i32 .pingpong(3), 2);
539    /// assert_eq!(  3_i32 .pingpong(3), 3);
540    /// assert_eq!(  4_i32 .pingpong(3), 2);
541    /// assert_eq!(  5_i32 .pingpong(3), 1);
542    /// assert_eq!(  6_i32 .pingpong(3), 0);
543    /// assert_eq!(  7_i32 .pingpong(3), 1);
544    /// ```
545    fn pingpong(self, upper: Bound) -> Self;
546
547    /// Calculates the shortest difference between two given angles, in radians.
548    fn delta_angle(self, target: Self) -> Self
549        where Self: From<Bound> + Sub<Output=Self> + PartialOrd,
550            Bound: FloatConst + Add<Output=Bound>
551    {
552        let num = Self::wrap(target - self, Bound::PI() + Bound::PI());
553        if num > Self::from(Bound::PI()) {
554            return num - Self::from(Bound::PI() + Bound::PI());
555        }
556        num
557    }
558    /// Calculates the shortest difference between two given angles, in degrees.
559    ///
560    /// This exists because it's enough for `Bound` to implement `From<u16>`.
561    fn delta_angle_degrees(self, target: Self) -> Self
562        where Self: From<Bound> + Sub<Output=Self> + PartialOrd,
563            Bound: From<u16>
564    {
565        let num = Self::wrap(target - self, Bound::from(360));
566        if num > Self::from(Bound::from(180)) {
567            return num - Self::from(Bound::from(360));
568        }
569        num
570    }
571
572}
573
574macro_rules! wrap_impl_float {
575    ($($T:ty)+) => {
576        $(
577            impl Wrap for $T {
578                fn wrapped(self, upper: Self) -> Self {
579                    assert!(upper > Self::zero());
580                    // assert_relative_ne!(upper, Self::zero());
581                    self - num_traits::Float::floor(self/upper) * upper
582                }
583                fn wrapped_between(self, lower: Self, upper: Self) -> Self {
584                    assert!(lower < upper);
585                    assert!(lower >= Self::zero());
586                    assert!(upper > Self::zero());
587                    let out = self - lower;
588                    let out = out.wrapped(upper - lower);
589                    out + lower
590                }
591                fn pingpong(self, upper: Self) -> Self {
592                    assert!(upper > Self::zero());
593                    // assert_relative_ne!(upper, Self::zero());
594                    let t = self.wrapped(upper + upper);
595                    let upper = || Self::from(upper);
596                    upper() - num_traits::Float::abs(t - upper())
597                }
598            }
599        )+
600    }
601}
602macro_rules! wrap_impl_uint {
603    ($($T:ty)+) => {
604        $(
605            impl Wrap for $T {
606                // https://stackoverflow.com/a/707426
607                fn wrapped_between(mut self, lower: Self, upper: Self) -> Self {
608                    assert!(lower < upper);
609                    assert!(lower >= Self::zero());
610                    assert!(upper > Self::zero());
611                    let range_size = upper - lower /*+ Self::one()*/;
612                    if self < lower {
613                        self += range_size * ((lower-self)/range_size + Self::one());
614                    }
615                    lower + (self - lower) % range_size
616                }
617                fn wrapped(self, upper: Self) -> Self {
618                    assert!(upper > Self::zero());
619                    self % upper
620                }
621                fn pingpong(self, upper: Self) -> Self {
622                    assert!(upper > Self::zero());
623                    let r = self % (upper+upper);
624                    if r < upper {
625                        r
626                    } else {
627                        upper+upper-r
628                    }
629                }
630            }
631        )+
632    }
633}
634macro_rules! wrap_impl_sint {
635    ($($T:ty)+) => {
636        $(
637            impl Wrap for $T {
638                // https://stackoverflow.com/a/707426
639                fn wrapped_between(mut self, lower: Self, upper: Self) -> Self {
640                    assert!(lower < upper);
641                    assert!(lower >= Self::zero());
642                    assert!(upper > Self::zero());
643                    let range_size = upper - lower /*+ Self::one()*/;
644                    if self < lower {
645                        self += range_size * ((lower-self)/range_size + Self::one());
646                    }
647                    lower + (self - lower) % range_size
648                }
649                fn wrapped(self, upper: Self) -> Self {
650                    assert!(upper > Self::zero());
651                    self.wrapped_between(Self::zero(), upper)
652                }
653                fn pingpong(self, upper: Self) -> Self {
654                    assert!(upper > Self::zero());
655                    let r = self.wrapped(upper+upper);
656                    if r <= upper {
657                        r
658                    } else {
659                        upper+upper-r
660                    }
661                }
662            }
663        )+
664    }
665}
666
667wrap_impl_float!{f32 f64}
668wrap_impl_uint!{
669    u8 u16 u32 u64 usize
670    Wrapping<u8>
671    Wrapping<u16>
672    Wrapping<u32>
673    Wrapping<u64>
674    Wrapping<usize>
675}
676wrap_impl_sint!{
677    i8 i16 i32 i64 isize
678    Wrapping<i8>
679    Wrapping<i16>
680    Wrapping<i32>
681    Wrapping<i64>
682    Wrapping<isize>
683}
684
685/// Trait for types that are suitable for representing a color component value.
686pub trait ColorComponent : Zero {
687    /// The minimum value such that the color is at its maximum.
688    ///
689    /// In pratice, it yields `T::MAX` for integers and `1` for real number types.
690    fn full() -> Self;
691}
692
693impl ColorComponent for f32 { fn full() -> Self { 1f32 } }
694impl ColorComponent for f64 { fn full() -> Self { 1f64 } }
695impl ColorComponent for u8  { fn full() -> Self { std::u8  ::MAX } }
696impl ColorComponent for u16 { fn full() -> Self { std::u16 ::MAX } }
697impl ColorComponent for u32 { fn full() -> Self { std::u32 ::MAX } }
698impl ColorComponent for u64 { fn full() -> Self { std::u64 ::MAX } }
699//impl ColorComponent for u128{ fn full() -> Self { ::std::u128::MAX } }
700impl ColorComponent for i8  { fn full() -> Self { std::i8  ::MAX } }
701impl ColorComponent for i16 { fn full() -> Self { std::i16 ::MAX } }
702impl ColorComponent for i32 { fn full() -> Self { std::i32 ::MAX } }
703impl ColorComponent for i64 { fn full() -> Self { std::i64 ::MAX } }
704//impl ColorComponent for i128{ fn full() -> Self { ::std::i128::MAX } }
705impl ColorComponent for Wrapping<u8 >  { fn full() -> Self { Wrapping(ColorComponent::full()) } }
706impl ColorComponent for Wrapping<u16>  { fn full() -> Self { Wrapping(ColorComponent::full()) } }
707impl ColorComponent for Wrapping<u32>  { fn full() -> Self { Wrapping(ColorComponent::full()) } }
708impl ColorComponent for Wrapping<u64>  { fn full() -> Self { Wrapping(ColorComponent::full()) } }
709//impl ColorComponent for Wrapping<u128> { fn full() -> Self { Wrapping(ColorComponent::full()) } }
710impl ColorComponent for Wrapping<i8 >  { fn full() -> Self { Wrapping(ColorComponent::full()) } }
711impl ColorComponent for Wrapping<i16>  { fn full() -> Self { Wrapping(ColorComponent::full()) } }
712impl ColorComponent for Wrapping<i32>  { fn full() -> Self { Wrapping(ColorComponent::full()) } }
713impl ColorComponent for Wrapping<i64>  { fn full() -> Self { Wrapping(ColorComponent::full()) } }
714//impl ColorComponent for Wrapping<i128> { fn full() -> Self { Wrapping(ColorComponent::full()) } }
715
716
717#[cfg(test)]
718mod tests {
719    use super::*;
720
721    macro_rules! for_each_unsigned_type {
722        ($($T:ident)+) => {
723            $(mod $T {
724                use super::Wrap;
725                #[test]
726                fn wrapped() {
727                    assert_eq!((0 as $T).wrapped(3 as $T), 0 as $T);
728                    assert_eq!((1 as $T).wrapped(3 as $T), 1 as $T);
729                    assert_eq!((2 as $T).wrapped(3 as $T), 2 as $T);
730                    assert_eq!((3 as $T).wrapped(3 as $T), 0 as $T);
731                    assert_eq!((4 as $T).wrapped(3 as $T), 1 as $T);
732                    assert_eq!((5 as $T).wrapped(3 as $T), 2 as $T);
733                }
734                #[test]
735                fn wrapped_between() {
736                    assert_eq!((0 as $T).wrapped_between(2 as $T, 5 as $T), 3 as $T);
737                    assert_eq!((1 as $T).wrapped_between(2 as $T, 5 as $T), 4 as $T);
738                    assert_eq!((2 as $T).wrapped_between(2 as $T, 5 as $T), 2 as $T);
739                    assert_eq!((3 as $T).wrapped_between(2 as $T, 5 as $T), 3 as $T);
740                    assert_eq!((4 as $T).wrapped_between(2 as $T, 5 as $T), 4 as $T);
741                    assert_eq!((5 as $T).wrapped_between(2 as $T, 5 as $T), 2 as $T);
742                    assert_eq!((6 as $T).wrapped_between(2 as $T, 5 as $T), 3 as $T);
743                }
744                #[test]
745                fn pingpong() {
746                    assert_eq!((0 as $T).pingpong(3 as $T), 0 as $T);
747                    assert_eq!((1 as $T).pingpong(3 as $T), 1 as $T);
748                    assert_eq!((2 as $T).pingpong(3 as $T), 2 as $T);
749                    assert_eq!((3 as $T).pingpong(3 as $T), 3 as $T);
750                    assert_eq!((4 as $T).pingpong(3 as $T), 2 as $T);
751                    assert_eq!((5 as $T).pingpong(3 as $T), 1 as $T);
752                    assert_eq!((6 as $T).pingpong(3 as $T), 0 as $T);
753                    assert_eq!((7 as $T).pingpong(3 as $T), 1 as $T);
754                }
755            })+
756        };
757    }
758
759    macro_rules! for_each_signed_type {
760        ($($T:ident)+) => {
761            $(mod $T {
762                use super::Wrap;
763                #[test]
764                fn wrapped() {
765                    assert_eq!((-5 as $T).wrapped(3 as $T), 1 as $T);
766                    assert_eq!((-4 as $T).wrapped(3 as $T), 2 as $T);
767                    assert_eq!((-3 as $T).wrapped(3 as $T), 0 as $T);
768                    assert_eq!((-2 as $T).wrapped(3 as $T), 1 as $T);
769                    assert_eq!((-1 as $T).wrapped(3 as $T), 2 as $T);
770                    assert_eq!(( 0 as $T).wrapped(3 as $T), 0 as $T);
771                    assert_eq!(( 1 as $T).wrapped(3 as $T), 1 as $T);
772                    assert_eq!(( 2 as $T).wrapped(3 as $T), 2 as $T);
773                    assert_eq!(( 3 as $T).wrapped(3 as $T), 0 as $T);
774                    assert_eq!(( 4 as $T).wrapped(3 as $T), 1 as $T);
775                    assert_eq!(( 5 as $T).wrapped(3 as $T), 2 as $T);
776                }
777                #[test]
778                fn wrapped_between() {
779                    assert_eq!((-4 as $T).wrapped_between(2 as $T, 5 as $T), 2 as $T);
780                    assert_eq!((-3 as $T).wrapped_between(2 as $T, 5 as $T), 3 as $T);
781                    assert_eq!((-2 as $T).wrapped_between(2 as $T, 5 as $T), 4 as $T);
782                    assert_eq!((-1 as $T).wrapped_between(2 as $T, 5 as $T), 2 as $T);
783                    assert_eq!(( 0 as $T).wrapped_between(2 as $T, 5 as $T), 3 as $T);
784                    assert_eq!(( 1 as $T).wrapped_between(2 as $T, 5 as $T), 4 as $T);
785                    assert_eq!(( 2 as $T).wrapped_between(2 as $T, 5 as $T), 2 as $T);
786                    assert_eq!(( 3 as $T).wrapped_between(2 as $T, 5 as $T), 3 as $T);
787                    assert_eq!(( 4 as $T).wrapped_between(2 as $T, 5 as $T), 4 as $T);
788                    assert_eq!(( 5 as $T).wrapped_between(2 as $T, 5 as $T), 2 as $T);
789                    assert_eq!(( 6 as $T).wrapped_between(2 as $T, 5 as $T), 3 as $T);
790                }
791                #[test]
792                fn pingpong() {
793                    assert_eq!((-4 as $T).pingpong(3 as $T), 2 as $T);
794                    assert_eq!((-3 as $T).pingpong(3 as $T), 3 as $T);
795                    assert_eq!((-2 as $T).pingpong(3 as $T), 2 as $T);
796                    assert_eq!((-1 as $T).pingpong(3 as $T), 1 as $T);
797                    assert_eq!(( 0 as $T).pingpong(3 as $T), 0 as $T);
798                    assert_eq!(( 1 as $T).pingpong(3 as $T), 1 as $T);
799                    assert_eq!(( 2 as $T).pingpong(3 as $T), 2 as $T);
800                    assert_eq!(( 3 as $T).pingpong(3 as $T), 3 as $T);
801                    assert_eq!(( 4 as $T).pingpong(3 as $T), 2 as $T);
802                    assert_eq!(( 5 as $T).pingpong(3 as $T), 1 as $T);
803                    assert_eq!(( 6 as $T).pingpong(3 as $T), 0 as $T);
804                    assert_eq!(( 7 as $T).pingpong(3 as $T), 1 as $T);
805                }
806            })+
807        };
808    }
809
810    macro_rules! for_each_float_type {
811        ($($T:ident)+) => {
812            $(mod $T {
813                use super::Wrap;
814                #[test]
815                fn wrapped() {
816                    assert_relative_eq!((-5 as $T).wrapped(3 as $T), 1 as $T);
817                    assert_relative_eq!((-4 as $T).wrapped(3 as $T), 2 as $T);
818                    assert_relative_eq!((-3 as $T).wrapped(3 as $T), 0 as $T);
819                    assert_relative_eq!((-2 as $T).wrapped(3 as $T), 1 as $T);
820                    assert_relative_eq!((-1 as $T).wrapped(3 as $T), 2 as $T);
821                    assert_relative_eq!(( 0 as $T).wrapped(3 as $T), 0 as $T);
822                    assert_relative_eq!(( 1 as $T).wrapped(3 as $T), 1 as $T);
823                    assert_relative_eq!(( 2 as $T).wrapped(3 as $T), 2 as $T);
824                    assert_relative_eq!(( 3 as $T).wrapped(3 as $T), 0 as $T);
825                    assert_relative_eq!(( 4 as $T).wrapped(3 as $T), 1 as $T);
826                    assert_relative_eq!(( 5 as $T).wrapped(3 as $T), 2 as $T);
827                }
828                #[test]
829                fn wrapped_between() {
830                    assert_relative_eq!((-4 as $T).wrapped_between(2 as $T, 5 as $T), 2 as $T);
831                    assert_relative_eq!((-3 as $T).wrapped_between(2 as $T, 5 as $T), 3 as $T);
832                    assert_relative_eq!((-2 as $T).wrapped_between(2 as $T, 5 as $T), 4 as $T);
833                    assert_relative_eq!((-1 as $T).wrapped_between(2 as $T, 5 as $T), 2 as $T);
834                    assert_relative_eq!(( 0 as $T).wrapped_between(2 as $T, 5 as $T), 3 as $T);
835                    assert_relative_eq!(( 1 as $T).wrapped_between(2 as $T, 5 as $T), 4 as $T);
836                    assert_relative_eq!(( 2 as $T).wrapped_between(2 as $T, 5 as $T), 2 as $T);
837                    assert_relative_eq!(( 3 as $T).wrapped_between(2 as $T, 5 as $T), 3 as $T);
838                    assert_relative_eq!(( 4 as $T).wrapped_between(2 as $T, 5 as $T), 4 as $T);
839                    assert_relative_eq!(( 5 as $T).wrapped_between(2 as $T, 5 as $T), 2 as $T);
840                    assert_relative_eq!(( 6 as $T).wrapped_between(2 as $T, 5 as $T), 3 as $T);
841                }
842                #[test]
843                fn pingpong() {
844                    assert_relative_eq!((-4 as $T).pingpong(3 as $T), 2 as $T);
845                    assert_relative_eq!((-3 as $T).pingpong(3 as $T), 3 as $T);
846                    assert_relative_eq!((-2 as $T).pingpong(3 as $T), 2 as $T);
847                    assert_relative_eq!((-1 as $T).pingpong(3 as $T), 1 as $T);
848                    assert_relative_eq!(( 0 as $T).pingpong(3 as $T), 0 as $T);
849                    assert_relative_eq!(( 1 as $T).pingpong(3 as $T), 1 as $T);
850                    assert_relative_eq!(( 2 as $T).pingpong(3 as $T), 2 as $T);
851                    assert_relative_eq!(( 3 as $T).pingpong(3 as $T), 3 as $T);
852                    assert_relative_eq!(( 4 as $T).pingpong(3 as $T), 2 as $T);
853                    assert_relative_eq!(( 5 as $T).pingpong(3 as $T), 1 as $T);
854                    assert_relative_eq!(( 6 as $T).pingpong(3 as $T), 0 as $T);
855                    assert_relative_eq!(( 7 as $T).pingpong(3 as $T), 1 as $T);
856                }
857            })+
858        };
859    }
860
861    for_each_float_type!{f32 f64}
862    for_each_signed_type!{i8 i16 i32 i64 isize}
863    for_each_unsigned_type!{u8 u16 u32 u64 usize}
864}