chromashift/
color_space.rs

1/// Identifies a colour space for gamut containment checks.
2///
3/// Used with [`crate::Color::in_gamut_of`] to test whether a colour can be represented in a target space without clamping.
4///
5/// Implements [`PartialOrd`] based on gamut containment — `a >= b` means every colour representable in `b` is also
6/// representable in `a`.  This is a *partial* order because some pairs (e.g. Display P3 and A98 RGB) overlap without
7/// either being a strict superset.
8///
9/// ```text
10/// sRGB ⊂ Display P3 ⊂ Rec 2020 ⊂ ProPhoto RGB
11/// sRGB ⊂ A98 RGB ⊂ ProPhoto RGB
12/// ```
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum ColorSpace {
15	Srgb,
16	DisplayP3,
17	A98Rgb,
18	ProphotoRgb,
19	Rec2020,
20}
21
22impl PartialOrd for ColorSpace {
23	fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
24		if self == other {
25			return Some(core::cmp::Ordering::Equal);
26		}
27		let self_contains_other = self.contains(*other);
28		let other_contains_self = other.contains(*self);
29		match (self_contains_other, other_contains_self) {
30			(true, false) => Some(core::cmp::Ordering::Greater),
31			(false, true) => Some(core::cmp::Ordering::Less),
32			_ => None,
33		}
34	}
35}
36
37impl ColorSpace {
38	/// Returns `true` if every colour representable in `other` is also representable in `self`.
39	pub fn contains(self, other: ColorSpace) -> bool {
40		if self == other {
41			return true;
42		}
43		match self {
44			ColorSpace::Srgb => false,
45			ColorSpace::DisplayP3 => other == ColorSpace::Srgb,
46			ColorSpace::A98Rgb => other == ColorSpace::Srgb,
47			ColorSpace::ProphotoRgb => other != ColorSpace::ProphotoRgb,
48			ColorSpace::Rec2020 => matches!(other, ColorSpace::Srgb | ColorSpace::DisplayP3),
49		}
50	}
51}