decal 0.6.0

Declarative DSL for describing scenes and rendering them to SVG or PNG
Documentation
use crate::{
    paint::ResourceIri,
    utils::ElementWriter,
};
use std::fmt::{
    Display,
    Formatter,
};

/// The SVG path element.
#[derive(Debug, Hash, Eq, PartialEq, Clone, Default)]
pub(crate) struct Path(String);

impl Path {
    /// Builds a [`Path`] by writing SVG content into a buffer.
    ///
    /// # Arguments
    /// - `write_fn`: The closure used to write SVG content into the path.
    ///
    /// # Returns
    /// - [`Self`] on success.
    /// - [`std::fmt::Error`] if writing fails.
    pub(crate) fn build<F>(write_fn: F) -> Result<Self, std::fmt::Error>
    where
        F: FnOnce(&mut String) -> std::fmt::Result,
    {
        let mut data = String::new();
        write_fn(&mut data)?;
        Ok(Path(data))
    }
}

impl ResourceIri for Path {}

impl Display for Path {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        ElementWriter::new(f, "path")?
            .attr("id", (self.iri(),))?
            .attr("d", self.0.as_str())?
            .close()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::test_utils::assert_xml;
    use std::fmt::Write;

    #[test]
    fn renders() {
        let path = Path::build(|out| out.write_str("data")).unwrap();
        assert_xml(
            path.to_string(),
            format!(r#"<path id="{}" d="data" />"#, path.iri()),
        );
    }
}