Skip to main content

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}