strife 0.3.0

A lightweight library for the Discord API.
Documentation
//! Models a color as an integer matching the Discord API representation.

#![allow(clippy::unreadable_literal)]

use std::fmt;

use serde::{Deserialize, Serialize};

/// A color used in the Discord API.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Deserialize, Serialize)]
pub struct Color(u32);

impl Color {
    /// Creates a new `Color` with the given integer value.
    ///
    /// # Notes
    ///
    /// Only the lowest 24-bits are taken into consideration when creating the
    /// color.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use strife::model::color::Color;
    ///
    /// let value = 0x12345678;
    /// let color = Color::new(value);
    ///
    /// assert_ne!(value, color);
    /// assert_eq!(0x345678, color);
    /// ```
    ///
    /// Oversized value:
    ///
    /// ```
    /// use strife::model::color::Color;
    ///
    /// // Oversized value, will be limited to 0x345678.
    /// let value = 0x12345678;
    /// let color = Color::new(value);
    ///
    /// assert_ne!(value, color);
    /// assert_eq!(0x345678, color);
    /// ```
    pub const fn new(value: u32) -> Color {
        Color(value & 0xFFFFFF)
    }

    /// Creates a new `Color` with the given integer value.
    ///
    /// # Safety
    ///
    /// This function is unsafe because it does not check that
    /// `value <= 0xFFFFFF`. If this constraint is violated, undefined behavior
    /// results, as the rest of the library assumes that the color value only
    /// uses the lowest 24-bits.
    pub const unsafe fn new_unchecked(value: u32) -> Color {
        Color(value)
    }

    /// Creates a new `Color` with the given RGB component values.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use strife::model::color::Color;
    ///
    /// let color = Color::rgb(0x42, 0x8C, 0x53);
    ///
    /// assert_eq!(color, Color::new(0x428C53));
    /// ```
    pub const fn rgb(red: u8, green: u8, blue: u8) -> Color {
        Color(((red as u32) << 16) | ((green as u32) << 8) | (blue as u32))
    }

    /// Returns the value of the red RGB component.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use strife::model::color::Color;
    ///
    /// let color = Color::rgb(0x42, 0x8C, 0x53);
    ///
    /// assert_eq!(color.r(), 0x42);
    /// ```
    pub const fn r(self) -> u8 {
        ((self.0 >> 16) & 0xFF) as u8
    }

    /// Returns the value of the green RGB component.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use strife::model::color::Color;
    ///
    /// let color = Color::rgb(0x42, 0x8C, 0x53);
    ///
    /// assert_eq!(color.g(), 0x8C);
    /// ```
    pub const fn g(self) -> u8 {
        ((self.0 >> 8) & 0xFF) as u8
    }

    /// Returns the value of the blue RGB component.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use strife::model::color::Color;
    ///
    /// let color = Color::rgb(0x42, 0x8C, 0x53);
    ///
    /// assert_eq!(color.b(), 0x53);
    /// ```
    pub const fn b(self) -> u8 {
        (self.0 & 0xFF) as u8
    }
}

impl Default for Color {
    fn default() -> Self {
        Color::new(0)
    }
}

impl From<u32> for Color {
    fn from(color: u32) -> Self {
        Color::new(color)
    }
}

impl From<Color> for u32 {
    fn from(color: Color) -> Self {
        color.0
    }
}

impl AsRef<u32> for Color {
    fn as_ref(&self) -> &u32 {
        &self.0
    }
}

impl PartialEq<u32> for Color {
    fn eq(&self, other: &u32) -> bool {
        self.0 == *other
    }
}

impl PartialEq<Color> for u32 {
    fn eq(&self, other: &Color) -> bool {
        other.0 == *self
    }
}

impl fmt::Display for Color {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if f.alternate() {
            write!(f, "rgb({}, {}, {})", self.r(), self.g(), self.b())
        } else {
            self.0.fmt(f)
        }
    }
}

impl fmt::LowerHex for Color {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if f.alternate() {
            f.write_str("0x")?;
        }
        write!(f, "{:06x}", self.0)
    }
}

impl fmt::UpperHex for Color {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if f.alternate() {
            f.write_str("0x")?;
        }
        write!(f, "{:06X}", self.0)
    }
}

impl fmt::Binary for Color {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if f.alternate() {
            f.write_str("0b")?;
        }
        write!(f, "{:024b}", self.0)
    }
}