badgen 0.1.0

Fast and configurable badge generator
Documentation
use core::fmt;

use crate::util::Escape;

pub(crate) struct SvgWrite<W> {
    w: W,
    open: bool,
    #[cfg(feature = "pretty")]
    level: i8,
}

impl<W> SvgWrite<W>
where
    W: fmt::Write,
{
    pub(crate) fn start(w: W) -> Result<Self, fmt::Error> {
        let mut this = Self {
            w,
            open: false,
            #[cfg(feature = "pretty")]
            level: 0,
        };
        this.open("svg")?;
        Ok(this)
    }

    pub(crate) fn open(&mut self, name: &str) -> Result<&mut Self, fmt::Error> {
        self.end_if_open()?;
        #[cfg(feature = "pretty")]
        self.write_indent()?;
        self.w.write_str("<")?;
        self.w.write_str(name)?;
        self.open = true;
        Ok(self)
    }

    pub(crate) fn close(&mut self, name: &str) -> Result<&mut Self, fmt::Error> {
        self.end_if_open()?;
        #[cfg(feature = "pretty")]
        {
            self.indent_delta(-1);
            self.write_indent()?;
        }
        self.w.write_str("</")?;
        self.w.write_str(name)?;
        self.w.write_str(">")?;
        #[cfg(feature = "pretty")]
        self.w.write_char('\n')?;
        Ok(self)
    }

    pub(crate) fn close_inline(&mut self) -> Result<&mut Self, fmt::Error> {
        assert!(self.open);
        self.open = false;
        self.w.write_str("/>")?;
        #[cfg(feature = "pretty")]
        self.w.write_char('\n')?;
        Ok(self)
    }

    #[inline]
    pub(crate) fn attr_fn<F>(&mut self, name: &str, value_fn: F) -> Result<&mut Self, fmt::Error>
    where
        F: FnOnce(&mut W) -> fmt::Result,
    {
        self.w.write_char(' ')?;
        self.w.write_str(name)?;
        self.w.write_str(r#"=""#)?;
        value_fn(&mut self.w)?;
        self.w.write_char('"')?;
        Ok(self)
    }

    pub(crate) fn attr_str(&mut self, name: &str, value: &str) -> Result<&mut Self, fmt::Error> {
        self.attr_fn(name, |w| w.write_str(value))?;
        Ok(self)
    }

    pub(crate) fn attr_int<V>(&mut self, name: &str, value: V) -> Result<&mut Self, fmt::Error>
    where
        V: itoa::Integer,
    {
        self.attr_fn(name, |w| itoa::fmt(w, value))?;
        Ok(self)
    }

    #[allow(dead_code)]
    pub(crate) fn write_value(&mut self, value: &str) -> Result<&mut Self, fmt::Error> {
        Escape(value).fmt(&mut self.w)?;
        self.end_if_open()?;
        Ok(self)
    }

    pub(crate) fn finish(mut self) -> Result<W, fmt::Error> {
        self.close("svg")?;
        Ok(self.w)
    }

    #[cfg(feature = "pretty")]
    fn indent_delta(&mut self, delta: i8) {
        self.level += delta;
    }

    #[cfg(feature = "pretty")]
    #[inline]
    fn write_indent(&mut self) -> fmt::Result {
        for _ in 0..self.level {
            self.w.write_char('\t')?;
        }
        Ok(())
    }

    fn end_if_open(&mut self) -> fmt::Result {
        if self.open {
            self.w.write_char('>')?;
            #[cfg(feature = "pretty")]
            {
                self.indent_delta(1);
                self.w.write_char('\n')?;
            }
            self.open = false;
        }
        Ok(())
    }
}