palette/
lib.rs

1//! A library that makes linear color calculations and conversion easy and
2//! accessible for anyone. It uses the type system to enforce correctness and to
3//! avoid mistakes, such as mixing incompatible color types.
4//!
5//! # Where Do I Start?
6//!
7//! The sections below give an overview of how the types in this library work,
8//! including color conversion. If you want to get your hands dirty, you'll
9//! probably want to start with [`Srgb`] or [`Srgba`]. They are aliases for the
10//! more generic [`Rgb`](rgb::Rgb) type and represent sRGB(A), the most common
11//! RGB format in images and tools. Their documentation has more details and
12//! examples.
13//!
14//! The documentation for each module and type goes deeper into their concepts.
15//! Here are a few you may want to read:
16//!
17//! * [`Rgb`](rgb::Rgb) - For getting started with RGB values.
18//! * [`Alpha`] - For more details on transparency.
19//! * [`convert`] - Describes the conversion traits and how to use and implement
20//!   them.
21//! * [`cast`] - Describes how to cast color types to and from other data
22//!   formats, such as arrays and unsigned integers.
23//! * [`color_difference`] - Describes different ways of measuring the
24//!   difference between colors.
25//!
26//! # Type Safety for Colors
27//!
28//! Digital colors are not "just RGB", and not even RGB is "just RGB". There are
29//! multiple representations of color, with a variety of pros and cons, and
30//! multiple standards for how to encode and decode them. Palette represents
31//! these "color spaces" as separate types for increased expressiveness and to
32//! prevent mistakes.
33//!
34//! Taking RGB as an example, it's often stored or displayed as "gamma
35//! corrected" values, meaning that a non-linear function has been applied to
36//! its values. This encoding is not suitable for all kinds of calculations
37//! (such as rescaling) and will give visibly incorrect results. Functions that
38//! require linear RGB can therefore request, for example, [`LinSrgb`] as their
39//! input type.
40//!
41//! ```rust,compile_fail
42//! // Srgb is an alias for Rgb<Srgb, T>, which is what most pictures store.
43//! // LinSrgb is an alias for Rgb<Linear<Srgb>, T>, better for color manipulation.
44//! use palette::{Srgb, LinSrgb};
45//!
46//! fn do_something(a: LinSrgb, b: LinSrgb) -> LinSrgb {
47//! // ...
48//! # LinSrgb::default()
49//! }
50//!
51//! let orangeish = Srgb::new(1.0, 0.6, 0.0);
52//! let blueish = Srgb::new(0.0, 0.2, 1.0);
53//! let result = do_something(orangeish, blueish); // Does not compile
54//! ```
55//!
56//! The colors will have to be decoded before being used in the function:
57//!
58//! ```rust
59//! // Srgb is an alias for Rgb<Srgb, T>, which is what most pictures store.
60//! // LinSrgb is an alias for Rgb<Linear<Srgb>, T>, better for color manipulation.
61//! use palette::{Srgb, LinSrgb};
62//!
63//! fn do_something(a: LinSrgb, b: LinSrgb) -> LinSrgb {
64//! // ...
65//! # LinSrgb::default()
66//! }
67//!
68//! let orangeish = Srgb::new(1.0, 0.6, 0.0).into_linear();
69//! let blueish = Srgb::new(0.0, 0.2, 1.0).into_linear();
70//! let result = do_something(orangeish, blueish);
71//! ```
72//!
73//! See the [rgb] module for a deeper dive into RGB and (non-)linearity.
74//!
75//! # Color Spaces and Conversion
76//!
77//! As the previous section mentions, there are many different ways of
78//! representing colors. These "color spaces" are represented as different types
79//! in Palette, each with a description of what it is and how it works. Most of
80//! them also have two type parameters for customization:
81//!
82//! * The component type (`T`) that decides which number type is used. The
83//!   default is `f32`, but `u8`, `f64`, and any other type that implement the
84//!   required traits will work. Including SIMD types in many cases.
85//! * The reference white point (`W`) or standard (`S`) that affects the range,
86//!   encoding or display properties of the color. This varies between color
87//!   spaces and can usually be left as its default or be set via a type alias.
88//!   For example, the [`Srgb`] and [`LinSrgb`] type aliases are both variants
89//!   of the [`Rgb`][rgb::Rgb] type, but with different standard (`S`) types.
90//!
91//! Selecting the proper color space can have a big impact on how the resulting
92//! image looks (as illustrated by some of the programs in `examples`), and
93//! Palette makes the conversion between them as easy as a call to
94//! [`from_color`][FromColor::from_color] or
95//! [`into_color`][IntoColor::into_color].
96//!
97//! This example takes an sRGB color, converts it to CIE L\*C\*h°, a color space
98//! similar to the colloquial HSL/HSV color spaces, shifts its hue by 180° and
99//! converts it back to RGB:
100//!
101//! ```
102//! use palette::{FromColor, ShiftHue, IntoColor, Lch, Srgb};
103//!
104//! let lch_color: Lch = Srgb::new(0.8, 0.2, 0.1).into_color();
105//! let new_color = Srgb::from_color(lch_color.shift_hue(180.0));
106//! ```
107//!
108//! # Transparency
109//!
110//! There are many cases where pixel transparency is important, but there are
111//! also many cases where it would just be unused memory space. Palette has
112//! therefore adopted a structure where the transparency component (alpha) is
113//! attachable using the [`Alpha`] type. This approach has shown to be very
114//! modular and easy to maintain, compared to having transparent copies of each
115//! type.
116//!
117//! An additional benefit is allowing operations to selectively affect the alpha
118//! component:
119//!
120//! ```rust
121//! // Each color type has a transparent alias that ends with "a" for "alpha"
122//! use palette::{LinSrgb, LinSrgba};
123//!
124//! let mut c1 = LinSrgba::new(1.0, 0.5, 0.5, 0.8);
125//! let c2 = LinSrgb::new(0.5, 1.0, 1.0);
126//!
127//! c1.color = c1.color * c2; //Leave the alpha as it is
128//! c1.blue += 0.2; //The color components can easily be accessed
129//! c1 = c1 * 0.5; //Scale both the color and the alpha
130//! ```
131//!
132//! There's also [`PreAlpha`][blend::PreAlpha] that represents pre-multiplied
133//! alpha (also known as alpha masked colors). It's commonly used in color
134//! blending and composition.
135//!
136//! # Images and Buffers
137//!
138//! Oftentimes, pixel data is stored in a plain array or slice such as a `[u8;
139//! 3]`. The [`cast`] module allows for easy conversion between Palette colors
140//! and arrays or slices. This also helps when working with other crates or
141//! systems. Here's an example of how the pixels in an image from the `image`
142//! crate can be worked with as `Srgb<u8>`:
143//!
144//! ```rust
145//! use image::RgbImage;
146//! use palette::{Srgb, Oklab, cast::FromComponents, Lighten, IntoColor, FromColor};
147//!
148//! fn lighten(image: &mut RgbImage, amount: f32) {
149//!     // RgbImage can be dereferenced as [u8], allowing us to cast it as a
150//!     // component slice to sRGB with u8 components.
151//!     for pixel in <&mut [Srgb<u8>]>::from_components(&mut **image) {
152//!         // Converting to linear sRGB with f32 components, and then to Oklab.
153//!         let color: Oklab = pixel.into_linear::<f32>().into_color();
154//!
155//!         let lightened_color = color.lighten(amount);
156//!
157//!         // Converting back to non-linear sRGB with u8 components.
158//!         *pixel = Srgb::from_linear(lightened_color.into_color());
159//!     }
160//! }
161//! ```
162//!
163//! Some of the conversions are also implemented on the color types as `From`,
164//! `TryFrom`, `Into`, `TryFrom` and `AsRef`. This example shows how `from` can
165//! be used to convert a `[u8;3]` into a Palette color, `into_format` converts
166//! from  `Srgb<u8>` to `Srgb<f32>`, and finally `into` converts back from a
167//! Palette color back to a `[u8;3]`:
168//!
169//! ```rust
170//! use approx::assert_relative_eq;
171//! use palette::Srgb;
172//!
173//! let buffer = [255, 0, 255];
174//! let srgb = Srgb::from(buffer);
175//! assert_eq!(srgb, Srgb::<u8>::new(255u8, 0, 255));
176//!
177//! let srgb_float: Srgb<f32> = srgb.into_format();
178//! assert_relative_eq!(srgb_float, Srgb::new(1.0, 0.0, 1.0));
179//!
180//! let array: [u8; 3] = srgb_float.into_format().into();
181//! assert_eq!(array, buffer);
182//! ```
183//!
184//! # A Basic Workflow
185//!
186//! The overall workflow can be divided into three steps, where the first and
187//! last may be taken care of by other parts of the application:
188//!
189//! ```text
190//! Decoding -> Processing -> Encoding
191//! ```
192//!
193//! ## 1. Decoding
194//!
195//! Find out what the source format is and convert it to a linear color space.
196//! There may be a specification, such as when working with SVG or CSS.
197//!
198//! When working with RGB or gray scale (luma):
199//!
200//! * If you are asking your user to enter an RGB value, you are in a gray zone
201//! where it depends on the context. It's usually safe to assume sRGB, but
202//! sometimes it's already linear.
203//!
204//! * If you are decoding an image, there may be some meta data that gives you
205//! the necessary details. Otherwise it's most commonly sRGB. Usually you will
206//! end up with a slice or vector with RGB bytes, which can easily be converted
207//! to Palette colors:
208//!
209//! ```rust
210//! # let mut image_buffer: Vec<u8> = vec![];
211//! use palette::{Srgb, cast::ComponentsAsMut};
212//!
213//! // This works for any color type (not only RGB) that can have the
214//! // buffer element type as component.
215//! let color_buffer: &mut [Srgb<u8>] = image_buffer.components_as_mut();
216//! ```
217//!
218//! * If you are getting your colors from the GPU, in a game or other graphical
219//! application, or if they are otherwise generated by the application, then
220//! chances are that they are already linear. Still, make sure to check that
221//! they are not being encoded somewhere.
222//!
223//! When working with other colors:
224//!
225//! * For HSL, HSV, HWB: Check if they are based on any other color space than
226//! sRGB, such as Adobe or Apple RGB.
227//!
228//! * For any of the CIE color spaces, check for a specification of white point
229//! and light source. These are necessary for converting to RGB and other
230//! colors, that depend on perception and "viewing devices". Common defaults are
231//! the D65 light source and the sRGB white point. The Palette defaults should
232//! take you far.
233//!
234//! ## 2. Processing
235//!
236//! When your color has been decoded into some Palette type, it's ready for
237//! processing. This includes things like blending, hue shifting, darkening and
238//! conversion to other formats. Just make sure that your non-linear RGB is made
239//! linear first (`my_srgb.into_linear()`), to make the operations available.
240//!
241//! Different color spaced have different capabilities, pros and cons. You may
242//! have to experiment a bit (or look at the example programs) to find out what
243//! gives the desired result.
244//!
245//! ## 3. Encoding
246//!
247//! When the desired processing is done, it's time to encode the colors back
248//! into some image format. The same rules applies as for the decoding, but the
249//! process reversed.
250
251// Keep the standard library when running tests, too
252#![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
253#![doc(html_root_url = "https://docs.rs/palette/0.7.6/")]
254#![warn(missing_docs)]
255
256#[cfg(feature = "alloc")]
257extern crate alloc;
258
259#[cfg(any(feature = "std", test))]
260extern crate core;
261
262#[cfg(feature = "approx")]
263#[cfg_attr(test, macro_use)]
264extern crate approx;
265
266#[macro_use]
267extern crate palette_derive;
268
269#[cfg(feature = "phf")]
270extern crate phf;
271
272#[cfg(feature = "serializing")]
273#[macro_use]
274extern crate serde as _;
275#[cfg(all(test, feature = "serializing"))]
276extern crate serde_json;
277
278use core::ops::{BitAndAssign, Neg};
279
280use bool_mask::{BoolMask, HasBoolMask};
281use luma::Luma;
282
283#[doc(inline)]
284pub use alpha::{Alpha, WithAlpha};
285
286#[doc(inline)]
287pub use hsl::{Hsl, Hsla};
288#[doc(inline)]
289pub use hsluv::{Hsluv, Hsluva};
290#[doc(inline)]
291pub use hsv::{Hsv, Hsva};
292#[doc(inline)]
293pub use hwb::{Hwb, Hwba};
294#[doc(inline)]
295pub use lab::{Lab, Laba};
296#[doc(inline)]
297pub use lch::{Lch, Lcha};
298#[doc(inline)]
299pub use lchuv::{Lchuv, Lchuva};
300#[doc(inline)]
301pub use luma::{GammaLuma, GammaLumaa, LinLuma, LinLumaa, SrgbLuma, SrgbLumaa};
302#[doc(inline)]
303pub use luv::{Luv, Luva};
304#[doc(inline)]
305pub use okhsl::{Okhsl, Okhsla};
306#[doc(inline)]
307pub use okhsv::{Okhsv, Okhsva};
308#[doc(inline)]
309pub use okhwb::{Okhwb, Okhwba};
310#[doc(inline)]
311pub use oklab::{Oklab, Oklaba};
312#[doc(inline)]
313pub use oklch::{Oklch, Oklcha};
314#[doc(inline)]
315pub use rgb::{GammaSrgb, GammaSrgba, LinSrgb, LinSrgba, Srgb, Srgba};
316#[doc(inline)]
317pub use xyz::{Xyz, Xyza};
318#[doc(inline)]
319pub use yxy::{Yxy, Yxya};
320
321#[doc(inline)]
322pub use hues::{LabHue, LuvHue, OklabHue, RgbHue};
323
324#[allow(deprecated)]
325pub use color_difference::ColorDifference;
326pub use convert::{FromColor, FromColorMut, FromColorMutGuard, IntoColor, IntoColorMut};
327pub use matrix::Mat3;
328#[allow(deprecated)]
329pub use relative_contrast::{contrast_ratio, RelativeContrast};
330
331#[macro_use]
332mod macros;
333
334#[cfg(feature = "named")]
335pub mod named;
336
337#[cfg(feature = "random")]
338mod random_sampling;
339
340#[cfg(feature = "serializing")]
341pub mod serde;
342
343pub mod alpha;
344pub mod angle;
345pub mod blend;
346pub mod bool_mask;
347pub mod cam16;
348pub mod cast;
349pub mod chromatic_adaptation;
350pub mod color_difference;
351pub mod color_theory;
352pub mod convert;
353pub mod encoding;
354pub mod hsl;
355pub mod hsluv;
356pub mod hsv;
357pub mod hues;
358pub mod hwb;
359pub mod lab;
360pub mod lch;
361pub mod lchuv;
362pub mod luma;
363pub mod luv;
364mod luv_bounds;
365pub mod num;
366mod ok_utils;
367pub mod okhsl;
368pub mod okhsv;
369pub mod okhwb;
370pub mod oklab;
371pub mod oklch;
372mod relative_contrast;
373pub mod rgb;
374pub mod stimulus;
375pub mod white_point;
376pub mod xyz;
377pub mod yxy;
378
379#[cfg(test)]
380#[cfg(feature = "approx")]
381mod visual;
382
383#[doc(hidden)]
384pub mod matrix;
385
386#[inline]
387fn clamp<T: num::Clamp>(value: T, min: T, max: T) -> T {
388    value.clamp(min, max)
389}
390
391#[inline]
392fn clamp_assign<T: num::ClampAssign>(value: &mut T, min: T, max: T) {
393    value.clamp_assign(min, max);
394}
395
396#[inline]
397fn clamp_min<T: num::Clamp>(value: T, min: T) -> T {
398    value.clamp_min(min)
399}
400
401#[inline]
402fn clamp_min_assign<T: num::ClampAssign>(value: &mut T, min: T) {
403    value.clamp_min_assign(min);
404}
405
406/// Checks if color components are within their expected range bounds.
407///
408/// A color with out-of-bounds components may be clamped with [`Clamp`] or
409/// [`ClampAssign`].
410///
411/// ```
412/// use palette::{Srgb, IsWithinBounds};
413/// let a = Srgb::new(0.4f32, 0.3, 0.8);
414/// let b = Srgb::new(1.2f32, 0.3, 0.8);
415/// let c = Srgb::new(-0.6f32, 0.3, 0.8);
416///
417/// assert!(a.is_within_bounds());
418/// assert!(!b.is_within_bounds());
419/// assert!(!c.is_within_bounds());
420/// ```
421///
422/// `IsWithinBounds` is also implemented for `[T]`:
423///
424/// ```
425/// use palette::{Srgb, IsWithinBounds};
426///
427/// let my_vec = vec![Srgb::new(0.4f32, 0.3, 0.8), Srgb::new(0.8, 0.5, 0.1)];
428/// let my_array = [Srgb::new(0.4f32, 0.3, 0.8), Srgb::new(1.3, 0.5, -3.0)];
429/// let my_slice = &[Srgb::new(0.4f32, 0.3, 0.8), Srgb::new(1.2, 0.3, 0.8)];
430///
431/// assert!(my_vec.is_within_bounds());
432/// assert!(!my_array.is_within_bounds());
433/// assert!(!my_slice.is_within_bounds());
434/// ```
435pub trait IsWithinBounds: HasBoolMask {
436    /// Check if the color's components are within the expected range bounds.
437    ///
438    /// ```
439    /// use palette::{Srgb, IsWithinBounds};
440    /// assert!(Srgb::new(0.8f32, 0.5, 0.2).is_within_bounds());
441    /// assert!(!Srgb::new(1.3f32, 0.5, -3.0).is_within_bounds());
442    /// ```
443    fn is_within_bounds(&self) -> Self::Mask;
444}
445
446impl<T> IsWithinBounds for [T]
447where
448    T: IsWithinBounds,
449    T::Mask: BoolMask + BitAndAssign,
450{
451    #[inline]
452    fn is_within_bounds(&self) -> Self::Mask {
453        let mut result = Self::Mask::from_bool(true);
454
455        for item in self {
456            result &= item.is_within_bounds();
457
458            if result.is_false() {
459                break;
460            }
461        }
462
463        result
464    }
465}
466
467/// An operator for restricting a color's components to their expected ranges.
468///
469/// [`IsWithinBounds`] can be used to check if the components are within their
470/// range bounds.
471///
472/// See also [`ClampAssign`].
473///
474/// ```
475/// use palette::{Srgb, IsWithinBounds, Clamp};
476///
477/// let unclamped = Srgb::new(1.3f32, 0.5, -3.0);
478/// assert!(!unclamped.is_within_bounds());
479///
480/// let clamped = unclamped.clamp();
481/// assert!(clamped.is_within_bounds());
482/// assert_eq!(clamped, Srgb::new(1.0, 0.5, 0.0));
483/// ```
484pub trait Clamp {
485    /// Return a new color where out-of-bounds components have been changed to
486    /// the nearest valid values.
487    ///
488    /// ```
489    /// use palette::{Srgb, Clamp};
490    /// assert_eq!(Srgb::new(1.3, 0.5, -3.0).clamp(), Srgb::new(1.0, 0.5, 0.0));
491    /// ```
492    #[must_use]
493    fn clamp(self) -> Self;
494}
495
496/// An assigning operator for restricting a color's components to their expected
497/// ranges.
498///
499/// [`IsWithinBounds`] can be used to check if the components are within their
500/// range bounds.
501///
502/// See also [`Clamp`].
503///
504/// ```
505/// use palette::{Srgb, IsWithinBounds, ClampAssign};
506///
507/// let mut color = Srgb::new(1.3f32, 0.5, -3.0);
508/// assert!(!color.is_within_bounds());
509///
510/// color.clamp_assign();
511/// assert!(color.is_within_bounds());
512/// assert_eq!(color, Srgb::new(1.0, 0.5, 0.0));
513/// ```
514///
515/// `ClampAssign` is also implemented for `[T]`:
516///
517/// ```
518/// use palette::{Srgb, ClampAssign};
519///
520/// let mut my_vec = vec![Srgb::new(0.4, 0.3, 0.8), Srgb::new(1.3, 0.5, -3.0)];
521/// let mut my_array = [Srgb::new(0.4, 0.3, 0.8), Srgb::new(1.3, 0.5, -3.0)];
522/// let mut my_slice = &mut [Srgb::new(0.4, 0.3, 0.8), Srgb::new(1.2, 0.3, 0.8)];
523///
524/// my_vec.clamp_assign();
525/// my_array.clamp_assign();
526/// my_slice.clamp_assign();
527/// ```
528pub trait ClampAssign {
529    /// Changes out-of-bounds components to the nearest valid values.
530    ///
531    /// ```
532    /// use palette::{Srgb, ClampAssign};
533    ///
534    /// let mut color = Srgb::new(1.3, 0.5, -3.0);
535    /// color.clamp_assign();
536    /// assert_eq!(color, Srgb::new(1.0, 0.5, 0.0));
537    /// ```
538    fn clamp_assign(&mut self);
539}
540
541impl<T> ClampAssign for [T]
542where
543    T: ClampAssign,
544{
545    #[inline]
546    fn clamp_assign(&mut self) {
547        self.iter_mut().for_each(T::clamp_assign);
548    }
549}
550
551/// Linear color interpolation of two colors.
552///
553/// See also [`MixAssign`].
554///
555/// ```
556/// use approx::assert_relative_eq;
557/// use palette::{LinSrgb, Mix};
558///
559/// let a = LinSrgb::new(0.0, 0.5, 1.0);
560/// let b = LinSrgb::new(1.0, 0.5, 0.0);
561///
562/// assert_relative_eq!(a.mix(b, 0.0), a);
563/// assert_relative_eq!(a.mix(b, 0.5), LinSrgb::new(0.5, 0.5, 0.5));
564/// assert_relative_eq!(a.mix(b, 1.0), b);
565/// ```
566pub trait Mix {
567    /// The type of the mixing factor.
568    type Scalar;
569
570    /// Mix the color with an other color, by `factor`.
571    ///
572    /// `factor` should be between `0.0` and `1.0`, where `0.0` will result in
573    /// the same color as `self` and `1.0` will result in the same color as
574    /// `other`.
575    #[must_use]
576    fn mix(self, other: Self, factor: Self::Scalar) -> Self;
577}
578
579/// Assigning linear color interpolation of two colors.
580///
581/// See also [`Mix`].
582///
583/// ```
584/// use approx::assert_relative_eq;
585/// use palette::{LinSrgb, MixAssign};
586///
587/// let mut a = LinSrgb::new(0.0, 0.5, 1.0);
588/// let b = LinSrgb::new(1.0, 0.5, 0.0);
589///
590/// a.mix_assign(b, 0.5);
591/// assert_relative_eq!(a, LinSrgb::new(0.5, 0.5, 0.5));
592/// ```
593pub trait MixAssign {
594    /// The type of the mixing factor.
595    type Scalar;
596
597    /// Mix the color with an other color, by `factor`.
598    ///
599    /// `factor` should be between `0.0` and `1.0`, where `0.0` will result in
600    /// the same color as `self` and `1.0` will result in the same color as
601    /// `other`.
602    fn mix_assign(&mut self, other: Self, factor: Self::Scalar);
603}
604
605/// Operators for lightening a color.
606///
607/// The trait's functions are split into two groups of functions: relative and
608/// fixed/absolute.
609///
610/// The relative function, [`lighten`](Lighten::lighten), scales the lightness
611/// towards the maximum lightness value. This means that for a color with 50%
612/// lightness, if `lighten(0.5)` is applied to it, the color will scale halfway
613/// to the maximum value of 100% resulting in a new lightness value of 75%.
614///
615/// The fixed or absolute function, [`lighten_fixed`](Lighten::lighten_fixed),
616/// increase the lightness value by an amount that is independent of the current
617/// lightness of the color. So for a color with 50% lightness, if
618/// `lighten_fixed(0.5)` is applied to it, the color will have 50% lightness
619/// added to its lightness value resulting in a new value of 100%.
620///
621/// See also [`LightenAssign`], [`Darken`] and [`DarkenAssign`].
622pub trait Lighten {
623    /// The type of the lighten modifier.
624    type Scalar;
625
626    /// Scale the color towards the maximum lightness by `factor`, a value
627    /// ranging from `0.0` to `1.0`.
628    ///
629    /// ```
630    /// use approx::assert_relative_eq;
631    /// use palette::{Hsl, Lighten};
632    ///
633    /// let color = Hsl::new_srgb(0.0, 1.0, 0.5);
634    /// assert_relative_eq!(color.lighten(0.5).lightness, 0.75);
635    /// ```
636    #[must_use]
637    fn lighten(self, factor: Self::Scalar) -> Self;
638
639    /// Lighten the color by `amount`, a value ranging from `0.0` to `1.0`.
640    ///
641    /// ```
642    /// use approx::assert_relative_eq;
643    /// use palette::{Hsl, Lighten};
644    ///
645    /// let color = Hsl::new_srgb(0.0, 1.0, 0.4);
646    /// assert_relative_eq!(color.lighten_fixed(0.2).lightness, 0.6);
647    /// ```
648    #[must_use]
649    fn lighten_fixed(self, amount: Self::Scalar) -> Self;
650}
651
652/// Assigning operators for lightening a color.
653///
654/// The trait's functions are split into two groups of functions: relative and
655/// fixed/absolute.
656///
657/// The relative function, [`lighten_assign`](LightenAssign::lighten_assign),
658/// scales the lightness towards the maximum lightness value. This means that
659/// for a color with 50% lightness, if `lighten_assign(0.5)` is applied to it,
660/// the color will scale halfway to the maximum value of 100% resulting in a new
661/// lightness value of 75%.
662///
663/// The fixed or absolute function,
664/// [`lighten_fixed_assign`](LightenAssign::lighten_fixed_assign), increase the
665/// lightness value by an amount that is independent of the current lightness of
666/// the color. So for a color with 50% lightness, if `lighten_fixed_assign(0.5)`
667/// is applied to it, the color will have 50% lightness added to its lightness
668/// value resulting in a new value of 100%.
669///
670/// `LightenAssign` is also implemented for `[T]`:
671///
672/// ```
673/// use palette::{Hsl, LightenAssign};
674///
675/// let mut my_vec = vec![Hsl::new_srgb(104.0, 0.3, 0.8), Hsl::new_srgb(113.0, 0.5, 0.8)];
676/// let mut my_array = [Hsl::new_srgb(104.0, 0.3, 0.8), Hsl::new_srgb(113.0, 0.5, 0.8)];
677/// let mut my_slice = &mut [Hsl::new_srgb(104.0, 0.3, 0.8), Hsl::new_srgb(112.0, 0.5, 0.8)];
678///
679/// my_vec.lighten_assign(0.5);
680/// my_array.lighten_assign(0.5);
681/// my_slice.lighten_assign(0.5);
682/// ```
683///
684/// See also [`Lighten`], [`Darken`] and [`DarkenAssign`].
685pub trait LightenAssign {
686    /// The type of the lighten modifier.
687    type Scalar;
688
689    /// Scale the color towards the maximum lightness by `factor`, a value
690    /// ranging from `0.0` to `1.0`.
691    ///
692    /// ```
693    /// use approx::assert_relative_eq;
694    /// use palette::{Hsl, LightenAssign};
695    ///
696    /// let mut color = Hsl::new_srgb(0.0, 1.0, 0.5);
697    /// color.lighten_assign(0.5);
698    /// assert_relative_eq!(color.lightness, 0.75);
699    /// ```
700    fn lighten_assign(&mut self, factor: Self::Scalar);
701
702    /// Lighten the color by `amount`, a value ranging from `0.0` to `1.0`.
703    ///
704    /// ```
705    /// use approx::assert_relative_eq;
706    /// use palette::{Hsl, LightenAssign};
707    ///
708    /// let mut color = Hsl::new_srgb(0.0, 1.0, 0.4);
709    /// color.lighten_fixed_assign(0.2);
710    /// assert_relative_eq!(color.lightness, 0.6);
711    /// ```
712    fn lighten_fixed_assign(&mut self, amount: Self::Scalar);
713}
714
715impl<T> LightenAssign for [T]
716where
717    T: LightenAssign,
718    T::Scalar: Clone,
719{
720    type Scalar = T::Scalar;
721
722    #[inline]
723    fn lighten_assign(&mut self, factor: Self::Scalar) {
724        for color in self {
725            color.lighten_assign(factor.clone());
726        }
727    }
728
729    #[inline]
730    fn lighten_fixed_assign(&mut self, amount: Self::Scalar) {
731        for color in self {
732            color.lighten_fixed_assign(amount.clone());
733        }
734    }
735}
736
737/// Operators for darkening a color;
738///
739/// The trait's functions are split into two groups of functions: relative and
740/// fixed/absolute.
741///
742/// The relative function, [`darken`](Darken::darken), scales the lightness
743/// towards the minimum lightness value. This means that for a color with 50%
744/// lightness, if `darken(0.5)` is applied to it, the color will scale halfway
745/// to the minimum value of 0% resulting in a new lightness value of 25%.
746///
747/// The fixed or absolute function, [`darken_fixed`](Darken::darken_fixed),
748/// decreases the lightness value by an amount that is independent of the
749/// current lightness of the color. So for a color with 50% lightness, if
750/// `darken_fixed(0.5)` is applied to it, the color will have 50% lightness
751/// removed from its lightness value resulting in a new value of 0%.
752///
753/// See also [`DarkenAssign`], [`Lighten`] and [`LightenAssign`].
754pub trait Darken {
755    /// The type of the darken modifier.
756    type Scalar;
757
758    /// Scale the color towards the minimum lightness by `factor`, a value
759    /// ranging from `0.0` to `1.0`.
760    ///
761    /// ```
762    /// use approx::assert_relative_eq;
763    /// use palette::{Hsv, Darken};
764    ///
765    /// let color = Hsv::new_srgb(0.0, 1.0, 0.5);
766    /// assert_relative_eq!(color.darken(0.5).value, 0.25);
767    /// ```
768    #[must_use]
769    fn darken(self, factor: Self::Scalar) -> Self;
770
771    /// Darken the color by `amount`, a value ranging from `0.0` to `1.0`.
772    ///
773    /// ```
774    /// use approx::assert_relative_eq;
775    /// use palette::{Hsv, Darken};
776    ///
777    /// let color = Hsv::new_srgb(0.0, 1.0, 0.4);
778    /// assert_relative_eq!(color.darken_fixed(0.2).value, 0.2);
779    /// ```
780    #[must_use]
781    fn darken_fixed(self, amount: Self::Scalar) -> Self;
782}
783
784impl<T> Darken for T
785where
786    T: Lighten,
787    T::Scalar: Neg<Output = T::Scalar>,
788{
789    type Scalar = T::Scalar;
790
791    #[inline]
792    fn darken(self, factor: Self::Scalar) -> Self {
793        self.lighten(-factor)
794    }
795
796    #[inline]
797    fn darken_fixed(self, amount: Self::Scalar) -> Self {
798        self.lighten_fixed(-amount)
799    }
800}
801
802/// Assigning operators for darkening a color;
803///
804/// The trait's functions are split into two groups of functions: relative and
805/// fixed/absolute.
806///
807/// The relative function, [`darken_assign`](DarkenAssign::darken_assign),
808/// scales the lightness towards the minimum lightness value. This means that
809/// for a color with 50% lightness, if `darken_assign(0.5)` is applied to it,
810/// the color will scale halfway to the minimum value of 0% resulting in a new
811/// lightness value of 25%.
812///
813/// The fixed or absolute function,
814/// [`darken_fixed_assign`](DarkenAssign::darken_fixed_assign), decreases the
815/// lightness value by an amount that is independent of the current lightness of
816/// the color. So for a color with 50% lightness, if `darken_fixed_assign(0.5)`
817/// is applied to it, the color will have 50% lightness removed from its
818/// lightness value resulting in a new value of 0%.
819///
820/// `DarkenAssign` is also implemented for `[T]`:
821///
822/// ```
823/// use palette::{Hsl, DarkenAssign};
824///
825/// let mut my_vec = vec![Hsl::new_srgb(104.0, 0.3, 0.8), Hsl::new_srgb(113.0, 0.5, 0.8)];
826/// let mut my_array = [Hsl::new_srgb(104.0, 0.3, 0.8), Hsl::new_srgb(113.0, 0.5, 0.8)];
827/// let mut my_slice = &mut [Hsl::new_srgb(104.0, 0.3, 0.8), Hsl::new_srgb(112.0, 0.5, 0.8)];
828///
829/// my_vec.darken_assign(0.5);
830/// my_array.darken_assign(0.5);
831/// my_slice.darken_assign(0.5);
832/// ```
833///
834/// See also [`Darken`], [`Lighten`] and [`LightenAssign`].
835pub trait DarkenAssign {
836    /// The type of the darken modifier.
837    type Scalar;
838
839    /// Scale the color towards the minimum lightness by `factor`, a value
840    /// ranging from `0.0` to `1.0`.
841    ///
842    /// ```
843    /// use approx::assert_relative_eq;
844    /// use palette::{Hsv, DarkenAssign};
845    ///
846    /// let mut color = Hsv::new_srgb(0.0, 1.0, 0.5);
847    /// color.darken_assign(0.5);
848    /// assert_relative_eq!(color.value, 0.25);
849    /// ```
850    fn darken_assign(&mut self, factor: Self::Scalar);
851
852    /// Darken the color by `amount`, a value ranging from `0.0` to `1.0`.
853    ///
854    /// ```
855    /// use approx::assert_relative_eq;
856    /// use palette::{Hsv, DarkenAssign};
857    ///
858    /// let mut color = Hsv::new_srgb(0.0, 1.0, 0.4);
859    /// color.darken_fixed_assign(0.2);
860    /// assert_relative_eq!(color.value, 0.2);
861    /// ```
862    fn darken_fixed_assign(&mut self, amount: Self::Scalar);
863}
864
865impl<T> DarkenAssign for T
866where
867    T: LightenAssign + ?Sized,
868    T::Scalar: Neg<Output = T::Scalar>,
869{
870    type Scalar = T::Scalar;
871
872    #[inline]
873    fn darken_assign(&mut self, factor: Self::Scalar) {
874        self.lighten_assign(-factor);
875    }
876
877    #[inline]
878    fn darken_fixed_assign(&mut self, amount: Self::Scalar) {
879        self.lighten_fixed_assign(-amount);
880    }
881}
882
883/// A trait for colors where a hue may be calculated.
884///
885/// See also [`WithHue`], [`SetHue`], [`ShiftHue`] and [`ShiftHueAssign`].
886///
887/// ```
888/// use approx::assert_relative_eq;
889/// use palette::{GetHue, LinSrgb};
890///
891/// let red = LinSrgb::new(1.0f32, 0.0, 0.0);
892/// let green = LinSrgb::new(0.0f32, 1.0, 0.0);
893/// let blue = LinSrgb::new(0.0f32, 0.0, 1.0);
894/// let gray = LinSrgb::new(0.5f32, 0.5, 0.5);
895///
896/// assert_relative_eq!(red.get_hue(), 0.0.into());
897/// assert_relative_eq!(green.get_hue(), 120.0.into());
898/// assert_relative_eq!(blue.get_hue(), 240.0.into());
899/// assert_relative_eq!(gray.get_hue(), 0.0.into());
900/// ```
901pub trait GetHue {
902    /// The kind of hue unit this color space uses.
903    ///
904    /// The hue is most commonly calculated as an angle around a color circle
905    /// and may not always be uniform between color spaces. It's therefore not
906    /// recommended to take one type of hue and apply it to a color space that
907    /// expects an other.
908    type Hue;
909
910    /// Calculate a hue if possible.
911    ///
912    /// Colors in the gray scale has no well defined hue and should preferably
913    /// return `0`.
914    #[must_use]
915    fn get_hue(&self) -> Self::Hue;
916}
917
918/// Change the hue of a color to a specific value.
919///
920/// See also [`SetHue`], [`GetHue`], [`ShiftHue`] and [`ShiftHueAssign`].
921///
922/// ```
923/// use palette::{Hsl, WithHue};
924///
925/// let green = Hsl::new_srgb(120.0, 1.0, 0.5);
926/// let blue = green.with_hue(240.0);
927/// assert_eq!(blue, Hsl::new_srgb(240.0, 1.0, 0.5));
928/// ```
929pub trait WithHue<H> {
930    /// Return a copy of `self` with a specific hue.
931    #[must_use]
932    fn with_hue(self, hue: H) -> Self;
933}
934
935/// Change the hue of a color to a specific value without moving.
936///
937/// See also [`WithHue`], [`GetHue`], [`ShiftHue`] and [`ShiftHueAssign`].
938///
939/// ```
940/// use palette::{Hsl, SetHue};
941///
942/// let mut color = Hsl::new_srgb(120.0, 1.0, 0.5);
943/// color.set_hue(240.0);
944/// assert_eq!(color, Hsl::new_srgb(240.0, 1.0, 0.5));
945/// ```
946///
947/// `SetHue` is also implemented for `[T]`:
948///
949/// ```
950/// use palette::{Hsl, SetHue};
951///
952/// let mut my_vec = vec![Hsl::new_srgb(104.0, 0.3, 0.8), Hsl::new_srgb(113.0, 0.5, 0.8)];
953/// let mut my_array = [Hsl::new_srgb(104.0, 0.3, 0.8), Hsl::new_srgb(113.0, 0.5, 0.8)];
954/// let mut my_slice = &mut [Hsl::new_srgb(104.0, 0.3, 0.8), Hsl::new_srgb(112.0, 0.5, 0.8)];
955///
956/// my_vec.set_hue(120.0);
957/// my_array.set_hue(120.0);
958/// my_slice.set_hue(120.0);
959/// ```
960pub trait SetHue<H> {
961    /// Change the hue to a specific value.
962    fn set_hue(&mut self, hue: H);
963}
964
965impl<T, H> SetHue<H> for [T]
966where
967    T: SetHue<H>,
968    H: Clone,
969{
970    fn set_hue(&mut self, hue: H) {
971        for color in self {
972            color.set_hue(hue.clone());
973        }
974    }
975}
976
977/// Operator for increasing or decreasing the hue by an amount.
978///
979/// See also [`ShiftHueAssign`], [`WithHue`], [`SetHue`] and [`GetHue`].
980///
981/// ```
982/// use palette::{Hsl, ShiftHue};
983///
984/// let green = Hsl::new_srgb(120.0, 1.0, 0.5);
985/// let blue = green.shift_hue(120.0);
986/// assert_eq!(blue, Hsl::new_srgb(240.0, 1.0, 0.5));
987/// ```
988pub trait ShiftHue {
989    /// The type of the hue modifier.
990    type Scalar;
991
992    /// Return a copy of `self` with the hue shifted by `amount`.
993    #[must_use]
994    fn shift_hue(self, amount: Self::Scalar) -> Self;
995}
996
997/// Assigning operator for increasing or decreasing the hue by an amount.
998///
999/// See also [`ShiftHue`], [`WithHue`], [`SetHue`] and [`GetHue`].
1000///
1001/// ```
1002/// use palette::{Hsl, ShiftHueAssign};
1003///
1004/// let mut color = Hsl::new_srgb(120.0, 1.0, 0.5);
1005/// color.shift_hue_assign(120.0);
1006/// assert_eq!(color, Hsl::new_srgb(240.0, 1.0, 0.5));
1007/// ```
1008///
1009/// `ShiftHueAssign` is also implemented for `[T]`:
1010///
1011/// ```
1012/// use palette::{Hsl, ShiftHueAssign};
1013///
1014/// let mut my_vec = vec![Hsl::new_srgb(104.0, 0.3, 0.8), Hsl::new_srgb(113.0, 0.5, 0.8)];
1015/// let mut my_array = [Hsl::new_srgb(104.0, 0.3, 0.8), Hsl::new_srgb(113.0, 0.5, 0.8)];
1016/// let mut my_slice = &mut [Hsl::new_srgb(104.0, 0.3, 0.8), Hsl::new_srgb(112.0, 0.5, 0.8)];
1017///
1018/// my_vec.shift_hue_assign(120.0);
1019/// my_array.shift_hue_assign(120.0);
1020/// my_slice.shift_hue_assign(120.0);
1021/// ```
1022pub trait ShiftHueAssign {
1023    /// The type of the hue modifier.
1024    type Scalar;
1025
1026    /// Shifts the hue by `amount`.
1027    fn shift_hue_assign(&mut self, amount: Self::Scalar);
1028}
1029
1030impl<T> ShiftHueAssign for [T]
1031where
1032    T: ShiftHueAssign,
1033    T::Scalar: Clone,
1034{
1035    type Scalar = T::Scalar;
1036
1037    fn shift_hue_assign(&mut self, amount: Self::Scalar) {
1038        for color in self {
1039            color.shift_hue_assign(amount.clone());
1040        }
1041    }
1042}
1043
1044/// Operator for increasing the saturation (or chroma) of a color.
1045///
1046/// The trait's functions are split into two groups of functions: relative and
1047/// fixed/absolute.
1048///
1049/// The relative function, [`saturate`](Saturate::saturate), scales the
1050/// saturation towards the maximum saturation value. This means that for a color
1051/// with 50% saturation, if `saturate(0.5)` is applied to it, the color will
1052/// scale halfway to the maximum value of 100% resulting in a new saturation
1053/// value of 75%.
1054///
1055/// The fixed or absolute function,
1056/// [`saturate_fixed`](Saturate::saturate_fixed), increases the saturation by an
1057/// amount that is independent of the current saturation of the color. So for a
1058/// color with 50% saturation, if `saturate_fixed(0.5)` is applied to it, the
1059/// color will have 50% saturation added to its saturation value resulting in a
1060/// new value of 100%.
1061///
1062/// See also [`SaturateAssign`], [`Desaturate`] and [`DesaturateAssign`].
1063///
1064/// ```
1065/// use approx::assert_relative_eq;
1066/// use palette::{Hsv, Saturate};
1067///
1068/// let a = Hsv::new_srgb(0.0, 0.5, 1.0);
1069///
1070/// assert_relative_eq!(a.saturate(0.5).saturation, 0.75);
1071/// assert_relative_eq!(a.saturate_fixed(0.5).saturation, 1.0);
1072/// ```
1073pub trait Saturate {
1074    /// The type of the saturation modifier.
1075    type Scalar;
1076
1077    /// Scale the color towards the maximum saturation by `factor`, a value
1078    /// ranging from `0.0` to `1.0`.
1079    ///
1080    /// ```
1081    /// use approx::assert_relative_eq;
1082    /// use palette::{Hsl, Saturate};
1083    ///
1084    /// let color = Hsl::new_srgb(0.0, 0.5, 0.5);
1085    /// assert_relative_eq!(color.saturate(0.5).saturation, 0.75);
1086    /// ```
1087    #[must_use]
1088    fn saturate(self, factor: Self::Scalar) -> Self;
1089
1090    /// Increase the saturation by `amount`, a value ranging from `0.0` to
1091    /// `1.0`.
1092    ///
1093    /// ```
1094    /// use approx::assert_relative_eq;
1095    /// use palette::{Hsl, Saturate};
1096    ///
1097    /// let color = Hsl::new_srgb(0.0, 0.4, 0.5);
1098    /// assert_relative_eq!(color.saturate_fixed(0.2).saturation, 0.6);
1099    /// ```
1100    #[must_use]
1101    fn saturate_fixed(self, amount: Self::Scalar) -> Self;
1102}
1103
1104/// Assigning operator for increasing the saturation (or chroma) of a color.
1105///
1106/// The trait's functions are split into two groups of functions: relative and
1107/// fixed/absolute.
1108///
1109/// The relative function, [`saturate_assign`](SaturateAssign::saturate_assign),
1110/// scales the saturation towards the maximum saturation value. This means that
1111/// for a color with 50% saturation, if `saturate_assign(0.5)` is applied to it,
1112/// the color will scale halfway to the maximum value of 100% resulting in a new
1113/// saturation value of 75%.
1114///
1115/// The fixed or absolute function,
1116/// [`saturate_fixed_assign`](SaturateAssign::saturate_fixed_assign), increases
1117/// the saturation by an amount that is independent of the current saturation of
1118/// the color. So for a color with 50% saturation, if
1119/// `saturate_fixed_assign(0.5)` is applied to it, the color will have 50%
1120/// saturation added to its saturation value resulting in a new value of 100%.
1121///
1122/// See also [`Saturate`], [`Desaturate`] and [`DesaturateAssign`].
1123///
1124/// ```
1125/// use approx::assert_relative_eq;
1126/// use palette::{Hsv, SaturateAssign};
1127///
1128/// let mut relative = Hsv::new_srgb(0.0, 0.5, 1.0);
1129/// relative.saturate_assign(0.5);
1130///
1131/// let mut fixed = Hsv::new_srgb(0.0, 0.5, 1.0);
1132/// fixed.saturate_fixed_assign(0.5);
1133///
1134/// assert_relative_eq!(relative.saturation, 0.75);
1135/// assert_relative_eq!(fixed.saturation, 1.0);
1136/// ```
1137///
1138/// `SaturateAssign` is also implemented for `[T]`:
1139///
1140/// ```
1141/// use palette::{Hsl, SaturateAssign};
1142///
1143/// let mut my_vec = vec![Hsl::new_srgb(104.0, 0.3, 0.8), Hsl::new_srgb(113.0, 0.5, 0.8)];
1144/// let mut my_array = [Hsl::new_srgb(104.0, 0.3, 0.8), Hsl::new_srgb(113.0, 0.5, 0.8)];
1145/// let mut my_slice = &mut [Hsl::new_srgb(104.0, 0.3, 0.8), Hsl::new_srgb(112.0, 0.5, 0.8)];
1146///
1147/// my_vec.saturate_assign(0.5);
1148/// my_array.saturate_assign(0.5);
1149/// my_slice.saturate_assign(0.5);
1150/// ```
1151pub trait SaturateAssign {
1152    /// The type of the saturation modifier.
1153    type Scalar;
1154
1155    /// Scale the color towards the maximum saturation by `factor`, a value
1156    /// ranging from `0.0` to `1.0`.
1157    ///
1158    /// ```
1159    /// use approx::assert_relative_eq;
1160    /// use palette::{Hsl, SaturateAssign};
1161    ///
1162    /// let mut color = Hsl::new_srgb(0.0, 0.5, 0.5);
1163    /// color.saturate_assign(0.5);
1164    /// assert_relative_eq!(color.saturation, 0.75);
1165    /// ```
1166    fn saturate_assign(&mut self, factor: Self::Scalar);
1167
1168    /// Increase the saturation by `amount`, a value ranging from `0.0` to
1169    /// `1.0`.
1170    ///
1171    /// ```
1172    /// use approx::assert_relative_eq;
1173    /// use palette::{Hsl, SaturateAssign};
1174    ///
1175    /// let mut color = Hsl::new_srgb(0.0, 0.4, 0.5);
1176    /// color.saturate_fixed_assign(0.2);
1177    /// assert_relative_eq!(color.saturation, 0.6);
1178    /// ```
1179    fn saturate_fixed_assign(&mut self, amount: Self::Scalar);
1180}
1181
1182impl<T> SaturateAssign for [T]
1183where
1184    T: SaturateAssign,
1185    T::Scalar: Clone,
1186{
1187    type Scalar = T::Scalar;
1188
1189    fn saturate_assign(&mut self, factor: Self::Scalar) {
1190        for color in self {
1191            color.saturate_assign(factor.clone());
1192        }
1193    }
1194
1195    fn saturate_fixed_assign(&mut self, amount: Self::Scalar) {
1196        for color in self {
1197            color.saturate_fixed_assign(amount.clone());
1198        }
1199    }
1200}
1201
1202/// Operator for decreasing the saturation (or chroma) of a color.
1203///
1204/// The trait's functions are split into two groups of functions: relative and
1205/// fixed/absolute.
1206///
1207/// The relative function, [`desaturate`](Desaturate::desaturate), scales the
1208/// saturation towards the minimum saturation value. This means that for a color
1209/// with 50% saturation, if `desaturate(0.5)` is applied to it, the color will
1210/// scale halfway to the minimum value of 0% resulting in a new saturation value
1211/// of 25%.
1212///
1213/// The fixed or absolute function,
1214/// [`desaturate_fixed`](Desaturate::desaturate_fixed), decreases the saturation
1215/// by an amount that is independent of the current saturation of the color. So
1216/// for a color with 50% saturation, if `desaturate_fixed(0.5)` is applied to
1217/// it, the color will have 50% saturation removed from its saturation value
1218/// resulting in a new value of 0%.
1219///
1220/// See also [`DesaturateAssign`], [`Saturate`] and [`SaturateAssign`].
1221///
1222/// ```
1223/// use approx::assert_relative_eq;
1224/// use palette::{Hsv, Desaturate};
1225///
1226/// let a = Hsv::new_srgb(0.0, 0.5, 1.0);
1227///
1228/// assert_relative_eq!(a.desaturate(0.5).saturation, 0.25);
1229/// assert_relative_eq!(a.desaturate_fixed(0.5).saturation, 0.0);
1230/// ```
1231pub trait Desaturate {
1232    /// The type of the desaturation modifier.
1233    type Scalar;
1234
1235    /// Scale the color towards the minimum saturation by `factor`, a value
1236    /// ranging from `0.0` to `1.0`.
1237    ///
1238    /// ```
1239    /// use approx::assert_relative_eq;
1240    /// use palette::{Hsv, Desaturate};
1241    ///
1242    /// let color = Hsv::new_srgb(0.0, 0.5, 0.5);
1243    /// assert_relative_eq!(color.desaturate(0.5).saturation, 0.25);
1244    /// ```
1245    #[must_use]
1246    fn desaturate(self, factor: Self::Scalar) -> Self;
1247
1248    /// Increase the saturation by `amount`, a value ranging from `0.0` to
1249    /// `1.0`.
1250    ///
1251    /// ```
1252    /// use approx::assert_relative_eq;
1253    /// use palette::{Hsv, Desaturate};
1254    ///
1255    /// let color = Hsv::new_srgb(0.0, 0.4, 0.5);
1256    /// assert_relative_eq!(color.desaturate_fixed(0.2).saturation, 0.2);
1257    /// ```
1258    #[must_use]
1259    fn desaturate_fixed(self, amount: Self::Scalar) -> Self;
1260}
1261
1262impl<T> Desaturate for T
1263where
1264    T: Saturate,
1265    T::Scalar: Neg<Output = T::Scalar>,
1266{
1267    type Scalar = T::Scalar;
1268
1269    #[inline]
1270    fn desaturate(self, factor: Self::Scalar) -> Self {
1271        self.saturate(-factor)
1272    }
1273
1274    #[inline]
1275    fn desaturate_fixed(self, amount: Self::Scalar) -> Self {
1276        self.saturate_fixed(-amount)
1277    }
1278}
1279
1280/// Assigning operator for decreasing the saturation (or chroma) of a color.
1281///
1282/// The trait's functions are split into two groups of functions: relative and
1283/// fixed/absolute.
1284///
1285/// The relative function,
1286/// [`desaturate_assign`](DesaturateAssign::desaturate_assign), scales the
1287/// saturation towards the minimum saturation value. This means that for a color
1288/// with 50% saturation, if `desaturate_assign(0.5)` is applied to it, the color
1289/// will scale halfway to the minimum value of 0% resulting in a new saturation
1290/// value of 25%.
1291///
1292/// The fixed or absolute function,
1293/// [`desaturate_fixed_assign`](DesaturateAssign::desaturate_fixed_assign),
1294/// decreases the saturation by an amount that is independent of the current
1295/// saturation of the color. So for a color with 50% saturation, if
1296/// `desaturate_fixed_assign(0.5)` is applied to it, the color will have 50%
1297/// saturation removed from its saturation value resulting in a new value of 0%.
1298///
1299/// See also [`Desaturate`], [`Saturate`] and [`SaturateAssign`].
1300///
1301/// ```
1302/// use approx::assert_relative_eq;
1303/// use palette::{Hsv, DesaturateAssign};
1304///
1305/// let mut relative = Hsv::new_srgb(0.0, 0.5, 1.0);
1306/// relative.desaturate_assign(0.5);
1307///
1308/// let mut fixed = Hsv::new_srgb(0.0, 0.5, 1.0);
1309/// fixed.desaturate_fixed_assign(0.5);
1310///
1311/// assert_relative_eq!(relative.saturation, 0.25);
1312/// assert_relative_eq!(fixed.saturation, 0.0);
1313/// ```
1314///
1315/// `DesaturateAssign` is also implemented for `[T]`:
1316///
1317/// ```
1318/// use palette::{Hsl, DesaturateAssign};
1319///
1320/// let mut my_vec = vec![Hsl::new_srgb(104.0, 0.3, 0.8), Hsl::new_srgb(113.0, 0.5, 0.8)];
1321/// let mut my_array = [Hsl::new_srgb(104.0, 0.3, 0.8), Hsl::new_srgb(113.0, 0.5, 0.8)];
1322/// let mut my_slice = &mut [Hsl::new_srgb(104.0, 0.3, 0.8), Hsl::new_srgb(112.0, 0.5, 0.8)];
1323///
1324/// my_vec.desaturate_assign(0.5);
1325/// my_array.desaturate_assign(0.5);
1326/// my_slice.desaturate_assign(0.5);
1327/// ```
1328pub trait DesaturateAssign {
1329    /// The type of the desaturation modifier.
1330    type Scalar;
1331
1332    /// Scale the color towards the minimum saturation by `factor`, a value
1333    /// ranging from `0.0` to `1.0`.
1334    ///
1335    /// ```
1336    /// use approx::assert_relative_eq;
1337    /// use palette::{Hsv, DesaturateAssign};
1338    ///
1339    /// let mut color = Hsv::new_srgb(0.0, 0.5, 0.5);
1340    /// color.desaturate_assign(0.5);
1341    /// assert_relative_eq!(color.saturation, 0.25);
1342    /// ```
1343    fn desaturate_assign(&mut self, factor: Self::Scalar);
1344
1345    /// Increase the saturation by `amount`, a value ranging from `0.0` to
1346    /// `1.0`.
1347    ///
1348    /// ```
1349    /// use approx::assert_relative_eq;
1350    /// use palette::{Hsv, DesaturateAssign};
1351    ///
1352    /// let mut color = Hsv::new_srgb(0.0, 0.4, 0.5);
1353    /// color.desaturate_fixed_assign(0.2);
1354    /// assert_relative_eq!(color.saturation, 0.2);
1355    /// ```
1356    fn desaturate_fixed_assign(&mut self, amount: Self::Scalar);
1357}
1358
1359impl<T> DesaturateAssign for T
1360where
1361    T: SaturateAssign + ?Sized,
1362    T::Scalar: Neg<Output = T::Scalar>,
1363{
1364    type Scalar = T::Scalar;
1365
1366    #[inline]
1367    fn desaturate_assign(&mut self, factor: Self::Scalar) {
1368        self.saturate_assign(-factor);
1369    }
1370
1371    #[inline]
1372    fn desaturate_fixed_assign(&mut self, amount: Self::Scalar) {
1373        self.saturate_fixed_assign(-amount);
1374    }
1375}
1376
1377/// Extension trait for fixed size arrays.
1378///
1379/// ## Safety
1380///
1381/// * `Item` must be the type of the array's items (eg: `T` in `[T; N]`).
1382/// * `LENGTH` must be the length of the array (eg: `N` in `[T; N]`).
1383pub unsafe trait ArrayExt {
1384    /// The type of the array's items.
1385    type Item;
1386
1387    /// The number of items in the array.
1388    const LENGTH: usize;
1389}
1390
1391unsafe impl<T, const N: usize> ArrayExt for [T; N] {
1392    type Item = T;
1393
1394    const LENGTH: usize = N;
1395}
1396
1397/// Temporary helper trait for getting an array type of size `N + 1`.
1398///
1399/// ## Safety
1400///
1401/// * `Next` must have the same item type as `Self`.
1402/// * `Next` must be one item longer than `Self`.
1403pub unsafe trait NextArray {
1404    /// An array of size `N + 1`.
1405    type Next: ArrayExt;
1406}
1407
1408macro_rules! impl_next_array {
1409    ($length: expr) => {};
1410    ($length: expr, $next_length: expr $(, $rest: expr)*) => {
1411        unsafe impl<T> NextArray for [T; $length] {
1412            type Next = [T; $next_length];
1413        }
1414
1415        impl_next_array!($next_length $(, $rest)*);
1416    };
1417}
1418
1419impl_next_array!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17);
1420
1421#[cfg(doctest)]
1422macro_rules! doctest {
1423    ($str: expr, $name: ident) => {
1424        #[doc = $str]
1425        mod $name {}
1426    };
1427}
1428
1429// Makes doctest run tests on README.md.
1430#[cfg(doctest)]
1431doctest!(include_str!("../README.md"), readme);