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}