palette/
hues.rs

1//! Hues and hue related types.
2
3#[cfg(any(feature = "approx", feature = "random"))]
4use core::ops::Mul;
5
6use core::ops::{Add, AddAssign, Neg, Sub, SubAssign};
7
8#[cfg(feature = "approx")]
9use approx::{AbsDiffEq, RelativeEq, UlpsEq};
10
11#[cfg(feature = "random")]
12use rand::{
13    distributions::{
14        uniform::{SampleBorrow, SampleUniform, Uniform, UniformSampler},
15        Distribution, Standard,
16    },
17    Rng,
18};
19
20#[cfg(feature = "approx")]
21use crate::{angle::HalfRotation, num::Zero};
22
23#[cfg(feature = "random")]
24use crate::angle::FullRotation;
25
26use crate::{
27    angle::{AngleEq, FromAngle, RealAngle, SignedAngle, UnsignedAngle},
28    num::Trigonometry,
29};
30
31macro_rules! make_hues {
32    ($($(#[$doc:meta])+ struct $name:ident; $iter_name:ident)+) => ($(
33        $(#[$doc])+
34        ///
35        /// The hue is a circular type, where `0` and `360` is the same, and
36        /// it's normalized to `(-180, 180]` when it's converted to a linear
37        /// number (like `f32`). This makes many calculations easier, but may
38        /// also have some surprising effects if it's expected to act as a
39        /// linear number.
40        #[derive(Clone, Copy, Debug, Default)]
41        #[cfg_attr(feature = "serializing", derive(Serialize, Deserialize))]
42        #[repr(C)]
43        pub struct $name<T = f32>(T);
44
45        impl<T> $name<T> {
46            /// Create a new hue, specified in the default unit for the angle
47            /// type `T`.
48            ///
49            /// `f32`, `f64` and other real number types represent degrees,
50            /// while `u8` simply represents the range `[0, 360]` as `[0, 256]`.
51            #[inline]
52            pub const fn new(angle: T) -> Self {
53                Self(angle)
54            }
55
56            /// Get the internal representation without normalizing or converting it.
57            ///
58            /// `f32`, `f64` and other real number types represent degrees,
59            /// while `u8` simply represents the range `[0, 360]` as `[0, 256]`.
60            pub fn into_inner(self) -> T {
61                self.0
62            }
63
64            /// Convert into another angle type.
65            pub fn into_format<U>(self) -> $name<U>
66            where
67                U: FromAngle<T>,
68            {
69                $name(U::from_angle(self.0))
70            }
71
72            /// Convert from another angle type.
73            pub fn from_format<U>(hue: $name<U>) -> Self
74            where
75                T: FromAngle<U>,
76            {
77                hue.into_format()
78            }
79        }
80
81        impl<T: RealAngle> $name<T> {
82            /// Create a new hue from degrees. This is an alias for `new`.
83            #[inline]
84            pub fn from_degrees(degrees: T) -> Self {
85                Self::new(degrees)
86            }
87
88            /// Create a new hue from radians, instead of degrees.
89            #[inline]
90            pub fn from_radians(radians: T) -> Self {
91                Self(T::radians_to_degrees(radians))
92            }
93
94            /// Get the internal representation as degrees, without normalizing it.
95            #[inline]
96            pub fn into_raw_degrees(self) -> T {
97                self.0
98            }
99
100            /// Get the internal representation as radians, without normalizing it.
101            #[inline]
102            pub fn into_raw_radians(self) -> T {
103                T::degrees_to_radians(self.0)
104            }
105        }
106
107        impl<T: RealAngle + SignedAngle> $name<T> {
108            /// Get the hue as degrees, in the range `(-180, 180]`.
109            #[inline]
110            pub fn into_degrees(self) -> T {
111                self.0.normalize_signed_angle()
112            }
113
114            /// Convert the hue to radians, in the range `(-π, π]`.
115            #[inline]
116            pub fn into_radians(self) -> T {
117                T::degrees_to_radians(self.0.normalize_signed_angle())
118            }
119        }
120
121        impl<T: RealAngle + UnsignedAngle> $name<T> {
122            /// Convert the hue to positive degrees, in the range `[0, 360)`.
123            #[inline]
124            pub fn into_positive_degrees(self) -> T {
125                self.0.normalize_unsigned_angle()
126            }
127
128            /// Convert the hue to positive radians, in the range `[0, 2Ï€)`.
129            #[inline]
130            pub fn into_positive_radians(self) -> T {
131                T::degrees_to_radians(self.0.normalize_unsigned_angle())
132            }
133        }
134
135        impl<T: RealAngle + Trigonometry> $name<T> {
136            /// Returns a hue from `a` and `b`, normalized to `[0°, 360°)`.
137            ///
138            /// If `a` and `b` are both `0`, returns `0`,
139            #[inline(always)]
140            pub fn from_cartesian(a: T, b: T) -> Self where T: Add<T, Output = T> + Neg<Output = T> {
141                // atan2 returns values in the interval [-π, π]
142                // instead of
143                //   let hue_rad = T::atan2(b,a);
144                // use negative a and be and rotate, to ensure the hue is normalized,
145                let hue_rad = T::from_f64(core::f64::consts::PI) + T::atan2(-b, -a);
146                Self::from_radians(hue_rad)
147            }
148
149            /// Returns `a` and `b` values for this hue, normalized to `[-1,
150            /// 1]`.
151            ///
152            /// They will have to be multiplied by a radius values, such as
153            /// saturation, value, chroma, etc., to represent a specific color.
154            #[inline(always)]
155            pub fn into_cartesian(self) -> (T, T) {
156                let (b, a) = self.into_raw_radians().sin_cos();
157                (a, b) // Note the swapped order compared to above
158            }
159        }
160
161        impl<T> $name<&T> {
162            /// Get an owned, copied version of this hue.
163            #[inline(always)]
164            pub fn copied(&self) -> $name<T>
165            where
166                T: Copy,
167            {
168                $name(*self.0)
169            }
170
171            /// Get an owned, cloned version of this hue.
172            #[inline(always)]
173            pub fn cloned(&self) -> $name<T>
174            where
175                T: Clone,
176            {
177                $name(self.0.clone())
178            }
179        }
180
181        impl<T> $name<&mut T> {
182            /// Update this hue with a new value.
183            #[inline(always)]
184            pub fn set(&mut self, value: $name<T>) {
185                *self.0 = value.0;
186            }
187
188            /// Borrow this hue's value as shared references.
189            #[inline(always)]
190            pub fn as_ref(&self) -> $name<&T> {
191                $name(&*self.0)
192            }
193
194            /// Get an owned, copied version of this hue.
195            #[inline(always)]
196            pub fn copied(&self) -> $name<T>
197            where
198                T: Copy,
199            {
200                $name(*self.0)
201            }
202
203            /// Get an owned, cloned version of this hue.
204            #[inline(always)]
205            pub fn cloned(&self) -> $name<T>
206            where
207                T: Clone,
208            {
209                $name(self.0.clone())
210            }
211        }
212
213        impl<C> $name<C> {
214            /// Return an iterator over the hues in the wrapped collection.
215            #[inline(always)]
216            pub fn iter<'a>(&'a self) -> <&'a Self as IntoIterator>::IntoIter where &'a Self: IntoIterator {
217                self.into_iter()
218            }
219
220            /// Return an iterator that allows modifying the hues in the wrapped collection.
221            #[inline(always)]
222            pub fn iter_mut<'a>(&'a mut self) -> <&'a mut Self as IntoIterator>::IntoIter where &'a mut Self: IntoIterator {
223                self.into_iter()
224            }
225
226            /// Get a hue, or slice of hues, with references to the values at `index`. See [`slice::get`] for details.
227            #[inline(always)]
228            pub fn get<'a, I, T>(&'a self, index: I) -> Option<$name<&<I as core::slice::SliceIndex<[T]>>::Output>>
229            where
230                T: 'a,
231                C: AsRef<[T]>,
232                I: core::slice::SliceIndex<[T]> + Clone,
233            {
234                self.0.as_ref().get(index).map($name)
235            }
236
237            /// Get a hue, or slice of hues, that allows modifying the values at `index`. See [`slice::get_mut`] for details.
238            #[inline(always)]
239            pub fn get_mut<'a, I, T>(&'a mut self, index: I) -> Option<$name<&mut <I as core::slice::SliceIndex<[T]>>::Output>>
240            where
241                T: 'a,
242                C: AsMut<[T]>,
243                I: core::slice::SliceIndex<[T]> + Clone,
244            {
245                self.0.as_mut().get_mut(index).map($name)
246            }
247        }
248
249        #[cfg(feature = "alloc")]
250        impl<T> $name<alloc::vec::Vec<T>> {
251            /// Create a struct with a vector with a minimum capacity. See [`Vec::with_capacity`] for details.
252            pub fn with_capacity(capacity: usize) -> Self {
253                Self(alloc::vec::Vec::with_capacity(capacity))
254            }
255
256            /// Push an additional hue onto the hue vector. See [`Vec::push`] for details.
257            pub fn push(&mut self, value: $name<T>) {
258                self.0.push(value.0);
259            }
260
261            /// Pop a hue from the hue vector. See [`Vec::pop`] for details.
262            pub fn pop(&mut self) -> Option<$name<T>> {
263                self.0.pop().map($name)
264            }
265
266            /// Clear the hue vector. See [`Vec::clear`] for details.
267            pub fn clear(&mut self) {
268                self.0.clear();
269            }
270
271            /// Return an iterator that moves hues out of the specified range.
272            pub fn drain<R>(&mut self, range: R) -> $iter_name<alloc::vec::Drain<T>>
273            where
274                R: core::ops::RangeBounds<usize> + Clone,
275            {
276                $iter_name(self.0.drain(range))
277            }
278        }
279
280        impl<T> From<T> for $name<T> {
281            #[inline]
282            fn from(degrees: T) -> $name<T> {
283                $name(degrees)
284            }
285        }
286
287        impl From<$name<f64>> for f64 {
288            #[inline]
289            fn from(hue: $name<f64>) -> f64 {
290                hue.0.normalize_signed_angle()
291            }
292        }
293
294        impl From<$name<f32>> for f64 {
295            #[inline]
296            fn from(hue: $name<f32>) -> f64 {
297                hue.0.normalize_signed_angle() as f64
298            }
299        }
300
301        impl From<$name<f32>> for f32 {
302            #[inline]
303            fn from(hue: $name<f32>) -> f32 {
304                hue.0.normalize_signed_angle()
305            }
306        }
307
308        impl From<$name<f64>> for f32 {
309            #[inline]
310            fn from(hue: $name<f64>) -> f32 {
311                hue.0.normalize_signed_angle() as f32
312            }
313        }
314
315        impl From<$name<u8>> for u8 {
316            #[inline]
317            fn from(hue: $name<u8>) -> u8 {
318                hue.0
319            }
320        }
321
322        impl<T> PartialEq for $name<T> where T: AngleEq<Mask = bool> + PartialEq {
323            #[inline]
324            fn eq(&self, other: &$name<T>) -> bool {
325                self.0.angle_eq(&other.0)
326            }
327        }
328
329        impl<T> PartialEq<T> for $name<T> where T: AngleEq<Mask = bool> + PartialEq {
330            #[inline]
331            fn eq(&self, other: &T) -> bool {
332                self.0.angle_eq(other)
333            }
334        }
335
336        impl<T> Eq for $name<T> where T: AngleEq<Mask = bool> + Eq {}
337
338
339        #[cfg(feature = "approx")]
340        impl<T> AbsDiffEq for $name<T>
341        where
342            T: RealAngle + SignedAngle + Zero + AngleEq<Mask = bool> + Sub<Output = T> + AbsDiffEq + Clone,
343            T::Epsilon: HalfRotation + Mul<Output = T::Epsilon>,
344        {
345            type Epsilon = T::Epsilon;
346
347            fn default_epsilon() -> Self::Epsilon {
348                // For hues, angles in (normalized) degrees are compared.
349                // Scaling from radians to degrees raises the order of magnitude of the
350                // error by 180/PI.
351                // Scale the default epsilon accordingly for absolute comparisons.
352                // Scaling is not required for relative comparisons (including ulps), as
353                // there the error is scaled to unit size anyway
354                T::default_epsilon() * T::Epsilon::half_rotation()
355            }
356
357            fn abs_diff_eq(&self, other: &Self, epsilon: T::Epsilon) -> bool {
358                T::abs_diff_eq(&self.clone().into_degrees(), &other.clone().into_degrees(), epsilon)
359            }
360            fn abs_diff_ne(&self, other: &Self, epsilon: T::Epsilon) -> bool {
361                T::abs_diff_ne(&self.clone().into_degrees(), &other.clone().into_degrees(), epsilon)
362            }
363        }
364
365        #[cfg(feature = "approx")]
366        impl<T> RelativeEq for $name<T>
367        where
368            T: RealAngle + SignedAngle + Zero + AngleEq<Mask = bool> + Sub<Output = T> + Clone + RelativeEq,
369            T::Epsilon: HalfRotation + Mul<Output = T::Epsilon>,
370        {
371            fn default_max_relative() -> Self::Epsilon {
372                T::default_max_relative()
373            }
374
375            fn relative_eq(
376                &self,
377                other: &Self,
378                epsilon: T::Epsilon,
379                max_relative: T::Epsilon,
380            ) -> bool {
381                T::relative_eq(&self.clone().into_degrees(), &other.clone().into_degrees(), epsilon, max_relative)
382            }
383            fn relative_ne(
384                &self,
385                other: &Self,
386                epsilon: Self::Epsilon,
387                max_relative: Self::Epsilon,
388            ) -> bool {
389                T::relative_ne(&self.clone().into_degrees(), &other.clone().into_degrees(), epsilon, max_relative)
390            }
391        }
392
393        #[cfg(feature = "approx")]
394        impl<T> UlpsEq for $name<T>
395        where
396            T: RealAngle + SignedAngle + Zero + AngleEq<Mask = bool> + Sub<Output = T> + Clone + UlpsEq,
397            T::Epsilon: HalfRotation + Mul<Output = T::Epsilon>,
398        {
399            fn default_max_ulps() -> u32 {
400                T::default_max_ulps()
401            }
402
403            fn ulps_eq(&self, other: &Self, epsilon: T::Epsilon, max_ulps: u32) -> bool {
404                T::ulps_eq(&self.clone().into_degrees(), &other.clone().into_degrees(), epsilon, max_ulps)
405            }
406            fn ulps_ne(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
407                T::ulps_ne(&self.clone().into_degrees(), &other.clone().into_degrees(), epsilon, max_ulps)
408            }
409        }
410
411        impl<T: Add<Output=T>> Add<$name<T>> for $name<T> {
412            type Output = $name<T>;
413
414            #[inline]
415            fn add(self, other: $name<T>) -> $name<T> {
416                $name(self.0 + other.0)
417            }
418        }
419
420        impl<T: Add<Output=T>> Add<T> for $name<T> {
421            type Output = $name<T>;
422
423            #[inline]
424            fn add(self, other: T) -> $name<T> {
425                $name(self.0 + other)
426            }
427        }
428
429        impl Add<$name<f32>> for f32 {
430            type Output = $name<f32>;
431
432            #[inline]
433            fn add(self, other: $name<f32>) -> $name<f32> {
434                $name(self + other.0)
435            }
436        }
437
438        impl Add<$name<f64>> for f64 {
439            type Output = $name<f64>;
440
441            #[inline]
442            fn add(self, other: $name<f64>) -> $name<f64> {
443                $name(self + other.0)
444            }
445        }
446
447        impl<T: AddAssign> AddAssign<$name<T>> for $name<T> {
448            #[inline]
449            fn add_assign(&mut self, other: $name<T>) {
450                self.0 += other.0;
451            }
452        }
453
454        impl<T: AddAssign> AddAssign<T> for $name<T> {
455            #[inline]
456            fn add_assign(&mut self, other: T) {
457                self.0 += other;
458            }
459        }
460
461        impl AddAssign<$name<f32>> for f32 {
462            #[inline]
463            fn add_assign(&mut self, other: $name<f32>) {
464                *self += other.0;
465            }
466        }
467
468        impl AddAssign<$name<f64>> for f64 {
469            #[inline]
470            fn add_assign(&mut self, other: $name<f64>){
471                *self += other.0;
472            }
473        }
474
475        impl<T: $crate::num::SaturatingAdd<Output=T>> $crate::num::SaturatingAdd<$name<T>> for $name<T> {
476            type Output = $name<T>;
477
478            #[inline]
479            fn saturating_add(self, other: $name<T>) -> $name<T> {
480                $name(self.0.saturating_add(other.0))
481            }
482        }
483
484        impl<T: $crate::num::SaturatingAdd<Output=T>> $crate::num::SaturatingAdd<T> for $name<T> {
485            type Output = $name<T>;
486
487            #[inline]
488            fn saturating_add(self, other: T) -> $name<T> {
489                $name(self.0.saturating_add(other))
490            }
491        }
492
493        impl<T: Sub<Output=T>> Sub<$name<T>> for $name<T> {
494            type Output = $name<T>;
495
496            #[inline]
497            fn sub(self, other: $name<T>) -> $name<T> {
498                $name(self.0 - other.0)
499            }
500        }
501
502        impl<T: Sub<Output=T>> Sub<T> for $name<T> {
503            type Output = $name<T>;
504
505            #[inline]
506            fn sub(self, other: T) -> $name<T> {
507                $name(self.0 - other)
508            }
509        }
510
511        impl Sub<$name<f32>> for f32 {
512            type Output = $name<f32>;
513
514            #[inline]
515            fn sub(self, other: $name<f32>) -> $name<f32> {
516                $name(self - other.0)
517            }
518        }
519
520        impl Sub<$name<f64>> for f64 {
521            type Output = $name<f64>;
522
523            #[inline]
524            fn sub(self, other: $name<f64>) -> $name<f64> {
525                $name(self - other.0)
526            }
527        }
528
529        impl<T: SubAssign> SubAssign<$name<T>> for $name<T> {
530            #[inline]
531            fn sub_assign(&mut self, other: $name<T>) {
532                self.0 -= other.0;
533            }
534        }
535
536        impl<T: SubAssign> SubAssign<T> for $name<T> {
537            #[inline]
538            fn sub_assign(&mut self, other: T) {
539                self.0 -= other;
540            }
541        }
542
543        impl SubAssign<$name<f32>> for f32 {
544            #[inline]
545            fn sub_assign(&mut self, other: $name<f32>) {
546                *self -= other.0;
547            }
548        }
549
550        impl SubAssign<$name<f64>> for f64 {
551            #[inline]
552            fn sub_assign(&mut self, other: $name<f64>){
553                *self -= other.0;
554            }
555        }
556
557        impl<T: $crate::num::SaturatingSub<Output=T>> $crate::num::SaturatingSub<$name<T>> for $name<T> {
558            type Output = $name<T>;
559
560            #[inline]
561            fn saturating_sub(self, other: $name<T>) -> $name<T> {
562                $name(self.0.saturating_sub(other.0))
563            }
564        }
565
566        impl<T: $crate::num::SaturatingSub<Output=T>> $crate::num::SaturatingSub<T> for $name<T> {
567            type Output = $name<T>;
568
569            #[inline]
570            fn saturating_sub(self, other: T) -> $name<T> {
571                $name(self.0.saturating_sub(other))
572            }
573        }
574
575        impl<C, T> Extend<T> for $name<C> where C: Extend<T> {
576            #[inline(always)]
577            fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
578                self.0.extend(iter);
579            }
580        }
581
582        impl<T, const N: usize> IntoIterator for $name<[T; N]> {
583            type Item = $name<T>;
584            type IntoIter = $iter_name<core::array::IntoIter<T, N>>;
585
586            #[inline(always)]
587            fn into_iter(self) -> Self::IntoIter {
588                $iter_name(IntoIterator::into_iter(self.0))
589            }
590        }
591
592        impl<'a, T> IntoIterator for $name<&'a [T]> {
593            type Item = $name<&'a T>;
594            type IntoIter = $iter_name<core::slice::Iter<'a, T>>;
595
596            #[inline(always)]
597            fn into_iter(self) -> Self::IntoIter {
598                $iter_name(self.0.into_iter())
599            }
600        }
601
602        impl<'a, T> IntoIterator for $name<&'a mut [T]> {
603            type Item = $name<&'a mut T>;
604            type IntoIter = $iter_name<core::slice::IterMut<'a, T>>;
605
606            #[inline(always)]
607            fn into_iter(self) -> Self::IntoIter {
608                $iter_name(self.0.into_iter())
609            }
610        }
611
612        #[cfg(feature = "alloc")]
613        impl<T> IntoIterator for $name<alloc::vec::Vec<T>> {
614            type Item = $name<T>;
615            type IntoIter = $iter_name<alloc::vec::IntoIter<T>>;
616
617            #[inline(always)]
618            fn into_iter(self) -> Self::IntoIter {
619                $iter_name(self.0.into_iter())
620            }
621        }
622
623        impl<'a, T, const N: usize> IntoIterator for &'a $name<[T; N]> {
624            type Item = $name<&'a T>;
625            type IntoIter = $iter_name<core::slice::Iter<'a, T>>;
626
627            #[inline(always)]
628            fn into_iter(self) -> Self::IntoIter {
629                $iter_name((&self.0).into_iter())
630            }
631        }
632
633        impl<'a, 'b, T> IntoIterator for &'a $name<&'b [T]> {
634            type Item = $name<&'a T>;
635            type IntoIter = $iter_name<core::slice::Iter<'a, T>>;
636
637            #[inline(always)]
638            fn into_iter(self) -> Self::IntoIter {
639                $iter_name(self.0.into_iter())
640            }
641        }
642
643        impl<'a, 'b, T> IntoIterator for &'a $name<&'b mut [T]> {
644            type Item = $name<&'a T>;
645            type IntoIter = $iter_name<core::slice::Iter<'a, T>>;
646
647            #[inline(always)]
648            fn into_iter(self) -> Self::IntoIter {
649                $iter_name((&*self.0).into_iter())
650            }
651        }
652
653        #[cfg(feature = "alloc")]
654        impl<'a, T> IntoIterator for &'a $name<alloc::vec::Vec<T>> {
655            type Item = $name<&'a T>;
656            type IntoIter = $iter_name<core::slice::Iter<'a, T>>;
657
658            #[inline(always)]
659            fn into_iter(self) -> Self::IntoIter {
660                $iter_name((&self.0).into_iter())
661            }
662        }
663
664        #[cfg(feature = "alloc")]
665        impl<'a, T> IntoIterator for &'a $name<alloc::boxed::Box<[T]>> {
666            type Item = $name<&'a T>;
667            type IntoIter = $iter_name<core::slice::Iter<'a, T>>;
668
669            #[inline(always)]
670            fn into_iter(self) -> Self::IntoIter {
671                $iter_name((&self.0).into_iter())
672            }
673        }
674
675        impl<'a, T, const N: usize> IntoIterator for &'a mut $name<[T; N]> {
676            type Item = $name<&'a mut T>;
677            type IntoIter = $iter_name<core::slice::IterMut<'a, T>>;
678
679            #[inline(always)]
680            fn into_iter(self) -> Self::IntoIter {
681                $iter_name((&mut self.0).into_iter())
682            }
683        }
684
685        impl<'a, 'b, T> IntoIterator for &'a mut $name<&'b mut [T]> {
686            type Item = $name<&'a mut T>;
687            type IntoIter = $iter_name<core::slice::IterMut<'a, T>>;
688
689            #[inline(always)]
690            fn into_iter(self) -> Self::IntoIter {
691                $iter_name(self.0.into_iter())
692            }
693        }
694
695        #[cfg(feature = "alloc")]
696        impl<'a, T> IntoIterator for &'a mut $name<alloc::vec::Vec<T>> {
697            type Item = $name<&'a mut T>;
698            type IntoIter = $iter_name<core::slice::IterMut<'a, T>>;
699
700            #[inline(always)]
701            fn into_iter(self) -> Self::IntoIter {
702                $iter_name((&mut self.0).into_iter())
703            }
704        }
705
706        #[cfg(feature = "alloc")]
707        impl<'a, T> IntoIterator for &'a mut $name<alloc::boxed::Box<[T]>> {
708            type Item = $name<&'a mut T>;
709            type IntoIter = $iter_name<core::slice::IterMut<'a, T>>;
710
711            #[inline(always)]
712            fn into_iter(self) -> Self::IntoIter {
713                $iter_name((&mut *self.0).into_iter())
714            }
715        }
716
717        #[doc = concat!("Iterator over [`", stringify!($name), "`] values.")]
718        pub struct $iter_name<I>(I);
719
720        impl<I> Iterator for $iter_name<I>
721        where
722            I: Iterator,
723        {
724            type Item = $name<I::Item>;
725
726            #[inline(always)]
727            fn next(&mut self) -> Option<Self::Item> {
728                self.0.next().map($name)
729            }
730
731            #[inline(always)]
732            fn size_hint(&self) -> (usize, Option<usize>) {
733                self.0.size_hint()
734            }
735
736            #[inline(always)]
737            fn count(self) -> usize {
738                self.0.count()
739            }
740        }
741
742        impl<I> DoubleEndedIterator for $iter_name<I>
743        where
744            I: DoubleEndedIterator,
745        {
746            #[inline(always)]
747            fn next_back(&mut self) -> Option<Self::Item> {
748                self.0.next_back().map($name)
749            }
750        }
751
752        impl<I> ExactSizeIterator for $iter_name<I>
753        where
754            I: ExactSizeIterator,
755        {
756            #[inline(always)]
757            fn len(&self) -> usize {
758                self.0.len()
759            }
760        }
761
762        #[cfg(feature = "random")]
763        impl<T> Distribution<$name<T>> for Standard
764        where
765            T: RealAngle + FullRotation + Mul<Output = T>,
766            Standard: Distribution<T>,
767        {
768            #[inline(always)]
769            fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $name<T> {
770                $name::from_degrees(rng.gen() * T::full_rotation())
771            }
772        }
773
774        #[cfg(feature = "bytemuck")]
775        unsafe impl<T: bytemuck::Zeroable> bytemuck::Zeroable for $name<T> {}
776        #[cfg(feature = "bytemuck")]
777        unsafe impl<T: bytemuck::Pod> bytemuck::Pod for $name<T> {}
778    )+)
779}
780
781make_hues! {
782    /// A hue type for the CIE L\*a\*b\* family of color spaces.
783    ///
784    /// It's measured in degrees and it's based on the four physiological
785    /// elementary colors _red_, _yellow_, _green_ and _blue_. This makes it
786    /// different from the hue of RGB based color spaces.
787    struct LabHue; LabHueIter
788
789    /// A hue type for the CIE L\*u\*v\* family of color spaces.
790    struct LuvHue; LuvHueIter
791
792    /// A hue type for the RGB family of color spaces.
793    ///
794    /// It's measured in degrees and uses the three additive primaries _red_,
795    /// _green_ and _blue_.
796    struct RgbHue; RgbHueIter
797
798    /// A hue type for the Oklab color space.
799    ///
800    /// It's measured in degrees.
801    struct OklabHue; OklabHueIter
802
803    /// A hue type for the CAM16 color appearance model.
804    ///
805    /// It's measured in degrees.
806    struct Cam16Hue; Cam16HueIter
807}
808
809macro_rules! impl_uniform {
810    (  $uni_ty: ident , $base_ty: ident) => {
811        #[doc = concat!("Sample [`", stringify!($base_ty), "`] uniformly.")]
812        #[cfg(feature = "random")]
813        pub struct $uni_ty<T>
814        where
815            T: SampleUniform,
816        {
817            hue: Uniform<T>,
818        }
819
820        #[cfg(feature = "random")]
821        impl<T> SampleUniform for $base_ty<T>
822        where
823            T: RealAngle
824                + UnsignedAngle
825                + FullRotation
826                + Add<Output = T>
827                + Mul<Output = T>
828                + PartialOrd
829                + Clone
830                + SampleUniform,
831        {
832            type Sampler = $uni_ty<T>;
833        }
834
835        #[cfg(feature = "random")]
836        impl<T> UniformSampler for $uni_ty<T>
837        where
838            T: RealAngle
839                + UnsignedAngle
840                + FullRotation
841                + Add<Output = T>
842                + Mul<Output = T>
843                + PartialOrd
844                + Clone
845                + SampleUniform,
846        {
847            type X = $base_ty<T>;
848
849            fn new<B1, B2>(low_b: B1, high_b: B2) -> Self
850            where
851                B1: SampleBorrow<Self::X> + Sized,
852                B2: SampleBorrow<Self::X> + Sized,
853            {
854                let low = low_b.borrow().clone();
855                let normalized_low = $base_ty::into_positive_degrees(low.clone());
856                let high = high_b.borrow().clone();
857                let normalized_high = $base_ty::into_positive_degrees(high.clone());
858
859                let normalized_high = if normalized_low >= normalized_high && low.0 < high.0 {
860                    normalized_high + T::full_rotation()
861                } else {
862                    normalized_high
863                };
864
865                $uni_ty {
866                    hue: Uniform::new(normalized_low, normalized_high),
867                }
868            }
869
870            fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Self
871            where
872                B1: SampleBorrow<Self::X> + Sized,
873                B2: SampleBorrow<Self::X> + Sized,
874            {
875                let low = low_b.borrow().clone();
876                let normalized_low = $base_ty::into_positive_degrees(low.clone());
877                let high = high_b.borrow().clone();
878                let normalized_high = $base_ty::into_positive_degrees(high.clone());
879
880                let normalized_high = if normalized_low >= normalized_high && low.0 < high.0 {
881                    normalized_high + T::full_rotation()
882                } else {
883                    normalized_high
884                };
885
886                $uni_ty {
887                    hue: Uniform::new_inclusive(normalized_low, normalized_high),
888                }
889            }
890
891            fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $base_ty<T> {
892                $base_ty::from(self.hue.sample(rng) * T::full_rotation())
893            }
894        }
895    };
896}
897
898impl_uniform!(UniformLabHue, LabHue);
899impl_uniform!(UniformRgbHue, RgbHue);
900impl_uniform!(UniformLuvHue, LuvHue);
901impl_uniform!(UniformOklabHue, OklabHue);
902impl_uniform!(UniformCam16Hue, Cam16Hue);
903
904#[cfg(test)]
905mod test {
906    #[cfg(feature = "approx")]
907    mod math {
908        use crate::{
909            angle::{SignedAngle, UnsignedAngle},
910            OklabHue, RgbHue,
911        };
912
913        #[test]
914        fn oklabhue_ab_roundtrip() {
915            for degree in [0.0_f64, 90.0, 30.0, 330.0, 120.0, 240.0] {
916                let hue = OklabHue::from_degrees(degree);
917                let (a, b) = hue.into_cartesian();
918                let roundtrip_hue = OklabHue::from_cartesian(a * 10000.0, b * 10000.0);
919                assert_abs_diff_eq!(roundtrip_hue, hue);
920            }
921        }
922
923        #[test]
924        fn normalize_angle_0_360() {
925            let inp = [
926                -1000.0_f32,
927                -900.0,
928                -360.5,
929                -360.0,
930                -359.5,
931                -240.0,
932                -180.5,
933                -180.0,
934                -179.5,
935                -90.0,
936                -0.5,
937                0.0,
938                0.5,
939                90.0,
940                179.5,
941                180.0,
942                180.5,
943                240.0,
944                359.5,
945                360.0,
946                360.5,
947                900.0,
948                1000.0,
949            ];
950
951            let expected = [
952                80.0_f32, 180.0, 359.5, 0.0, 0.5, 120.0, 179.5, 180.0, 180.5, 270.0, 359.5, 0.0,
953                0.5, 90.0, 179.5, 180.0, 180.5, 240.0, 359.5, 0.0, 0.5, 180.0, 280.0,
954            ];
955
956            let result: Vec<f32> = inp
957                .iter()
958                .map(|x| (*x).normalize_unsigned_angle())
959                .collect();
960            for (res, exp) in result.iter().zip(expected.iter()) {
961                assert_relative_eq!(res, exp);
962            }
963        }
964
965        #[test]
966        fn normalize_angle_180_180() {
967            let inp = [
968                -1000.0_f32,
969                -900.0,
970                -360.5,
971                -360.0,
972                -359.5,
973                -240.0,
974                -180.5,
975                -180.0,
976                -179.5,
977                -90.0,
978                -0.5,
979                0.0,
980                0.5,
981                90.0,
982                179.5,
983                180.0,
984                180.5,
985                240.0,
986                359.5,
987                360.0,
988                360.5,
989                900.0,
990                1000.0,
991            ];
992
993            let expected = [
994                80.0, 180.0, -0.5, 0.0, 0.5, 120.0, 179.5, 180.0, -179.5, -90.0, -0.5, 0.0, 0.5,
995                90.0, 179.5, 180.0, -179.5, -120.0, -0.5, 0.0, 0.5, 180.0, -80.0,
996            ];
997
998            let result: Vec<f32> = inp.iter().map(|x| (*x).normalize_signed_angle()).collect();
999            for (res, exp) in result.iter().zip(expected.iter()) {
1000                assert_relative_eq!(res, exp);
1001            }
1002        }
1003
1004        #[test]
1005        fn float_conversion() {
1006            for i in -180..180 {
1007                let hue = RgbHue::from(4.0 * i as f32);
1008
1009                let degs = hue.into_degrees();
1010                assert!(degs > -180.0 && degs <= 180.0);
1011
1012                let pos_degs = hue.into_positive_degrees();
1013                assert!((0.0..360.0).contains(&pos_degs));
1014
1015                assert_relative_eq!(RgbHue::from(degs), RgbHue::from(pos_degs));
1016            }
1017        }
1018    }
1019
1020    #[cfg(feature = "serializing")]
1021    mod serde {
1022        use crate::RgbHue;
1023
1024        #[test]
1025        fn serialize() {
1026            let serialized = ::serde_json::to_string(&RgbHue::from_degrees(10.2)).unwrap();
1027
1028            assert_eq!(serialized, "10.2");
1029        }
1030
1031        #[test]
1032        fn deserialize() {
1033            let deserialized: RgbHue = ::serde_json::from_str("10.2").unwrap();
1034
1035            assert_eq!(deserialized, RgbHue::from_degrees(10.2));
1036        }
1037    }
1038}