From 05acc869b922dab6fe9b3546ece427a5e58544af Mon Sep 17 00:00:00 2001 From: Michal Srb Date: Fri, 22 Nov 2019 12:15:16 +0100 Subject: [PATCH] Accept Borrow as items The parse::parse and format::format functions accepted Iterator of owned Items. While it is sometimes convenient to pass in the owned values, neither of the functions really need to own them, so references would be enough. The Borrow trait allows us to pass in Iterator over values, references, boxes, etc. According to RFC 1105 this is a minor change, because it shouldn't break any existing code. And chrono is in pre-1.0 version anyway. This allows us to remove multiple cloned() calls which speeds up parsing and formating: name control ns/iter remove-cloned ns/iter diff ns/iter diff % speedup datetime::tests::bench_datetime_from_str 712 582 -130 -18.26% x 1.22 datetime::tests::bench_datetime_parse_from_rfc2822 252 244 -8 -3.17% x 1.03 datetime::tests::bench_datetime_parse_from_rfc3339 242 239 -3 -1.24% x 1.01 --- CHANGELOG.md | 8 ++++++++ src/date.rs | 5 +++-- src/datetime.rs | 19 ++++++++++--------- src/format/mod.rs | 13 +++++++------ src/format/parse.rs | 17 +++++++++-------- src/naive/date.rs | 7 ++++--- src/naive/datetime.rs | 7 ++++--- src/naive/time.rs | 7 ++++--- 8 files changed, 49 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c8b941..9cc0c24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,14 @@ Chrono obeys the principle of [Semantic Versioning](http://semver.org/). There were/are numerous minor versions before 1.0 due to the language changes. Versions with only mechanical changes will be omitted from the following list. +## next + +### Features + +* Functions that were accepting `Iterator` of `Item`s (for example + `format_with_items`) now accept `Iterator` of `Borrow`, so one can + use values or references. + ## 0.4.9 ### Fixes diff --git a/src/date.rs b/src/date.rs index d449009..7026c41 100644 --- a/src/date.rs +++ b/src/date.rs @@ -3,6 +3,7 @@ //! ISO 8601 calendar date with time zone. +use core::borrow::Borrow; use core::{fmt, hash}; use core::cmp::Ordering; use core::ops::{Add, Sub}; @@ -258,8 +259,8 @@ impl Date where Tz::Offset: fmt::Display { /// Formats the date with the specified formatting items. #[cfg(any(feature = "alloc", feature = "std", test))] #[inline] - pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat - where I: Iterator> + Clone { + pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat + where I: Iterator + Clone, B: Borrow> { DelayedFormat::new_with_offset(Some(self.naive_local()), None, &self.offset, items) } diff --git a/src/datetime.rs b/src/datetime.rs index f0a8c19..e39020d 100644 --- a/src/datetime.rs +++ b/src/datetime.rs @@ -25,6 +25,7 @@ use format::{Item, Numeric, Pad, Fixed}; use format::{parse, Parsed, ParseError, ParseResult, StrftimeItems}; #[cfg(any(feature = "alloc", feature = "std", test))] use format::DelayedFormat; +use core::borrow::Borrow; /// Specific formatting options for seconds. This may be extended in the /// future, so exhaustive matching in external code is not recommended. @@ -326,7 +327,7 @@ impl DateTime { pub fn parse_from_rfc2822(s: &str) -> ParseResult> { const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC2822)]; let mut parsed = Parsed::new(); - try!(parse(&mut parsed, s, ITEMS.iter().cloned())); + try!(parse(&mut parsed, s, ITEMS.iter())); parsed.to_datetime() } @@ -338,7 +339,7 @@ impl DateTime { pub fn parse_from_rfc3339(s: &str) -> ParseResult> { const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC3339)]; let mut parsed = Parsed::new(); - try!(parse(&mut parsed, s, ITEMS.iter().cloned())); + try!(parse(&mut parsed, s, ITEMS.iter())); parsed.to_datetime() } @@ -374,14 +375,14 @@ impl DateTime where Tz::Offset: fmt::Display { #[cfg(any(feature = "alloc", feature = "std", test))] pub fn to_rfc2822(&self) -> String { const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC2822)]; - self.format_with_items(ITEMS.iter().cloned()).to_string() + self.format_with_items(ITEMS.iter()).to_string() } /// Returns an RFC 3339 and ISO 8601 date and time string such as `1996-12-19T16:39:57-08:00`. #[cfg(any(feature = "alloc", feature = "std", test))] pub fn to_rfc3339(&self) -> String { const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC3339)]; - self.format_with_items(ITEMS.iter().cloned()).to_string() + self.format_with_items(ITEMS.iter()).to_string() } /// Return an RFC 3339 and ISO 8601 date and time string with subseconds @@ -450,11 +451,11 @@ impl DateTime where Tz::Offset: fmt::Display { match ssitem { None => self.format_with_items( - PREFIX.iter().chain([tzitem].iter()).cloned() + PREFIX.iter().chain([tzitem].iter()) ).to_string(), Some(s) => self.format_with_items( - PREFIX.iter().chain([s, tzitem].iter()).cloned() + PREFIX.iter().chain([s, tzitem].iter()) ).to_string(), } } @@ -462,8 +463,8 @@ impl DateTime where Tz::Offset: fmt::Display { /// Formats the combined date and time with the specified formatting items. #[cfg(any(feature = "alloc", feature = "std", test))] #[inline] - pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat - where I: Iterator> + Clone { + pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat + where I: Iterator + Clone, B: Borrow> { let local = self.naive_local(); DelayedFormat::new_with_offset(Some(local.date()), Some(local.time()), &self.offset, items) } @@ -638,7 +639,7 @@ impl str::FromStr for DateTime { ]; let mut parsed = Parsed::new(); - try!(parse(&mut parsed, s, ITEMS.iter().cloned())); + try!(parse(&mut parsed, s, ITEMS.iter())); parsed.to_datetime() } } diff --git a/src/format/mod.rs b/src/format/mod.rs index b8e6458..e9ae6b9 100644 --- a/src/format/mod.rs +++ b/src/format/mod.rs @@ -17,6 +17,7 @@ #![allow(ellipsis_inclusive_range_patterns)] +use core::borrow::Borrow; use core::fmt; use core::str::FromStr; #[cfg(any(feature = "std", test))] @@ -356,14 +357,14 @@ const BAD_FORMAT: ParseError = ParseError(ParseErrorKind::BadFormat); /// Tries to format given arguments with given formatting items. /// Internally used by `DelayedFormat`. #[cfg(any(feature = "alloc", feature = "std", test))] -pub fn format<'a, I>( +pub fn format<'a, I, B>( w: &mut fmt::Formatter, date: Option<&NaiveDate>, time: Option<&NaiveTime>, off: Option<&(String, FixedOffset)>, items: I, ) -> fmt::Result - where I: Iterator> + where I: Iterator + Clone, B: Borrow> { // full and abbreviated month and weekday names static SHORT_MONTHS: [&'static str; 12] = @@ -380,7 +381,7 @@ pub fn format<'a, I>( let mut result = String::new(); for item in items { - match item { + match item.borrow() { Item::Literal(s) | Item::Space(s) => result.push_str(s), #[cfg(any(feature = "alloc", feature = "std", test))] Item::OwnedLiteral(ref s) | Item::OwnedSpace(ref s) => result.push_str(s), @@ -433,7 +434,7 @@ pub fn format<'a, I>( if let Some(v) = v { try!( - if (spec == Year || spec == IsoYear) && !(0 <= v && v < 10_000) { + if (*spec == Year || *spec == IsoYear) && !(0 <= v && v < 10_000) { // non-four-digit years require an explicit sign as per ISO 8601 match pad { Pad::None => write!(result, "{:+}", v), @@ -633,7 +634,7 @@ pub struct DelayedFormat { } #[cfg(any(feature = "alloc", feature = "std", test))] -impl<'a, I: Iterator> + Clone> DelayedFormat { +impl<'a, I: Iterator + Clone, B: Borrow>> DelayedFormat { /// Makes a new `DelayedFormat` value out of local date and time. pub fn new(date: Option, time: Option, items: I) -> DelayedFormat { DelayedFormat { date: date, time: time, off: None, items: items } @@ -649,7 +650,7 @@ impl<'a, I: Iterator> + Clone> DelayedFormat { } #[cfg(any(feature = "alloc", feature = "std", test))] -impl<'a, I: Iterator> + Clone> fmt::Display for DelayedFormat { +impl<'a, I: Iterator + Clone, B: Borrow>> fmt::Display for DelayedFormat { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { format(f, self.date.as_ref(), self.time.as_ref(), self.off.as_ref(), self.items.clone()) } diff --git a/src/format/parse.rs b/src/format/parse.rs index e8e0d25..ed88722 100644 --- a/src/format/parse.rs +++ b/src/format/parse.rs @@ -6,6 +6,7 @@ #![allow(deprecated)] +use core::borrow::Borrow; use core::usize; use Weekday; @@ -204,14 +205,14 @@ fn parse_rfc3339<'a>(parsed: &mut Parsed, mut s: &'a str) -> ParseResult<(&'a st /// so one can prepend any number of whitespace then any number of zeroes before numbers. /// /// - (Still) obeying the intrinsic parsing width. This allows, for example, parsing `HHMMSS`. -pub fn parse<'a, I>(parsed: &mut Parsed, mut s: &str, items: I) -> ParseResult<()> - where I: Iterator> { +pub fn parse<'a, I, B>(parsed: &mut Parsed, mut s: &str, items: I) -> ParseResult<()> + where I: Iterator, B: Borrow> { macro_rules! try_consume { ($e:expr) => ({ let (s_, v) = try!($e); s = s_; v }) } for item in items { - match item { + match item.borrow() { Item::Literal(prefix) => { if s.len() < prefix.len() { return Err(TOO_SHORT); } if !s.starts_with(prefix) { return Err(INVALID); } @@ -388,7 +389,7 @@ fn test_parse() { // workaround for Rust issue #22255 fn parse_all(s: &str, items: &[Item]) -> ParseResult { let mut parsed = Parsed::new(); - try!(parse(&mut parsed, s, items.iter().cloned())); + try!(parse(&mut parsed, s, items.iter())); Ok(parsed) } @@ -699,12 +700,12 @@ fn test_rfc2822() { fn rfc2822_to_datetime(date: &str) -> ParseResult> { let mut parsed = Parsed::new(); - try!(parse(&mut parsed, date, [Item::Fixed(Fixed::RFC2822)].iter().cloned())); + try!(parse(&mut parsed, date, [Item::Fixed(Fixed::RFC2822)].iter())); parsed.to_datetime() } fn fmt_rfc2822_datetime(dt: DateTime) -> String { - dt.format_with_items([Item::Fixed(Fixed::RFC2822)].iter().cloned()).to_string() + dt.format_with_items([Item::Fixed(Fixed::RFC2822)].iter()).to_string() } // Test against test data above @@ -780,12 +781,12 @@ fn test_rfc3339() { fn rfc3339_to_datetime(date: &str) -> ParseResult> { let mut parsed = Parsed::new(); - try!(parse(&mut parsed, date, [Item::Fixed(Fixed::RFC3339)].iter().cloned())); + try!(parse(&mut parsed, date, [Item::Fixed(Fixed::RFC3339)].iter())); parsed.to_datetime() } fn fmt_rfc3339_datetime(dt: DateTime) -> String { - dt.format_with_items([Item::Fixed(Fixed::RFC3339)].iter().cloned()).to_string() + dt.format_with_items([Item::Fixed(Fixed::RFC3339)].iter()).to_string() } // Test against test data above diff --git a/src/naive/date.rs b/src/naive/date.rs index f67b670..a307604 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -3,6 +3,7 @@ //! ISO 8601 calendar date without timezone. +use core::borrow::Borrow; use core::{str, fmt}; use core::ops::{Add, Sub, AddAssign, SubAssign}; use num_traits::ToPrimitive; @@ -920,8 +921,8 @@ impl NaiveDate { /// ~~~~ #[cfg(any(feature = "alloc", feature = "std", test))] #[inline] - pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat - where I: Iterator> + Clone { + pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat + where I: Iterator + Clone, B: Borrow> { DelayedFormat::new(Some(*self), None, items) } @@ -1516,7 +1517,7 @@ impl str::FromStr for NaiveDate { ]; let mut parsed = Parsed::new(); - try!(parse(&mut parsed, s, ITEMS.iter().cloned())); + try!(parse(&mut parsed, s, ITEMS.iter())); parsed.to_naive_date() } } diff --git a/src/naive/datetime.rs b/src/naive/datetime.rs index 2049782..feeb9d4 100644 --- a/src/naive/datetime.rs +++ b/src/naive/datetime.rs @@ -3,6 +3,7 @@ //! ISO 8601 date and time without timezone. +use core::borrow::Borrow; use core::{str, fmt, hash}; use core::ops::{Add, Sub, AddAssign, SubAssign}; use num_traits::ToPrimitive; @@ -649,8 +650,8 @@ impl NaiveDateTime { /// ~~~~ #[cfg(any(feature = "alloc", feature = "std", test))] #[inline] - pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat - where I: Iterator> + Clone { + pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat + where I: Iterator + Clone, B: Borrow> { DelayedFormat::new(Some(self.date), Some(self.time), items) } @@ -1487,7 +1488,7 @@ impl str::FromStr for NaiveDateTime { ]; let mut parsed = Parsed::new(); - try!(parse(&mut parsed, s, ITEMS.iter().cloned())); + try!(parse(&mut parsed, s, ITEMS.iter())); parsed.to_naive_datetime_with_offset(0) } } diff --git a/src/naive/time.rs b/src/naive/time.rs index c0272c8..9ae72f2 100644 --- a/src/naive/time.rs +++ b/src/naive/time.rs @@ -3,6 +3,7 @@ //! ISO 8601 time without timezone. +use core::borrow::Borrow; use core::{str, fmt, hash}; use core::ops::{Add, Sub, AddAssign, SubAssign}; use oldtime::Duration as OldDuration; @@ -727,8 +728,8 @@ impl NaiveTime { /// ~~~~ #[cfg(any(feature = "alloc", feature = "std", test))] #[inline] - pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat - where I: Iterator> + Clone { + pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat + where I: Iterator + Clone, B: Borrow> { DelayedFormat::new(None, Some(*self), items) } @@ -1312,7 +1313,7 @@ impl str::FromStr for NaiveTime { ]; let mut parsed = Parsed::new(); - try!(parse(&mut parsed, s, ITEMS.iter().cloned())); + try!(parse(&mut parsed, s, ITEMS.iter())); parsed.to_naive_time() } }