From 43842ebf8e4a664218ed326dd622ef5b18737cf0 Mon Sep 17 00:00:00 2001 From: yuankunzhang Date: Sat, 23 Aug 2025 22:20:51 +0800 Subject: [PATCH] refactor: misc minor refactors --- src/items/epoch.rs | 10 ++++++---- src/items/primitive.rs | 8 ++++++++ src/items/time.rs | 2 +- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/items/epoch.rs b/src/items/epoch.rs index 21a5c20..60edc8f 100644 --- a/src/items/epoch.rs +++ b/src/items/epoch.rs @@ -1,6 +1,8 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. +//! Parse a timestamp item. +//! //! From the GNU docs: //! //! > If you precede a number with ‘@’, it represents an internal timestamp as @@ -22,7 +24,7 @@ use winnow::{ ModalResult, Parser, }; -use super::primitive::{dec_uint, s}; +use super::primitive::{dec_uint, plus_or_minus, s}; /// Represents a timestamp with nanosecond accuracy. /// @@ -43,7 +45,7 @@ impl TryFrom for jiff::Timestamp { fn try_from(ts: Timestamp) -> Result { jiff::Timestamp::new( ts.second, - i32::try_from(ts.nanosecond).map_err(|_| "nanosecond value exceeds i32::MAX")?, + i32::try_from(ts.nanosecond).map_err(|_| "nanosecond in timestamp exceeds i32::MAX")?, ) .map_err(|_| "timestamp value is out of valid range") } @@ -52,7 +54,7 @@ impl TryFrom for jiff::Timestamp { /// Parse a timestamp in the form of `@1234567890` or `@-1234567890.12345` or /// `@1234567890,12345`. pub(super) fn parse(input: &mut &str) -> ModalResult { - (s("@"), opt(s(one_of(['-', '+']))), sec_and_nsec) + (s("@"), opt(plus_or_minus), s(sec_and_nsec)) .verify_map(|(_, sign, (sec, nsec))| { let sec = i64::try_from(sec).ok()?; let (second, nanosecond) = match (sign, nsec) { @@ -74,7 +76,7 @@ pub(super) fn parse(input: &mut &str) -> ModalResult { /// (padded with zeros on the right if fewer digits are present). If the second /// part is omitted, it defaults to 0 nanoseconds. pub(super) fn sec_and_nsec(input: &mut &str) -> ModalResult<(u64, u32)> { - (s(dec_uint), opt(preceded(one_of(['.', ',']), digit1))) + (dec_uint, opt(preceded(one_of(['.', ',']), digit1))) .verify_map(|(sec, opt_nsec_str)| match opt_nsec_str { Some(nsec_str) if nsec_str.len() >= 9 => Some((sec, nsec_str[..9].parse().ok()?)), Some(nsec_str) => { diff --git a/src/items/primitive.rs b/src/items/primitive.rs index 8aff9b7..e1de350 100644 --- a/src/items/primitive.rs +++ b/src/items/primitive.rs @@ -122,6 +122,14 @@ where s(':').void().parse_next(input) } +/// Parse a plus or minus character optionally preceeded by whitespace. +pub(super) fn plus_or_minus<'a, E>(input: &mut &'a str) -> winnow::Result +where + E: ParserError<&'a str>, +{ + s(alt(('+', '-'))).parse_next(input) +} + /// Create a context error with a reason. pub(super) fn ctx_err(reason: &'static str) -> ContextError { let mut err = ContextError::new(); diff --git a/src/items/time.rs b/src/items/time.rs index 5ece5c2..2a79943 100644 --- a/src/items/time.rs +++ b/src/items/time.rs @@ -166,7 +166,7 @@ pub(super) fn minute(input: &mut &str) -> ModalResult { /// Parse a number of seconds in `0..60` and an optional number of nanoseconds /// (default to 0 if not set). fn second(input: &mut &str) -> ModalResult<(u8, u32)> { - sec_and_nsec + s(sec_and_nsec) .verify_map(|(s, ns)| if s < 60 { Some((s as u8, ns)) } else { None }) .parse_next(input) }