diff options
| author | mo khan <mo@mokhan.ca> | 2025-07-15 16:37:08 -0600 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-07-17 16:30:22 -0600 |
| commit | 45df4d0d9b577fecee798d672695fe24ff57fb1b (patch) | |
| tree | 1b99bf645035b58e0d6db08c7a83521f41f7a75b /vendor/time/src/formatting | |
| parent | f94f79608393d4ab127db63cc41668445ef6b243 (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.rs | 312 | ||||
| -rw-r--r-- | vendor/time/src/formatting/iso8601.rs | 142 | ||||
| -rw-r--r-- | vendor/time/src/formatting/mod.rs | 517 |
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()) - } - } -} |
