summaryrefslogtreecommitdiff
path: root/vendor/time/src/formatting
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-07-15 16:37:08 -0600
committermo khan <mo@mokhan.ca>2025-07-17 16:30:22 -0600
commit45df4d0d9b577fecee798d672695fe24ff57fb1b (patch)
tree1b99bf645035b58e0d6db08c7a83521f41f7a75b /vendor/time/src/formatting
parentf94f79608393d4ab127db63cc41668445ef6b243 (diff)
feat: migrate from Cedar to SpiceDB authorization system
This is a major architectural change that replaces the Cedar policy-based authorization system with SpiceDB's relation-based authorization. Key changes: - Migrate from Rust to Go implementation - Replace Cedar policies with SpiceDB schema and relationships - Switch from envoy `ext_authz` with Cedar to SpiceDB permission checks - Update build system and dependencies for Go ecosystem - Maintain Envoy integration for external authorization This change enables more flexible permission modeling through SpiceDB's Google Zanzibar inspired relation-based system, supporting complex hierarchical permissions that were difficult to express in Cedar. Breaking change: Existing Cedar policies and Rust-based configuration will no longer work and need to be migrated to SpiceDB schema.
Diffstat (limited to 'vendor/time/src/formatting')
-rw-r--r--vendor/time/src/formatting/formattable.rs312
-rw-r--r--vendor/time/src/formatting/iso8601.rs142
-rw-r--r--vendor/time/src/formatting/mod.rs517
3 files changed, 0 insertions, 971 deletions
diff --git a/vendor/time/src/formatting/formattable.rs b/vendor/time/src/formatting/formattable.rs
deleted file mode 100644
index 7d1ce031..00000000
--- a/vendor/time/src/formatting/formattable.rs
+++ /dev/null
@@ -1,312 +0,0 @@
-//! A trait that can be used to format an item from its components.
-
-use alloc::string::String;
-use alloc::vec::Vec;
-use core::ops::Deref;
-use std::io;
-
-use num_conv::prelude::*;
-
-use crate::format_description::well_known::iso8601::EncodedConfig;
-use crate::format_description::well_known::{Iso8601, Rfc2822, Rfc3339};
-use crate::format_description::{BorrowedFormatItem, OwnedFormatItem};
-use crate::formatting::{
- format_component, format_number_pad_zero, iso8601, write, MONTH_NAMES, WEEKDAY_NAMES,
-};
-use crate::{error, Date, Time, UtcOffset};
-
-/// A type that describes a format.
-///
-/// Implementors of [`Formattable`] are [format descriptions](crate::format_description).
-///
-/// [`Date::format`] and [`Time::format`] each use a format description to generate
-/// a String from their data. See the respective methods for usage examples.
-#[cfg_attr(docsrs, doc(notable_trait))]
-pub trait Formattable: sealed::Sealed {}
-impl Formattable for BorrowedFormatItem<'_> {}
-impl Formattable for [BorrowedFormatItem<'_>] {}
-impl Formattable for OwnedFormatItem {}
-impl Formattable for [OwnedFormatItem] {}
-impl Formattable for Rfc3339 {}
-impl Formattable for Rfc2822 {}
-impl<const CONFIG: EncodedConfig> Formattable for Iso8601<CONFIG> {}
-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.
- 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 + ?Sized),
- 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())
- }
- }
-}
-
-impl sealed::Sealed for BorrowedFormatItem<'_> {
- fn format_into(
- &self,
- output: &mut (impl io::Write + ?Sized),
- 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 sealed::Sealed for [BorrowedFormatItem<'_>] {
- fn format_into(
- &self,
- output: &mut (impl io::Write + ?Sized),
- 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 sealed::Sealed for OwnedFormatItem {
- fn format_into(
- &self,
- output: &mut (impl io::Write + ?Sized),
- date: Option<Date>,
- time: Option<Time>,
- offset: Option<UtcOffset>,
- ) -> Result<usize, error::Format> {
- match self {
- Self::Literal(literal) => Ok(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 {
- [] => Ok(0),
- [item, ..] => item.format_into(output, date, time, offset),
- },
- }
- }
-}
-
-impl sealed::Sealed for [OwnedFormatItem] {
- fn format_into(
- &self,
- output: &mut (impl io::Write + ?Sized),
- 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 + ?Sized),
- date: Option<Date>,
- time: Option<Time>,
- offset: Option<UtcOffset>,
- ) -> Result<usize, error::Format> {
- self.deref().format_into(output, date, time, offset)
- }
-}
-
-impl sealed::Sealed for Rfc2822 {
- fn format_into(
- &self,
- output: &mut (impl io::Write + ?Sized),
- 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().extend::<usize>()][..3],
- )?;
- bytes += write(output, b", ")?;
- bytes += format_number_pad_zero::<2>(output, day)?;
- bytes += write(output, b" ")?;
- bytes += write(
- output,
- &MONTH_NAMES[u8::from(month).extend::<usize>() - 1][..3],
- )?;
- bytes += write(output, b" ")?;
- bytes += format_number_pad_zero::<4>(output, year.cast_unsigned())?;
- 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 + ?Sized),
- 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.whole_hours().unsigned_abs() > 23 {
- return Err(error::Format::InvalidComponent("offset_hour"));
- }
- if offset.seconds_past_minute() != 0 {
- return Err(error::Format::InvalidComponent("offset_second"));
- }
-
- bytes += format_number_pad_zero::<4>(output, year.cast_unsigned())?;
- bytes += write(output, b"-")?;
- bytes += format_number_pad_zero::<2>(output, u8::from(date.month()))?;
- 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())?;
-
- 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)
- }
-}
-
-impl<const CONFIG: EncodedConfig> sealed::Sealed for Iso8601<CONFIG> {
- fn format_into(
- &self,
- output: &mut (impl io::Write + ?Sized),
- date: Option<Date>,
- time: Option<Time>,
- offset: Option<UtcOffset>,
- ) -> Result<usize, error::Format> {
- let mut bytes = 0;
-
- if Self::FORMAT_DATE {
- let date = date.ok_or(error::Format::InsufficientTypeInformation)?;
- bytes += iso8601::format_date::<CONFIG>(output, date)?;
- }
- if Self::FORMAT_TIME {
- let time = time.ok_or(error::Format::InsufficientTypeInformation)?;
- bytes += iso8601::format_time::<CONFIG>(output, time)?;
- }
- if Self::FORMAT_OFFSET {
- let offset = offset.ok_or(error::Format::InsufficientTypeInformation)?;
- bytes += iso8601::format_offset::<CONFIG>(output, offset)?;
- }
-
- if bytes == 0 {
- // The only reason there would be no bytes written is if the format was only for
- // parsing.
- panic!("attempted to format a parsing-only format description");
- }
-
- Ok(bytes)
- }
-}
diff --git a/vendor/time/src/formatting/iso8601.rs b/vendor/time/src/formatting/iso8601.rs
deleted file mode 100644
index a2d2affa..00000000
--- a/vendor/time/src/formatting/iso8601.rs
+++ /dev/null
@@ -1,142 +0,0 @@
-//! Helpers for implementing formatting for ISO 8601.
-
-use std::io;
-
-use num_conv::prelude::*;
-
-use crate::convert::*;
-use crate::format_description::well_known::iso8601::{
- DateKind, EncodedConfig, OffsetPrecision, TimePrecision,
-};
-use crate::format_description::well_known::Iso8601;
-use crate::formatting::{format_float, format_number_pad_zero, write, write_if, write_if_else};
-use crate::{error, Date, Time, UtcOffset};
-
-/// Format the date portion of ISO 8601.
-pub(super) fn format_date<const CONFIG: EncodedConfig>(
- output: &mut (impl io::Write + ?Sized),
- date: Date,
-) -> Result<usize, error::Format> {
- let mut bytes = 0;
-
- match Iso8601::<CONFIG>::DATE_KIND {
- DateKind::Calendar => {
- let (year, month, day) = date.to_calendar_date();
- if Iso8601::<CONFIG>::YEAR_IS_SIX_DIGITS {
- bytes += write_if_else(output, year < 0, b"-", b"+")?;
- bytes += format_number_pad_zero::<6>(output, year.unsigned_abs())?;
- } else if !(0..=9999).contains(&year) {
- return Err(error::Format::InvalidComponent("year"));
- } else {
- bytes += format_number_pad_zero::<4>(output, year.cast_unsigned())?;
- }
- bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b"-")?;
- bytes += format_number_pad_zero::<2>(output, u8::from(month))?;
- bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b"-")?;
- bytes += format_number_pad_zero::<2>(output, day)?;
- }
- DateKind::Week => {
- let (year, week, day) = date.to_iso_week_date();
- if Iso8601::<CONFIG>::YEAR_IS_SIX_DIGITS {
- bytes += write_if_else(output, year < 0, b"-", b"+")?;
- bytes += format_number_pad_zero::<6>(output, year.unsigned_abs())?;
- } else if !(0..=9999).contains(&year) {
- return Err(error::Format::InvalidComponent("year"));
- } else {
- bytes += format_number_pad_zero::<4>(output, year.cast_unsigned())?;
- }
- bytes += write_if_else(output, Iso8601::<CONFIG>::USE_SEPARATORS, b"-W", b"W")?;
- bytes += format_number_pad_zero::<2>(output, week)?;
- bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b"-")?;
- bytes += format_number_pad_zero::<1>(output, day.number_from_monday())?;
- }
- DateKind::Ordinal => {
- let (year, day) = date.to_ordinal_date();
- if Iso8601::<CONFIG>::YEAR_IS_SIX_DIGITS {
- bytes += write_if_else(output, year < 0, b"-", b"+")?;
- bytes += format_number_pad_zero::<6>(output, year.unsigned_abs())?;
- } else if !(0..=9999).contains(&year) {
- return Err(error::Format::InvalidComponent("year"));
- } else {
- bytes += format_number_pad_zero::<4>(output, year.cast_unsigned())?;
- }
- bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b"-")?;
- bytes += format_number_pad_zero::<3>(output, day)?;
- }
- }
-
- Ok(bytes)
-}
-
-/// Format the time portion of ISO 8601.
-pub(super) fn format_time<const CONFIG: EncodedConfig>(
- output: &mut (impl io::Write + ?Sized),
- time: Time,
-) -> Result<usize, error::Format> {
- let mut bytes = 0;
-
- // The "T" can only be omitted in extended format where there is no date being formatted.
- bytes += write_if(
- output,
- Iso8601::<CONFIG>::USE_SEPARATORS || Iso8601::<CONFIG>::FORMAT_DATE,
- b"T",
- )?;
-
- let (hours, minutes, seconds, nanoseconds) = time.as_hms_nano();
-
- match Iso8601::<CONFIG>::TIME_PRECISION {
- TimePrecision::Hour { decimal_digits } => {
- let hours = (hours as f64)
- + (minutes as f64) / Minute::per(Hour) as f64
- + (seconds as f64) / Second::per(Hour) as f64
- + (nanoseconds as f64) / Nanosecond::per(Hour) as f64;
- format_float(output, hours, 2, decimal_digits)?;
- }
- TimePrecision::Minute { decimal_digits } => {
- bytes += format_number_pad_zero::<2>(output, hours)?;
- bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b":")?;
- let minutes = (minutes as f64)
- + (seconds as f64) / Second::per(Minute) as f64
- + (nanoseconds as f64) / Nanosecond::per(Minute) as f64;
- bytes += format_float(output, minutes, 2, decimal_digits)?;
- }
- TimePrecision::Second { decimal_digits } => {
- bytes += format_number_pad_zero::<2>(output, hours)?;
- bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b":")?;
- bytes += format_number_pad_zero::<2>(output, minutes)?;
- bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b":")?;
- let seconds = (seconds as f64) + (nanoseconds as f64) / Nanosecond::per(Second) as f64;
- bytes += format_float(output, seconds, 2, decimal_digits)?;
- }
- }
-
- Ok(bytes)
-}
-
-/// Format the UTC offset portion of ISO 8601.
-pub(super) fn format_offset<const CONFIG: EncodedConfig>(
- output: &mut (impl io::Write + ?Sized),
- offset: UtcOffset,
-) -> Result<usize, error::Format> {
- if Iso8601::<CONFIG>::FORMAT_TIME && offset.is_utc() {
- return Ok(write(output, b"Z")?);
- }
-
- let mut bytes = 0;
-
- let (hours, minutes, seconds) = offset.as_hms();
- if seconds != 0 {
- return Err(error::Format::InvalidComponent("offset_second"));
- }
- bytes += write_if_else(output, offset.is_negative(), b"-", b"+")?;
- bytes += format_number_pad_zero::<2>(output, hours.unsigned_abs())?;
-
- if Iso8601::<CONFIG>::OFFSET_PRECISION == OffsetPrecision::Hour && minutes != 0 {
- return Err(error::Format::InvalidComponent("offset_minute"));
- } else if Iso8601::<CONFIG>::OFFSET_PRECISION == OffsetPrecision::Minute {
- bytes += write_if(output, Iso8601::<CONFIG>::USE_SEPARATORS, b":")?;
- bytes += format_number_pad_zero::<2>(output, minutes.unsigned_abs())?;
- }
-
- Ok(bytes)
-}
diff --git a/vendor/time/src/formatting/mod.rs b/vendor/time/src/formatting/mod.rs
deleted file mode 100644
index c3837107..00000000
--- a/vendor/time/src/formatting/mod.rs
+++ /dev/null
@@ -1,517 +0,0 @@
-//! Formatting for various types.
-
-pub(crate) mod formattable;
-mod iso8601;
-
-use core::num::NonZeroU8;
-use std::io;
-
-use num_conv::prelude::*;
-
-pub use self::formattable::Formattable;
-use crate::convert::*;
-use crate::ext::DigitCount;
-use crate::format_description::{modifier, Component};
-use crate::{error, Date, OffsetDateTime, Time, UtcOffset};
-
-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",
-];
-
-const WEEKDAY_NAMES: [&[u8]; 7] = [
- b"Monday",
- b"Tuesday",
- b"Wednesday",
- b"Thursday",
- b"Friday",
- b"Saturday",
- b"Sunday",
-];
-
-/// Write all bytes to the output, returning the number of bytes written.
-pub(crate) fn write(output: &mut (impl io::Write + ?Sized), bytes: &[u8]) -> io::Result<usize> {
- output.write_all(bytes)?;
- Ok(bytes.len())
-}
-
-/// If `pred` is true, write all bytes to the output, returning the number of bytes written.
-pub(crate) fn write_if(
- output: &mut (impl io::Write + ?Sized),
- pred: bool,
- bytes: &[u8],
-) -> io::Result<usize> {
- if pred {
- write(output, bytes)
- } else {
- Ok(0)
- }
-}
-
-/// If `pred` is true, write `true_bytes` to the output. Otherwise, write `false_bytes`.
-pub(crate) fn write_if_else(
- output: &mut (impl io::Write + ?Sized),
- pred: bool,
- true_bytes: &[u8],
- false_bytes: &[u8],
-) -> io::Result<usize> {
- write(output, if pred { true_bytes } else { false_bytes })
-}
-
-/// Write the floating point number to the output, returning the number of bytes written.
-///
-/// This method accepts the number of digits before and after the decimal. The value will be padded
-/// with zeroes to the left if necessary.
-pub(crate) fn format_float(
- output: &mut (impl io::Write + ?Sized),
- value: f64,
- digits_before_decimal: u8,
- digits_after_decimal: Option<NonZeroU8>,
-) -> io::Result<usize> {
- match digits_after_decimal {
- Some(digits_after_decimal) => {
- // Truncate the decimal points up to the precision
- let trunc_num = 10_f64.powi(digits_after_decimal.get().cast_signed().extend());
- let value = f64::trunc(value * trunc_num) / trunc_num;
-
- let digits_after_decimal = digits_after_decimal.get().extend();
- let width = digits_before_decimal.extend::<usize>() + 1 + digits_after_decimal;
- write!(output, "{value:0>width$.digits_after_decimal$}")?;
- Ok(width)
- }
- None => {
- let value = value.trunc() as u64;
- let width = digits_before_decimal.extend();
- write!(output, "{value:0>width$}")?;
- Ok(width)
- }
- }
-}
-
-/// Format a number with the provided padding and width.
-///
-/// The sign must be written by the caller.
-pub(crate) fn format_number<const WIDTH: u8>(
- output: &mut (impl io::Write + ?Sized),
- value: impl itoa::Integer + DigitCount + Copy,
- 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 => format_number_pad_none(output, value),
- }
-}
-
-/// 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<const WIDTH: u8>(
- output: &mut (impl io::Write + ?Sized),
- value: impl itoa::Integer + DigitCount + Copy,
-) -> 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<const WIDTH: u8>(
- output: &mut (impl io::Write + ?Sized),
- value: impl itoa::Integer + DigitCount + Copy,
-) -> 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 a number with no padding.
-///
-/// If the sign is mandatory, the sign must be written by the caller.
-pub(crate) fn format_number_pad_none(
- output: &mut (impl io::Write + ?Sized),
- value: impl itoa::Integer + Copy,
-) -> Result<usize, io::Error> {
- write(output, itoa::Buffer::new().format(value).as_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 + ?Sized),
- 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)?,
- (Ignore(_), ..) => 0,
- (UnixTimestamp(modifier), Some(date), Some(time), Some(offset)) => {
- fmt_unix_timestamp(output, date, time, offset, modifier)?
- }
- (End(modifier::End {}), ..) => 0,
-
- // This is functionally the same as a wildcard arm, but it will cause an error if a new
- // component is added. This is to avoid a bug where a new component, the code compiles, and
- // formatting fails.
- // Allow unreachable patterns because some branches may be fully matched above.
- #[allow(unreachable_patterns)]
- (
- Day(_) | Month(_) | Ordinal(_) | Weekday(_) | WeekNumber(_) | Year(_) | Hour(_)
- | Minute(_) | Period(_) | Second(_) | Subsecond(_) | OffsetHour(_) | OffsetMinute(_)
- | OffsetSecond(_) | Ignore(_) | UnixTimestamp(_) | End(_),
- ..,
- ) => return Err(error::Format::InsufficientTypeInformation),
- })
-}
-
-/// Format the day into the designated output.
-fn fmt_day(
- output: &mut (impl io::Write + ?Sized),
- 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 + ?Sized),
- 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, u8::from(date.month()), padding)
- }
- modifier::MonthRepr::Long => write(
- output,
- MONTH_NAMES[u8::from(date.month()).extend::<usize>() - 1],
- ),
- modifier::MonthRepr::Short => write(
- output,
- &MONTH_NAMES[u8::from(date.month()).extend::<usize>() - 1][..3],
- ),
- }
-}
-
-/// Format the ordinal into the designated output.
-fn fmt_ordinal(
- output: &mut (impl io::Write + ?Sized),
- 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 + ?Sized),
- 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().extend::<usize>()][..3],
- ),
- modifier::WeekdayRepr::Long => write(
- output,
- WEEKDAY_NAMES[date.weekday().number_days_from_monday().extend::<usize>()],
- ),
- modifier::WeekdayRepr::Sunday => format_number::<1>(
- output,
- date.weekday().number_days_from_sunday() + u8::from(one_indexed),
- modifier::Padding::None,
- ),
- modifier::WeekdayRepr::Monday => format_number::<1>(
- output,
- date.weekday().number_days_from_monday() + u8::from(one_indexed),
- modifier::Padding::None,
- ),
- }
-}
-
-/// Format the week number into the designated output.
-fn fmt_week_number(
- output: &mut (impl io::Write + ?Sized),
- 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 + ?Sized),
- date: Date,
- modifier::Year {
- padding,
- repr,
- range,
- iso_week_based,
- sign_is_mandatory,
- }: modifier::Year,
-) -> Result<usize, error::Format> {
- 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::Century => full_year / 100,
- modifier::YearRepr::LastTwo => (full_year % 100).abs(),
- };
- let format_number = if cfg!(feature = "large-dates") && range == modifier::YearRange::Extended {
- match repr {
- modifier::YearRepr::Full if value.abs() >= 100_000 => format_number::<6>,
- modifier::YearRepr::Full if value.abs() >= 10_000 => format_number::<5>,
- modifier::YearRepr::Full => format_number::<4>,
- modifier::YearRepr::Century if value.abs() >= 1_000 => format_number::<4>,
- modifier::YearRepr::Century if value.abs() >= 100 => format_number::<3>,
- modifier::YearRepr::Century => format_number::<2>,
- modifier::YearRepr::LastTwo => format_number::<2>,
- }
- } else {
- match repr {
- modifier::YearRepr::Full | modifier::YearRepr::Century if full_year.abs() >= 10_000 => {
- return Err(error::ComponentRange {
- name: "year",
- minimum: -9999,
- maximum: 9999,
- value: full_year.extend(),
- conditional_message: Some("when `range:standard` is used"),
- }
- .into());
- }
- _ => {}
- }
- match repr {
- modifier::YearRepr::Full => format_number::<4>,
- modifier::YearRepr::Century => format_number::<2>,
- 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)
-}
-
-/// Format the hour into the designated output.
-fn fmt_hour(
- output: &mut (impl io::Write + ?Sized),
- 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 + ?Sized),
- 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 + ?Sized),
- 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 + ?Sized),
- 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(
- output: &mut (impl io::Write + ?Sized),
- 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)
- }
-}
-
-/// Format the offset hour into the designated output.
-fn fmt_offset_hour(
- output: &mut (impl io::Write + ?Sized),
- 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 + ?Sized),
- 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 + ?Sized),
- offset: UtcOffset,
- modifier::OffsetSecond { padding }: modifier::OffsetSecond,
-) -> Result<usize, io::Error> {
- format_number::<2>(output, offset.seconds_past_minute().unsigned_abs(), padding)
-}
-
-/// Format the Unix timestamp into the designated output.
-fn fmt_unix_timestamp(
- output: &mut (impl io::Write + ?Sized),
- date: Date,
- time: Time,
- offset: UtcOffset,
- modifier::UnixTimestamp {
- precision,
- sign_is_mandatory,
- }: modifier::UnixTimestamp,
-) -> Result<usize, io::Error> {
- let date_time = OffsetDateTime::new_in_offset(date, time, offset).to_offset(UtcOffset::UTC);
-
- if date_time < OffsetDateTime::UNIX_EPOCH {
- write(output, b"-")?;
- } else if sign_is_mandatory {
- write(output, b"+")?;
- }
-
- match precision {
- modifier::UnixTimestampPrecision::Second => {
- format_number_pad_none(output, date_time.unix_timestamp().unsigned_abs())
- }
- modifier::UnixTimestampPrecision::Millisecond => format_number_pad_none(
- output,
- (date_time.unix_timestamp_nanos()
- / Nanosecond::per(Millisecond).cast_signed().extend::<i128>())
- .unsigned_abs(),
- ),
- modifier::UnixTimestampPrecision::Microsecond => format_number_pad_none(
- output,
- (date_time.unix_timestamp_nanos()
- / Nanosecond::per(Microsecond).cast_signed().extend::<i128>())
- .unsigned_abs(),
- ),
- modifier::UnixTimestampPrecision::Nanosecond => {
- format_number_pad_none(output, date_time.unix_timestamp_nanos().unsigned_abs())
- }
- }
-}