1use crate::x11_colors;
7
8#[derive(Default, Clone, Copy, PartialEq, Eq, Hash)]
22#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
23pub struct Flags {
24 missing: Missing,
26
27 name: u8,
32}
33
34#[cfg(test)]
36const _: () = const {
37 if x11_colors::NAMES.len() > 253 {
38 panic!("There are more X11 color names than can be packed into Flags.");
39 }
40};
41
42#[derive(Default, Clone, Copy, PartialEq, Eq, Hash)]
47#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
48pub struct Missing(u8);
49
50impl Flags {
51 #[inline]
53 pub const fn from_missing(missing: Missing) -> Self {
54 Self { missing, name: 0 }
55 }
56
57 #[inline]
59 #[warn(
60 clippy::missing_const_for_fn,
61 reason = "can be made const with MSRV 1.83"
62 )]
63 pub fn set_missing(&mut self, missing: Missing) {
64 self.missing = missing;
65 }
66
67 #[inline]
69 pub const fn missing(self) -> Missing {
70 self.missing
71 }
72
73 pub(crate) fn set_named_color(&mut self, name_ix: usize) {
76 debug_assert!(
77 name_ix < x11_colors::NAMES.len(),
78 "Expected an X11 color name index no larger than: {}. Got: {}.",
79 x11_colors::NAMES.len(),
80 name_ix
81 );
82
83 #[expect(
84 clippy::cast_possible_truncation,
85 reason = "name_ix is guaranteed to small enough by the above condition and by the test on the length of `x11_colors::NAMES`"
86 )]
87 {
88 self.name = name_ix as u8 + 1;
89 }
90 }
91
92 #[warn(
95 clippy::missing_const_for_fn,
96 reason = "can be made const with MSRV 1.83"
97 )]
98 pub(crate) fn set_named_color_space(&mut self) {
99 self.name = 255;
100 }
101
102 #[inline]
105 pub const fn named(self) -> bool {
106 self.name != 0
107 }
108
109 pub const fn color_name(self) -> Option<&'static str> {
113 let name_ix = self.name;
114 if name_ix == 0 || name_ix == 255 {
115 None
116 } else {
117 Some(x11_colors::NAMES[name_ix as usize - 1])
118 }
119 }
120
121 #[inline]
123 #[warn(
124 clippy::missing_const_for_fn,
125 reason = "can be made const with MSRV 1.83"
126 )]
127 pub fn discard_name(&mut self) {
128 self.name = 0;
129 }
130}
131
132impl core::fmt::Debug for Flags {
133 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
134 f.debug_struct("Flags")
135 .field("missing", &self.missing)
136 .field("name", &self.name)
137 .field("named", &self.named())
138 .field("color_name", &self.color_name())
139 .finish()
140 }
141}
142
143impl Missing {
144 pub const EMPTY: Self = Self(0);
146
147 #[inline]
149 pub const fn single(ix: usize) -> Self {
150 debug_assert!(ix <= 3, "color component index must be 0, 1, 2 or 3");
151 Self(1 << ix)
152 }
153
154 #[inline]
156 pub const fn contains(self, ix: usize) -> bool {
157 (self.0 & Self::single(ix).0) != 0
158 }
159
160 #[inline]
162 #[warn(
163 clippy::missing_const_for_fn,
164 reason = "can be made const with MSRV 1.83"
165 )]
166 pub fn insert(&mut self, ix: usize) {
167 self.0 |= Self::single(ix).0;
168 }
169
170 #[inline]
172 pub const fn is_empty(self) -> bool {
173 self.0 == 0
174 }
175}
176
177impl core::ops::BitAnd for Missing {
178 type Output = Self;
179
180 #[inline]
181 fn bitand(self, rhs: Self) -> Self {
182 Self(self.0 & rhs.0)
183 }
184}
185
186impl core::ops::BitOr for Missing {
187 type Output = Self;
188
189 #[inline]
190 fn bitor(self, rhs: Self) -> Self {
191 Self(self.0 | rhs.0)
192 }
193}
194
195impl core::ops::Not for Missing {
196 type Output = Self;
197
198 #[inline]
199 fn not(self) -> Self::Output {
200 Self(!self.0)
201 }
202}
203
204impl core::fmt::Debug for Missing {
205 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
206 f.debug_tuple("Missing")
207 .field(&format_args!("{:#010b}", self.0))
208 .finish()
209 }
210}