svg/lib.rs
1//! An SVG composer and parser.
2//!
3//! ## Example: Composing
4//!
5//! ```
6//! # extern crate svg;
7//! use svg::Document;
8//! use svg::node::element::Path;
9//! use svg::node::element::path::Data;
10//!
11//! # fn main() {
12//! let data = Data::new()
13//! .move_to((10, 10))
14//! .line_by((0, 50))
15//! .line_by((50, 0))
16//! .line_by((0, -50))
17//! .close();
18//!
19//! let path = Path::new()
20//! .set("fill", "none")
21//! .set("stroke", "black")
22//! .set("stroke-width", 3)
23//! .set("d", data);
24//!
25//! let document = Document::new()
26//! .set("viewBox", (0, 0, 70, 70))
27//! .add(path);
28//!
29//! svg::save("image.svg", &document).unwrap();
30//! # std::fs::remove_file("image.svg");
31//! # }
32//! ```
33//!
34//! ## Example: Parsing
35//!
36//! ```
37//! # extern crate svg;
38//! use svg::node::element::path::{Command, Data};
39//! use svg::node::element::tag::Path;
40//! use svg::parser::Event;
41//!
42//! # fn main() {
43//! let path = "image.svg";
44//! # let path = "tests/fixtures/benton.svg";
45//! let mut content = String::new();
46//! for event in svg::open(path, &mut content).unwrap() {
47//! match event {
48//! Event::Tag(Path, _, attributes) => {
49//! let data = attributes.get("d").unwrap();
50//! let data = Data::parse(data).unwrap();
51//! for command in data.iter() {
52//! match command {
53//! &Command::Move(..) => { /* … */ },
54//! &Command::Line(..) => { /* … */ },
55//! _ => {}
56//! }
57//! }
58//! }
59//! _ => {}
60//! }
61//! }
62//! # }
63//! ```
64
65use std::fs::File;
66use std::io::{Read, Result, Write};
67use std::path::Path;
68
69pub mod node;
70pub mod parser;
71
72pub use crate::node::Node;
73pub use crate::parser::Parser;
74
75/// A document.
76pub type Document = node::element::SVG;
77
78/// Open a document.
79pub fn open<T>(path: T, content: &'_ mut String) -> Result<Parser<'_>>
80where
81 T: AsRef<Path>,
82{
83 let mut file = File::open(path)?;
84 file.read_to_string(content)?;
85 read(content)
86}
87
88/// Read a document.
89pub fn read(content: &'_ str) -> Result<Parser<'_>> {
90 Ok(Parser::new(content))
91}
92
93/// Save a document.
94pub fn save<T, U>(path: T, document: &U) -> Result<()>
95where
96 T: AsRef<Path>,
97 U: Node,
98{
99 let mut file = File::create(path)?;
100 file.write_all(&document.to_string().into_bytes())
101}
102
103/// Write a document.
104pub fn write<T, U>(mut target: T, document: &U) -> Result<()>
105where
106 T: Write,
107 U: Node,
108{
109 target.write_all(&document.to_string().into_bytes())
110}
111
112#[cfg(test)]
113mod tests {
114 use std::fs::File;
115 use std::io::Read;
116
117 use crate::parser::{Event, Parser};
118
119 const TEST_PATH: &'static str = "tests/fixtures/benton.svg";
120
121 #[test]
122 fn open() {
123 let mut content = String::new();
124 exercise(crate::open(self::TEST_PATH, &mut content).unwrap());
125 }
126
127 #[test]
128 fn read() {
129 let mut content = String::new();
130 let mut file = File::open(self::TEST_PATH).unwrap();
131 file.read_to_string(&mut content).unwrap();
132
133 exercise(crate::read(&content).unwrap());
134 }
135
136 fn exercise<'l>(mut parser: Parser<'l>) {
137 macro_rules! test(
138 ($matcher:pat) => (match parser.next().unwrap() {
139 $matcher => {}
140 _ => unreachable!(),
141 });
142 );
143
144 test!(Event::Instruction(_));
145 test!(Event::Comment(_));
146 test!(Event::Declaration(_));
147 test!(Event::Tag("svg", _, _));
148 test!(Event::Tag("path", _, _));
149 test!(Event::Tag("path", _, _));
150 test!(Event::Tag("path", _, _));
151 test!(Event::Tag("path", _, _));
152 test!(Event::Tag("svg", _, _));
153
154 assert!(parser.next().is_none());
155 }
156}