Skip to content

Commit f5e1579

Browse files
author
Steven Tang
committed
Expose format_into and format_into_io for DelayedFormat
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`.
1 parent 5f2f5a8 commit f5e1579

File tree

2 files changed

+89
-4
lines changed

2 files changed

+89
-4
lines changed

bench/benches/chrono.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,33 @@ fn bench_format_with_items(c: &mut Criterion) {
185185
});
186186
}
187187

188+
fn benches_delayed_format(c: &mut Criterion) {
189+
let mut group = c.benchmark_group("delayed_format");
190+
let dt = Local::now();
191+
group.bench_function(BenchmarkId::new("with_display", dt), |b| {
192+
b.iter_batched(
193+
|| dt.format("%Y-%m-%dT%H:%M:%S%.f%:z"),
194+
|df| black_box(df).to_string(),
195+
criterion::BatchSize::SmallInput,
196+
)
197+
});
198+
group.bench_function(BenchmarkId::new("with_string_buffer", dt), |b| {
199+
b.iter_batched(
200+
|| (dt.format("%Y-%m-%dT%H:%M:%S%.f%:z"), String::with_capacity(256)),
201+
|(df, string)| black_box(df).format_into(&mut black_box(string)),
202+
criterion::BatchSize::SmallInput,
203+
)
204+
});
205+
group.bench_function(BenchmarkId::new("with_vec_buffer", dt), |b| {
206+
b.iter_batched(
207+
|| (dt.format("%Y-%m-%dT%H:%M:%S%.f%:z"), String::with_capacity(256)),
208+
|(df, string)| black_box(df).format_into(&mut black_box(string)),
209+
criterion::BatchSize::SmallInput,
210+
)
211+
});
212+
group.finish();
213+
}
214+
188215
fn bench_format_manual(c: &mut Criterion) {
189216
let dt = Local::now();
190217
c.bench_function("bench_format_manual", |b| {
@@ -237,6 +264,7 @@ criterion_group!(
237264
bench_format,
238265
bench_format_with_items,
239266
bench_format_manual,
267+
benches_delayed_format,
240268
bench_naivedate_add_signed,
241269
bench_datetime_with,
242270
);

src/format/formatting.rs

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,30 @@ impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> {
9797
DelayedFormat { date, time, off: Some(name_and_diff), items, locale }
9898
}
9999

100-
fn format(&self, w: &mut impl Write) -> fmt::Result {
100+
/// Formats `DelayedFormat` into an `std::io::Write` instance.
101+
/// # Errors
102+
/// This function returns an error if formatting into the `std::io::Write` instance fails.
103+
#[cfg(feature = "std")]
104+
pub fn format_into_io(self, w: &mut impl std::io::Write) -> fmt::Result {
105+
// wrapper to allow reuse of the existing string based
106+
// writers
107+
struct IoWriter<W: std::io::Write> {
108+
writer: W,
109+
}
110+
impl<W: std::io::Write> fmt::Write for IoWriter<W> {
111+
#[inline]
112+
fn write_str(&mut self, s: &str) -> fmt::Result {
113+
self.writer.write_all(s.as_bytes()).map_err(|_| fmt::Error)
114+
}
115+
}
116+
let mut writer = IoWriter { writer: w };
117+
self.format_into(&mut writer)
118+
}
119+
120+
/// Formats `DelayedFormat` into a `core::fmt::Write` instance.
121+
/// # Errors
122+
/// This function returns an error if formatting into the `core::fmt::Write` instance fails.
123+
pub fn format_into(&self, w: &mut impl Write) -> fmt::Result {
101124
for item in self.items.clone() {
102125
match *item.borrow() {
103126
Item::Literal(s) | Item::Space(s) => w.write_str(s),
@@ -321,7 +344,7 @@ impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> {
321344
impl<'a, I: Iterator<Item = B> + Clone, B: Borrow<Item<'a>>> Display for DelayedFormat<I> {
322345
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
323346
let mut result = String::new();
324-
self.format(&mut result)?;
347+
self.format_into(&mut result)?;
325348
f.pad(&result)
326349
}
327350
}
@@ -353,7 +376,7 @@ where
353376

354377
/// Formats single formatting item
355378
#[cfg(feature = "alloc")]
356-
#[deprecated(since = "0.4.32", note = "Use DelayedFormat::fmt instead")]
379+
#[deprecated(since = "0.4.32", note = "Use DelayedFormat::fmt or DelayedFormat::format instead")]
357380
pub fn format_item(
358381
w: &mut fmt::Formatter,
359382
date: Option<&NaiveDate>,
@@ -609,7 +632,41 @@ mod tests {
609632
use super::{Colons, OffsetFormat, OffsetPrecision, Pad};
610633
use crate::FixedOffset;
611634
#[cfg(feature = "alloc")]
612-
use crate::{NaiveDate, NaiveTime, TimeZone, Timelike, Utc};
635+
use crate::{DateTime, NaiveDate, NaiveTime, TimeZone, Timelike, Utc};
636+
637+
#[cfg(feature = "std")]
638+
#[test]
639+
fn test_delayed_format_into_io_matches_format_into() {
640+
let dt = DateTime::from_timestamp(1643723400, 123456789).unwrap();
641+
let df = dt.format("%Y-%m-%d %H:%M:%S%.9f");
642+
643+
let mut dt_str = String::new();
644+
let mut dt_vec_str = Vec::new();
645+
646+
df.format_into(&mut dt_str).unwrap();
647+
df.format_into_io(&mut dt_vec_str).unwrap();
648+
649+
assert_eq!(dt_str, String::from_utf8(dt_vec_str).unwrap());
650+
assert_eq!(dt_str, "2022-02-01 13:50:00.123456789");
651+
}
652+
653+
#[cfg(all(feature = "std", feature = "unstable-locales", feature = "alloc"))]
654+
#[test]
655+
fn test_with_locale_delayed_format_into_io_matches_format_into() {
656+
use crate::format::locales::Locale;
657+
658+
let dt = DateTime::from_timestamp(1643723400, 123456789).unwrap();
659+
let df = dt.format_localized("%A, %B %d, %Y", Locale::ja_JP);
660+
661+
let mut dt_str = String::new();
662+
let mut dt_vec_str = Vec::new();
663+
664+
df.format_into(&mut dt_str).unwrap();
665+
df.format_into_io(&mut dt_vec_str).unwrap();
666+
667+
assert_eq!(dt_str, String::from_utf8(dt_vec_str).unwrap());
668+
assert_eq!(dt_str, "火曜日, 2月 01, 2022");
669+
}
613670

614671
#[test]
615672
#[cfg(feature = "alloc")]

0 commit comments

Comments
 (0)