1use std::borrow::Cow;
2
3use serde::{Deserialize, Serialize};
4
5manual_braid! {
6 pub struct HexColor;
8 pub struct HexColorRef;
9}
10impl_extra!(no_arb, HexColor, HexColorRef);
11
12#[cfg(feature = "arbitrary")]
13impl<'a> arbitrary::Arbitrary<'a> for HexColor {
14 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
15 let mut buff = [0u8; 3];
16 u.fill_buffer(&mut buff)?;
17 Ok(HexColor::from(format!(
18 "#{:02X}{:02X}{:02X}",
19 buff[0], buff[1], buff[2]
20 )))
21 }
22}
23
24#[derive(Debug, PartialEq, Eq, Clone, serde_derive::Deserialize)]
26#[serde(field_identifier, rename_all = "snake_case")]
27pub enum NamedUserColor<'a> {
28 Blue,
30 BlueViolet,
32 CadetBlue,
34 Chocolate,
36 Coral,
38 DodgerBlue,
40 Firebrick,
42 GoldenRod,
44 Green,
46 HotPink,
48 OrangeRed,
50 Red,
52 SeaGreen,
54 SpringGreen,
56 YellowGreen,
58 #[serde(borrow = "'a")]
60 Hex(Cow<'a, HexColorRef>),
61}
62
63#[cfg(feature = "arbitrary")]
64impl<'a> arbitrary::Arbitrary<'a> for NamedUserColor<'a> {
65 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
66 Ok(match u.int_in_range(0..=15)? {
67 0 => NamedUserColor::Blue,
68 1 => NamedUserColor::BlueViolet,
69 2 => NamedUserColor::CadetBlue,
70 3 => NamedUserColor::Chocolate,
71 4 => NamedUserColor::Coral,
72 5 => NamedUserColor::DodgerBlue,
73 6 => NamedUserColor::Firebrick,
74 7 => NamedUserColor::GoldenRod,
75 8 => NamedUserColor::Green,
76 9 => NamedUserColor::HotPink,
77 10 => NamedUserColor::OrangeRed,
78 11 => NamedUserColor::Red,
79 12 => NamedUserColor::SeaGreen,
80 13 => NamedUserColor::SpringGreen,
81 14 => NamedUserColor::YellowGreen,
82 15 => NamedUserColor::Hex(arbitrary::Arbitrary::arbitrary(u)?),
83 _ => unreachable!(),
84 })
85 }
86
87 fn size_hint(depth: usize) -> (usize, Option<usize>) {
88 arbitrary::size_hint::or_all(&[
89 arbitrary::size_hint::and_all(&[]),
90 <Cow<'a, HexColorRef> as arbitrary::Arbitrary>::size_hint(depth),
91 ])
92 }
93}
94
95#[cfg(feature = "zerofrom")]
96impl<'zf, 'zf_inner> zerofrom::ZeroFrom<'zf, NamedUserColor<'zf_inner>> for NamedUserColor<'zf> {
97 fn zero_from(this: &'zf NamedUserColor<'zf_inner>) -> Self {
98 match *this {
99 NamedUserColor::Blue => NamedUserColor::Blue,
100 NamedUserColor::BlueViolet => NamedUserColor::BlueViolet,
101 NamedUserColor::CadetBlue => NamedUserColor::CadetBlue,
102 NamedUserColor::Chocolate => NamedUserColor::Chocolate,
103 NamedUserColor::Coral => NamedUserColor::Coral,
104 NamedUserColor::DodgerBlue => NamedUserColor::DodgerBlue,
105 NamedUserColor::Firebrick => NamedUserColor::Firebrick,
106 NamedUserColor::GoldenRod => NamedUserColor::GoldenRod,
107 NamedUserColor::Green => NamedUserColor::Green,
108 NamedUserColor::HotPink => NamedUserColor::HotPink,
109 NamedUserColor::OrangeRed => NamedUserColor::OrangeRed,
110 NamedUserColor::Red => NamedUserColor::Red,
111 NamedUserColor::SeaGreen => NamedUserColor::SeaGreen,
112 NamedUserColor::SpringGreen => NamedUserColor::SpringGreen,
113 NamedUserColor::YellowGreen => NamedUserColor::YellowGreen,
114 NamedUserColor::Hex(ref __binding_0) => {
115 NamedUserColor::Hex(<Cow<'zf, HexColorRef> as zerofrom::ZeroFrom<
116 'zf,
117 Cow<'zf_inner, HexColorRef>,
118 >>::zero_from(__binding_0))
119 }
120 }
121 }
122}
123
124impl<'a> NamedUserColor<'a> {
125 pub fn to_owned(&self) -> NamedUserColor<'static> {
127 match self {
128 NamedUserColor::Blue => NamedUserColor::Blue,
129 NamedUserColor::BlueViolet => NamedUserColor::BlueViolet,
130 NamedUserColor::CadetBlue => NamedUserColor::CadetBlue,
131 NamedUserColor::Chocolate => NamedUserColor::Chocolate,
132 NamedUserColor::Coral => NamedUserColor::Coral,
133 NamedUserColor::DodgerBlue => NamedUserColor::DodgerBlue,
134 NamedUserColor::Firebrick => NamedUserColor::Firebrick,
135 NamedUserColor::GoldenRod => NamedUserColor::GoldenRod,
136 NamedUserColor::Green => NamedUserColor::Green,
137 NamedUserColor::HotPink => NamedUserColor::HotPink,
138 NamedUserColor::OrangeRed => NamedUserColor::OrangeRed,
139 NamedUserColor::Red => NamedUserColor::Red,
140 NamedUserColor::SeaGreen => NamedUserColor::SeaGreen,
141 NamedUserColor::SpringGreen => NamedUserColor::SpringGreen,
142 NamedUserColor::YellowGreen => NamedUserColor::YellowGreen,
143 NamedUserColor::Hex(hex) => NamedUserColor::Hex(hex.as_ref().to_owned().into()),
144 }
145 }
146
147 pub fn all() -> &'static [NamedUserColor<'static>] {
149 &[
150 NamedUserColor::Blue,
151 NamedUserColor::BlueViolet,
152 NamedUserColor::CadetBlue,
153 NamedUserColor::Chocolate,
154 NamedUserColor::Coral,
155 NamedUserColor::DodgerBlue,
156 NamedUserColor::Firebrick,
157 NamedUserColor::GoldenRod,
158 NamedUserColor::Green,
159 NamedUserColor::HotPink,
160 NamedUserColor::OrangeRed,
161 NamedUserColor::Red,
162 NamedUserColor::SeaGreen,
163 NamedUserColor::SpringGreen,
164 NamedUserColor::YellowGreen,
165 ]
166 }
167
168 pub fn as_hex(&'a self) -> &'a HexColorRef {
170 match self {
171 NamedUserColor::Blue => HexColorRef::from_static("#0000FF"),
172 NamedUserColor::BlueViolet => HexColorRef::from_static("#8A2BE2"),
173 NamedUserColor::CadetBlue => HexColorRef::from_static("#5F9EA0"),
174 NamedUserColor::Chocolate => HexColorRef::from_static("#D2691E"),
175 NamedUserColor::Coral => HexColorRef::from_static("#FF7F50"),
176 NamedUserColor::DodgerBlue => HexColorRef::from_static("#1E90FF"),
177 NamedUserColor::Firebrick => HexColorRef::from_static("#B22222"),
178 NamedUserColor::GoldenRod => HexColorRef::from_static("#DAA520"),
179 NamedUserColor::Green => HexColorRef::from_static("#008000"),
180 NamedUserColor::HotPink => HexColorRef::from_static("#FF69B4"),
181 NamedUserColor::OrangeRed => HexColorRef::from_static("#FF4500"),
182 NamedUserColor::Red => HexColorRef::from_static("#FF0000"),
183 NamedUserColor::SeaGreen => HexColorRef::from_static("#2E8B57"),
184 NamedUserColor::SpringGreen => HexColorRef::from_static("#00FF7F"),
185 NamedUserColor::YellowGreen => HexColorRef::from_static("#ADFF2F"),
186 NamedUserColor::Hex(hex) => hex,
187 }
188 }
189}
190
191impl Serialize for NamedUserColor<'_> {
192 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
193 where S: serde::Serializer {
194 serializer.serialize_str(match self {
195 NamedUserColor::Blue => "blue",
196 NamedUserColor::BlueViolet => "blue_violet",
197 NamedUserColor::CadetBlue => "cadet_blue",
198 NamedUserColor::Chocolate => "chocolate",
199 NamedUserColor::Coral => "coral",
200 NamedUserColor::DodgerBlue => "dodger_blue",
201 NamedUserColor::Firebrick => "firebrick",
202 NamedUserColor::GoldenRod => "golden_rod",
203 NamedUserColor::Green => "green",
204 NamedUserColor::HotPink => "hot_pink",
205 NamedUserColor::OrangeRed => "orange_red",
206 NamedUserColor::Red => "red",
207 NamedUserColor::SeaGreen => "sea_green",
208 NamedUserColor::SpringGreen => "spring_green",
209 NamedUserColor::YellowGreen => "yellow_green",
210 NamedUserColor::Hex(o) => o.as_str(),
211 })
212 }
213}
214
215impl<'a> TryFrom<&'a str> for NamedUserColor<'a> {
216 type Error = serde::de::value::Error;
217
218 fn try_from(s: &'a str) -> Result<Self, Self::Error> {
219 use serde::de::IntoDeserializer;
220
221 NamedUserColor::deserialize(s.into_deserializer())
222 }
223}
224
225impl<'a> From<Cow<'a, HexColorRef>> for NamedUserColor<'a> {
226 fn from(color: Cow<'a, HexColorRef>) -> Self { NamedUserColor::Hex(color) }
227}
228
229impl From<HexColor> for NamedUserColor<'_> {
230 fn from(color: HexColor) -> Self { NamedUserColor::Hex(color.into()) }
231}
232
233impl std::fmt::Display for NamedUserColor<'_> {
234 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.serialize(f) }
235}
236
237#[cfg(test)]
238#[test]
239fn color() {
240 let colors = ["red", "hot_pink", "#9146FF"];
241 let check = vec![
242 NamedUserColor::Red,
243 NamedUserColor::HotPink,
244 NamedUserColor::Hex(HexColorRef::from_static("#9146FF").into()),
245 ];
246 assert_eq!(
247 check,
248 colors
249 .into_iter()
250 .map(|c: &str| c.try_into())
251 .collect::<Result<Vec<NamedUserColor>, serde::de::value::Error>>()
252 .unwrap()
253 );
254 assert_eq!(
255 check.iter().map(|c| c.to_string()).collect::<Vec<_>>(),
256 colors
257 );
258}