Skip to content

Commit 8c2aeb1

Browse files
committed
perf(dash-wasm): parse integer attributes directly from bytes
1 parent bc2ab3d commit 8c2aeb1

1 file changed

Lines changed: 65 additions & 10 deletions

File tree

  • src/parsers/manifest/dash/wasm-parser/rs

‎src/parsers/manifest/dash/wasm-parser/rs/utils.rs‎

Lines changed: 65 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::errors::{ParsingError, Result};
2+
use core::convert::TryFrom;
23

34
/// Try to parse the given array of bytes into an f64, by first converting
45
/// it to the corresponding ASCII (or even here, UTF-8) values.
@@ -8,20 +9,50 @@ pub fn parse_f64(value: &[u8]) -> Result<f64> {
89
Ok(res_f64)
910
}
1011

11-
/// Try to parse the given array of bytes into an i64, by first converting
12-
/// it to the corresponding ASCII (or even here, UTF-8) values.
12+
/// Try to parse the given array of ASCII bytes into an i64.
1313
pub fn parse_i64(value: &[u8]) -> Result<i64> {
14-
let res = std::str::from_utf8(value)?;
15-
let res_u64 = res.parse::<i64>()?;
16-
Ok(res_u64)
14+
let (is_negative, digits) = match value.first() {
15+
Some(b'-') => (true, &value[1..]),
16+
Some(b'+') => (false, &value[1..]),
17+
_ => (false, value),
18+
};
19+
let magnitude = parse_unsigned_digits(digits)?;
20+
if is_negative {
21+
if magnitude == (i64::MAX as u64) + 1 {
22+
Ok(i64::MIN)
23+
} else {
24+
let value = i64::try_from(magnitude).map_err(|_| invalid_integer())?;
25+
Ok(-value)
26+
}
27+
} else {
28+
i64::try_from(magnitude).map_err(|_| invalid_integer())
29+
}
1730
}
1831

19-
/// Try to parse the given array of bytes into an u64, by first converting
20-
/// it to the corresponding ASCII (or even here, UTF-8) values.
32+
/// Try to parse the given array of ASCII bytes into a u64.
2133
pub fn parse_u64(value: &[u8]) -> Result<u64> {
22-
let res = std::str::from_utf8(value)?;
23-
let res_u64 = res.parse::<u64>()?;
24-
Ok(res_u64)
34+
let digits = value.strip_prefix(b"+").unwrap_or(value);
35+
parse_unsigned_digits(digits)
36+
}
37+
38+
fn parse_unsigned_digits(value: &[u8]) -> Result<u64> {
39+
if value.is_empty() {
40+
return Err(invalid_integer());
41+
}
42+
let mut result = 0u64;
43+
for byte in value {
44+
let digit = byte.checked_sub(b'0').filter(|digit| *digit <= 9);
45+
let digit = digit.ok_or_else(invalid_integer)?;
46+
result = result
47+
.checked_mul(10)
48+
.and_then(|number| number.checked_add(u64::from(digit)))
49+
.ok_or_else(invalid_integer)?;
50+
}
51+
Ok(result)
52+
}
53+
54+
fn invalid_integer() -> ParsingError {
55+
ParsingError("Invalid integer found in the MPD.".to_owned())
2556
}
2657

2758
/// Try to parse the given array of bytes into an f64:
@@ -219,6 +250,30 @@ pub fn u32_to_u8_slice_be(x: u32) -> [u8; 4] {
219250
mod tests {
220251
use super::*;
221252

253+
#[test]
254+
fn test_parse_integers() {
255+
assert_eq!(parse_u64(b"0").unwrap(), 0);
256+
assert_eq!(parse_u64(b"+42").unwrap(), 42);
257+
assert_eq!(parse_u64(b"18446744073709551615").unwrap(), u64::MAX);
258+
assert_eq!(parse_i64(b"+42").unwrap(), 42);
259+
assert_eq!(parse_i64(b"-42").unwrap(), -42);
260+
assert_eq!(parse_i64(b"9223372036854775807").unwrap(), i64::MAX);
261+
assert_eq!(parse_i64(b"-9223372036854775808").unwrap(), i64::MIN);
262+
263+
for invalid in [
264+
b"".as_slice(),
265+
b"+",
266+
b"-",
267+
b"12a",
268+
b" 12",
269+
b"18446744073709551616",
270+
] {
271+
assert!(parse_u64(invalid).is_err());
272+
}
273+
assert!(parse_i64(b"9223372036854775808").is_err());
274+
assert!(parse_i64(b"-9223372036854775809").is_err());
275+
}
276+
222277
#[test]
223278
fn test_parse_maybe_division() {
224279
assert_eq!(parse_maybe_division(b" 100 / 50 ").unwrap(), 100. / 50.);

0 commit comments

Comments
 (0)