vectordraw 0.1.2

A library for vector drawing with multiple output types
Documentation
use super::backend::*;
use std::io::{Error, Write};

pub struct SvgBackend<W> {
    pub out: W,
    pub float_precision: usize
}

impl <W: Write> SvgBackend<W> {
    pub fn new(mut out: W) -> Result<SvgBackend<W>, Error> {
        write!(out, "<svg xmlns=\"http://www.w3.org/2000/svg\">\n")?;
        Ok(SvgBackend {
            out: out,
            float_precision: 2,
        })
    }
}

impl <W: Write> DrawBackend for SvgBackend<W> {
    type Error = Error;

    fn apply(&mut self, command: Command) -> Result<(), Error>{
        use super::backend::Command::*;

        match command {
            StartShape(options) => write!(&mut self.out, r#"    <path d=""#),
            MoveTo { x , y } => write!(&mut self.out, "M{:.p$},{:.p$} ", x, y, p=self.float_precision),
            LineTo { x, y } => write!(&mut self.out, "L{:.p$},{:.p$} ", x, y, p=self.float_precision),
            CubicCurveTo { cx1, cy1, cx2, cy2, x, y, } => unimplemented!(),
            QuadraticCurveTo { cx, cy, x, y, } => unimplemented!(),
            ArcTo { rx, ry, rotation, large_arc, sweep, x, y, } => unimplemented!(),
            CloseShape => writeln!(&mut self.out, r#"z"/>"#),
            EndShape => writeln!(&mut self.out, r#""/>"#),
        }
    }
    fn close(mut self) -> Result<(), Error> {
        write!(&mut self.out, "</svg>")
    }
}

#[cfg(test)]
mod test {
    use super::super::*;
    use super::*;

    fn run_in_canvas<F>(f: F) -> String
    where F: FnOnce(&mut Canvas<SvgBackend<&mut Vec<u8>>>) -> Result<(), std::io::Error> {
        let mut buffer: Vec<u8> = Vec::new();
        {
            let mut canvas = Canvas::new(SvgBackend::new(&mut buffer).unwrap());
            f(&mut canvas).unwrap();
            canvas.close().unwrap();
        }
        return String::from_utf8(buffer).unwrap();
    }

    #[test]
    fn empty() {
        assert_eq!(run_in_canvas(|canvas| {
            Ok(())
        }).trim(), r#"
<svg xmlns="http://www.w3.org/2000/svg">
</svg>
        "#.trim())
    }

    #[test]
    fn empty_polygon() {
        assert_eq!(run_in_canvas(|canvas| {
            canvas.draw_closed_polygon(&[], DrawOptions::default())?;
            Ok(())
        }).trim(), r#"
<svg xmlns="http://www.w3.org/2000/svg">
</svg>
        "#.trim())
    }

    #[test]
    fn triangle_polygon() {
        assert_eq!(run_in_canvas(|canvas| {
            canvas.draw_closed_polygon(&[(0.0, 0.0), (0.0, 50.0), (50.0, 0.0)], DrawOptions::default())?;
            Ok(())
        }).trim(), r#"
<svg xmlns="http://www.w3.org/2000/svg">
    <path d="M0,0 L0,50 L50,0 z"/>
</svg>
        "#.trim())
    }

    #[test]
    fn triangle_polygon_reversed() {
        assert_eq!(run_in_canvas(|canvas| {
            canvas.draw_closed_polygon(&[(50.0, 0.0), (0.0, 50.0), (0.0, 0.0)], DrawOptions::default())?;
            Ok(())
        }).trim(), r#"
<svg xmlns="http://www.w3.org/2000/svg">
    <path d="M0,0 L0,50 L50,0 z"/>
</svg>
        "#.trim())
    }

    #[test]
    fn triangle_polygon_reversed_with_holes() {
        assert_eq!(run_in_canvas(|canvas| {
            canvas.draw_holy_polygon(
                vec![&[(50.0, 0.0), (0.0, 50.0), (0.0, 0.0)] as &[_]],
                vec![&[(30.0, 10.0), (10.0, 30.0), (10.0, 10.0)] as &[_]],
                DrawOptions::default()
            )
        }).trim(), r#"
<svg xmlns="http://www.w3.org/2000/svg">
    <path d="M50,0 L0,0 L0,50 L50,0 M30,10 L10,30 L10,10 L30,10 "/>
</svg>
        "#.trim())
    }
}