use crate::output::path::PathCommand;
use crate::utils::{MAX_FORMAT_PRECISION, bounded_precision, format_point};
pub trait PathFormatter {
type Output;
fn format(&self, commands: &[PathCommand]) -> Self::Output;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SvgPathFormat {
precision: usize,
}
impl SvgPathFormat {
#[must_use]
pub fn new(precision: usize) -> Self {
Self {
precision: bounded_precision(precision),
}
}
pub const MAX_PRECISION: usize = MAX_FORMAT_PRECISION;
#[must_use]
pub fn precision(&self) -> usize {
self.precision
}
}
impl Default for SvgPathFormat {
fn default() -> Self {
Self::new(6)
}
}
impl PathFormatter for SvgPathFormat {
type Output = String;
fn format(&self, commands: &[PathCommand]) -> Self::Output {
let mut parts = Vec::with_capacity(commands.len());
for command in commands {
match *command {
PathCommand::MoveTo(point) => {
parts.push(format!("M {}", format_point(point, self.precision)));
}
PathCommand::LineTo(point) => {
parts.push(format!("L {}", format_point(point, self.precision)));
}
PathCommand::CubicTo { ctrl1, ctrl2, to } => {
parts.push(format!(
"C {} {} {}",
format_point(ctrl1, self.precision),
format_point(ctrl2, self.precision),
format_point(to, self.precision)
));
}
PathCommand::Close => parts.push("Z".to_owned()),
}
}
parts.join(" ")
}
}