RPM build fix (reverted CI changes which will need to be un-reverted or made conditional) and vendor Rust dependencies to make builds much faster in any CI system.
This commit is contained in:
238
zeroidc/vendor/time/src/formatting/formattable.rs
vendored
Normal file
238
zeroidc/vendor/time/src/formatting/formattable.rs
vendored
Normal file
@@ -0,0 +1,238 @@
|
||||
//! A trait that can be used to format an item from its components.
|
||||
|
||||
use core::ops::Deref;
|
||||
use std::io;
|
||||
|
||||
use crate::format_description::well_known::{Rfc2822, Rfc3339};
|
||||
use crate::format_description::FormatItem;
|
||||
use crate::formatting::{
|
||||
format_component, format_number_pad_zero, write, MONTH_NAMES, WEEKDAY_NAMES,
|
||||
};
|
||||
use crate::{error, Date, Time, UtcOffset};
|
||||
|
||||
/// A type that can be formatted.
|
||||
#[cfg_attr(__time_03_docs, doc(notable_trait))]
|
||||
pub trait Formattable: sealed::Sealed {}
|
||||
impl Formattable for FormatItem<'_> {}
|
||||
impl Formattable for [FormatItem<'_>] {}
|
||||
impl Formattable for Rfc3339 {}
|
||||
impl Formattable for Rfc2822 {}
|
||||
impl<T: Deref> Formattable for T where T::Target: Formattable {}
|
||||
|
||||
/// Seal the trait to prevent downstream users from implementing it.
|
||||
mod sealed {
|
||||
#[allow(clippy::wildcard_imports)]
|
||||
use super::*;
|
||||
|
||||
/// Format the item using a format description, the intended output, and the various components.
|
||||
#[cfg_attr(__time_03_docs, doc(cfg(feature = "formatting")))]
|
||||
pub trait Sealed {
|
||||
/// Format the item into the provided output, returning the number of bytes written.
|
||||
fn format_into(
|
||||
&self,
|
||||
output: &mut impl io::Write,
|
||||
date: Option<Date>,
|
||||
time: Option<Time>,
|
||||
offset: Option<UtcOffset>,
|
||||
) -> Result<usize, error::Format>;
|
||||
|
||||
/// Format the item directly to a `String`.
|
||||
fn format(
|
||||
&self,
|
||||
date: Option<Date>,
|
||||
time: Option<Time>,
|
||||
offset: Option<UtcOffset>,
|
||||
) -> Result<String, error::Format> {
|
||||
let mut buf = Vec::new();
|
||||
self.format_into(&mut buf, date, time, offset)?;
|
||||
Ok(String::from_utf8_lossy(&buf).into_owned())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// region: custom formats
|
||||
impl<'a> sealed::Sealed for FormatItem<'a> {
|
||||
fn format_into(
|
||||
&self,
|
||||
output: &mut impl io::Write,
|
||||
date: Option<Date>,
|
||||
time: Option<Time>,
|
||||
offset: Option<UtcOffset>,
|
||||
) -> Result<usize, error::Format> {
|
||||
Ok(match *self {
|
||||
Self::Literal(literal) => write(output, literal)?,
|
||||
Self::Component(component) => format_component(output, component, date, time, offset)?,
|
||||
Self::Compound(items) => items.format_into(output, date, time, offset)?,
|
||||
Self::Optional(item) => item.format_into(output, date, time, offset)?,
|
||||
Self::First(items) => match items {
|
||||
[] => 0,
|
||||
[item, ..] => item.format_into(output, date, time, offset)?,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> sealed::Sealed for [FormatItem<'a>] {
|
||||
fn format_into(
|
||||
&self,
|
||||
output: &mut impl io::Write,
|
||||
date: Option<Date>,
|
||||
time: Option<Time>,
|
||||
offset: Option<UtcOffset>,
|
||||
) -> Result<usize, error::Format> {
|
||||
let mut bytes = 0;
|
||||
for item in self.iter() {
|
||||
bytes += item.format_into(output, date, time, offset)?;
|
||||
}
|
||||
Ok(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Deref> sealed::Sealed for T
|
||||
where
|
||||
T::Target: sealed::Sealed,
|
||||
{
|
||||
fn format_into(
|
||||
&self,
|
||||
output: &mut impl io::Write,
|
||||
date: Option<Date>,
|
||||
time: Option<Time>,
|
||||
offset: Option<UtcOffset>,
|
||||
) -> Result<usize, error::Format> {
|
||||
self.deref().format_into(output, date, time, offset)
|
||||
}
|
||||
}
|
||||
// endregion custom formats
|
||||
|
||||
// region: well-known formats
|
||||
impl sealed::Sealed for Rfc2822 {
|
||||
fn format_into(
|
||||
&self,
|
||||
output: &mut impl io::Write,
|
||||
date: Option<Date>,
|
||||
time: Option<Time>,
|
||||
offset: Option<UtcOffset>,
|
||||
) -> Result<usize, error::Format> {
|
||||
let date = date.ok_or(error::Format::InsufficientTypeInformation)?;
|
||||
let time = time.ok_or(error::Format::InsufficientTypeInformation)?;
|
||||
let offset = offset.ok_or(error::Format::InsufficientTypeInformation)?;
|
||||
|
||||
let mut bytes = 0;
|
||||
|
||||
let (year, month, day) = date.to_calendar_date();
|
||||
|
||||
if year < 1900 {
|
||||
return Err(error::Format::InvalidComponent("year"));
|
||||
}
|
||||
if offset.seconds_past_minute() != 0 {
|
||||
return Err(error::Format::InvalidComponent("offset_second"));
|
||||
}
|
||||
|
||||
bytes += write(
|
||||
output,
|
||||
&WEEKDAY_NAMES[date.weekday().number_days_from_monday() as usize][..3],
|
||||
)?;
|
||||
bytes += write(output, b", ")?;
|
||||
bytes += format_number_pad_zero::<_, _, 2>(output, day)?;
|
||||
bytes += write(output, b" ")?;
|
||||
bytes += write(output, &MONTH_NAMES[month as usize - 1][..3])?;
|
||||
bytes += write(output, b" ")?;
|
||||
bytes += format_number_pad_zero::<_, _, 4>(output, year as u32)?;
|
||||
bytes += write(output, b" ")?;
|
||||
bytes += format_number_pad_zero::<_, _, 2>(output, time.hour())?;
|
||||
bytes += write(output, b":")?;
|
||||
bytes += format_number_pad_zero::<_, _, 2>(output, time.minute())?;
|
||||
bytes += write(output, b":")?;
|
||||
bytes += format_number_pad_zero::<_, _, 2>(output, time.second())?;
|
||||
bytes += write(output, b" ")?;
|
||||
bytes += write(output, if offset.is_negative() { b"-" } else { b"+" })?;
|
||||
bytes += format_number_pad_zero::<_, _, 2>(output, offset.whole_hours().unsigned_abs())?;
|
||||
bytes +=
|
||||
format_number_pad_zero::<_, _, 2>(output, offset.minutes_past_hour().unsigned_abs())?;
|
||||
|
||||
Ok(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl sealed::Sealed for Rfc3339 {
|
||||
fn format_into(
|
||||
&self,
|
||||
output: &mut impl io::Write,
|
||||
date: Option<Date>,
|
||||
time: Option<Time>,
|
||||
offset: Option<UtcOffset>,
|
||||
) -> Result<usize, error::Format> {
|
||||
let date = date.ok_or(error::Format::InsufficientTypeInformation)?;
|
||||
let time = time.ok_or(error::Format::InsufficientTypeInformation)?;
|
||||
let offset = offset.ok_or(error::Format::InsufficientTypeInformation)?;
|
||||
|
||||
let mut bytes = 0;
|
||||
|
||||
let year = date.year();
|
||||
|
||||
if !(0..10_000).contains(&year) {
|
||||
return Err(error::Format::InvalidComponent("year"));
|
||||
}
|
||||
if offset.seconds_past_minute() != 0 {
|
||||
return Err(error::Format::InvalidComponent("offset_second"));
|
||||
}
|
||||
|
||||
bytes += format_number_pad_zero::<_, _, 4>(output, year as u32)?;
|
||||
bytes += write(output, &[b'-'])?;
|
||||
bytes += format_number_pad_zero::<_, _, 2>(output, date.month() as u8)?;
|
||||
bytes += write(output, &[b'-'])?;
|
||||
bytes += format_number_pad_zero::<_, _, 2>(output, date.day())?;
|
||||
bytes += write(output, &[b'T'])?;
|
||||
bytes += format_number_pad_zero::<_, _, 2>(output, time.hour())?;
|
||||
bytes += write(output, &[b':'])?;
|
||||
bytes += format_number_pad_zero::<_, _, 2>(output, time.minute())?;
|
||||
bytes += write(output, &[b':'])?;
|
||||
bytes += format_number_pad_zero::<_, _, 2>(output, time.second())?;
|
||||
|
||||
#[allow(clippy::if_not_else)]
|
||||
if time.nanosecond() != 0 {
|
||||
let nanos = time.nanosecond();
|
||||
bytes += write(output, &[b'.'])?;
|
||||
bytes += if nanos % 10 != 0 {
|
||||
format_number_pad_zero::<_, _, 9>(output, nanos)
|
||||
} else if (nanos / 10) % 10 != 0 {
|
||||
format_number_pad_zero::<_, _, 8>(output, nanos / 10)
|
||||
} else if (nanos / 100) % 10 != 0 {
|
||||
format_number_pad_zero::<_, _, 7>(output, nanos / 100)
|
||||
} else if (nanos / 1_000) % 10 != 0 {
|
||||
format_number_pad_zero::<_, _, 6>(output, nanos / 1_000)
|
||||
} else if (nanos / 10_000) % 10 != 0 {
|
||||
format_number_pad_zero::<_, _, 5>(output, nanos / 10_000)
|
||||
} else if (nanos / 100_000) % 10 != 0 {
|
||||
format_number_pad_zero::<_, _, 4>(output, nanos / 100_000)
|
||||
} else if (nanos / 1_000_000) % 10 != 0 {
|
||||
format_number_pad_zero::<_, _, 3>(output, nanos / 1_000_000)
|
||||
} else if (nanos / 10_000_000) % 10 != 0 {
|
||||
format_number_pad_zero::<_, _, 2>(output, nanos / 10_000_000)
|
||||
} else {
|
||||
format_number_pad_zero::<_, _, 1>(output, nanos / 100_000_000)
|
||||
}?;
|
||||
}
|
||||
|
||||
if offset == UtcOffset::UTC {
|
||||
bytes += write(output, &[b'Z'])?;
|
||||
return Ok(bytes);
|
||||
}
|
||||
|
||||
bytes += write(
|
||||
output,
|
||||
if offset.is_negative() {
|
||||
&[b'-']
|
||||
} else {
|
||||
&[b'+']
|
||||
},
|
||||
)?;
|
||||
bytes += format_number_pad_zero::<_, _, 2>(output, offset.whole_hours().unsigned_abs())?;
|
||||
bytes += write(output, &[b':'])?;
|
||||
bytes +=
|
||||
format_number_pad_zero::<_, _, 2>(output, offset.minutes_past_hour().unsigned_abs())?;
|
||||
|
||||
Ok(bytes)
|
||||
}
|
||||
}
|
||||
// endregion well-known formats
|
||||
457
zeroidc/vendor/time/src/formatting/mod.rs
vendored
Normal file
457
zeroidc/vendor/time/src/formatting/mod.rs
vendored
Normal file
@@ -0,0 +1,457 @@
|
||||
//! Formatting for various types.
|
||||
|
||||
pub(crate) mod formattable;
|
||||
|
||||
use std::io;
|
||||
|
||||
pub use self::formattable::Formattable;
|
||||
use crate::format_description::{modifier, Component};
|
||||
use crate::{error, Date, Time, UtcOffset};
|
||||
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
const MONTH_NAMES: [&[u8]; 12] = [
|
||||
b"January",
|
||||
b"February",
|
||||
b"March",
|
||||
b"April",
|
||||
b"May",
|
||||
b"June",
|
||||
b"July",
|
||||
b"August",
|
||||
b"September",
|
||||
b"October",
|
||||
b"November",
|
||||
b"December",
|
||||
];
|
||||
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
const WEEKDAY_NAMES: [&[u8]; 7] = [
|
||||
b"Monday",
|
||||
b"Tuesday",
|
||||
b"Wednesday",
|
||||
b"Thursday",
|
||||
b"Friday",
|
||||
b"Saturday",
|
||||
b"Sunday",
|
||||
];
|
||||
|
||||
// region: extension trait
|
||||
/// A trait that indicates the formatted width of the value can be determined.
|
||||
///
|
||||
/// Note that this should not be implemented for any signed integers. This forces the caller to
|
||||
/// write the sign if desired.
|
||||
pub(crate) trait DigitCount {
|
||||
/// The number of digits in the stringified value.
|
||||
fn num_digits(self) -> u8;
|
||||
}
|
||||
impl DigitCount for u8 {
|
||||
fn num_digits(self) -> u8 {
|
||||
// Using a lookup table as with u32 is *not* faster in standalone benchmarks.
|
||||
if self < 10 {
|
||||
1
|
||||
} else if self < 100 {
|
||||
2
|
||||
} else {
|
||||
3
|
||||
}
|
||||
}
|
||||
}
|
||||
impl DigitCount for u16 {
|
||||
fn num_digits(self) -> u8 {
|
||||
// Using a lookup table as with u32 is *not* faster in standalone benchmarks.
|
||||
if self < 10 {
|
||||
1
|
||||
} else if self < 100 {
|
||||
2
|
||||
} else if self < 1_000 {
|
||||
3
|
||||
} else if self < 10_000 {
|
||||
4
|
||||
} else {
|
||||
5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DigitCount for u32 {
|
||||
fn num_digits(self) -> u8 {
|
||||
/// Lookup table
|
||||
const TABLE: &[u64] = &[
|
||||
0x0001_0000_0000,
|
||||
0x0001_0000_0000,
|
||||
0x0001_0000_0000,
|
||||
0x0001_FFFF_FFF6,
|
||||
0x0002_0000_0000,
|
||||
0x0002_0000_0000,
|
||||
0x0002_FFFF_FF9C,
|
||||
0x0003_0000_0000,
|
||||
0x0003_0000_0000,
|
||||
0x0003_FFFF_FC18,
|
||||
0x0004_0000_0000,
|
||||
0x0004_0000_0000,
|
||||
0x0004_0000_0000,
|
||||
0x0004_FFFF_D8F0,
|
||||
0x0005_0000_0000,
|
||||
0x0005_0000_0000,
|
||||
0x0005_FFFE_7960,
|
||||
0x0006_0000_0000,
|
||||
0x0006_0000_0000,
|
||||
0x0006_FFF0_BDC0,
|
||||
0x0007_0000_0000,
|
||||
0x0007_0000_0000,
|
||||
0x0007_0000_0000,
|
||||
0x0007_FF67_6980,
|
||||
0x0008_0000_0000,
|
||||
0x0008_0000_0000,
|
||||
0x0008_FA0A_1F00,
|
||||
0x0009_0000_0000,
|
||||
0x0009_0000_0000,
|
||||
0x0009_C465_3600,
|
||||
0x000A_0000_0000,
|
||||
0x000A_0000_0000,
|
||||
];
|
||||
((self as u64 + TABLE[31_u32.saturating_sub(self.leading_zeros()) as usize]) >> 32) as _
|
||||
}
|
||||
}
|
||||
// endregion extension trait
|
||||
|
||||
/// Write all bytes to the output, returning the number of bytes written.
|
||||
fn write(output: &mut impl io::Write, bytes: &[u8]) -> io::Result<usize> {
|
||||
output.write_all(bytes)?;
|
||||
Ok(bytes.len())
|
||||
}
|
||||
|
||||
/// Format a number with the provided padding and width.
|
||||
///
|
||||
/// The sign must be written by the caller.
|
||||
pub(crate) fn format_number<W: io::Write, V: itoa::Integer + DigitCount + Copy, const WIDTH: u8>(
|
||||
output: &mut W,
|
||||
value: V,
|
||||
padding: modifier::Padding,
|
||||
) -> Result<usize, io::Error> {
|
||||
match padding {
|
||||
modifier::Padding::Space => format_number_pad_space::<_, _, WIDTH>(output, value),
|
||||
modifier::Padding::Zero => format_number_pad_zero::<_, _, WIDTH>(output, value),
|
||||
modifier::Padding::None => write(output, itoa::Buffer::new().format(value).as_bytes()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Format a number with the provided width and spaces as padding.
|
||||
///
|
||||
/// The sign must be written by the caller.
|
||||
pub(crate) fn format_number_pad_space<
|
||||
W: io::Write,
|
||||
V: itoa::Integer + DigitCount + Copy,
|
||||
const WIDTH: u8,
|
||||
>(
|
||||
output: &mut W,
|
||||
value: V,
|
||||
) -> Result<usize, io::Error> {
|
||||
let mut bytes = 0;
|
||||
for _ in 0..(WIDTH.saturating_sub(value.num_digits())) {
|
||||
bytes += write(output, &[b' '])?;
|
||||
}
|
||||
bytes += write(output, itoa::Buffer::new().format(value).as_bytes())?;
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
/// Format a number with the provided width and zeros as padding.
|
||||
///
|
||||
/// The sign must be written by the caller.
|
||||
pub(crate) fn format_number_pad_zero<
|
||||
W: io::Write,
|
||||
V: itoa::Integer + DigitCount + Copy,
|
||||
const WIDTH: u8,
|
||||
>(
|
||||
output: &mut W,
|
||||
value: V,
|
||||
) -> Result<usize, io::Error> {
|
||||
let mut bytes = 0;
|
||||
for _ in 0..(WIDTH.saturating_sub(value.num_digits())) {
|
||||
bytes += write(output, &[b'0'])?;
|
||||
}
|
||||
bytes += write(output, itoa::Buffer::new().format(value).as_bytes())?;
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
/// Format the provided component into the designated output. An `Err` will be returned if the
|
||||
/// component requires information that it does not provide or if the value cannot be output to the
|
||||
/// stream.
|
||||
pub(crate) fn format_component(
|
||||
output: &mut impl io::Write,
|
||||
component: Component,
|
||||
date: Option<Date>,
|
||||
time: Option<Time>,
|
||||
offset: Option<UtcOffset>,
|
||||
) -> Result<usize, error::Format> {
|
||||
use Component::*;
|
||||
Ok(match (component, date, time, offset) {
|
||||
(Day(modifier), Some(date), ..) => fmt_day(output, date, modifier)?,
|
||||
(Month(modifier), Some(date), ..) => fmt_month(output, date, modifier)?,
|
||||
(Ordinal(modifier), Some(date), ..) => fmt_ordinal(output, date, modifier)?,
|
||||
(Weekday(modifier), Some(date), ..) => fmt_weekday(output, date, modifier)?,
|
||||
(WeekNumber(modifier), Some(date), ..) => fmt_week_number(output, date, modifier)?,
|
||||
(Year(modifier), Some(date), ..) => fmt_year(output, date, modifier)?,
|
||||
(Hour(modifier), _, Some(time), _) => fmt_hour(output, time, modifier)?,
|
||||
(Minute(modifier), _, Some(time), _) => fmt_minute(output, time, modifier)?,
|
||||
(Period(modifier), _, Some(time), _) => fmt_period(output, time, modifier)?,
|
||||
(Second(modifier), _, Some(time), _) => fmt_second(output, time, modifier)?,
|
||||
(Subsecond(modifier), _, Some(time), _) => fmt_subsecond(output, time, modifier)?,
|
||||
(OffsetHour(modifier), .., Some(offset)) => fmt_offset_hour(output, offset, modifier)?,
|
||||
(OffsetMinute(modifier), .., Some(offset)) => fmt_offset_minute(output, offset, modifier)?,
|
||||
(OffsetSecond(modifier), .., Some(offset)) => fmt_offset_second(output, offset, modifier)?,
|
||||
_ => return Err(error::Format::InsufficientTypeInformation),
|
||||
})
|
||||
}
|
||||
|
||||
// region: date formatters
|
||||
/// Format the day into the designated output.
|
||||
fn fmt_day(
|
||||
output: &mut impl io::Write,
|
||||
date: Date,
|
||||
modifier::Day { padding }: modifier::Day,
|
||||
) -> Result<usize, io::Error> {
|
||||
format_number::<_, _, 2>(output, date.day(), padding)
|
||||
}
|
||||
|
||||
/// Format the month into the designated output.
|
||||
fn fmt_month(
|
||||
output: &mut impl io::Write,
|
||||
date: Date,
|
||||
modifier::Month {
|
||||
padding,
|
||||
repr,
|
||||
case_sensitive: _, // no effect on formatting
|
||||
}: modifier::Month,
|
||||
) -> Result<usize, io::Error> {
|
||||
match repr {
|
||||
modifier::MonthRepr::Numerical => {
|
||||
format_number::<_, _, 2>(output, date.month() as u8, padding)
|
||||
}
|
||||
modifier::MonthRepr::Long => write(output, MONTH_NAMES[date.month() as usize - 1]),
|
||||
modifier::MonthRepr::Short => write(output, &MONTH_NAMES[date.month() as usize - 1][..3]),
|
||||
}
|
||||
}
|
||||
|
||||
/// Format the ordinal into the designated output.
|
||||
fn fmt_ordinal(
|
||||
output: &mut impl io::Write,
|
||||
date: Date,
|
||||
modifier::Ordinal { padding }: modifier::Ordinal,
|
||||
) -> Result<usize, io::Error> {
|
||||
format_number::<_, _, 3>(output, date.ordinal(), padding)
|
||||
}
|
||||
|
||||
/// Format the weekday into the designated output.
|
||||
fn fmt_weekday(
|
||||
output: &mut impl io::Write,
|
||||
date: Date,
|
||||
modifier::Weekday {
|
||||
repr,
|
||||
one_indexed,
|
||||
case_sensitive: _, // no effect on formatting
|
||||
}: modifier::Weekday,
|
||||
) -> Result<usize, io::Error> {
|
||||
match repr {
|
||||
modifier::WeekdayRepr::Short => write(
|
||||
output,
|
||||
&WEEKDAY_NAMES[date.weekday().number_days_from_monday() as usize][..3],
|
||||
),
|
||||
modifier::WeekdayRepr::Long => write(
|
||||
output,
|
||||
WEEKDAY_NAMES[date.weekday().number_days_from_monday() as usize],
|
||||
),
|
||||
modifier::WeekdayRepr::Sunday => format_number::<_, _, 1>(
|
||||
output,
|
||||
date.weekday().number_days_from_sunday() + one_indexed as u8,
|
||||
modifier::Padding::None,
|
||||
),
|
||||
modifier::WeekdayRepr::Monday => format_number::<_, _, 1>(
|
||||
output,
|
||||
date.weekday().number_days_from_monday() + one_indexed as u8,
|
||||
modifier::Padding::None,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Format the week number into the designated output.
|
||||
fn fmt_week_number(
|
||||
output: &mut impl io::Write,
|
||||
date: Date,
|
||||
modifier::WeekNumber { padding, repr }: modifier::WeekNumber,
|
||||
) -> Result<usize, io::Error> {
|
||||
format_number::<_, _, 2>(
|
||||
output,
|
||||
match repr {
|
||||
modifier::WeekNumberRepr::Iso => date.iso_week(),
|
||||
modifier::WeekNumberRepr::Sunday => date.sunday_based_week(),
|
||||
modifier::WeekNumberRepr::Monday => date.monday_based_week(),
|
||||
},
|
||||
padding,
|
||||
)
|
||||
}
|
||||
|
||||
/// Format the year into the designated output.
|
||||
fn fmt_year(
|
||||
output: &mut impl io::Write,
|
||||
date: Date,
|
||||
modifier::Year {
|
||||
padding,
|
||||
repr,
|
||||
iso_week_based,
|
||||
sign_is_mandatory,
|
||||
}: modifier::Year,
|
||||
) -> Result<usize, io::Error> {
|
||||
let full_year = if iso_week_based {
|
||||
date.iso_year_week().0
|
||||
} else {
|
||||
date.year()
|
||||
};
|
||||
let value = match repr {
|
||||
modifier::YearRepr::Full => full_year,
|
||||
modifier::YearRepr::LastTwo => (full_year % 100).abs(),
|
||||
};
|
||||
let format_number = match repr {
|
||||
#[cfg(feature = "large-dates")]
|
||||
modifier::YearRepr::Full if value.abs() >= 100_000 => format_number::<_, _, 6>,
|
||||
#[cfg(feature = "large-dates")]
|
||||
modifier::YearRepr::Full if value.abs() >= 10_000 => format_number::<_, _, 5>,
|
||||
modifier::YearRepr::Full => format_number::<_, _, 4>,
|
||||
modifier::YearRepr::LastTwo => format_number::<_, _, 2>,
|
||||
};
|
||||
let mut bytes = 0;
|
||||
if repr != modifier::YearRepr::LastTwo {
|
||||
if full_year < 0 {
|
||||
bytes += write(output, &[b'-'])?;
|
||||
} else if sign_is_mandatory || cfg!(feature = "large-dates") && full_year >= 10_000 {
|
||||
bytes += write(output, &[b'+'])?;
|
||||
}
|
||||
}
|
||||
bytes += format_number(output, value.unsigned_abs(), padding)?;
|
||||
Ok(bytes)
|
||||
}
|
||||
// endregion date formatters
|
||||
|
||||
// region: time formatters
|
||||
/// Format the hour into the designated output.
|
||||
fn fmt_hour(
|
||||
output: &mut impl io::Write,
|
||||
time: Time,
|
||||
modifier::Hour {
|
||||
padding,
|
||||
is_12_hour_clock,
|
||||
}: modifier::Hour,
|
||||
) -> Result<usize, io::Error> {
|
||||
let value = match (time.hour(), is_12_hour_clock) {
|
||||
(hour, false) => hour,
|
||||
(0 | 12, true) => 12,
|
||||
(hour, true) if hour < 12 => hour,
|
||||
(hour, true) => hour - 12,
|
||||
};
|
||||
format_number::<_, _, 2>(output, value, padding)
|
||||
}
|
||||
|
||||
/// Format the minute into the designated output.
|
||||
fn fmt_minute(
|
||||
output: &mut impl io::Write,
|
||||
time: Time,
|
||||
modifier::Minute { padding }: modifier::Minute,
|
||||
) -> Result<usize, io::Error> {
|
||||
format_number::<_, _, 2>(output, time.minute(), padding)
|
||||
}
|
||||
|
||||
/// Format the period into the designated output.
|
||||
fn fmt_period(
|
||||
output: &mut impl io::Write,
|
||||
time: Time,
|
||||
modifier::Period {
|
||||
is_uppercase,
|
||||
case_sensitive: _, // no effect on formatting
|
||||
}: modifier::Period,
|
||||
) -> Result<usize, io::Error> {
|
||||
match (time.hour() >= 12, is_uppercase) {
|
||||
(false, false) => write(output, b"am"),
|
||||
(false, true) => write(output, b"AM"),
|
||||
(true, false) => write(output, b"pm"),
|
||||
(true, true) => write(output, b"PM"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Format the second into the designated output.
|
||||
fn fmt_second(
|
||||
output: &mut impl io::Write,
|
||||
time: Time,
|
||||
modifier::Second { padding }: modifier::Second,
|
||||
) -> Result<usize, io::Error> {
|
||||
format_number::<_, _, 2>(output, time.second(), padding)
|
||||
}
|
||||
|
||||
/// Format the subsecond into the designated output.
|
||||
fn fmt_subsecond<W: io::Write>(
|
||||
output: &mut W,
|
||||
time: Time,
|
||||
modifier::Subsecond { digits }: modifier::Subsecond,
|
||||
) -> Result<usize, io::Error> {
|
||||
use modifier::SubsecondDigits::*;
|
||||
let nanos = time.nanosecond();
|
||||
|
||||
if digits == Nine || (digits == OneOrMore && nanos % 10 != 0) {
|
||||
format_number_pad_zero::<_, _, 9>(output, nanos)
|
||||
} else if digits == Eight || (digits == OneOrMore && (nanos / 10) % 10 != 0) {
|
||||
format_number_pad_zero::<_, _, 8>(output, nanos / 10)
|
||||
} else if digits == Seven || (digits == OneOrMore && (nanos / 100) % 10 != 0) {
|
||||
format_number_pad_zero::<_, _, 7>(output, nanos / 100)
|
||||
} else if digits == Six || (digits == OneOrMore && (nanos / 1_000) % 10 != 0) {
|
||||
format_number_pad_zero::<_, _, 6>(output, nanos / 1_000)
|
||||
} else if digits == Five || (digits == OneOrMore && (nanos / 10_000) % 10 != 0) {
|
||||
format_number_pad_zero::<_, _, 5>(output, nanos / 10_000)
|
||||
} else if digits == Four || (digits == OneOrMore && (nanos / 100_000) % 10 != 0) {
|
||||
format_number_pad_zero::<_, _, 4>(output, nanos / 100_000)
|
||||
} else if digits == Three || (digits == OneOrMore && (nanos / 1_000_000) % 10 != 0) {
|
||||
format_number_pad_zero::<_, _, 3>(output, nanos / 1_000_000)
|
||||
} else if digits == Two || (digits == OneOrMore && (nanos / 10_000_000) % 10 != 0) {
|
||||
format_number_pad_zero::<_, _, 2>(output, nanos / 10_000_000)
|
||||
} else {
|
||||
format_number_pad_zero::<_, _, 1>(output, nanos / 100_000_000)
|
||||
}
|
||||
}
|
||||
// endregion time formatters
|
||||
|
||||
// region: offset formatters
|
||||
/// Format the offset hour into the designated output.
|
||||
fn fmt_offset_hour(
|
||||
output: &mut impl io::Write,
|
||||
offset: UtcOffset,
|
||||
modifier::OffsetHour {
|
||||
padding,
|
||||
sign_is_mandatory,
|
||||
}: modifier::OffsetHour,
|
||||
) -> Result<usize, io::Error> {
|
||||
let mut bytes = 0;
|
||||
if offset.is_negative() {
|
||||
bytes += write(output, &[b'-'])?;
|
||||
} else if sign_is_mandatory {
|
||||
bytes += write(output, &[b'+'])?;
|
||||
}
|
||||
bytes += format_number::<_, _, 2>(output, offset.whole_hours().unsigned_abs(), padding)?;
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
/// Format the offset minute into the designated output.
|
||||
fn fmt_offset_minute(
|
||||
output: &mut impl io::Write,
|
||||
offset: UtcOffset,
|
||||
modifier::OffsetMinute { padding }: modifier::OffsetMinute,
|
||||
) -> Result<usize, io::Error> {
|
||||
format_number::<_, _, 2>(output, offset.minutes_past_hour().unsigned_abs(), padding)
|
||||
}
|
||||
|
||||
/// Format the offset second into the designated output.
|
||||
fn fmt_offset_second(
|
||||
output: &mut impl io::Write,
|
||||
offset: UtcOffset,
|
||||
modifier::OffsetSecond { padding }: modifier::OffsetSecond,
|
||||
) -> Result<usize, io::Error> {
|
||||
format_number::<_, _, 2>(output, offset.seconds_past_minute().unsigned_abs(), padding)
|
||||
}
|
||||
// endregion offset formatters
|
||||
Reference in New Issue
Block a user