Sfoglia il codice sorgente

Thread writer abstraction through AsSVG

Getty Ritter 5 anni fa
parent
commit
5e66bb3fef
1 ha cambiato i file con 41 aggiunte e 38 eliminazioni
  1. 41 38
      src/lib.rs

+ 41 - 38
src/lib.rs

@@ -1,5 +1,6 @@
 use std::fmt::Display;
 use std::fmt::{Formatter, Error};
+use std::io;
 use std::io::Write;
 
 /// An SVG document
@@ -20,24 +21,27 @@ impl Display for Inches {
 
 fn inches(amt: f64) -> Inches { Inches { amt } }
 
-fn xml_tag(w: &mut Vec<u8>, name: &str, attrs: &[(&str, &Display)]) {
-    write!(w, "<{}", name);
+fn xml_tag(w: &mut Write, name: &str, attrs: &[(&str, &Display)]) -> io::Result<()> {
+    write!(w, "<{}", name)?;
     for &(k, v) in attrs {
-        write!(w, " {}=\"{}\"", k, v);
+        write!(w, " {}=\"{}\"", k, v)?;
     }
-    writeln!(w, "/>");
+    writeln!(w, "/>")?;
+    Ok(())
 }
 
-fn xml_open(w: &mut Vec<u8>, name: &str, attrs: &[(&str, &Display)]) {
-    write!(w, "<{}", name);
+fn xml_open(w: &mut Write, name: &str, attrs: &[(&str, &Display)]) -> io::Result<()> {
+    write!(w, "<{}", name)?;
     for &(k, v) in attrs {
-        write!(w, " {}=\"{}\"", k, v);
+        write!(w, " {}=\"{}\"", k, v)?;
     }
-    writeln!(w, ">");
+    writeln!(w, ">")?;
+    Ok(())
 }
 
-fn xml_close(w: &mut Vec<u8>, name: &str) {
-    write!(w, "</{}>", name);
+fn xml_close(w: &mut Write, name: &str) -> io::Result<()> {
+    write!(w, "</{}>", name)?;
+    Ok(())
 }
 
 /// Create a new empty SVG document of the specified width and height
@@ -50,24 +54,21 @@ pub fn svg(w: f64, h: f64) -> SVG {
 
 impl SVG {
     /// Print this SVG document to stdout
-    pub fn to_stdout(self) {
-        let buf = self.to_bytes();
-        println!("{}", String::from_utf8(buf).unwrap());
+    pub fn to_stdout(self) -> io::Result<()> {
+        self.write_svg(&mut std::io::stdout())
     }
 
-    /// Write this SVG document to a file
-    pub fn to_file<W: Write>(self, w: &mut W) -> Result<(), std::io::Error> {
-        let buf = self.to_bytes();
-        w.write(&buf)?;
-        Ok(())
+    pub fn to_bytes(self) -> io::Result<Vec<u8>> {
+        let mut buf = Vec::new();
+        self.write_svg(&mut buf)?;
+        Ok(buf)
     }
 
-    pub fn to_bytes(self) -> Vec<u8> {
-        let mut buf = Vec::new();
+    pub fn write_svg<W: Write>(self, buf: &mut W) -> io::Result<()> {
         let (w, h) = self.size;
-        writeln!(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+        writeln!(buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>")?;
         xml_open(
-            &mut buf, "svg",
+            buf, "svg",
             &[("xmlns", &"http://www.w3.org/2000/svg"),
               ("version", &"1.1"),
               ("width", &inches(w)),
@@ -75,12 +76,11 @@ impl SVG {
               ("viewBox", &format!("0 0 {} {}", w, h)),
               ("stroke-width", &"0.0001in"),
             ],
-        );
+        )?;
         for elem in self.stuff {
-            elem.draw_svg(&mut buf);
+            elem.draw_svg(buf)?;
         }
-        xml_close(&mut buf, "svg");
-        buf
+        xml_close(buf, "svg")
     }
 
     /// Add a new drawable thing to this SVG document
@@ -94,7 +94,7 @@ impl SVG {
 /// The AsSVG trait represents things which can be rendered to an SVG
 /// canvas.
 pub trait AsSVG {
-    fn draw_svg(&self, buf: &mut Vec<u8>);
+    fn draw_svg(&self, buf: &mut Write) -> io::Result<()>;
     // This is a bit of a hack to make sure that all of our types live
     // long enough: it's now on the implementer of AsSVG to box it up
     // and make sure that we can keep a trait object around.
@@ -110,7 +110,7 @@ pub struct Line {
 }
 
 impl AsSVG for Line {
-    fn draw_svg(&self, buf: &mut Vec<u8>) {
+    fn draw_svg(&self, buf: &mut Write) -> io::Result<()> {
         if self.points.len() == 0 {
             // if there are no later points, then we just draw a
             // 'point' at the starting position, which is just a tiny
@@ -120,10 +120,10 @@ impl AsSVG for Line {
                 buf, "circle",
                 &[("cx", &x),
                   ("cy", &y),
-                  ("r", &"0.01in"),
+                  ("r", &"0.01"),
                   ("fill", &"black"),
                 ],
-            );
+            )
         } else {
             // Otherwise, we draw a path, which mean assembling this
             // somewhat wonky path field
@@ -131,17 +131,20 @@ impl AsSVG for Line {
             let path = {
                 let mut path = Vec::new();
                 let (x, y) = self.start;
-                write!(&mut path, "M{} {}", x, y);
+                write!(&mut path, "M{} {}", x, y)?;
                 for &(x, y) in self.points.iter() {
-                    write!(&mut path, " L{} {}", x, y);
+                    write!(&mut path, " L{} {}", x, y)?;
                 }
                 String::from_utf8(path).unwrap()
             };
 
             xml_tag(
                 buf, "path",
-                &[("d", &path), ("stroke", &"black")],
-            );
+                &[("d", &path),
+                  ("stroke", &"black"),
+                  ("fill", &"none"),
+                ],
+            )
         }
     }
 
@@ -181,7 +184,7 @@ pub fn rect(position: (f64, f64), size: (f64, f64)) -> Rect {
 }
 
 impl AsSVG for Rect {
-    fn draw_svg(&self, buf: &mut Vec<u8>) {
+    fn draw_svg(&self, buf: &mut Write) -> io::Result<()> {
         let (x, y) = self.position;
         let (w, h) = self.size;
         xml_tag(
@@ -193,7 +196,7 @@ impl AsSVG for Rect {
               ("stroke", &"black"),
               ("fill", &"white"),
             ]
-        );
+        )
     }
 
     fn consume(self) -> Box<AsSVG> {
@@ -212,7 +215,7 @@ pub fn circle(position: (f64, f64), radius: f64) -> Circle {
 }
 
 impl AsSVG for Circle {
-    fn draw_svg(&self, buf: &mut Vec<u8>) {
+    fn draw_svg(&self, buf: &mut Write) -> io::Result<()> {
         let (x, y) = self.position;
         let r = self.radius;
         xml_tag(
@@ -223,7 +226,7 @@ impl AsSVG for Circle {
               ("stroke", &"black"),
               ("fill", &"white"),
             ]
-        );
+        )
     }
 
     fn consume(self) -> Box<AsSVG> {