[librsvg: 1/3] parser: use const generics for NumberList




commit 3b4bb2430c98766185493ec91b51ac8647ed07e9
Author: Paolo Borelli <pborelli gnome org>
Date:   Sun May 2 16:33:56 2021 +0200

    parser: use const generics for NumberList

 src/filters/color_matrix.rs       |  5 +--
 src/filters/component_transfer.rs |  9 ++--
 src/filters/convolve_matrix.rs    |  8 ++--
 src/parsers.rs                    | 94 +++++++++++++--------------------------
 src/viewbox.rs                    |  5 +--
 5 files changed, 42 insertions(+), 79 deletions(-)
---
diff --git a/src/filters/color_matrix.rs b/src/filters/color_matrix.rs
index a39e4f38..46f5257c 100644
--- a/src/filters/color_matrix.rs
+++ b/src/filters/color_matrix.rs
@@ -7,7 +7,7 @@ use crate::drawing_ctx::DrawingCtx;
 use crate::element::{ElementResult, SetAttributes};
 use crate::error::*;
 use crate::node::{CascadedValues, Node};
-use crate::parsers::{NumberList, NumberListLength, Parse, ParseValue};
+use crate::parsers::{NumberList, Parse, ParseValue};
 use crate::property_defs::ColorInterpolationFilters;
 use crate::rect::IRect;
 use crate::surface_utils::{
@@ -95,8 +95,7 @@ impl SetAttributes for FeColorMatrix {
                 let new_matrix = match operation_type {
                     OperationType::LuminanceToAlpha => unreachable!(),
                     OperationType::Matrix => {
-                        let NumberList(v) =
-                            NumberList::parse_str(value, NumberListLength::Exact(20))
+                        let NumberList::<20, 20>(v) = NumberList::parse_str(value)
                                 .attribute(attr)?;
                         let matrix = Matrix4x5::from_row_slice(&v);
                         let mut matrix = matrix.fixed_resize(0.0);
diff --git a/src/filters/component_transfer.rs b/src/filters/component_transfer.rs
index 11259d1e..e38f3991 100644
--- a/src/filters/component_transfer.rs
+++ b/src/filters/component_transfer.rs
@@ -8,7 +8,7 @@ use crate::drawing_ctx::DrawingCtx;
 use crate::element::{Draw, Element, ElementResult, SetAttributes};
 use crate::error::*;
 use crate::node::{CascadedValues, Node, NodeBorrow};
-use crate::parsers::{NumberList, NumberListLength, Parse, ParseValue};
+use crate::parsers::{NumberList, Parse, ParseValue};
 use crate::property_defs::ColorInterpolationFilters;
 use crate::rect::IRect;
 use crate::surface_utils::{
@@ -219,10 +219,9 @@ macro_rules! func_x {
                     match attr.expanded() {
                         expanded_name!("", "type") => self.function_type = attr.parse(value)?,
                         expanded_name!("", "tableValues") => {
-                            let NumberList(v) =
-                                // #691: Limit list to 256 to mitigate malicious SVGs
-                                NumberList::parse_str(value, NumberListLength::MaxLength(256))
-                                    .attribute(attr)?;
+                            // #691: Limit list to 256 to mitigate malicious SVGs
+                            let NumberList::<0, 256>(v) =
+                                NumberList::parse_str(value).attribute(attr)?;
                             self.table_values = v;
                         }
                         expanded_name!("", "slope") => self.slope = attr.parse(value)?,
diff --git a/src/filters/convolve_matrix.rs b/src/filters/convolve_matrix.rs
index 3b802e2c..8f77d2d8 100644
--- a/src/filters/convolve_matrix.rs
+++ b/src/filters/convolve_matrix.rs
@@ -7,9 +7,7 @@ use crate::drawing_ctx::DrawingCtx;
 use crate::element::{ElementResult, SetAttributes};
 use crate::error::*;
 use crate::node::{CascadedValues, Node};
-use crate::parsers::{
-    NonNegative, NumberList, NumberListLength, NumberOptionalNumber, Parse, ParseValue,
-};
+use crate::parsers::{NonNegative, NumberList, NumberOptionalNumber, Parse, ParseValue};
 use crate::property_defs::ColorInterpolationFilters;
 use crate::rect::IRect;
 use crate::surface_utils::{
@@ -109,8 +107,8 @@ impl SetAttributes for FeConvolveMatrix {
                 // #352: Parse as an unbounded list rather than exact length to prevent aborts due
                 //       to huge allocation attempts by underlying Vec::with_capacity().
                 // #691: Limit list to 400 (20x20) to mitigate malicious SVGs
-                let NumberList(v) = NumberList::parse_str(value, NumberListLength::MaxLength(400))
-                    .attribute(attr.clone())?;
+                let NumberList::<0, 400>(v) =
+                    NumberList::parse_str(value).attribute(attr.clone())?;
                 // #691: Update check as v.len can be different than number of elements because
                 //       of the above limit (and will = 400 if that happens)
                 if v.len() != number_of_elements && v.len() != 400 {
diff --git a/src/parsers.rs b/src/parsers.rs
index 51eb84a8..75b1db48 100644
--- a/src/parsers.rs
+++ b/src/parsers.rs
@@ -131,70 +131,38 @@ impl Parse for u32 {
     }
 }
 
-#[derive(Eq, PartialEq)]
-pub enum NumberListLength {
-    MaxLength(usize),
-    Exact(usize),
-}
-
-#[derive(Debug, PartialEq)]
-pub struct NumberList(pub Vec<f64>);
-
 /// CSS number-list values.
-impl NumberList {
-    pub fn parse<'i>(
-        parser: &mut Parser<'i, '_>,
-        length: NumberListLength,
-    ) -> Result<Self, ParseError<'i>> {
-        let mut v = match length {
-            NumberListLength::MaxLength(l) if l > 0 => Vec::<f64>::with_capacity(l),
-            NumberListLength::MaxLength(_) => {
-                //cargo fmt suggests this formatting for some reason
-                unreachable!("NumberListLength::MaxLength cannot be 0")
-            }
-            NumberListLength::Exact(l) if l > 0 => Vec::<f64>::with_capacity(l),
-            NumberListLength::Exact(_) => unreachable!("NumberListLength::Exact cannot be 0"),
-        };
+#[derive(Debug, PartialEq)]
+pub struct NumberList<const REQUIRED: usize, const MAX: usize>(pub Vec<f64>);
 
-        for i in 0.. {
+impl<const REQUIRED: usize, const MAX: usize> NumberList<REQUIRED, MAX> {
+    pub fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
+        let loc = parser.current_source_location();
+        let mut v = Vec::<f64>::with_capacity(MAX);
+        for i in 0..MAX {
             if i != 0 {
                 optional_comma(parser);
             }
 
             v.push(f64::parse(parser)?);
 
-            if let NumberListLength::MaxLength(l) = length {
-                if i + 1 == l {
-                    break;
-                }
-            }
-
-            if let NumberListLength::Exact(l) = length {
-                if i + 1 == l {
-                    break;
-                }
-            }
-
             if parser.is_exhausted() {
-                match length {
-                    NumberListLength::Exact(l) => {
-                        if i + 1 == l {
-                            break;
-                        }
-                    }
-                    _ => break,
-                }
+                break;
             }
         }
 
-        Ok(NumberList(v))
+        if REQUIRED > 0 && v.len() < REQUIRED {
+            Err(loc.new_custom_error(ValueErrorKind::value_error("expected more numbers")))
+        } else {
+            Ok(NumberList(v))
+        }
     }
 
-    pub fn parse_str(s: &str, length: NumberListLength) -> Result<NumberList, ParseError<'_>> {
+    pub fn parse_str(s: &str) -> Result<Self, ParseError<'_>> {
         let mut input = ParserInput::new(s);
         let mut parser = Parser::new(&mut input);
 
-        let res = Self::parse(&mut parser, length)?;
+        let res = Self::parse(&mut parser)?;
         parser.expect_exhausted()?;
         Ok(res)
     }
@@ -374,22 +342,22 @@ mod tests {
     #[test]
     fn parses_number_list() {
         assert_eq!(
-            NumberList::parse_str("5", NumberListLength::Exact(1)).unwrap(),
+            NumberList::<1, 1>::parse_str("5").unwrap(),
             NumberList(vec![5.0])
         );
 
         assert_eq!(
-            NumberList::parse_str("1 2 3 4", NumberListLength::Exact(4)).unwrap(),
+            NumberList::<4, 4>::parse_str("1 2 3 4").unwrap(),
             NumberList(vec![1.0, 2.0, 3.0, 4.0])
         );
 
         assert_eq!(
-            NumberList::parse_str("1 2 3 4 5", NumberListLength::MaxLength(5)).unwrap(),
+            NumberList::<0, 5>::parse_str("1 2 3 4 5").unwrap(),
             NumberList(vec![1.0, 2.0, 3.0, 4.0, 5.0])
         );
 
         assert_eq!(
-            NumberList::parse_str("1 2 3", NumberListLength::MaxLength(5)).unwrap(),
+            NumberList::<0, 5>::parse_str("1 2 3").unwrap(),
             NumberList(vec![1.0, 2.0, 3.0])
         );
     }
@@ -397,26 +365,26 @@ mod tests {
     #[test]
     fn errors_on_invalid_number_list() {
         // empty
-        assert!(NumberList::parse_str("", NumberListLength::Exact(1)).is_err());
-        assert!(NumberList::parse_str("", NumberListLength::MaxLength(1)).is_err());
+        assert!(NumberList::<1, 1>::parse_str("").is_err());
+        assert!(NumberList::<0, 1>::parse_str("").is_err());
 
         // garbage
-        assert!(NumberList::parse_str("foo", NumberListLength::Exact(1)).is_err());
-        assert!(NumberList::parse_str("1foo", NumberListLength::Exact(2)).is_err());
-        assert!(NumberList::parse_str("1 foo", NumberListLength::Exact(2)).is_err());
-        assert!(NumberList::parse_str("1 foo 2", NumberListLength::Exact(2)).is_err());
-        assert!(NumberList::parse_str("1,foo", NumberListLength::Exact(2)).is_err());
+        assert!(NumberList::<1, 1>::parse_str("foo").is_err());
+        assert!(NumberList::<2, 2>::parse_str("1foo").is_err());
+        assert!(NumberList::<2, 2>::parse_str("1 foo").is_err());
+        assert!(NumberList::<2, 2>::parse_str("1 foo 2").is_err());
+        assert!(NumberList::<2, 2>::parse_str("1,foo").is_err());
 
         // too many
-        assert!(NumberList::parse_str("1 2", NumberListLength::Exact(1)).is_err());
+        assert!(NumberList::<1, 1>::parse_str("1 2").is_err());
 
         // extra token
-        assert!(NumberList::parse_str("1,", NumberListLength::Exact(1)).is_err());
-        assert!(NumberList::parse_str("1,", NumberListLength::MaxLength(1)).is_err());
+        assert!(NumberList::<1, 1>::parse_str("1,").is_err());
+        assert!(NumberList::<0, 1>::parse_str("1,").is_err());
 
         // too few
-        assert!(NumberList::parse_str("1", NumberListLength::Exact(2)).is_err());
-        assert!(NumberList::parse_str("1 2", NumberListLength::Exact(3)).is_err());
+        assert!(NumberList::<2, 2>::parse_str("1").is_err());
+        assert!(NumberList::<3, 3>::parse_str("1 2").is_err());
     }
 
     #[test]
diff --git a/src/viewbox.rs b/src/viewbox.rs
index b979f216..b9be4d8b 100644
--- a/src/viewbox.rs
+++ b/src/viewbox.rs
@@ -4,7 +4,7 @@ use cssparser::Parser;
 use std::ops::Deref;
 
 use crate::error::*;
-use crate::parsers::{NumberList, NumberListLength, Parse};
+use crate::parsers::{NumberList, Parse};
 use crate::rect::Rect;
 
 /// Newtype around a [`Rect`], used to represent the `viewBox` attribute.
@@ -45,8 +45,7 @@ impl Parse for ViewBox {
     fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<ViewBox, ParseError<'i>> {
         let loc = parser.current_source_location();
 
-        let NumberList(v) = NumberList::parse(parser, NumberListLength::Exact(4))?;
-
+        let NumberList::<4, 4>(v) = NumberList::parse(parser)?;
         let (x, y, width, height) = (v[0], v[1], v[2], v[3]);
 
         if width >= 0.0 && height >= 0.0 {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]