1use std::fmt;
2use std::fmt::Write;
3
4#[cfg(doctest)]
5mod test_readme {
6 macro_rules! external_doc_test {
7 ($x:expr) => {
8 #[doc = $x]
9 extern "C" {}
10 };
11 }
12
13 external_doc_test!(include_str!("../README.md"));
14}
15
16pub enum PathCommand<F> {
22 M(F, F),
24 M_(F, F),
26 L(F, F),
28 L_(F, F),
30 H(F),
32 H_(F),
34 V(F),
36 V_(F),
38 C(F, F, F, F, F, F),
40 C_(F, F, F, F, F, F),
42 S(F, F, F, F),
44 S_(F, F, F, F),
46 Q(F, F, F, F),
48 Q_(F, F, F, F),
50 T(F, F),
52 T_(F, F),
54 A(F, F, F, F, F, F, F),
56 A_(F, F, F, F, F, F, F),
58 Z(F),
60}
61
62impl<F> PathCommand<F> {
63 #[inline(always)]
64 pub fn map<J>(self, mut func: impl FnMut(F) -> J) -> PathCommand<J> {
65 use PathCommand::*;
66
67 match self {
68 M(x, y) => M(func(x), func(y)),
69 M_(x, y) => M_(func(x), func(y)),
70 L(x, y) => L(func(x), func(y)),
71 L_(x, y) => L_(func(x), func(y)),
72 H(a) => H(func(a)),
73 H_(a) => H_(func(a)),
74 V(a) => V(func(a)),
75 V_(a) => V_(func(a)),
76 C(x1, y1, x2, y2, x, y) => C(func(x1), func(y1), func(x2), func(y2), func(x), func(y)),
77 C_(dx1, dy1, dx2, dy2, dx, dy) => C_(
78 func(dx1),
79 func(dy1),
80 func(dx2),
81 func(dy2),
82 func(dx),
83 func(dy),
84 ),
85 S(x2, y2, x, y) => S(func(x2), func(y2), func(x), func(y)),
86 S_(x2, y2, x, y) => S_(func(x2), func(y2), func(x), func(y)),
87 Q(x1, y1, x, y) => Q(func(x1), func(y1), func(x), func(y)),
88 Q_(dx1, dy1, dx, dy) => Q_(func(dx1), func(dy1), func(dx), func(dy)),
89 T(x, y) => T(func(x), func(y)),
90 T_(x, y) => T_(func(x), func(y)),
91 A(rx, ry, x_axis_rotation, large_arc_flag, sweep_flag, x, y) => A(
92 func(rx),
93 func(ry),
94 func(x_axis_rotation),
95 func(large_arc_flag),
96 func(sweep_flag),
97 func(x),
98 func(y),
99 ),
100 A_(rx, ry, x_axis_rotation, large_arc_flag, sweep_flag, dx, dy) => A_(
101 func(rx),
102 func(ry),
103 func(x_axis_rotation),
104 func(large_arc_flag),
105 func(sweep_flag),
106 func(dx),
107 func(dy),
108 ),
109 Z(a) => Z(func(a)),
110 }
111 }
112
113 #[inline(always)]
114 fn write<T: fmt::Write>(&self, mut writer: T) -> fmt::Result
115 where
116 F: fmt::Display,
117 {
118 use PathCommand::*;
119 match self {
120 M(x, y) => {
121 write!(writer, " M {} {}", x, y)
122 }
123 M_(x, y) => {
124 write!(writer, " m {} {}", x, y)
125 }
126 L(x, y) => {
127 write!(writer, " L {} {}", x, y)
128 }
129 L_(x, y) => {
130 write!(writer, " l {} {}", x, y)
131 }
132 H(a) => {
133 write!(writer, " H {}", a)
134 }
135 H_(a) => {
136 write!(writer, " h {}", a)
137 }
138 V(a) => {
139 write!(writer, " V {}", a)
140 }
141 V_(a) => {
142 write!(writer, " v {}", a)
143 }
144 C(x1, y1, x2, y2, x, y) => {
145 write!(writer, " C {} {}, {} {}, {} {}", x1, y1, x2, y2, x, y)
146 }
147 C_(dx1, dy1, dx2, dy2, dx, dy) => {
148 write!(writer, " c {} {}, {} {}, {} {}", dx1, dy1, dx2, dy2, dx, dy)
149 }
150 S(x2, y2, x, y) => {
151 write!(writer, " S {},{} {} {}", x2, y2, x, y)
152 }
153 S_(x2, y2, x, y) => {
154 write!(writer, " s {},{} {} {}", x2, y2, x, y)
155 }
156 Q(x1, y1, x, y) => {
157 write!(writer, " Q {} {}, {} {}", x1, y1, x, y)
158 }
159 Q_(dx1, dy1, dx, dy) => {
160 write!(writer, " q {} {}, {} {}", dx1, dy1, dx, dy)
161 }
162 T(x, y) => {
163 write!(writer, " T {} {}", x, y)
164 }
165 T_(x, y) => {
166 write!(writer, " t {} {}", x, y)
167 }
168 A(rx, ry, x_axis_rotation, large_arc_flag, sweep_flag, x, y) => {
169 write!(
170 writer,
171 " A {} {} {} {} {} {} {}",
172 rx, ry, x_axis_rotation, large_arc_flag, sweep_flag, x, y
173 )
174 }
175 A_(rx, ry, x_axis_rotation, large_arc_flag, sweep_flag, dx, dy) => {
176 write!(
177 writer,
178 " a {} {} {} {} {} {} {}",
179 rx, ry, x_axis_rotation, large_arc_flag, sweep_flag, dx, dy
180 )
181 }
182 Z(_) => {
183 write!(writer, " Z")
184 }
185 }
186 }
187}
188
189pub struct PathBuilder<'a, T> {
193 writer: &'a mut T,
194}
195impl<'a, T: fmt::Write> PathBuilder<'a, T> {
196 #[inline(always)]
197 pub fn put(&mut self, command: crate::PathCommand<impl fmt::Display>) -> fmt::Result {
198 command.write(escape_guard(&mut self.writer))
199 }
200}
201
202pub struct PointsBuilder<'a, T> {
206 writer: &'a mut T,
207}
208impl<'a, T: fmt::Write> PointsBuilder<'a, T> {
209 #[inline(always)]
210 pub fn put(&mut self, x: impl fmt::Display, y: impl fmt::Display) -> fmt::Result {
211 write!(escape_guard(&mut self.writer), "{},{} ", x, y)
212 }
213}
214
215pub struct Adaptor<T> {
220 pub inner: T,
221 pub error: Result<(), std::io::Error>,
222}
223
224pub fn new<T: fmt::Write>(a: T) -> ElemWriter<T> {
228 ElemWriter(a)
229}
230
231pub fn upgrade_write<T: std::io::Write>(inner: T) -> Adaptor<T> {
233 Adaptor {
234 inner,
235 error: Ok(()),
236 }
237}
238
239impl<T: std::io::Write> std::fmt::Write for Adaptor<T> {
240 fn write_str(&mut self, s: &str) -> std::fmt::Result {
241 match self.inner.write_all(s.as_bytes()) {
242 Ok(()) => Ok(()),
243 Err(e) => {
244 self.error = Err(e);
245 Err(std::fmt::Error)
246 }
247 }
248 }
249}
250
251#[must_use]
256pub struct ElementBridge<'a, T, D, K> {
257 writer: &'a mut ElemWriter<T>,
258 tag: D,
259 pub k: K,
260}
261impl<'a, T: fmt::Write, D: fmt::Display, K> ElementBridge<'a, T, D, K> {
262 pub fn build<J>(
263 self,
264 func: impl FnOnce(&mut ElemWriter<T>) -> Result<J, fmt::Error>,
265 ) -> Result<J, fmt::Error> {
266 let k = func(self.writer)?;
267 self.writer.0.write_str("</")?;
268 write!(escape_guard(&mut self.writer.0), "{}", self.tag)?;
269 self.writer.0.write_char('>')?;
270 Ok(k)
271 }
272}
273
274pub struct AttrWriter<'a, T>(&'a mut T);
278impl<'a, T: fmt::Write> AttrWriter<'a, T> {
279 pub fn attr(&mut self, a: impl fmt::Display, b: impl fmt::Display) -> fmt::Result {
280 write!(escape_guard(&mut self.0), " {}", a)?;
281 self.0.write_str("=\"")?;
282 write!(escape_guard(&mut self.0), "{}", b)?;
283 self.0.write_str("\"")
284 }
285
286 #[deprecated(note = "please use `writer_escapable or writer_safe` instead")]
290 pub fn writer(&mut self) -> &mut T {
291 self.0
292 }
293
294 pub fn writer_safe(&mut self) -> EscapeGuard<&mut T> {
295 escape_guard(self.0)
296 }
297
298 pub fn writer_escapable(&mut self) -> &mut T {
302 self.0
303 }
304
305 pub fn put_raw(&mut self, a: impl fmt::Display) -> fmt::Result {
306 write!(escape_guard(&mut self.0), " {}", a)
307 }
308
309 pub fn put_raw_escapable(&mut self, a: impl fmt::Display) -> fmt::Result {
313 write!(&mut self.0, " {}", a)
314 }
315 pub fn path(&mut self, a: impl FnOnce(&mut PathBuilder<T>) -> fmt::Result) -> fmt::Result {
316 let mut p = PathBuilder { writer: self.0 };
317 p.writer.write_str(" d=\"")?;
318 a(&mut p)?;
319 p.writer.write_str("\"")
320 }
321 pub fn points(&mut self, a: impl FnOnce(&mut PointsBuilder<T>) -> fmt::Result) -> fmt::Result {
322 let mut p = PointsBuilder { writer: self.0 };
323 p.writer.write_str(" points=\"")?;
324 a(&mut p)?;
325 p.writer.write_str("\"")
326 }
327}
328
329pub struct ElemWriter<T>(T);
333
334impl<'a> ElemWriter<&'a mut dyn fmt::Write> {
335 pub fn swap_writer(&mut self, other: &'a mut dyn fmt::Write) {
339 self.0 = other;
340 }
341}
342
343impl<T: fmt::Write> ElemWriter<T> {
344 pub fn into_writer(self) -> T {
345 self.0
346 }
347
348 #[deprecated(note = "please use `writer_escapable or writer_safe` instead")]
352 pub fn writer(&mut self) -> &mut T {
353 &mut self.0
354 }
355
356 pub fn writer_safe(&mut self) -> EscapeGuard<&mut T> {
357 escape_guard(&mut self.0)
358 }
359
360 pub fn writer_escapable(&mut self) -> &mut T {
364 &mut self.0
365 }
366
367 pub fn put_raw(&mut self, a: impl fmt::Display) -> fmt::Result {
368 write!(escape_guard(&mut self.0), " {}", a)
369 }
370
371 pub fn put_raw_escapable(&mut self, a: impl fmt::Display) -> fmt::Result {
375 write!(&mut self.0, " {}", a)
376 }
377
378 pub fn single<D: fmt::Display>(
379 &mut self,
380 tag: D,
381 func: impl FnOnce(&mut AttrWriter<T>) -> fmt::Result,
382 ) -> fmt::Result {
383 self.0.write_char('<')?;
384 write!(escape_guard(&mut self.0), "{}", tag)?;
385 self.0.write_char(' ')?;
386 func(&mut AttrWriter(&mut self.0))?;
387 self.0.write_str(" />")
388 }
389 pub fn elem<D: fmt::Display, K>(
390 &mut self,
391 tag: D,
392 func: impl FnOnce(&mut AttrWriter<T>) -> Result<K, fmt::Error>,
393 ) -> Result<ElementBridge<T, D, K>, fmt::Error> {
394 self.0.write_char('<')?;
395 write!(escape_guard(&mut self.0), "{}", tag)?;
396 self.0.write_char(' ')?;
397 let k = func(&mut AttrWriter(&mut self.0))?;
398 self.0.write_str(" >")?;
399
400 Ok(ElementBridge {
401 writer: self,
402 tag,
403 k,
404 })
405 }
406}
407
408pub fn no_attr<T>() -> impl FnOnce(&mut AttrWriter<T>) -> fmt::Result {
413 move |_| Ok(())
414}
415
416pub fn escape_guard<T: std::fmt::Write>(a: T) -> EscapeGuard<T> {
420 EscapeGuard::new(a)
421}
422
423pub struct EscapeGuard<T> {
429 writer: T,
430}
431
432impl<T: std::fmt::Write> EscapeGuard<T> {
433 pub fn new(writer: T) -> EscapeGuard<T> {
434 EscapeGuard { writer }
435 }
436}
437
438impl<T: std::fmt::Write> std::fmt::Write for EscapeGuard<T> {
439 fn write_str(&mut self, s: &str) -> Result<(), std::fmt::Error> {
440 for c in s.chars() {
441 let r = match c {
442 '\"' => Some("""),
443 '\'' => Some("'"),
444 '<' => Some("<"),
445 '>' => Some(">"),
446 '&' => Some("&"),
447 _ => None,
448 };
449
450 if let Some(r) = r {
451 self.writer.write_str(r)?;
452 } else {
453 self.writer.write_char(c)?;
454 }
455 }
456 Ok(())
457 }
458}