farver 3.2.1

A Rust color library with easy transformation of colors with less functions.
Documentation
use serde::de::Error;
use serde::{de::Visitor, Deserialize, Serialize, Serializer};
use std::num::ParseIntError;

use crate::Color;

macro_rules! impl_serialize {
    ($x:ident) => (
        impl Serialize for crate::$x
        {
            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
            where
                S: Serializer,
            {
                serializer.serialize_str(&self.to_hex())
            }
        }
    );
    ($x:ident, $($y:ident),+ $(,)?) => (
        impl_serialize!($x);

        impl_serialize!($($y),+);
    );
}

impl_serialize!(RGB, RGBA, HSL, HSLA);

struct RgbVisitor;
impl<'de> Visitor<'de> for RgbVisitor {
    type Value = crate::RGB;

    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        formatter.write_str("a string in the format of rrggbb")
    }

    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        let err = Err(serde::de::Error::invalid_value(
            serde::de::Unexpected::Str(v),
            &self,
        ));
        if v.len() != 7 {
            return err;
        }

        if let Some('#') = v.chars().next() {
            let values: Vec<u8> = match (1..v.len())
                .step_by(2)
                .map(|i| u8::from_str_radix(&v[i..i + 2], 16))
                .collect::<Result<Vec<u8>, ParseIntError>>()
            {
                Ok(v) => v,
                Err(_) => return err,
            };
            unsafe {
                Ok(crate::rgb(
                    *values.get_unchecked(0),
                    *values.get_unchecked(1),
                    *values.get_unchecked(2),
                ))
            }
        } else {
            err
        }
    }

    fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
    where
        E: Error,
    {
        self.visit_str(&v)
    }
}
struct RgbaVisitor;
impl<'de> Visitor<'de> for RgbaVisitor {
    type Value = crate::RGBA;

    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        formatter.write_str("a string in the format of rrggbbaa")
    }

    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        let err = Err(serde::de::Error::invalid_value(
            serde::de::Unexpected::Str(v),
            &self,
        ));
        if v.len() != 9 {
            return err;
        }

        if let Some('#') = v.chars().next() {
            let values: Vec<u8> = match (1..v.len())
                .step_by(2)
                .map(|i| u8::from_str_radix(&v[i..i + 2], 16))
                .collect::<Result<Vec<u8>, ParseIntError>>()
            {
                Ok(v) => v,
                Err(_) => return err,
            };
            unsafe {
                Ok(crate::rgba(
                    *values.get_unchecked(0),
                    *values.get_unchecked(1),
                    *values.get_unchecked(2),
                    *values.get_unchecked(3) as f32 / 255.,
                ))
            }
        } else {
            err
        }
    }

    fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
    where
        E: Error,
    {
        self.visit_str(&v)
    }
}

impl<'de> Deserialize<'de> for crate::RGB {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        deserializer.deserialize_string(RgbVisitor)
    }
}
impl<'de> Deserialize<'de> for crate::HSL {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        deserializer
            .deserialize_string(RgbVisitor)
            .map(|c| c.to_hsl())
    }
}
impl<'de> Deserialize<'de> for crate::RGBA {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        deserializer.deserialize_string(RgbaVisitor)
    }
}
impl<'de> Deserialize<'de> for crate::HSLA {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        deserializer
            .deserialize_string(RgbaVisitor)
            .map(|c| c.to_hsla())
    }
}

#[cfg(test)]
mod tests {
    use serde::Deserialize;

    #[test]
    fn no_alpha_json_deserializing() {
        let input_str = r##"{"color": "#010203"}"##;
        #[derive(Deserialize, Debug, PartialEq)]
        struct Test {
            color: crate::RGB,
        }
        let t: Test = serde_json::from_str(input_str).unwrap();
        assert_eq!(
            t,
            Test {
                color: crate::rgb(1, 2, 3)
            }
        )
    }

    #[cfg(test)]
    #[test]
    fn alpha_json_deserializing() {
        let input_str = r##"{"color": "#010203FF"}"##;
        #[derive(Deserialize, Debug, PartialEq)]
        struct Test {
            color: crate::RGBA,
        }
        let t: Test = serde_json::from_str(input_str).unwrap();
        assert_eq!(
            t,
            Test {
                color: crate::rgba(1, 2, 3, 1.)
            }
        )
    }
}