Skip to content

Commit

Permalink
Expose format_into and format_into_io for DelayedFormat
Browse files Browse the repository at this point in the history
Request for #1649
- renamed format to format_into and made it public.
- added format_into_io to allow format into a `std::io::Write`.
- added unittests
- added benchmarks for the 3 methods, `Display`, `format_into`, and
  `format_into_io`.
  • Loading branch information
Steven Tang committed Jan 21, 2025
1 parent 5f2f5a8 commit bfdd4d7
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 3 deletions.
28 changes: 28 additions & 0 deletions bench/benches/chrono.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,33 @@ fn bench_format_with_items(c: &mut Criterion) {
});
}

fn benches_delayed_format(c: &mut Criterion) {
let mut group = c.benchmark_group("delayed_format");
let dt = Local::now();
group.bench_function(BenchmarkId::new("with_display", dt), |b| {
b.iter_batched(
|| dt.format("%Y-%m-%dT%H:%M:%S%.f%:z"),
|df| black_box(df).to_string(),
criterion::BatchSize::SmallInput,
)
});
group.bench_function(BenchmarkId::new("with_string_buffer", dt), |b| {
b.iter_batched(
|| (dt.format("%Y-%m-%dT%H:%M:%S%.f%:z"), String::with_capacity(256)),
|(df, string)| black_box(df).format_into(&mut black_box(string)),
criterion::BatchSize::SmallInput,
)
});
group.bench_function(BenchmarkId::new("with_vec_buffer", dt), |b| {
b.iter_batched(
|| (dt.format("%Y-%m-%dT%H:%M:%S%.f%:z"), String::with_capacity(256)),
|(df, string)| black_box(df).format_into(&mut black_box(string)),
criterion::BatchSize::SmallInput,
)
});
group.finish();
}

fn bench_format_manual(c: &mut Criterion) {
let dt = Local::now();
c.bench_function("bench_format_manual", |b| {
Expand Down Expand Up @@ -237,6 +264,7 @@ criterion_group!(
bench_format,
bench_format_with_items,
bench_format_manual,
benches_delayed_format,
bench_naivedate_add_signed,
bench_datetime_with,
);
Expand Down
64 changes: 61 additions & 3 deletions src/format/formatting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,30 @@ impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> {
DelayedFormat { date, time, off: Some(name_and_diff), items, locale }
}

fn format(&self, w: &mut impl Write) -> fmt::Result {
/// Formats `DelayedFormat` into an `std::io::Write` instance.
/// # Errors
/// This function returns an error if formatting into the `std::io::Write` instance fails.
#[cfg(feature = "std")]
pub fn format_into_io(self, w: &mut impl std::io::Write) -> fmt::Result {
// wrapper to allow reuse of the existing string based
// writers
struct IoWriter<W: std::io::Write> {
writer: W,
}
impl<W: std::io::Write> fmt::Write for IoWriter<W> {
#[inline]
fn write_str(&mut self, s: &str) -> fmt::Result {
self.writer.write_all(s.as_bytes()).map_err(|_| fmt::Error)
}
}
let mut writer = IoWriter { writer: w };
self.format_into(&mut writer)
}

/// Formats `DelayedFormat` into a `core::fmt::Write` instance.
/// # Errors
/// This function returns an error if formatting into the `core::fmt::Write` instance fails.
pub fn format_into(&self, w: &mut impl Write) -> fmt::Result {
for item in self.items.clone() {
match *item.borrow() {
Item::Literal(s) | Item::Space(s) => w.write_str(s),
Expand Down Expand Up @@ -321,7 +344,7 @@ impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> {
impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> Display for DelayedFormat<I> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut result = String::new();
self.format(&mut result)?;
self.format_into(&mut result)?;
f.pad(&result)
}
}
Expand Down Expand Up @@ -353,7 +376,7 @@ where

/// Formats single formatting item
#[cfg(feature = "alloc")]
#[deprecated(since = "0.4.32", note = "Use DelayedFormat::fmt instead")]
#[deprecated(since = "0.4.32", note = "Use DelayedFormat::fmt or DelayedFormat::format instead")]
pub fn format_item(
w: &mut fmt::Formatter,
date: Option<&NaiveDate>,
Expand Down Expand Up @@ -611,6 +634,41 @@ mod tests {
#[cfg(feature = "alloc")]
use crate::{NaiveDate, NaiveTime, TimeZone, Timelike, Utc};

#[cfg(all(feature = "std", feature = "alloc"))]
#[test]
fn test_delayed_format_into_io_matches_format_into() {
let dt = crate::DateTime::from_timestamp(1643723400, 123456789).unwrap();
let df = dt.format("%Y-%m-%d %H:%M:%S%.9f");

let mut dt_str = String::new();
let mut dt_vec_str = Vec::new();

df.format_into(&mut dt_str).unwrap();
df.format_into_io(&mut dt_vec_str).unwrap();

assert_eq!(dt_str, String::from_utf8(dt_vec_str).unwrap());
assert_eq!(dt_str, "2022-02-01 13:50:00.123456789");
}

#[cfg(all(feature = "std", feature = "unstable-locales", feature = "alloc"))]
#[test]
fn test_with_locale_delayed_format_into_io_matches_format_into() {
use crate::format::locales::Locale;
use crate::DateTime;

let dt = DateTime::from_timestamp(1643723400, 123456789).unwrap();
let df = dt.format_localized("%A, %B %d, %Y", Locale::ja_JP);

let mut dt_str = String::new();
let mut dt_vec_str = Vec::new();

df.format_into(&mut dt_str).unwrap();
df.format_into_io(&mut dt_vec_str).unwrap();

assert_eq!(dt_str, String::from_utf8(dt_vec_str).unwrap());
assert_eq!(dt_str, "火曜日, 2月 01, 2022");
}

#[test]
#[cfg(feature = "alloc")]
fn test_date_format() {
Expand Down

0 comments on commit bfdd4d7

Please sign in to comment.