wolf-graph-dot 0.1.0

Adds support for generating Graphviz DOT files from wolf-graph graphs.
Documentation
use std::fmt;

#[derive(Debug, Clone, PartialEq)]
pub enum Color {
    Rgb(u8, u8, u8, Option<u8>),
    Hsv(f64, f64, f64),
    X11(&'static str),
    Svg(&'static str),
    Brewer(BrewerScheme, usize, usize),
}

impl Color {
    pub fn rgb(r: u8, g: u8, b: u8, a: Option<u8>) -> Color {
        Color::Rgb(r, g, b, a)
    }

    pub fn hsv(h: f64, s: f64, v: f64) -> Color {
        Color::Hsv(h, s, v)
    }

    pub fn x11(color_name: &'static str) -> Color {
        Color::X11(color_name)
    }

    pub fn svg(color_name: &'static str) -> Color {
        Color::Svg(color_name)
    }

    pub fn brewer(scheme: BrewerScheme, index: usize, max_index: usize) -> Color {
        Color::Brewer(scheme, index, max_index)
    }

    pub const RED: Color = Color::X11("red");
    pub const GREEN: Color = Color::X11("green");
    pub const BLUE: Color = Color::X11("blue");
    pub const CYAN: Color = Color::X11("cyan");
    pub const MAGENTA: Color = Color::X11("magenta");
    pub const YELLOW: Color = Color::X11("yellow");
    pub const BLACK: Color = Color::X11("black");
    pub const WHITE: Color = Color::X11("white");
    pub const GRAY: Color = Color::X11("gray");

    pub fn scheme_name(&self) -> Option<String> {
        match self {
            Color::Rgb(_, _, _, _) | Color::Hsv(_, _, _) => None,
            Color::X11(_)  => Some("x11".to_string()),
            Color::Svg(_) => Some("svg".to_string()),
            Color::Brewer(scheme, _, max_index) => Some(format!("{}{}", scheme, max_index)),
        }
    }

    pub fn color_name(&self) -> String {
        match self {
            Color::Rgb(r, g, b, a) => {
                let components = vec![Some(r), Some(g), Some(b), a.as_ref()].into_iter().flatten().map(Color::hex_byte).collect::<String>();
                format!("#{}", components)
            },
            Color::Hsv(h, s, v) => format!("{} {} {}", h, s, v),
            Color::X11(color_name) => color_name.to_string(),
            Color::Svg(color_name) => color_name.to_string(),
            Color::Brewer(_, index, _) => index.to_string(),
        }
    }

    fn hex_byte(n: &u8) -> String {
        format!("{:02x}", n)
    }

    pub fn full_color_name(&self) -> String {
        let mut components = Vec::new();
        if let Some(scheme_name) = self.scheme_name() {
            components.push(scheme_name);
        }
        components.push(self.color_name());
        components.join("/")
    }
}

impl fmt::Display for Color {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.color_name())
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BrewerScheme {
    // Sequential
    Blues,
    BuGn,
    BuPu,
    GnBu,
    Greens,
    Greys,
    Oranges,
    OrRd,
    PuBu,
    PuBuGn,
    PuRd,
    Purples,
    RdPu,
    Reds,
    YlGn,
    YlGnBu,
    YlOrBr,
    YlOrRd,

    // Divergent
    BrBG,
    PiYG,
    PRGn,
    PuOr,
    RdBu,
    RdGy,
    RdYlBu,
    RdYlGn,
    Spectral,

    // Qualitative
    Accent,
    Dark2,
    Paired,
    Pastel1,
    Pastel2,
    Set1,
    Set2,
    Set3,
}

impl fmt::Display for BrewerScheme {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}