Skip to content

Commit

Permalink
avoid some dynamic dispatch
Browse files Browse the repository at this point in the history
  • Loading branch information
conradludgate committed Oct 15, 2022
1 parent 49a720c commit 431307c
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 79 deletions.
47 changes: 25 additions & 22 deletions src/datetime/mod.rs
Expand Up @@ -7,10 +7,7 @@
extern crate alloc;

#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::{
format,
string::{String, ToString},
};
use alloc::string::{String, ToString};
#[cfg(any(feature = "alloc", feature = "std", test))]
use core::borrow::Borrow;
use core::cmp::Ordering;
Expand Down Expand Up @@ -613,27 +610,33 @@ where
// reuse `Debug` impls which already print ISO 8601 format.
// this is faster in this way.
let local = self.naive_local();
let mut output = format!("{:?}T{:?}", local.date(), local.time());

let mut off = self.offset.fix().local_minus_utc();
let mut bytes: [u8; 6] = *b"+00:00";
if off < 0 {
off = -off;
bytes[0] = b'-';
}
let mut output = String::with_capacity(30);
local.date().write_into(&mut output).expect("writing dates to strings should never fail");
output.push('T');
local.time().write_into(&mut output).expect("writing times to strings should never fail");

// write the timezone with optimised integer formatting
{
let mut off = self.offset.fix().local_minus_utc();
let mut bytes: [u8; 6] = *b"+00:00";
if off < 0 {
off = -off;
bytes[0] = b'-';
}

// all formats have the hour offset
let hours = off / 3600;
bytes[1] = b'0' + (hours / 10) as u8;
bytes[2] = b'0' + (hours % 10) as u8;
// all formats have the hour offset
let hours = off / 3600;
bytes[1] = b'0' + (hours / 10) as u8;
bytes[2] = b'0' + (hours % 10) as u8;

// colon is already in the bytes
let mins = off / 60 % 60;
bytes[4] = b'0' + (mins / 10) as u8;
bytes[5] = b'0' + (mins % 10) as u8;
// colon is already in the bytes
let mins = off / 60 % 60;
bytes[4] = b'0' + (mins / 10) as u8;
bytes[5] = b'0' + (mins % 10) as u8;

let tz = core::str::from_utf8(&bytes).expect("timezone should be valid utf8");
output.push_str(tz);
let tz = core::str::from_utf8(&bytes).expect("timezone should be valid utf8");
output.push_str(tz);
}

output
}
Expand Down
4 changes: 3 additions & 1 deletion src/format/mod.rs
Expand Up @@ -757,7 +757,9 @@ fn format_inner<'a>(
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.
write!(result, "{:?}T{:?}", d, t)?;
d.write_into(result)?;
result.push('T');
t.write_into(result)?;
Some(write_local_minus_utc(result, off, false, Colons::Single))
} else {
None
Expand Down
56 changes: 31 additions & 25 deletions src/naive/date.rs
Expand Up @@ -1796,30 +1796,8 @@ impl DoubleEndedIterator for NaiveDateWeeksIterator {
// TrustedLen, and Step once they becomes stable.
// See: https://github.com/chronotope/chrono/issues/208

/// The `Debug` output of the naive date `d` is the same as
/// [`d.format("%Y-%m-%d")`](../format/strftime/index.html).
///
/// The string printed can be readily parsed via the `parse` method on `str`.
///
/// # Example
///
/// ```
/// use chrono::NaiveDate;
///
/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(2015, 9, 5).unwrap()), "2015-09-05");
/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt( 0, 1, 1).unwrap()), "0000-01-01");
/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(9999, 12, 31).unwrap()), "9999-12-31");
/// ```
///
/// ISO 8601 requires an explicit sign for years before 1 BCE or after 9999 CE.
///
/// ```
/// # use chrono::NaiveDate;
/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt( -1, 1, 1).unwrap()), "-0001-01-01");
/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(10000, 12, 31).unwrap()), "+10000-12-31");
/// ```
impl fmt::Debug for NaiveDate {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
impl NaiveDate {
pub(crate) fn write_into(&self, f: &mut impl fmt::Write) -> fmt::Result {
let year = self.year();
let mdf = self.mdf();
if (0..=9999).contains(&year) {
Expand Down Expand Up @@ -1853,6 +1831,34 @@ impl fmt::Debug for NaiveDate {
}
}

/// The `Debug` output of the naive date `d` is the same as
/// [`d.format("%Y-%m-%d")`](../format/strftime/index.html).
///
/// The string printed can be readily parsed via the `parse` method on `str`.
///
/// # Example
///
/// ```
/// use chrono::NaiveDate;
///
/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(2015, 9, 5).unwrap()), "2015-09-05");
/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt( 0, 1, 1).unwrap()), "0000-01-01");
/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(9999, 12, 31).unwrap()), "9999-12-31");
/// ```
///
/// ISO 8601 requires an explicit sign for years before 1 BCE or after 9999 CE.
///
/// ```
/// # use chrono::NaiveDate;
/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt( -1, 1, 1).unwrap()), "-0001-01-01");
/// assert_eq!(format!("{:?}", NaiveDate::from_ymd_opt(10000, 12, 31).unwrap()), "+10000-12-31");
/// ```
impl fmt::Debug for NaiveDate {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.write_into(f)
}
}

