Accept Borrow<Item> 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
This commit is contained in:
Michal Srb 2019-11-22 12:15:16 +01:00
parent 53ef941c3a
commit 05acc869b9
8 changed files with 49 additions and 34 deletions

View File

@ -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<Item>`, so one can
use values or references.
## 0.4.9
### Fixes

View File

@ -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<Tz: TimeZone> Date<Tz> 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<I>
where I: Iterator<Item=Item<'a>> + Clone {
pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
where I: Iterator<Item=B> + Clone, B: Borrow<Item<'a>> {
DelayedFormat::new_with_offset(Some(self.naive_local()), None, &self.offset, items)
}

View File

@ -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<FixedOffset> {
pub fn parse_from_rfc2822(s: &str) -> ParseResult<DateTime<FixedOffset>> {
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<FixedOffset> {
pub fn parse_from_rfc3339(s: &str) -> ParseResult<DateTime<FixedOffset>> {
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<Tz: TimeZone> DateTime<Tz> 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<Tz: TimeZone> DateTime<Tz> 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<Tz: TimeZone> DateTime<Tz> 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<I>
where I: Iterator<Item=Item<'a>> + Clone {
pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
where I: Iterator<Item=B> + Clone, B: Borrow<Item<'a>> {
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<FixedOffset> {
];
let mut parsed = Parsed::new();
try!(parse(&mut parsed, s, ITEMS.iter().cloned()));
try!(parse(&mut parsed, s, ITEMS.iter()));
parsed.to_datetime()
}
}

View File

@ -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<Item=Item<'a>>
where I: Iterator<Item=B> + Clone, B: Borrow<Item<'a>>
{
// 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<I> {
}
#[cfg(any(feature = "alloc", feature = "std", test))]
impl<'a, I: Iterator<Item=Item<'a>> + Clone> DelayedFormat<I> {
impl<'a, I: Iterator<Item=B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> {
/// Makes a new `DelayedFormat` value out of local date and time.
pub fn new(date: Option<NaiveDate>, time: Option<NaiveTime>, items: I) -> DelayedFormat<I> {
DelayedFormat { date: date, time: time, off: None, items: items }
@ -649,7 +650,7 @@ impl<'a, I: Iterator<Item=Item<'a>> + Clone> DelayedFormat<I> {
}
#[cfg(any(feature = "alloc", feature = "std", test))]
impl<'a, I: Iterator<Item=Item<'a>> + Clone> fmt::Display for DelayedFormat<I> {
impl<'a, I: Iterator<Item=B> + Clone, B: Borrow<Item<'a>>> fmt::Display for DelayedFormat<I> {
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())
}

View File

@ -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<Item=Item<'a>> {
pub fn parse<'a, I, B>(parsed: &mut Parsed, mut s: &str, items: I) -> ParseResult<()>
where I: Iterator<Item=B>, B: Borrow<Item<'a>> {
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<Parsed> {
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<DateTime<FixedOffset>> {
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<FixedOffset>) -> 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<DateTime<FixedOffset>> {
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<FixedOffset>) -> 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

View File

@ -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<I>
where I: Iterator<Item=Item<'a>> + Clone {
pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
where I: Iterator<Item=B> + Clone, B: Borrow<Item<'a>> {
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()
}
}

View File

@ -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<I>
where I: Iterator<Item=Item<'a>> + Clone {
pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
where I: Iterator<Item=B> + Clone, B: Borrow<Item<'a>> {
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)
}
}

View File

@ -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<I>
where I: Iterator<Item=Item<'a>> + Clone {
pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
where I: Iterator<Item=B> + Clone, B: Borrow<Item<'a>> {
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()
}
}