charming 0.6.0

A visualization library for Rust
Documentation
use serde::{de::Visitor, Deserialize, Deserializer, Serialize};
use std::fmt;

#[derive(Serialize, Deserialize, Debug, PartialEq, PartialOrd, Clone, Copy)]
#[serde(rename_all = "camelCase")]
pub enum FontStyle {
    Normal,
    Italic,
    Oblique,
}

#[derive(Debug, PartialEq, PartialOrd, Clone)]
pub enum FontWeight {
    Normal,
    Bold,
    Bolder,
    Lighter,
    Number(i32),
    Custom(String),
}
impl<S> From<S> for FontWeight
where
    S: Into<String>,
{
    fn from(s: S) -> Self {
        let s = s.into();
        match s.as_str() {
            "normal" => FontWeight::Normal,
            "bold" => FontWeight::Bold,
            "bolder" => FontWeight::Bolder,
            "lighter" => FontWeight::Lighter,
            _ => FontWeight::Custom(s),
        }
    }
}

impl Serialize for FontWeight {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        match self {
            FontWeight::Normal => serializer.serialize_str("normal"),
            FontWeight::Bold => serializer.serialize_str("bold"),
            FontWeight::Bolder => serializer.serialize_str("bolder"),
            FontWeight::Lighter => serializer.serialize_str("lighter"),
            FontWeight::Number(num) => serializer.serialize_i32(*num),
            FontWeight::Custom(val) => serializer.serialize_str(val),
        }
    }
}

impl<'de> Deserialize<'de> for FontWeight {
    fn deserialize<D>(deserializer: D) -> Result<FontWeight, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct FontWeightVisitor;

        impl serde::de::Visitor<'_> for FontWeightVisitor {
            type Value = FontWeight;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a string like 'normal' or an integer font weight")
            }

            fn visit_str<E>(self, value: &str) -> Result<FontWeight, E>
            where
                E: serde::de::Error,
            {
                match value {
                    "normal" => Ok(FontWeight::Normal),
                    "bold" => Ok(FontWeight::Bold),
                    "bolder" => Ok(FontWeight::Bolder),
                    "lighter" => Ok(FontWeight::Lighter),
                    other => Ok(FontWeight::Custom(other.to_string())),
                }
            }

            fn visit_i64<E>(self, value: i64) -> Result<FontWeight, E>
            where
                E: serde::de::Error,
            {
                Ok(FontWeight::Number(value as i32))
            }

            fn visit_u64<E>(self, value: u64) -> Result<FontWeight, E>
            where
                E: serde::de::Error,
            {
                Ok(FontWeight::Number(value as i32))
            }
        }

        deserializer.deserialize_any(FontWeightVisitor)
    }
}

#[derive(Debug, PartialEq, PartialOrd, Clone)]
pub enum FontFamily {
    Serif,
    SansSerif,
    MonoSpace,
    Cursive,
    Fantasy,
    Custom(String),
}

impl<S> From<S> for FontFamily
where
    S: Into<String>,
{
    fn from(s: S) -> Self {
        let s = s.into();
        match s.as_str() {
            "serif" => FontFamily::Serif,
            "sans-serif" => FontFamily::SansSerif,
            "monospace" => FontFamily::MonoSpace,
            "cursive" => FontFamily::Cursive,
            "fantasy" => FontFamily::Fantasy,
            _ => FontFamily::Custom(s),
        }
    }
}

impl Serialize for FontFamily {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        match self {
            FontFamily::Serif => serializer.serialize_str("serif"),
            FontFamily::SansSerif => serializer.serialize_str("sans-serif"),
            FontFamily::MonoSpace => serializer.serialize_str("monospace"),
            FontFamily::Cursive => serializer.serialize_str("cursive"),
            FontFamily::Fantasy => serializer.serialize_str("fantasy"),
            FontFamily::Custom(val) => serializer.serialize_str(val),
        }
    }
}

impl<'de> Deserialize<'de> for FontFamily {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct FontFamilyVisitor;

        impl Visitor<'_> for FontFamilyVisitor {
            type Value = FontFamily;

            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                formatter.write_str("a string representing a font family")
            }

            fn visit_str<E>(self, value: &str) -> Result<FontFamily, E>
            where
                E: serde::de::Error,
            {
                match value {
                    "serif" => Ok(FontFamily::Serif),
                    "sans-serif" => Ok(FontFamily::SansSerif),
                    "monospace" => Ok(FontFamily::MonoSpace),
                    "cursive" => Ok(FontFamily::Cursive),
                    "fantasy" => Ok(FontFamily::Fantasy),
                    custom => Ok(FontFamily::Custom(custom.to_string())),
                }
            }
        }

        deserializer.deserialize_str(FontFamilyVisitor)
    }
}

#[cfg(test)]
#[test]
fn font_style() {
    let normal = serde_json::to_string(&FontStyle::Normal).unwrap();
    let italic = serde_json::to_string(&FontStyle::Italic).unwrap();
    let oblique = serde_json::to_string(&FontStyle::Oblique).unwrap();

    assert_eq!("\"normal\"", normal);
    assert_eq!("\"italic\"", italic);
    assert_eq!("\"oblique\"", oblique);
}

#[test]
fn font_weight() {
    let normal = serde_json::to_string(&FontWeight::Normal).unwrap();
    let bold = serde_json::to_string(&FontWeight::Bold).unwrap();
    let bolder = serde_json::to_string(&FontWeight::Bolder).unwrap();
    let lighter = serde_json::to_string(&FontWeight::Lighter).unwrap();
    let number = serde_json::to_string(&FontWeight::Number(100)).unwrap();
    let custom = serde_json::to_string(&FontWeight::Custom("test".to_string())).unwrap();

    assert_eq!("\"normal\"", normal);
    assert_eq!("\"bold\"", bold);
    assert_eq!("\"bolder\"", bolder);
    assert_eq!("\"lighter\"", lighter);
    assert_eq!("100", number);
    assert_eq!("\"test\"", custom);
}

#[test]
fn font_family() {
    let serif = serde_json::to_string(&FontFamily::Serif).unwrap();
    let sans_serif = serde_json::to_string(&FontFamily::SansSerif).unwrap();
    let monospace = serde_json::to_string(&FontFamily::MonoSpace).unwrap();
    let cursive = serde_json::to_string(&FontFamily::Cursive).unwrap();
    let fantasy = serde_json::to_string(&FontFamily::Fantasy).unwrap();
    let custom = serde_json::to_string(&FontFamily::Custom("test".to_string())).unwrap();

    assert_eq!("\"serif\"", serif);
    assert_eq!("\"sans-serif\"", sans_serif);
    assert_eq!("\"monospace\"", monospace);
    assert_eq!("\"cursive\"", cursive);
    assert_eq!("\"fantasy\"", fantasy);
    assert_eq!("\"test\"", custom);
}