diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 00000000..4b6c79f5 --- /dev/null +++ b/clippy.toml @@ -0,0 +1,4 @@ +allow-unwrap-in-tests = true +allow-expect-in-tests = true +allow-panic-in-tests = true +allow-indexing-slicing-in-tests = true diff --git a/crates/svg/src/lib.rs b/crates/svg/src/lib.rs index 2825cdfa..06ae671a 100644 --- a/crates/svg/src/lib.rs +++ b/crates/svg/src/lib.rs @@ -4,6 +4,8 @@ //! ([`Doc`]): groups with transforms and opacity, and shapes with fills and strokes in their own //! user space. [`rasterize`] draws it at any scale; the engine converts it to shape layers. +#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)] + mod color; mod pathdata; mod raster; diff --git a/crates/svg/src/pathdata.rs b/crates/svg/src/pathdata.rs index 842efb45..c8fa7f67 100644 --- a/crates/svg/src/pathdata.rs +++ b/crates/svg/src/pathdata.rs @@ -109,8 +109,9 @@ pub fn parse_path_data(d: &str) -> BezPath { let c = match l.command() { Some(c) => c, None => match cmd { - // Implicit repeat (a moveto repeats as lineto). - Some(c) if l.at_number() => match c { + // Implicit repeat (a moveto repeats as lineto). Z takes no numbers, so a number + // after it is an error: repeating Z would loop forever without consuming input. + Some(c) if l.at_number() && !c.eq_ignore_ascii_case(&b'z') => match c { b'M' => b'L', b'm' => b'l', other => other, @@ -284,6 +285,15 @@ mod tests { assert!(parse_path_data("").elements().is_empty()); } + #[test] + fn number_after_close_stops_instead_of_looping() { + // "Z9": Z was repeated implicitly without consuming the number, appending close-paths + // until memory ran out. + let p = parse_path_data("M0 0 L10 0 L10 10 Z9 C1 2 3 4 5 6"); + assert_eq!(p.elements().len(), 4); + assert!(parse_path_data("M0 0 L10 0 z 9 9").elements().len() <= 4); + } + #[test] fn number_lists() { assert_eq!(numbers("0 0,100 50"), vec![0.0, 0.0, 100.0, 50.0]);