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