From 58a2149a8ef5eaab7236bc447a4a37a3965b579b Mon Sep 17 00:00:00 2001 From: Paul Dicker Date: Tue, 11 Jul 2023 13:33:39 +0200 Subject: [PATCH] Add `StrftimeItems::parse_to_owned` --- src/format/mod.rs | 16 ++++++++++++++++ src/format/strftime.rs | 43 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/src/format/mod.rs b/src/format/mod.rs index fda4d425b6..a822882786 100644 --- a/src/format/mod.rs +++ b/src/format/mod.rs @@ -363,6 +363,22 @@ const fn internal_fixed(val: InternalInternal) -> Item<'static> { Item::Fixed(Fixed::Internal(InternalFixed { val })) } +impl<'a> Item<'a> { + /// Convert items that contain a reference to the format string into an owned variant. + #[cfg(any(feature = "alloc", feature = "std"))] + pub fn to_owned(self) -> Item<'static> { + match self { + Item::Literal(s) => Item::OwnedLiteral(Box::from(s)), + Item::Space(s) => Item::OwnedSpace(Box::from(s)), + Item::Numeric(n, p) => Item::Numeric(n, p), + Item::Fixed(f) => Item::Fixed(f), + Item::OwnedLiteral(l) => Item::OwnedLiteral(l), + Item::OwnedSpace(s) => Item::OwnedSpace(s), + Item::Error => Item::Error, + } + } +} + /// An error from the `parse` function. #[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)] pub struct ParseError(ParseErrorKind); diff --git a/src/format/strftime.rs b/src/format/strftime.rs index e55fe70961..26fa391201 100644 --- a/src/format/strftime.rs +++ b/src/format/strftime.rs @@ -338,6 +338,49 @@ impl<'a> StrftimeItems<'a> { }) .collect() } + + /// Parse format string into a `Vec` of [`Item`]'s that contain no references to slices of the + /// format string. + /// + /// A `Vec` created with [`StrftimeItems::parse`] contains references to the format string, + /// binding the lifetime of the `Vec` to that string. [`StrftimeItems::parse_to_owned`] will + /// convert the references to owned types. + /// + /// # Errors + /// + /// Returns an error if the format string contains an invalid or unrecognized formatting + /// specifier. + /// + /// # Example + /// + /// ``` + /// use chrono::format::{Item, ParseError, StrftimeItems}; + /// use chrono::NaiveDate; + /// + /// fn format_items(date_fmt: &str, time_fmt: &str) -> Result>, ParseError> { + /// // `fmt_string` is dropped at the end of this function. + /// let fmt_string = format!("{} {}", date_fmt, time_fmt); + /// StrftimeItems::new(&fmt_string).parse_to_owned() + /// } + /// + /// let fmt_items = format_items("%e %b %Y", "%k.%M")?; + /// let datetime = NaiveDate::from_ymd_opt(2023, 7, 11).unwrap().and_hms_opt(9, 0, 0).unwrap(); + /// + /// assert_eq!( + /// datetime.format_with_items(fmt_items.as_slice().iter()).to_string(), + /// "11 Jul 2023 9.00" + /// ); + /// # Ok::<(), ParseError>(()) + /// ``` + #[cfg(any(feature = "alloc", feature = "std"))] + pub fn parse_to_owned(self) -> Result>, ParseError> { + self.into_iter() + .map(|item| match item == Item::Error { + false => Ok(item.to_owned()), + true => Err(BAD_FORMAT), + }) + .collect() + } } const HAVE_ALTERNATES: &str = "z";