serenity/model/colour.rs
1// Disable this lint to avoid it wanting to change `0xABCDEF` to `0xAB_CDEF`.
2#![allow(clippy::unreadable_literal)]
3
4/// A utility struct to help with working with the basic representation of a colour.
5///
6/// This is particularly useful when working with a [`Role`]'s colour, as the API works with an
7/// integer value instead of an RGB value.
8///
9/// Instances can be created by using the struct's associated functions. These produce presets
10/// equivalent to those found in the official client's colour picker.
11///
12/// # Examples
13///
14/// Passing in a role's colour, and then retrieving its green component via [`Self::g`]:
15///
16/// ```rust
17/// # use serenity::json::{json, from_value};
18/// # use serenity::model::guild::Role;
19/// # use serenity::model::id::RoleId;
20/// # use serenity::model::id::GuildId;
21/// # use serenity::model::permissions;
22/// #
23/// # fn main() {
24/// # let role = from_value::<Role>(json!({
25/// # "color": Colour::BLURPLE,
26/// # "hoist": false,
27/// # "id": RoleId::new(1),
28/// # "guild_id": GuildId::new(2),
29/// # "managed": false,
30/// # "mentionable": false,
31/// # "name": "test",
32/// # "permissions": permissions::PRESET_GENERAL,
33/// # "position": 7,
34/// # })).unwrap();
35/// #
36/// use serenity::model::Colour;
37///
38/// // assuming a `role` has already been bound
39///
40/// let green = role.colour.g();
41///
42/// println!("The green component is: {}", green);
43/// # }
44/// ```
45///
46/// Creating an instance with the [`Self::DARK_TEAL`] preset:
47///
48/// ```rust
49/// use serenity::model::Colour;
50///
51/// let colour = Colour::DARK_TEAL;
52///
53/// assert_eq!(colour.tuple(), (17, 128, 106));
54/// ```
55///
56/// Colours can also be directly compared for equivalence:
57///
58/// ```rust
59/// use serenity::model::Colour;
60///
61/// let blitz_blue = Colour::BLITZ_BLUE;
62/// let fooyoo = Colour::FOOYOO;
63/// let fooyoo2 = Colour::FOOYOO;
64/// assert!(blitz_blue != fooyoo);
65/// assert_eq!(fooyoo, fooyoo2);
66/// assert!(blitz_blue > fooyoo);
67/// ```
68///
69/// [`Role`]: crate::model::guild::Role
70#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
71#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
72pub struct Colour(pub u32);
73
74pub type Color = Colour;
75
76impl Colour {
77 /// Generates a new Colour with the given integer value set.
78 ///
79 /// # Examples
80 ///
81 /// Create a new Colour, and then ensure that its inner value is equivalent to a specific RGB
82 /// value, retrieved via [`Self::tuple`]:
83 ///
84 /// ```rust
85 /// use serenity::model::Colour;
86 ///
87 /// let colour = Colour::new(6573123);
88 ///
89 /// assert_eq!(colour.tuple(), (100, 76, 67));
90 /// ```
91 #[inline]
92 #[must_use]
93 pub const fn new(value: u32) -> Colour {
94 Colour(value)
95 }
96
97 /// Generates a new Colour from an RGB value, creating an inner u32 representation.
98 ///
99 /// # Examples
100 ///
101 /// Creating a [`Colour`] via its RGB values will set its inner u32 correctly:
102 ///
103 /// ```rust
104 /// use serenity::model::Colour;
105 ///
106 /// assert!(Colour::from_rgb(255, 0, 0).0 == 0xFF0000);
107 /// assert!(Colour::from_rgb(217, 23, 211).0 == 0xD917D3);
108 /// ```
109 ///
110 /// And you can then retrieve those same RGB values via its methods:
111 ///
112 /// ```rust
113 /// use serenity::model::Colour;
114 ///
115 /// let colour = Colour::from_rgb(217, 45, 215);
116 ///
117 /// assert_eq!(colour.r(), 217);
118 /// assert_eq!(colour.g(), 45);
119 /// assert_eq!(colour.b(), 215);
120 /// assert_eq!(colour.tuple(), (217, 45, 215));
121 /// ```
122 // Clippy wants to use `u32::from` instead `as`-casts,
123 // but this not doable as `u32::from` is not a const fn.
124 #[allow(clippy::cast_lossless)]
125 #[must_use]
126 pub const fn from_rgb(red: u8, green: u8, blue: u8) -> Colour {
127 Colour((red as u32) << 16 | (green as u32) << 8 | blue as u32)
128 }
129
130 /// Returns the red RGB component of this Colour.
131 ///
132 /// # Examples
133 ///
134 /// ```rust
135 /// use serenity::model::Colour;
136 ///
137 /// assert_eq!(Colour::new(6573123).r(), 100);
138 /// ```
139 #[must_use]
140 pub const fn r(self) -> u8 {
141 ((self.0 >> 16) & 255) as u8
142 }
143
144 /// Returns the green RGB component of this Colour.
145 ///
146 /// # Examples
147 ///
148 /// ```rust
149 /// use serenity::model::Colour;
150 ///
151 /// assert_eq!(Colour::new(6573123).g(), 76);
152 /// ```
153 #[must_use]
154 pub const fn g(self) -> u8 {
155 ((self.0 >> 8) & 255) as u8
156 }
157
158 /// Returns the blue RGB component of this Colour.
159 ///
160 /// # Examples
161 ///
162 /// ```rust
163 /// use serenity::model::Colour;
164 ///
165 /// assert_eq!(Colour::new(6573123).b(), 67);
166 /// ```
167 #[must_use]
168 pub const fn b(self) -> u8 {
169 (self.0 & 255) as u8
170 }
171
172 /// Returns a tuple of the red, green, and blue components of this Colour.
173 ///
174 /// This is equivalent to creating a tuple with the return values of [`Self::r`], [`Self::g`],
175 /// and [`Self::b`].
176 ///
177 /// # Examples
178 ///
179 /// ```rust
180 /// use serenity::model::Colour;
181 ///
182 /// assert_eq!(Colour::new(6573123).tuple(), (100, 76, 67));
183 /// ```
184 #[must_use]
185 pub const fn tuple(self) -> (u8, u8, u8) {
186 (self.r(), self.g(), self.b())
187 }
188
189 /// Returns a hexadecimal string of this Colour.
190 ///
191 /// This is equivalent to passing the integer value through [`std::fmt::UpperHex`] with 0
192 /// padding and 6 width.
193 ///
194 /// # Examples
195 ///
196 /// ```rust
197 /// use serenity::model::Colour;
198 ///
199 /// assert_eq!(Colour::new(6573123).hex(), "644C43");
200 /// ```
201 #[must_use]
202 pub fn hex(self) -> String {
203 format!("{:06X}", self.0)
204 }
205}
206
207impl From<i32> for Colour {
208 /// Constructs a Colour from a i32.
209 ///
210 /// This is used for functions that accept `Into<Colour>`.
211 ///
212 /// This is useful when providing hex values.
213 ///
214 /// # Examples
215 ///
216 /// ```rust
217 /// use serenity::model::Colour;
218 ///
219 /// assert_eq!(Colour::from(0xDEA584).tuple(), (222, 165, 132));
220 /// ```
221 fn from(value: i32) -> Colour {
222 Colour(value as u32)
223 }
224}
225
226impl From<u32> for Colour {
227 /// Constructs a Colour from a u32.
228 ///
229 /// This is used for functions that accept `Into<Colour>`.
230 ///
231 /// # Examples
232 ///
233 /// ```rust
234 /// use serenity::model::Colour;
235 ///
236 /// assert_eq!(Colour::from(6573123u32).r(), 100);
237 /// ```
238 fn from(value: u32) -> Colour {
239 Colour(value)
240 }
241}
242
243impl From<u64> for Colour {
244 /// Constructs a Colour from a u32.
245 ///
246 /// This is used for functions that accept `Into<Colour>`.
247 ///
248 /// # Examples
249 ///
250 /// ```rust
251 /// use serenity::model::Colour;
252 ///
253 /// assert_eq!(Colour::from(6573123u64).r(), 100);
254 /// ```
255 fn from(value: u64) -> Colour {
256 Colour(value as u32)
257 }
258}
259
260impl From<(u8, u8, u8)> for Colour {
261 /// Constructs a Colour from RGB.
262 fn from((red, green, blue): (u8, u8, u8)) -> Self {
263 Colour::from_rgb(red, green, blue)
264 }
265}
266
267impl Colour {
268 /// Creates a new [`Colour`], setting its RGB value to `(111, 198, 226)`.
269 pub const BLITZ_BLUE: Colour = Colour(0x6FC6E2);
270 /// Creates a new [`Colour`], setting its RGB value to `(52, 152, 219)`.
271 pub const BLUE: Colour = Colour(0x3498DB);
272 /// Creates a new [`Colour`], setting its RGB value to `(114, 137, 218)`.
273 pub const BLURPLE: Colour = Colour(0x7289DA);
274 /// Creates a new [`Colour`], setting its RGB value to `(32, 102, 148)`.
275 pub const DARK_BLUE: Colour = Colour(0x206694);
276 /// Creates a new [`Colour`], setting its RGB value to `(194, 124, 14)`.
277 pub const DARK_GOLD: Colour = Colour(0xC27C0E);
278 /// Creates a new [`Colour`], setting its RGB value to `(31, 139, 76)`.
279 pub const DARK_GREEN: Colour = Colour(0x1F8B4C);
280 /// Creates a new [`Colour`], setting its RGB value to `(96, 125, 139)`.
281 pub const DARK_GREY: Colour = Colour(0x607D8B);
282 /// Creates a new [`Colour`], setting its RGB value to `(173, 20, 87)`.
283 pub const DARK_MAGENTA: Colour = Colour(0xAD1457);
284 /// Creates a new [`Colour`], setting its RGB value to `(168, 67, 0)`.
285 pub const DARK_ORANGE: Colour = Colour(0xA84300);
286 /// Creates a new [`Colour`], setting its RGB value to `(113, 54, 138)`.
287 pub const DARK_PURPLE: Colour = Colour(0x71368A);
288 /// Creates a new [`Colour`], setting its RGB value to `(153, 45, 34)`.
289 pub const DARK_RED: Colour = Colour(0x992D22);
290 /// Creates a new [`Colour`], setting its RGB value to `(17, 128, 106)`.
291 pub const DARK_TEAL: Colour = Colour(0x11806A);
292 /// Creates a new [`Colour`], setting its RGB value to `(84, 110, 122)`.
293 pub const DARKER_GREY: Colour = Colour(0x546E7A);
294 /// Creates a new [`Colour`], setting its RGB value to `(250, 177, 237)`.
295 pub const FABLED_PINK: Colour = Colour(0xFAB1ED);
296 /// Creates a new [`Colour`], setting its RGB value to `(136, 130, 196)`.
297 pub const FADED_PURPLE: Colour = Colour(0x8882C4);
298 /// Creates a new [`Colour`], setting its RGB value to `(17, 202, 128)`.
299 pub const FOOYOO: Colour = Colour(0x11CA80);
300 /// Creates a new [`Colour`], setting its RGB value to `(241, 196, 15)`.
301 pub const GOLD: Colour = Colour(0xF1C40F);
302 /// Creates a new [`Colour`], setting its RGB value to `(186, 218, 85)`.
303 pub const KERBAL: Colour = Colour(0xBADA55);
304 /// Creates a new [`Colour`], setting its RGB value to `(151, 156, 159)`.
305 pub const LIGHT_GREY: Colour = Colour(0x979C9F);
306 /// Creates a new [`Colour`], setting its RGB value to `(149, 165, 166)`.
307 pub const LIGHTER_GREY: Colour = Colour(0x95A5A6);
308 /// Creates a new [`Colour`], setting its RGB value to `(233, 30, 99)`.
309 pub const MAGENTA: Colour = Colour(0xE91E63);
310 /// Creates a new [`Colour`], setting its RGB value to `(230, 131, 151)`.
311 pub const MEIBE_PINK: Colour = Colour(0xE68397);
312 /// Creates a new [`Colour`], setting its RGB value to `(230, 126, 34)`.
313 pub const ORANGE: Colour = Colour(0xE67E22);
314 /// Creates a new [`Colour`], setting its RGB value to `(155, 89, 182)`.
315 pub const PURPLE: Colour = Colour(0x9B59B6);
316 /// Creates a new [`Colour`], setting its RGB value to `(231, 76, 60)`.
317 pub const RED: Colour = Colour(0xE74C3C);
318 /// Creates a new [`Colour`], setting its RGB value to `(117, 150, 255)`.
319 pub const ROHRKATZE_BLUE: Colour = Colour(0x7596FF);
320 /// Creates a new [`Colour`], setting its RGB value to `(246, 219, 216)`.
321 pub const ROSEWATER: Colour = Colour(0xF6DBD8);
322 /// Creates a new [`Colour`], setting its RGB value to `(26, 188, 156)`.
323 pub const TEAL: Colour = Colour(0x1ABC9C);
324}
325
326/// Colour constants used by Discord for their branding, role colour palette, etc.
327pub mod colours {
328 pub mod branding {
329 use super::super::Colour;
330
331 /// Creates a new [`Colour`], setting its value to `rgb(88, 101, 242)`.
332 pub const BLURPLE: Colour = Colour(0x5865F2);
333 /// Creates a new [`Colour`], setting its value to `rgb(87, 242, 135)`.
334 pub const GREEN: Colour = Colour(0x57F287);
335 /// Creates a new [`Colour`], setting its value to `rgb(254, 231, 92)`.
336 pub const YELLOW: Colour = Colour(0xFEE75C);
337 /// Creates a new [`Colour`], setting its value to `rgb(235, 69, 158)`.
338 pub const FUCHSIA: Colour = Colour(0xEB459E);
339 /// Creates a new [`Colour`], setting its value to `rgb(237, 66, 69)`.
340 pub const RED: Colour = Colour(0xED4245);
341 /// Creates a new [`Colour`], setting its value to `rgb(255, 255, 255)`.
342 pub const WHITE: Colour = Colour(0xFFFFFF);
343 /// Creates a new [`Colour`], setting its value to `rgb(35, 39, 42)`.
344 pub const BLACK: Colour = Colour(0x23272A);
345 }
346 pub mod css {
347 use super::super::Colour;
348
349 /// Creates a new [`Colour`], setting its value to `hsl(139, 47.3%, 43.9%)`.
350 pub const POSITIVE: Colour = Colour(0x3BA55D);
351 /// Creates a new [`Colour`], setting its value to `hsl(38, 95.7%, 54.1%)`.
352 pub const WARNING: Colour = Colour(0xFAA81A);
353 /// Creates a new [`Colour`], setting its value to `hsl(359, 82.6%, 59.4%)`.
354 pub const DANGER: Colour = Colour(0xED4245);
355 }
356 pub mod roles {
357 use super::super::Colour;
358
359 /// Creates a new [`Colour`], setting its value to `rgb(153, 170, 181)`.
360 pub const DEFAULT: Colour = Colour(0x99AAB5);
361 /// Creates a new [`Colour`], setting its value to `rgb(26, 188, 156)`.
362 pub const TEAL: Colour = Colour(0x1ABC9C);
363 /// Creates a new [`Colour`], setting its value to `rgb(17, 128, 106)`.
364 pub const DARK_TEAL: Colour = Colour(0x11806A);
365 /// Creates a new [`Colour`], setting its value to `rgb(46, 204, 113)`.
366 pub const GREEN: Colour = Colour(0x2ECC71);
367 /// Creates a new [`Colour`], setting its value to `rgb(31, 139, 76)`.
368 pub const DARK_GREEN: Colour = Colour(0x1F8B4C);
369 /// Creates a new [`Colour`], setting its value to `rgb(52, 152, 219)`.
370 pub const BLUE: Colour = Colour(0x3498DB);
371 /// Creates a new [`Colour`], setting its value to `rgb(32, 102, 148)`.
372 pub const DARK_BLUE: Colour = Colour(0x206694);
373 /// Creates a new [`Colour`], setting its value to `rgb(155, 89, 182)`.
374 pub const PURPLE: Colour = Colour(0x9B59B6);
375 /// Creates a new [`Colour`], setting its value to `rgb(113, 54, 138)`.
376 pub const DARK_PURPLE: Colour = Colour(0x71368A);
377 /// Creates a new [`Colour`], setting its value to `rgb(233, 30, 99)`.
378 pub const MAGENTA: Colour = Colour(0xE91E63);
379 /// Creates a new [`Colour`], setting its value to `rgb(173, 20, 87)`.
380 pub const DARK_MAGENTA: Colour = Colour(0xAD1457);
381 /// Creates a new [`Colour`], setting its value to `rgb(241, 196, 15)`.
382 pub const GOLD: Colour = Colour(0xF1C40F);
383 /// Creates a new [`Colour`], setting its value to `rgb(194, 124, 14)`.
384 pub const DARK_GOLD: Colour = Colour(0xC27C0E);
385 /// Creates a new [`Colour`], setting its value to `rgb(230, 126, 34)`.
386 pub const ORANGE: Colour = Colour(0xE67E22);
387 /// Creates a new [`Colour`], setting its value to `rgb(168, 67, 0)`.
388 pub const DARK_ORANGE: Colour = Colour(0xA84300);
389 /// Creates a new [`Colour`], setting its value to `rgb(231, 76, 60)`.
390 pub const RED: Colour = Colour(0xE74C3C);
391 /// Creates a new [`Colour`], setting its value to `rgb(153, 45, 34)`.
392 pub const DARK_RED: Colour = Colour(0x992D22);
393 /// Creates a new [`Colour`], setting its value to `rgb(149, 165, 166)`.
394 pub const LIGHTER_GREY: Colour = Colour(0x95A5A6);
395 /// Creates a new [`Colour`], setting its value to `rgb(151, 156, 159)`.
396 pub const LIGHT_GREY: Colour = Colour(0x979C9F);
397 /// Creates a new [`Colour`], setting its value to `rgb(96, 125, 139)`.
398 pub const DARK_GREY: Colour = Colour(0x607D8B);
399 /// Creates a new [`Colour`], setting its value to `rgb(84, 110, 122)`.
400 pub const DARKER_GREY: Colour = Colour(0x546E7A);
401 }
402}
403
404#[cfg(test)]
405mod test {
406 use super::Colour;
407
408 #[test]
409 fn new() {
410 assert_eq!(Colour::new(1).0, 1);
411 assert_eq!(Colour::new(u32::MIN).0, u32::MIN);
412 assert_eq!(Colour::new(u32::MAX).0, u32::MAX);
413 }
414
415 #[test]
416 fn from_rgb() {
417 assert_eq!(Colour::from_rgb(255, 0, 0).0, 0xFF0000);
418 assert_eq!(Colour::from_rgb(0, 255, 0).0, 0x00FF00);
419 assert_eq!(Colour::from_rgb(0, 0, 255).0, 0x0000FF);
420 }
421
422 #[test]
423 fn r() {
424 assert_eq!(Colour::new(0x336123).r(), 0x33);
425 }
426
427 #[test]
428 fn g() {
429 assert_eq!(Colour::new(0x336123).g(), 0x61);
430 }
431
432 #[test]
433 fn b() {
434 assert_eq!(Colour::new(0x336123).b(), 0x23);
435 }
436
437 #[test]
438 fn tuple() {
439 assert_eq!(Colour::new(0x336123).tuple(), (0x33, 0x61, 0x23));
440 }
441
442 #[test]
443 fn default() {
444 assert_eq!(Colour::default().0, 0);
445 }
446
447 #[test]
448 fn from() {
449 assert_eq!(Colour::from(7i32).0, 7);
450 assert_eq!(Colour::from(7u32).0, 7);
451 assert_eq!(Colour::from(7u64).0, 7);
452 }
453}