Skip to content

Commit bb723b6

Browse files
committed
Add trailing_input modifier to end
1 parent 31c4f8e commit bb723b6

File tree

9 files changed

+105
-16
lines changed

9 files changed

+105
-16
lines changed

time-macros/src/format_description/format_item.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,9 @@ component_definition! {
207207
Day = "day" {
208208
padding = "padding": Option<Padding> => padding,
209209
},
210-
End = "end" {},
210+
End = "end" {
211+
trailing_input = "trailing_input": Option<TrailingInput> => trailing_input,
212+
},
211213
Hour = "hour" {
212214
padding = "padding": Option<Padding> => padding,
213215
base = "repr": Option<HourBase> => is_12_hour_clock,
@@ -382,6 +384,12 @@ modifier! {
382384
OneOrMore = b"1+",
383385
}
384386

387+
enum TrailingInput {
388+
#[default]
389+
Prohibit = b"prohibit",
390+
Discard = b"discard",
391+
}
392+
385393
enum UnixTimestampPrecision {
386394
#[default]
387395
Second = b"second",

time-macros/src/format_description/public/modifier.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,5 +266,14 @@ to_tokens! {
266266
}
267267

268268
to_tokens! {
269-
pub(crate) struct End {}
269+
pub(crate) enum TrailingInput {
270+
Prohibit,
271+
Discard,
272+
}
273+
}
274+
275+
to_tokens! {
276+
pub(crate) struct End {
277+
pub(crate) trailing_input: TrailingInput = TrailingInput::Prohibit,
278+
}
270279
}

time/src/format_description/modifier.rs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -293,12 +293,22 @@ pub struct UnixTimestamp {
293293
pub sign_is_mandatory: bool,
294294
}
295295

296+
/// Whether trailing input after the declared end is permitted.
297+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
298+
pub enum TrailingInput {
299+
/// Trailing input is not permitted and will cause an error.
300+
Prohibit,
301+
/// Trailing input is permitted but discarded.
302+
Discard,
303+
}
304+
296305
/// The end of input.
297-
///
298-
/// There is currently not customization for this modifier.
299306
#[non_exhaustive]
300307
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
301-
pub struct End;
308+
pub struct End {
309+
/// How to handle any input after this component.
310+
pub trailing_input: TrailingInput,
311+
}
302312

303313
/// Generate the provided code if and only if `pub` is present.
304314
macro_rules! if_pub {
@@ -432,6 +442,10 @@ impl_const_default! {
432442
precision: UnixTimestampPrecision::Second,
433443
sign_is_mandatory: false,
434444
};
435-
/// Creates a modifier used to represent the end of input.
436-
@pub End => End;
445+
/// Indicate that any trailing characters after the end of input are prohibited and will cause
446+
/// an error when used with `parse`.
447+
TrailingInput => Self::Prohibit;
448+
/// Creates a modifier used to represent the end of input, not allowing any trailing input (i.e.
449+
/// the input must be fully consumed).
450+
@pub End => Self { trailing_input: TrailingInput::Prohibit };
437451
}

time/src/format_description/parse/format_item.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,9 @@ component_definition! {
285285
Day = "day" {
286286
padding = "padding": Option<Padding> => padding,
287287
},
288-
End = "end" {},
288+
End = "end" {
289+
trailing_input = "trailing_input": Option<TrailingInput> => trailing_input,
290+
},
289291
Hour = "hour" {
290292
padding = "padding": Option<Padding> => padding,
291293
base = "repr": Option<HourBase> => is_12_hour_clock,
@@ -487,6 +489,12 @@ modifier! {
487489
OneOrMore = b"1+",
488490
}
489491

492+
enum TrailingInput {
493+
#[default]
494+
Prohibit = b"prohibit",
495+
Discard = b"discard",
496+
}
497+
490498
enum UnixTimestampPrecision {
491499
#[default]
492500
Second = b"second",

time/src/formatting/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ where
297297
))
298298
}
299299
},
300-
End(modifier::End {}) => 0,
300+
End(modifier::End { trailing_input: _ }) => 0,
301301

302302
// This is functionally the same as a wildcard arm, but it will cause an error if a new
303303
// component is added. This is to avoid a bug where a new component, the code compiles, and

time/src/parsing/component.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -471,14 +471,15 @@ pub(crate) fn parse_unix_timestamp(
471471
}
472472
}
473473

474-
/// Parse the `end` component, which represents the end of input. If any input is remaining, `None`
475-
/// is returned.
474+
/// Parse the `end` component, which represents the end of input. If any input is remaining _and_
475+
/// trailing input is prohibited, `None` is returned. If trailing input is permitted, it is
476+
/// discarded.
476477
#[inline]
477-
pub(crate) const fn parse_end(input: &[u8], end: modifier::End) -> Option<ParsedItem<'_, ()>> {
478-
let modifier::End {} = end;
478+
pub(crate) fn parse_end(input: &[u8], end: modifier::End) -> Option<ParsedItem<'_, ()>> {
479+
let modifier::End { trailing_input } = end;
479480

480-
if input.is_empty() {
481-
Some(ParsedItem(input, ()))
481+
if trailing_input == modifier::TrailingInput::Discard || input.is_empty() {
482+
Some(ParsedItem(b"", ()))
482483
} else {
483484
None
484485
}

time/tests/integration/macros.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,25 @@ fn format_description_coverage() {
347347
assert_eq!(
348348
format_description!("[end]"),
349349
&[BorrowedFormatItem::Component(Component::End(modifier!(
350-
End
350+
End {
351+
trailing_input: TrailingInput::Prohibit,
352+
}
353+
)))]
354+
);
355+
assert_eq!(
356+
format_description!("[end trailing_input:prohibit]"),
357+
&[BorrowedFormatItem::Component(Component::End(modifier!(
358+
End {
359+
trailing_input: TrailingInput::Prohibit,
360+
}
361+
)))]
362+
);
363+
assert_eq!(
364+
format_description!("[end trailing_input:discard]"),
365+
&[BorrowedFormatItem::Component(Component::End(modifier!(
366+
End {
367+
trailing_input: TrailingInput::Discard,
368+
}
351369
)))]
352370
);
353371
}

time/tests/integration/parse_format_description.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,11 @@ fn modifiers(
126126
(UnixTimestampPrecision::Nanosecond, "precision:nanosecond"),
127127
)]
128128
unix_timestamp_precision: _,
129+
#[values(
130+
(TrailingInput::Prohibit, "trailing_input:prohibit"),
131+
(TrailingInput::Discard, "trailing_input:discard"),
132+
)]
133+
trailing_input: _,
129134
) {}
130135

