smooth_frame/output/
format.rs1use crate::output::path::PathCommand;
2use crate::utils::{MAX_FORMAT_PRECISION, bounded_precision, format_point};
3
4pub trait PathFormatter {
9 type Output;
11
12 fn format(&self, commands: &[PathCommand]) -> Self::Output;
14}
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub struct SvgPathFormat {
19 precision: usize,
20}
21
22impl SvgPathFormat {
23 #[must_use]
27 pub fn new(precision: usize) -> Self {
28 Self {
29 precision: bounded_precision(precision),
30 }
31 }
32
33 pub const MAX_PRECISION: usize = MAX_FORMAT_PRECISION;
35
36 #[must_use]
38 pub fn precision(&self) -> usize {
39 self.precision
40 }
41}
42
43impl Default for SvgPathFormat {
44 fn default() -> Self {
45 Self::new(6)
46 }
47}
48
49impl PathFormatter for SvgPathFormat {
50 type Output = String;
51
52 fn format(&self, commands: &[PathCommand]) -> Self::Output {
53 let mut parts = Vec::with_capacity(commands.len());
54 for command in commands {
55 match *command {
56 PathCommand::MoveTo(point) => {
57 parts.push(format!("M {}", format_point(point, self.precision)));
58 }
59 PathCommand::LineTo(point) => {
60 parts.push(format!("L {}", format_point(point, self.precision)));
61 }
62 PathCommand::CubicTo { ctrl1, ctrl2, to } => {
63 parts.push(format!(
64 "C {} {} {}",
65 format_point(ctrl1, self.precision),
66 format_point(ctrl2, self.precision),
67 format_point(to, self.precision)
68 ));
69 }
70 PathCommand::Close => parts.push("Z".to_owned()),
71 }
72 }
73 parts.join(" ")
74 }
75}