/// The `Display` output of the naive date `d` is the same as
/// [`d.format("%Y-%m-%d")`](../format/strftime/index.html).
///
Expand All @@ -1877,7 +1883,7 @@ impl fmt::Debug for NaiveDate {
/// ```
impl fmt::Display for NaiveDate {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self, f)
self.write_into(f)
}
}

Expand Down
68 changes: 37 additions & 31 deletions src/naive/time/mod.rs
Expand Up @@ -1140,36 +1140,8 @@ impl Sub<NaiveTime> for NaiveTime {
}
}

/// The `Debug` output of the naive time `t` is the same as
/// [`t.format("%H:%M:%S%.f")`](../format/strftime/index.html).
///
/// The string printed can be readily parsed via the `parse` method on `str`.
///
/// It should be noted that, for leap seconds not on the minute boundary,
/// it may print a representation not distinguishable from non-leap seconds.
/// This doesn't matter in practice, since such leap seconds never happened.
/// (By the time of the first leap second on 1972-06-30,
/// every time zone offset around the world has standardized to the 5-minute alignment.)
///
/// # Example
///
/// ```
/// use chrono::NaiveTime;
///
/// assert_eq!(format!("{:?}", NaiveTime::from_hms_opt(23, 56, 4).unwrap()), "23:56:04");
/// assert_eq!(format!("{:?}", NaiveTime::from_hms_milli_opt(23, 56, 4, 12).unwrap()), "23:56:04.012");
/// assert_eq!(format!("{:?}", NaiveTime::from_hms_micro_opt(23, 56, 4, 1234).unwrap()), "23:56:04.001234");
/// assert_eq!(format!("{:?}", NaiveTime::from_hms_nano_opt(23, 56, 4, 123456).unwrap()), "23:56:04.000123456");
/// ```
///
/// Leap seconds may also be used.
///
/// ```
/// # use chrono::NaiveTime;
/// assert_eq!(format!("{:?}", NaiveTime::from_hms_milli_opt(6, 59, 59, 1_500).unwrap()), "06:59:60.500");
/// ```
impl fmt::Debug for NaiveTime {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
impl NaiveTime {
pub(crate) fn write_into(&self, f: &mut impl fmt::Write) -> fmt::Result {
let (hour, min, sec) = self.hms();
let (sec, nano) = if self.frac >= 1_000_000_000 {
(sec + 1, self.frac - 1_000_000_000)
Expand Down Expand Up @@ -1214,6 +1186,40 @@ impl fmt::Debug for NaiveTime {
}
}

/// The `Debug` output of the naive time `t` is the same as
/// [`t.format("%H:%M:%S%.f")`](../format/strftime/index.html).
///
/// The string printed can be readily parsed via the `parse` method on `str`.
///
/// It should be noted that, for leap seconds not on the minute boundary,
/// it may print a representation not distinguishable from non-leap seconds.
/// This doesn't matter in practice, since such leap seconds never happened.
/// (By the time of the first leap second on 1972-06-30,
/// every time zone offset around the world has standardized to the 5-minute alignment.)
///
/// # Example
///
/// ```
/// use chrono::NaiveTime;
///
/// assert_eq!(format!("{:?}", NaiveTime::from_hms_opt(23, 56, 4).unwrap()), "23:56:04");
/// assert_eq!(format!("{:?}", NaiveTime::from_hms_milli_opt(23, 56, 4, 12).unwrap()), "23:56:04.012");
/// assert_eq!(format!("{:?}", NaiveTime::from_hms_micro_opt(23, 56, 4, 1234).unwrap()), "23:56:04.001234");
/// assert_eq!(format!("{:?}", NaiveTime::from_hms_nano_opt(23, 56, 4, 123456).unwrap()), "23:56:04.000123456");
/// ```
///
/// Leap seconds may also be used.
///
/// ```
/// # use chrono::NaiveTime;
/// assert_eq!(format!("{:?}", NaiveTime::from_hms_milli_opt(6, 59, 59, 1_500).unwrap()), "06:59:60.500");
/// ```
impl fmt::Debug for NaiveTime {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.write_into(f)
}
}

/// The `Display` output of the naive time `t` is the same as
/// [`t.format("%H:%M:%S%.f")`](../format/strftime/index.html).
///
Expand Down Expand Up @@ -1244,7 +1250,7 @@ impl fmt::Debug for NaiveTime {
/// ```
impl fmt::Display for NaiveTime {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self, f)
self.write_into(f)
}
}

Expand Down

0 comments on commit 431307c

Please sign in to comment.