From 3a6420907e8616cc10673a41bc1e659c95b52407 Mon Sep 17 00:00:00 2001 From: Kevin Ness <46825870+nekevss@users.noreply.github.com> Date: Mon, 3 Jun 2024 22:29:57 -0400 Subject: [PATCH] Migrate from `&str` to `&[u8]` in `ixdtf` (#4918) --- Cargo.lock | 1 + utils/ixdtf/Cargo.toml | 1 + utils/ixdtf/README.md | 30 ++-- utils/ixdtf/src/lib.rs | 30 ++-- utils/ixdtf/src/parsers/annotations.rs | 10 +- utils/ixdtf/src/parsers/duration.rs | 6 +- utils/ixdtf/src/parsers/grammar.rs | 2 +- utils/ixdtf/src/parsers/mod.rs | 111 +++++++----- utils/ixdtf/src/parsers/records.rs | 8 +- utils/ixdtf/src/parsers/tests.rs | 227 ++++++++++++------------- utils/ixdtf/src/parsers/timezone.rs | 8 +- 11 files changed, 226 insertions(+), 208 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d69464f61f4..34ff7d7d4fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1654,6 +1654,7 @@ dependencies = [ "criterion", "displaydoc", "serde-json-core", + "utf8_iter", ] [[package]] diff --git a/utils/ixdtf/Cargo.toml b/utils/ixdtf/Cargo.toml index 62bbefe8fd4..3bf04b40821 100644 --- a/utils/ixdtf/Cargo.toml +++ b/utils/ixdtf/Cargo.toml @@ -28,6 +28,7 @@ duration = [] [dependencies] displaydoc = { workspace = true } +utf8_iter.workspace = true [dev-dependencies] serde-json-core = { workspace = true, features = ["std"] } diff --git a/utils/ixdtf/README.md b/utils/ixdtf/README.md index 0bf35a185eb..d54422c7462 100644 --- a/utils/ixdtf/README.md +++ b/utils/ixdtf/README.md @@ -25,7 +25,7 @@ use ixdtf::parsers::{ let ixdtf_str = "2024-03-02T08:48:00-05:00[America/New_York]"; -let result = IxdtfParser::new(ixdtf_str).parse().unwrap(); +let result = IxdtfParser::from_str(ixdtf_str).parse().unwrap(); let date = result.date.unwrap(); let time = result.time.unwrap(); @@ -41,7 +41,7 @@ assert_eq!(offset.sign, Sign::Negative); assert_eq!(offset.hour, 5); assert_eq!(offset.minute, 0); assert!(!tz_annotation.critical); -assert_eq!(tz_annotation.tz, TimeZoneRecord::Name("America/New_York")); +assert_eq!(tz_annotation.tz, TimeZoneRecord::Name("America/New_York".as_bytes())); ``` ### Date/Time Strings @@ -141,9 +141,7 @@ use ixdtf::{parsers::IxdtfParser, ParserError}; let example_one = "2024-03-02T08:48:00-05:00[u-ca=iso8601][America/New_York]"; -let mut ixdtf = IxdtfParser::new(example_one); - -let result = ixdtf.parse(); +let result = IxdtfParser::from_str(example_one).parse(); assert_eq!(result, Err(ParserError::AnnotationKeyLeadingChar)); ``` @@ -157,9 +155,9 @@ the ixdtf string must be treated as erroneous ```rust use ixdtf::{parsers::IxdtfParser, ParserError}; -let example_one = "2024-03-02T08:48:00-05:00[u-ca=iso8601][!u-ca=japanese]"; +let example_two = "2024-03-02T08:48:00-05:00[u-ca=iso8601][!u-ca=japanese]"; -let result = IxdtfParser::new(example_one).parse(); +let result = IxdtfParser::from_str(example_two).parse(); assert_eq!(result, Err(ParserError::CriticalDuplicateCalendar)); ``` @@ -172,10 +170,10 @@ error on an unknown flag being flagged as critical. ```rust use ixdtf::{parsers::IxdtfParser, ParserError}; -let example_one = +let example_three = "2024-03-02T08:48:00-05:00[u-ca=iso8601][!answer-to-universe=fortytwo]"; -let result = IxdtfParser::new(example_one).parse(); +let result = IxdtfParser::from_str(example_three).parse(); assert_eq!(result, Err(ParserError::UnrecognizedCritical)); ``` @@ -206,11 +204,9 @@ between the offset and annotation. ```rust use ixdtf::parsers::{IxdtfParser, records::TimeZoneRecord}; -let example_one = "2024-03-02T08:48:00+01:00[!America/New_York]"; - -let mut ixdtf = IxdtfParser::new(example_one); +let example_two = "2024-03-02T08:48:00+01:00[!America/New_York]"; -let result = ixdtf.parse().unwrap(); +let result = IxdtfParser::from_str(example_two).parse().unwrap(); let tz_annotation = result.tz.unwrap(); let offset = result.offset.unwrap(); @@ -218,7 +214,7 @@ let offset = result.offset.unwrap(); // The time zone annotation and offset conflict with each other, and must therefore be // resolved by the user. assert!(tz_annotation.critical); -assert_eq!(tz_annotation.tz, TimeZoneRecord::Name("America/New_York")); +assert_eq!(tz_annotation.tz, TimeZoneRecord::Name("America/New_York".as_bytes())); assert_eq!(offset.hour, 1); ``` @@ -253,8 +249,8 @@ let example_with_custom_key = "2024-03-02T08:48:00-05:00[u-ca=iso8601][!answer-t let mut answer = None; -let _ = IxdtfParser::new(example_with_custom_key).parse_with_annotation_handler(|annotation| { - if annotation.key == "answer-to-universe" { +let _ = IxdtfParser::from_str(example_with_custom_key).parse_with_annotation_handler(|annotation| { + if annotation.key == "answer-to-universe".as_bytes() { answer.get_or_insert(annotation); // Found our value! We don't need `ixdtf` to handle this annotation. return None @@ -267,7 +263,7 @@ let _ = IxdtfParser::new(example_with_custom_key).parse_with_annotation_handler( let answer = answer.unwrap(); assert!(answer.critical); -assert_eq!(answer.value, "fortytwo"); +assert_eq!(answer.value, "fortytwo".as_bytes()); ``` It is worth noting that in the above example the annotation above found is a critically flagged diff --git a/utils/ixdtf/src/lib.rs b/utils/ixdtf/src/lib.rs index 67b59473ec7..a168bb5bad7 100644 --- a/utils/ixdtf/src/lib.rs +++ b/utils/ixdtf/src/lib.rs @@ -25,7 +25,7 @@ //! //! let ixdtf_str = "2024-03-02T08:48:00-05:00[America/New_York]"; //! -//! let result = IxdtfParser::new(ixdtf_str).parse().unwrap(); +//! let result = IxdtfParser::from_str(ixdtf_str).parse().unwrap(); //! //! let date = result.date.unwrap(); //! let time = result.time.unwrap(); @@ -41,7 +41,7 @@ //! assert_eq!(offset.hour, 5); //! assert_eq!(offset.minute, 0); //! assert!(!tz_annotation.critical); -//! assert_eq!(tz_annotation.tz, TimeZoneRecord::Name("America/New_York")); +//! assert_eq!(tz_annotation.tz, TimeZoneRecord::Name("America/New_York".as_bytes())); //! ``` //! //! ## Date/Time Strings @@ -142,9 +142,7 @@ //! let example_one = //! "2024-03-02T08:48:00-05:00[u-ca=iso8601][America/New_York]"; //! -//! let mut ixdtf = IxdtfParser::new(example_one); -//! -//! let result = ixdtf.parse(); +//! let result = IxdtfParser::from_str(example_one).parse(); //! //! assert_eq!(result, Err(ParserError::AnnotationKeyLeadingChar)); //! ``` @@ -158,9 +156,9 @@ //! ```rust //! use ixdtf::{parsers::IxdtfParser, ParserError}; //! -//! let example_one = "2024-03-02T08:48:00-05:00[u-ca=iso8601][!u-ca=japanese]"; +//! let example_two = "2024-03-02T08:48:00-05:00[u-ca=iso8601][!u-ca=japanese]"; //! -//! let result = IxdtfParser::new(example_one).parse(); +//! let result = IxdtfParser::from_str(example_two).parse(); //! //! assert_eq!(result, Err(ParserError::CriticalDuplicateCalendar)); //! ``` @@ -173,10 +171,10 @@ //! ```rust //! use ixdtf::{parsers::IxdtfParser, ParserError}; //! -//! let example_one = +//! let example_three = //! "2024-03-02T08:48:00-05:00[u-ca=iso8601][!answer-to-universe=fortytwo]"; //! -//! let result = IxdtfParser::new(example_one).parse(); +//! let result = IxdtfParser::from_str(example_three).parse(); //! //! assert_eq!(result, Err(ParserError::UnrecognizedCritical)); //! ``` @@ -207,11 +205,9 @@ //! ```rust //! use ixdtf::parsers::{IxdtfParser, records::TimeZoneRecord}; //! -//! let example_one = "2024-03-02T08:48:00+01:00[!America/New_York]"; -//! -//! let mut ixdtf = IxdtfParser::new(example_one); +//! let example_two = "2024-03-02T08:48:00+01:00[!America/New_York]"; //! -//! let result = ixdtf.parse().unwrap(); +//! let result = IxdtfParser::from_str(example_two).parse().unwrap(); //! //! let tz_annotation = result.tz.unwrap(); //! let offset = result.offset.unwrap(); @@ -219,7 +215,7 @@ //! // The time zone annotation and offset conflict with each other, and must therefore be //! // resolved by the user. //! assert!(tz_annotation.critical); -//! assert_eq!(tz_annotation.tz, TimeZoneRecord::Name("America/New_York")); +//! assert_eq!(tz_annotation.tz, TimeZoneRecord::Name("America/New_York".as_bytes())); //! assert_eq!(offset.hour, 1); //! ``` //! @@ -254,8 +250,8 @@ //! //! let mut answer = None; //! -//! let _ = IxdtfParser::new(example_with_custom_key).parse_with_annotation_handler(|annotation| { -//! if annotation.key == "answer-to-universe" { +//! let _ = IxdtfParser::from_str(example_with_custom_key).parse_with_annotation_handler(|annotation| { +//! if annotation.key == "answer-to-universe".as_bytes() { //! answer.get_or_insert(annotation); //! // Found our value! We don't need `ixdtf` to handle this annotation. //! return None @@ -268,7 +264,7 @@ //! let answer = answer.unwrap(); //! //! assert!(answer.critical); -//! assert_eq!(answer.value, "fortytwo"); +//! assert_eq!(answer.value, "fortytwo".as_bytes()); //! ``` //! //! It is worth noting that in the above example the annotation above found is a critically flagged diff --git a/utils/ixdtf/src/parsers/annotations.rs b/utils/ixdtf/src/parsers/annotations.rs index 124a9344afe..6027ec26519 100644 --- a/utils/ixdtf/src/parsers/annotations.rs +++ b/utils/ixdtf/src/parsers/annotations.rs @@ -21,7 +21,7 @@ use crate::{ /// Strictly a parsing intermediary for the checking the common annotation backing. pub(crate) struct AnnotationSet<'a> { pub(crate) tz: Option>, - pub(crate) calendar: Option<&'a str>, + pub(crate) calendar: Option<&'a [u8]>, } /// Parse a `TimeZoneAnnotation` `Annotations` set @@ -53,7 +53,7 @@ pub(crate) fn parse_annotation_set<'a>( pub(crate) fn parse_annotations<'a>( cursor: &mut Cursor<'a>, mut handler: impl FnMut(Annotation<'a>) -> Option>, -) -> ParserResult> { +) -> ParserResult> { let mut calendar: Option> = None; while cursor.check_or(false, is_annotation_open) { @@ -61,7 +61,7 @@ pub(crate) fn parse_annotations<'a>( match annotation { // Check if the key is the registered key "u-ca". - Some(kv) if kv.key == "u-ca" => { + Some(kv) if kv.key == "u-ca".as_bytes() => { // Check the calendar match calendar { Some(calendar) @@ -124,7 +124,7 @@ fn parse_kv_annotation<'a>(cursor: &mut Cursor<'a>) -> ParserResult(cursor: &mut Cursor<'a>) -> ParserResult<&'a str> { +fn parse_annotation_key<'a>(cursor: &mut Cursor<'a>) -> ParserResult<&'a [u8]> { let key_start = cursor.pos(); assert_syntax!( is_a_key_leading_char(cursor.next_or(ParserError::AnnotationKeyLeadingChar)?), @@ -147,7 +147,7 @@ fn parse_annotation_key<'a>(cursor: &mut Cursor<'a>) -> ParserResult<&'a str> { } /// Parse an `AnnotationValue`. -fn parse_annotation_value<'a>(cursor: &mut Cursor<'a>) -> ParserResult<&'a str> { +fn parse_annotation_value<'a>(cursor: &mut Cursor<'a>) -> ParserResult<&'a [u8]> { let value_start = cursor.pos(); cursor.advance(); while let Some(potential_value_char) = cursor.next() { diff --git a/utils/ixdtf/src/parsers/duration.rs b/utils/ixdtf/src/parsers/duration.rs index 1ecdde37e33..aaa5487304b 100644 --- a/utils/ixdtf/src/parsers/duration.rs +++ b/utils/ixdtf/src/parsers/duration.rs @@ -66,7 +66,7 @@ pub(crate) fn parse_date_duration(cursor: &mut Cursor) -> ParserResult ParserResult) = (0, 0, 0, None); let mut previous_unit = TimeUnit::None; - while cursor.check_or(false, |ch| ch.is_ascii_digit()) { + while cursor.check_or(false, |c| c.is_ascii_digit()) { let mut value: u32 = 0; while cursor.check_or(false, |c| c.is_ascii_digit()) { let digit = cursor diff --git a/utils/ixdtf/src/parsers/grammar.rs b/utils/ixdtf/src/parsers/grammar.rs index c2c5fa4f6a9..9018dc561f6 100644 --- a/utils/ixdtf/src/parsers/grammar.rs +++ b/utils/ixdtf/src/parsers/grammar.rs @@ -66,7 +66,7 @@ pub(crate) const fn is_time_designator(ch: char) -> bool { #[inline] /// Checks if char is a space. pub(crate) const fn is_space(ch: char) -> bool { - ch == '\u{0020}' + ch == ' ' } /// Checks if char is a `DateTimeSeparator`. diff --git a/utils/ixdtf/src/parsers/mod.rs b/utils/ixdtf/src/parsers/mod.rs index 88ed7a1dbd4..7730347c7dc 100644 --- a/utils/ixdtf/src/parsers/mod.rs +++ b/utils/ixdtf/src/parsers/mod.rs @@ -2,13 +2,14 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -//! The parser module contains the implementation details for `IXDTFParser` and `ISODurationParser` +//! The parser module contains the implementation details for `IxdtfParser` and `IsoDurationParser` use crate::{ParserError, ParserResult}; #[cfg(feature = "duration")] use records::DurationParseRecord; use records::IxdtfParseRecord; +use utf8_iter::Utf8CharIndices; use self::records::Annotation; @@ -49,7 +50,7 @@ macro_rules! assert_syntax { /// /// let ixdtf_str = "2024-03-02T08:48:00-05:00[America/New_York]"; /// -/// let result = IxdtfParser::new(ixdtf_str).parse().unwrap(); +/// let result = IxdtfParser::from_str(ixdtf_str).parse().unwrap(); /// /// let date = result.date.unwrap(); /// let time = result.time.unwrap(); @@ -65,7 +66,7 @@ macro_rules! assert_syntax { /// assert_eq!(offset.hour, 5); /// assert_eq!(offset.minute, 0); /// assert!(!tz_annotation.critical); -/// assert_eq!(tz_annotation.tz, TimeZoneRecord::Name("America/New_York")); +/// assert_eq!(tz_annotation.tz, TimeZoneRecord::Name("America/New_York".as_bytes())); /// ``` /// /// [rfc9557]: https://datatracker.ietf.org/doc/rfc9557/ @@ -76,13 +77,23 @@ pub struct IxdtfParser<'a> { } impl<'a> IxdtfParser<'a> { - /// Creates a new `IXDTFParser` from a provided `&str`. - pub fn new(value: &'a str) -> Self { + /// Creates a new `IxdtfParser` from a slice of utf-8 bytes. + #[inline] + #[must_use] + pub fn from_utf8(source: &'a [u8]) -> Self { Self { - cursor: Cursor::new(value), + cursor: Cursor::new(source), } } + /// Creates a new `IxdtfParser` from a source `&str`. + #[inline] + #[must_use] + #[allow(clippy::should_implement_trait)] + pub fn from_str(source: &'a str) -> Self { + Self::from_utf8(source.as_bytes()) + } + /// Parses the source as an [extended Date/Time string][rfc9557]. /// /// This is the baseline parse method for `ixdtf`. For this method, the @@ -114,7 +125,7 @@ impl<'a> IxdtfParser<'a> { /// /// let extended_year_month = "2020-11[u-ca=iso8601]"; /// - /// let result = IxdtfParser::new(extended_year_month) + /// let result = IxdtfParser::from_str(extended_year_month) /// .parse_year_month() /// .unwrap(); /// @@ -147,7 +158,7 @@ impl<'a> IxdtfParser<'a> { /// # use ixdtf::parsers::IxdtfParser; /// let extended_month_day = "1107[+04:00]"; /// - /// let result = IxdtfParser::new(extended_month_day) + /// let result = IxdtfParser::from_str(extended_month_day) /// .parse_month_day() /// .unwrap(); /// @@ -180,7 +191,7 @@ impl<'a> IxdtfParser<'a> { /// # use ixdtf::parsers::{IxdtfParser, records::{Sign, TimeZoneRecord}}; /// let extended_time = "12:01:04-05:00[America/New_York][u-ca=iso8601]"; /// - /// let result = IxdtfParser::new(extended_time).parse_time().unwrap(); + /// let result = IxdtfParser::from_str(extended_time).parse_time().unwrap(); /// /// let time = result.time.unwrap(); /// let offset = result.offset.unwrap(); @@ -193,7 +204,7 @@ impl<'a> IxdtfParser<'a> { /// assert_eq!(offset.hour, 5); /// assert_eq!(offset.minute, 0); /// assert!(!tz_annotation.critical); - /// assert_eq!(tz_annotation.tz, TimeZoneRecord::Name("America/New_York")); + /// assert_eq!(tz_annotation.tz, TimeZoneRecord::Name("America/New_York".as_bytes())); /// ``` /// /// [temporal-time]: https://tc39.es/proposal-temporal/#prod-TemporalTimeString @@ -223,7 +234,7 @@ impl<'a> IxdtfParser<'a> { /// /// let duration_str = "P1Y2M1DT2H10M30S"; /// -/// let result = IsoDurationParser::new(duration_str).parse().unwrap(); +/// let result = IsoDurationParser::from_str(duration_str).parse().unwrap(); /// /// let date_duration = result.date.unwrap(); /// @@ -256,13 +267,23 @@ pub struct IsoDurationParser<'a> { #[cfg(feature = "duration")] impl<'a> IsoDurationParser<'a> { - /// Creates a new `IsoDurationParser` from a target `&str`. - pub fn new(value: &'a str) -> Self { + /// Creates a new `IsoDurationParser` from a slice of utf-8 bytes. + #[inline] + #[must_use] + pub fn from_utf8(source: &'a [u8]) -> Self { Self { - cursor: Cursor::new(value), + cursor: Cursor::new(source), } } + /// Creates a new `IsoDurationParser` from a source `&str`. + #[inline] + #[must_use] + #[allow(clippy::should_implement_trait)] + pub fn from_str(source: &'a str) -> Self { + Self::from_utf8(source.as_bytes()) + } + /// Parse the contents of this `IsoDurationParser` into a `DurationParseRecord`. /// /// # Examples @@ -273,7 +294,7 @@ impl<'a> IsoDurationParser<'a> { /// # use ixdtf::parsers::{IsoDurationParser, records::DurationParseRecord }; /// let date_duration = "P1Y2M3W1D"; /// - /// let result = IsoDurationParser::new(date_duration).parse().unwrap(); + /// let result = IsoDurationParser::from_str(date_duration).parse().unwrap(); /// /// let date_duration = result.date.unwrap(); /// @@ -290,7 +311,7 @@ impl<'a> IsoDurationParser<'a> { /// # use ixdtf::parsers::{IsoDurationParser, records::{DurationParseRecord, TimeDurationRecord }}; /// let time_duration = "PT2H10M30S"; /// - /// let result = IsoDurationParser::new(time_duration).parse().unwrap(); + /// let result = IsoDurationParser::from_str(time_duration).parse().unwrap(); /// /// let (hours, minutes, seconds, fraction) = match result.time { /// // Hours variant is defined as { hours: u32, fraction: u64 } @@ -318,18 +339,18 @@ impl<'a> IsoDurationParser<'a> { #[derive(Debug)] pub(crate) struct Cursor<'a> { pos: usize, - source: &'a str, + source: &'a [u8], } impl<'a> Cursor<'a> { /// Create a new cursor from a source `String` value. #[must_use] - pub(crate) fn new(source: &'a str) -> Self { + pub fn new(source: &'a [u8]) -> Self { Self { pos: 0, source } } /// Returns a string value from a slice of the cursor. - fn slice(&self, start: usize, end: usize) -> Option<&'a str> { + fn slice(&self, start: usize, end: usize) -> Option<&'a [u8]> { self.source.get(start..end) } @@ -340,23 +361,31 @@ impl<'a> Cursor<'a> { /// Peek the value at next position (current + 1). fn peek(&self) -> Option { - self.peek_n_char(1) + self.peek_n(1) } /// Returns current position in source as `char`. fn current(&self) -> Option { - self.peek_n_char(0) + self.peek_n(0) } - /// Peek the value at n len from current. - fn peek_n(&self, n: usize) -> Option<&'a str> { - let index = self.pos + n; - self.source.get(index..index + 1) + /// Peeks the value at `n` as a `char`. + fn peek_n(&self, n: usize) -> Option { + let (_, char) = self.peek_with_info(n)?; + Some(char) } - /// Peeks the value at `n` as a `char`. - fn peek_n_char(&self, n: usize) -> Option { - self.peek_n(n).map(str::chars).and_then(|mut c| c.next()) + /// Peeks the value at `n` and returns the char with its byte length. + fn peek_with_info(&self, n: usize) -> Option<(usize, char)> { + let mut chars = + Utf8CharIndices::new(self.source.get(self.pos..self.source.len()).unwrap_or(&[])); + for _ in 0..n { + let _ = chars.next(); + } + let (_, peek) = chars.next()?; + let offset = chars.offset(); + + Some((offset, peek)) } /// Runs the provided check on the current position. @@ -377,9 +406,10 @@ impl<'a> Cursor<'a> { /// Returns `Cursor`'s current char and advances to the next position. fn next(&mut self) -> Option { - let result = self.current(); - self.advance(); - result + self.peek_with_info(0).map(|(offset, result)| { + self.advance_n(offset); + result + }) } /// Returns the next value as a digit. @@ -388,11 +418,11 @@ impl<'a> Cursor<'a> { /// - Returns a SyntaxError if value is not an ascii digit /// - Returns an AbruptEnd error if cursor ends. fn next_digit(&mut self) -> ParserResult> { - let p_digit = self.next_or(ParserError::InvalidEnd)?.to_digit(10); - let Some(digit) = p_digit else { - return Ok(None); - }; - Ok(Some(digit as u8)) + // Note: Char digit with a radix of ten must be in the range of a u8 + Ok(self + .next_or(ParserError::InvalidEnd)? + .to_digit(10) + .map(|d| d as u8)) } /// A utility next method that returns an `AbruptEnd` error if invalid. @@ -400,9 +430,14 @@ impl<'a> Cursor<'a> { self.next().ok_or(err) } - /// Advances the cursor's position by 1. + /// Advances the cursor's position by n bytes. + fn advance_n(&mut self, n: usize) { + self.pos += n; + } + + // Advances the cursor by 1 byte. fn advance(&mut self) { - self.pos += 1; + self.advance_n(1) } /// Utility function to advance when a condition is true diff --git a/utils/ixdtf/src/parsers/records.rs b/utils/ixdtf/src/parsers/records.rs index 07563cb9eca..ad98e1a28b8 100644 --- a/utils/ixdtf/src/parsers/records.rs +++ b/utils/ixdtf/src/parsers/records.rs @@ -17,7 +17,7 @@ pub struct IxdtfParseRecord<'a> { /// Parsed `TimeZone` annotation with critical flag and data (UTCOffset | IANA name) pub tz: Option>, /// The parsed calendar value. - pub calendar: Option<&'a str>, + pub calendar: Option<&'a [u8]>, } #[non_exhaustive] @@ -27,9 +27,9 @@ pub struct Annotation<'a> { /// Whether this annotation is flagged as critical pub critical: bool, /// The parsed key value of the annotation - pub key: &'a str, + pub key: &'a [u8], /// The parsed value of the annotation - pub value: &'a str, + pub value: &'a [u8], } #[allow(clippy::exhaustive_structs)] // DateRecord only allows for a year, month, and day value. @@ -73,7 +73,7 @@ pub struct TimeZoneAnnotation<'a> { #[derive(Debug, Clone, PartialEq)] pub enum TimeZoneRecord<'a> { /// TimeZoneIANAName - Name(&'a str), + Name(&'a [u8]), /// TimeZoneOffset Offset(UTCOffsetRecord), } diff --git a/utils/ixdtf/src/parsers/tests.rs b/utils/ixdtf/src/parsers/tests.rs index e3735e7fa60..834c6f7dc05 100644 --- a/utils/ixdtf/src/parsers/tests.rs +++ b/utils/ixdtf/src/parsers/tests.rs @@ -18,8 +18,8 @@ use crate::{ #[test] fn temporal_parser_basic() { - let basic_result = IxdtfParser::new("20201108").parse().unwrap(); - let sep_result = IxdtfParser::new("2020-11-08").parse().unwrap(); + let basic_result = IxdtfParser::from_str("20201108").parse().unwrap(); + let sep_result = IxdtfParser::from_str("2020-11-08").parse().unwrap(); assert_eq!( basic_result.date, @@ -34,7 +34,7 @@ fn temporal_parser_basic() { #[test] fn temporal_date_time_max() { - let result = IxdtfParser::new( + let result = IxdtfParser::from_str( "+002020-11-08T12:28:32.329402834[!America/Argentina/ComodRivadavia][!u-ca=iso8601]", ) .parse() @@ -53,7 +53,7 @@ fn temporal_date_time_max() { #[test] fn good_zoned_date_time() { - let result = IxdtfParser::new("2020-04-08[America/Chicago]") + let result = IxdtfParser::from_str("2020-04-08[America/Chicago]") .parse() .unwrap(); assert_eq!( @@ -69,7 +69,7 @@ fn good_zoned_date_time() { tz_annotation, TimeZoneAnnotation { critical: false, - tz: TimeZoneRecord::Name("America/Chicago") + tz: TimeZoneRecord::Name("America/Chicago".as_bytes()) } ); } @@ -77,7 +77,7 @@ fn good_zoned_date_time() { #[test] fn bad_zoned_date_time() { let bad_value = "2020-04-08(America/Chicago]"; - let err = IxdtfParser::new(bad_value).parse(); + let err = IxdtfParser::from_str(bad_value).parse(); assert_eq!( err, Err(ParserError::InvalidEnd), @@ -85,7 +85,7 @@ fn bad_zoned_date_time() { ); let bad_value = "2020-04-08[America/Chicago)"; - let err = IxdtfParser::new(bad_value).parse(); + let err = IxdtfParser::from_str(bad_value).parse(); assert_eq!( err, Err(ParserError::IanaChar), @@ -93,7 +93,7 @@ fn bad_zoned_date_time() { ); let bad_value = "2020-04-08[America/ Chicago)"; - let err = IxdtfParser::new(bad_value).parse(); + let err = IxdtfParser::from_str(bad_value).parse(); assert_eq!( err, Err(ParserError::IanaCharPostSeparator), @@ -101,7 +101,7 @@ fn bad_zoned_date_time() { ); let bad_value = "2020-04-08[Amer"; - let err = IxdtfParser::new(bad_value).parse(); + let err = IxdtfParser::from_str(bad_value).parse(); assert_eq!( err, Err(ParserError::AbruptEnd { @@ -111,7 +111,7 @@ fn bad_zoned_date_time() { ); let bad_value = "2020-04-08[u-ca=iso8601][Europe/London]"; - let err = IxdtfParser::new(bad_value).parse(); + let err = IxdtfParser::from_str(bad_value).parse(); assert_eq!( err, Err(ParserError::AnnotationKeyLeadingChar), @@ -122,8 +122,7 @@ fn bad_zoned_date_time() { #[test] fn good_extended_year_parsing() { let extended_year = "+002020-11-08"; - let mut ixdtf = IxdtfParser::new(extended_year); - let result = ixdtf.parse().unwrap(); + let result = IxdtfParser::from_str(extended_year).parse().unwrap(); assert_eq!( result.date, Some(DateRecord { @@ -135,8 +134,7 @@ fn good_extended_year_parsing() { ); let extended_year = "-002020-11-08"; - let mut ixdtf = IxdtfParser::new(extended_year); - let result = ixdtf.parse().unwrap(); + let result = IxdtfParser::from_str(extended_year).parse().unwrap(); assert_eq!( result.date, Some(DateRecord { @@ -151,7 +149,7 @@ fn good_extended_year_parsing() { #[test] fn bad_extended_year() { let bad_year = "-000000-11-08"; - let err = IxdtfParser::new(bad_year).parse(); + let err = IxdtfParser::from_str(bad_year).parse(); assert_eq!( err, Err(ParserError::DateExtendedYear), @@ -159,7 +157,7 @@ fn bad_extended_year() { ); let bad_year = "-1000000-11-08"; - let err = IxdtfParser::new(bad_year).parse(); + let err = IxdtfParser::from_str(bad_year).parse(); assert_eq!( err, Err(ParserError::DateMonth), @@ -167,7 +165,7 @@ fn bad_extended_year() { ); let bad_year = "+10000001108"; - let err = IxdtfParser::new(bad_year).parse(); + let err = IxdtfParser::from_str(bad_year).parse(); assert_eq!( err, Err(ParserError::InvalidEnd), @@ -177,11 +175,11 @@ fn bad_extended_year() { #[test] fn good_annotations_date_time() { - let mut basic = - IxdtfParser::new("2020-11-08[!America/Argentina/ComodRivadavia][u-ca=iso8601][foo=bar]"); - let mut omitted = IxdtfParser::new("+0020201108[!u-ca=iso8601][f-1a2b=a0sa-2l4s]"); - - let result = basic.parse().unwrap(); + let result = IxdtfParser::from_str( + "2020-11-08[!America/Argentina/ComodRivadavia][u-ca=iso8601][foo=bar]", + ) + .parse() + .unwrap(); let tz_annotation = result.tz.unwrap(); @@ -189,23 +187,25 @@ fn good_annotations_date_time() { tz_annotation, TimeZoneAnnotation { critical: true, - tz: TimeZoneRecord::Name("America/Argentina/ComodRivadavia"), + tz: TimeZoneRecord::Name("America/Argentina/ComodRivadavia".as_bytes()), } ); - assert_eq!(result.calendar, Some("iso8601")); + assert_eq!(result.calendar, Some("iso8601".as_bytes())); - let omit_result = omitted.parse().unwrap(); + let omit_result = IxdtfParser::from_str("+0020201108[!u-ca=iso8601][f-1a2b=a0sa-2l4s]") + .parse() + .unwrap(); assert!(omit_result.tz.is_none()); - assert_eq!(omit_result.calendar, Some("iso8601")); + assert_eq!(omit_result.calendar, Some("iso8601".as_bytes())); } #[test] fn invalid_day_for_month() { let bad_value = "2021-02-29"; - let err = IxdtfParser::new(bad_value).parse(); + let err = IxdtfParser::from_str(bad_value).parse(); assert_eq!( err, Err(ParserError::InvalidDayRange), @@ -213,7 +213,7 @@ fn invalid_day_for_month() { ); let bad_value = "1900-02-29"; - let err = IxdtfParser::new(bad_value).parse(); + let err = IxdtfParser::from_str(bad_value).parse(); assert_eq!( err, Err(ParserError::InvalidDayRange), @@ -221,7 +221,7 @@ fn invalid_day_for_month() { ); let bad_value = "2021-04-31"; - let err = IxdtfParser::new(bad_value).parse(); + let err = IxdtfParser::from_str(bad_value).parse(); assert_eq!( err, Err(ParserError::InvalidDayRange), @@ -229,7 +229,7 @@ fn invalid_day_for_month() { ); let bad_value = "2021-04-00"; - let err = IxdtfParser::new(bad_value).parse(); + let err = IxdtfParser::from_str(bad_value).parse(); assert_eq!( err, Err(ParserError::InvalidDayRange), @@ -240,7 +240,7 @@ fn invalid_day_for_month() { #[test] fn invalid_month() { let bad_value = "2021-00-29"; - let mut ixdtf = IxdtfParser::new(bad_value); + let mut ixdtf = IxdtfParser::from_str(bad_value); let err = ixdtf.parse(); assert_eq!( err, @@ -249,7 +249,7 @@ fn invalid_month() { ); let bad_value = "1900-13-29"; - let mut ixdtf = IxdtfParser::new(bad_value); + let mut ixdtf = IxdtfParser::from_str(bad_value); let err = ixdtf.parse(); assert_eq!( err, @@ -261,7 +261,7 @@ fn invalid_month() { #[test] fn invalid_annotations() { let bad_value = "2021-01-29 02:12:48+01:00:00(u-ca=iso8601]"; - let err = IxdtfParser::new(bad_value).parse(); + let err = IxdtfParser::from_str(bad_value).parse(); assert_eq!( err, Err(ParserError::InvalidEnd), @@ -269,7 +269,7 @@ fn invalid_annotations() { ); let bad_value = "2021-01-29 02:12:48+01:00:00[u-ca=iso8601)"; - let err = IxdtfParser::new(bad_value).parse(); + let err = IxdtfParser::from_str(bad_value).parse(); assert_eq!( err, Err(ParserError::AnnotationValueChar), @@ -277,7 +277,7 @@ fn invalid_annotations() { ); let bad_value = "2021-01-29 02:12:48+01:00:00[u][u-ca=iso8601]"; - let err = IxdtfParser::new(bad_value).parse(); + let err = IxdtfParser::from_str(bad_value).parse(); assert_eq!( err, Err(ParserError::InvalidAnnotation), @@ -285,7 +285,7 @@ fn invalid_annotations() { ); let bad_value = "2021-01-29 02:12:48+01:00:00[u-ca=iso8601][!foo=bar]"; - let err = IxdtfParser::new(bad_value).parse(); + let err = IxdtfParser::from_str(bad_value).parse(); assert_eq!( err, Err(ParserError::UnrecognizedCritical), @@ -296,7 +296,7 @@ fn invalid_annotations() { #[test] fn invalid_calendar_annotations() { let bad_value = "2021-01-29 02:12:48+01:00:00[!u-ca=iso8601][u-ca=japanese]"; - let err = IxdtfParser::new(bad_value).parse(); + let err = IxdtfParser::from_str(bad_value).parse(); assert_eq!( err, Err(ParserError::CriticalDuplicateCalendar), @@ -304,7 +304,7 @@ fn invalid_calendar_annotations() { ); let bad_value = "2021-01-29 02:12:48+01:00:00[u-ca=japanese][u-ca=iso8601][!u-ca=gregorian]"; - let err = IxdtfParser::new(bad_value).parse(); + let err = IxdtfParser::from_str(bad_value).parse(); assert_eq!( err, Err(ParserError::CriticalDuplicateCalendar), @@ -320,10 +320,11 @@ fn duplicate_same_calendar() { ]; for duplicate in duplicate_calendars { - let result = IxdtfParser::new(duplicate).parse().unwrap(); + let result = IxdtfParser::from_str(duplicate).parse().unwrap(); let calendar = result.calendar.unwrap(); assert_eq!( - calendar, "iso8601", + calendar, + "iso8601".as_bytes(), "Invalid Ixdtf parsing: \"{duplicate}\" should fail parsing." ); } @@ -333,7 +334,7 @@ fn duplicate_same_calendar() { fn valid_calendar_annotations() { let value = "2021-01-29 02:12:48+01:00:00[u-ca=japanese][u-ca=iso8601][u-ca=gregorian]"; let mut annotations = Vec::default(); - let result = IxdtfParser::new(value) + let result = IxdtfParser::from_str(value) .parse_with_annotation_handler(|annotation| { annotations.push(annotation.clone()); Some(annotation) @@ -341,7 +342,7 @@ fn valid_calendar_annotations() { .unwrap(); assert_eq!( result.calendar, - Some("japanese"), + Some("japanese".as_bytes()), "Valid annotation parsing: \"{value}\" should parse calendar as 'japanese'." ); @@ -349,8 +350,8 @@ fn valid_calendar_annotations() { annotations[1], Annotation { critical: false, - key: "u-ca", - value: "iso8601" + key: "u-ca".as_bytes(), + value: "iso8601".as_bytes() }, "Valid annotation parsing: \"{value}\" should parse first annotation as 'iso8601'." ); @@ -359,15 +360,15 @@ fn valid_calendar_annotations() { annotations[2], Annotation { critical: false, - key: "u-ca", - value: "gregorian" + key: "u-ca".as_bytes(), + value: "gregorian".as_bytes(), }, "Valid annotation parsing: \"{value}\" should parse second annotation as 'gregorian'." ); let value = "2021-01-29 02:12:48+01:00:00[u-ca=gregorian][u-ca=iso8601][u-ca=japanese]"; let mut annotations = Vec::default(); - let result = IxdtfParser::new(value) + let result = IxdtfParser::from_str(value) .parse_with_annotation_handler(|annotation| { annotations.push(annotation.clone()); Some(annotation) @@ -375,7 +376,7 @@ fn valid_calendar_annotations() { .unwrap(); assert_eq!( result.calendar, - Some("gregorian"), + Some("gregorian".as_bytes()), "Valid annotation parsing: \"{value}\" should parse calendar as 'gregorian'." ); @@ -383,8 +384,8 @@ fn valid_calendar_annotations() { annotations[1], Annotation { critical: false, - key: "u-ca", - value: "iso8601" + key: "u-ca".as_bytes(), + value: "iso8601".as_bytes() }, "Valid annotation parsing: \"{value}\" should parse first annotation as 'iso8601'." ); @@ -393,8 +394,8 @@ fn valid_calendar_annotations() { annotations[2], Annotation { critical: false, - key: "u-ca", - value: "japanese" + key: "u-ca".as_bytes(), + value: "japanese".as_bytes(), }, "Valid annotation parsing: \"{value}\" should parse second annotation as 'japanese'." ); @@ -410,7 +411,7 @@ fn temporal_year_month() { ]; for ym in possible_year_months { - let result = IxdtfParser::new(ym).parse_year_month().unwrap(); + let result = IxdtfParser::from_str(ym).parse_year_month().unwrap(); let date = result.date.unwrap(); @@ -423,15 +424,15 @@ fn temporal_year_month() { fn invalid_year_month() { // Valid AnnotatedDateTime, but not a valid AnnotatedYearMonth. let bad_value = "+002020-11T12:28:32[!u-ca=iso8601]"; - let err = IxdtfParser::new(bad_value).parse_year_month(); + let err = IxdtfParser::from_str(bad_value).parse_year_month(); assert_eq!(err, Err(ParserError::InvalidEnd)); let bad_value = "-202011[!u-ca=iso8601]"; - let err = IxdtfParser::new(bad_value).parse_year_month(); + let err = IxdtfParser::from_str(bad_value).parse_year_month(); assert_eq!(err, Err(ParserError::DateMonth)); let bad_value = "-00202011Z[Europe/Berlin]"; - let err = IxdtfParser::new(bad_value).parse_year_month(); + let err = IxdtfParser::from_str(bad_value).parse_year_month(); assert_eq!(err, Err(ParserError::InvalidEnd)); } @@ -440,7 +441,7 @@ fn temporal_month_day() { let possible_month_day = ["11-07", "1107[+04:00]", "--11-07", "--1107[+04:00]"]; for md in possible_month_day { - let result = IxdtfParser::new(md).parse_month_day().unwrap(); + let result = IxdtfParser::from_str(md).parse_month_day().unwrap(); let date = result.date.unwrap(); @@ -452,7 +453,7 @@ fn temporal_month_day() { #[test] fn invalid_month_day() { let bad_value = "-11-07"; - let err = IxdtfParser::new(bad_value).parse_month_day(); + let err = IxdtfParser::from_str(bad_value).parse_month_day(); assert_eq!(err, Err(ParserError::MonthDayHyphen)) } @@ -464,11 +465,11 @@ fn temporal_time() { "12:01:04", "12:01:04[u-ca=iso8601]", "12:01:04[+04:00][u-ca=iso8601]", - "12:01:04-05:00[America/New_York][u-ca=iso8601]", + "12:01:04-05:00[America/from_str_York][u-ca=iso8601]", ]; for time in possible_times { - let result = IxdtfParser::new(time).parse_time().unwrap(); + let result = IxdtfParser::from_str(time).parse_time().unwrap(); let time = result.time.unwrap(); assert_eq!(time.hour, 12); assert_eq!(time.minute, 1); @@ -479,7 +480,7 @@ fn temporal_time() { #[test] fn invalid_time() { let bad_value = "20240801"; - let err = IxdtfParser::new(bad_value).parse_time(); + let err = IxdtfParser::from_str(bad_value).parse_time(); assert_eq!( err, Err(ParserError::InvalidEnd), @@ -487,7 +488,7 @@ fn invalid_time() { ); let bad_value = "24-12-08"; - let err = IxdtfParser::new(bad_value).parse_time(); + let err = IxdtfParser::from_str(bad_value).parse_time(); assert_eq!( err, Err(ParserError::TimeHour), @@ -496,7 +497,7 @@ fn invalid_time() { // Attempts to parse UTC offset: -12, leaving -08 on end as junk. let bad_value = "T19-12-08"; - let err = IxdtfParser::new(bad_value).parse_time(); + let err = IxdtfParser::from_str(bad_value).parse_time(); assert_eq!( err, Err(ParserError::InvalidEnd), @@ -504,7 +505,7 @@ fn invalid_time() { ); let bad_value = "T19:12-089"; - let err = IxdtfParser::new(bad_value).parse_time(); + let err = IxdtfParser::from_str(bad_value).parse_time(); assert_eq!( err, Err(ParserError::InvalidEnd), @@ -512,7 +513,7 @@ fn invalid_time() { ); let bad_value = "T19:120-08"; - let err = IxdtfParser::new(bad_value).parse_time(); + let err = IxdtfParser::from_str(bad_value).parse_time(); assert_eq!( err, Err(ParserError::TimeSeparator), @@ -529,7 +530,7 @@ fn temporal_valid_instant_strings() { ]; for test in instants { - let result = IxdtfParser::new(test).parse(); + let result = IxdtfParser::from_str(test).parse(); assert!(result.is_ok()); } } @@ -550,14 +551,14 @@ fn temporal_duration_parsing() { ]; for dur in durations { - let ok_result = IsoDurationParser::new(dur).parse(); + let ok_result = IsoDurationParser::from_str(dur).parse(); assert!( ok_result.is_ok(), "Failing to parse a valid ISO 8601 target: \"{dur}\" should pass." ); } - let sub_second = IsoDurationParser::new(durations[2]).parse().unwrap(); + let sub_second = IsoDurationParser::from_str(durations[2]).parse().unwrap(); assert_eq!( sub_second, DurationParseRecord { @@ -579,7 +580,7 @@ fn temporal_duration_parsing() { durations[2] ); - let test_result = IsoDurationParser::new(durations[3]).parse().unwrap(); + let test_result = IsoDurationParser::from_str(durations[3]).parse().unwrap(); assert_eq!( test_result, DurationParseRecord { @@ -611,7 +612,7 @@ fn temporal_invalid_durations() { ]; for test in invalids { - let err = IsoDurationParser::new(test).parse(); + let err = IsoDurationParser::from_str(test).parse(); assert!( err.is_err(), "Invalid ISO8601 Duration target: \"{test}\" should fail duration parsing." @@ -625,15 +626,15 @@ fn maximum_duration_fraction() { use crate::parsers::IsoDurationParser; let test = "P1Y1DT1.999999999H"; - let result = IsoDurationParser::new(test).parse(); + let result = IsoDurationParser::from_str(test).parse(); assert!(result.is_ok()); let test = "P1Y1DT1H1.999999999M"; - let result = IsoDurationParser::new(test).parse(); + let result = IsoDurationParser::from_str(test).parse(); assert!(result.is_ok()); let test = "P1Y1DT1H1M1.999999999S"; - let result = IsoDurationParser::new(test).parse(); + let result = IsoDurationParser::from_str(test).parse(); assert!(result.is_ok()); } @@ -643,11 +644,11 @@ fn duration_exceeds_range() { use crate::parsers::IsoDurationParser; let test = "P1000000000000000000000000000000000000000YT1H"; - let err = IsoDurationParser::new(test).parse(); + let err = IsoDurationParser::from_str(test).parse(); assert_eq!(err, Err(ParserError::DurationValueExceededRange)); let test = "P1YT1000000000000000000000000000000000000000H"; - let err = IsoDurationParser::new(test).parse(); + let err = IsoDurationParser::from_str(test).parse(); assert_eq!(err, Err(ParserError::DurationValueExceededRange)); } @@ -690,7 +691,7 @@ fn temporal_invalid_iso_datetime_strings() { ]; for invalid_target in INVALID_DATETIME_STRINGS { - let error_result = IxdtfParser::new(invalid_target).parse(); + let error_result = IxdtfParser::from_str(invalid_target).parse(); assert!( error_result.is_err(), "Invalid ISO8601 `DateTime` target: \"{invalid_target}\" should fail parsing." @@ -701,7 +702,7 @@ fn temporal_invalid_iso_datetime_strings() { #[test] fn test_correct_datetime() { let dt = "2022-11-08"; - let parsed = IxdtfParser::new(dt).parse(); + let parsed = IxdtfParser::from_str(dt).parse(); assert_eq!( parsed, Ok(IxdtfParseRecord { @@ -718,7 +719,7 @@ fn test_correct_datetime() { ); let dt = "20220605"; - let parsed = IxdtfParser::new(dt).parse(); + let parsed = IxdtfParser::from_str(dt).parse(); assert_eq!( parsed, Ok(IxdtfParseRecord { @@ -735,7 +736,7 @@ fn test_correct_datetime() { ); let dt = "2022-06-05T04"; - let parsed = IxdtfParser::new(dt).parse(); + let parsed = IxdtfParser::from_str(dt).parse(); assert_eq!( parsed, Ok(IxdtfParseRecord { @@ -757,7 +758,7 @@ fn test_correct_datetime() { ); let dt = "2022-06-05t04:34"; - let parsed = IxdtfParser::new(dt).parse(); + let parsed = IxdtfParser::from_str(dt).parse(); assert_eq!( parsed, Ok(IxdtfParseRecord { @@ -779,7 +780,7 @@ fn test_correct_datetime() { ); let dt = "2022-06-05 04:34:22"; - let parsed = IxdtfParser::new(dt).parse(); + let parsed = IxdtfParser::from_str(dt).parse(); assert_eq!( parsed, Ok(IxdtfParseRecord { @@ -801,7 +802,7 @@ fn test_correct_datetime() { ); let dt = "2022-06-05 04:34:22.000"; - let parsed = IxdtfParser::new(dt).parse(); + let parsed = IxdtfParser::from_str(dt).parse(); assert_eq!( parsed, Ok(IxdtfParseRecord { @@ -823,7 +824,7 @@ fn test_correct_datetime() { ); let dt = "2022-06-05 043422.000"; - let parsed = IxdtfParser::new(dt).parse(); + let parsed = IxdtfParser::from_str(dt).parse(); assert_eq!( parsed, Ok(IxdtfParseRecord { @@ -848,65 +849,53 @@ fn test_correct_datetime() { #[test] fn test_bad_date() { let dt = "-2022-06-05"; - let mut ixdtf = IxdtfParser::new(dt); - let parsed = ixdtf.parse(); - assert_eq!(parsed, Err(ParserError::DateExtendedYear)); + let err = IxdtfParser::from_str(dt).parse(); + assert_eq!(err, Err(ParserError::DateExtendedYear)); let dt = "!2022-06-05"; - let mut ixdtf = IxdtfParser::new(dt); - let parsed = ixdtf.parse(); - assert_eq!(parsed, Err(ParserError::DateYear)); + let err = IxdtfParser::from_str(dt).parse(); + assert_eq!(err, Err(ParserError::DateYear)); let dt = "20-06-05"; - let mut ixdtf = IxdtfParser::new(dt); - let parsed = ixdtf.parse(); - assert_eq!(parsed, Err(ParserError::DateYear)); + let err = IxdtfParser::from_str(dt).parse(); + assert_eq!(err, Err(ParserError::DateYear)); let dt = "2022-0605"; - let mut ixdtf = IxdtfParser::new(dt); - let parsed = ixdtf.parse(); - assert_eq!(parsed, Err(ParserError::DateSeparator)); + let err = IxdtfParser::from_str(dt).parse(); + assert_eq!(err, Err(ParserError::DateSeparator)); let dt = "202206-05"; - let mut ixdtf = IxdtfParser::new(dt); - let parsed = ixdtf.parse(); - assert_eq!(parsed, Err(ParserError::DateSeparator)); + let err = IxdtfParser::from_str(dt).parse(); + assert_eq!(err, Err(ParserError::DateSeparator)); let dt = "2022-06-05e"; - let mut ixdtf = IxdtfParser::new(dt); - let parsed = ixdtf.parse(); - assert_eq!(parsed, Err(ParserError::InvalidEnd)); + let err = IxdtfParser::from_str(dt).parse(); + assert_eq!(err, Err(ParserError::InvalidEnd)); } #[test] fn test_bad_time_spec_separator() { let dt = "2022-06-05 043422.000"; - let mut ixdtf = IxdtfParser::new(dt); - let parsed = ixdtf.parse(); - assert_eq!(parsed, Err(ParserError::TimeHour)); + let err = IxdtfParser::from_str(dt).parse(); + assert_eq!(err, Err(ParserError::TimeHour)); let dt = "2022-06-05 04:3422.000"; - let mut ixdtf = IxdtfParser::new(dt); - let parsed = ixdtf.parse(); - assert_eq!(parsed, Err(ParserError::TimeSeparator)); + let err = IxdtfParser::from_str(dt).parse(); + assert_eq!(err, Err(ParserError::TimeSeparator)); let dt = "2022-06-05 0434:22.000"; - let mut ixdtf = IxdtfParser::new(dt); - let parsed = ixdtf.parse(); - assert_eq!(parsed, Err(ParserError::TimeSeparator)); + let err = IxdtfParser::from_str(dt).parse(); + assert_eq!(err, Err(ParserError::TimeSeparator)); let dt = "2022-06-05 03422.000"; - let mut ixdtf = IxdtfParser::new(dt); - let parsed = ixdtf.parse(); - assert_eq!(parsed, Err(ParserError::TimeSecond)); + let err = IxdtfParser::from_str(dt).parse(); + assert_eq!(err, Err(ParserError::TimeSecond)); let dt = "2022-06-05 3:42:22.000"; - let mut ixdtf = IxdtfParser::new(dt); - let parsed = ixdtf.parse(); - assert_eq!(parsed, Err(ParserError::TimeHour)); + let err = IxdtfParser::from_str(dt).parse(); + assert_eq!(err, Err(ParserError::TimeHour)); let dt = "2022-06-05 03:42:22;000"; - let mut ixdtf = IxdtfParser::new(dt); - let parsed = ixdtf.parse(); - assert_eq!(parsed, Err(ParserError::InvalidEnd)); + let err = IxdtfParser::from_str(dt).parse(); + assert_eq!(err, Err(ParserError::InvalidEnd)); } diff --git a/utils/ixdtf/src/parsers/timezone.rs b/utils/ixdtf/src/parsers/timezone.rs index 27c48b3f000..0599a6f9b2d 100644 --- a/utils/ixdtf/src/parsers/timezone.rs +++ b/utils/ixdtf/src/parsers/timezone.rs @@ -26,7 +26,7 @@ pub(crate) fn parse_ambiguous_tz_annotation<'a>( // Peek position + 1 to check for critical flag. let mut current_peek = 1; let critical = cursor - .peek_n_char(current_peek) + .peek_n(current_peek) .map(is_critical_flag) .ok_or(ParserError::abrupt_end("AmbiguousAnnotation"))?; @@ -36,14 +36,14 @@ pub(crate) fn parse_ambiguous_tz_annotation<'a>( } let leading_char = cursor - .peek_n_char(current_peek) + .peek_n(current_peek) .ok_or(ParserError::abrupt_end("AmbiguousAnnotation"))?; if is_tz_leading_char(leading_char) || is_sign(leading_char) { // Ambigious start values when lowercase alpha that is shared between `TzLeadingChar` and `KeyLeadingChar`. if is_a_key_leading_char(leading_char) { let mut peek_pos = current_peek + 1; - while let Some(ch) = cursor.peek_n_char(peek_pos) { + while let Some(ch) = cursor.peek_n(peek_pos) { if is_tz_name_separator(ch) || (is_tz_char(ch) && !is_a_key_char(ch)) { let tz = parse_tz_annotation(cursor)?; return Ok(Some(tz)); @@ -147,7 +147,7 @@ pub(crate) fn parse_date_time_utc(cursor: &mut Cursor) -> ParserResult