From db8784f97cbe71a37f49f89d3cc95288f8dbc5cf Mon Sep 17 00:00:00 2001 From: Michal Srb Date: Fri, 22 Nov 2019 11:57:43 +0100 Subject: [PATCH 1/9] Fix existing benchmarks The #[cfg(bench)] attribute does not exist and is always false. Lets define a feature "bench" which can be used to enable benchmarks when building with nightly. --- Cargo.toml | 1 + src/lib.rs | 4 +++- src/naive/internals.rs | 3 +-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6fbb591721..a572dc96a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ alloc = [] std = [] clock = ["time", "std"] wasmbind = ["wasm-bindgen", "js-sys"] +bench = ["std"] [dependencies] time = { version = "0.1.39", optional = true } diff --git a/src/lib.rs b/src/lib.rs index bbc4324044..928b5158c0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -383,7 +383,7 @@ #![doc(html_root_url = "https://docs.rs/chrono/latest/")] -#![cfg_attr(bench, feature(test))] // lib stability features as per RFC #507 +#![cfg_attr(feature = "bench", feature(test))] // lib stability features as per RFC #507 #![deny(missing_docs)] #![deny(missing_debug_implementations)] @@ -427,6 +427,8 @@ extern crate doc_comment; extern crate wasm_bindgen; #[cfg(all(target_arch = "wasm32", feature="wasmbind"))] extern crate js_sys; +#[cfg(feature = "bench")] +extern crate test; #[cfg(test)] doctest!("../README.md"); diff --git a/src/naive/internals.rs b/src/naive/internals.rs index a1cd1f6d46..d0431634bf 100644 --- a/src/naive/internals.rs +++ b/src/naive/internals.rs @@ -470,7 +470,6 @@ impl fmt::Debug for Mdf { #[cfg(test)] mod tests { #[cfg(test)] extern crate num_iter; - #[cfg(bench)] extern crate test; use Weekday; use super::{Of, Mdf}; @@ -517,7 +516,7 @@ mod tests { assert_eq!(GF.nisoweeks(), 52); } - #[cfg(bench)] + #[cfg(feature = "bench")] #[bench] fn bench_year_flags_from_year(bh: &mut test::Bencher) { bh.iter(|| { From 53ef941c3ad1f49e39667a0dafd0cdb513b0d1ff Mon Sep 17 00:00:00 2001 From: Michal Srb Date: Fri, 22 Nov 2019 12:13:36 +0100 Subject: [PATCH 2/9] Add benchmarks for DateTime parsing and formatting --- src/datetime.rs | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/datetime.rs b/src/datetime.rs index 3bd6c77bfe..f0a8c19738 100644 --- a/src/datetime.rs +++ b/src/datetime.rs @@ -2213,4 +2213,53 @@ mod tests { assert_eq!(format!("{} ", ymd_formatted), format!("{:<17}", ymd)); assert_eq!(format!(" {} ", ymd_formatted), format!("{:^17}", ymd)); } + + #[cfg(feature = "bench")] + #[bench] + fn bench_datetime_parse_from_rfc2822(bh: &mut test::Bencher) { + bh.iter(|| { + let str = test::black_box("Wed, 18 Feb 2015 23:16:09 +0000"); + DateTime::parse_from_rfc2822(str).unwrap() + }); + } + + #[cfg(feature = "bench")] + #[bench] + fn bench_datetime_parse_from_rfc3339(bh: &mut test::Bencher) { + bh.iter(|| { + let str = test::black_box("2015-02-18T23:59:60.234567+05:00"); + DateTime::parse_from_rfc3339(str).unwrap() + }); + } + + #[cfg(feature = "bench")] + #[bench] + fn bench_datetime_from_str(bh: &mut test::Bencher) { + use std::str::FromStr; + + bh.iter(|| { + let str = test::black_box("2019-03-30T18:46:57.193Z"); + DateTime::::from_str(str).unwrap() + }); + } + + #[cfg(feature = "bench")] + #[bench] + fn bench_datetime_to_rfc2822(bh: &mut test::Bencher) { + let pst = FixedOffset::east(8 * 60 * 60); + let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 13, 084_660_000); + bh.iter(|| { + test::black_box(dt).to_rfc2822() + }); + } + + #[cfg(feature = "bench")] + #[bench] + fn bench_datetime_to_rfc3339(bh: &mut test::Bencher) { + let pst = FixedOffset::east(8 * 60 * 60); + let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 13, 084_660_000); + bh.iter(|| { + test::black_box(dt).to_rfc3339() + }); + } } From 05acc869b922dab6fe9b3546ece427a5e58544af Mon Sep 17 00:00:00 2001 From: Michal Srb Date: Fri, 22 Nov 2019 12:15:16 +0100 Subject: [PATCH 3/9] 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 0c8b941098..9cc0c248dc 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 d4490092d4..7026c41345 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 f0a8c19738..e39020d0a7 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 b8e6458345..e9ae6b9064 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 e8e0d25752..ed887226a8 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 f67b670cdb..a3076046ef 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 2049782203..feeb9d43da 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 c0272c8fe9..9ae72f2c28 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() } } From f7318277e217aa31da2c022867fa23b5a20d92fa Mon Sep 17 00:00:00 2001 From: Michal Srb Date: Fri, 22 Nov 2019 14:30:45 +0100 Subject: [PATCH 4/9] Simplify ITEMS in FromStr implementations The Item::Space calls str::trim_left and Item::Numeric also calls str::trim_left before doing anything else, so there is no need to have Item::Space before Item::Numeric. Speeds up parsing: name remove-cloned ns/iter simplify-from-str ns/iter diff ns/iter diff % speedup datetime::tests::bench_datetime_from_str 582 448 -134 -23.02% x 1.30 datetime::tests::bench_datetime_parse_from_rfc2822 244 242 -2 -0.82% x 1.01 datetime::tests::bench_datetime_parse_from_rfc3339 239 234 -5 -2.09% x 1.02 --- src/datetime.rs | 12 ++++++------ src/naive/date.rs | 6 +++--- src/naive/datetime.rs | 12 ++++++------ src/naive/time.rs | 6 +++--- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/datetime.rs b/src/datetime.rs index e39020d0a7..7e32da75f4 100644 --- a/src/datetime.rs +++ b/src/datetime.rs @@ -622,17 +622,17 @@ impl str::FromStr for DateTime { fn from_str(s: &str) -> ParseResult> { const ITEMS: &'static [Item<'static>] = &[ - Item::Space(""), Item::Numeric(Numeric::Year, Pad::Zero), + Item::Numeric(Numeric::Year, Pad::Zero), Item::Space(""), Item::Literal("-"), - Item::Space(""), Item::Numeric(Numeric::Month, Pad::Zero), + Item::Numeric(Numeric::Month, Pad::Zero), Item::Space(""), Item::Literal("-"), - Item::Space(""), Item::Numeric(Numeric::Day, Pad::Zero), + Item::Numeric(Numeric::Day, Pad::Zero), Item::Space(""), Item::Literal("T"), // XXX shouldn't this be case-insensitive? - Item::Space(""), Item::Numeric(Numeric::Hour, Pad::Zero), + Item::Numeric(Numeric::Hour, Pad::Zero), Item::Space(""), Item::Literal(":"), - Item::Space(""), Item::Numeric(Numeric::Minute, Pad::Zero), + Item::Numeric(Numeric::Minute, Pad::Zero), Item::Space(""), Item::Literal(":"), - Item::Space(""), Item::Numeric(Numeric::Second, Pad::Zero), + Item::Numeric(Numeric::Second, Pad::Zero), Item::Fixed(Fixed::Nanosecond), Item::Space(""), Item::Fixed(Fixed::TimezoneOffsetZ), Item::Space(""), diff --git a/src/naive/date.rs b/src/naive/date.rs index a3076046ef..9ac240f972 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -1508,11 +1508,11 @@ impl str::FromStr for NaiveDate { fn from_str(s: &str) -> ParseResult { const ITEMS: &'static [Item<'static>] = &[ - Item::Space(""), Item::Numeric(Numeric::Year, Pad::Zero), + Item::Numeric(Numeric::Year, Pad::Zero), Item::Space(""), Item::Literal("-"), - Item::Space(""), Item::Numeric(Numeric::Month, Pad::Zero), + Item::Numeric(Numeric::Month, Pad::Zero), Item::Space(""), Item::Literal("-"), - Item::Space(""), Item::Numeric(Numeric::Day, Pad::Zero), + Item::Numeric(Numeric::Day, Pad::Zero), Item::Space(""), ]; diff --git a/src/naive/datetime.rs b/src/naive/datetime.rs index feeb9d43da..ba9cf4feb0 100644 --- a/src/naive/datetime.rs +++ b/src/naive/datetime.rs @@ -1473,17 +1473,17 @@ impl str::FromStr for NaiveDateTime { fn from_str(s: &str) -> ParseResult { const ITEMS: &'static [Item<'static>] = &[ - Item::Space(""), Item::Numeric(Numeric::Year, Pad::Zero), + Item::Numeric(Numeric::Year, Pad::Zero), Item::Space(""), Item::Literal("-"), - Item::Space(""), Item::Numeric(Numeric::Month, Pad::Zero), + Item::Numeric(Numeric::Month, Pad::Zero), Item::Space(""), Item::Literal("-"), - Item::Space(""), Item::Numeric(Numeric::Day, Pad::Zero), + Item::Numeric(Numeric::Day, Pad::Zero), Item::Space(""), Item::Literal("T"), // XXX shouldn't this be case-insensitive? - Item::Space(""), Item::Numeric(Numeric::Hour, Pad::Zero), + Item::Numeric(Numeric::Hour, Pad::Zero), Item::Space(""), Item::Literal(":"), - Item::Space(""), Item::Numeric(Numeric::Minute, Pad::Zero), + Item::Numeric(Numeric::Minute, Pad::Zero), Item::Space(""), Item::Literal(":"), - Item::Space(""), Item::Numeric(Numeric::Second, Pad::Zero), + Item::Numeric(Numeric::Second, Pad::Zero), Item::Fixed(Fixed::Nanosecond), Item::Space(""), ]; diff --git a/src/naive/time.rs b/src/naive/time.rs index 9ae72f2c28..ff02f4d8c6 100644 --- a/src/naive/time.rs +++ b/src/naive/time.rs @@ -1304,11 +1304,11 @@ impl str::FromStr for NaiveTime { fn from_str(s: &str) -> ParseResult { const ITEMS: &'static [Item<'static>] = &[ - Item::Space(""), Item::Numeric(Numeric::Hour, Pad::Zero), + Item::Numeric(Numeric::Hour, Pad::Zero), Item::Space(""), Item::Literal(":"), - Item::Space(""), Item::Numeric(Numeric::Minute, Pad::Zero), + Item::Numeric(Numeric::Minute, Pad::Zero), Item::Space(""), Item::Literal(":"), - Item::Space(""), Item::Numeric(Numeric::Second, Pad::Zero), + Item::Numeric(Numeric::Second, Pad::Zero), Item::Fixed(Fixed::Nanosecond), Item::Space(""), ]; From 6da5359d39433dca43a3f25e65172d6592eae5f7 Mon Sep 17 00:00:00 2001 From: Michal Srb Date: Fri, 22 Nov 2019 14:34:30 +0100 Subject: [PATCH 5/9] Reimplement scan::number The original would first check that there is right amount of numeric characters and then parsed them using the std::str::parse, which internally checks the characters again and also checks for -/+ prefix, which is not necessary in this case. Since we are already going over the characters, we may as well do the parsing ourselves. The length of the function is roughly the same and it is faster: name simplify-from-str ns/iter reimplement-number ns/iter diff ns/iter diff % speedup datetime::tests::bench_datetime_from_str 448 365 -83 -18.53% x 1.23 datetime::tests::bench_datetime_parse_from_rfc2822 242 195 -47 -19.42% x 1.24 datetime::tests::bench_datetime_parse_from_rfc3339 234 166 -68 -29.06% x 1.41 --- src/format/scan.rs | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/format/scan.rs b/src/format/scan.rs index c3111758c2..6ceb387306 100644 --- a/src/format/scan.rs +++ b/src/format/scan.rs @@ -33,20 +33,31 @@ fn equals(s: &str, pattern: &str) -> bool { pub fn number(s: &str, min: usize, max: usize) -> ParseResult<(&str, i64)> { assert!(min <= max); - // limit `s` to given number of digits - let mut window = s.as_bytes(); - if window.len() > max { window = &window[..max]; } - - // scan digits - let upto = window.iter().position(|&c| c < b'0' || b'9' < c) - .unwrap_or_else(|| window.len()); - if upto < min { - return Err(if window.is_empty() {TOO_SHORT} else {INVALID}); + // We are only interested in ascii numbers, so we can work with the `str` as bytes. We stop on + // the first non-numeric byte, which may be another ascii character or beginning of multi-byte + // UTF-8 character. + let bytes = s.as_bytes(); + if bytes.len() < min { + return Err(TOO_SHORT); + } + + let mut n = 0i64; + for (i, c) in bytes.iter().take(max).copied().enumerate() { + if c < b'0' || b'9' < c { + if i < min { + return Err(INVALID); + } else { + return Ok((&s[i..], n)); + } + } + + n = match n.checked_mul(10).and_then(|n| n.checked_add((c - b'0') as i64)) { + Some(n) => n, + None => return Err(OUT_OF_RANGE), + }; } - // we can overflow here, which is the only possible cause of error from `parse`. - let v: i64 = try!(s[..upto].parse().map_err(|_| OUT_OF_RANGE)); - Ok((&s[upto..], v)) + Ok((&s[max.min(bytes.len())..], n)) } /// Tries to consume at least one digits as a fractional second. From a716b48e9ddcd301887fe4c0bc73861052eda8b3 Mon Sep 17 00:00:00 2001 From: Michal Srb Date: Fri, 22 Nov 2019 14:42:55 +0100 Subject: [PATCH 6/9] Inline some parse related functions Speedups: datetime::tests::bench_datetime_from_str 365 337 -28 -7.67% x 1.08 datetime::tests::bench_datetime_parse_from_rfc2822 195 181 -14 -7.18% x 1.08 datetime::tests::bench_datetime_parse_from_rfc3339 166 142 -24 -14.46% x 1.17 --- src/format/parsed.rs | 22 ++++++++++++++++++++++ src/format/scan.rs | 1 + 2 files changed, 23 insertions(+) diff --git a/src/format/parsed.rs b/src/format/parsed.rs index 7b9708d07a..a09dd196b6 100644 --- a/src/format/parsed.rs +++ b/src/format/parsed.rs @@ -112,6 +112,7 @@ pub struct Parsed { /// Checks if `old` is either empty or has the same value to `new` (i.e. "consistent"), /// and if it is empty, set `old` to `new` as well. +#[inline] fn set_if_consistent(old: &mut Option, new: T) -> ParseResult<()> { if let Some(ref old) = *old { if *old == new {Ok(())} else {Err(IMPOSSIBLE)} @@ -141,82 +142,97 @@ impl Parsed { } /// Tries to set the [`year`](#structfield.year) field from given value. + #[inline] pub fn set_year(&mut self, value: i64) -> ParseResult<()> { set_if_consistent(&mut self.year, try!(value.to_i32().ok_or(OUT_OF_RANGE))) } /// Tries to set the [`year_div_100`](#structfield.year_div_100) field from given value. + #[inline] pub fn set_year_div_100(&mut self, value: i64) -> ParseResult<()> { if value < 0 { return Err(OUT_OF_RANGE); } set_if_consistent(&mut self.year_div_100, try!(value.to_i32().ok_or(OUT_OF_RANGE))) } /// Tries to set the [`year_mod_100`](#structfield.year_mod_100) field from given value. + #[inline] pub fn set_year_mod_100(&mut self, value: i64) -> ParseResult<()> { if value < 0 { return Err(OUT_OF_RANGE); } set_if_consistent(&mut self.year_mod_100, try!(value.to_i32().ok_or(OUT_OF_RANGE))) } /// Tries to set the [`isoyear`](#structfield.isoyear) field from given value. + #[inline] pub fn set_isoyear(&mut self, value: i64) -> ParseResult<()> { set_if_consistent(&mut self.isoyear, try!(value.to_i32().ok_or(OUT_OF_RANGE))) } /// Tries to set the [`isoyear_div_100`](#structfield.isoyear_div_100) field from given value. + #[inline] pub fn set_isoyear_div_100(&mut self, value: i64) -> ParseResult<()> { if value < 0 { return Err(OUT_OF_RANGE); } set_if_consistent(&mut self.isoyear_div_100, try!(value.to_i32().ok_or(OUT_OF_RANGE))) } /// Tries to set the [`isoyear_mod_100`](#structfield.isoyear_mod_100) field from given value. + #[inline] pub fn set_isoyear_mod_100(&mut self, value: i64) -> ParseResult<()> { if value < 0 { return Err(OUT_OF_RANGE); } set_if_consistent(&mut self.isoyear_mod_100, try!(value.to_i32().ok_or(OUT_OF_RANGE))) } /// Tries to set the [`month`](#structfield.month) field from given value. + #[inline] pub fn set_month(&mut self, value: i64) -> ParseResult<()> { set_if_consistent(&mut self.month, try!(value.to_u32().ok_or(OUT_OF_RANGE))) } /// Tries to set the [`week_from_sun`](#structfield.week_from_sun) field from given value. + #[inline] pub fn set_week_from_sun(&mut self, value: i64) -> ParseResult<()> { set_if_consistent(&mut self.week_from_sun, try!(value.to_u32().ok_or(OUT_OF_RANGE))) } /// Tries to set the [`week_from_mon`](#structfield.week_from_mon) field from given value. + #[inline] pub fn set_week_from_mon(&mut self, value: i64) -> ParseResult<()> { set_if_consistent(&mut self.week_from_mon, try!(value.to_u32().ok_or(OUT_OF_RANGE))) } /// Tries to set the [`isoweek`](#structfield.isoweek) field from given value. + #[inline] pub fn set_isoweek(&mut self, value: i64) -> ParseResult<()> { set_if_consistent(&mut self.isoweek, try!(value.to_u32().ok_or(OUT_OF_RANGE))) } /// Tries to set the [`weekday`](#structfield.weekday) field from given value. + #[inline] pub fn set_weekday(&mut self, value: Weekday) -> ParseResult<()> { set_if_consistent(&mut self.weekday, value) } /// Tries to set the [`ordinal`](#structfield.ordinal) field from given value. + #[inline] pub fn set_ordinal(&mut self, value: i64) -> ParseResult<()> { set_if_consistent(&mut self.ordinal, try!(value.to_u32().ok_or(OUT_OF_RANGE))) } /// Tries to set the [`day`](#structfield.day) field from given value. + #[inline] pub fn set_day(&mut self, value: i64) -> ParseResult<()> { set_if_consistent(&mut self.day, try!(value.to_u32().ok_or(OUT_OF_RANGE))) } /// Tries to set the [`hour_div_12`](#structfield.hour_div_12) field from given value. /// (`false` for AM, `true` for PM) + #[inline] pub fn set_ampm(&mut self, value: bool) -> ParseResult<()> { set_if_consistent(&mut self.hour_div_12, if value {1} else {0}) } /// Tries to set the [`hour_mod_12`](#structfield.hour_mod_12) field from /// given hour number in 12-hour clocks. + #[inline] pub fn set_hour12(&mut self, value: i64) -> ParseResult<()> { if value < 1 || value > 12 { return Err(OUT_OF_RANGE); } set_if_consistent(&mut self.hour_mod_12, value as u32 % 12) @@ -224,6 +240,7 @@ impl Parsed { /// Tries to set both [`hour_div_12`](#structfield.hour_div_12) and /// [`hour_mod_12`](#structfield.hour_mod_12) fields from given value. + #[inline] pub fn set_hour(&mut self, value: i64) -> ParseResult<()> { let v = try!(value.to_u32().ok_or(OUT_OF_RANGE)); try!(set_if_consistent(&mut self.hour_div_12, v / 12)); @@ -232,26 +249,31 @@ impl Parsed { } /// Tries to set the [`minute`](#structfield.minute) field from given value. + #[inline] pub fn set_minute(&mut self, value: i64) -> ParseResult<()> { set_if_consistent(&mut self.minute, try!(value.to_u32().ok_or(OUT_OF_RANGE))) } /// Tries to set the [`second`](#structfield.second) field from given value. + #[inline] pub fn set_second(&mut self, value: i64) -> ParseResult<()> { set_if_consistent(&mut self.second, try!(value.to_u32().ok_or(OUT_OF_RANGE))) } /// Tries to set the [`nanosecond`](#structfield.nanosecond) field from given value. + #[inline] pub fn set_nanosecond(&mut self, value: i64) -> ParseResult<()> { set_if_consistent(&mut self.nanosecond, try!(value.to_u32().ok_or(OUT_OF_RANGE))) } /// Tries to set the [`timestamp`](#structfield.timestamp) field from given value. + #[inline] pub fn set_timestamp(&mut self, value: i64) -> ParseResult<()> { set_if_consistent(&mut self.timestamp, value) } /// Tries to set the [`offset`](#structfield.offset) field from given value. + #[inline] pub fn set_offset(&mut self, value: i64) -> ParseResult<()> { set_if_consistent(&mut self.offset, try!(value.to_i32().ok_or(OUT_OF_RANGE))) } diff --git a/src/format/scan.rs b/src/format/scan.rs index 6ceb387306..acbc92f026 100644 --- a/src/format/scan.rs +++ b/src/format/scan.rs @@ -30,6 +30,7 @@ fn equals(s: &str, pattern: &str) -> bool { /// The absence of digits at all is an unconditional error. /// More than `max` digits are consumed up to the first `max` digits. /// Any number that does not fit in `i64` is an error. +#[inline] pub fn number(s: &str, min: usize, max: usize) -> ParseResult<(&str, i64)> { assert!(min <= max); From 0b8c248791475a519bd9a0c538359d382314a1fb Mon Sep 17 00:00:00 2001 From: Michal Srb Date: Fri, 22 Nov 2019 19:32:05 +0100 Subject: [PATCH 7/9] Fix build with rust 1.13.0 --- src/format/mod.rs | 108 ++++++++++++++++++++++---------------------- src/format/parse.rs | 86 +++++++++++++++++------------------ src/format/scan.rs | 4 +- 3 files changed, 99 insertions(+), 99 deletions(-) diff --git a/src/format/mod.rs b/src/format/mod.rs index e9ae6b9064..dfd8627fee 100644 --- a/src/format/mod.rs +++ b/src/format/mod.rs @@ -382,11 +382,11 @@ pub fn format<'a, I, B>( for item in items { match item.borrow() { - Item::Literal(s) | Item::Space(s) => result.push_str(s), + &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), + &Item::OwnedLiteral(ref s) | &Item::OwnedSpace(ref s) => result.push_str(s), - Item::Numeric(spec, pad) => { + &Item::Numeric(ref spec, ref pad) => { use self::Numeric::*; let week_from_sun = |d: &NaiveDate| @@ -395,31 +395,31 @@ pub fn format<'a, I, B>( (d.ordinal() as i32 - d.weekday().num_days_from_monday() as i32 + 7) / 7; let (width, v) = match spec { - Year => (4, date.map(|d| i64::from(d.year()))), - YearDiv100 => (2, date.map(|d| div_floor(i64::from(d.year()), 100))), - YearMod100 => (2, date.map(|d| mod_floor(i64::from(d.year()), 100))), - IsoYear => (4, date.map(|d| i64::from(d.iso_week().year()))), - IsoYearDiv100 => (2, date.map(|d| div_floor( + &Year => (4, date.map(|d| i64::from(d.year()))), + &YearDiv100 => (2, date.map(|d| div_floor(i64::from(d.year()), 100))), + &YearMod100 => (2, date.map(|d| mod_floor(i64::from(d.year()), 100))), + &IsoYear => (4, date.map(|d| i64::from(d.iso_week().year()))), + &IsoYearDiv100 => (2, date.map(|d| div_floor( i64::from(d.iso_week().year()), 100))), - IsoYearMod100 => (2, date.map(|d| mod_floor( + &IsoYearMod100 => (2, date.map(|d| mod_floor( i64::from(d.iso_week().year()), 100))), - Month => (2, date.map(|d| i64::from(d.month()))), - Day => (2, date.map(|d| i64::from(d.day()))), - WeekFromSun => (2, date.map(|d| i64::from(week_from_sun(d)))), - WeekFromMon => (2, date.map(|d| i64::from(week_from_mon(d)))), - IsoWeek => (2, date.map(|d| i64::from(d.iso_week().week()))), - NumDaysFromSun => (1, date.map(|d| i64::from(d.weekday() + &Month => (2, date.map(|d| i64::from(d.month()))), + &Day => (2, date.map(|d| i64::from(d.day()))), + &WeekFromSun => (2, date.map(|d| i64::from(week_from_sun(d)))), + &WeekFromMon => (2, date.map(|d| i64::from(week_from_mon(d)))), + &IsoWeek => (2, date.map(|d| i64::from(d.iso_week().week()))), + &NumDaysFromSun => (1, date.map(|d| i64::from(d.weekday() .num_days_from_sunday()))), - WeekdayFromMon => (1, date.map(|d| i64::from(d.weekday() + &WeekdayFromMon => (1, date.map(|d| i64::from(d.weekday() .number_from_monday()))), - Ordinal => (3, date.map(|d| i64::from(d.ordinal()))), - Hour => (2, time.map(|t| i64::from(t.hour()))), - Hour12 => (2, time.map(|t| i64::from(t.hour12().1))), - Minute => (2, time.map(|t| i64::from(t.minute()))), - Second => (2, time.map(|t| i64::from(t.second() + + &Ordinal => (3, date.map(|d| i64::from(d.ordinal()))), + &Hour => (2, time.map(|t| i64::from(t.hour()))), + &Hour12 => (2, time.map(|t| i64::from(t.hour12().1))), + &Minute => (2, time.map(|t| i64::from(t.minute()))), + &Second => (2, time.map(|t| i64::from(t.second() + t.nanosecond() / 1_000_000_000))), - Nanosecond => (9, time.map(|t| i64::from(t.nanosecond() % 1_000_000_000))), - Timestamp => (1, match (date, time, off) { + &Nanosecond => (9, time.map(|t| i64::from(t.nanosecond() % 1_000_000_000))), + &Timestamp => (1, match (date, time, off) { (Some(d), Some(t), None) => Some(d.and_time(*t).timestamp()), (Some(d), Some(t), Some(&(_, off))) => @@ -428,24 +428,24 @@ pub fn format<'a, I, B>( }), // for the future expansion - Internal(ref int) => match int._dummy {}, + &Internal(ref int) => match int._dummy {}, }; 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), - Pad::Zero => write!(result, "{:+01$}", v, width + 1), - Pad::Space => write!(result, "{:+1$}", v, width + 1), + &Pad::None => write!(result, "{:+}", v), + &Pad::Zero => write!(result, "{:+01$}", v, width + 1), + &Pad::Space => write!(result, "{:+1$}", v, width + 1), } } else { match pad { - Pad::None => write!(result, "{}", v), - Pad::Zero => write!(result, "{:01$}", v, width), - Pad::Space => write!(result, "{:1$}", v, width), + &Pad::None => write!(result, "{}", v), + &Pad::Zero => write!(result, "{:01$}", v, width), + &Pad::Space => write!(result, "{:1$}", v, width), } } ) @@ -454,7 +454,7 @@ pub fn format<'a, I, B>( } }, - Item::Fixed(spec) => { + &Item::Fixed(ref spec) => { use self::Fixed::*; /// Prints an offset from UTC in the format of `+HHMM` or `+HH:MM`. @@ -480,41 +480,41 @@ pub fn format<'a, I, B>( } let ret = match spec { - ShortMonthName => + &ShortMonthName => date.map(|d| { result.push_str(SHORT_MONTHS[d.month0() as usize]); Ok(()) }), - LongMonthName => + &LongMonthName => date.map(|d| { result.push_str(LONG_MONTHS[d.month0() as usize]); Ok(()) }), - ShortWeekdayName => + &ShortWeekdayName => date.map(|d| { result.push_str( SHORT_WEEKDAYS[d.weekday().num_days_from_monday() as usize] ); Ok(()) }), - LongWeekdayName => + &LongWeekdayName => date.map(|d| { result.push_str( LONG_WEEKDAYS[d.weekday().num_days_from_monday() as usize] ); Ok(()) }), - LowerAmPm => + &LowerAmPm => time.map(|t| { result.push_str(if t.hour12().0 {"pm"} else {"am"}); Ok(()) }), - UpperAmPm => + &UpperAmPm => time.map(|t| { result.push_str(if t.hour12().0 {"PM"} else {"AM"}); Ok(()) }), - Nanosecond => + &Nanosecond => time.map(|t| { let nano = t.nanosecond() % 1_000_000_000; if nano == 0 { @@ -527,52 +527,52 @@ pub fn format<'a, I, B>( write!(result, ".{:09}", nano) } }), - Nanosecond3 => + &Nanosecond3 => time.map(|t| { let nano = t.nanosecond() % 1_000_000_000; write!(result, ".{:03}", nano / 1_000_000) }), - Nanosecond6 => + &Nanosecond6 => time.map(|t| { let nano = t.nanosecond() % 1_000_000_000; write!(result, ".{:06}", nano / 1_000) }), - Nanosecond9 => + &Nanosecond9 => time.map(|t| { let nano = t.nanosecond() % 1_000_000_000; write!(result, ".{:09}", nano) }), - Internal(InternalFixed { val: InternalInternal::Nanosecond3NoDot }) => + &Internal(InternalFixed { val: InternalInternal::Nanosecond3NoDot }) => time.map(|t| { let nano = t.nanosecond() % 1_000_000_000; write!(result, "{:03}", nano / 1_000_000) }), - Internal(InternalFixed { val: InternalInternal::Nanosecond6NoDot }) => + &Internal(InternalFixed { val: InternalInternal::Nanosecond6NoDot }) => time.map(|t| { let nano = t.nanosecond() % 1_000_000_000; write!(result, "{:06}", nano / 1_000) }), - Internal(InternalFixed { val: InternalInternal::Nanosecond9NoDot }) => + &Internal(InternalFixed { val: InternalInternal::Nanosecond9NoDot }) => time.map(|t| { let nano = t.nanosecond() % 1_000_000_000; write!(result, "{:09}", nano) }), - TimezoneName => + &TimezoneName => off.map(|&(ref name, _)| { result.push_str(name); Ok(()) }), - TimezoneOffsetColon => + &TimezoneOffsetColon => off.map(|&(_, off)| write_local_minus_utc(&mut result, off, false, true)), - TimezoneOffsetColonZ => + &TimezoneOffsetColonZ => off.map(|&(_, off)| write_local_minus_utc(&mut result, off, true, true)), - TimezoneOffset => + &TimezoneOffset => off.map(|&(_, off)| write_local_minus_utc(&mut result, off, false, false)), - TimezoneOffsetZ => + &TimezoneOffsetZ => off.map(|&(_, off)| write_local_minus_utc(&mut result, off, true, false)), - Internal(InternalFixed { val: InternalInternal::TimezoneOffsetPermissive }) => + &Internal(InternalFixed { val: InternalInternal::TimezoneOffsetPermissive }) => panic!("Do not try to write %#z it is undefined"), - RFC2822 => // same to `%a, %e %b %Y %H:%M:%S %z` + &RFC2822 => // same to `%a, %e %b %Y %H:%M:%S %z` if let (Some(d), Some(t), Some(&(_, off))) = (date, time, off) { let sec = t.second() + t.nanosecond() / 1_000_000_000; try!(write!( @@ -586,7 +586,7 @@ pub fn format<'a, I, B>( } else { None }, - RFC3339 => // same to `%Y-%m-%dT%H:%M:%S%.f%:z` + &RFC3339 => // same to `%Y-%m-%dT%H:%M:%S%.f%:z` if let (Some(d), Some(t), Some(&(_, off))) = (date, time, off) { // reuse `Debug` impls which already print ISO 8601 format. // this is faster in this way. @@ -603,7 +603,7 @@ pub fn format<'a, I, B>( } }, - Item::Error => return Err(fmt::Error), + &Item::Error => return Err(fmt::Error), } } diff --git a/src/format/parse.rs b/src/format/parse.rs index ed887226a8..0a7d6a7d6b 100644 --- a/src/format/parse.rs +++ b/src/format/parse.rs @@ -213,56 +213,56 @@ pub fn parse<'a, I, B>(parsed: &mut Parsed, mut s: &str, items: I) -> ParseResul for item in items { match item.borrow() { - Item::Literal(prefix) => { + &Item::Literal(prefix) => { if s.len() < prefix.len() { return Err(TOO_SHORT); } if !s.starts_with(prefix) { return Err(INVALID); } s = &s[prefix.len()..]; } #[cfg(any(feature = "alloc", feature = "std", test))] - Item::OwnedLiteral(ref prefix) => { + &Item::OwnedLiteral(ref prefix) => { if s.len() < prefix.len() { return Err(TOO_SHORT); } if !s.starts_with(&prefix[..]) { return Err(INVALID); } s = &s[prefix.len()..]; } - Item::Space(_) => { + &Item::Space(_) => { s = s.trim_left(); } #[cfg(any(feature = "alloc", feature = "std", test))] - Item::OwnedSpace(_) => { + &Item::OwnedSpace(_) => { s = s.trim_left(); } - Item::Numeric(spec, _pad) => { + &Item::Numeric(ref spec, ref _pad) => { use super::Numeric::*; type Setter = fn(&mut Parsed, i64) -> ParseResult<()>; let (width, signed, set): (usize, bool, Setter) = match spec { - Year => (4, true, Parsed::set_year), - YearDiv100 => (2, false, Parsed::set_year_div_100), - YearMod100 => (2, false, Parsed::set_year_mod_100), - IsoYear => (4, true, Parsed::set_isoyear), - IsoYearDiv100 => (2, false, Parsed::set_isoyear_div_100), - IsoYearMod100 => (2, false, Parsed::set_isoyear_mod_100), - Month => (2, false, Parsed::set_month), - Day => (2, false, Parsed::set_day), - WeekFromSun => (2, false, Parsed::set_week_from_sun), - WeekFromMon => (2, false, Parsed::set_week_from_mon), - IsoWeek => (2, false, Parsed::set_isoweek), - NumDaysFromSun => (1, false, set_weekday_with_num_days_from_sunday), - WeekdayFromMon => (1, false, set_weekday_with_number_from_monday), - Ordinal => (3, false, Parsed::set_ordinal), - Hour => (2, false, Parsed::set_hour), - Hour12 => (2, false, Parsed::set_hour12), - Minute => (2, false, Parsed::set_minute), - Second => (2, false, Parsed::set_second), - Nanosecond => (9, false, Parsed::set_nanosecond), - Timestamp => (usize::MAX, false, Parsed::set_timestamp), + &Year => (4, true, Parsed::set_year), + &YearDiv100 => (2, false, Parsed::set_year_div_100), + &YearMod100 => (2, false, Parsed::set_year_mod_100), + &IsoYear => (4, true, Parsed::set_isoyear), + &IsoYearDiv100 => (2, false, Parsed::set_isoyear_div_100), + &IsoYearMod100 => (2, false, Parsed::set_isoyear_mod_100), + &Month => (2, false, Parsed::set_month), + &Day => (2, false, Parsed::set_day), + &WeekFromSun => (2, false, Parsed::set_week_from_sun), + &WeekFromMon => (2, false, Parsed::set_week_from_mon), + &IsoWeek => (2, false, Parsed::set_isoweek), + &NumDaysFromSun => (1, false, set_weekday_with_num_days_from_sunday), + &WeekdayFromMon => (1, false, set_weekday_with_number_from_monday), + &Ordinal => (3, false, Parsed::set_ordinal), + &Hour => (2, false, Parsed::set_hour), + &Hour12 => (2, false, Parsed::set_hour12), + &Minute => (2, false, Parsed::set_minute), + &Second => (2, false, Parsed::set_second), + &Nanosecond => (9, false, Parsed::set_nanosecond), + &Timestamp => (usize::MAX, false, Parsed::set_timestamp), // for the future expansion - Internal(ref int) => match int._dummy {}, + &Internal(ref int) => match int._dummy {}, }; s = s.trim_left(); @@ -282,31 +282,31 @@ pub fn parse<'a, I, B>(parsed: &mut Parsed, mut s: &str, items: I) -> ParseResul try!(set(parsed, v)); } - Item::Fixed(spec) => { + &Item::Fixed(ref spec) => { use super::Fixed::*; match spec { - ShortMonthName => { + &ShortMonthName => { let month0 = try_consume!(scan::short_month0(s)); try!(parsed.set_month(i64::from(month0) + 1)); } - LongMonthName => { + &LongMonthName => { let month0 = try_consume!(scan::short_or_long_month0(s)); try!(parsed.set_month(i64::from(month0) + 1)); } - ShortWeekdayName => { + &ShortWeekdayName => { let weekday = try_consume!(scan::short_weekday(s)); try!(parsed.set_weekday(weekday)); } - LongWeekdayName => { + &LongWeekdayName => { let weekday = try_consume!(scan::short_or_long_weekday(s)); try!(parsed.set_weekday(weekday)); } - LowerAmPm | UpperAmPm => { + &LowerAmPm | &UpperAmPm => { if s.len() < 2 { return Err(TOO_SHORT); } let ampm = match (s.as_bytes()[0] | 32, s.as_bytes()[1] | 32) { (b'a',b'm') => false, @@ -317,56 +317,56 @@ pub fn parse<'a, I, B>(parsed: &mut Parsed, mut s: &str, items: I) -> ParseResul s = &s[2..]; } - Nanosecond | Nanosecond3 | Nanosecond6 | Nanosecond9 => { + &Nanosecond | &Nanosecond3 | &Nanosecond6 | &Nanosecond9 => { if s.starts_with('.') { let nano = try_consume!(scan::nanosecond(&s[1..])); try!(parsed.set_nanosecond(nano)); } } - Internal(InternalFixed { val: InternalInternal::Nanosecond3NoDot }) => { + &Internal(InternalFixed { val: InternalInternal::Nanosecond3NoDot }) => { if s.len() < 3 { return Err(TOO_SHORT); } let nano = try_consume!(scan::nanosecond_fixed(s, 3)); try!(parsed.set_nanosecond(nano)); } - Internal(InternalFixed { val: InternalInternal::Nanosecond6NoDot }) => { + &Internal(InternalFixed { val: InternalInternal::Nanosecond6NoDot }) => { if s.len() < 6 { return Err(TOO_SHORT); } let nano = try_consume!(scan::nanosecond_fixed(s, 6)); try!(parsed.set_nanosecond(nano)); } - Internal(InternalFixed { val: InternalInternal::Nanosecond9NoDot }) => { + &Internal(InternalFixed { val: InternalInternal::Nanosecond9NoDot }) => { if s.len() < 9 { return Err(TOO_SHORT); } let nano = try_consume!(scan::nanosecond_fixed(s, 9)); try!(parsed.set_nanosecond(nano)); } - TimezoneName => return Err(BAD_FORMAT), + &TimezoneName => return Err(BAD_FORMAT), - TimezoneOffsetColon | TimezoneOffset => { + &TimezoneOffsetColon | &TimezoneOffset => { let offset = try_consume!(scan::timezone_offset(s.trim_left(), scan::colon_or_space)); try!(parsed.set_offset(i64::from(offset))); } - TimezoneOffsetColonZ | TimezoneOffsetZ => { + &TimezoneOffsetColonZ | &TimezoneOffsetZ => { let offset = try_consume!(scan::timezone_offset_zulu(s.trim_left(), scan::colon_or_space)); try!(parsed.set_offset(i64::from(offset))); } - Internal(InternalFixed { val: InternalInternal::TimezoneOffsetPermissive }) => { + &Internal(InternalFixed { val: InternalInternal::TimezoneOffsetPermissive }) => { let offset = try_consume!(scan::timezone_offset_permissive( s.trim_left(), scan::colon_or_space)); try!(parsed.set_offset(i64::from(offset))); } - RFC2822 => try_consume!(parse_rfc2822(parsed, s)), - RFC3339 => try_consume!(parse_rfc3339(parsed, s)), + &RFC2822 => try_consume!(parse_rfc2822(parsed, s)), + &RFC3339 => try_consume!(parse_rfc3339(parsed, s)), } } - Item::Error => { + &Item::Error => { return Err(BAD_FORMAT); } } diff --git a/src/format/scan.rs b/src/format/scan.rs index acbc92f026..e776fee81c 100644 --- a/src/format/scan.rs +++ b/src/format/scan.rs @@ -43,7 +43,7 @@ pub fn number(s: &str, min: usize, max: usize) -> ParseResult<(&str, i64)> { } let mut n = 0i64; - for (i, c) in bytes.iter().take(max).copied().enumerate() { + for (i, c) in bytes.iter().take(max).cloned().enumerate() { // cloned() = copied() if c < b'0' || b'9' < c { if i < min { return Err(INVALID); @@ -58,7 +58,7 @@ pub fn number(s: &str, min: usize, max: usize) -> ParseResult<(&str, i64)> { }; } - Ok((&s[max.min(bytes.len())..], n)) + Ok((&s[::core::cmp::min(max, bytes.len())..], n)) } /// Tries to consume at least one digits as a fractional second. From 27f5e5e9b39a72723a41b11a23cbda16c8355b1c Mon Sep 17 00:00:00 2001 From: Brandon W Maister Date: Sat, 23 Nov 2019 18:22:40 -0500 Subject: [PATCH 8/9] Temporarily globally allow deprecated The question mark will be fixed in a pending commit --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 928b5158c0..84831db0e9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -386,6 +386,7 @@ #![cfg_attr(feature = "bench", feature(test))] // lib stability features as per RFC #507 #![deny(missing_docs)] #![deny(missing_debug_implementations)] +#![allow(deprecated)] #![cfg_attr(not(any(feature = "std", test)), no_std)] From b717e0442c6a61b0377c0b19f315ba40a7e97716 Mon Sep 17 00:00:00 2001 From: Brandon W Maister Date: Sat, 23 Nov 2019 18:38:38 -0500 Subject: [PATCH 9/9] Handle some semantic merge conflicts Something that wasn't part of this PR: the work to support nested `Option<[ChronoType]>` was merged without being adjusted for the no-std support And now there are some unused import warnings because they need to get configged out. --- src/datetime.rs | 6 +++--- src/naive/date.rs | 1 + src/naive/datetime.rs | 1 + src/naive/time.rs | 1 + 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/datetime.rs b/src/datetime.rs index 7e32da75f4..92cf178d2a 100644 --- a/src/datetime.rs +++ b/src/datetime.rs @@ -1141,7 +1141,7 @@ pub mod serde { /// # fn main() { example().unwrap(); } /// ``` pub mod ts_nanoseconds_option { - use std::fmt; + use core::fmt; use serdelib::{ser, de}; use {DateTime, Utc}; @@ -1432,7 +1432,7 @@ pub mod serde { /// # fn main() { example().unwrap(); } /// ``` pub mod ts_milliseconds_option { - use std::fmt; + use core::fmt; use serdelib::{ser, de}; use {DateTime, Utc}; @@ -1719,7 +1719,7 @@ pub mod serde { /// # fn main() { example().unwrap(); } /// ``` pub mod ts_seconds_option { - use std::fmt; + use core::fmt; use serdelib::{ser, de}; use {DateTime, Utc}; diff --git a/src/naive/date.rs b/src/naive/date.rs index 9ac240f972..f0e63e27f5 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -3,6 +3,7 @@ //! ISO 8601 calendar date without timezone. +#[cfg(any(feature = "alloc", feature = "std", test))] use core::borrow::Borrow; use core::{str, fmt}; use core::ops::{Add, Sub, AddAssign, SubAssign}; diff --git a/src/naive/datetime.rs b/src/naive/datetime.rs index ba9cf4feb0..50ba8b03bd 100644 --- a/src/naive/datetime.rs +++ b/src/naive/datetime.rs @@ -3,6 +3,7 @@ //! ISO 8601 date and time without timezone. +#[cfg(any(feature = "alloc", feature = "std", test))] use core::borrow::Borrow; use core::{str, fmt, hash}; use core::ops::{Add, Sub, AddAssign, SubAssign}; diff --git a/src/naive/time.rs b/src/naive/time.rs index ff02f4d8c6..4ce520cd7a 100644 --- a/src/naive/time.rs +++ b/src/naive/time.rs @@ -3,6 +3,7 @@ //! ISO 8601 time without timezone. +#[cfg(any(feature = "alloc", feature = "std", test))] use core::borrow::Borrow; use core::{str, fmt, hash}; use core::ops::{Add, Sub, AddAssign, SubAssign};