mod assert;
mod check;
mod utils;
mod week;
mod write;
use core::fmt;
use core::num::IntErrorKind;
use core::str;
use crate::Error;
use assert::{assert_sorted, assert_sorted_elem_0, assert_to_ascii_uppercase};
use check::CheckedTime;
use utils::{Cursor, SizeLimiter};
use week::{iso_8601_year_and_week_number, week_number, WeekStart};
use write::Write;
pub(crate) use write::FmtWrite;
#[cfg(feature = "std")]
pub(crate) use write::IoWrite;
#[cfg(feature = "std")]
type Int = std::os::raw::c_int;
#[cfg(not(feature = "std"))]
type Int = i32;
const DAYS: [&str; 7] = [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
];
const DAYS_UPPER: [&str; 7] = [
"SUNDAY",
"MONDAY",
"TUESDAY",
"WEDNESDAY",
"THURSDAY",
"FRIDAY",
"SATURDAY",
];
const MONTHS: [&str; 12] = [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
];
const MONTHS_UPPER: [&str; 12] = [
"JANUARY",
"FEBRUARY",
"MARCH",
"APRIL",
"MAY",
"JUNE",
"JULY",
"AUGUST",
"SEPTEMBER",
"OCTOBER",
"NOVEMBER",
"DECEMBER",
];
const _: () = {
assert_to_ascii_uppercase(&DAYS, &DAYS_UPPER);
assert_to_ascii_uppercase(&MONTHS, &MONTHS_UPPER);
};
#[repr(u8)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
enum Flag {
LeftPadding = 1 << 0,
ChangeCase = 1 << 1,
UpperCase = 1 << 2,
}
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
struct Flags(u8);
impl Flags {
#[must_use]
fn contains(self, flag: Flag) -> bool {
let flag = flag as u8;
(self.0 & flag) == flag
}
fn set(&mut self, flag: Flag) {
self.0 |= flag as u8;
}
#[must_use]
fn has_change_or_upper_case(self) -> bool {
let flags = Flag::ChangeCase as u8 | Flag::UpperCase as u8;
self.0 & flags != 0
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
enum Padding {
Left,
Spaces,
Zeros,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
enum Spec {
Year4Digits,
YearDiv100,
YearRem100,
Month,
MonthName,
MonthNameAbbr,
MonthDayZero,
MonthDaySpace,
YearDay,
Hour24hZero,
Hour24hSpace,
Hour12hZero,
Hour12hSpace,
MeridianLower,
MeridianUpper,
Minute,
Second,
MilliSecond,
FractionalSecond,
TimeZoneOffsetHourMinute,
TimeZoneOffsetHourMinuteColon,
TimeZoneOffsetHourMinuteSecondColon,
TimeZoneOffsetColonMinimal,
TimeZoneName,
WeekDayName,
WeekDayNameAbbr,
WeekDayFrom1,
WeekDayFrom0,
YearIso8601,
YearIso8601Rem100,
WeekNumberIso8601,
WeekNumberFromSunday,
WeekNumberFromMonday,
SecondsSinceEpoch,
Newline,
Tabulation,
Percent,
CombinationDateTime,
CombinationDate,
CombinationIso8601,
CombinationVmsDate,
CombinationTime12h,
CombinationHourMinute24h,
CombinationTime24h,
}
#[derive(Debug)]
struct UtcOffset {
hour: f64,
minute: u32,
second: u32,
}
impl UtcOffset {
fn new(hour: f64, minute: u32, second: u32) -> Self {
Self {
hour,
minute,
second,
}
}
}
#[derive(Debug)]
struct Piece {
width: Option<usize>,
padding: Padding,
flags: Flags,
spec: Spec,
}
impl Piece {
fn new(width: Option<usize>, padding: Padding, flags: Flags, spec: Spec) -> Self {
Self {
width,
padding,
flags,
spec,
}
}
fn format_num_zeros(
&self,
f: &mut SizeLimiter<'_>,
value: impl fmt::Display,
default_width: usize,
) -> Result<(), Error> {
if self.flags.contains(Flag::LeftPadding) {
write!(f, "{value}")
} else if self.padding == Padding::Spaces {
let width = self.width.unwrap_or(default_width);
write!(f, "{value: >width$}")
} else {
let width = self.width.unwrap_or(default_width);
write!(f, "{value:0width$}")
}
}
fn format_num_spaces(
&self,
f: &mut SizeLimiter<'_>,
value: impl fmt::Display,
default_width: usize,
) -> Result<(), Error> {
if self.flags.contains(Flag::LeftPadding) {
write!(f, "{value}")
} else if self.padding == Padding::Zeros {
let width = self.width.unwrap_or(default_width);
write!(f, "{value:0width$}")
} else {
let width = self.width.unwrap_or(default_width);
write!(f, "{value: >width$}")
}
}
#[allow(clippy::uninlined_format_args)] fn format_nanoseconds(
&self,
f: &mut SizeLimiter<'_>,
nanoseconds: u32,
default_width: usize,
) -> Result<(), Error> {
let width = self.width.unwrap_or(default_width);
if width <= 9 {
let value = nanoseconds / 10u32.pow(9 - width as u32);
write!(f, "{value:0n$}", n = width)
} else {
write!(f, "{nanoseconds:09}{:0n$}", 0, n = width - 9)
}
}
fn format_string(&self, f: &mut SizeLimiter<'_>, s: &str) -> Result<(), Error> {
match self.width {
None => write!(f, "{s}"),
Some(width) => {
if self.flags.contains(Flag::LeftPadding) {
write!(f, "{s}")
} else if self.padding == Padding::Zeros {
write!(f, "{s:0>width$}")
} else {
write!(f, "{s: >width$}")
}
}
}
}
fn write_padding(&self, f: &mut SizeLimiter<'_>, min_width: usize) -> Result<(), Error> {
if let Some(width) = self.width {
let n = width.saturating_sub(min_width);
match self.padding {
Padding::Zeros => write!(f, "{:0>n$}", "")?,
_ => write!(f, "{: >n$}", "")?,
};
}
Ok(())
}
fn compute_offset_parts(&self, time: &impl CheckedTime) -> UtcOffset {
let utc_offset = time.utc_offset();
let utc_offset_abs = utc_offset.unsigned_abs();
let sign = if utc_offset < 0 || time.is_utc() && self.flags.contains(Flag::LeftPadding) {
-1.0
} else {
1.0
};
let hour = sign * f64::from(utc_offset_abs / 3600);
let minute = (utc_offset_abs / 60) % 60;
let second = utc_offset_abs % 60;
UtcOffset::new(hour, minute, second)
}
fn hour_padding(&self, min_width: usize) -> usize {
const MIN_PADDING: usize = "+hh".len();
match self.width {
Some(width) => width.saturating_sub(min_width) + MIN_PADDING,
None => MIN_PADDING,
}
}
fn write_offset_hh(
&self,
f: &mut SizeLimiter<'_>,
utc_offset: &UtcOffset,
) -> Result<(), Error> {
let hour = utc_offset.hour;
let n = self.hour_padding("+hh".len());
match self.padding {
Padding::Spaces => write!(f, "{hour: >+n$.0}"),
_ => write!(f, "{hour:+0n$.0}"),
}
}
fn write_offset_hhmm(
&self,
f: &mut SizeLimiter<'_>,
utc_offset: &UtcOffset,
) -> Result<(), Error> {
let UtcOffset { hour, minute, .. } = utc_offset;
let n = self.hour_padding("+hhmm".len());
match self.padding {
Padding::Spaces => write!(f, "{hour: >+n$.0}{minute:02}"),
_ => write!(f, "{hour:+0n$.0}{minute:02}"),
}
}
fn write_offset_hh_mm(
&self,
f: &mut SizeLimiter<'_>,
utc_offset: &UtcOffset,
) -> Result<(), Error> {
let UtcOffset { hour, minute, .. } = utc_offset;
let n = self.hour_padding("+hh:mm".len());
match self.padding {
Padding::Spaces => write!(f, "{hour: >+n$.0}:{minute:02}"),
_ => write!(f, "{hour:+0n$.0}:{minute:02}"),
}
}
fn write_offset_hh_mm_ss(
&self,
f: &mut SizeLimiter<'_>,
utc_offset: &UtcOffset,
) -> Result<(), Error> {
let UtcOffset {
hour,
minute,
second,
} = utc_offset;
let n = self.hour_padding("+hh:mm:ss".len());
match self.padding {
Padding::Spaces => write!(f, "{hour: >+n$.0}:{minute:02}:{second:02}"),
_ => write!(f, "{hour:+0n$.0}:{minute:02}:{second:02}"),
}
}
#[allow(clippy::too_many_lines)]
fn fmt(&self, f: &mut SizeLimiter<'_>, time: &impl CheckedTime) -> Result<(), Error> {
match self.spec {
Spec::Year4Digits => {
let year = time.year();
let default_width = if year < 0 { 5 } else { 4 };
self.format_num_zeros(f, year, default_width)
}
Spec::YearDiv100 => self.format_num_zeros(f, time.year().div_euclid(100), 2),
Spec::YearRem100 => self.format_num_zeros(f, time.year().rem_euclid(100), 2),
Spec::Month => self.format_num_zeros(f, time.month()?, 2),
Spec::MonthName => {
let index = (time.month()? - 1) as usize;
if self.flags.has_change_or_upper_case() {
self.format_string(f, MONTHS_UPPER[index])
} else {
self.format_string(f, MONTHS[index])
}
}
Spec::MonthNameAbbr => {
let index = (time.month()? - 1) as usize;
if self.flags.has_change_or_upper_case() {
self.format_string(f, &MONTHS_UPPER[index][..3])
} else {
self.format_string(f, &MONTHS[index][..3])
}
}
Spec::MonthDayZero => self.format_num_zeros(f, time.day()?, 2),
Spec::MonthDaySpace => self.format_num_spaces(f, time.day()?, 2),
Spec::YearDay => self.format_num_zeros(f, time.day_of_year()?, 3),
Spec::Hour24hZero => self.format_num_zeros(f, time.hour()?, 2),
Spec::Hour24hSpace => self.format_num_spaces(f, time.hour()?, 2),
Spec::Hour12hZero => {
let hour = time.hour()? % 12;
let hour = if hour == 0 { 12 } else { hour };
self.format_num_zeros(f, hour, 2)
}
Spec::Hour12hSpace => {
let hour = time.hour()? % 12;
let hour = if hour == 0 { 12 } else { hour };
self.format_num_spaces(f, hour, 2)
}
Spec::MeridianLower => {
let (am, pm) = if self.flags.has_change_or_upper_case() {
("AM", "PM")
} else {
("am", "pm")
};
let meridian = if time.hour()? < 12 { am } else { pm };
self.format_string(f, meridian)
}
Spec::MeridianUpper => {
let (am, pm) = if self.flags.contains(Flag::ChangeCase) {
("am", "pm")
} else {
("AM", "PM")
};
let meridian = if time.hour()? < 12 { am } else { pm };
self.format_string(f, meridian)
}
Spec::Minute => self.format_num_zeros(f, time.minute()?, 2),
Spec::Second => self.format_num_zeros(f, time.second()?, 2),
Spec::MilliSecond => self.format_nanoseconds(f, time.nanoseconds()?, 3),
Spec::FractionalSecond => self.format_nanoseconds(f, time.nanoseconds()?, 9),
Spec::TimeZoneOffsetHourMinute => {
self.write_offset_hhmm(f, &self.compute_offset_parts(time))
}
Spec::TimeZoneOffsetHourMinuteColon => {
self.write_offset_hh_mm(f, &self.compute_offset_parts(time))
}
Spec::TimeZoneOffsetHourMinuteSecondColon => {
self.write_offset_hh_mm_ss(f, &self.compute_offset_parts(time))
}
Spec::TimeZoneOffsetColonMinimal => {
let utc_offset = self.compute_offset_parts(time);
if utc_offset.second != 0 {
self.write_offset_hh_mm_ss(f, &utc_offset)
} else if utc_offset.minute != 0 {
self.write_offset_hh_mm(f, &utc_offset)
} else {
self.write_offset_hh(f, &utc_offset)
}
}
Spec::TimeZoneName => {
let tz_name = time.time_zone()?;
if !tz_name.is_empty() {
if !self.flags.contains(Flag::LeftPadding) {
self.write_padding(f, tz_name.len())?;
}
let convert: fn(&u8) -> u8 = if self.flags.contains(Flag::ChangeCase) {
u8::to_ascii_lowercase
} else if self.flags.contains(Flag::UpperCase) {
u8::to_ascii_uppercase
} else {
|&x| x
};
for x in tz_name.as_bytes() {
f.write_all(&[convert(x)])?;
}
}
Ok(())
}
Spec::WeekDayName => {
let index = time.day_of_week()? as usize;
if self.flags.has_change_or_upper_case() {
self.format_string(f, DAYS_UPPER[index])
} else {
self.format_string(f, DAYS[index])
}
}
Spec::WeekDayNameAbbr => {
let index = time.day_of_week()? as usize;
if self.flags.has_change_or_upper_case() {
self.format_string(f, &DAYS_UPPER[index][..3])
} else {
self.format_string(f, &DAYS[index][..3])
}
}
Spec::WeekDayFrom1 => {
let day_of_week = time.day_of_week()?;
let day_of_week = if day_of_week == 0 { 7 } else { day_of_week };
self.format_num_zeros(f, day_of_week, 1)
}
Spec::WeekDayFrom0 => self.format_num_zeros(f, time.day_of_week()?, 1),
Spec::YearIso8601 => {
let (iso_year, _) = iso_8601_year_and_week_number(
time.year().into(),
time.day_of_week()?.into(),
time.day_of_year()?.into(),
);
let default_width = if iso_year < 0 { 5 } else { 4 };
self.format_num_zeros(f, iso_year, default_width)
}
Spec::YearIso8601Rem100 => {
let (iso_year, _) = iso_8601_year_and_week_number(
time.year().into(),
time.day_of_week()?.into(),
time.day_of_year()?.into(),
);
self.format_num_zeros(f, iso_year.rem_euclid(100), 2)
}
Spec::WeekNumberIso8601 => {
let (_, iso_week_number) = iso_8601_year_and_week_number(
time.year().into(),
time.day_of_week()?.into(),
time.day_of_year()?.into(),
);
self.format_num_zeros(f, iso_week_number, 2)
}
Spec::WeekNumberFromSunday => {
let week_number = week_number(
time.day_of_week()?.into(),
time.day_of_year()?.into(),
WeekStart::Sunday,
);
self.format_num_zeros(f, week_number, 2)
}
Spec::WeekNumberFromMonday => {
let week_number = week_number(
time.day_of_week()?.into(),
time.day_of_year()?.into(),
WeekStart::Monday,
);
self.format_num_zeros(f, week_number, 2)
}
Spec::SecondsSinceEpoch => self.format_num_zeros(f, time.to_int(), 1),
Spec::Newline => self.format_string(f, "\n"),
Spec::Tabulation => self.format_string(f, "\t"),
Spec::Percent => self.format_string(f, "%"),
Spec::CombinationDateTime => {
const MIN_WIDTH_NO_YEAR: usize = "www mmm dd HH:MM:SS ".len();
let year = time.year();
let default_year_width = if year < 0 { 5 } else { 4 };
let min_width = MIN_WIDTH_NO_YEAR + year_width(year).max(default_year_width);
self.write_padding(f, min_width)?;
let (day_names, month_names) = if self.flags.contains(Flag::UpperCase) {
(&DAYS_UPPER, &MONTHS_UPPER)
} else {
(&DAYS, &MONTHS)
};
let week_day_name = &day_names[time.day_of_week()? as usize][..3];
let month_name = &month_names[(time.month()? - 1) as usize][..3];
let day = time.day()?;
let (hour, minute, second) = (time.hour()?, time.minute()?, time.second()?);
write!(f, "{week_day_name} {month_name} ")?;
write!(f, "{day: >2} {hour:02}:{minute:02}:{second:02} ")?;
write!(f, "{year:0default_year_width$}")
}
Spec::CombinationDate => {
self.write_padding(f, "mm/dd/yy".len())?;
let year = time.year().rem_euclid(100);
let month = time.month()?;
let day = time.day()?;
write!(f, "{month:02}/{day:02}/{year:02}")
}
Spec::CombinationIso8601 => {
const MIN_WIDTH_NO_YEAR: usize = "-mm-dd".len();
let year = time.year();
let default_year_width = if year < 0 { 5 } else { 4 };
let min_width = MIN_WIDTH_NO_YEAR + year_width(year).max(default_year_width);
self.write_padding(f, min_width)?;
let month = time.month()?;
let day = time.day()?;
write!(f, "{year:0default_year_width$}-{month:02}-{day:02}")
}
Spec::CombinationVmsDate => {
let year = time.year();
self.write_padding(f, "dd-mmm-".len() + year_width(year).max(4))?;
let month_name = &MONTHS_UPPER[(time.month()? - 1) as usize][..3];
let day = time.day()?;
write!(f, "{day: >2}-{month_name}-{year:04}")
}
Spec::CombinationTime12h => {
self.write_padding(f, "HH:MM:SS PM".len())?;
let hour = time.hour()? % 12;
let hour = if hour == 0 { 12 } else { hour };
let (minute, second) = (time.minute()?, time.second()?);
let meridian = if time.hour()? < 12 { "AM" } else { "PM" };
write!(f, "{hour:02}:{minute:02}:{second:02} {meridian}")
}
Spec::CombinationHourMinute24h => {
self.write_padding(f, "HH:MM".len())?;
let (hour, minute) = (time.hour()?, time.minute()?);
write!(f, "{hour:02}:{minute:02}")
}
Spec::CombinationTime24h => {
self.write_padding(f, "HH:MM:SS".len())?;
let (hour, minute, second) = (time.hour()?, time.minute()?, time.second()?);
write!(f, "{hour:02}:{minute:02}:{second:02}")
}
}
}
}
pub(crate) struct TimeFormatter<'t, 'f, T> {
time: &'t T,
format: &'f [u8],
}
impl<'t, 'f, T: CheckedTime> TimeFormatter<'t, 'f, T> {
pub(crate) fn new<F: AsRef<[u8]> + ?Sized>(time: &'t T, format: &'f F) -> Self {
Self {
time,
format: format.as_ref(),
}
}
pub(crate) fn fmt(&self, buf: &mut dyn Write) -> Result<(), Error> {
if self.format.is_empty() {
return Ok(());
}
let size_limit = self.format.len().saturating_mul(512 * 1024);
let mut f = SizeLimiter::new(buf, size_limit);
let mut cursor = Cursor::new(self.format);
loop {
f.write_all(cursor.read_until(|&x| x == b'%'))?;
let remaining_before = cursor.remaining();
if cursor.next().is_none() {
break;
}
if let Some(piece) = Self::parse_spec(&mut cursor)? {
piece.fmt(&mut f, self.time)?;
} else {
let remaining_after = cursor.remaining();
let text = &remaining_before[..remaining_before.len() - remaining_after.len()];
f.write_all(text)?;
}
}
Ok(())
}
fn parse_spec(cursor: &mut Cursor<'_>) -> Result<Option<Piece>, Error> {
let mut padding = Padding::Left;
let mut flags = Flags::default();
loop {
match cursor.remaining().first() {
Some(&b'-') => {
padding = Padding::Left;
flags.set(Flag::LeftPadding);
}
Some(&b'_') => padding = Padding::Spaces,
Some(&b'0') => padding = Padding::Zeros,
Some(&b'^') => flags.set(Flag::UpperCase),
Some(&b'#') => flags.set(Flag::ChangeCase),
_ => break,
}
cursor.next();
}
let width_digits = str::from_utf8(cursor.read_while(u8::is_ascii_digit))
.expect("reading ASCII digits should yield a valid UTF-8 slice");
let width = match width_digits.parse::<usize>() {
Ok(width) if Int::try_from(width).is_ok() => Some(width),
Err(err) if *err.kind() == IntErrorKind::Empty => None,
_ => return Ok(None),
};
if let Some(&[ext, spec]) = cursor.remaining().get(..2) {
const EXT_E_SPECS: &[u8] = assert_sorted(b"CXYcxy");
const EXT_O_SPECS: &[u8] = assert_sorted(b"HIMSUVWdeklmuwy");
match ext {
b'E' if EXT_E_SPECS.binary_search(&spec).is_ok() => cursor.next(),
b'O' if EXT_O_SPECS.binary_search(&spec).is_ok() => cursor.next(),
_ => None,
};
}
let colons = cursor.read_while(|&x| x == b':');
let spec = if colons.is_empty() {
const POSSIBLE_SPECS: &[(u8, Spec)] = assert_sorted_elem_0(&[
(b'%', Spec::Percent),
(b'A', Spec::WeekDayName),
(b'B', Spec::MonthName),
(b'C', Spec::YearDiv100),
(b'D', Spec::CombinationDate),
(b'F', Spec::CombinationIso8601),
(b'G', Spec::YearIso8601),
(b'H', Spec::Hour24hZero),
(b'I', Spec::Hour12hZero),
(b'L', Spec::MilliSecond),
(b'M', Spec::Minute),
(b'N', Spec::FractionalSecond),
(b'P', Spec::MeridianLower),
(b'R', Spec::CombinationHourMinute24h),
(b'S', Spec::Second),
(b'T', Spec::CombinationTime24h),
(b'U', Spec::WeekNumberFromSunday),
(b'V', Spec::WeekNumberIso8601),
(b'W', Spec::WeekNumberFromMonday),
(b'X', Spec::CombinationTime24h),
(b'Y', Spec::Year4Digits),
(b'Z', Spec::TimeZoneName),
(b'a', Spec::WeekDayNameAbbr),
(b'b', Spec::MonthNameAbbr),
(b'c', Spec::CombinationDateTime),
(b'd', Spec::MonthDayZero),
(b'e', Spec::MonthDaySpace),
(b'g', Spec::YearIso8601Rem100),
(b'h', Spec::MonthNameAbbr),
(b'j', Spec::YearDay),
(b'k', Spec::Hour24hSpace),
(b'l', Spec::Hour12hSpace),
(b'm', Spec::Month),
(b'n', Spec::Newline),
(b'p', Spec::MeridianUpper),
(b'r', Spec::CombinationTime12h),
(b's', Spec::SecondsSinceEpoch),
(b't', Spec::Tabulation),
(b'u', Spec::WeekDayFrom1),
(b'v', Spec::CombinationVmsDate),
(b'w', Spec::WeekDayFrom0),
(b'x', Spec::CombinationDate),
(b'y', Spec::YearRem100),
(b'z', Spec::TimeZoneOffsetHourMinute),
]);
match cursor.next() {
Some(x) => match POSSIBLE_SPECS.binary_search_by_key(&x, |&(c, _)| c) {
Ok(index) => Some(POSSIBLE_SPECS[index].1),
Err(_) => None,
},
None => return Err(Error::InvalidFormatString),
}
} else if cursor.read_optional_tag(b"z") {
match colons.len() {
1 => Some(Spec::TimeZoneOffsetHourMinuteColon),
2 => Some(Spec::TimeZoneOffsetHourMinuteSecondColon),
3 => Some(Spec::TimeZoneOffsetColonMinimal),
_ => None,
}
} else {
None
};
Ok(spec.map(|spec| Piece::new(width, padding, flags, spec)))
}
}
fn year_width(year: i32) -> usize {
const MINUS_SIGN_WIDTH: usize = 1;
let mut n = if year <= 0 { MINUS_SIGN_WIDTH } else { 0 };
let mut val = year;
while val != 0 {
val /= 10;
n += 1;
}
n
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_year_width() {
assert_eq!(year_width(-100), 4);
assert_eq!(year_width(-99), 3);
assert_eq!(year_width(-10), 3);
assert_eq!(year_width(-9), 2);
assert_eq!(year_width(-1), 2);
assert_eq!(year_width(0), 1);
assert_eq!(year_width(1), 1);
assert_eq!(year_width(9), 1);
assert_eq!(year_width(10), 2);
assert_eq!(year_width(99), 2);
assert_eq!(year_width(100), 3);
}
#[cfg(feature = "alloc")]
#[test]
fn test_flag_debug_is_non_empty() {
use alloc::format;
assert!(!format!("{:?}", Flag::LeftPadding).is_empty());
assert!(!format!("{:?}", Flag::ChangeCase).is_empty());
assert!(!format!("{:?}", Flag::UpperCase).is_empty());
}
#[cfg(feature = "alloc")]
#[test]
fn test_flags_debug_is_non_empty() {
use alloc::format;
assert!(!format!("{:?}", Flags::default()).is_empty());
}
#[cfg(feature = "alloc")]
#[test]
fn test_padding_debug_is_non_empty() {
use alloc::format;
assert!(!format!("{:?}", Padding::Left).is_empty());
assert!(!format!("{:?}", Padding::Spaces).is_empty());
assert!(!format!("{:?}", Padding::Zeros).is_empty());
}
#[cfg(feature = "alloc")]
#[test]
fn test_spec_debug_is_non_empty() {
use alloc::format;
assert!(!format!("{:?}", Spec::Year4Digits).is_empty());
assert!(!format!("{:?}", Spec::YearDiv100).is_empty());
assert!(!format!("{:?}", Spec::YearRem100).is_empty());
assert!(!format!("{:?}", Spec::Month).is_empty());
assert!(!format!("{:?}", Spec::MonthName).is_empty());
assert!(!format!("{:?}", Spec::MonthNameAbbr).is_empty());
assert!(!format!("{:?}", Spec::MonthDayZero).is_empty());
assert!(!format!("{:?}", Spec::MonthDaySpace).is_empty());
assert!(!format!("{:?}", Spec::YearDay).is_empty());
assert!(!format!("{:?}", Spec::Hour24hZero).is_empty());
assert!(!format!("{:?}", Spec::Hour24hSpace).is_empty());
assert!(!format!("{:?}", Spec::Hour12hZero).is_empty());
assert!(!format!("{:?}", Spec::Hour12hSpace).is_empty());
assert!(!format!("{:?}", Spec::MeridianLower).is_empty());
assert!(!format!("{:?}", Spec::MeridianUpper).is_empty());
assert!(!format!("{:?}", Spec::Minute).is_empty());
assert!(!format!("{:?}", Spec::Second).is_empty());
assert!(!format!("{:?}", Spec::MilliSecond).is_empty());
assert!(!format!("{:?}", Spec::FractionalSecond).is_empty());
assert!(!format!("{:?}", Spec::TimeZoneOffsetHourMinute).is_empty());
assert!(!format!("{:?}", Spec::TimeZoneOffsetHourMinuteColon).is_empty());
assert!(!format!("{:?}", Spec::TimeZoneOffsetHourMinuteSecondColon).is_empty());
assert!(!format!("{:?}", Spec::TimeZoneOffsetColonMinimal).is_empty());
assert!(!format!("{:?}", Spec::TimeZoneName).is_empty());
assert!(!format!("{:?}", Spec::WeekDayName).is_empty());
assert!(!format!("{:?}", Spec::WeekDayNameAbbr).is_empty());
assert!(!format!("{:?}", Spec::WeekDayFrom1).is_empty());
assert!(!format!("{:?}", Spec::WeekDayFrom0).is_empty());
assert!(!format!("{:?}", Spec::YearIso8601).is_empty());
assert!(!format!("{:?}", Spec::YearIso8601Rem100).is_empty());
assert!(!format!("{:?}", Spec::WeekNumberIso8601).is_empty());
assert!(!format!("{:?}", Spec::WeekNumberFromSunday).is_empty());
assert!(!format!("{:?}", Spec::WeekNumberFromMonday).is_empty());
assert!(!format!("{:?}", Spec::SecondsSinceEpoch).is_empty());
assert!(!format!("{:?}", Spec::Newline).is_empty());
assert!(!format!("{:?}", Spec::Tabulation).is_empty());
assert!(!format!("{:?}", Spec::Percent).is_empty());
assert!(!format!("{:?}", Spec::CombinationDateTime).is_empty());
assert!(!format!("{:?}", Spec::CombinationDate).is_empty());
assert!(!format!("{:?}", Spec::CombinationIso8601).is_empty());
assert!(!format!("{:?}", Spec::CombinationVmsDate).is_empty());
assert!(!format!("{:?}", Spec::CombinationTime12h).is_empty());
assert!(!format!("{:?}", Spec::CombinationHourMinute24h).is_empty());
assert!(!format!("{:?}", Spec::CombinationTime24h).is_empty());
}
#[cfg(feature = "alloc")]
#[test]
fn test_utc_offset_debug_is_non_empty() {
use alloc::format;
assert!(!format!("{:?}", UtcOffset::new(0.0, 0, 0)).is_empty());
}
#[cfg(feature = "alloc")]
#[test]
fn test_piece_debug_is_non_empty() {
use alloc::format;
let piece = Piece::new(
None,
Padding::Spaces,
Flags::default(),
Spec::CombinationTime24h,
);
assert!(!format!("{piece:?}").is_empty());
}
}