We'll extend our random-number-generating service with two features – generating random colors and shuffling an array of bytes. For the first feature, we need to add the Color struct to hold the color components. Create a new file, color.rs, and add the following code to it:
#[derive(Clone, PartialEq, Eq)]
pub struct Color {
pub red: u8,
pub green: u8,
pub blue: u8,
}
Add two constant colors that we'll use later:
pub const WHITE: Color = Color { red: 0xFF, green: 0xFF, blue: 0xFF };
pub const BLACK: Color = Color { red: 0x00, green: 0x00, blue: 0x00 };
The struct also implements PartialEq and Eq to compare a value with these constants.
We'll use a textual representation of color that's compatible with CSS. We'll support RGB colors in hex format and two textual colors: black and white. To convert a color to a string, implement the Display trait for Color:
impl fmt::Display for Color {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&WHITE => f.write_str("white"),
&BLACK => f.write_str("black"),
color => {
write!(f, "#{:02X}{:02X}{:02X}", color.red, color.green, color.blue)
},
}
}
}
This implementation writes three color components to a string with the '#' prefix. Every color component byte is written in hex format with the '0' prefix for nonsignificant digits and with a width of two characters.
We can now use this formatter to implement the Serialize trait for the Color struct:
impl Serialize for Color {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
This Serialize implementation calls the serialize_str method of the Serializer to store a hex representation of a color to a string. Before implementing a custom deserialization, add all necessary imports to the color.rs file:
use std::fmt;
use std::str::FromStr;
use std::num::ParseIntError;
use serde::{de::{self, Visitor}, Deserialize, Deserializer, Serialize, Serializer};