Skip to content

Commit 98149d7

Browse files
committed
Fix scanning of multibyte chars
1 parent 29fca80 commit 98149d7

File tree

1 file changed

+9
-7
lines changed

1 file changed

+9
-7
lines changed

src/duration/mod.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,8 @@ pub struct Duration(std::time::Duration);
6161
impl FromStr for Duration {
6262
type Err = DurationParseError;
6363

64-
fn from_str(s: &str) -> Result<Self, Self::Err> {
64+
fn from_str(input: &str) -> Result<Self, Self::Err> {
6565
use duration_parse_error::*;
66-
let input = s.trim();
67-
6866
if input.is_empty() {
6967
return EmptyInputSnafu.fail();
7068
}
@@ -76,12 +74,15 @@ impl FromStr for Duration {
7674
let mut take_group = |f: fn(char) -> bool| {
7775
let &(from, _) = chars.peek()?;
7876
let mut to = from;
77+
let mut last_char = None;
7978

80-
while let Some((i, _)) = chars.next_if(|(_, c)| f(*c)) {
79+
while let Some((i, c)) = chars.next_if(|(_, c)| f(*c)) {
8180
to = i;
81+
last_char = Some(c);
8282
}
8383

84-
Some(&input[from..=to])
84+
// if last_char == None then we read 0 characters => fail
85+
Some(&input[from..(to + last_char?.len_utf8())])
8586
};
8687

8788
while let Some(value) = take_group(char::is_numeric) {
@@ -326,8 +327,9 @@ mod test {
326327
#[rstest]
327328
#[case("1D", DurationParseError::ParseUnitError{unit: "D".into()})]
328329
#[case("2d2", DurationParseError::NoUnit{value: 2})]
329-
#[case("1ä", DurationParseError::EmptyInput)]
330-
#[case(" ", DurationParseError::EmptyInput)]
330+
#[case("1ä", DurationParseError::ParseUnitError { unit: "ä".into() })]
331+
#[case(" ", DurationParseError::UnexpectedCharacter { chr: ' ' })]
332+
#[case("", DurationParseError::EmptyInput)]
331333
fn parse_invalid(#[case] input: &str, #[case] expected_err: DurationParseError) {
332334
let err = Duration::from_str(input).unwrap_err();
333335
assert_eq!(err, expected_err)

0 commit comments

Comments
 (0)