131136
#[rstest]
@@ -242,6 +247,16 @@ fn day_component(padding: M<Padding>) {
242247
);
243248
}
244249

250+
#[apply(modifiers)]
251+
fn end_component(trailing_input: M<TrailingInput>) {
252+
assert_eq!(
253+
parse_with_modifiers!("end", trailing_input),
254+
Ok(vec![BorrowedFormatItem::Component(Component::End(
255+
modifier_m!(End { trailing_input })
256+
))])
257+
);
258+
}
259+
245260
#[apply(modifiers)]
246261
fn minute_component(padding: M<Padding>) {
247262
assert_eq!(

time/tests/integration/parsing.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1941,6 +1941,13 @@ fn end() -> time::Result<()> {
19411941
Time::parse("00:00", &fd::parse("[hour]:[minute][end]")?),
19421942
Ok(time!(0:00))
19431943
);
1944+
assert_eq!(
1945+
Time::parse(
1946+
"00:00abcdef",
1947+
&fd::parse("[hour]:[minute][end trailing_input:discard]")?
1948+
),
1949+
Ok(time!(0:00))
1950+
);
19441951
assert_eq!(
19451952
Time::parse(
19461953
"00:00:00",
@@ -1957,6 +1964,15 @@ fn end() -> time::Result<()> {
19571964
error::ParseFromDescription::UnexpectedTrailingCharacters { .. }
19581965
))
19591966
));
1967+
assert!(matches!(
1968+
Time::parse(
1969+
"00:00:00",
1970+
&fd::parse_owned::<2>("[hour]:[minute][end trailing_input:discard]:[second]")?
1971+
),
1972+
Err(error::Parse::ParseFromDescription(
1973+
error::ParseFromDescription::InvalidLiteral { .. }
1974+
))
1975+
));
19601976

19611977
Ok(())
19621978
}

0 commit comments

Comments
 (0)