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:
1032
zeroidc/vendor/time/src/date.rs
vendored
Normal file
1032
zeroidc/vendor/time/src/date.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1049
zeroidc/vendor/time/src/duration.rs
vendored
Normal file
1049
zeroidc/vendor/time/src/duration.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
93
zeroidc/vendor/time/src/error/component_range.rs
vendored
Normal file
93
zeroidc/vendor/time/src/error/component_range.rs
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
//! Component range error
|
||||
|
||||
use core::convert::TryFrom;
|
||||
use core::fmt;
|
||||
|
||||
use crate::error;
|
||||
|
||||
/// An error type indicating that a component provided to a method was out of range, causing a
|
||||
/// failure.
|
||||
// i64 is the narrowest type fitting all use cases. This eliminates the need for a type parameter.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct ComponentRange {
|
||||
/// Name of the component.
|
||||
pub(crate) name: &'static str,
|
||||
/// Minimum allowed value, inclusive.
|
||||
pub(crate) minimum: i64,
|
||||
/// Maximum allowed value, inclusive.
|
||||
pub(crate) maximum: i64,
|
||||
/// Value that was provided.
|
||||
pub(crate) value: i64,
|
||||
/// The minimum and/or maximum value is conditional on the value of other
|
||||
/// parameters.
|
||||
pub(crate) conditional_range: bool,
|
||||
}
|
||||
|
||||
impl ComponentRange {
|
||||
/// Obtain the name of the component whose value was out of range.
|
||||
pub const fn name(self) -> &'static str {
|
||||
self.name
|
||||
}
|
||||
|
||||
/// Whether the value's permitted range is conditional, i.e. whether an input with this
|
||||
/// value could have succeeded if the values of other components were different.
|
||||
pub const fn is_conditional(self) -> bool {
|
||||
self.conditional_range
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ComponentRange {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{} must be in the range {}..={}",
|
||||
self.name, self.minimum, self.maximum
|
||||
)?;
|
||||
|
||||
if self.conditional_range {
|
||||
f.write_str(", given values of other parameters")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ComponentRange> for crate::Error {
|
||||
fn from(original: ComponentRange) -> Self {
|
||||
Self::ComponentRange(original)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<crate::Error> for ComponentRange {
|
||||
type Error = error::DifferentVariant;
|
||||
|
||||
fn try_from(err: crate::Error) -> Result<Self, Self::Error> {
|
||||
match err {
|
||||
crate::Error::ComponentRange(err) => Ok(err),
|
||||
_ => Err(error::DifferentVariant),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// **This trait implementation is deprecated and will be removed in a future breaking release.**
|
||||
#[cfg(feature = "serde")]
|
||||
impl serde::de::Expected for ComponentRange {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"a value in the range {}..={}",
|
||||
self.minimum, self.maximum
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl ComponentRange {
|
||||
/// Convert the error to a deserialization error.
|
||||
pub(crate) fn into_de_error<E: serde::de::Error>(self) -> E {
|
||||
E::invalid_value(serde::de::Unexpected::Signed(self.value), &self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for ComponentRange {}
|
||||
37
zeroidc/vendor/time/src/error/conversion_range.rs
vendored
Normal file
37
zeroidc/vendor/time/src/error/conversion_range.rs
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
//! Conversion range error
|
||||
|
||||
use core::convert::TryFrom;
|
||||
use core::fmt;
|
||||
|
||||
use crate::error;
|
||||
|
||||
/// An error type indicating that a conversion failed because the target type could not store the
|
||||
/// initial value.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct ConversionRange;
|
||||
|
||||
impl fmt::Display for ConversionRange {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("Source value is out of range for the target type")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for ConversionRange {}
|
||||
|
||||
impl From<ConversionRange> for crate::Error {
|
||||
fn from(err: ConversionRange) -> Self {
|
||||
Self::ConversionRange(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<crate::Error> for ConversionRange {
|
||||
type Error = error::DifferentVariant;
|
||||
|
||||
fn try_from(err: crate::Error) -> Result<Self, Self::Error> {
|
||||
match err {
|
||||
crate::Error::ConversionRange(err) => Ok(err),
|
||||
_ => Err(error::DifferentVariant),
|
||||
}
|
||||
}
|
||||
}
|
||||
35
zeroidc/vendor/time/src/error/different_variant.rs
vendored
Normal file
35
zeroidc/vendor/time/src/error/different_variant.rs
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
//! Different variant error
|
||||
|
||||
use core::convert::TryFrom;
|
||||
use core::fmt;
|
||||
|
||||
/// An error type indicating that a [`TryFrom`](core::convert::TryFrom) call failed because the
|
||||
/// original value was of a different variant.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct DifferentVariant;
|
||||
|
||||
impl fmt::Display for DifferentVariant {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "value was of a different variant than required")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for DifferentVariant {}
|
||||
|
||||
impl From<DifferentVariant> for crate::Error {
|
||||
fn from(err: DifferentVariant) -> Self {
|
||||
Self::DifferentVariant(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<crate::Error> for DifferentVariant {
|
||||
type Error = Self;
|
||||
|
||||
fn try_from(err: crate::Error) -> Result<Self, Self::Error> {
|
||||
match err {
|
||||
crate::Error::DifferentVariant(err) => Ok(err),
|
||||
_ => Err(Self),
|
||||
}
|
||||
}
|
||||
}
|
||||
97
zeroidc/vendor/time/src/error/format.rs
vendored
Normal file
97
zeroidc/vendor/time/src/error/format.rs
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
//! Error formatting a struct
|
||||
|
||||
use core::convert::TryFrom;
|
||||
use core::fmt;
|
||||
use std::io;
|
||||
|
||||
use crate::error;
|
||||
|
||||
/// An error occurred when formatting.
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_copy_implementations)]
|
||||
#[cfg_attr(__time_03_docs, doc(cfg(feature = "formatting")))]
|
||||
#[derive(Debug)]
|
||||
pub enum Format {
|
||||
/// The type being formatted does not contain sufficient information to format a component.
|
||||
#[non_exhaustive]
|
||||
InsufficientTypeInformation,
|
||||
/// The component named has a value that cannot be formatted into the requested format.
|
||||
///
|
||||
/// This variant is only returned when using well-known formats.
|
||||
InvalidComponent(&'static str),
|
||||
/// A value of `std::io::Error` was returned internally.
|
||||
StdIo(io::Error),
|
||||
}
|
||||
|
||||
impl fmt::Display for Format {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::InsufficientTypeInformation => f.write_str(
|
||||
"The type being formatted does not contain sufficient information to format a \
|
||||
component.",
|
||||
),
|
||||
Self::InvalidComponent(component) => write!(
|
||||
f,
|
||||
"The {} component cannot be formatted into the requested format.",
|
||||
component
|
||||
),
|
||||
Self::StdIo(err) => err.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for Format {
|
||||
fn from(err: io::Error) -> Self {
|
||||
Self::StdIo(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Format> for io::Error {
|
||||
type Error = error::DifferentVariant;
|
||||
|
||||
fn try_from(err: Format) -> Result<Self, Self::Error> {
|
||||
match err {
|
||||
Format::StdIo(err) => Ok(err),
|
||||
_ => Err(error::DifferentVariant),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for Format {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match *self {
|
||||
Self::InsufficientTypeInformation | Self::InvalidComponent(_) => None,
|
||||
Self::StdIo(ref err) => Some(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(__time_03_docs, doc(cfg(feature = "formatting")))]
|
||||
impl From<Format> for crate::Error {
|
||||
fn from(original: Format) -> Self {
|
||||
Self::Format(original)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(__time_03_docs, doc(cfg(feature = "formatting")))]
|
||||
impl TryFrom<crate::Error> for Format {
|
||||
type Error = error::DifferentVariant;
|
||||
|
||||
fn try_from(err: crate::Error) -> Result<Self, Self::Error> {
|
||||
match err {
|
||||
crate::Error::Format(err) => Ok(err),
|
||||
_ => Err(error::DifferentVariant),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl Format {
|
||||
/// Obtain an error type for the serializer.
|
||||
#[doc(hidden)] // Exposed only for the `declare_format_string` macro
|
||||
pub fn into_invalid_serde_value<S: serde::Serializer>(self) -> S::Error {
|
||||
use serde::ser::Error;
|
||||
S::Error::custom(format!("{}", self))
|
||||
}
|
||||
}
|
||||
39
zeroidc/vendor/time/src/error/indeterminate_offset.rs
vendored
Normal file
39
zeroidc/vendor/time/src/error/indeterminate_offset.rs
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
//! Indeterminate offset
|
||||
|
||||
use core::convert::TryFrom;
|
||||
use core::fmt;
|
||||
|
||||
use crate::error;
|
||||
|
||||
/// The system's UTC offset could not be determined at the given datetime.
|
||||
#[cfg_attr(__time_03_docs, doc(cfg(feature = "local-offset")))]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct IndeterminateOffset;
|
||||
|
||||
impl fmt::Display for IndeterminateOffset {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("The system's UTC offset could not be determined")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for IndeterminateOffset {}
|
||||
|
||||
#[cfg_attr(__time_03_docs, doc(cfg(feature = "local-offset")))]
|
||||
impl From<IndeterminateOffset> for crate::Error {
|
||||
fn from(err: IndeterminateOffset) -> Self {
|
||||
Self::IndeterminateOffset(err)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(__time_03_docs, doc(cfg(feature = "std")))]
|
||||
impl TryFrom<crate::Error> for IndeterminateOffset {
|
||||
type Error = error::DifferentVariant;
|
||||
|
||||
fn try_from(err: crate::Error) -> Result<Self, Self::Error> {
|
||||
match err {
|
||||
crate::Error::IndeterminateOffset(err) => Ok(err),
|
||||
_ => Err(error::DifferentVariant),
|
||||
}
|
||||
}
|
||||
}
|
||||
95
zeroidc/vendor/time/src/error/invalid_format_description.rs
vendored
Normal file
95
zeroidc/vendor/time/src/error/invalid_format_description.rs
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
//! Invalid format description
|
||||
|
||||
use alloc::string::String;
|
||||
use core::convert::TryFrom;
|
||||
use core::fmt;
|
||||
|
||||
use crate::error;
|
||||
|
||||
/// The format description provided was not valid.
|
||||
#[cfg_attr(
|
||||
__time_03_docs,
|
||||
doc(cfg(all(any(feature = "formatting", feature = "parsing"), feature = "alloc")))
|
||||
)]
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum InvalidFormatDescription {
|
||||
/// There was a bracket pair that was opened but not closed.
|
||||
#[non_exhaustive]
|
||||
UnclosedOpeningBracket {
|
||||
/// The zero-based index of the opening bracket.
|
||||
index: usize,
|
||||
},
|
||||
/// A component name is not valid.
|
||||
#[non_exhaustive]
|
||||
InvalidComponentName {
|
||||
/// The name of the invalid component name.
|
||||
name: String,
|
||||
/// The zero-based index the component name starts at.
|
||||
index: usize,
|
||||
},
|
||||
/// A modifier is not valid.
|
||||
#[non_exhaustive]
|
||||
InvalidModifier {
|
||||
/// The value of the invalid modifier.
|
||||
value: String,
|
||||
/// The zero-based index the modifier starts at.
|
||||
index: usize,
|
||||
},
|
||||
/// A component name is missing.
|
||||
#[non_exhaustive]
|
||||
MissingComponentName {
|
||||
/// The zero-based index where the component name should start.
|
||||
index: usize,
|
||||
},
|
||||
}
|
||||
|
||||
#[cfg_attr(
|
||||
__time_03_docs,
|
||||
doc(cfg(all(any(feature = "formatting", feature = "parsing"), feature = "alloc")))
|
||||
)]
|
||||
impl From<InvalidFormatDescription> for crate::Error {
|
||||
fn from(original: InvalidFormatDescription) -> Self {
|
||||
Self::InvalidFormatDescription(original)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(
|
||||
__time_03_docs,
|
||||
doc(cfg(all(any(feature = "formatting", feature = "parsing"), feature = "alloc")))
|
||||
)]
|
||||
impl TryFrom<crate::Error> for InvalidFormatDescription {
|
||||
type Error = error::DifferentVariant;
|
||||
|
||||
fn try_from(err: crate::Error) -> Result<Self, Self::Error> {
|
||||
match err {
|
||||
crate::Error::InvalidFormatDescription(err) => Ok(err),
|
||||
_ => Err(error::DifferentVariant),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for InvalidFormatDescription {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use InvalidFormatDescription::*;
|
||||
match self {
|
||||
UnclosedOpeningBracket { index } => {
|
||||
write!(f, "unclosed opening bracket at byte index {}", index)
|
||||
}
|
||||
InvalidComponentName { name, index } => write!(
|
||||
f,
|
||||
"invalid component name `{}` at byte index {}",
|
||||
name, index
|
||||
),
|
||||
InvalidModifier { value, index } => {
|
||||
write!(f, "invalid modifier `{}` at byte index {}", value, index)
|
||||
}
|
||||
MissingComponentName { index } => {
|
||||
write!(f, "missing component name at byte index {}", index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for InvalidFormatDescription {}
|
||||
35
zeroidc/vendor/time/src/error/invalid_variant.rs
vendored
Normal file
35
zeroidc/vendor/time/src/error/invalid_variant.rs
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
//! Invalid variant error
|
||||
|
||||
use core::convert::TryFrom;
|
||||
use core::fmt;
|
||||
|
||||
/// An error type indicating that a [`FromStr`](core::str::FromStr) call failed because the value
|
||||
/// was not a valid variant.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct InvalidVariant;
|
||||
|
||||
impl fmt::Display for InvalidVariant {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "value was not a valid variant")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for InvalidVariant {}
|
||||
|
||||
impl From<InvalidVariant> for crate::Error {
|
||||
fn from(err: InvalidVariant) -> Self {
|
||||
Self::InvalidVariant(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<crate::Error> for InvalidVariant {
|
||||
type Error = crate::error::DifferentVariant;
|
||||
|
||||
fn try_from(err: crate::Error) -> Result<Self, Self::Error> {
|
||||
match err {
|
||||
crate::Error::InvalidVariant(err) => Ok(err),
|
||||
_ => Err(crate::error::DifferentVariant),
|
||||
}
|
||||
}
|
||||
}
|
||||
112
zeroidc/vendor/time/src/error/mod.rs
vendored
Normal file
112
zeroidc/vendor/time/src/error/mod.rs
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
//! Various error types returned by methods in the time crate.
|
||||
|
||||
mod component_range;
|
||||
mod conversion_range;
|
||||
mod different_variant;
|
||||
#[cfg(feature = "formatting")]
|
||||
mod format;
|
||||
#[cfg(feature = "local-offset")]
|
||||
mod indeterminate_offset;
|
||||
#[cfg(all(any(feature = "formatting", feature = "parsing"), feature = "alloc"))]
|
||||
mod invalid_format_description;
|
||||
mod invalid_variant;
|
||||
#[cfg(feature = "parsing")]
|
||||
mod parse;
|
||||
#[cfg(feature = "parsing")]
|
||||
mod parse_from_description;
|
||||
#[cfg(feature = "parsing")]
|
||||
mod try_from_parsed;
|
||||
|
||||
use core::fmt;
|
||||
|
||||
pub use component_range::ComponentRange;
|
||||
pub use conversion_range::ConversionRange;
|
||||
pub use different_variant::DifferentVariant;
|
||||
#[cfg(feature = "formatting")]
|
||||
pub use format::Format;
|
||||
#[cfg(feature = "local-offset")]
|
||||
pub use indeterminate_offset::IndeterminateOffset;
|
||||
#[cfg(all(any(feature = "formatting", feature = "parsing"), feature = "alloc"))]
|
||||
pub use invalid_format_description::InvalidFormatDescription;
|
||||
pub use invalid_variant::InvalidVariant;
|
||||
#[cfg(feature = "parsing")]
|
||||
pub use parse::Parse;
|
||||
#[cfg(feature = "parsing")]
|
||||
pub use parse_from_description::ParseFromDescription;
|
||||
#[cfg(feature = "parsing")]
|
||||
pub use try_from_parsed::TryFromParsed;
|
||||
|
||||
/// A unified error type for anything returned by a method in the time crate.
|
||||
///
|
||||
/// This can be used when you either don't know or don't care about the exact error returned.
|
||||
/// `Result<_, time::Error>` (or its alias `time::Result<_>`) will work in these situations.
|
||||
#[allow(missing_copy_implementations, variant_size_differences)]
|
||||
#[allow(clippy::missing_docs_in_private_items)] // variants only
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
ConversionRange(ConversionRange),
|
||||
ComponentRange(ComponentRange),
|
||||
#[cfg(feature = "local-offset")]
|
||||
IndeterminateOffset(IndeterminateOffset),
|
||||
#[cfg(feature = "formatting")]
|
||||
Format(Format),
|
||||
#[cfg(feature = "parsing")]
|
||||
ParseFromDescription(ParseFromDescription),
|
||||
#[cfg(feature = "parsing")]
|
||||
#[non_exhaustive]
|
||||
UnexpectedTrailingCharacters,
|
||||
#[cfg(feature = "parsing")]
|
||||
TryFromParsed(TryFromParsed),
|
||||
#[cfg(all(any(feature = "formatting", feature = "parsing"), feature = "alloc"))]
|
||||
InvalidFormatDescription(InvalidFormatDescription),
|
||||
DifferentVariant(DifferentVariant),
|
||||
InvalidVariant(InvalidVariant),
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::ConversionRange(e) => e.fmt(f),
|
||||
Self::ComponentRange(e) => e.fmt(f),
|
||||
#[cfg(feature = "local-offset")]
|
||||
Self::IndeterminateOffset(e) => e.fmt(f),
|
||||
#[cfg(feature = "formatting")]
|
||||
Self::Format(e) => e.fmt(f),
|
||||
#[cfg(feature = "parsing")]
|
||||
Self::ParseFromDescription(e) => e.fmt(f),
|
||||
#[cfg(feature = "parsing")]
|
||||
Self::UnexpectedTrailingCharacters => f.write_str("unexpected trailing characters"),
|
||||
#[cfg(feature = "parsing")]
|
||||
Self::TryFromParsed(e) => e.fmt(f),
|
||||
#[cfg(all(any(feature = "formatting", feature = "parsing"), feature = "alloc"))]
|
||||
Self::InvalidFormatDescription(e) => e.fmt(f),
|
||||
Self::DifferentVariant(e) => e.fmt(f),
|
||||
Self::InvalidVariant(e) => e.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for Error {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::ConversionRange(err) => Some(err),
|
||||
Self::ComponentRange(err) => Some(err),
|
||||
#[cfg(feature = "local-offset")]
|
||||
Self::IndeterminateOffset(err) => Some(err),
|
||||
#[cfg(feature = "formatting")]
|
||||
Self::Format(err) => Some(err),
|
||||
#[cfg(feature = "parsing")]
|
||||
Self::ParseFromDescription(err) => Some(err),
|
||||
#[cfg(feature = "parsing")]
|
||||
Self::UnexpectedTrailingCharacters => None,
|
||||
#[cfg(feature = "parsing")]
|
||||
Self::TryFromParsed(err) => Some(err),
|
||||
#[cfg(all(any(feature = "formatting", feature = "parsing"), feature = "alloc"))]
|
||||
Self::InvalidFormatDescription(err) => Some(err),
|
||||
Self::DifferentVariant(err) => Some(err),
|
||||
Self::InvalidVariant(err) => Some(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
105
zeroidc/vendor/time/src/error/parse.rs
vendored
Normal file
105
zeroidc/vendor/time/src/error/parse.rs
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
//! Error that occurred at some stage of parsing
|
||||
|
||||
use core::convert::TryFrom;
|
||||
use core::fmt;
|
||||
|
||||
use crate::error::{self, ParseFromDescription, TryFromParsed};
|
||||
|
||||
/// An error that occurred at some stage of parsing.
|
||||
#[cfg_attr(__time_03_docs, doc(cfg(feature = "parsing")))]
|
||||
#[allow(variant_size_differences)]
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Parse {
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
TryFromParsed(TryFromParsed),
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
ParseFromDescription(ParseFromDescription),
|
||||
/// The input should have ended, but there were characters remaining.
|
||||
#[non_exhaustive]
|
||||
UnexpectedTrailingCharacters,
|
||||
}
|
||||
|
||||
impl fmt::Display for Parse {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::TryFromParsed(err) => err.fmt(f),
|
||||
Self::ParseFromDescription(err) => err.fmt(f),
|
||||
Self::UnexpectedTrailingCharacters => f.write_str("unexpected trailing characters"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for Parse {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::TryFromParsed(err) => Some(err),
|
||||
Self::ParseFromDescription(err) => Some(err),
|
||||
Self::UnexpectedTrailingCharacters => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(__time_03_docs, doc(cfg(feature = "parsing")))]
|
||||
impl From<TryFromParsed> for Parse {
|
||||
fn from(err: TryFromParsed) -> Self {
|
||||
Self::TryFromParsed(err)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(__time_03_docs, doc(cfg(feature = "parsing")))]
|
||||
impl TryFrom<Parse> for TryFromParsed {
|
||||
type Error = error::DifferentVariant;
|
||||
|
||||
fn try_from(err: Parse) -> Result<Self, Self::Error> {
|
||||
match err {
|
||||
Parse::TryFromParsed(err) => Ok(err),
|
||||
_ => Err(error::DifferentVariant),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(__time_03_docs, doc(cfg(feature = "parsing")))]
|
||||
impl From<ParseFromDescription> for Parse {
|
||||
fn from(err: ParseFromDescription) -> Self {
|
||||
Self::ParseFromDescription(err)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(__time_03_docs, doc(cfg(feature = "parsing")))]
|
||||
impl TryFrom<Parse> for ParseFromDescription {
|
||||
type Error = error::DifferentVariant;
|
||||
|
||||
fn try_from(err: Parse) -> Result<Self, Self::Error> {
|
||||
match err {
|
||||
Parse::ParseFromDescription(err) => Ok(err),
|
||||
_ => Err(error::DifferentVariant),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(__time_03_docs, doc(cfg(feature = "parsing")))]
|
||||
impl From<Parse> for crate::Error {
|
||||
fn from(err: Parse) -> Self {
|
||||
match err {
|
||||
Parse::TryFromParsed(err) => Self::TryFromParsed(err),
|
||||
Parse::ParseFromDescription(err) => Self::ParseFromDescription(err),
|
||||
Parse::UnexpectedTrailingCharacters => Self::UnexpectedTrailingCharacters,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(__time_03_docs, doc(cfg(feature = "parsing")))]
|
||||
impl TryFrom<crate::Error> for Parse {
|
||||
type Error = error::DifferentVariant;
|
||||
|
||||
fn try_from(err: crate::Error) -> Result<Self, Self::Error> {
|
||||
match err {
|
||||
crate::Error::ParseFromDescription(err) => Ok(Self::ParseFromDescription(err)),
|
||||
crate::Error::UnexpectedTrailingCharacters => Ok(Self::UnexpectedTrailingCharacters),
|
||||
crate::Error::TryFromParsed(err) => Ok(Self::TryFromParsed(err)),
|
||||
_ => Err(error::DifferentVariant),
|
||||
}
|
||||
}
|
||||
}
|
||||
51
zeroidc/vendor/time/src/error/parse_from_description.rs
vendored
Normal file
51
zeroidc/vendor/time/src/error/parse_from_description.rs
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
//! Error parsing an input into a [`Parsed`](crate::parsing::Parsed) struct
|
||||
|
||||
use core::convert::TryFrom;
|
||||
use core::fmt;
|
||||
|
||||
use crate::error;
|
||||
|
||||
/// An error that occurred while parsing the input into a [`Parsed`](crate::parsing::Parsed) struct.
|
||||
#[cfg_attr(__time_03_docs, doc(cfg(feature = "parsing")))]
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ParseFromDescription {
|
||||
/// A string literal was not what was expected.
|
||||
#[non_exhaustive]
|
||||
InvalidLiteral,
|
||||
/// A dynamic component was not valid.
|
||||
InvalidComponent(&'static str),
|
||||
}
|
||||
|
||||
impl fmt::Display for ParseFromDescription {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::InvalidLiteral => f.write_str("a character literal was not valid"),
|
||||
Self::InvalidComponent(name) => {
|
||||
write!(f, "the '{}' component could not be parsed", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for ParseFromDescription {}
|
||||
|
||||
#[cfg_attr(__time_03_docs, doc(cfg(feature = "parsing")))]
|
||||
impl From<ParseFromDescription> for crate::Error {
|
||||
fn from(original: ParseFromDescription) -> Self {
|
||||
Self::ParseFromDescription(original)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(__time_03_docs, doc(cfg(feature = "parsing")))]
|
||||
impl TryFrom<crate::Error> for ParseFromDescription {
|
||||
type Error = error::DifferentVariant;
|
||||
|
||||
fn try_from(err: crate::Error) -> Result<Self, Self::Error> {
|
||||
match err {
|
||||
crate::Error::ParseFromDescription(err) => Ok(err),
|
||||
_ => Err(error::DifferentVariant),
|
||||
}
|
||||
}
|
||||
}
|
||||
75
zeroidc/vendor/time/src/error/try_from_parsed.rs
vendored
Normal file
75
zeroidc/vendor/time/src/error/try_from_parsed.rs
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
//! Error converting a [`Parsed`](crate::parsing::Parsed) struct to another type
|
||||
|
||||
use core::convert::TryFrom;
|
||||
use core::fmt;
|
||||
|
||||
use crate::error;
|
||||
|
||||
/// An error that occurred when converting a [`Parsed`](crate::parsing::Parsed) to another type.
|
||||
#[non_exhaustive]
|
||||
#[cfg_attr(__time_03_docs, doc(cfg(feature = "parsing")))]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum TryFromParsed {
|
||||
/// The [`Parsed`](crate::parsing::Parsed) did not include enough information to construct the
|
||||
/// type.
|
||||
InsufficientInformation,
|
||||
/// Some component contained an invalid value for the type.
|
||||
ComponentRange(error::ComponentRange),
|
||||
}
|
||||
|
||||
impl fmt::Display for TryFromParsed {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::InsufficientInformation => f.write_str(
|
||||
"the `Parsed` struct did not include enough information to construct the type",
|
||||
),
|
||||
Self::ComponentRange(err) => err.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<error::ComponentRange> for TryFromParsed {
|
||||
fn from(v: error::ComponentRange) -> Self {
|
||||
Self::ComponentRange(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<TryFromParsed> for error::ComponentRange {
|
||||
type Error = error::DifferentVariant;
|
||||
|
||||
fn try_from(err: TryFromParsed) -> Result<Self, Self::Error> {
|
||||
match err {
|
||||
TryFromParsed::ComponentRange(err) => Ok(err),
|
||||
_ => Err(error::DifferentVariant),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for TryFromParsed {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::InsufficientInformation => None,
|
||||
Self::ComponentRange(err) => Some(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(__time_03_docs, doc(cfg(feature = "parsing")))]
|
||||
impl From<TryFromParsed> for crate::Error {
|
||||
fn from(original: TryFromParsed) -> Self {
|
||||
Self::TryFromParsed(original)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(__time_03_docs, doc(cfg(feature = "parsing")))]
|
||||
impl TryFrom<crate::Error> for TryFromParsed {
|
||||
type Error = error::DifferentVariant;
|
||||
|
||||
fn try_from(err: crate::Error) -> Result<Self, Self::Error> {
|
||||
match err {
|
||||
crate::Error::TryFromParsed(err) => Ok(err),
|
||||
_ => Err(error::DifferentVariant),
|
||||
}
|
||||
}
|
||||
}
|
||||
279
zeroidc/vendor/time/src/ext.rs
vendored
Normal file
279
zeroidc/vendor/time/src/ext.rs
vendored
Normal file
@@ -0,0 +1,279 @@
|
||||
//! Extension traits.
|
||||
|
||||
use core::time::Duration as StdDuration;
|
||||
|
||||
use crate::Duration;
|
||||
|
||||
/// Sealed trait to prevent downstream implementations.
|
||||
mod sealed {
|
||||
/// A trait that cannot be implemented by downstream users.
|
||||
pub trait Sealed {}
|
||||
impl Sealed for i64 {}
|
||||
impl Sealed for u64 {}
|
||||
impl Sealed for f64 {}
|
||||
}
|
||||
|
||||
// region: NumericalDuration
|
||||
/// Create [`Duration`]s from numeric literals.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic construction of [`Duration`]s.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{Duration, ext::NumericalDuration};
|
||||
/// assert_eq!(5.nanoseconds(), Duration::nanoseconds(5));
|
||||
/// assert_eq!(5.microseconds(), Duration::microseconds(5));
|
||||
/// assert_eq!(5.milliseconds(), Duration::milliseconds(5));
|
||||
/// assert_eq!(5.seconds(), Duration::seconds(5));
|
||||
/// assert_eq!(5.minutes(), Duration::minutes(5));
|
||||
/// assert_eq!(5.hours(), Duration::hours(5));
|
||||
/// assert_eq!(5.days(), Duration::days(5));
|
||||
/// assert_eq!(5.weeks(), Duration::weeks(5));
|
||||
/// ```
|
||||
///
|
||||
/// Signed integers work as well!
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{Duration, ext::NumericalDuration};
|
||||
/// assert_eq!((-5).nanoseconds(), Duration::nanoseconds(-5));
|
||||
/// assert_eq!((-5).microseconds(), Duration::microseconds(-5));
|
||||
/// assert_eq!((-5).milliseconds(), Duration::milliseconds(-5));
|
||||
/// assert_eq!((-5).seconds(), Duration::seconds(-5));
|
||||
/// assert_eq!((-5).minutes(), Duration::minutes(-5));
|
||||
/// assert_eq!((-5).hours(), Duration::hours(-5));
|
||||
/// assert_eq!((-5).days(), Duration::days(-5));
|
||||
/// assert_eq!((-5).weeks(), Duration::weeks(-5));
|
||||
/// ```
|
||||
///
|
||||
/// Just like any other [`Duration`], they can be added, subtracted, etc.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::ext::NumericalDuration;
|
||||
/// assert_eq!(2.seconds() + 500.milliseconds(), 2_500.milliseconds());
|
||||
/// assert_eq!(2.seconds() - 500.milliseconds(), 1_500.milliseconds());
|
||||
/// ```
|
||||
///
|
||||
/// When called on floating point values, any remainder of the floating point value will be
|
||||
/// truncated. Keep in mind that floating point numbers are inherently imprecise and have limited
|
||||
/// capacity.
|
||||
pub trait NumericalDuration: sealed::Sealed {
|
||||
/// Create a [`Duration`] from the number of nanoseconds.
|
||||
fn nanoseconds(self) -> Duration;
|
||||
/// Create a [`Duration`] from the number of microseconds.
|
||||
fn microseconds(self) -> Duration;
|
||||
/// Create a [`Duration`] from the number of milliseconds.
|
||||
fn milliseconds(self) -> Duration;
|
||||
/// Create a [`Duration`] from the number of seconds.
|
||||
fn seconds(self) -> Duration;
|
||||
/// Create a [`Duration`] from the number of minutes.
|
||||
fn minutes(self) -> Duration;
|
||||
/// Create a [`Duration`] from the number of hours.
|
||||
fn hours(self) -> Duration;
|
||||
/// Create a [`Duration`] from the number of days.
|
||||
fn days(self) -> Duration;
|
||||
/// Create a [`Duration`] from the number of weeks.
|
||||
fn weeks(self) -> Duration;
|
||||
}
|
||||
|
||||
impl NumericalDuration for i64 {
|
||||
fn nanoseconds(self) -> Duration {
|
||||
Duration::nanoseconds(self)
|
||||
}
|
||||
|
||||
fn microseconds(self) -> Duration {
|
||||
Duration::microseconds(self)
|
||||
}
|
||||
|
||||
fn milliseconds(self) -> Duration {
|
||||
Duration::milliseconds(self)
|
||||
}
|
||||
|
||||
fn seconds(self) -> Duration {
|
||||
Duration::seconds(self)
|
||||
}
|
||||
|
||||
fn minutes(self) -> Duration {
|
||||
Duration::minutes(self)
|
||||
}
|
||||
|
||||
fn hours(self) -> Duration {
|
||||
Duration::hours(self)
|
||||
}
|
||||
|
||||
fn days(self) -> Duration {
|
||||
Duration::days(self)
|
||||
}
|
||||
|
||||
fn weeks(self) -> Duration {
|
||||
Duration::weeks(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl NumericalDuration for f64 {
|
||||
fn nanoseconds(self) -> Duration {
|
||||
Duration::nanoseconds(self as _)
|
||||
}
|
||||
|
||||
fn microseconds(self) -> Duration {
|
||||
Duration::nanoseconds((self * 1_000.) as _)
|
||||
}
|
||||
|
||||
fn milliseconds(self) -> Duration {
|
||||
Duration::nanoseconds((self * 1_000_000.) as _)
|
||||
}
|
||||
|
||||
fn seconds(self) -> Duration {
|
||||
Duration::nanoseconds((self * 1_000_000_000.) as _)
|
||||
}
|
||||
|
||||
fn minutes(self) -> Duration {
|
||||
Duration::nanoseconds((self * 60_000_000_000.) as _)
|
||||
}
|
||||
|
||||
fn hours(self) -> Duration {
|
||||
Duration::nanoseconds((self * 3_600_000_000_000.) as _)
|
||||
}
|
||||
|
||||
fn days(self) -> Duration {
|
||||
Duration::nanoseconds((self * 86_400_000_000_000.) as _)
|
||||
}
|
||||
|
||||
fn weeks(self) -> Duration {
|
||||
Duration::nanoseconds((self * 604_800_000_000_000.) as _)
|
||||
}
|
||||
}
|
||||
// endregion NumericalDuration
|
||||
|
||||
// region: NumericalStdDuration
|
||||
/// Create [`std::time::Duration`]s from numeric literals.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic construction of [`std::time::Duration`]s.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::ext::NumericalStdDuration;
|
||||
/// # use core::time::Duration;
|
||||
/// assert_eq!(5.std_nanoseconds(), Duration::from_nanos(5));
|
||||
/// assert_eq!(5.std_microseconds(), Duration::from_micros(5));
|
||||
/// assert_eq!(5.std_milliseconds(), Duration::from_millis(5));
|
||||
/// assert_eq!(5.std_seconds(), Duration::from_secs(5));
|
||||
/// assert_eq!(5.std_minutes(), Duration::from_secs(5 * 60));
|
||||
/// assert_eq!(5.std_hours(), Duration::from_secs(5 * 3_600));
|
||||
/// assert_eq!(5.std_days(), Duration::from_secs(5 * 86_400));
|
||||
/// assert_eq!(5.std_weeks(), Duration::from_secs(5 * 604_800));
|
||||
/// ```
|
||||
///
|
||||
/// Just like any other [`std::time::Duration`], they can be added, subtracted, etc.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::ext::NumericalStdDuration;
|
||||
/// assert_eq!(
|
||||
/// 2.std_seconds() + 500.std_milliseconds(),
|
||||
/// 2_500.std_milliseconds()
|
||||
/// );
|
||||
/// assert_eq!(
|
||||
/// 2.std_seconds() - 500.std_milliseconds(),
|
||||
/// 1_500.std_milliseconds()
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// When called on floating point values, any remainder of the floating point value will be
|
||||
/// truncated. Keep in mind that floating point numbers are inherently imprecise and have limited
|
||||
/// capacity.
|
||||
pub trait NumericalStdDuration: sealed::Sealed {
|
||||
/// Create a [`std::time::Duration`] from the number of nanoseconds.
|
||||
fn std_nanoseconds(self) -> StdDuration;
|
||||
/// Create a [`std::time::Duration`] from the number of microseconds.
|
||||
fn std_microseconds(self) -> StdDuration;
|
||||
/// Create a [`std::time::Duration`] from the number of milliseconds.
|
||||
fn std_milliseconds(self) -> StdDuration;
|
||||
/// Create a [`std::time::Duration`] from the number of seconds.
|
||||
fn std_seconds(self) -> StdDuration;
|
||||
/// Create a [`std::time::Duration`] from the number of minutes.
|
||||
fn std_minutes(self) -> StdDuration;
|
||||
/// Create a [`std::time::Duration`] from the number of hours.
|
||||
fn std_hours(self) -> StdDuration;
|
||||
/// Create a [`std::time::Duration`] from the number of days.
|
||||
fn std_days(self) -> StdDuration;
|
||||
/// Create a [`std::time::Duration`] from the number of weeks.
|
||||
fn std_weeks(self) -> StdDuration;
|
||||
}
|
||||
|
||||
impl NumericalStdDuration for u64 {
|
||||
fn std_nanoseconds(self) -> StdDuration {
|
||||
StdDuration::from_nanos(self)
|
||||
}
|
||||
|
||||
fn std_microseconds(self) -> StdDuration {
|
||||
StdDuration::from_micros(self)
|
||||
}
|
||||
|
||||
fn std_milliseconds(self) -> StdDuration {
|
||||
StdDuration::from_millis(self)
|
||||
}
|
||||
|
||||
fn std_seconds(self) -> StdDuration {
|
||||
StdDuration::from_secs(self)
|
||||
}
|
||||
|
||||
fn std_minutes(self) -> StdDuration {
|
||||
StdDuration::from_secs(self * 60)
|
||||
}
|
||||
|
||||
fn std_hours(self) -> StdDuration {
|
||||
StdDuration::from_secs(self * 3_600)
|
||||
}
|
||||
|
||||
fn std_days(self) -> StdDuration {
|
||||
StdDuration::from_secs(self * 86_400)
|
||||
}
|
||||
|
||||
fn std_weeks(self) -> StdDuration {
|
||||
StdDuration::from_secs(self * 604_800)
|
||||
}
|
||||
}
|
||||
|
||||
impl NumericalStdDuration for f64 {
|
||||
fn std_nanoseconds(self) -> StdDuration {
|
||||
assert!(self >= 0.);
|
||||
StdDuration::from_nanos(self as _)
|
||||
}
|
||||
|
||||
fn std_microseconds(self) -> StdDuration {
|
||||
assert!(self >= 0.);
|
||||
StdDuration::from_nanos((self * 1_000.) as _)
|
||||
}
|
||||
|
||||
fn std_milliseconds(self) -> StdDuration {
|
||||
assert!(self >= 0.);
|
||||
StdDuration::from_nanos((self * 1_000_000.) as _)
|
||||
}
|
||||
|
||||
fn std_seconds(self) -> StdDuration {
|
||||
assert!(self >= 0.);
|
||||
StdDuration::from_nanos((self * 1_000_000_000.) as _)
|
||||
}
|
||||
|
||||
fn std_minutes(self) -> StdDuration {
|
||||
assert!(self >= 0.);
|
||||
StdDuration::from_nanos((self * 60_000_000_000.) as _)
|
||||
}
|
||||
|
||||
fn std_hours(self) -> StdDuration {
|
||||
assert!(self >= 0.);
|
||||
StdDuration::from_nanos((self * 3_600_000_000_000.) as _)
|
||||
}
|
||||
|
||||
fn std_days(self) -> StdDuration {
|
||||
assert!(self >= 0.);
|
||||
StdDuration::from_nanos((self * 86_400_000_000_000.) as _)
|
||||
}
|
||||
|
||||
fn std_weeks(self) -> StdDuration {
|
||||
assert!(self >= 0.);
|
||||
StdDuration::from_nanos((self * 604_800_000_000_000.) as _)
|
||||
}
|
||||
}
|
||||
// endregion NumericalStdDuration
|
||||
167
zeroidc/vendor/time/src/format_description/component.rs
vendored
Normal file
167
zeroidc/vendor/time/src/format_description/component.rs
vendored
Normal file
@@ -0,0 +1,167 @@
|
||||
//! Part of a format description.
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::string::String;
|
||||
|
||||
use crate::format_description::modifier;
|
||||
#[cfg(feature = "alloc")]
|
||||
use crate::{error::InvalidFormatDescription, format_description::modifier::Modifiers};
|
||||
|
||||
/// A component of a larger format description.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Component {
|
||||
/// Day of the month.
|
||||
Day(modifier::Day),
|
||||
/// Month of the year.
|
||||
Month(modifier::Month),
|
||||
/// Ordinal day of the year.
|
||||
Ordinal(modifier::Ordinal),
|
||||
/// Day of the week.
|
||||
Weekday(modifier::Weekday),
|
||||
/// Week within the year.
|
||||
WeekNumber(modifier::WeekNumber),
|
||||
/// Year of the date.
|
||||
Year(modifier::Year),
|
||||
/// Hour of the day.
|
||||
Hour(modifier::Hour),
|
||||
/// Minute within the hour.
|
||||
Minute(modifier::Minute),
|
||||
/// AM/PM part of the time.
|
||||
Period(modifier::Period),
|
||||
/// Second within the minute.
|
||||
Second(modifier::Second),
|
||||
/// Subsecond within the second.
|
||||
Subsecond(modifier::Subsecond),
|
||||
/// Hour of the UTC offset.
|
||||
OffsetHour(modifier::OffsetHour),
|
||||
/// Minute within the hour of the UTC offset.
|
||||
OffsetMinute(modifier::OffsetMinute),
|
||||
/// Second within the minute of the UTC offset.
|
||||
OffsetSecond(modifier::OffsetSecond),
|
||||
}
|
||||
|
||||
/// A component with no modifiers present.
|
||||
#[cfg(feature = "alloc")]
|
||||
pub(crate) enum NakedComponent {
|
||||
/// Day of the month.
|
||||
Day,
|
||||
/// Month of the year.
|
||||
Month,
|
||||
/// Ordinal day of the year.
|
||||
Ordinal,
|
||||
/// Day of the week.
|
||||
Weekday,
|
||||
/// Week within the year.
|
||||
WeekNumber,
|
||||
/// Year of the date.
|
||||
Year,
|
||||
/// Hour of the day.
|
||||
Hour,
|
||||
/// Minute within the hour.
|
||||
Minute,
|
||||
/// AM/PM part of the time.
|
||||
Period,
|
||||
/// Second within the minute.
|
||||
Second,
|
||||
/// Subsecond within the second.
|
||||
Subsecond,
|
||||
/// Hour of the UTC offset.
|
||||
OffsetHour,
|
||||
/// Minute within the hour of the UTC offset.
|
||||
OffsetMinute,
|
||||
/// Second within the minute of the UTC offset.
|
||||
OffsetSecond,
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl NakedComponent {
|
||||
/// Parse a component (without its modifiers) from the provided name.
|
||||
pub(crate) fn parse(
|
||||
component_name: &[u8],
|
||||
component_index: usize,
|
||||
) -> Result<Self, InvalidFormatDescription> {
|
||||
match component_name {
|
||||
b"day" => Ok(Self::Day),
|
||||
b"month" => Ok(Self::Month),
|
||||
b"ordinal" => Ok(Self::Ordinal),
|
||||
b"weekday" => Ok(Self::Weekday),
|
||||
b"week_number" => Ok(Self::WeekNumber),
|
||||
b"year" => Ok(Self::Year),
|
||||
b"hour" => Ok(Self::Hour),
|
||||
b"minute" => Ok(Self::Minute),
|
||||
b"period" => Ok(Self::Period),
|
||||
b"second" => Ok(Self::Second),
|
||||
b"subsecond" => Ok(Self::Subsecond),
|
||||
b"offset_hour" => Ok(Self::OffsetHour),
|
||||
b"offset_minute" => Ok(Self::OffsetMinute),
|
||||
b"offset_second" => Ok(Self::OffsetSecond),
|
||||
b"" => Err(InvalidFormatDescription::MissingComponentName {
|
||||
index: component_index,
|
||||
}),
|
||||
_ => Err(InvalidFormatDescription::InvalidComponentName {
|
||||
name: String::from_utf8_lossy(component_name).into_owned(),
|
||||
index: component_index,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Attach the necessary modifiers to the component.
|
||||
pub(crate) fn attach_modifiers(self, modifiers: &Modifiers) -> Component {
|
||||
match self {
|
||||
Self::Day => Component::Day(modifier::Day {
|
||||
padding: modifiers.padding.unwrap_or_default(),
|
||||
}),
|
||||
Self::Month => Component::Month(modifier::Month {
|
||||
padding: modifiers.padding.unwrap_or_default(),
|
||||
repr: modifiers.month_repr.unwrap_or_default(),
|
||||
case_sensitive: modifiers.case_sensitive.unwrap_or(true),
|
||||
}),
|
||||
Self::Ordinal => Component::Ordinal(modifier::Ordinal {
|
||||
padding: modifiers.padding.unwrap_or_default(),
|
||||
}),
|
||||
Self::Weekday => Component::Weekday(modifier::Weekday {
|
||||
repr: modifiers.weekday_repr.unwrap_or_default(),
|
||||
one_indexed: modifiers.weekday_is_one_indexed.unwrap_or(true),
|
||||
case_sensitive: modifiers.case_sensitive.unwrap_or(true),
|
||||
}),
|
||||
Self::WeekNumber => Component::WeekNumber(modifier::WeekNumber {
|
||||
padding: modifiers.padding.unwrap_or_default(),
|
||||
repr: modifiers.week_number_repr.unwrap_or_default(),
|
||||
}),
|
||||
Self::Year => Component::Year(modifier::Year {
|
||||
padding: modifiers.padding.unwrap_or_default(),
|
||||
repr: modifiers.year_repr.unwrap_or_default(),
|
||||
iso_week_based: modifiers.year_is_iso_week_based.unwrap_or_default(),
|
||||
sign_is_mandatory: modifiers.sign_is_mandatory.unwrap_or_default(),
|
||||
}),
|
||||
Self::Hour => Component::Hour(modifier::Hour {
|
||||
padding: modifiers.padding.unwrap_or_default(),
|
||||
is_12_hour_clock: modifiers.hour_is_12_hour_clock.unwrap_or_default(),
|
||||
}),
|
||||
Self::Minute => Component::Minute(modifier::Minute {
|
||||
padding: modifiers.padding.unwrap_or_default(),
|
||||
}),
|
||||
Self::Period => Component::Period(modifier::Period {
|
||||
is_uppercase: modifiers.period_is_uppercase.unwrap_or(true),
|
||||
case_sensitive: modifiers.case_sensitive.unwrap_or(true),
|
||||
}),
|
||||
Self::Second => Component::Second(modifier::Second {
|
||||
padding: modifiers.padding.unwrap_or_default(),
|
||||
}),
|
||||
Self::Subsecond => Component::Subsecond(modifier::Subsecond {
|
||||
digits: modifiers.subsecond_digits.unwrap_or_default(),
|
||||
}),
|
||||
Self::OffsetHour => Component::OffsetHour(modifier::OffsetHour {
|
||||
sign_is_mandatory: modifiers.sign_is_mandatory.unwrap_or_default(),
|
||||
padding: modifiers.padding.unwrap_or_default(),
|
||||
}),
|
||||
Self::OffsetMinute => Component::OffsetMinute(modifier::OffsetMinute {
|
||||
padding: modifiers.padding.unwrap_or_default(),
|
||||
}),
|
||||
Self::OffsetSecond => Component::OffsetSecond(modifier::OffsetSecond {
|
||||
padding: modifiers.padding.unwrap_or_default(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
186
zeroidc/vendor/time/src/format_description/mod.rs
vendored
Normal file
186
zeroidc/vendor/time/src/format_description/mod.rs
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
//! Description of how types should be formatted and parsed.
|
||||
//!
|
||||
//! The formatted value will be output to the provided writer. Format descriptions can be
|
||||
//! [well-known](crate::format_description::well_known) or obtained by using the
|
||||
//! [`format_description!`](crate::macros::format_description) macro, the
|
||||
//! [`format_description::parse`](crate::format_description::parse()) function.
|
||||
|
||||
mod component;
|
||||
pub mod modifier;
|
||||
#[cfg(feature = "alloc")]
|
||||
pub(crate) mod parse;
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::string::String;
|
||||
use core::convert::TryFrom;
|
||||
#[cfg(feature = "alloc")]
|
||||
use core::fmt;
|
||||
|
||||
pub use self::component::Component;
|
||||
#[cfg(feature = "alloc")]
|
||||
pub use self::parse::parse;
|
||||
use crate::error;
|
||||
|
||||
/// Helper methods.
|
||||
#[cfg(feature = "alloc")]
|
||||
mod helper {
|
||||
/// Consume all leading whitespace, advancing `index` as appropriate.
|
||||
#[must_use = "This does not modify the original slice."]
|
||||
pub(crate) fn consume_whitespace<'a>(bytes: &'a [u8], index: &mut usize) -> &'a [u8] {
|
||||
let first_non_whitespace = bytes
|
||||
.iter()
|
||||
.position(|c| !c.is_ascii_whitespace())
|
||||
.unwrap_or(bytes.len());
|
||||
*index += first_non_whitespace;
|
||||
&bytes[first_non_whitespace..]
|
||||
}
|
||||
}
|
||||
|
||||
/// Well-known formats, typically RFCs.
|
||||
pub mod well_known {
|
||||
/// The format described in [RFC 3339](https://tools.ietf.org/html/rfc3339#section-5.6).
|
||||
///
|
||||
/// Format example: 1985-04-12T23:20:50.52Z
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{format_description::well_known::Rfc3339, macros::datetime, OffsetDateTime};
|
||||
/// assert_eq!(
|
||||
/// OffsetDateTime::parse("1985-04-12T23:20:50.52Z", &Rfc3339)?,
|
||||
/// datetime!(1985-04-12 23:20:50.52 +00:00)
|
||||
/// );
|
||||
/// # Ok::<_, time::Error>(())
|
||||
/// ```
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{format_description::well_known::Rfc3339, macros::datetime};
|
||||
/// assert_eq!(
|
||||
/// datetime!(1985-04-12 23:20:50.52 +00:00).format(&Rfc3339)?,
|
||||
/// "1985-04-12T23:20:50.52Z"
|
||||
/// );
|
||||
/// # Ok::<_, time::Error>(())
|
||||
/// ```
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Rfc3339;
|
||||
|
||||
/// The format described in [RFC 2822](https://tools.ietf.org/html/rfc2822#section-3.3).
|
||||
///
|
||||
/// Example: Fri, 21 Nov 1997 09:55:06 -0600
|
||||
///
|
||||
/// # Examples
|
||||
/// ```rust
|
||||
/// # use time::{format_description::well_known::Rfc2822, macros::datetime, OffsetDateTime};
|
||||
/// assert_eq!(
|
||||
/// OffsetDateTime::parse("Sat, 12 Jun 1993 13:25:19 GMT", &Rfc2822)?,
|
||||
/// datetime!(1993-06-12 13:25:19 +00:00)
|
||||
/// );
|
||||
/// # Ok::<_, time::Error>(())
|
||||
/// ```
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{format_description::well_known::Rfc2822, macros::datetime};
|
||||
/// assert_eq!(
|
||||
/// datetime!(1997-11-21 09:55:06 -06:00).format(&Rfc2822)?,
|
||||
/// "Fri, 21 Nov 1997 09:55:06 -0600"
|
||||
/// );
|
||||
/// # Ok::<_, time::Error>(())
|
||||
/// ```
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Rfc2822;
|
||||
}
|
||||
|
||||
/// A complete description of how to format and parse a type.
|
||||
#[non_exhaustive]
|
||||
#[cfg_attr(not(feature = "alloc"), derive(Debug))]
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub enum FormatItem<'a> {
|
||||
/// Bytes that are formatted as-is.
|
||||
///
|
||||
/// **Note**: If you call the `format` method that returns a `String`, these bytes will be
|
||||
/// passed through `String::from_utf8_lossy`.
|
||||
Literal(&'a [u8]),
|
||||
/// A minimal representation of a single non-literal item.
|
||||
Component(Component),
|
||||
/// A series of literals or components that collectively form a partial or complete
|
||||
/// description.
|
||||
Compound(&'a [Self]),
|
||||
/// A `FormatItem` that may or may not be present when parsing. If parsing fails, there will be
|
||||
/// no effect on the resulting `struct`.
|
||||
///
|
||||
/// This variant has no effect on formatting, as the value is guaranteed to be present.
|
||||
Optional(&'a Self),
|
||||
/// A series of `FormatItem`s where, when parsing, the first successful parse is used. When
|
||||
/// formatting, the first element of the slice is used. An empty slice is a no-op when
|
||||
/// formatting or parsing.
|
||||
First(&'a [Self]),
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl fmt::Debug for FormatItem<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
FormatItem::Literal(literal) => f.write_str(&String::from_utf8_lossy(literal)),
|
||||
FormatItem::Component(component) => component.fmt(f),
|
||||
FormatItem::Compound(compound) => compound.fmt(f),
|
||||
FormatItem::Optional(item) => f.debug_tuple("Optional").field(item).finish(),
|
||||
FormatItem::First(items) => f.debug_tuple("First").field(items).finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Component> for FormatItem<'_> {
|
||||
fn from(component: Component) -> Self {
|
||||
Self::Component(component)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<FormatItem<'_>> for Component {
|
||||
type Error = error::DifferentVariant;
|
||||
|
||||
fn try_from(value: FormatItem<'_>) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
FormatItem::Component(component) => Ok(component),
|
||||
_ => Err(error::DifferentVariant),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a [FormatItem<'_>]> for FormatItem<'a> {
|
||||
fn from(items: &'a [FormatItem<'_>]) -> FormatItem<'a> {
|
||||
FormatItem::Compound(items)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<FormatItem<'a>> for &[FormatItem<'a>] {
|
||||
type Error = error::DifferentVariant;
|
||||
|
||||
fn try_from(value: FormatItem<'a>) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
FormatItem::Compound(items) => Ok(items),
|
||||
_ => Err(error::DifferentVariant),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Component> for FormatItem<'_> {
|
||||
fn eq(&self, rhs: &Component) -> bool {
|
||||
matches!(self, FormatItem::Component(component) if component == rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<FormatItem<'_>> for Component {
|
||||
fn eq(&self, rhs: &FormatItem<'_>) -> bool {
|
||||
rhs == self
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&[FormatItem<'_>]> for FormatItem<'_> {
|
||||
fn eq(&self, rhs: &&[FormatItem<'_>]) -> bool {
|
||||
matches!(self, FormatItem::Compound(compound) if compound == rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<FormatItem<'_>> for &[FormatItem<'_>] {
|
||||
fn eq(&self, rhs: &FormatItem<'_>) -> bool {
|
||||
rhs == self
|
||||
}
|
||||
}
|
||||
509
zeroidc/vendor/time/src/format_description/modifier.rs
vendored
Normal file
509
zeroidc/vendor/time/src/format_description/modifier.rs
vendored
Normal file
@@ -0,0 +1,509 @@
|
||||
//! Various modifiers for components.
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::string::String;
|
||||
#[cfg(feature = "alloc")]
|
||||
use core::mem;
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
use crate::{error::InvalidFormatDescription, format_description::helper};
|
||||
|
||||
// region: date modifiers
|
||||
/// Day of the month.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Day {
|
||||
/// The padding to obtain the minimum width.
|
||||
pub padding: Padding,
|
||||
}
|
||||
|
||||
/// The representation of a month.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum MonthRepr {
|
||||
/// The number of the month (January is 1, December is 12).
|
||||
Numerical,
|
||||
/// The long form of the month name (e.g. "January").
|
||||
Long,
|
||||
/// The short form of the month name (e.g. "Jan").
|
||||
Short,
|
||||
}
|
||||
|
||||
/// Month of the year.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Month {
|
||||
/// The padding to obtain the minimum width.
|
||||
pub padding: Padding,
|
||||
/// What form of representation should be used?
|
||||
pub repr: MonthRepr,
|
||||
/// Is the value case sensitive when parsing?
|
||||
pub case_sensitive: bool,
|
||||
}
|
||||
|
||||
/// Ordinal day of the year.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Ordinal {
|
||||
/// The padding to obtain the minimum width.
|
||||
pub padding: Padding,
|
||||
}
|
||||
|
||||
/// The representation used for the day of the week.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum WeekdayRepr {
|
||||
/// The short form of the weekday (e.g. "Mon").
|
||||
Short,
|
||||
/// The long form of the weekday (e.g. "Monday").
|
||||
Long,
|
||||
/// A numerical representation using Sunday as the first day of the week.
|
||||
///
|
||||
/// Sunday is either 0 or 1, depending on the other modifier's value.
|
||||
Sunday,
|
||||
/// A numerical representation using Monday as the first day of the week.
|
||||
///
|
||||
/// Monday is either 0 or 1, depending on the other modifier's value.
|
||||
Monday,
|
||||
}
|
||||
|
||||
/// Day of the week.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Weekday {
|
||||
/// What form of representation should be used?
|
||||
pub repr: WeekdayRepr,
|
||||
/// When using a numerical representation, should it be zero or one-indexed?
|
||||
pub one_indexed: bool,
|
||||
/// Is the value case sensitive when parsing?
|
||||
pub case_sensitive: bool,
|
||||
}
|
||||
|
||||
/// The representation used for the week number.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum WeekNumberRepr {
|
||||
/// Week 1 is the week that contains January 4.
|
||||
Iso,
|
||||
/// Week 1 begins on the first Sunday of the calendar year.
|
||||
Sunday,
|
||||
/// Week 1 begins on the first Monday of the calendar year.
|
||||
Monday,
|
||||
}
|
||||
|
||||
/// Week within the year.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct WeekNumber {
|
||||
/// The padding to obtain the minimum width.
|
||||
pub padding: Padding,
|
||||
/// What kind of representation should be used?
|
||||
pub repr: WeekNumberRepr,
|
||||
}
|
||||
|
||||
/// The representation used for a year value.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum YearRepr {
|
||||
/// The full value of the year.
|
||||
Full,
|
||||
/// Only the last two digits of the year.
|
||||
LastTwo,
|
||||
}
|
||||
|
||||
/// Year of the date.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Year {
|
||||
/// The padding to obtain the minimum width.
|
||||
pub padding: Padding,
|
||||
/// What kind of representation should be used?
|
||||
pub repr: YearRepr,
|
||||
/// Whether the value is based on the ISO week number or the Gregorian calendar.
|
||||
pub iso_week_based: bool,
|
||||
/// Whether the `+` sign is present when a positive year contains fewer than five digits.
|
||||
pub sign_is_mandatory: bool,
|
||||
}
|
||||
// endregion date modifiers
|
||||
|
||||
// region: time modifiers
|
||||
/// Hour of the day.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Hour {
|
||||
/// The padding to obtain the minimum width.
|
||||
pub padding: Padding,
|
||||
/// Is the hour displayed using a 12 or 24-hour clock?
|
||||
pub is_12_hour_clock: bool,
|
||||
}
|
||||
|
||||
/// Minute within the hour.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Minute {
|
||||
/// The padding to obtain the minimum width.
|
||||
pub padding: Padding,
|
||||
}
|
||||
|
||||
/// AM/PM part of the time.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Period {
|
||||
/// Is the period uppercase or lowercase?
|
||||
pub is_uppercase: bool,
|
||||
/// Is the value case sensitive when parsing?
|
||||
///
|
||||
/// Note that when `false`, the `is_uppercase` field has no effect on parsing behavior.
|
||||
pub case_sensitive: bool,
|
||||
}
|
||||
|
||||
/// Second within the minute.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Second {
|
||||
/// The padding to obtain the minimum width.
|
||||
pub padding: Padding,
|
||||
}
|
||||
|
||||
/// The number of digits present in a subsecond representation.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum SubsecondDigits {
|
||||
/// Exactly one digit.
|
||||
One,
|
||||
/// Exactly two digits.
|
||||
Two,
|
||||
/// Exactly three digits.
|
||||
Three,
|
||||
/// Exactly four digits.
|
||||
Four,
|
||||
/// Exactly five digits.
|
||||
Five,
|
||||
/// Exactly six digits.
|
||||
Six,
|
||||
/// Exactly seven digits.
|
||||
Seven,
|
||||
/// Exactly eight digits.
|
||||
Eight,
|
||||
/// Exactly nine digits.
|
||||
Nine,
|
||||
/// Any number of digits (up to nine) that is at least one. When formatting, the minimum digits
|
||||
/// necessary will be used.
|
||||
OneOrMore,
|
||||
}
|
||||
|
||||
/// Subsecond within the second.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Subsecond {
|
||||
/// How many digits are present in the component?
|
||||
pub digits: SubsecondDigits,
|
||||
}
|
||||
// endregion time modifiers
|
||||
|
||||
// region: offset modifiers
|
||||
/// Hour of the UTC offset.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct OffsetHour {
|
||||
/// Whether the `+` sign is present on positive values.
|
||||
pub sign_is_mandatory: bool,
|
||||
/// The padding to obtain the minimum width.
|
||||
pub padding: Padding,
|
||||
}
|
||||
|
||||
/// Minute within the hour of the UTC offset.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct OffsetMinute {
|
||||
/// The padding to obtain the minimum width.
|
||||
pub padding: Padding,
|
||||
}
|
||||
|
||||
/// Second within the minute of the UTC offset.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct OffsetSecond {
|
||||
/// The padding to obtain the minimum width.
|
||||
pub padding: Padding,
|
||||
}
|
||||
// endregion offset modifiers
|
||||
|
||||
/// Type of padding to ensure a minimum width.
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Padding {
|
||||
/// A space character (` `) should be used as padding.
|
||||
Space,
|
||||
/// A zero character (`0`) should be used as padding.
|
||||
Zero,
|
||||
/// There is no padding. This can result in a width below the otherwise minimum number of
|
||||
/// characters.
|
||||
None,
|
||||
}
|
||||
|
||||
/// Generate the provided code if and only if `pub` is present.
|
||||
macro_rules! if_pub {
|
||||
(pub $(#[$attr:meta])*; $($x:tt)*) => {
|
||||
$(#[$attr])*
|
||||
///
|
||||
/// This function exists since [`Default::default()`] cannot be used in a `const` context.
|
||||
/// It may be removed once that becomes possible. As the [`Default`] trait is in the
|
||||
/// prelude, removing this function in the future will not cause any resolution failures for
|
||||
/// the overwhelming majority of users; only users who use `#![no_implicit_prelude]` will be
|
||||
/// affected. As such it will not be considered a breaking change.
|
||||
$($x)*
|
||||
};
|
||||
($($_:tt)*) => {};
|
||||
}
|
||||
|
||||
/// Implement `Default` for the given type. This also generates an inherent implementation of a
|
||||
/// `default` method that is `const fn`, permitting the default value to be used in const contexts.
|
||||
// Every modifier should use this macro rather than a derived `Default`.
|
||||
macro_rules! impl_const_default {
|
||||
($($(#[$doc:meta])* $(@$pub:ident)? $type:ty => $default:expr;)*) => {$(
|
||||
impl $type {
|
||||
if_pub! {
|
||||
$($pub)?
|
||||
$(#[$doc])*;
|
||||
pub const fn default() -> Self {
|
||||
$default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$(#[$doc])*
|
||||
impl Default for $type {
|
||||
fn default() -> Self {
|
||||
$default
|
||||
}
|
||||
}
|
||||
)*};
|
||||
}
|
||||
|
||||
impl_const_default! {
|
||||
/// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero).
|
||||
@pub Day => Self { padding: Padding::Zero };
|
||||
/// Creates a modifier that indicates the value uses the
|
||||
/// [`Numerical`](Self::Numerical) representation.
|
||||
MonthRepr => Self::Numerical;
|
||||
/// Creates an instance of this type that indicates the value uses the
|
||||
/// [`Numerical`](MonthRepr::Numerical) representation, is [padded with zeroes](Padding::Zero),
|
||||
/// and is case-sensitive when parsing.
|
||||
@pub Month => Self {
|
||||
padding: Padding::Zero,
|
||||
repr: MonthRepr::Numerical,
|
||||
case_sensitive: true,
|
||||
};
|
||||
/// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero).
|
||||
@pub Ordinal => Self { padding: Padding::Zero };
|
||||
/// Creates a modifier that indicates the value uses the [`Long`](Self::Long) representation.
|
||||
WeekdayRepr => Self::Long;
|
||||
/// Creates a modifier that indicates the value uses the [`Long`](WeekdayRepr::Long)
|
||||
/// representation and is case-sensitive when parsing. If the representation is changed to a
|
||||
/// numerical one, the instance defaults to one-based indexing.
|
||||
@pub Weekday => Self {
|
||||
repr: WeekdayRepr::Long,
|
||||
one_indexed: true,
|
||||
case_sensitive: true,
|
||||
};
|
||||
/// Creates a modifier that indicates that the value uses the [`Iso`](Self::Iso) representation.
|
||||
WeekNumberRepr => Self::Iso;
|
||||
/// Creates a modifier that indicates that the value is [padded with zeroes](Padding::Zero)
|
||||
/// and uses the [`Iso`](WeekNumberRepr::Iso) representation.
|
||||
@pub WeekNumber => Self {
|
||||
padding: Padding::Zero,
|
||||
repr: WeekNumberRepr::Iso,
|
||||
};
|
||||
/// Creates a modifier that indicates the value uses the [`Full`](Self::Full) representation.
|
||||
YearRepr => Self::Full;
|
||||
/// Creates a modifier that indicates the value uses the [`Full`](YearRepr::Full)
|
||||
/// representation, is [padded with zeroes](Padding::Zero), uses the Gregorian calendar as its
|
||||
/// base, and only includes the year's sign if necessary.
|
||||
@pub Year => Self {
|
||||
padding: Padding::Zero,
|
||||
repr: YearRepr::Full,
|
||||
iso_week_based: false,
|
||||
sign_is_mandatory: false,
|
||||
};
|
||||
/// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero) and
|
||||
/// has the 24-hour representation.
|
||||
@pub Hour => Self {
|
||||
padding: Padding::Zero,
|
||||
is_12_hour_clock: false,
|
||||
};
|
||||
/// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero).
|
||||
@pub Minute => Self { padding: Padding::Zero };
|
||||
/// Creates a modifier that indicates the value uses the upper-case representation and is
|
||||
/// case-sensitive when parsing.
|
||||
@pub Period => Self {
|
||||
is_uppercase: true,
|
||||
case_sensitive: true,
|
||||
};
|
||||
/// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero).
|
||||
@pub Second => Self { padding: Padding::Zero };
|
||||
/// Creates a modifier that indicates the stringified value contains [one or more
|
||||
/// digits](Self::OneOrMore).
|
||||
SubsecondDigits => Self::OneOrMore;
|
||||
/// Creates a modifier that indicates the stringified value contains [one or more
|
||||
/// digits](SubsecondDigits::OneOrMore).
|
||||
@pub Subsecond => Self { digits: SubsecondDigits::OneOrMore };
|
||||
/// Creates a modifier that indicates the value uses the `+` sign for all positive values
|
||||
/// and is [padded with zeroes](Padding::Zero).
|
||||
@pub OffsetHour => Self {
|
||||
sign_is_mandatory: true,
|
||||
padding: Padding::Zero,
|
||||
};
|
||||
/// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero).
|
||||
@pub OffsetMinute => Self { padding: Padding::Zero };
|
||||
/// Creates a modifier that indicates the value is [padded with zeroes](Padding::Zero).
|
||||
@pub OffsetSecond => Self { padding: Padding::Zero };
|
||||
/// Creates a modifier that indicates the value is [padded with zeroes](Self::Zero).
|
||||
Padding => Self::Zero;
|
||||
}
|
||||
|
||||
/// The modifiers parsed for any given component. `None` indicates the modifier was not present.
|
||||
#[cfg(feature = "alloc")]
|
||||
#[allow(clippy::missing_docs_in_private_items)] // fields
|
||||
#[derive(Debug, Default)]
|
||||
pub(crate) struct Modifiers {
|
||||
pub(crate) padding: Option<Padding>,
|
||||
pub(crate) hour_is_12_hour_clock: Option<bool>,
|
||||
pub(crate) period_is_uppercase: Option<bool>,
|
||||
pub(crate) month_repr: Option<MonthRepr>,
|
||||
pub(crate) subsecond_digits: Option<SubsecondDigits>,
|
||||
pub(crate) weekday_repr: Option<WeekdayRepr>,
|
||||
pub(crate) weekday_is_one_indexed: Option<bool>,
|
||||
pub(crate) week_number_repr: Option<WeekNumberRepr>,
|
||||
pub(crate) year_repr: Option<YearRepr>,
|
||||
pub(crate) year_is_iso_week_based: Option<bool>,
|
||||
pub(crate) sign_is_mandatory: Option<bool>,
|
||||
pub(crate) case_sensitive: Option<bool>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl Modifiers {
|
||||
/// Parse the modifiers of a given component.
|
||||
#[allow(clippy::too_many_lines)]
|
||||
pub(crate) fn parse(
|
||||
component_name: &[u8],
|
||||
mut bytes: &[u8],
|
||||
index: &mut usize,
|
||||
) -> Result<Self, InvalidFormatDescription> {
|
||||
let mut modifiers = Self::default();
|
||||
|
||||
while !bytes.is_empty() {
|
||||
// Trim any whitespace between modifiers.
|
||||
bytes = helper::consume_whitespace(bytes, index);
|
||||
|
||||
let modifier;
|
||||
if let Some(whitespace_loc) = bytes.iter().position(u8::is_ascii_whitespace) {
|
||||
*index += whitespace_loc;
|
||||
modifier = &bytes[..whitespace_loc];
|
||||
bytes = &bytes[whitespace_loc..];
|
||||
} else {
|
||||
modifier = mem::take(&mut bytes);
|
||||
}
|
||||
|
||||
if modifier.is_empty() {
|
||||
break;
|
||||
}
|
||||
|
||||
match (component_name, modifier) {
|
||||
(
|
||||
b"day" | b"hour" | b"minute" | b"month" | b"offset_hour" | b"offset_minute"
|
||||
| b"offset_second" | b"ordinal" | b"second" | b"week_number" | b"year",
|
||||
b"padding:space",
|
||||
) => modifiers.padding = Some(Padding::Space),
|
||||
(
|
||||
b"day" | b"hour" | b"minute" | b"month" | b"offset_hour" | b"offset_minute"
|
||||
| b"offset_second" | b"ordinal" | b"second" | b"week_number" | b"year",
|
||||
b"padding:zero",
|
||||
) => modifiers.padding = Some(Padding::Zero),
|
||||
(
|
||||
b"day" | b"hour" | b"minute" | b"month" | b"offset_hour" | b"offset_minute"
|
||||
| b"offset_second" | b"ordinal" | b"second" | b"week_number" | b"year",
|
||||
b"padding:none",
|
||||
) => modifiers.padding = Some(Padding::None),
|
||||
(b"hour", b"repr:24") => modifiers.hour_is_12_hour_clock = Some(false),
|
||||
(b"hour", b"repr:12") => modifiers.hour_is_12_hour_clock = Some(true),
|
||||
(b"month" | b"period" | b"weekday", b"case_sensitive:true") => {
|
||||
modifiers.case_sensitive = Some(true)
|
||||
}
|
||||
(b"month" | b"period" | b"weekday", b"case_sensitive:false") => {
|
||||
modifiers.case_sensitive = Some(false)
|
||||
}
|
||||
(b"month", b"repr:numerical") => modifiers.month_repr = Some(MonthRepr::Numerical),
|
||||
(b"month", b"repr:long") => modifiers.month_repr = Some(MonthRepr::Long),
|
||||
(b"month", b"repr:short") => modifiers.month_repr = Some(MonthRepr::Short),
|
||||
(b"offset_hour" | b"year", b"sign:automatic") => {
|
||||
modifiers.sign_is_mandatory = Some(false);
|
||||
}
|
||||
(b"offset_hour" | b"year", b"sign:mandatory") => {
|
||||
modifiers.sign_is_mandatory = Some(true);
|
||||
}
|
||||
(b"period", b"case:upper") => modifiers.period_is_uppercase = Some(true),
|
||||
(b"period", b"case:lower") => modifiers.period_is_uppercase = Some(false),
|
||||
(b"subsecond", b"digits:1") => {
|
||||
modifiers.subsecond_digits = Some(SubsecondDigits::One);
|
||||
}
|
||||
(b"subsecond", b"digits:2") => {
|
||||
modifiers.subsecond_digits = Some(SubsecondDigits::Two);
|
||||
}
|
||||
(b"subsecond", b"digits:3") => {
|
||||
modifiers.subsecond_digits = Some(SubsecondDigits::Three);
|
||||
}
|
||||
(b"subsecond", b"digits:4") => {
|
||||
modifiers.subsecond_digits = Some(SubsecondDigits::Four);
|
||||
}
|
||||
(b"subsecond", b"digits:5") => {
|
||||
modifiers.subsecond_digits = Some(SubsecondDigits::Five);
|
||||
}
|
||||
(b"subsecond", b"digits:6") => {
|
||||
modifiers.subsecond_digits = Some(SubsecondDigits::Six);
|
||||
}
|
||||
(b"subsecond", b"digits:7") => {
|
||||
modifiers.subsecond_digits = Some(SubsecondDigits::Seven);
|
||||
}
|
||||
(b"subsecond", b"digits:8") => {
|
||||
modifiers.subsecond_digits = Some(SubsecondDigits::Eight);
|
||||
}
|
||||
(b"subsecond", b"digits:9") => {
|
||||
modifiers.subsecond_digits = Some(SubsecondDigits::Nine);
|
||||
}
|
||||
(b"subsecond", b"digits:1+") => {
|
||||
modifiers.subsecond_digits = Some(SubsecondDigits::OneOrMore);
|
||||
}
|
||||
(b"weekday", b"repr:short") => modifiers.weekday_repr = Some(WeekdayRepr::Short),
|
||||
(b"weekday", b"repr:long") => modifiers.weekday_repr = Some(WeekdayRepr::Long),
|
||||
(b"weekday", b"repr:sunday") => modifiers.weekday_repr = Some(WeekdayRepr::Sunday),
|
||||
(b"weekday", b"repr:monday") => modifiers.weekday_repr = Some(WeekdayRepr::Monday),
|
||||
(b"weekday", b"one_indexed:true") => modifiers.weekday_is_one_indexed = Some(true),
|
||||
(b"weekday", b"one_indexed:false") => {
|
||||
modifiers.weekday_is_one_indexed = Some(false);
|
||||
}
|
||||
(b"week_number", b"repr:iso") => {
|
||||
modifiers.week_number_repr = Some(WeekNumberRepr::Iso);
|
||||
}
|
||||
(b"week_number", b"repr:sunday") => {
|
||||
modifiers.week_number_repr = Some(WeekNumberRepr::Sunday);
|
||||
}
|
||||
(b"week_number", b"repr:monday") => {
|
||||
modifiers.week_number_repr = Some(WeekNumberRepr::Monday);
|
||||
}
|
||||
(b"year", b"repr:full") => modifiers.year_repr = Some(YearRepr::Full),
|
||||
(b"year", b"repr:last_two") => modifiers.year_repr = Some(YearRepr::LastTwo),
|
||||
(b"year", b"base:calendar") => modifiers.year_is_iso_week_based = Some(false),
|
||||
(b"year", b"base:iso_week") => modifiers.year_is_iso_week_based = Some(true),
|
||||
_ => {
|
||||
return Err(InvalidFormatDescription::InvalidModifier {
|
||||
value: String::from_utf8_lossy(modifier).into_owned(),
|
||||
index: *index,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(modifiers)
|
||||
}
|
||||
}
|
||||
97
zeroidc/vendor/time/src/format_description/parse.rs
vendored
Normal file
97
zeroidc/vendor/time/src/format_description/parse.rs
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
//! Parse a format description into a standardized representation.
|
||||
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use crate::error::InvalidFormatDescription;
|
||||
use crate::format_description::component::{Component, NakedComponent};
|
||||
use crate::format_description::{helper, modifier, FormatItem};
|
||||
|
||||
/// The item parsed and remaining chunk of the format description after one iteration.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ParsedItem<'a> {
|
||||
/// The item that was parsed.
|
||||
pub(crate) item: FormatItem<'a>,
|
||||
/// What is left of the input string after the item was parsed.
|
||||
pub(crate) remaining: &'a [u8],
|
||||
}
|
||||
|
||||
/// Parse a component from the format description. Neither the leading nor trailing bracket should
|
||||
/// be present in the parameter.
|
||||
fn parse_component(mut s: &[u8], index: &mut usize) -> Result<Component, InvalidFormatDescription> {
|
||||
// Trim any whitespace between the opening bracket and the component name.
|
||||
s = helper::consume_whitespace(s, index);
|
||||
|
||||
// Everything before the first whitespace is the component name.
|
||||
let component_index = *index;
|
||||
let whitespace_loc = s
|
||||
.iter()
|
||||
.position(u8::is_ascii_whitespace)
|
||||
.unwrap_or(s.len());
|
||||
*index += whitespace_loc;
|
||||
let component_name = &s[..whitespace_loc];
|
||||
s = &s[whitespace_loc..];
|
||||
s = helper::consume_whitespace(s, index);
|
||||
|
||||
Ok(NakedComponent::parse(component_name, component_index)?
|
||||
.attach_modifiers(&modifier::Modifiers::parse(component_name, s, index)?))
|
||||
}
|
||||
|
||||
/// Parse a literal string from the format description.
|
||||
fn parse_literal<'a>(s: &'a [u8], index: &mut usize) -> ParsedItem<'a> {
|
||||
let loc = s.iter().position(|&c| c == b'[').unwrap_or(s.len());
|
||||
*index += loc;
|
||||
ParsedItem {
|
||||
item: FormatItem::Literal(&s[..loc]),
|
||||
remaining: &s[loc..],
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse either a literal or a component from the format description.
|
||||
fn parse_item<'a>(
|
||||
s: &'a [u8],
|
||||
index: &mut usize,
|
||||
) -> Result<ParsedItem<'a>, InvalidFormatDescription> {
|
||||
if let [b'[', b'[', remaining @ ..] = s {
|
||||
*index += 2;
|
||||
return Ok(ParsedItem {
|
||||
item: FormatItem::Literal(&[b'[']),
|
||||
remaining,
|
||||
});
|
||||
};
|
||||
|
||||
if s.starts_with(&[b'[']) {
|
||||
if let Some(bracket_index) = s.iter().position(|&c| c == b']') {
|
||||
*index += 1; // opening bracket
|
||||
let ret_val = ParsedItem {
|
||||
item: FormatItem::Component(parse_component(&s[1..bracket_index], index)?),
|
||||
remaining: &s[bracket_index + 1..],
|
||||
};
|
||||
*index += 1; // closing bracket
|
||||
Ok(ret_val)
|
||||
} else {
|
||||
Err(InvalidFormatDescription::UnclosedOpeningBracket { index: *index })
|
||||
}
|
||||
} else {
|
||||
Ok(parse_literal(s, index))
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a sequence of items from the format description.
|
||||
///
|
||||
/// The syntax for the format description can be found in [the
|
||||
/// book](https://time-rs.github.io/book/api/format-description.html).
|
||||
#[cfg_attr(__time_03_docs, doc(cfg(feature = "alloc")))]
|
||||
pub fn parse(s: &str) -> Result<Vec<FormatItem<'_>>, InvalidFormatDescription> {
|
||||
let mut compound = Vec::new();
|
||||
let mut loc = 0;
|
||||
|
||||
let mut s = s.as_bytes();
|
||||
|
||||
while !s.is_empty() {
|
||||
let ParsedItem { item, remaining } = parse_item(s, &mut loc)?;
|
||||
s = remaining;
|
||||
compound.push(item);
|
||||
}
|
||||
|
||||
Ok(compound)
|
||||
}
|
||||
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
|
||||
262
zeroidc/vendor/time/src/instant.rs
vendored
Normal file
262
zeroidc/vendor/time/src/instant.rs
vendored
Normal file
@@ -0,0 +1,262 @@
|
||||
//! The [`Instant`] struct and its associated `impl`s.
|
||||
|
||||
use core::cmp::{Ord, Ordering, PartialEq, PartialOrd};
|
||||
use core::convert::{TryFrom, TryInto};
|
||||
use core::ops::{Add, Sub};
|
||||
use core::time::Duration as StdDuration;
|
||||
use std::borrow::Borrow;
|
||||
use std::time::Instant as StdInstant;
|
||||
|
||||
use crate::Duration;
|
||||
|
||||
/// A measurement of a monotonically non-decreasing clock. Opaque and useful only with [`Duration`].
|
||||
///
|
||||
/// Instants are always guaranteed to be no less than any previously measured instant when created,
|
||||
/// and are often useful for tasks such as measuring benchmarks or timing how long an operation
|
||||
/// takes.
|
||||
///
|
||||
/// Note, however, that instants are not guaranteed to be **steady**. In other words, each tick of
|
||||
/// the underlying clock may not be the same length (e.g. some seconds may be longer than others).
|
||||
/// An instant may jump forwards or experience time dilation (slow down or speed up), but it will
|
||||
/// never go backwards.
|
||||
///
|
||||
/// Instants are opaque types that can only be compared to one another. There is no method to get
|
||||
/// "the number of seconds" from an instant. Instead, it only allows measuring the duration between
|
||||
/// two instants (or comparing two instants).
|
||||
///
|
||||
/// This implementation allows for operations with signed [`Duration`]s, but is otherwise identical
|
||||
/// to [`std::time::Instant`].
|
||||
#[cfg_attr(__time_03_docs, doc(cfg(feature = "std")))]
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Instant(pub StdInstant);
|
||||
|
||||
impl Instant {
|
||||
// region: delegation
|
||||
/// Returns an `Instant` corresponding to "now".
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::Instant;
|
||||
/// println!("{:?}", Instant::now());
|
||||
/// ```
|
||||
pub fn now() -> Self {
|
||||
Self(StdInstant::now())
|
||||
}
|
||||
|
||||
/// Returns the amount of time elapsed since this instant was created. The duration will always
|
||||
/// be nonnegative if the instant is not synthetically created.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{Instant, ext::{NumericalStdDuration, NumericalDuration}};
|
||||
/// # use std::thread;
|
||||
/// let instant = Instant::now();
|
||||
/// thread::sleep(1.std_milliseconds());
|
||||
/// assert!(instant.elapsed() >= 1.milliseconds());
|
||||
/// ```
|
||||
pub fn elapsed(self) -> Duration {
|
||||
Self::now() - self
|
||||
}
|
||||
// endregion delegation
|
||||
|
||||
// region: checked arithmetic
|
||||
/// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be represented as
|
||||
/// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
|
||||
/// otherwise.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{Instant, ext::NumericalDuration};
|
||||
/// let now = Instant::now();
|
||||
/// assert_eq!(now.checked_add(5.seconds()), Some(now + 5.seconds()));
|
||||
/// assert_eq!(now.checked_add((-5).seconds()), Some(now + (-5).seconds()));
|
||||
/// ```
|
||||
pub fn checked_add(self, duration: Duration) -> Option<Self> {
|
||||
if duration.is_zero() {
|
||||
Some(self)
|
||||
} else if duration.is_positive() {
|
||||
self.0.checked_add(duration.abs_std()).map(Self)
|
||||
} else {
|
||||
debug_assert!(duration.is_negative());
|
||||
self.0.checked_sub(duration.abs_std()).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be represented as
|
||||
/// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
|
||||
/// otherwise.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{Instant, ext::NumericalDuration};
|
||||
/// let now = Instant::now();
|
||||
/// assert_eq!(now.checked_sub(5.seconds()), Some(now - 5.seconds()));
|
||||
/// assert_eq!(now.checked_sub((-5).seconds()), Some(now - (-5).seconds()));
|
||||
/// ```
|
||||
pub fn checked_sub(self, duration: Duration) -> Option<Self> {
|
||||
if duration.is_zero() {
|
||||
Some(self)
|
||||
} else if duration.is_positive() {
|
||||
self.0.checked_sub(duration.abs_std()).map(Self)
|
||||
} else {
|
||||
debug_assert!(duration.is_negative());
|
||||
self.0.checked_add(duration.abs_std()).map(Self)
|
||||
}
|
||||
}
|
||||
// endregion checked arithmetic
|
||||
|
||||
/// Obtain the inner [`std::time::Instant`].
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::Instant;
|
||||
/// let now = Instant::now();
|
||||
/// assert_eq!(now.into_inner(), now.0);
|
||||
/// ```
|
||||
pub const fn into_inner(self) -> StdInstant {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
// region: trait impls
|
||||
impl From<StdInstant> for Instant {
|
||||
fn from(instant: StdInstant) -> Self {
|
||||
Self(instant)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Instant> for StdInstant {
|
||||
fn from(instant: Instant) -> Self {
|
||||
instant.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for Instant {
|
||||
type Output = Duration;
|
||||
|
||||
fn sub(self, other: Self) -> Self::Output {
|
||||
match self.0.cmp(&other.0) {
|
||||
Ordering::Equal => Duration::ZERO,
|
||||
Ordering::Greater => (self.0 - other.0)
|
||||
.try_into()
|
||||
.expect("overflow converting `std::time::Duration` to `time::Duration`"),
|
||||
Ordering::Less => -Duration::try_from(other.0 - self.0)
|
||||
.expect("overflow converting `std::time::Duration` to `time::Duration`"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<StdInstant> for Instant {
|
||||
type Output = Duration;
|
||||
|
||||
fn sub(self, other: StdInstant) -> Self::Output {
|
||||
self - Self(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<Instant> for StdInstant {
|
||||
type Output = Duration;
|
||||
|
||||
fn sub(self, other: Instant) -> Self::Output {
|
||||
Instant(self) - other
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Duration> for Instant {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, duration: Duration) -> Self::Output {
|
||||
if duration.is_positive() {
|
||||
Self(self.0 + duration.abs_std())
|
||||
} else if duration.is_negative() {
|
||||
Self(self.0 - duration.abs_std())
|
||||
} else {
|
||||
self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Duration> for StdInstant {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, duration: Duration) -> Self::Output {
|
||||
(Instant(self) + duration).0
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<StdDuration> for Instant {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, duration: StdDuration) -> Self::Output {
|
||||
Self(self.0 + duration)
|
||||
}
|
||||
}
|
||||
|
||||
impl_add_assign!(Instant: Duration, StdDuration);
|
||||
impl_add_assign!(StdInstant: Duration);
|
||||
|
||||
impl Sub<Duration> for Instant {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, duration: Duration) -> Self::Output {
|
||||
if duration.is_positive() {
|
||||
Self(self.0 - duration.abs_std())
|
||||
} else if duration.is_negative() {
|
||||
Self(self.0 + duration.abs_std())
|
||||
} else {
|
||||
self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<Duration> for StdInstant {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, duration: Duration) -> Self::Output {
|
||||
(Instant(self) - duration).0
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<StdDuration> for Instant {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, duration: StdDuration) -> Self::Output {
|
||||
Self(self.0 - duration)
|
||||
}
|
||||
}
|
||||
|
||||
impl_sub_assign!(Instant: Duration, StdDuration);
|
||||
impl_sub_assign!(StdInstant: Duration);
|
||||
|
||||
impl PartialEq<StdInstant> for Instant {
|
||||
fn eq(&self, rhs: &StdInstant) -> bool {
|
||||
self.0.eq(rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Instant> for StdInstant {
|
||||
fn eq(&self, rhs: &Instant) -> bool {
|
||||
self.eq(&rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<StdInstant> for Instant {
|
||||
fn partial_cmp(&self, rhs: &StdInstant) -> Option<Ordering> {
|
||||
self.0.partial_cmp(rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<Instant> for StdInstant {
|
||||
fn partial_cmp(&self, rhs: &Instant) -> Option<Ordering> {
|
||||
self.partial_cmp(&rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<StdInstant> for Instant {
|
||||
fn as_ref(&self) -> &StdInstant {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Borrow<StdInstant> for Instant {
|
||||
fn borrow(&self) -> &StdInstant {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
// endregion trait impls
|
||||
330
zeroidc/vendor/time/src/lib.rs
vendored
Normal file
330
zeroidc/vendor/time/src/lib.rs
vendored
Normal file
@@ -0,0 +1,330 @@
|
||||
//! # Feature flags
|
||||
//!
|
||||
//! This crate exposes a number of features. These can be enabled or disabled as shown
|
||||
//! [in Cargo's documentation](https://doc.rust-lang.org/cargo/reference/features.html). Features
|
||||
//! are _disabled_ by default unless otherwise noted.
|
||||
//!
|
||||
//! Reliance on a given feature is always indicated alongside the item definition.
|
||||
//!
|
||||
//! - `std` (_enabled by default, implicitly enables `alloc`_)
|
||||
//!
|
||||
//! This enables a number of features that depend on the standard library.
|
||||
//!
|
||||
//! - `alloc` (_enabled by default via `std`_)
|
||||
//!
|
||||
//! Enables a number of features that require the ability to dynamically allocate memory.
|
||||
//!
|
||||
//! - `macros`
|
||||
//!
|
||||
//! Enables macros that provide compile-time verification of values and intuitive syntax.
|
||||
//!
|
||||
//! - `formatting` (_implicitly enables `std`_)
|
||||
//!
|
||||
//! Enables formatting of most structs.
|
||||
//!
|
||||
//! - `parsing`
|
||||
//!
|
||||
//! Enables parsing of most structs.
|
||||
//!
|
||||
//! - `local-offset` (_implicitly enables `std`_)
|
||||
//!
|
||||
//! This feature enables a number of methods that allow obtaining the system's UTC offset.
|
||||
//!
|
||||
//! - `large-dates`
|
||||
//!
|
||||
//! By default, only years within the ±9999 range (inclusive) are supported. If you need support
|
||||
//! for years outside this range, consider enabling this feature; the supported range will be
|
||||
//! increased to ±999,999.
|
||||
//!
|
||||
//! Note that enabling this feature has some costs, as it means forgoing some optimizations.
|
||||
//! Ambiguities may be introduced when parsing that would not otherwise exist.
|
||||
//!
|
||||
//! If you are using this feature, **please leave a comment**
|
||||
//! [on this discussion](https://github.com/time-rs/time/discussions/306) with your use case. If
|
||||
//! there is not sufficient demand for this feature, it will be dropped in a future release.
|
||||
//!
|
||||
//! - `serde`
|
||||
//!
|
||||
//! Enables [serde](https://docs.rs/serde) support for all types except [`Instant`].
|
||||
//!
|
||||
//! - `serde-human-readable` (_implicitly enables `serde`, `formatting`, and `parsing`_)
|
||||
//!
|
||||
//! Allows serde representations to use a human-readable format. This is determined by the
|
||||
//! serializer, not the user. If this feature is not enabled or if the serializer requests a
|
||||
//! non-human-readable format, a format optimized for binary representation will be used.
|
||||
//!
|
||||
//! Libraries should never enable this feature, as the decision of what format to use should be up
|
||||
//! to the user.
|
||||
//!
|
||||
//! - `serde-well-known` (_implicitly enables `serde/alloc`, `formatting`, and `parsing`_)
|
||||
//!
|
||||
//! Enables support for serializing and deserializing well-known formats using serde's
|
||||
//! [`#[with]` attribute](https://serde.rs/field-attrs.html#with).
|
||||
//!
|
||||
//! - `rand`
|
||||
//!
|
||||
//! Enables [rand](https://docs.rs/rand) support for all types.
|
||||
//!
|
||||
//! - `quickcheck` (_implicitly enables `alloc`_)
|
||||
//!
|
||||
//! Enables [quickcheck](https://docs.rs/quickcheck) support for all types except [`Instant`].
|
||||
//!
|
||||
//! One pseudo-feature flag that is only available to end users is the `unsound_local_offset` cfg.
|
||||
//! As the name indicates, using the feature is unsound, and [may cause unexpected segmentation
|
||||
//! faults](https://github.com/time-rs/time/issues/293). Unlike other flags, this is deliberately
|
||||
//! only available to end users; this is to ensure that a user doesn't have unsound behavior without
|
||||
//! knowing it. To enable this behavior, you must use `RUSTFLAGS="--cfg unsound_local_offset" cargo
|
||||
//! build` or similar. Note: This flag is _not tested anywhere_, including in the regular test of
|
||||
//! the powerset of all feature flags. Use at your own risk. Without this flag, any method that
|
||||
//! requires the local offset will return the `Err` variant.
|
||||
|
||||
#![doc(html_playground_url = "https://play.rust-lang.org")]
|
||||
#![cfg_attr(__time_03_docs, feature(doc_cfg, doc_auto_cfg, doc_notable_trait))]
|
||||
#![cfg_attr(
|
||||
__time_03_docs,
|
||||
deny(rustdoc::broken_intra_doc_links, rustdoc::private_intra_doc_links)
|
||||
)]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![deny(
|
||||
anonymous_parameters,
|
||||
clippy::all,
|
||||
const_err,
|
||||
illegal_floating_point_literal_pattern,
|
||||
late_bound_lifetime_arguments,
|
||||
path_statements,
|
||||
patterns_in_fns_without_body,
|
||||
rust_2018_idioms,
|
||||
trivial_casts,
|
||||
trivial_numeric_casts,
|
||||
unreachable_pub,
|
||||
unsafe_code,
|
||||
unsafe_op_in_unsafe_fn,
|
||||
unused_extern_crates
|
||||
)]
|
||||
#![warn(
|
||||
clippy::dbg_macro,
|
||||
clippy::decimal_literal_representation,
|
||||
clippy::get_unwrap,
|
||||
clippy::missing_docs_in_private_items,
|
||||
clippy::nursery,
|
||||
clippy::print_stdout,
|
||||
clippy::todo,
|
||||
clippy::unimplemented,
|
||||
clippy::unnested_or_patterns,
|
||||
clippy::unwrap_in_result,
|
||||
clippy::unwrap_used,
|
||||
clippy::use_debug,
|
||||
deprecated_in_future,
|
||||
missing_copy_implementations,
|
||||
missing_debug_implementations,
|
||||
unused_qualifications,
|
||||
variant_size_differences
|
||||
)]
|
||||
#![allow(clippy::redundant_pub_crate)]
|
||||
#![doc(html_favicon_url = "https://avatars0.githubusercontent.com/u/55999857")]
|
||||
#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/55999857")]
|
||||
#![doc(test(attr(deny(warnings))))]
|
||||
|
||||
#[allow(unused_extern_crates)]
|
||||
#[cfg(feature = "alloc")]
|
||||
extern crate alloc;
|
||||
|
||||
// region: macros
|
||||
/// Helper macro for easily implementing `OpAssign`.
|
||||
macro_rules! __impl_assign {
|
||||
($sym:tt $op:ident $fn:ident $target:ty : $($(#[$attr:meta])* $t:ty),+) => {$(
|
||||
#[allow(unused_qualifications)]
|
||||
$(#[$attr])*
|
||||
impl core::ops::$op<$t> for $target {
|
||||
fn $fn(&mut self, rhs: $t) {
|
||||
*self = *self $sym rhs;
|
||||
}
|
||||
}
|
||||
)+};
|
||||
}
|
||||
|
||||
/// Implement `AddAssign` for the provided types.
|
||||
macro_rules! impl_add_assign {
|
||||
($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
|
||||
__impl_assign!(+ AddAssign add_assign $target : $($(#[$attr])* $t),+);
|
||||
};
|
||||
}
|
||||
|
||||
/// Implement `SubAssign` for the provided types.
|
||||
macro_rules! impl_sub_assign {
|
||||
($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
|
||||
__impl_assign!(- SubAssign sub_assign $target : $($(#[$attr])* $t),+);
|
||||
};
|
||||
}
|
||||
|
||||
/// Implement `MulAssign` for the provided types.
|
||||
macro_rules! impl_mul_assign {
|
||||
($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
|
||||
__impl_assign!(* MulAssign mul_assign $target : $($(#[$attr])* $t),+);
|
||||
};
|
||||
}
|
||||
|
||||
/// Implement `DivAssign` for the provided types.
|
||||
macro_rules! impl_div_assign {
|
||||
($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
|
||||
__impl_assign!(/ DivAssign div_assign $target : $($(#[$attr])* $t),+);
|
||||
};
|
||||
}
|
||||
|
||||
/// Division of integers, rounding the resulting value towards negative infinity.
|
||||
macro_rules! div_floor {
|
||||
($a:expr, $b:expr) => {{
|
||||
let _a = $a;
|
||||
let _b = $b;
|
||||
|
||||
let (_quotient, _remainder) = (_a / _b, _a % _b);
|
||||
|
||||
if (_remainder > 0 && _b < 0) || (_remainder < 0 && _b > 0) {
|
||||
_quotient - 1
|
||||
} else {
|
||||
_quotient
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
/// Cascade an out-of-bounds value.
|
||||
macro_rules! cascade {
|
||||
(@ordinal ordinal) => {};
|
||||
(@year year) => {};
|
||||
|
||||
// Cascade an out-of-bounds value from "from" to "to".
|
||||
($from:ident in $min:literal.. $max:literal => $to:tt) => {
|
||||
#[allow(unused_comparisons, unused_assignments)]
|
||||
if $from >= $max {
|
||||
$from -= $max - $min;
|
||||
$to += 1;
|
||||
} else if $from < $min {
|
||||
$from += $max - $min;
|
||||
$to -= 1;
|
||||
}
|
||||
};
|
||||
|
||||
// Special case the ordinal-to-year cascade, as it has different behavior.
|
||||
($ordinal:ident => $year:ident) => {
|
||||
// We need to actually capture the idents. Without this, macro hygiene causes errors.
|
||||
cascade!(@ordinal $ordinal);
|
||||
cascade!(@year $year);
|
||||
#[allow(unused_assignments)]
|
||||
if $ordinal > crate::util::days_in_year($year) {
|
||||
$year += 1;
|
||||
$ordinal = 1;
|
||||
} else if $ordinal == 0 {
|
||||
$year -= 1;
|
||||
$ordinal = crate::util::days_in_year($year);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns `Err(error::ComponentRange)` if the value is not in range.
|
||||
macro_rules! ensure_value_in_range {
|
||||
($value:ident in $start:expr => $end:expr) => {{
|
||||
let _start = $start;
|
||||
let _end = $end;
|
||||
#[allow(trivial_numeric_casts, unused_comparisons)]
|
||||
if $value < _start || $value > _end {
|
||||
return Err(crate::error::ComponentRange {
|
||||
name: stringify!($value),
|
||||
minimum: _start as _,
|
||||
maximum: _end as _,
|
||||
value: $value as _,
|
||||
conditional_range: false,
|
||||
});
|
||||
}
|
||||
}};
|
||||
|
||||
($value:ident conditionally in $start:expr => $end:expr) => {{
|
||||
let _start = $start;
|
||||
let _end = $end;
|
||||
#[allow(trivial_numeric_casts, unused_comparisons)]
|
||||
if $value < _start || $value > _end {
|
||||
return Err(crate::error::ComponentRange {
|
||||
name: stringify!($value),
|
||||
minimum: _start as _,
|
||||
maximum: _end as _,
|
||||
value: $value as _,
|
||||
conditional_range: true,
|
||||
});
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
/// Try to unwrap an expression, returning if not possible.
|
||||
///
|
||||
/// This is similar to the `?` operator, but does not perform `.into()`. Because of this, it is
|
||||
/// usable in `const` contexts.
|
||||
macro_rules! const_try {
|
||||
($e:expr) => {
|
||||
match $e {
|
||||
Ok(value) => value,
|
||||
Err(error) => return Err(error),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Try to unwrap an expression, returning if not possible.
|
||||
///
|
||||
/// This is similar to the `?` operator, but is usable in `const` contexts.
|
||||
macro_rules! const_try_opt {
|
||||
($e:expr) => {
|
||||
match $e {
|
||||
Some(value) => value,
|
||||
None => return None,
|
||||
}
|
||||
};
|
||||
}
|
||||
// endregion macros
|
||||
|
||||
mod date;
|
||||
mod duration;
|
||||
pub mod error;
|
||||
pub mod ext;
|
||||
#[cfg(any(feature = "formatting", feature = "parsing"))]
|
||||
pub mod format_description;
|
||||
#[cfg(feature = "formatting")]
|
||||
pub mod formatting;
|
||||
#[cfg(feature = "std")]
|
||||
mod instant;
|
||||
#[cfg(feature = "macros")]
|
||||
pub mod macros;
|
||||
mod month;
|
||||
mod offset_date_time;
|
||||
#[cfg(feature = "parsing")]
|
||||
pub mod parsing;
|
||||
mod primitive_date_time;
|
||||
#[cfg(feature = "quickcheck")]
|
||||
#[cfg_attr(__time_03_docs, doc(cfg(feature = "quickcheck")))]
|
||||
mod quickcheck;
|
||||
#[cfg(feature = "rand")]
|
||||
#[cfg_attr(__time_03_docs, doc(cfg(feature = "rand")))]
|
||||
mod rand;
|
||||
#[cfg(feature = "serde")]
|
||||
#[cfg_attr(__time_03_docs, doc(cfg(feature = "serde")))]
|
||||
#[allow(missing_copy_implementations, missing_debug_implementations)]
|
||||
pub mod serde;
|
||||
mod sys;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod time;
|
||||
mod utc_offset;
|
||||
pub mod util;
|
||||
mod weekday;
|
||||
|
||||
pub use crate::date::Date;
|
||||
pub use crate::duration::Duration;
|
||||
pub use crate::error::Error;
|
||||
#[cfg(feature = "std")]
|
||||
pub use crate::instant::Instant;
|
||||
pub use crate::month::Month;
|
||||
pub use crate::offset_date_time::OffsetDateTime;
|
||||
pub use crate::primitive_date_time::PrimitiveDateTime;
|
||||
pub use crate::time::Time;
|
||||
pub use crate::utc_offset::UtcOffset;
|
||||
pub use crate::weekday::Weekday;
|
||||
|
||||
/// An alias for [`std::result::Result`] with a generic error from the time crate.
|
||||
pub type Result<T> = core::result::Result<T, Error>;
|
||||
114
zeroidc/vendor/time/src/macros.rs
vendored
Normal file
114
zeroidc/vendor/time/src/macros.rs
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
//! Macros to construct statically known values.
|
||||
|
||||
/// Construct a [`Date`](crate::Date) with a statically known value.
|
||||
///
|
||||
/// The resulting expression can be used in `const` or `static` declarations.
|
||||
///
|
||||
/// Three formats are supported: year-week-weekday, year-ordinal, and year-month-day.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{Date, Weekday::*, Month, macros::date};
|
||||
/// assert_eq!(
|
||||
/// date!(2020 - W 01 - 3),
|
||||
/// Date::from_iso_week_date(2020, 1, Wednesday)?
|
||||
/// );
|
||||
/// assert_eq!(date!(2020 - 001), Date::from_ordinal_date(2020, 1)?);
|
||||
/// assert_eq!(
|
||||
/// date!(2020 - 01 - 01),
|
||||
/// Date::from_calendar_date(2020, Month::January, 1)?
|
||||
/// );
|
||||
/// # Ok::<_, time::Error>(())
|
||||
/// ```
|
||||
pub use time_macros::date;
|
||||
/// Construct a [`PrimitiveDateTime`] or [`OffsetDateTime`] with a statically known value.
|
||||
///
|
||||
/// The resulting expression can be used in `const` or `static` declarations.
|
||||
///
|
||||
/// The syntax accepted by this macro is the same as [`date!`] and [`time!`], with an optional
|
||||
/// [`offset!`], all space-separated. If an [`offset!`] is provided, the resulting value will
|
||||
/// be an [`OffsetDateTime`]; otherwise it will be a [`PrimitiveDateTime`].
|
||||
///
|
||||
/// [`OffsetDateTime`]: crate::OffsetDateTime
|
||||
/// [`PrimitiveDateTime`]: crate::PrimitiveDateTime
|
||||
pub use time_macros::datetime;
|
||||
/// Equivalent of performing [`format_description::parse()`] at compile time.
|
||||
///
|
||||
/// Using the macro instead of the function results in a static slice rather than a [`Vec`],
|
||||
/// such that it can be used in `#![no_alloc]` situations.
|
||||
///
|
||||
/// The resulting expression can be used in `const` or `static` declarations, and implements
|
||||
/// the sealed traits required for both formatting and parsing.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{format_description, macros::format_description};
|
||||
/// assert_eq!(
|
||||
/// format_description!("[hour]:[minute]:[second]"),
|
||||
/// format_description::parse("[hour]:[minute]:[second]")?
|
||||
/// );
|
||||
/// # Ok::<_, time::Error>(())
|
||||
/// ```
|
||||
///
|
||||
/// The syntax accepted by this macro is the same as [`format_description::parse()`], which can
|
||||
/// be found in [the book](https://time-rs.github.io/book/api/format-description.html).
|
||||
///
|
||||
/// [`format_description::parse()`]: crate::format_description::parse()
|
||||
#[cfg(any(feature = "formatting", feature = "parsing"))]
|
||||
pub use time_macros::format_description;
|
||||
/// Construct a [`UtcOffset`](crate::UtcOffset) with a statically known value.
|
||||
///
|
||||
/// The resulting expression can be used in `const` or `static` declarations.
|
||||
///
|
||||
/// A sign and the hour must be provided; minutes and seconds default to zero. `UTC` (both
|
||||
/// uppercase and lowercase) is also allowed.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{UtcOffset, macros::offset};
|
||||
/// assert_eq!(offset!(UTC), UtcOffset::from_hms(0, 0, 0)?);
|
||||
/// assert_eq!(offset!(utc), UtcOffset::from_hms(0, 0, 0)?);
|
||||
/// assert_eq!(offset!(+0), UtcOffset::from_hms(0, 0, 0)?);
|
||||
/// assert_eq!(offset!(+1), UtcOffset::from_hms(1, 0, 0)?);
|
||||
/// assert_eq!(offset!(-1), UtcOffset::from_hms(-1, 0, 0)?);
|
||||
/// assert_eq!(offset!(+1:30), UtcOffset::from_hms(1, 30, 0)?);
|
||||
/// assert_eq!(offset!(-1:30), UtcOffset::from_hms(-1, -30, 0)?);
|
||||
/// assert_eq!(offset!(+1:30:59), UtcOffset::from_hms(1, 30, 59)?);
|
||||
/// assert_eq!(offset!(-1:30:59), UtcOffset::from_hms(-1, -30, -59)?);
|
||||
/// assert_eq!(offset!(+23:59:59), UtcOffset::from_hms(23, 59, 59)?);
|
||||
/// assert_eq!(offset!(-23:59:59), UtcOffset::from_hms(-23, -59, -59)?);
|
||||
/// # Ok::<_, time::Error>(())
|
||||
/// ```
|
||||
pub use time_macros::offset;
|
||||
/// Construct a [`Time`](crate::Time) with a statically known value.
|
||||
///
|
||||
/// The resulting expression can be used in `const` or `static` declarations.
|
||||
///
|
||||
/// Hours and minutes must be provided, while seconds defaults to zero. AM/PM is allowed
|
||||
/// (either uppercase or lowercase). Any number of subsecond digits may be provided (though any
|
||||
/// past nine will be discarded).
|
||||
///
|
||||
/// All components are validated at compile-time. An error will be raised if any value is
|
||||
/// invalid.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{Time, macros::time};
|
||||
/// assert_eq!(time!(0:00), Time::from_hms(0, 0, 0)?);
|
||||
/// assert_eq!(time!(1:02:03), Time::from_hms(1, 2, 3)?);
|
||||
/// assert_eq!(
|
||||
/// time!(1:02:03.004_005_006),
|
||||
/// Time::from_hms_nano(1, 2, 3, 4_005_006)?
|
||||
/// );
|
||||
/// assert_eq!(time!(12:00 am), Time::from_hms(0, 0, 0)?);
|
||||
/// assert_eq!(time!(1:02:03 am), Time::from_hms(1, 2, 3)?);
|
||||
/// assert_eq!(
|
||||
/// time!(1:02:03.004_005_006 am),
|
||||
/// Time::from_hms_nano(1, 2, 3, 4_005_006)?
|
||||
/// );
|
||||
/// assert_eq!(time!(12 pm), Time::from_hms(12, 0, 0)?);
|
||||
/// assert_eq!(time!(12:00 pm), Time::from_hms(12, 0, 0)?);
|
||||
/// assert_eq!(time!(1:02:03 pm), Time::from_hms(13, 2, 3)?);
|
||||
/// assert_eq!(
|
||||
/// time!(1:02:03.004_005_006 pm),
|
||||
/// Time::from_hms_nano(13, 2, 3, 4_005_006)?
|
||||
/// );
|
||||
/// # Ok::<_, time::Error>(())
|
||||
/// ```
|
||||
pub use time_macros::time;
|
||||
165
zeroidc/vendor/time/src/month.rs
vendored
Normal file
165
zeroidc/vendor/time/src/month.rs
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
//! The `Month` enum and its associated `impl`s.
|
||||
|
||||
use core::convert::TryFrom;
|
||||
use core::fmt;
|
||||
use core::num::NonZeroU8;
|
||||
use core::str::FromStr;
|
||||
|
||||
use self::Month::*;
|
||||
use crate::error;
|
||||
|
||||
/// Months of the year.
|
||||
#[allow(clippy::missing_docs_in_private_items)] // variants
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum Month {
|
||||
January = 1,
|
||||
February = 2,
|
||||
March = 3,
|
||||
April = 4,
|
||||
May = 5,
|
||||
June = 6,
|
||||
July = 7,
|
||||
August = 8,
|
||||
September = 9,
|
||||
October = 10,
|
||||
November = 11,
|
||||
December = 12,
|
||||
}
|
||||
|
||||
impl Month {
|
||||
/// Create a `Month` from its numerical value.
|
||||
pub(crate) const fn from_number(n: NonZeroU8) -> Result<Self, error::ComponentRange> {
|
||||
match n.get() {
|
||||
1 => Ok(January),
|
||||
2 => Ok(February),
|
||||
3 => Ok(March),
|
||||
4 => Ok(April),
|
||||
5 => Ok(May),
|
||||
6 => Ok(June),
|
||||
7 => Ok(July),
|
||||
8 => Ok(August),
|
||||
9 => Ok(September),
|
||||
10 => Ok(October),
|
||||
11 => Ok(November),
|
||||
12 => Ok(December),
|
||||
n => Err(error::ComponentRange {
|
||||
name: "month",
|
||||
minimum: 1,
|
||||
maximum: 12,
|
||||
value: n as _,
|
||||
conditional_range: false,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the previous month.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::Month;
|
||||
/// assert_eq!(Month::January.previous(), Month::December);
|
||||
/// ```
|
||||
pub const fn previous(self) -> Self {
|
||||
match self {
|
||||
January => December,
|
||||
February => January,
|
||||
March => February,
|
||||
April => March,
|
||||
May => April,
|
||||
June => May,
|
||||
July => June,
|
||||
August => July,
|
||||
September => August,
|
||||
October => September,
|
||||
November => October,
|
||||
December => November,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the next month.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::Month;
|
||||
/// assert_eq!(Month::January.next(), Month::February);
|
||||
/// ```
|
||||
pub const fn next(self) -> Self {
|
||||
match self {
|
||||
January => February,
|
||||
February => March,
|
||||
March => April,
|
||||
April => May,
|
||||
May => June,
|
||||
June => July,
|
||||
July => August,
|
||||
August => September,
|
||||
September => October,
|
||||
October => November,
|
||||
November => December,
|
||||
December => January,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Month {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(match self {
|
||||
January => "January",
|
||||
February => "February",
|
||||
March => "March",
|
||||
April => "April",
|
||||
May => "May",
|
||||
June => "June",
|
||||
July => "July",
|
||||
August => "August",
|
||||
September => "September",
|
||||
October => "October",
|
||||
November => "November",
|
||||
December => "December",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Month {
|
||||
type Err = error::InvalidVariant;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"January" => Ok(January),
|
||||
"February" => Ok(February),
|
||||
"March" => Ok(March),
|
||||
"April" => Ok(April),
|
||||
"May" => Ok(May),
|
||||
"June" => Ok(June),
|
||||
"July" => Ok(July),
|
||||
"August" => Ok(August),
|
||||
"September" => Ok(September),
|
||||
"October" => Ok(October),
|
||||
"November" => Ok(November),
|
||||
"December" => Ok(December),
|
||||
_ => Err(error::InvalidVariant),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Month> for u8 {
|
||||
fn from(month: Month) -> Self {
|
||||
month as _
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for Month {
|
||||
type Error = error::ComponentRange;
|
||||
|
||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||
match NonZeroU8::new(value) {
|
||||
Some(value) => Self::from_number(value),
|
||||
None => Err(error::ComponentRange {
|
||||
name: "month",
|
||||
minimum: 1,
|
||||
maximum: 12,
|
||||
value: 0,
|
||||
conditional_range: false,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
1321
zeroidc/vendor/time/src/offset_date_time.rs
vendored
Normal file
1321
zeroidc/vendor/time/src/offset_date_time.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
192
zeroidc/vendor/time/src/parsing/combinator/mod.rs
vendored
Normal file
192
zeroidc/vendor/time/src/parsing/combinator/mod.rs
vendored
Normal file
@@ -0,0 +1,192 @@
|
||||
//! Implementations of the low-level parser combinators.
|
||||
|
||||
pub(crate) mod rfc;
|
||||
|
||||
use crate::format_description::modifier::Padding;
|
||||
use crate::parsing::shim::{Integer, IntegerParseBytes};
|
||||
use crate::parsing::ParsedItem;
|
||||
|
||||
/// Parse a "+" or "-" sign. Returns the ASCII byte representing the sign, if present.
|
||||
pub(crate) const fn sign(input: &[u8]) -> Option<ParsedItem<'_, u8>> {
|
||||
match input {
|
||||
[sign @ (b'-' | b'+'), remaining @ ..] => Some(ParsedItem(remaining, *sign)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Consume the first matching item, returning its associated value.
|
||||
pub(crate) fn first_match<'a, T>(
|
||||
options: impl IntoIterator<Item = (&'a [u8], T)>,
|
||||
case_sensitive: bool,
|
||||
) -> impl FnMut(&'a [u8]) -> Option<ParsedItem<'a, T>> {
|
||||
let mut options = options.into_iter();
|
||||
move |input| {
|
||||
options.find_map(|(expected, t)| {
|
||||
if case_sensitive {
|
||||
Some(ParsedItem(input.strip_prefix(expected)?, t))
|
||||
} else {
|
||||
let n = expected.len();
|
||||
if n <= input.len() {
|
||||
let (head, tail) = input.split_at(n);
|
||||
if head.eq_ignore_ascii_case(expected) {
|
||||
return Some(ParsedItem(tail, t));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Consume zero or more instances of the provided parser. The parser must return the unit value.
|
||||
pub(crate) fn zero_or_more<'a, P: Fn(&'a [u8]) -> Option<ParsedItem<'a, ()>>>(
|
||||
parser: P,
|
||||
) -> impl FnMut(&'a [u8]) -> ParsedItem<'a, ()> {
|
||||
move |mut input| {
|
||||
while let Some(remaining) = parser(input) {
|
||||
input = remaining.into_inner();
|
||||
}
|
||||
ParsedItem(input, ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Consume one of or more instances of the provided parser. The parser must produce the unit value.
|
||||
pub(crate) fn one_or_more<'a, P: Fn(&'a [u8]) -> Option<ParsedItem<'a, ()>>>(
|
||||
parser: P,
|
||||
) -> impl Fn(&'a [u8]) -> Option<ParsedItem<'a, ()>> {
|
||||
move |mut input| {
|
||||
input = parser(input)?.into_inner();
|
||||
while let Some(remaining) = parser(input) {
|
||||
input = remaining.into_inner();
|
||||
}
|
||||
Some(ParsedItem(input, ()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Consume between `n` and `m` instances of the provided parser.
|
||||
pub(crate) fn n_to_m<
|
||||
'a,
|
||||
T,
|
||||
P: Fn(&'a [u8]) -> Option<ParsedItem<'a, T>>,
|
||||
const N: u8,
|
||||
const M: u8,
|
||||
>(
|
||||
parser: P,
|
||||
) -> impl Fn(&'a [u8]) -> Option<ParsedItem<'a, &'a [u8]>> {
|
||||
debug_assert!(M >= N);
|
||||
move |mut input| {
|
||||
// We need to keep this to determine the total length eventually consumed.
|
||||
let orig_input = input;
|
||||
|
||||
// Mandatory
|
||||
for _ in 0..N {
|
||||
input = parser(input)?.0;
|
||||
}
|
||||
|
||||
// Optional
|
||||
for _ in N..M {
|
||||
match parser(input) {
|
||||
Some(parsed) => input = parsed.0,
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
|
||||
Some(ParsedItem(
|
||||
input,
|
||||
&orig_input[..(orig_input.len() - input.len())],
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Consume between `n` and `m` digits, returning the numerical value.
|
||||
pub(crate) fn n_to_m_digits<T: Integer, const N: u8, const M: u8>(
|
||||
input: &[u8],
|
||||
) -> Option<ParsedItem<'_, T>> {
|
||||
debug_assert!(M >= N);
|
||||
n_to_m::<_, _, N, M>(any_digit)(input)?.flat_map(|value| value.parse_bytes())
|
||||
}
|
||||
|
||||
/// Consume exactly `n` digits, returning the numerical value.
|
||||
pub(crate) fn exactly_n_digits<T: Integer, const N: u8>(input: &[u8]) -> Option<ParsedItem<'_, T>> {
|
||||
n_to_m_digits::<_, N, N>(input)
|
||||
}
|
||||
|
||||
/// Consume exactly `n` digits, returning the numerical value.
|
||||
pub(crate) fn exactly_n_digits_padded<'a, T: Integer, const N: u8>(
|
||||
padding: Padding,
|
||||
) -> impl Fn(&'a [u8]) -> Option<ParsedItem<'a, T>> {
|
||||
n_to_m_digits_padded::<_, N, N>(padding)
|
||||
}
|
||||
|
||||
/// Consume between `n` and `m` digits, returning the numerical value.
|
||||
pub(crate) fn n_to_m_digits_padded<'a, T: Integer, const N: u8, const M: u8>(
|
||||
padding: Padding,
|
||||
) -> impl Fn(&'a [u8]) -> Option<ParsedItem<'a, T>> {
|
||||
debug_assert!(M >= N);
|
||||
move |mut input| match padding {
|
||||
Padding::None => n_to_m_digits::<_, 1, M>(input),
|
||||
Padding::Space => {
|
||||
debug_assert!(N > 0);
|
||||
|
||||
let mut orig_input = input;
|
||||
for _ in 0..(N - 1) {
|
||||
match ascii_char::<b' '>(input) {
|
||||
Some(parsed) => input = parsed.0,
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
let pad_width = (orig_input.len() - input.len()) as u8;
|
||||
|
||||
orig_input = input;
|
||||
for _ in 0..(N - pad_width) {
|
||||
input = any_digit(input)?.0;
|
||||
}
|
||||
for _ in N..M {
|
||||
match any_digit(input) {
|
||||
Some(parsed) => input = parsed.0,
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
|
||||
ParsedItem(input, &orig_input[..(orig_input.len() - input.len())])
|
||||
.flat_map(|value| value.parse_bytes())
|
||||
}
|
||||
Padding::Zero => n_to_m_digits::<_, N, M>(input),
|
||||
}
|
||||
}
|
||||
|
||||
/// Consume exactly one digit.
|
||||
pub(crate) const fn any_digit(input: &[u8]) -> Option<ParsedItem<'_, u8>> {
|
||||
match input {
|
||||
[c, remaining @ ..] if c.is_ascii_digit() => Some(ParsedItem(remaining, *c)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Consume exactly one of the provided ASCII characters.
|
||||
pub(crate) fn ascii_char<const CHAR: u8>(input: &[u8]) -> Option<ParsedItem<'_, ()>> {
|
||||
debug_assert!(CHAR.is_ascii_graphic() || CHAR.is_ascii_whitespace());
|
||||
match input {
|
||||
[c, remaining @ ..] if *c == CHAR => Some(ParsedItem(remaining, ())),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Consume exactly one of the provided ASCII characters, case-insensitive.
|
||||
pub(crate) fn ascii_char_ignore_case<const CHAR: u8>(input: &[u8]) -> Option<ParsedItem<'_, ()>> {
|
||||
debug_assert!(CHAR.is_ascii_graphic() || CHAR.is_ascii_whitespace());
|
||||
match input {
|
||||
[c, remaining @ ..] if c.eq_ignore_ascii_case(&CHAR) => Some(ParsedItem(remaining, ())),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Optionally consume an input with a given parser.
|
||||
pub(crate) fn opt<'a, T>(
|
||||
parser: impl Fn(&'a [u8]) -> Option<ParsedItem<'a, T>>,
|
||||
) -> impl Fn(&'a [u8]) -> ParsedItem<'a, Option<T>> {
|
||||
move |input| match parser(input) {
|
||||
Some(value) => value.map(Some),
|
||||
None => ParsedItem(input, None),
|
||||
}
|
||||
}
|
||||
8
zeroidc/vendor/time/src/parsing/combinator/rfc/mod.rs
vendored
Normal file
8
zeroidc/vendor/time/src/parsing/combinator/rfc/mod.rs
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
//! Combinators for rules as defined in an RFC.
|
||||
//!
|
||||
//! These rules have been converted strictly following the ABNF syntax as specified in [RFC 2234].
|
||||
//!
|
||||
//! [RFC 2234]: https://datatracker.ietf.org/doc/html/rfc2234
|
||||
|
||||
pub(crate) mod rfc2234;
|
||||
pub(crate) mod rfc2822;
|
||||
13
zeroidc/vendor/time/src/parsing/combinator/rfc/rfc2234.rs
vendored
Normal file
13
zeroidc/vendor/time/src/parsing/combinator/rfc/rfc2234.rs
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
//! Rules defined in [RFC 2234].
|
||||
//!
|
||||
//! [RFC 2234]: https://datatracker.ietf.org/doc/html/rfc2234
|
||||
|
||||
use crate::parsing::ParsedItem;
|
||||
|
||||
/// Consume exactly one space or tab.
|
||||
pub(crate) const fn wsp(input: &[u8]) -> Option<ParsedItem<'_, ()>> {
|
||||
match input {
|
||||
[b' ' | b'\t', rest @ ..] => Some(ParsedItem(rest, ())),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
115
zeroidc/vendor/time/src/parsing/combinator/rfc/rfc2822.rs
vendored
Normal file
115
zeroidc/vendor/time/src/parsing/combinator/rfc/rfc2822.rs
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
//! Rules defined in [RFC 2822].
|
||||
//!
|
||||
//! [RFC 2822]: https://datatracker.ietf.org/doc/html/rfc2822
|
||||
|
||||
use crate::parsing::combinator::rfc::rfc2234::wsp;
|
||||
use crate::parsing::combinator::{ascii_char, one_or_more, zero_or_more};
|
||||
use crate::parsing::ParsedItem;
|
||||
|
||||
/// Consume the `fws` rule.
|
||||
// The full rule is equivalent to /\r\n[ \t]+|[ \t]+(?:\r\n[ \t]+)*/
|
||||
pub(crate) fn fws(mut input: &[u8]) -> Option<ParsedItem<'_, ()>> {
|
||||
if let [b'\r', b'\n', rest @ ..] = input {
|
||||
one_or_more(wsp)(rest)
|
||||
} else {
|
||||
input = one_or_more(wsp)(input)?.into_inner();
|
||||
while let [b'\r', b'\n', rest @ ..] = input {
|
||||
input = one_or_more(wsp)(rest)?.into_inner();
|
||||
}
|
||||
Some(ParsedItem(input, ()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Consume the `cfws` rule.
|
||||
// The full rule is equivalent to any combination of `fws` and `comment` so long as it is not empty.
|
||||
pub(crate) fn cfws(input: &[u8]) -> Option<ParsedItem<'_, ()>> {
|
||||
one_or_more(|input| fws(input).or_else(|| comment(input)))(input)
|
||||
}
|
||||
|
||||
/// Consume the `comment` rule.
|
||||
fn comment(mut input: &[u8]) -> Option<ParsedItem<'_, ()>> {
|
||||
input = ascii_char::<b'('>(input)?.into_inner();
|
||||
input = zero_or_more(fws)(input).into_inner();
|
||||
while let Some(rest) = ccontent(input) {
|
||||
input = rest.into_inner();
|
||||
input = zero_or_more(fws)(input).into_inner();
|
||||
}
|
||||
input = ascii_char::<b')'>(input)?.into_inner();
|
||||
|
||||
Some(ParsedItem(input, ()))
|
||||
}
|
||||
|
||||
/// Consume the `ccontent` rule.
|
||||
fn ccontent(input: &[u8]) -> Option<ParsedItem<'_, ()>> {
|
||||
ctext(input)
|
||||
.or_else(|| quoted_pair(input))
|
||||
.or_else(|| comment(input))
|
||||
}
|
||||
|
||||
/// Consume the `ctext` rule.
|
||||
#[allow(clippy::unnecessary_lazy_evaluations)] // rust-lang/rust-clippy#8522
|
||||
fn ctext(input: &[u8]) -> Option<ParsedItem<'_, ()>> {
|
||||
no_ws_ctl(input).or_else(|| match input {
|
||||
[33..=39 | 42..=91 | 93..=126, rest @ ..] => Some(ParsedItem(rest, ())),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Consume the `quoted_pair` rule.
|
||||
fn quoted_pair(mut input: &[u8]) -> Option<ParsedItem<'_, ()>> {
|
||||
input = ascii_char::<b'\\'>(input)?.into_inner();
|
||||
|
||||
let old_input_len = input.len();
|
||||
|
||||
input = text(input).into_inner();
|
||||
|
||||
// If nothing is parsed, this means we hit the `obs-text` rule and nothing matched. This is
|
||||
// technically a success, but we should still check the `obs-qp` rule to ensure we consume
|
||||
// everything possible.
|
||||
if input.len() == old_input_len {
|
||||
match input {
|
||||
[0..=127, rest @ ..] => Some(ParsedItem(rest, ())),
|
||||
_ => Some(ParsedItem(input, ())),
|
||||
}
|
||||
} else {
|
||||
Some(ParsedItem(input, ()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Consume the `no_ws_ctl` rule.
|
||||
const fn no_ws_ctl(input: &[u8]) -> Option<ParsedItem<'_, ()>> {
|
||||
match input {
|
||||
[1..=8 | 11..=12 | 14..=31 | 127, rest @ ..] => Some(ParsedItem(rest, ())),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Consume the `text` rule.
|
||||
fn text<'a>(input: &'a [u8]) -> ParsedItem<'a, ()> {
|
||||
let new_text = |input: &'a [u8]| match input {
|
||||
[1..=9 | 11..=12 | 14..=127, rest @ ..] => Some(ParsedItem(rest, ())),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let obs_char = |input: &'a [u8]| match input {
|
||||
// This is technically allowed, but consuming this would mean the rest of the string is
|
||||
// eagerly consumed without consideration for where the comment actually ends.
|
||||
[b')', ..] => None,
|
||||
[0..=9 | 11..=12 | 14..=127, rest @ ..] => Some(rest),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let obs_text = |mut input| {
|
||||
input = zero_or_more(ascii_char::<b'\n'>)(input).into_inner();
|
||||
input = zero_or_more(ascii_char::<b'\r'>)(input).into_inner();
|
||||
while let Some(rest) = obs_char(input) {
|
||||
input = rest;
|
||||
input = zero_or_more(ascii_char::<b'\n'>)(input).into_inner();
|
||||
input = zero_or_more(ascii_char::<b'\r'>)(input).into_inner();
|
||||
}
|
||||
|
||||
ParsedItem(input, ())
|
||||
};
|
||||
|
||||
new_text(input).unwrap_or_else(|| obs_text(input))
|
||||
}
|
||||
290
zeroidc/vendor/time/src/parsing/component.rs
vendored
Normal file
290
zeroidc/vendor/time/src/parsing/component.rs
vendored
Normal file
@@ -0,0 +1,290 @@
|
||||
//! Parsing implementations for all [`Component`](crate::format_description::Component)s.
|
||||
|
||||
use core::num::{NonZeroU16, NonZeroU8};
|
||||
|
||||
use crate::format_description::modifier;
|
||||
#[cfg(feature = "large-dates")]
|
||||
use crate::parsing::combinator::n_to_m_digits_padded;
|
||||
use crate::parsing::combinator::{
|
||||
any_digit, exactly_n_digits, exactly_n_digits_padded, first_match, opt, sign,
|
||||
};
|
||||
use crate::parsing::ParsedItem;
|
||||
use crate::{Month, Weekday};
|
||||
|
||||
// region: date components
|
||||
/// Parse the "year" component of a `Date`.
|
||||
pub(crate) fn parse_year(input: &[u8], modifiers: modifier::Year) -> Option<ParsedItem<'_, i32>> {
|
||||
match modifiers.repr {
|
||||
modifier::YearRepr::Full => {
|
||||
let ParsedItem(input, sign) = opt(sign)(input);
|
||||
#[cfg(not(feature = "large-dates"))]
|
||||
let ParsedItem(input, year) =
|
||||
exactly_n_digits_padded::<u32, 4>(modifiers.padding)(input)?;
|
||||
#[cfg(feature = "large-dates")]
|
||||
let ParsedItem(input, year) =
|
||||
n_to_m_digits_padded::<u32, 4, 6>(modifiers.padding)(input)?;
|
||||
match sign {
|
||||
Some(b'-') => Some(ParsedItem(input, -(year as i32))),
|
||||
None if modifiers.sign_is_mandatory || year >= 10_000 => None,
|
||||
_ => Some(ParsedItem(input, year as i32)),
|
||||
}
|
||||
}
|
||||
modifier::YearRepr::LastTwo => {
|
||||
Some(exactly_n_digits_padded::<u32, 2>(modifiers.padding)(input)?.map(|v| v as i32))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse the "month" component of a `Date`.
|
||||
pub(crate) fn parse_month(
|
||||
input: &[u8],
|
||||
modifiers: modifier::Month,
|
||||
) -> Option<ParsedItem<'_, Month>> {
|
||||
use Month::*;
|
||||
let ParsedItem(remaining, value) = first_match(
|
||||
match modifiers.repr {
|
||||
modifier::MonthRepr::Numerical => {
|
||||
return exactly_n_digits_padded::<_, 2>(modifiers.padding)(input)?
|
||||
.flat_map(|n| Month::from_number(n).ok());
|
||||
}
|
||||
modifier::MonthRepr::Long => [
|
||||
(&b"January"[..], January),
|
||||
(&b"February"[..], February),
|
||||
(&b"March"[..], March),
|
||||
(&b"April"[..], April),
|
||||
(&b"May"[..], May),
|
||||
(&b"June"[..], June),
|
||||
(&b"July"[..], July),
|
||||
(&b"August"[..], August),
|
||||
(&b"September"[..], September),
|
||||
(&b"October"[..], October),
|
||||
(&b"November"[..], November),
|
||||
(&b"December"[..], December),
|
||||
],
|
||||
modifier::MonthRepr::Short => [
|
||||
(&b"Jan"[..], January),
|
||||
(&b"Feb"[..], February),
|
||||
(&b"Mar"[..], March),
|
||||
(&b"Apr"[..], April),
|
||||
(&b"May"[..], May),
|
||||
(&b"Jun"[..], June),
|
||||
(&b"Jul"[..], July),
|
||||
(&b"Aug"[..], August),
|
||||
(&b"Sep"[..], September),
|
||||
(&b"Oct"[..], October),
|
||||
(&b"Nov"[..], November),
|
||||
(&b"Dec"[..], December),
|
||||
],
|
||||
},
|
||||
modifiers.case_sensitive,
|
||||
)(input)?;
|
||||
Some(ParsedItem(remaining, value))
|
||||
}
|
||||
|
||||
/// Parse the "week number" component of a `Date`.
|
||||
pub(crate) fn parse_week_number(
|
||||
input: &[u8],
|
||||
modifiers: modifier::WeekNumber,
|
||||
) -> Option<ParsedItem<'_, u8>> {
|
||||
exactly_n_digits_padded::<_, 2>(modifiers.padding)(input)
|
||||
}
|
||||
|
||||
/// Parse the "weekday" component of a `Date`.
|
||||
pub(crate) fn parse_weekday(
|
||||
input: &[u8],
|
||||
modifiers: modifier::Weekday,
|
||||
) -> Option<ParsedItem<'_, Weekday>> {
|
||||
first_match(
|
||||
match (modifiers.repr, modifiers.one_indexed) {
|
||||
(modifier::WeekdayRepr::Short, _) => [
|
||||
(&b"Mon"[..], Weekday::Monday),
|
||||
(&b"Tue"[..], Weekday::Tuesday),
|
||||
(&b"Wed"[..], Weekday::Wednesday),
|
||||
(&b"Thu"[..], Weekday::Thursday),
|
||||
(&b"Fri"[..], Weekday::Friday),
|
||||
(&b"Sat"[..], Weekday::Saturday),
|
||||
(&b"Sun"[..], Weekday::Sunday),
|
||||
],
|
||||
(modifier::WeekdayRepr::Long, _) => [
|
||||
(&b"Monday"[..], Weekday::Monday),
|
||||
(&b"Tuesday"[..], Weekday::Tuesday),
|
||||
(&b"Wednesday"[..], Weekday::Wednesday),
|
||||
(&b"Thursday"[..], Weekday::Thursday),
|
||||
(&b"Friday"[..], Weekday::Friday),
|
||||
(&b"Saturday"[..], Weekday::Saturday),
|
||||
(&b"Sunday"[..], Weekday::Sunday),
|
||||
],
|
||||
(modifier::WeekdayRepr::Sunday, false) => [
|
||||
(&b"1"[..], Weekday::Monday),
|
||||
(&b"2"[..], Weekday::Tuesday),
|
||||
(&b"3"[..], Weekday::Wednesday),
|
||||
(&b"4"[..], Weekday::Thursday),
|
||||
(&b"5"[..], Weekday::Friday),
|
||||
(&b"6"[..], Weekday::Saturday),
|
||||
(&b"0"[..], Weekday::Sunday),
|
||||
],
|
||||
(modifier::WeekdayRepr::Sunday, true) => [
|
||||
(&b"2"[..], Weekday::Monday),
|
||||
(&b"3"[..], Weekday::Tuesday),
|
||||
(&b"4"[..], Weekday::Wednesday),
|
||||
(&b"5"[..], Weekday::Thursday),
|
||||
(&b"6"[..], Weekday::Friday),
|
||||
(&b"7"[..], Weekday::Saturday),
|
||||
(&b"1"[..], Weekday::Sunday),
|
||||
],
|
||||
(modifier::WeekdayRepr::Monday, false) => [
|
||||
(&b"0"[..], Weekday::Monday),
|
||||
(&b"1"[..], Weekday::Tuesday),
|
||||
(&b"2"[..], Weekday::Wednesday),
|
||||
(&b"3"[..], Weekday::Thursday),
|
||||
(&b"4"[..], Weekday::Friday),
|
||||
(&b"5"[..], Weekday::Saturday),
|
||||
(&b"6"[..], Weekday::Sunday),
|
||||
],
|
||||
(modifier::WeekdayRepr::Monday, true) => [
|
||||
(&b"1"[..], Weekday::Monday),
|
||||
(&b"2"[..], Weekday::Tuesday),
|
||||
(&b"3"[..], Weekday::Wednesday),
|
||||
(&b"4"[..], Weekday::Thursday),
|
||||
(&b"5"[..], Weekday::Friday),
|
||||
(&b"6"[..], Weekday::Saturday),
|
||||
(&b"7"[..], Weekday::Sunday),
|
||||
],
|
||||
},
|
||||
modifiers.case_sensitive,
|
||||
)(input)
|
||||
}
|
||||
|
||||
/// Parse the "ordinal" component of a `Date`.
|
||||
pub(crate) fn parse_ordinal(
|
||||
input: &[u8],
|
||||
modifiers: modifier::Ordinal,
|
||||
) -> Option<ParsedItem<'_, NonZeroU16>> {
|
||||
exactly_n_digits_padded::<_, 3>(modifiers.padding)(input)
|
||||
}
|
||||
|
||||
/// Parse the "day" component of a `Date`.
|
||||
pub(crate) fn parse_day(
|
||||
input: &[u8],
|
||||
modifiers: modifier::Day,
|
||||
) -> Option<ParsedItem<'_, NonZeroU8>> {
|
||||
exactly_n_digits_padded::<_, 2>(modifiers.padding)(input)
|
||||
}
|
||||
// endregion date components
|
||||
|
||||
// region: time components
|
||||
/// Indicate whether the hour is "am" or "pm".
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum Period {
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
Am,
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
Pm,
|
||||
}
|
||||
|
||||
/// Parse the "hour" component of a `Time`.
|
||||
pub(crate) fn parse_hour(input: &[u8], modifiers: modifier::Hour) -> Option<ParsedItem<'_, u8>> {
|
||||
exactly_n_digits_padded::<_, 2>(modifiers.padding)(input)
|
||||
}
|
||||
|
||||
/// Parse the "minute" component of a `Time`.
|
||||
pub(crate) fn parse_minute(
|
||||
input: &[u8],
|
||||
modifiers: modifier::Minute,
|
||||
) -> Option<ParsedItem<'_, u8>> {
|
||||
exactly_n_digits_padded::<_, 2>(modifiers.padding)(input)
|
||||
}
|
||||
|
||||
/// Parse the "second" component of a `Time`.
|
||||
pub(crate) fn parse_second(
|
||||
input: &[u8],
|
||||
modifiers: modifier::Second,
|
||||
) -> Option<ParsedItem<'_, u8>> {
|
||||
exactly_n_digits_padded::<_, 2>(modifiers.padding)(input)
|
||||
}
|
||||
|
||||
/// Parse the "period" component of a `Time`. Required if the hour is on a 12-hour clock.
|
||||
pub(crate) fn parse_period(
|
||||
input: &[u8],
|
||||
modifiers: modifier::Period,
|
||||
) -> Option<ParsedItem<'_, Period>> {
|
||||
first_match(
|
||||
if modifiers.is_uppercase {
|
||||
[(&b"AM"[..], Period::Am), (&b"PM"[..], Period::Pm)]
|
||||
} else {
|
||||
[(&b"am"[..], Period::Am), (&b"pm"[..], Period::Pm)]
|
||||
},
|
||||
modifiers.case_sensitive,
|
||||
)(input)
|
||||
}
|
||||
|
||||
/// Parse the "subsecond" component of a `Time`.
|
||||
pub(crate) fn parse_subsecond(
|
||||
input: &[u8],
|
||||
modifiers: modifier::Subsecond,
|
||||
) -> Option<ParsedItem<'_, u32>> {
|
||||
use modifier::SubsecondDigits::*;
|
||||
Some(match modifiers.digits {
|
||||
One => exactly_n_digits::<u32, 1>(input)?.map(|v| v * 100_000_000),
|
||||
Two => exactly_n_digits::<u32, 2>(input)?.map(|v| v * 10_000_000),
|
||||
Three => exactly_n_digits::<u32, 3>(input)?.map(|v| v * 1_000_000),
|
||||
Four => exactly_n_digits::<u32, 4>(input)?.map(|v| v * 100_000),
|
||||
Five => exactly_n_digits::<u32, 5>(input)?.map(|v| v * 10_000),
|
||||
Six => exactly_n_digits::<u32, 6>(input)?.map(|v| v * 1_000),
|
||||
Seven => exactly_n_digits::<u32, 7>(input)?.map(|v| v * 100),
|
||||
Eight => exactly_n_digits::<u32, 8>(input)?.map(|v| v * 10),
|
||||
Nine => exactly_n_digits::<u32, 9>(input)?,
|
||||
OneOrMore => {
|
||||
let ParsedItem(mut input, mut value) =
|
||||
any_digit(input)?.map(|v| (v - b'0') as u32 * 100_000_000);
|
||||
|
||||
let mut multiplier = 10_000_000;
|
||||
while let Some(ParsedItem(new_input, digit)) = any_digit(input) {
|
||||
value += (digit - b'0') as u32 * multiplier;
|
||||
input = new_input;
|
||||
multiplier /= 10;
|
||||
}
|
||||
|
||||
ParsedItem(input, value)
|
||||
}
|
||||
})
|
||||
}
|
||||
// endregion time components
|
||||
|
||||
// region: offset components
|
||||
/// Parse the "hour" component of a `UtcOffset`.
|
||||
pub(crate) fn parse_offset_hour(
|
||||
input: &[u8],
|
||||
modifiers: modifier::OffsetHour,
|
||||
) -> Option<ParsedItem<'_, i8>> {
|
||||
let ParsedItem(input, sign) = opt(sign)(input);
|
||||
let ParsedItem(input, hour) = exactly_n_digits_padded::<u8, 2>(modifiers.padding)(input)?;
|
||||
match sign {
|
||||
Some(b'-') => Some(ParsedItem(input, -(hour as i8))),
|
||||
None if modifiers.sign_is_mandatory => None,
|
||||
_ => Some(ParsedItem(input, hour as i8)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse the "minute" component of a `UtcOffset`.
|
||||
pub(crate) fn parse_offset_minute(
|
||||
input: &[u8],
|
||||
modifiers: modifier::OffsetMinute,
|
||||
) -> Option<ParsedItem<'_, i8>> {
|
||||
Some(
|
||||
exactly_n_digits_padded::<u8, 2>(modifiers.padding)(input)?
|
||||
.map(|offset_minute| offset_minute as _),
|
||||
)
|
||||
}
|
||||
|
||||
/// Parse the "second" component of a `UtcOffset`.
|
||||
pub(crate) fn parse_offset_second(
|
||||
input: &[u8],
|
||||
modifiers: modifier::OffsetSecond,
|
||||
) -> Option<ParsedItem<'_, i8>> {
|
||||
Some(
|
||||
exactly_n_digits_padded::<u8, 2>(modifiers.padding)(input)?
|
||||
.map(|offset_second| offset_second as _),
|
||||
)
|
||||
}
|
||||
// endregion offset components
|
||||
49
zeroidc/vendor/time/src/parsing/mod.rs
vendored
Normal file
49
zeroidc/vendor/time/src/parsing/mod.rs
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
//! Parsing for various types.
|
||||
|
||||
pub(crate) mod combinator;
|
||||
pub(crate) mod component;
|
||||
pub(crate) mod parsable;
|
||||
mod parsed;
|
||||
pub(crate) mod shim;
|
||||
|
||||
pub use self::parsable::Parsable;
|
||||
pub use self::parsed::Parsed;
|
||||
|
||||
/// An item that has been parsed. Represented as a `(remaining, value)` pair.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ParsedItem<'a, T>(pub(crate) &'a [u8], pub(crate) T);
|
||||
|
||||
impl<'a, T> ParsedItem<'a, T> {
|
||||
/// Map the value to a new value, preserving the remaining input.
|
||||
pub(crate) fn map<U>(self, f: impl FnOnce(T) -> U) -> ParsedItem<'a, U> {
|
||||
ParsedItem(self.0, f(self.1))
|
||||
}
|
||||
|
||||
/// Map the value to a new, optional value, preserving the remaining input.
|
||||
pub(crate) fn flat_map<U>(self, f: impl FnOnce(T) -> Option<U>) -> Option<ParsedItem<'a, U>> {
|
||||
Some(ParsedItem(self.0, f(self.1)?))
|
||||
}
|
||||
|
||||
/// Consume the stored value with the provided function. The remaining input is returned.
|
||||
#[must_use = "this returns the remaining input"]
|
||||
pub(crate) fn consume_value(self, f: impl FnOnce(T) -> Option<()>) -> Option<&'a [u8]> {
|
||||
f(self.1)?;
|
||||
Some(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ParsedItem<'a, ()> {
|
||||
/// Discard the unit value, returning the remaining input.
|
||||
#[must_use = "this returns the remaining input"]
|
||||
pub(crate) const fn into_inner(self) -> &'a [u8] {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ParsedItem<'a, Option<()>> {
|
||||
/// Discard the potential unit value, returning the remaining input.
|
||||
#[must_use = "this returns the remaining input"]
|
||||
pub(crate) const fn into_inner(self) -> &'a [u8] {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
492
zeroidc/vendor/time/src/parsing/parsable.rs
vendored
Normal file
492
zeroidc/vendor/time/src/parsing/parsable.rs
vendored
Normal file
@@ -0,0 +1,492 @@
|
||||
//! A trait that can be used to parse an item from an input.
|
||||
|
||||
use core::convert::TryInto;
|
||||
use core::ops::Deref;
|
||||
|
||||
use crate::error::TryFromParsed;
|
||||
use crate::format_description::well_known::{Rfc2822, Rfc3339};
|
||||
use crate::format_description::FormatItem;
|
||||
use crate::parsing::{Parsed, ParsedItem};
|
||||
use crate::{error, Date, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset, Weekday};
|
||||
|
||||
/// A type that can be parsed.
|
||||
#[cfg_attr(__time_03_docs, doc(notable_trait))]
|
||||
pub trait Parsable: sealed::Sealed {}
|
||||
impl Parsable for FormatItem<'_> {}
|
||||
impl Parsable for [FormatItem<'_>] {}
|
||||
impl Parsable for Rfc2822 {}
|
||||
impl Parsable for Rfc3339 {}
|
||||
impl<T: Deref> Parsable for T where T::Target: Parsable {}
|
||||
|
||||
/// Seal the trait to prevent downstream users from implementing it, while still allowing it to
|
||||
/// exist in generic bounds.
|
||||
mod sealed {
|
||||
|
||||
#[allow(clippy::wildcard_imports)]
|
||||
use super::*;
|
||||
|
||||
/// Parse the item using a format description and an input.
|
||||
#[cfg_attr(__time_03_docs, doc(cfg(feature = "parsing")))]
|
||||
pub trait Sealed {
|
||||
/// Parse the item into the provided [`Parsed`] struct.
|
||||
///
|
||||
/// This method can be used to parse a single component without parsing the full value.
|
||||
fn parse_into<'a>(
|
||||
&self,
|
||||
input: &'a [u8],
|
||||
parsed: &mut Parsed,
|
||||
) -> Result<&'a [u8], error::Parse>;
|
||||
|
||||
/// Parse the item into a new [`Parsed`] struct.
|
||||
///
|
||||
/// This method can only be used to parse a complete value of a type. If any characters
|
||||
/// remain after parsing, an error will be returned.
|
||||
fn parse(&self, input: &[u8]) -> Result<Parsed, error::Parse> {
|
||||
let mut parsed = Parsed::new();
|
||||
if self.parse_into(input, &mut parsed)?.is_empty() {
|
||||
Ok(parsed)
|
||||
} else {
|
||||
Err(error::Parse::UnexpectedTrailingCharacters)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a [`Date`] from the format description.
|
||||
fn parse_date(&self, input: &[u8]) -> Result<Date, error::Parse> {
|
||||
Ok(self.parse(input)?.try_into()?)
|
||||
}
|
||||
|
||||
/// Parse a [`Time`] from the format description.
|
||||
fn parse_time(&self, input: &[u8]) -> Result<Time, error::Parse> {
|
||||
Ok(self.parse(input)?.try_into()?)
|
||||
}
|
||||
|
||||
/// Parse a [`UtcOffset`] from the format description.
|
||||
fn parse_offset(&self, input: &[u8]) -> Result<UtcOffset, error::Parse> {
|
||||
Ok(self.parse(input)?.try_into()?)
|
||||
}
|
||||
|
||||
/// Parse a [`PrimitiveDateTime`] from the format description.
|
||||
fn parse_date_time(&self, input: &[u8]) -> Result<PrimitiveDateTime, error::Parse> {
|
||||
Ok(self.parse(input)?.try_into()?)
|
||||
}
|
||||
|
||||
/// Parse a [`OffsetDateTime`] from the format description.
|
||||
fn parse_offset_date_time(&self, input: &[u8]) -> Result<OffsetDateTime, error::Parse> {
|
||||
Ok(self.parse(input)?.try_into()?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// region: custom formats
|
||||
impl sealed::Sealed for FormatItem<'_> {
|
||||
fn parse_into<'a>(
|
||||
&self,
|
||||
input: &'a [u8],
|
||||
parsed: &mut Parsed,
|
||||
) -> Result<&'a [u8], error::Parse> {
|
||||
Ok(parsed.parse_item(input, self)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl sealed::Sealed for [FormatItem<'_>] {
|
||||
fn parse_into<'a>(
|
||||
&self,
|
||||
input: &'a [u8],
|
||||
parsed: &mut Parsed,
|
||||
) -> Result<&'a [u8], error::Parse> {
|
||||
Ok(parsed.parse_items(input, self)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Deref> sealed::Sealed for T
|
||||
where
|
||||
T::Target: sealed::Sealed,
|
||||
{
|
||||
fn parse_into<'a>(
|
||||
&self,
|
||||
input: &'a [u8],
|
||||
parsed: &mut Parsed,
|
||||
) -> Result<&'a [u8], error::Parse> {
|
||||
self.deref().parse_into(input, parsed)
|
||||
}
|
||||
}
|
||||
// endregion custom formats
|
||||
|
||||
// region: well-known formats
|
||||
impl sealed::Sealed for Rfc2822 {
|
||||
fn parse_into<'a>(
|
||||
&self,
|
||||
input: &'a [u8],
|
||||
parsed: &mut Parsed,
|
||||
) -> Result<&'a [u8], error::Parse> {
|
||||
use crate::error::ParseFromDescription::{InvalidComponent, InvalidLiteral};
|
||||
use crate::parsing::combinator::rfc::rfc2822::{cfws, fws};
|
||||
use crate::parsing::combinator::{
|
||||
ascii_char, exactly_n_digits, first_match, n_to_m_digits, opt, sign,
|
||||
};
|
||||
|
||||
let colon = ascii_char::<b':'>;
|
||||
let comma = ascii_char::<b','>;
|
||||
|
||||
let input = opt(fws)(input).into_inner();
|
||||
let input = first_match(
|
||||
[
|
||||
(&b"Mon"[..], Weekday::Monday),
|
||||
(&b"Tue"[..], Weekday::Tuesday),
|
||||
(&b"Wed"[..], Weekday::Wednesday),
|
||||
(&b"Thu"[..], Weekday::Thursday),
|
||||
(&b"Fri"[..], Weekday::Friday),
|
||||
(&b"Sat"[..], Weekday::Saturday),
|
||||
(&b"Sun"[..], Weekday::Sunday),
|
||||
],
|
||||
false,
|
||||
)(input)
|
||||
.and_then(|item| item.consume_value(|value| parsed.set_weekday(value)))
|
||||
.ok_or(InvalidComponent("weekday"))?;
|
||||
let input = comma(input).ok_or(InvalidLiteral)?.into_inner();
|
||||
let input = cfws(input).ok_or(InvalidLiteral)?.into_inner();
|
||||
let input = n_to_m_digits::<_, 1, 2>(input)
|
||||
.and_then(|item| item.consume_value(|value| parsed.set_day(value)))
|
||||
.ok_or(InvalidComponent("day"))?;
|
||||
let input = cfws(input).ok_or(InvalidLiteral)?.into_inner();
|
||||
let input = first_match(
|
||||
[
|
||||
(&b"Jan"[..], Month::January),
|
||||
(&b"Feb"[..], Month::February),
|
||||
(&b"Mar"[..], Month::March),
|
||||
(&b"Apr"[..], Month::April),
|
||||
(&b"May"[..], Month::May),
|
||||
(&b"Jun"[..], Month::June),
|
||||
(&b"Jul"[..], Month::July),
|
||||
(&b"Aug"[..], Month::August),
|
||||
(&b"Sep"[..], Month::September),
|
||||
(&b"Oct"[..], Month::October),
|
||||
(&b"Nov"[..], Month::November),
|
||||
(&b"Dec"[..], Month::December),
|
||||
],
|
||||
false,
|
||||
)(input)
|
||||
.and_then(|item| item.consume_value(|value| parsed.set_month(value)))
|
||||
.ok_or(InvalidComponent("month"))?;
|
||||
let input = cfws(input).ok_or(InvalidLiteral)?.into_inner();
|
||||
let input = match exactly_n_digits::<u32, 4>(input) {
|
||||
Some(item) => {
|
||||
let input = item
|
||||
.flat_map(|year| if year >= 1900 { Some(year) } else { None })
|
||||
.and_then(|item| item.consume_value(|value| parsed.set_year(value as _)))
|
||||
.ok_or(InvalidComponent("year"))?;
|
||||
let input = fws(input).ok_or(InvalidLiteral)?.into_inner();
|
||||
input
|
||||
}
|
||||
None => {
|
||||
let input = exactly_n_digits::<u32, 2>(input)
|
||||
.and_then(|item| {
|
||||
item.map(|year| if year < 50 { year + 2000 } else { year + 1900 })
|
||||
.map(|year| year as _)
|
||||
.consume_value(|value| parsed.set_year(value))
|
||||
})
|
||||
.ok_or(InvalidComponent("year"))?;
|
||||
let input = cfws(input).ok_or(InvalidLiteral)?.into_inner();
|
||||
input
|
||||
}
|
||||
};
|
||||
|
||||
let input = exactly_n_digits::<_, 2>(input)
|
||||
.and_then(|item| item.consume_value(|value| parsed.set_hour_24(value)))
|
||||
.ok_or(InvalidComponent("hour"))?;
|
||||
let input = opt(cfws)(input).into_inner();
|
||||
let input = colon(input).ok_or(InvalidLiteral)?.into_inner();
|
||||
let input = opt(cfws)(input).into_inner();
|
||||
let input = exactly_n_digits::<_, 2>(input)
|
||||
.and_then(|item| item.consume_value(|value| parsed.set_minute(value)))
|
||||
.ok_or(InvalidComponent("minute"))?;
|
||||
|
||||
let input = if let Some(input) = colon(opt(cfws)(input).into_inner()) {
|
||||
let input = input.into_inner(); // discard the colon
|
||||
let input = opt(cfws)(input).into_inner();
|
||||
let input = exactly_n_digits::<_, 2>(input)
|
||||
.and_then(|item| item.consume_value(|value| parsed.set_second(value)))
|
||||
.ok_or(InvalidComponent("second"))?;
|
||||
let input = cfws(input).ok_or(InvalidLiteral)?.into_inner();
|
||||
input
|
||||
} else {
|
||||
cfws(input).ok_or(InvalidLiteral)?.into_inner()
|
||||
};
|
||||
|
||||
// The RFC explicitly allows leap seconds.
|
||||
parsed.set_leap_second_allowed(true);
|
||||
|
||||
#[allow(clippy::unnecessary_lazy_evaluations)] // rust-lang/rust-clippy#8522
|
||||
let zone_literal = first_match(
|
||||
[
|
||||
(&b"UT"[..], 0),
|
||||
(&b"GMT"[..], 0),
|
||||
(&b"EST"[..], -5),
|
||||
(&b"EDT"[..], -4),
|
||||
(&b"CST"[..], -6),
|
||||
(&b"CDT"[..], -5),
|
||||
(&b"MST"[..], -7),
|
||||
(&b"MDT"[..], -6),
|
||||
(&b"PST"[..], -8),
|
||||
(&b"PDT"[..], -7),
|
||||
],
|
||||
false,
|
||||
)(input)
|
||||
.or_else(|| match input {
|
||||
[
|
||||
b'a'..=b'i' | b'k'..=b'z' | b'A'..=b'I' | b'K'..=b'Z',
|
||||
rest @ ..,
|
||||
] => Some(ParsedItem(rest, 0)),
|
||||
_ => None,
|
||||
});
|
||||
if let Some(zone_literal) = zone_literal {
|
||||
let input = zone_literal
|
||||
.consume_value(|value| parsed.set_offset_hour(value))
|
||||
.ok_or(InvalidComponent("offset hour"))?;
|
||||
parsed
|
||||
.set_offset_minute_signed(0)
|
||||
.ok_or(InvalidComponent("offset minute"))?;
|
||||
parsed
|
||||
.set_offset_second_signed(0)
|
||||
.ok_or(InvalidComponent("offset second"))?;
|
||||
return Ok(input);
|
||||
}
|
||||
|
||||
let ParsedItem(input, offset_sign) = sign(input).ok_or(InvalidComponent("offset hour"))?;
|
||||
let input = exactly_n_digits::<u8, 2>(input)
|
||||
.and_then(|item| {
|
||||
item.map(|offset_hour| {
|
||||
if offset_sign == b'-' {
|
||||
-(offset_hour as i8)
|
||||
} else {
|
||||
offset_hour as _
|
||||
}
|
||||
})
|
||||
.consume_value(|value| parsed.set_offset_hour(value))
|
||||
})
|
||||
.ok_or(InvalidComponent("offset hour"))?;
|
||||
let input = exactly_n_digits::<u8, 2>(input)
|
||||
.and_then(|item| {
|
||||
item.consume_value(|value| parsed.set_offset_minute_signed(value as _))
|
||||
})
|
||||
.ok_or(InvalidComponent("offset minute"))?;
|
||||
|
||||
Ok(input)
|
||||
}
|
||||
}
|
||||
|
||||
impl sealed::Sealed for Rfc3339 {
|
||||
fn parse_into<'a>(
|
||||
&self,
|
||||
input: &'a [u8],
|
||||
parsed: &mut Parsed,
|
||||
) -> Result<&'a [u8], error::Parse> {
|
||||
use crate::error::ParseFromDescription::{InvalidComponent, InvalidLiteral};
|
||||
use crate::parsing::combinator::{
|
||||
any_digit, ascii_char, ascii_char_ignore_case, exactly_n_digits, sign,
|
||||
};
|
||||
|
||||
let dash = ascii_char::<b'-'>;
|
||||
let colon = ascii_char::<b':'>;
|
||||
|
||||
let input = exactly_n_digits::<u32, 4>(input)
|
||||
.and_then(|item| item.consume_value(|value| parsed.set_year(value as _)))
|
||||
.ok_or(InvalidComponent("year"))?;
|
||||
let input = dash(input).ok_or(InvalidLiteral)?.into_inner();
|
||||
let input = exactly_n_digits::<_, 2>(input)
|
||||
.and_then(|item| item.flat_map(|value| Month::from_number(value).ok()))
|
||||
.and_then(|item| item.consume_value(|value| parsed.set_month(value)))
|
||||
.ok_or(InvalidComponent("month"))?;
|
||||
let input = dash(input).ok_or(InvalidLiteral)?.into_inner();
|
||||
let input = exactly_n_digits::<_, 2>(input)
|
||||
.and_then(|item| item.consume_value(|value| parsed.set_day(value)))
|
||||
.ok_or(InvalidComponent("day"))?;
|
||||
let input = ascii_char_ignore_case::<b'T'>(input)
|
||||
.ok_or(InvalidLiteral)?
|
||||
.into_inner();
|
||||
let input = exactly_n_digits::<_, 2>(input)
|
||||
.and_then(|item| item.consume_value(|value| parsed.set_hour_24(value)))
|
||||
.ok_or(InvalidComponent("hour"))?;
|
||||
let input = colon(input).ok_or(InvalidLiteral)?.into_inner();
|
||||
let input = exactly_n_digits::<_, 2>(input)
|
||||
.and_then(|item| item.consume_value(|value| parsed.set_minute(value)))
|
||||
.ok_or(InvalidComponent("minute"))?;
|
||||
let input = colon(input).ok_or(InvalidLiteral)?.into_inner();
|
||||
let input = exactly_n_digits::<_, 2>(input)
|
||||
.and_then(|item| item.consume_value(|value| parsed.set_second(value)))
|
||||
.ok_or(InvalidComponent("second"))?;
|
||||
let input = if let Some(ParsedItem(input, ())) = ascii_char::<b'.'>(input) {
|
||||
let ParsedItem(mut input, mut value) = any_digit(input)
|
||||
.ok_or(InvalidComponent("subsecond"))?
|
||||
.map(|v| (v - b'0') as u32 * 100_000_000);
|
||||
|
||||
let mut multiplier = 10_000_000;
|
||||
while let Some(ParsedItem(new_input, digit)) = any_digit(input) {
|
||||
value += (digit - b'0') as u32 * multiplier;
|
||||
input = new_input;
|
||||
multiplier /= 10;
|
||||
}
|
||||
|
||||
parsed
|
||||
.set_subsecond(value)
|
||||
.ok_or(InvalidComponent("subsecond"))?;
|
||||
input
|
||||
} else {
|
||||
input
|
||||
};
|
||||
|
||||
// The RFC explicitly allows leap seconds.
|
||||
parsed.set_leap_second_allowed(true);
|
||||
|
||||
if let Some(ParsedItem(input, ())) = ascii_char_ignore_case::<b'Z'>(input) {
|
||||
parsed
|
||||
.set_offset_hour(0)
|
||||
.ok_or(InvalidComponent("offset hour"))?;
|
||||
parsed
|
||||
.set_offset_minute_signed(0)
|
||||
.ok_or(InvalidComponent("offset minute"))?;
|
||||
parsed
|
||||
.set_offset_second_signed(0)
|
||||
.ok_or(InvalidComponent("offset second"))?;
|
||||
return Ok(input);
|
||||
}
|
||||
|
||||
let ParsedItem(input, offset_sign) = sign(input).ok_or(InvalidComponent("offset hour"))?;
|
||||
let input = exactly_n_digits::<u8, 2>(input)
|
||||
.and_then(|item| {
|
||||
item.map(|offset_hour| {
|
||||
if offset_sign == b'-' {
|
||||
-(offset_hour as i8)
|
||||
} else {
|
||||
offset_hour as _
|
||||
}
|
||||
})
|
||||
.consume_value(|value| parsed.set_offset_hour(value))
|
||||
})
|
||||
.ok_or(InvalidComponent("offset hour"))?;
|
||||
let input = colon(input).ok_or(InvalidLiteral)?.into_inner();
|
||||
let input = exactly_n_digits::<u8, 2>(input)
|
||||
.and_then(|item| {
|
||||
item.consume_value(|value| parsed.set_offset_minute_signed(value as _))
|
||||
})
|
||||
.ok_or(InvalidComponent("offset minute"))?;
|
||||
|
||||
Ok(input)
|
||||
}
|
||||
|
||||
fn parse_offset_date_time(&self, input: &[u8]) -> Result<OffsetDateTime, error::Parse> {
|
||||
use crate::error::ParseFromDescription::{InvalidComponent, InvalidLiteral};
|
||||
use crate::parsing::combinator::{
|
||||
any_digit, ascii_char, ascii_char_ignore_case, exactly_n_digits, sign,
|
||||
};
|
||||
|
||||
let dash = ascii_char::<b'-'>;
|
||||
let colon = ascii_char::<b':'>;
|
||||
|
||||
let ParsedItem(input, year) =
|
||||
exactly_n_digits::<u32, 4>(input).ok_or(InvalidComponent("year"))?;
|
||||
let input = dash(input).ok_or(InvalidLiteral)?.into_inner();
|
||||
let ParsedItem(input, month) =
|
||||
exactly_n_digits::<_, 2>(input).ok_or(InvalidComponent("month"))?;
|
||||
let input = dash(input).ok_or(InvalidLiteral)?.into_inner();
|
||||
let ParsedItem(input, day) =
|
||||
exactly_n_digits::<_, 2>(input).ok_or(InvalidComponent("day"))?;
|
||||
let input = ascii_char_ignore_case::<b'T'>(input)
|
||||
.ok_or(InvalidLiteral)?
|
||||
.into_inner();
|
||||
let ParsedItem(input, hour) =
|
||||
exactly_n_digits::<_, 2>(input).ok_or(InvalidComponent("hour"))?;
|
||||
let input = colon(input).ok_or(InvalidLiteral)?.into_inner();
|
||||
let ParsedItem(input, minute) =
|
||||
exactly_n_digits::<_, 2>(input).ok_or(InvalidComponent("minute"))?;
|
||||
let input = colon(input).ok_or(InvalidLiteral)?.into_inner();
|
||||
let ParsedItem(input, mut second) =
|
||||
exactly_n_digits::<_, 2>(input).ok_or(InvalidComponent("second"))?;
|
||||
let ParsedItem(input, mut nanosecond) =
|
||||
if let Some(ParsedItem(input, ())) = ascii_char::<b'.'>(input) {
|
||||
let ParsedItem(mut input, mut value) = any_digit(input)
|
||||
.ok_or(InvalidComponent("subsecond"))?
|
||||
.map(|v| (v - b'0') as u32 * 100_000_000);
|
||||
|
||||
let mut multiplier = 10_000_000;
|
||||
while let Some(ParsedItem(new_input, digit)) = any_digit(input) {
|
||||
value += (digit - b'0') as u32 * multiplier;
|
||||
input = new_input;
|
||||
multiplier /= 10;
|
||||
}
|
||||
|
||||
ParsedItem(input, value)
|
||||
} else {
|
||||
ParsedItem(input, 0)
|
||||
};
|
||||
let ParsedItem(input, offset) = {
|
||||
if let Some(ParsedItem(input, ())) = ascii_char_ignore_case::<b'Z'>(input) {
|
||||
ParsedItem(input, UtcOffset::UTC)
|
||||
} else {
|
||||
let ParsedItem(input, offset_sign) =
|
||||
sign(input).ok_or(InvalidComponent("offset hour"))?;
|
||||
let ParsedItem(input, offset_hour) =
|
||||
exactly_n_digits::<u8, 2>(input).ok_or(InvalidComponent("offset hour"))?;
|
||||
let input = colon(input).ok_or(InvalidLiteral)?.into_inner();
|
||||
let ParsedItem(input, offset_minute) =
|
||||
exactly_n_digits::<u8, 2>(input).ok_or(InvalidComponent("offset minute"))?;
|
||||
UtcOffset::from_hms(
|
||||
if offset_sign == b'-' {
|
||||
-(offset_hour as i8)
|
||||
} else {
|
||||
offset_hour as _
|
||||
},
|
||||
offset_minute as _,
|
||||
0,
|
||||
)
|
||||
.map(|offset| ParsedItem(input, offset))
|
||||
.map_err(|mut err| {
|
||||
// Provide the user a more accurate error.
|
||||
if err.name == "hours" {
|
||||
err.name = "offset hour";
|
||||
} else if err.name == "minutes" {
|
||||
err.name = "offset minute";
|
||||
}
|
||||
err
|
||||
})
|
||||
.map_err(TryFromParsed::ComponentRange)?
|
||||
}
|
||||
};
|
||||
|
||||
if !input.is_empty() {
|
||||
return Err(error::Parse::UnexpectedTrailingCharacters);
|
||||
}
|
||||
|
||||
// The RFC explicitly permits leap seconds. We don't currently support them, so treat it as
|
||||
// the preceding nanosecond. However, leap seconds can only occur as the last second of the
|
||||
// month UTC.
|
||||
let leap_second_input = if second == 60 {
|
||||
second = 59;
|
||||
nanosecond = 999_999_999;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let dt = Month::from_number(month)
|
||||
.and_then(|month| Date::from_calendar_date(year as _, month, day))
|
||||
.and_then(|date| date.with_hms_nano(hour, minute, second, nanosecond))
|
||||
.map(|date| date.assume_offset(offset))
|
||||
.map_err(TryFromParsed::ComponentRange)?;
|
||||
|
||||
if leap_second_input && !dt.is_valid_leap_second_stand_in() {
|
||||
return Err(error::Parse::TryFromParsed(TryFromParsed::ComponentRange(
|
||||
error::ComponentRange {
|
||||
name: "second",
|
||||
minimum: 0,
|
||||
maximum: 59,
|
||||
value: 60,
|
||||
conditional_range: true,
|
||||
},
|
||||
)));
|
||||
}
|
||||
|
||||
Ok(dt)
|
||||
}
|
||||
}
|
||||
// endregion well-known formats
|
||||
625
zeroidc/vendor/time/src/parsing/parsed.rs
vendored
Normal file
625
zeroidc/vendor/time/src/parsing/parsed.rs
vendored
Normal file
@@ -0,0 +1,625 @@
|
||||
//! Information parsed from an input and format description.
|
||||
|
||||
use core::convert::{TryFrom, TryInto};
|
||||
use core::num::{NonZeroU16, NonZeroU8};
|
||||
|
||||
use crate::error::TryFromParsed::InsufficientInformation;
|
||||
use crate::format_description::modifier::{WeekNumberRepr, YearRepr};
|
||||
use crate::format_description::{Component, FormatItem};
|
||||
use crate::parsing::component::{
|
||||
parse_day, parse_hour, parse_minute, parse_month, parse_offset_hour, parse_offset_minute,
|
||||
parse_offset_second, parse_ordinal, parse_period, parse_second, parse_subsecond,
|
||||
parse_week_number, parse_weekday, parse_year, Period,
|
||||
};
|
||||
use crate::parsing::ParsedItem;
|
||||
use crate::{error, Date, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset, Weekday};
|
||||
|
||||
/// All information parsed.
|
||||
///
|
||||
/// This information is directly used to construct the final values.
|
||||
///
|
||||
/// Most users will not need think about this struct in any way. It is public to allow for manual
|
||||
/// control over values, in the instance that the default parser is insufficient.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Parsed {
|
||||
/// Calendar year.
|
||||
year: Option<i32>,
|
||||
/// The last two digits of the calendar year.
|
||||
year_last_two: Option<u8>,
|
||||
/// Year of the [ISO week date](https://en.wikipedia.org/wiki/ISO_week_date).
|
||||
iso_year: Option<i32>,
|
||||
/// The last two digits of the ISO week year.
|
||||
iso_year_last_two: Option<u8>,
|
||||
/// Month of the year.
|
||||
month: Option<Month>,
|
||||
/// Week of the year, where week one begins on the first Sunday of the calendar year.
|
||||
sunday_week_number: Option<u8>,
|
||||
/// Week of the year, where week one begins on the first Monday of the calendar year.
|
||||
monday_week_number: Option<u8>,
|
||||
/// Week of the year, where week one is the Monday-to-Sunday period containing January 4.
|
||||
iso_week_number: Option<NonZeroU8>,
|
||||
/// Day of the week.
|
||||
weekday: Option<Weekday>,
|
||||
/// Day of the year.
|
||||
ordinal: Option<NonZeroU16>,
|
||||
/// Day of the month.
|
||||
day: Option<NonZeroU8>,
|
||||
/// Hour within the day.
|
||||
hour_24: Option<u8>,
|
||||
/// Hour within the 12-hour period (midnight to noon or vice versa). This is typically used in
|
||||
/// conjunction with AM/PM, which is indicated by the `hour_12_is_pm` field.
|
||||
hour_12: Option<NonZeroU8>,
|
||||
/// Whether the `hour_12` field indicates a time that "PM".
|
||||
hour_12_is_pm: Option<bool>,
|
||||
/// Minute within the hour.
|
||||
minute: Option<u8>,
|
||||
/// Second within the minute.
|
||||
second: Option<u8>,
|
||||
/// Nanosecond within the second.
|
||||
subsecond: Option<u32>,
|
||||
/// Whole hours of the UTC offset.
|
||||
offset_hour: Option<i8>,
|
||||
/// Minutes within the hour of the UTC offset.
|
||||
offset_minute: Option<i8>,
|
||||
/// Seconds within the minute of the UTC offset.
|
||||
offset_second: Option<i8>,
|
||||
/// Indicates whether a leap second is permitted to be parsed. This is required by some
|
||||
/// well-known formats.
|
||||
leap_second_allowed: bool,
|
||||
}
|
||||
|
||||
impl Parsed {
|
||||
/// Create a new instance of `Parsed` with no information known.
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
year: None,
|
||||
year_last_two: None,
|
||||
iso_year: None,
|
||||
iso_year_last_two: None,
|
||||
month: None,
|
||||
sunday_week_number: None,
|
||||
monday_week_number: None,
|
||||
iso_week_number: None,
|
||||
weekday: None,
|
||||
ordinal: None,
|
||||
day: None,
|
||||
hour_24: None,
|
||||
hour_12: None,
|
||||
hour_12_is_pm: None,
|
||||
minute: None,
|
||||
second: None,
|
||||
subsecond: None,
|
||||
offset_hour: None,
|
||||
offset_minute: None,
|
||||
offset_second: None,
|
||||
leap_second_allowed: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a single [`FormatItem`], mutating the struct. The remaining input is returned as the
|
||||
/// `Ok` value.
|
||||
///
|
||||
/// If a [`FormatItem::Optional`] is passed, parsing will not fail; the input will be returned
|
||||
/// as-is if the expected format is not present.
|
||||
pub fn parse_item<'a>(
|
||||
&mut self,
|
||||
input: &'a [u8],
|
||||
item: &FormatItem<'_>,
|
||||
) -> Result<&'a [u8], error::ParseFromDescription> {
|
||||
match item {
|
||||
FormatItem::Literal(literal) => Self::parse_literal(input, literal),
|
||||
FormatItem::Component(component) => self.parse_component(input, *component),
|
||||
FormatItem::Compound(compound) => self.parse_items(input, compound),
|
||||
FormatItem::Optional(item) => self.parse_item(input, item).or(Ok(input)),
|
||||
FormatItem::First(items) => {
|
||||
let mut first_err = None;
|
||||
|
||||
for item in items.iter() {
|
||||
match self.parse_item(input, item) {
|
||||
Ok(remaining_input) => return Ok(remaining_input),
|
||||
Err(err) if first_err.is_none() => first_err = Some(err),
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
match first_err {
|
||||
Some(err) => Err(err),
|
||||
// This location will be reached if the slice is empty, skipping the `for` loop.
|
||||
// As this case is expected to be uncommon, there's no need to check up front.
|
||||
None => Ok(input),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a sequence of [`FormatItem`]s, mutating the struct. The remaining input is returned as
|
||||
/// the `Ok` value.
|
||||
///
|
||||
/// This method will fail if any of the contained [`FormatItem`]s fail to parse. `self` will not
|
||||
/// be mutated in this instance.
|
||||
pub fn parse_items<'a>(
|
||||
&mut self,
|
||||
mut input: &'a [u8],
|
||||
items: &[FormatItem<'_>],
|
||||
) -> Result<&'a [u8], error::ParseFromDescription> {
|
||||
// Make a copy that we can mutate. It will only be set to the user's copy if everything
|
||||
// succeeds.
|
||||
let mut this = *self;
|
||||
for item in items {
|
||||
input = this.parse_item(input, item)?;
|
||||
}
|
||||
*self = this;
|
||||
Ok(input)
|
||||
}
|
||||
|
||||
/// Parse a literal byte sequence. The remaining input is returned as the `Ok` value.
|
||||
pub fn parse_literal<'a>(
|
||||
input: &'a [u8],
|
||||
literal: &[u8],
|
||||
) -> Result<&'a [u8], error::ParseFromDescription> {
|
||||
input
|
||||
.strip_prefix(literal)
|
||||
.ok_or(error::ParseFromDescription::InvalidLiteral)
|
||||
}
|
||||
|
||||
/// Parse a single component, mutating the struct. The remaining input is returned as the `Ok`
|
||||
/// value.
|
||||
pub fn parse_component<'a>(
|
||||
&mut self,
|
||||
input: &'a [u8],
|
||||
component: Component,
|
||||
) -> Result<&'a [u8], error::ParseFromDescription> {
|
||||
use error::ParseFromDescription::InvalidComponent;
|
||||
|
||||
match component {
|
||||
Component::Day(modifiers) => parse_day(input, modifiers)
|
||||
.and_then(|parsed| parsed.consume_value(|value| self.set_day(value)))
|
||||
.ok_or(InvalidComponent("day")),
|
||||
Component::Month(modifiers) => parse_month(input, modifiers)
|
||||
.and_then(|parsed| parsed.consume_value(|value| self.set_month(value)))
|
||||
.ok_or(InvalidComponent("month")),
|
||||
Component::Ordinal(modifiers) => parse_ordinal(input, modifiers)
|
||||
.and_then(|parsed| parsed.consume_value(|value| self.set_ordinal(value)))
|
||||
.ok_or(InvalidComponent("ordinal")),
|
||||
Component::Weekday(modifiers) => parse_weekday(input, modifiers)
|
||||
.and_then(|parsed| parsed.consume_value(|value| self.set_weekday(value)))
|
||||
.ok_or(InvalidComponent("weekday")),
|
||||
Component::WeekNumber(modifiers) => {
|
||||
let ParsedItem(remaining, value) =
|
||||
parse_week_number(input, modifiers).ok_or(InvalidComponent("week number"))?;
|
||||
match modifiers.repr {
|
||||
WeekNumberRepr::Iso => {
|
||||
NonZeroU8::new(value).and_then(|value| self.set_iso_week_number(value))
|
||||
}
|
||||
WeekNumberRepr::Sunday => self.set_sunday_week_number(value),
|
||||
WeekNumberRepr::Monday => self.set_monday_week_number(value),
|
||||
}
|
||||
.ok_or(InvalidComponent("week number"))?;
|
||||
Ok(remaining)
|
||||
}
|
||||
Component::Year(modifiers) => {
|
||||
let ParsedItem(remaining, value) =
|
||||
parse_year(input, modifiers).ok_or(InvalidComponent("year"))?;
|
||||
match (modifiers.iso_week_based, modifiers.repr) {
|
||||
(false, YearRepr::Full) => self.set_year(value),
|
||||
(false, YearRepr::LastTwo) => self.set_year_last_two(value as _),
|
||||
(true, YearRepr::Full) => self.set_iso_year(value),
|
||||
(true, YearRepr::LastTwo) => self.set_iso_year_last_two(value as _),
|
||||
}
|
||||
.ok_or(InvalidComponent("year"))?;
|
||||
Ok(remaining)
|
||||
}
|
||||
Component::Hour(modifiers) => {
|
||||
let ParsedItem(remaining, value) =
|
||||
parse_hour(input, modifiers).ok_or(InvalidComponent("hour"))?;
|
||||
if modifiers.is_12_hour_clock {
|
||||
NonZeroU8::new(value).and_then(|value| self.set_hour_12(value))
|
||||
} else {
|
||||
self.set_hour_24(value)
|
||||
}
|
||||
.ok_or(InvalidComponent("hour"))?;
|
||||
Ok(remaining)
|
||||
}
|
||||
Component::Minute(modifiers) => parse_minute(input, modifiers)
|
||||
.and_then(|parsed| parsed.consume_value(|value| self.set_minute(value)))
|
||||
.ok_or(InvalidComponent("minute")),
|
||||
Component::Period(modifiers) => parse_period(input, modifiers)
|
||||
.and_then(|parsed| {
|
||||
parsed.consume_value(|value| self.set_hour_12_is_pm(value == Period::Pm))
|
||||
})
|
||||
.ok_or(InvalidComponent("period")),
|
||||
Component::Second(modifiers) => parse_second(input, modifiers)
|
||||
.and_then(|parsed| parsed.consume_value(|value| self.set_second(value)))
|
||||
.ok_or(InvalidComponent("second")),
|
||||
Component::Subsecond(modifiers) => parse_subsecond(input, modifiers)
|
||||
.and_then(|parsed| parsed.consume_value(|value| self.set_subsecond(value)))
|
||||
.ok_or(InvalidComponent("subsecond")),
|
||||
Component::OffsetHour(modifiers) => parse_offset_hour(input, modifiers)
|
||||
.and_then(|parsed| parsed.consume_value(|value| self.set_offset_hour(value)))
|
||||
.ok_or(InvalidComponent("offset hour")),
|
||||
Component::OffsetMinute(modifiers) => parse_offset_minute(input, modifiers)
|
||||
.and_then(|parsed| {
|
||||
parsed.consume_value(|value| self.set_offset_minute_signed(value))
|
||||
})
|
||||
.ok_or(InvalidComponent("offset minute")),
|
||||
Component::OffsetSecond(modifiers) => parse_offset_second(input, modifiers)
|
||||
.and_then(|parsed| {
|
||||
parsed.consume_value(|value| self.set_offset_second_signed(value))
|
||||
})
|
||||
.ok_or(InvalidComponent("offset second")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate getters for each of the fields.
|
||||
macro_rules! getters {
|
||||
($($name:ident: $ty:ty),+ $(,)?) => {$(
|
||||
/// Obtain the named component.
|
||||
pub const fn $name(&self) -> Option<$ty> {
|
||||
self.$name
|
||||
}
|
||||
)*}
|
||||
}
|
||||
|
||||
/// Getter methods
|
||||
impl Parsed {
|
||||
getters! {
|
||||
year: i32,
|
||||
year_last_two: u8,
|
||||
iso_year: i32,
|
||||
iso_year_last_two: u8,
|
||||
month: Month,
|
||||
sunday_week_number: u8,
|
||||
monday_week_number: u8,
|
||||
iso_week_number: NonZeroU8,
|
||||
weekday: Weekday,
|
||||
ordinal: NonZeroU16,
|
||||
day: NonZeroU8,
|
||||
hour_24: u8,
|
||||
hour_12: NonZeroU8,
|
||||
hour_12_is_pm: bool,
|
||||
minute: u8,
|
||||
second: u8,
|
||||
subsecond: u32,
|
||||
offset_hour: i8,
|
||||
}
|
||||
|
||||
/// Obtain the absolute value of the offset minute.
|
||||
#[deprecated(since = "0.3.8", note = "use `parsed.offset_minute_signed()` instead")]
|
||||
pub const fn offset_minute(&self) -> Option<u8> {
|
||||
Some(const_try_opt!(self.offset_minute_signed()).unsigned_abs())
|
||||
}
|
||||
|
||||
/// Obtain the offset minute as an `i8`.
|
||||
pub const fn offset_minute_signed(&self) -> Option<i8> {
|
||||
self.offset_minute
|
||||
}
|
||||
|
||||
/// Obtain the absolute value of the offset second.
|
||||
#[deprecated(since = "0.3.8", note = "use `parsed.offset_second_signed()` instead")]
|
||||
pub const fn offset_second(&self) -> Option<u8> {
|
||||
Some(const_try_opt!(self.offset_second_signed()).unsigned_abs())
|
||||
}
|
||||
|
||||
/// Obtain the offset second as an `i8`.
|
||||
pub const fn offset_second_signed(&self) -> Option<i8> {
|
||||
self.offset_second
|
||||
}
|
||||
|
||||
/// Obtain whether leap seconds are permitted in the current format.
|
||||
pub(crate) const fn leap_second_allowed(&self) -> bool {
|
||||
self.leap_second_allowed
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate setters for each of the fields.
|
||||
///
|
||||
/// This macro should only be used for fields where the value is not validated beyond its type.
|
||||
macro_rules! setters {
|
||||
($($setter_name:ident $name:ident: $ty:ty),+ $(,)?) => {$(
|
||||
/// Set the named component.
|
||||
pub fn $setter_name(&mut self, value: $ty) -> Option<()> {
|
||||
self.$name = Some(value);
|
||||
Some(())
|
||||
}
|
||||
)*}
|
||||
}
|
||||
|
||||
/// Setter methods
|
||||
///
|
||||
/// All setters return `Option<()>`, which is `Some` if the value was set, and `None` if not. The
|
||||
/// setters _may_ fail if the value is invalid, though behavior is not guaranteed.
|
||||
impl Parsed {
|
||||
setters! {
|
||||
set_year year: i32,
|
||||
set_year_last_two year_last_two: u8,
|
||||
set_iso_year iso_year: i32,
|
||||
set_iso_year_last_two iso_year_last_two: u8,
|
||||
set_month month: Month,
|
||||
set_sunday_week_number sunday_week_number: u8,
|
||||
set_monday_week_number monday_week_number: u8,
|
||||
set_iso_week_number iso_week_number: NonZeroU8,
|
||||
set_weekday weekday: Weekday,
|
||||
set_ordinal ordinal: NonZeroU16,
|
||||
set_day day: NonZeroU8,
|
||||
set_hour_24 hour_24: u8,
|
||||
set_hour_12 hour_12: NonZeroU8,
|
||||
set_hour_12_is_pm hour_12_is_pm: bool,
|
||||
set_minute minute: u8,
|
||||
set_second second: u8,
|
||||
set_subsecond subsecond: u32,
|
||||
set_offset_hour offset_hour: i8,
|
||||
}
|
||||
|
||||
/// Set the named component.
|
||||
#[deprecated(
|
||||
since = "0.3.8",
|
||||
note = "use `parsed.set_offset_minute_signed()` instead"
|
||||
)]
|
||||
pub fn set_offset_minute(&mut self, value: u8) -> Option<()> {
|
||||
if value > i8::MAX as u8 {
|
||||
None
|
||||
} else {
|
||||
self.set_offset_minute_signed(value as _)
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the `offset_minute` component.
|
||||
pub fn set_offset_minute_signed(&mut self, value: i8) -> Option<()> {
|
||||
self.offset_minute = Some(value);
|
||||
Some(())
|
||||
}
|
||||
|
||||
/// Set the named component.
|
||||
#[deprecated(
|
||||
since = "0.3.8",
|
||||
note = "use `parsed.set_offset_second_signed()` instead"
|
||||
)]
|
||||
pub fn set_offset_second(&mut self, value: u8) -> Option<()> {
|
||||
if value > i8::MAX as u8 {
|
||||
None
|
||||
} else {
|
||||
self.set_offset_second_signed(value as _)
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the `offset_second` component.
|
||||
pub fn set_offset_second_signed(&mut self, value: i8) -> Option<()> {
|
||||
self.offset_second = Some(value);
|
||||
Some(())
|
||||
}
|
||||
|
||||
/// Set the leap second allowed flag.
|
||||
pub(crate) fn set_leap_second_allowed(&mut self, value: bool) {
|
||||
self.leap_second_allowed = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate build methods for each of the fields.
|
||||
///
|
||||
/// This macro should only be used for fields where the value is not validated beyond its type.
|
||||
macro_rules! builders {
|
||||
($($builder_name:ident $name:ident: $ty:ty),+ $(,)?) => {$(
|
||||
/// Set the named component and return `self`.
|
||||
pub const fn $builder_name(mut self, value: $ty) -> Option<Self> {
|
||||
self.$name = Some(value);
|
||||
Some(self)
|
||||
}
|
||||
)*}
|
||||
}
|
||||
|
||||
/// Builder methods
|
||||
///
|
||||
/// All builder methods return `Option<Self>`, which is `Some` if the value was set, and `None` if
|
||||
/// not. The builder methods _may_ fail if the value is invalid, though behavior is not guaranteed.
|
||||
impl Parsed {
|
||||
builders! {
|
||||
with_year year: i32,
|
||||
with_year_last_two year_last_two: u8,
|
||||
with_iso_year iso_year: i32,
|
||||
with_iso_year_last_two iso_year_last_two: u8,
|
||||
with_month month: Month,
|
||||
with_sunday_week_number sunday_week_number: u8,
|
||||
with_monday_week_number monday_week_number: u8,
|
||||
with_iso_week_number iso_week_number: NonZeroU8,
|
||||
with_weekday weekday: Weekday,
|
||||
with_ordinal ordinal: NonZeroU16,
|
||||
with_day day: NonZeroU8,
|
||||
with_hour_24 hour_24: u8,
|
||||
with_hour_12 hour_12: NonZeroU8,
|
||||
with_hour_12_is_pm hour_12_is_pm: bool,
|
||||
with_minute minute: u8,
|
||||
with_second second: u8,
|
||||
with_subsecond subsecond: u32,
|
||||
with_offset_hour offset_hour: i8,
|
||||
}
|
||||
|
||||
/// Set the named component and return `self`.
|
||||
#[deprecated(
|
||||
since = "0.3.8",
|
||||
note = "use `parsed.with_offset_minute_signed()` instead"
|
||||
)]
|
||||
pub const fn with_offset_minute(self, value: u8) -> Option<Self> {
|
||||
if value > i8::MAX as u8 {
|
||||
None
|
||||
} else {
|
||||
self.with_offset_minute_signed(value as _)
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the `offset_minute` component and return `self`.
|
||||
pub const fn with_offset_minute_signed(mut self, value: i8) -> Option<Self> {
|
||||
self.offset_minute = Some(value);
|
||||
Some(self)
|
||||
}
|
||||
|
||||
/// Set the named component and return `self`.
|
||||
#[deprecated(
|
||||
since = "0.3.8",
|
||||
note = "use `parsed.with_offset_second_signed()` instead"
|
||||
)]
|
||||
pub const fn with_offset_second(self, value: u8) -> Option<Self> {
|
||||
if value > i8::MAX as u8 {
|
||||
None
|
||||
} else {
|
||||
self.with_offset_second_signed(value as _)
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the `offset_second` component and return `self`.
|
||||
pub const fn with_offset_second_signed(mut self, value: i8) -> Option<Self> {
|
||||
self.offset_second = Some(value);
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Parsed> for Date {
|
||||
type Error = error::TryFromParsed;
|
||||
|
||||
fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
|
||||
/// Match on the components that need to be present.
|
||||
macro_rules! match_ {
|
||||
(_ => $catch_all:expr $(,)?) => {
|
||||
$catch_all
|
||||
};
|
||||
(($($name:ident),* $(,)?) => $arm:expr, $($rest:tt)*) => {
|
||||
if let ($(Some($name)),*) = ($(parsed.$name()),*) {
|
||||
$arm
|
||||
} else {
|
||||
match_!($($rest)*)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Get the value needed to adjust the ordinal day for Sunday and Monday-based week
|
||||
/// numbering.
|
||||
const fn adjustment(year: i32) -> i16 {
|
||||
match Date::__from_ordinal_date_unchecked(year, 1).weekday() {
|
||||
Weekday::Monday => 7,
|
||||
Weekday::Tuesday => 1,
|
||||
Weekday::Wednesday => 2,
|
||||
Weekday::Thursday => 3,
|
||||
Weekday::Friday => 4,
|
||||
Weekday::Saturday => 5,
|
||||
Weekday::Sunday => 6,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Only the basics have been covered. There are many other valid values that are not
|
||||
// currently constructed from the information known.
|
||||
|
||||
match_! {
|
||||
(year, ordinal) => Ok(Self::from_ordinal_date(year, ordinal.get())?),
|
||||
(year, month, day) => Ok(Self::from_calendar_date(year, month, day.get())?),
|
||||
(iso_year, iso_week_number, weekday) => Ok(Self::from_iso_week_date(
|
||||
iso_year,
|
||||
iso_week_number.get(),
|
||||
weekday,
|
||||
)?),
|
||||
(year, sunday_week_number, weekday) => Ok(Self::from_ordinal_date(
|
||||
year,
|
||||
(sunday_week_number as i16 * 7 + weekday.number_days_from_sunday() as i16
|
||||
- adjustment(year)
|
||||
+ 1) as u16,
|
||||
)?),
|
||||
(year, monday_week_number, weekday) => Ok(Self::from_ordinal_date(
|
||||
year,
|
||||
(monday_week_number as i16 * 7 + weekday.number_days_from_monday() as i16
|
||||
- adjustment(year)
|
||||
+ 1) as u16,
|
||||
)?),
|
||||
_ => Err(InsufficientInformation),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Parsed> for Time {
|
||||
type Error = error::TryFromParsed;
|
||||
|
||||
fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
|
||||
let hour = match (parsed.hour_24(), parsed.hour_12(), parsed.hour_12_is_pm()) {
|
||||
(Some(hour), _, _) => hour,
|
||||
(_, Some(hour), Some(false)) if hour.get() == 12 => 0,
|
||||
(_, Some(hour), Some(true)) if hour.get() == 12 => 12,
|
||||
(_, Some(hour), Some(false)) => hour.get(),
|
||||
(_, Some(hour), Some(true)) => hour.get() + 12,
|
||||
_ => return Err(InsufficientInformation),
|
||||
};
|
||||
if parsed.hour_24().is_none()
|
||||
&& parsed.hour_12().is_some()
|
||||
&& parsed.hour_12_is_pm().is_some()
|
||||
&& parsed.minute().is_none()
|
||||
&& parsed.second().is_none()
|
||||
&& parsed.subsecond().is_none()
|
||||
{
|
||||
return Ok(Self::from_hms_nano(hour, 0, 0, 0)?);
|
||||
}
|
||||
let minute = parsed.minute().ok_or(InsufficientInformation)?;
|
||||
let second = parsed.second().unwrap_or(0);
|
||||
let subsecond = parsed.subsecond().unwrap_or(0);
|
||||
Ok(Self::from_hms_nano(hour, minute, second, subsecond)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Parsed> for UtcOffset {
|
||||
type Error = error::TryFromParsed;
|
||||
|
||||
fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
|
||||
let hour = parsed.offset_hour().ok_or(InsufficientInformation)?;
|
||||
let minute = parsed.offset_minute_signed().unwrap_or(0);
|
||||
let second = parsed.offset_second_signed().unwrap_or(0);
|
||||
|
||||
Self::from_hms(hour, minute, second).map_err(|mut err| {
|
||||
// Provide the user a more accurate error.
|
||||
if err.name == "hours" {
|
||||
err.name = "offset hour";
|
||||
} else if err.name == "minutes" {
|
||||
err.name = "offset minute";
|
||||
} else if err.name == "seconds" {
|
||||
err.name = "offset second";
|
||||
}
|
||||
err.into()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Parsed> for PrimitiveDateTime {
|
||||
type Error = error::TryFromParsed;
|
||||
|
||||
fn try_from(parsed: Parsed) -> Result<Self, Self::Error> {
|
||||
Ok(Self::new(parsed.try_into()?, parsed.try_into()?))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Parsed> for OffsetDateTime {
|
||||
type Error = error::TryFromParsed;
|
||||
|
||||
#[allow(clippy::unwrap_in_result)] // We know the values are valid.
|
||||
fn try_from(mut parsed: Parsed) -> Result<Self, Self::Error> {
|
||||
// Some well-known formats explicitly allow leap seconds. We don't currently support them,
|
||||
// so treat it as the nearest preceding moment that can be represented. Because leap seconds
|
||||
// always fall at the end of a month UTC, reject any that are at other times.
|
||||
let leap_second_input = if parsed.leap_second_allowed() && parsed.second() == Some(60) {
|
||||
parsed.set_second(59).expect("59 is a valid second");
|
||||
parsed
|
||||
.set_subsecond(999_999_999)
|
||||
.expect("999_999_999 is a valid subsecond");
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let dt = PrimitiveDateTime::try_from(parsed)?.assume_offset(parsed.try_into()?);
|
||||
if leap_second_input && !dt.is_valid_leap_second_stand_in() {
|
||||
return Err(error::TryFromParsed::ComponentRange(
|
||||
error::ComponentRange {
|
||||
name: "second",
|
||||
minimum: 0,
|
||||
maximum: 59,
|
||||
value: 60,
|
||||
conditional_range: true,
|
||||
},
|
||||
));
|
||||
}
|
||||
Ok(dt)
|
||||
}
|
||||
}
|
||||
50
zeroidc/vendor/time/src/parsing/shim.rs
vendored
Normal file
50
zeroidc/vendor/time/src/parsing/shim.rs
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
//! Extension traits for things either not implemented or not yet stable in the MSRV.
|
||||
|
||||
/// Equivalent of `foo.parse()` for slices.
|
||||
pub(crate) trait IntegerParseBytes<T> {
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
fn parse_bytes(&self) -> Option<T>;
|
||||
}
|
||||
|
||||
impl<T: Integer> IntegerParseBytes<T> for [u8] {
|
||||
fn parse_bytes(&self) -> Option<T> {
|
||||
T::parse_bytes(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Marker trait for all integer types, including `NonZero*`
|
||||
pub(crate) trait Integer: Sized {
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
fn parse_bytes(src: &[u8]) -> Option<Self>;
|
||||
}
|
||||
|
||||
/// Parse the given types from bytes.
|
||||
macro_rules! impl_parse_bytes {
|
||||
($($t:ty)*) => ($(
|
||||
impl Integer for $t {
|
||||
#[allow(trivial_numeric_casts)]
|
||||
fn parse_bytes(src: &[u8]) -> Option<Self> {
|
||||
src.iter().try_fold::<Self, _, _>(0, |result, c| {
|
||||
result.checked_mul(10)?.checked_add((c - b'0') as Self)
|
||||
})
|
||||
}
|
||||
}
|
||||
)*)
|
||||
}
|
||||
impl_parse_bytes! { u8 u16 u32 }
|
||||
|
||||
/// Parse the given types from bytes.
|
||||
macro_rules! impl_parse_bytes_nonzero {
|
||||
($($t:ty)*) => {$(
|
||||
impl Integer for $t {
|
||||
fn parse_bytes(src: &[u8]) -> Option<Self> {
|
||||
Self::new(src.parse_bytes()?)
|
||||
}
|
||||
}
|
||||
)*}
|
||||
}
|
||||
|
||||
impl_parse_bytes_nonzero! {
|
||||
core::num::NonZeroU8
|
||||
core::num::NonZeroU16
|
||||
}
|
||||
936
zeroidc/vendor/time/src/primitive_date_time.rs
vendored
Normal file
936
zeroidc/vendor/time/src/primitive_date_time.rs
vendored
Normal file
@@ -0,0 +1,936 @@
|
||||
//! The [`PrimitiveDateTime`] struct and its associated `impl`s.
|
||||
|
||||
use core::fmt;
|
||||
use core::ops::{Add, Sub};
|
||||
use core::time::Duration as StdDuration;
|
||||
#[cfg(feature = "formatting")]
|
||||
use std::io;
|
||||
|
||||
#[cfg(feature = "formatting")]
|
||||
use crate::formatting::Formattable;
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::parsing::Parsable;
|
||||
use crate::{error, util, Date, Duration, Month, OffsetDateTime, Time, UtcOffset, Weekday};
|
||||
|
||||
/// Combined date and time.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct PrimitiveDateTime {
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
pub(crate) date: Date,
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
pub(crate) time: Time,
|
||||
}
|
||||
|
||||
impl PrimitiveDateTime {
|
||||
/// The smallest value that can be represented by `PrimitiveDateTime`.
|
||||
///
|
||||
/// Depending on `large-dates` feature flag, value of this constant may vary.
|
||||
///
|
||||
/// 1. With `large-dates` disabled it is equal to `-9999 - 01 - 01 00:00:00.0`
|
||||
/// 2. With `large-dates` enabled it is equal to `-999999 - 01 - 01 00:00:00.0`
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{PrimitiveDateTime, macros::datetime};
|
||||
/// // Assuming `large-dates` feature is enabled.
|
||||
/// assert_eq!(PrimitiveDateTime::MIN, datetime!(-999999 - 01 - 01 0:00));
|
||||
/// ```
|
||||
pub const MIN: Self = Self::new(Date::MIN, Time::MIN);
|
||||
|
||||
/// The largest value that can be represented by `PrimitiveDateTime`.
|
||||
///
|
||||
/// Depending on `large-dates` feature flag, value of this constant may vary.
|
||||
///
|
||||
/// 1. With `large-dates` disabled it is equal to `9999 - 12 - 31 23:59:59.999_999_999`
|
||||
/// 2. With `large-dates` enabled it is equal to `999999 - 12 - 31 23:59:59.999_999_999`
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{PrimitiveDateTime, macros::datetime};
|
||||
/// // Assuming `large-dates` feature is enabled.
|
||||
/// assert_eq!(PrimitiveDateTime::MAX, datetime!(+999999 - 12 - 31 23:59:59.999_999_999));
|
||||
/// ```
|
||||
pub const MAX: Self = Self::new(Date::MAX, Time::MAX);
|
||||
|
||||
/// Create a new `PrimitiveDateTime` from the provided [`Date`] and [`Time`].
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{PrimitiveDateTime, macros::{date, datetime, time}};
|
||||
/// assert_eq!(
|
||||
/// PrimitiveDateTime::new(date!(2019-01-01), time!(0:00)),
|
||||
/// datetime!(2019-01-01 0:00),
|
||||
/// );
|
||||
/// ```
|
||||
pub const fn new(date: Date, time: Time) -> Self {
|
||||
Self { date, time }
|
||||
}
|
||||
|
||||
// region: component getters
|
||||
/// Get the [`Date`] component of the `PrimitiveDateTime`.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::{date, datetime};
|
||||
/// assert_eq!(datetime!(2019-01-01 0:00).date(), date!(2019-01-01));
|
||||
/// ```
|
||||
pub const fn date(self) -> Date {
|
||||
self.date
|
||||
}
|
||||
|
||||
/// Get the [`Time`] component of the `PrimitiveDateTime`.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::{datetime, time};
|
||||
/// assert_eq!(datetime!(2019-01-01 0:00).time(), time!(0:00));
|
||||
pub const fn time(self) -> Time {
|
||||
self.time
|
||||
}
|
||||
// endregion component getters
|
||||
|
||||
// region: date getters
|
||||
/// Get the year of the date.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(datetime!(2019-01-01 0:00).year(), 2019);
|
||||
/// assert_eq!(datetime!(2019-12-31 0:00).year(), 2019);
|
||||
/// assert_eq!(datetime!(2020-01-01 0:00).year(), 2020);
|
||||
/// ```
|
||||
pub const fn year(self) -> i32 {
|
||||
self.date.year()
|
||||
}
|
||||
|
||||
/// Get the month of the date.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{macros::datetime, Month};
|
||||
/// assert_eq!(datetime!(2019-01-01 0:00).month(), Month::January);
|
||||
/// assert_eq!(datetime!(2019-12-31 0:00).month(), Month::December);
|
||||
/// ```
|
||||
pub const fn month(self) -> Month {
|
||||
self.date.month()
|
||||
}
|
||||
|
||||
/// Get the day of the date.
|
||||
///
|
||||
/// The returned value will always be in the range `1..=31`.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(datetime!(2019-01-01 0:00).day(), 1);
|
||||
/// assert_eq!(datetime!(2019-12-31 0:00).day(), 31);
|
||||
/// ```
|
||||
pub const fn day(self) -> u8 {
|
||||
self.date.day()
|
||||
}
|
||||
|
||||
/// Get the day of the year.
|
||||
///
|
||||
/// The returned value will always be in the range `1..=366` (`1..=365` for common years).
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(datetime!(2019-01-01 0:00).ordinal(), 1);
|
||||
/// assert_eq!(datetime!(2019-12-31 0:00).ordinal(), 365);
|
||||
/// ```
|
||||
pub const fn ordinal(self) -> u16 {
|
||||
self.date.ordinal()
|
||||
}
|
||||
|
||||
/// Get the ISO week number.
|
||||
///
|
||||
/// The returned value will always be in the range `1..=53`.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(datetime!(2019-01-01 0:00).iso_week(), 1);
|
||||
/// assert_eq!(datetime!(2019-10-04 0:00).iso_week(), 40);
|
||||
/// assert_eq!(datetime!(2020-01-01 0:00).iso_week(), 1);
|
||||
/// assert_eq!(datetime!(2020-12-31 0:00).iso_week(), 53);
|
||||
/// assert_eq!(datetime!(2021-01-01 0:00).iso_week(), 53);
|
||||
/// ```
|
||||
pub const fn iso_week(self) -> u8 {
|
||||
self.date.iso_week()
|
||||
}
|
||||
|
||||
/// Get the week number where week 1 begins on the first Sunday.
|
||||
///
|
||||
/// The returned value will always be in the range `0..=53`.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(datetime!(2019-01-01 0:00).sunday_based_week(), 0);
|
||||
/// assert_eq!(datetime!(2020-01-01 0:00).sunday_based_week(), 0);
|
||||
/// assert_eq!(datetime!(2020-12-31 0:00).sunday_based_week(), 52);
|
||||
/// assert_eq!(datetime!(2021-01-01 0:00).sunday_based_week(), 0);
|
||||
/// ```
|
||||
pub const fn sunday_based_week(self) -> u8 {
|
||||
self.date.sunday_based_week()
|
||||
}
|
||||
|
||||
/// Get the week number where week 1 begins on the first Monday.
|
||||
///
|
||||
/// The returned value will always be in the range `0..=53`.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(datetime!(2019-01-01 0:00).monday_based_week(), 0);
|
||||
/// assert_eq!(datetime!(2020-01-01 0:00).monday_based_week(), 0);
|
||||
/// assert_eq!(datetime!(2020-12-31 0:00).monday_based_week(), 52);
|
||||
/// assert_eq!(datetime!(2021-01-01 0:00).monday_based_week(), 0);
|
||||
/// ```
|
||||
pub const fn monday_based_week(self) -> u8 {
|
||||
self.date.monday_based_week()
|
||||
}
|
||||
|
||||
/// Get the year, month, and day.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{macros::datetime, Month};
|
||||
/// assert_eq!(
|
||||
/// datetime!(2019-01-01 0:00).to_calendar_date(),
|
||||
/// (2019, Month::January, 1)
|
||||
/// );
|
||||
/// ```
|
||||
pub const fn to_calendar_date(self) -> (i32, Month, u8) {
|
||||
self.date.to_calendar_date()
|
||||
}
|
||||
|
||||
/// Get the year and ordinal day number.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(datetime!(2019-01-01 0:00).to_ordinal_date(), (2019, 1));
|
||||
/// ```
|
||||
pub const fn to_ordinal_date(self) -> (i32, u16) {
|
||||
self.date.to_ordinal_date()
|
||||
}
|
||||
|
||||
/// Get the ISO 8601 year, week number, and weekday.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{Weekday::*, macros::datetime};
|
||||
/// assert_eq!(
|
||||
/// datetime!(2019-01-01 0:00).to_iso_week_date(),
|
||||
/// (2019, 1, Tuesday)
|
||||
/// );
|
||||
/// assert_eq!(
|
||||
/// datetime!(2019-10-04 0:00).to_iso_week_date(),
|
||||
/// (2019, 40, Friday)
|
||||
/// );
|
||||
/// assert_eq!(
|
||||
/// datetime!(2020-01-01 0:00).to_iso_week_date(),
|
||||
/// (2020, 1, Wednesday)
|
||||
/// );
|
||||
/// assert_eq!(
|
||||
/// datetime!(2020-12-31 0:00).to_iso_week_date(),
|
||||
/// (2020, 53, Thursday)
|
||||
/// );
|
||||
/// assert_eq!(
|
||||
/// datetime!(2021-01-01 0:00).to_iso_week_date(),
|
||||
/// (2020, 53, Friday)
|
||||
/// );
|
||||
/// ```
|
||||
pub const fn to_iso_week_date(self) -> (i32, u8, Weekday) {
|
||||
self.date.to_iso_week_date()
|
||||
}
|
||||
|
||||
/// Get the weekday.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{Weekday::*, macros::datetime};
|
||||
/// assert_eq!(datetime!(2019-01-01 0:00).weekday(), Tuesday);
|
||||
/// assert_eq!(datetime!(2019-02-01 0:00).weekday(), Friday);
|
||||
/// assert_eq!(datetime!(2019-03-01 0:00).weekday(), Friday);
|
||||
/// assert_eq!(datetime!(2019-04-01 0:00).weekday(), Monday);
|
||||
/// assert_eq!(datetime!(2019-05-01 0:00).weekday(), Wednesday);
|
||||
/// assert_eq!(datetime!(2019-06-01 0:00).weekday(), Saturday);
|
||||
/// assert_eq!(datetime!(2019-07-01 0:00).weekday(), Monday);
|
||||
/// assert_eq!(datetime!(2019-08-01 0:00).weekday(), Thursday);
|
||||
/// assert_eq!(datetime!(2019-09-01 0:00).weekday(), Sunday);
|
||||
/// assert_eq!(datetime!(2019-10-01 0:00).weekday(), Tuesday);
|
||||
/// assert_eq!(datetime!(2019-11-01 0:00).weekday(), Friday);
|
||||
/// assert_eq!(datetime!(2019-12-01 0:00).weekday(), Sunday);
|
||||
/// ```
|
||||
pub const fn weekday(self) -> Weekday {
|
||||
self.date.weekday()
|
||||
}
|
||||
|
||||
/// Get the Julian day for the date. The time is not taken into account for this calculation.
|
||||
///
|
||||
/// The algorithm to perform this conversion is derived from one provided by Peter Baum; it is
|
||||
/// freely available [here](https://www.researchgate.net/publication/316558298_Date_Algorithms).
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(datetime!(-4713-11-24 0:00).to_julian_day(), 0);
|
||||
/// assert_eq!(datetime!(2000-01-01 0:00).to_julian_day(), 2_451_545);
|
||||
/// assert_eq!(datetime!(2019-01-01 0:00).to_julian_day(), 2_458_485);
|
||||
/// assert_eq!(datetime!(2019-12-31 0:00).to_julian_day(), 2_458_849);
|
||||
/// ```
|
||||
pub const fn to_julian_day(self) -> i32 {
|
||||
self.date.to_julian_day()
|
||||
}
|
||||
// endregion date getters
|
||||
|
||||
// region: time getters
|
||||
/// Get the clock hour, minute, and second.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(datetime!(2020-01-01 0:00:00).as_hms(), (0, 0, 0));
|
||||
/// assert_eq!(datetime!(2020-01-01 23:59:59).as_hms(), (23, 59, 59));
|
||||
/// ```
|
||||
pub const fn as_hms(self) -> (u8, u8, u8) {
|
||||
self.time.as_hms()
|
||||
}
|
||||
|
||||
/// Get the clock hour, minute, second, and millisecond.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(datetime!(2020-01-01 0:00:00).as_hms_milli(), (0, 0, 0, 0));
|
||||
/// assert_eq!(
|
||||
/// datetime!(2020-01-01 23:59:59.999).as_hms_milli(),
|
||||
/// (23, 59, 59, 999)
|
||||
/// );
|
||||
/// ```
|
||||
pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
|
||||
self.time.as_hms_milli()
|
||||
}
|
||||
|
||||
/// Get the clock hour, minute, second, and microsecond.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(datetime!(2020-01-01 0:00:00).as_hms_micro(), (0, 0, 0, 0));
|
||||
/// assert_eq!(
|
||||
/// datetime!(2020-01-01 23:59:59.999_999).as_hms_micro(),
|
||||
/// (23, 59, 59, 999_999)
|
||||
/// );
|
||||
/// ```
|
||||
pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
|
||||
self.time.as_hms_micro()
|
||||
}
|
||||
|
||||
/// Get the clock hour, minute, second, and nanosecond.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(datetime!(2020-01-01 0:00:00).as_hms_nano(), (0, 0, 0, 0));
|
||||
/// assert_eq!(
|
||||
/// datetime!(2020-01-01 23:59:59.999_999_999).as_hms_nano(),
|
||||
/// (23, 59, 59, 999_999_999)
|
||||
/// );
|
||||
/// ```
|
||||
pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
|
||||
self.time.as_hms_nano()
|
||||
}
|
||||
|
||||
/// Get the clock hour.
|
||||
///
|
||||
/// The returned value will always be in the range `0..24`.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(datetime!(2019-01-01 0:00).hour(), 0);
|
||||
/// assert_eq!(datetime!(2019-01-01 23:59:59).hour(), 23);
|
||||
/// ```
|
||||
pub const fn hour(self) -> u8 {
|
||||
self.time.hour()
|
||||
}
|
||||
|
||||
/// Get the minute within the hour.
|
||||
///
|
||||
/// The returned value will always be in the range `0..60`.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(datetime!(2019-01-01 0:00).minute(), 0);
|
||||
/// assert_eq!(datetime!(2019-01-01 23:59:59).minute(), 59);
|
||||
/// ```
|
||||
pub const fn minute(self) -> u8 {
|
||||
self.time.minute()
|
||||
}
|
||||
|
||||
/// Get the second within the minute.
|
||||
///
|
||||
/// The returned value will always be in the range `0..60`.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(datetime!(2019-01-01 0:00).second(), 0);
|
||||
/// assert_eq!(datetime!(2019-01-01 23:59:59).second(), 59);
|
||||
/// ```
|
||||
pub const fn second(self) -> u8 {
|
||||
self.time.second()
|
||||
}
|
||||
|
||||
/// Get the milliseconds within the second.
|
||||
///
|
||||
/// The returned value will always be in the range `0..1_000`.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(datetime!(2019-01-01 0:00).millisecond(), 0);
|
||||
/// assert_eq!(datetime!(2019-01-01 23:59:59.999).millisecond(), 999);
|
||||
/// ```
|
||||
pub const fn millisecond(self) -> u16 {
|
||||
self.time.millisecond()
|
||||
}
|
||||
|
||||
/// Get the microseconds within the second.
|
||||
///
|
||||
/// The returned value will always be in the range `0..1_000_000`.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(datetime!(2019-01-01 0:00).microsecond(), 0);
|
||||
/// assert_eq!(
|
||||
/// datetime!(2019-01-01 23:59:59.999_999).microsecond(),
|
||||
/// 999_999
|
||||
/// );
|
||||
/// ```
|
||||
pub const fn microsecond(self) -> u32 {
|
||||
self.time.microsecond()
|
||||
}
|
||||
|
||||
/// Get the nanoseconds within the second.
|
||||
///
|
||||
/// The returned value will always be in the range `0..1_000_000_000`.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(datetime!(2019-01-01 0:00).nanosecond(), 0);
|
||||
/// assert_eq!(
|
||||
/// datetime!(2019-01-01 23:59:59.999_999_999).nanosecond(),
|
||||
/// 999_999_999,
|
||||
/// );
|
||||
/// ```
|
||||
pub const fn nanosecond(self) -> u32 {
|
||||
self.time.nanosecond()
|
||||
}
|
||||
// endregion time getters
|
||||
|
||||
// region: attach offset
|
||||
/// Assuming that the existing `PrimitiveDateTime` represents a moment in the provided
|
||||
/// [`UtcOffset`], return an [`OffsetDateTime`].
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::{datetime, offset};
|
||||
/// assert_eq!(
|
||||
/// datetime!(2019-01-01 0:00)
|
||||
/// .assume_offset(offset!(UTC))
|
||||
/// .unix_timestamp(),
|
||||
/// 1_546_300_800,
|
||||
/// );
|
||||
/// assert_eq!(
|
||||
/// datetime!(2019-01-01 0:00)
|
||||
/// .assume_offset(offset!(-1))
|
||||
/// .unix_timestamp(),
|
||||
/// 1_546_304_400,
|
||||
/// );
|
||||
/// ```
|
||||
pub const fn assume_offset(self, offset: UtcOffset) -> OffsetDateTime {
|
||||
OffsetDateTime {
|
||||
utc_datetime: self.offset_to_utc(offset),
|
||||
offset,
|
||||
}
|
||||
}
|
||||
|
||||
/// Assuming that the existing `PrimitiveDateTime` represents a moment in UTC, return an
|
||||
/// [`OffsetDateTime`].
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(
|
||||
/// datetime!(2019-01-01 0:00).assume_utc().unix_timestamp(),
|
||||
/// 1_546_300_800,
|
||||
/// );
|
||||
/// ```
|
||||
pub const fn assume_utc(self) -> OffsetDateTime {
|
||||
OffsetDateTime {
|
||||
utc_datetime: self,
|
||||
offset: UtcOffset::UTC,
|
||||
}
|
||||
}
|
||||
// endregion attach offset
|
||||
|
||||
// region: checked arithmetic
|
||||
/// Computes `self + duration`, returning `None` if an overflow occurred.
|
||||
///
|
||||
/// ```
|
||||
/// # use time::{Date, ext::NumericalDuration};
|
||||
/// # use time::macros::datetime;
|
||||
/// let datetime = Date::MIN.midnight();
|
||||
/// assert_eq!(datetime.checked_add((-2).days()), None);
|
||||
///
|
||||
/// let datetime = Date::MAX.midnight();
|
||||
/// assert_eq!(datetime.checked_add(1.days()), None);
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// datetime!(2019 - 11 - 25 15:30).checked_add(27.hours()),
|
||||
/// Some(datetime!(2019 - 11 - 26 18:30))
|
||||
/// );
|
||||
/// ```
|
||||
pub const fn checked_add(self, duration: Duration) -> Option<Self> {
|
||||
let (date_adjustment, time) = self.time.adjusting_add(duration);
|
||||
let date = const_try_opt!(self.date.checked_add(duration));
|
||||
|
||||
Some(Self {
|
||||
date: match date_adjustment {
|
||||
util::DateAdjustment::Previous => const_try_opt!(date.previous_day()),
|
||||
util::DateAdjustment::Next => const_try_opt!(date.next_day()),
|
||||
util::DateAdjustment::None => date,
|
||||
},
|
||||
time,
|
||||
})
|
||||
}
|
||||
|
||||
/// Computes `self - duration`, returning `None` if an overflow occurred.
|
||||
///
|
||||
/// ```
|
||||
/// # use time::{Date, ext::NumericalDuration};
|
||||
/// # use time::macros::datetime;
|
||||
/// let datetime = Date::MIN.midnight();
|
||||
/// assert_eq!(datetime.checked_sub(2.days()), None);
|
||||
///
|
||||
/// let datetime = Date::MAX.midnight();
|
||||
/// assert_eq!(datetime.checked_sub((-1).days()), None);
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// datetime!(2019 - 11 - 25 15:30).checked_sub(27.hours()),
|
||||
/// Some(datetime!(2019 - 11 - 24 12:30))
|
||||
/// );
|
||||
/// ```
|
||||
pub const fn checked_sub(self, duration: Duration) -> Option<Self> {
|
||||
let (date_adjustment, time) = self.time.adjusting_sub(duration);
|
||||
let date = const_try_opt!(self.date.checked_sub(duration));
|
||||
|
||||
Some(Self {
|
||||
date: match date_adjustment {
|
||||
util::DateAdjustment::Previous => const_try_opt!(date.previous_day()),
|
||||
util::DateAdjustment::Next => const_try_opt!(date.next_day()),
|
||||
util::DateAdjustment::None => date,
|
||||
},
|
||||
time,
|
||||
})
|
||||
}
|
||||
// endregion: checked arithmetic
|
||||
|
||||
// region: saturating arithmetic
|
||||
/// Computes `self + duration`, saturating value on overflow.
|
||||
///
|
||||
/// ```
|
||||
/// # use time::{PrimitiveDateTime, ext::NumericalDuration};
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(
|
||||
/// PrimitiveDateTime::MIN.saturating_add((-2).days()),
|
||||
/// PrimitiveDateTime::MIN
|
||||
/// );
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// PrimitiveDateTime::MAX.saturating_add(2.days()),
|
||||
/// PrimitiveDateTime::MAX
|
||||
/// );
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// datetime!(2019 - 11 - 25 15:30).saturating_add(27.hours()),
|
||||
/// datetime!(2019 - 11 - 26 18:30)
|
||||
/// );
|
||||
/// ```
|
||||
pub const fn saturating_add(self, duration: Duration) -> Self {
|
||||
if let Some(datetime) = self.checked_add(duration) {
|
||||
datetime
|
||||
} else if duration.is_negative() {
|
||||
Self::MIN
|
||||
} else {
|
||||
Self::MAX
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes `self - duration`, saturating value on overflow.
|
||||
///
|
||||
/// ```
|
||||
/// # use time::{PrimitiveDateTime, ext::NumericalDuration};
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(
|
||||
/// PrimitiveDateTime::MIN.saturating_sub(2.days()),
|
||||
/// PrimitiveDateTime::MIN
|
||||
/// );
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// PrimitiveDateTime::MAX.saturating_sub((-2).days()),
|
||||
/// PrimitiveDateTime::MAX
|
||||
/// );
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// datetime!(2019 - 11 - 25 15:30).saturating_sub(27.hours()),
|
||||
/// datetime!(2019 - 11 - 24 12:30)
|
||||
/// );
|
||||
/// ```
|
||||
pub const fn saturating_sub(self, duration: Duration) -> Self {
|
||||
if let Some(datetime) = self.checked_sub(duration) {
|
||||
datetime
|
||||
} else if duration.is_negative() {
|
||||
Self::MAX
|
||||
} else {
|
||||
Self::MIN
|
||||
}
|
||||
}
|
||||
// endregion: saturating arithmetic
|
||||
}
|
||||
|
||||
// region: replacement
|
||||
/// Methods that replace part of the `PrimitiveDateTime`.
|
||||
impl PrimitiveDateTime {
|
||||
/// Replace the time, preserving the date.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::{datetime, time};
|
||||
/// assert_eq!(
|
||||
/// datetime!(2020-01-01 17:00).replace_time(time!(5:00)),
|
||||
/// datetime!(2020-01-01 5:00)
|
||||
/// );
|
||||
/// ```
|
||||
#[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
|
||||
pub const fn replace_time(self, time: Time) -> Self {
|
||||
self.date.with_time(time)
|
||||
}
|
||||
|
||||
/// Replace the date, preserving the time.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::{datetime, date};
|
||||
/// assert_eq!(
|
||||
/// datetime!(2020-01-01 12:00).replace_date(date!(2020-01-30)),
|
||||
/// datetime!(2020-01-30 12:00)
|
||||
/// );
|
||||
/// ```
|
||||
#[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
|
||||
pub const fn replace_date(self, date: Date) -> Self {
|
||||
date.with_time(self.time)
|
||||
}
|
||||
|
||||
/// Replace the year. The month and day will be unchanged.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(
|
||||
/// datetime!(2022 - 02 - 18 12:00).replace_year(2019),
|
||||
/// Ok(datetime!(2019 - 02 - 18 12:00))
|
||||
/// );
|
||||
/// assert!(datetime!(2022 - 02 - 18 12:00).replace_year(-1_000_000_000).is_err()); // -1_000_000_000 isn't a valid year
|
||||
/// assert!(datetime!(2022 - 02 - 18 12:00).replace_year(1_000_000_000).is_err()); // 1_000_000_000 isn't a valid year
|
||||
/// ```
|
||||
#[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
|
||||
pub const fn replace_year(self, year: i32) -> Result<Self, error::ComponentRange> {
|
||||
Ok(const_try!(self.date.replace_year(year)).with_time(self.time))
|
||||
}
|
||||
|
||||
/// Replace the month of the year.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::datetime;
|
||||
/// # use time::Month;
|
||||
/// assert_eq!(
|
||||
/// datetime!(2022 - 02 - 18 12:00).replace_month(Month::January),
|
||||
/// Ok(datetime!(2022 - 01 - 18 12:00))
|
||||
/// );
|
||||
/// assert!(datetime!(2022 - 01 - 30 12:00).replace_month(Month::February).is_err()); // 30 isn't a valid day in February
|
||||
/// ```
|
||||
#[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
|
||||
pub const fn replace_month(self, month: Month) -> Result<Self, error::ComponentRange> {
|
||||
Ok(const_try!(self.date.replace_month(month)).with_time(self.time))
|
||||
}
|
||||
|
||||
/// Replace the day of the month.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(
|
||||
/// datetime!(2022 - 02 - 18 12:00).replace_day(1),
|
||||
/// Ok(datetime!(2022 - 02 - 01 12:00))
|
||||
/// );
|
||||
/// assert!(datetime!(2022 - 02 - 18 12:00).replace_day(0).is_err()); // 00 isn't a valid day
|
||||
/// assert!(datetime!(2022 - 02 - 18 12:00).replace_day(30).is_err()); // 30 isn't a valid day in February
|
||||
/// ```
|
||||
#[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
|
||||
pub const fn replace_day(self, day: u8) -> Result<Self, error::ComponentRange> {
|
||||
Ok(const_try!(self.date.replace_day(day)).with_time(self.time))
|
||||
}
|
||||
|
||||
/// Replace the clock hour.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(
|
||||
/// datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_hour(7),
|
||||
/// Ok(datetime!(2022 - 02 - 18 07:02:03.004_005_006))
|
||||
/// );
|
||||
/// assert!(datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_hour(24).is_err()); // 24 isn't a valid hour
|
||||
/// ```
|
||||
#[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
|
||||
pub const fn replace_hour(self, hour: u8) -> Result<Self, error::ComponentRange> {
|
||||
Ok(self
|
||||
.date()
|
||||
.with_time(const_try!(self.time.replace_hour(hour))))
|
||||
}
|
||||
|
||||
/// Replace the minutes within the hour.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(
|
||||
/// datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_minute(7),
|
||||
/// Ok(datetime!(2022 - 02 - 18 01:07:03.004_005_006))
|
||||
/// );
|
||||
/// assert!(datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_minute(60).is_err()); // 60 isn't a valid minute
|
||||
/// ```
|
||||
#[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
|
||||
pub const fn replace_minute(self, minute: u8) -> Result<Self, error::ComponentRange> {
|
||||
Ok(self
|
||||
.date()
|
||||
.with_time(const_try!(self.time.replace_minute(minute))))
|
||||
}
|
||||
|
||||
/// Replace the seconds within the minute.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(
|
||||
/// datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_second(7),
|
||||
/// Ok(datetime!(2022 - 02 - 18 01:02:07.004_005_006))
|
||||
/// );
|
||||
/// assert!(datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_second(60).is_err()); // 60 isn't a valid second
|
||||
/// ```
|
||||
#[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
|
||||
pub const fn replace_second(self, second: u8) -> Result<Self, error::ComponentRange> {
|
||||
Ok(self
|
||||
.date()
|
||||
.with_time(const_try!(self.time.replace_second(second))))
|
||||
}
|
||||
|
||||
/// Replace the milliseconds within the second.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(
|
||||
/// datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_millisecond(7),
|
||||
/// Ok(datetime!(2022 - 02 - 18 01:02:03.007))
|
||||
/// );
|
||||
/// assert!(datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_millisecond(1_000).is_err()); // 1_000 isn't a valid millisecond
|
||||
/// ```
|
||||
#[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
|
||||
pub const fn replace_millisecond(
|
||||
self,
|
||||
millisecond: u16,
|
||||
) -> Result<Self, error::ComponentRange> {
|
||||
Ok(self
|
||||
.date()
|
||||
.with_time(const_try!(self.time.replace_millisecond(millisecond))))
|
||||
}
|
||||
|
||||
/// Replace the microseconds within the second.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(
|
||||
/// datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_microsecond(7_008),
|
||||
/// Ok(datetime!(2022 - 02 - 18 01:02:03.007_008))
|
||||
/// );
|
||||
/// assert!(datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_microsecond(1_000_000).is_err()); // 1_000_000 isn't a valid microsecond
|
||||
/// ```
|
||||
#[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
|
||||
pub const fn replace_microsecond(
|
||||
self,
|
||||
microsecond: u32,
|
||||
) -> Result<Self, error::ComponentRange> {
|
||||
Ok(self
|
||||
.date()
|
||||
.with_time(const_try!(self.time.replace_microsecond(microsecond))))
|
||||
}
|
||||
|
||||
/// Replace the nanoseconds within the second.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::datetime;
|
||||
/// assert_eq!(
|
||||
/// datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_nanosecond(7_008_009),
|
||||
/// Ok(datetime!(2022 - 02 - 18 01:02:03.007_008_009))
|
||||
/// );
|
||||
/// assert!(datetime!(2022 - 02 - 18 01:02:03.004_005_006).replace_nanosecond(1_000_000_000).is_err()); // 1_000_000_000 isn't a valid nanosecond
|
||||
/// ```
|
||||
#[must_use = "This method does not mutate the original `PrimitiveDateTime`."]
|
||||
pub const fn replace_nanosecond(self, nanosecond: u32) -> Result<Self, error::ComponentRange> {
|
||||
Ok(self
|
||||
.date()
|
||||
.with_time(const_try!(self.time.replace_nanosecond(nanosecond))))
|
||||
}
|
||||
}
|
||||
// endregion replacement
|
||||
|
||||
// region: offset conversion helpers
|
||||
/// Helper methods to adjust a [`PrimitiveDateTime`] to a given [`UtcOffset`].
|
||||
impl PrimitiveDateTime {
|
||||
/// Assuming that the current [`PrimitiveDateTime`] is a value in the provided [`UtcOffset`],
|
||||
/// obtain the equivalent value in the UTC.
|
||||
pub(crate) const fn offset_to_utc(self, offset: UtcOffset) -> Self {
|
||||
let mut second = self.second() as i8 - offset.seconds_past_minute();
|
||||
let mut minute = self.minute() as i8 - offset.minutes_past_hour();
|
||||
let mut hour = self.hour() as i8 - offset.whole_hours();
|
||||
let (mut year, mut ordinal) = self.date.to_ordinal_date();
|
||||
|
||||
cascade!(second in 0..60 => minute);
|
||||
cascade!(minute in 0..60 => hour);
|
||||
cascade!(hour in 0..24 => ordinal);
|
||||
cascade!(ordinal => year);
|
||||
|
||||
Self {
|
||||
date: Date::__from_ordinal_date_unchecked(year, ordinal),
|
||||
time: Time::__from_hms_nanos_unchecked(
|
||||
hour as _,
|
||||
minute as _,
|
||||
second as _,
|
||||
self.nanosecond(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Assuming that the current [`PrimitiveDateTime`] is a value in UTC, obtain the equivalent
|
||||
/// value in the provided [`UtcOffset`].
|
||||
pub(crate) const fn utc_to_offset(self, offset: UtcOffset) -> Self {
|
||||
self.offset_to_utc(UtcOffset::__from_hms_unchecked(
|
||||
-offset.whole_hours(),
|
||||
-offset.minutes_past_hour(),
|
||||
-offset.seconds_past_minute(),
|
||||
))
|
||||
}
|
||||
}
|
||||
// endregion offset conversion helpers
|
||||
|
||||
// region: formatting & parsing
|
||||
#[cfg(feature = "formatting")]
|
||||
impl PrimitiveDateTime {
|
||||
/// Format the `PrimitiveDateTime` using the provided [format
|
||||
/// description](crate::format_description).
|
||||
pub fn format_into(
|
||||
self,
|
||||
output: &mut impl io::Write,
|
||||
format: &(impl Formattable + ?Sized),
|
||||
) -> Result<usize, error::Format> {
|
||||
format.format_into(output, Some(self.date), Some(self.time), None)
|
||||
}
|
||||
|
||||
/// Format the `PrimitiveDateTime` using the provided [format
|
||||
/// description](crate::format_description).
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{format_description, macros::datetime};
|
||||
/// let format = format_description::parse("[year]-[month]-[day] [hour]:[minute]:[second]")?;
|
||||
/// assert_eq!(
|
||||
/// datetime!(2020-01-02 03:04:05).format(&format)?,
|
||||
/// "2020-01-02 03:04:05"
|
||||
/// );
|
||||
/// # Ok::<_, time::Error>(())
|
||||
/// ```
|
||||
pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
|
||||
format.format(Some(self.date), Some(self.time), None)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
impl PrimitiveDateTime {
|
||||
/// Parse a `PrimitiveDateTime` from the input using the provided [format
|
||||
/// description](crate::format_description).
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{format_description, macros::datetime, PrimitiveDateTime};
|
||||
/// let format = format_description::parse("[year]-[month]-[day] [hour]:[minute]:[second]")?;
|
||||
/// assert_eq!(
|
||||
/// PrimitiveDateTime::parse("2020-01-02 03:04:05", &format)?,
|
||||
/// datetime!(2020-01-02 03:04:05)
|
||||
/// );
|
||||
/// # Ok::<_, time::Error>(())
|
||||
/// ```
|
||||
pub fn parse(
|
||||
input: &str,
|
||||
description: &(impl Parsable + ?Sized),
|
||||
) -> Result<Self, error::Parse> {
|
||||
description.parse_date_time(input.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for PrimitiveDateTime {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{} {}", self.date, self.time)
|
||||
}
|
||||
}
|
||||
// endregion formatting & parsing
|
||||
|
||||
// region: trait impls
|
||||
impl Add<Duration> for PrimitiveDateTime {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, duration: Duration) -> Self::Output {
|
||||
self.checked_add(duration)
|
||||
.expect("resulting value is out of range")
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<StdDuration> for PrimitiveDateTime {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, duration: StdDuration) -> Self::Output {
|
||||
let (is_next_day, time) = self.time.adjusting_add_std(duration);
|
||||
|
||||
Self {
|
||||
date: if is_next_day {
|
||||
(self.date + duration)
|
||||
.next_day()
|
||||
.expect("resulting value is out of range")
|
||||
} else {
|
||||
self.date + duration
|
||||
},
|
||||
time,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_add_assign!(PrimitiveDateTime: Duration, StdDuration);
|
||||
|
||||
impl Sub<Duration> for PrimitiveDateTime {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, duration: Duration) -> Self::Output {
|
||||
self.checked_sub(duration)
|
||||
.expect("resulting value is out of range")
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<StdDuration> for PrimitiveDateTime {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, duration: StdDuration) -> Self::Output {
|
||||
let (is_previous_day, time) = self.time.adjusting_sub_std(duration);
|
||||
|
||||
Self {
|
||||
date: if is_previous_day {
|
||||
(self.date - duration)
|
||||
.previous_day()
|
||||
.expect("resulting value is out of range")
|
||||
} else {
|
||||
self.date - duration
|
||||
},
|
||||
time,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_sub_assign!(PrimitiveDateTime: Duration, StdDuration);
|
||||
|
||||
impl Sub for PrimitiveDateTime {
|
||||
type Output = Duration;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
(self.date - rhs.date) + (self.time - rhs.time)
|
||||
}
|
||||
}
|
||||
// endregion trait impls
|
||||
216
zeroidc/vendor/time/src/quickcheck.rs
vendored
Normal file
216
zeroidc/vendor/time/src/quickcheck.rs
vendored
Normal file
@@ -0,0 +1,216 @@
|
||||
//! Implementations of the [`quickcheck::Arbitrary`](quickcheck_dep::Arbitrary) trait.
|
||||
//!
|
||||
//! This enables users to write tests such as this, and have test values provided automatically:
|
||||
//!
|
||||
//! ```
|
||||
//! # #![allow(dead_code)]
|
||||
//! # use quickcheck_dep::quickcheck;
|
||||
//! # #[cfg(pretend_we_didnt_rename_the_dependency)]
|
||||
//! use quickcheck::quickcheck;
|
||||
//! use time::Date;
|
||||
//!
|
||||
//! struct DateRange {
|
||||
//! from: Date,
|
||||
//! to: Date,
|
||||
//! }
|
||||
//!
|
||||
//! impl DateRange {
|
||||
//! fn new(from: Date, to: Date) -> Result<Self, ()> {
|
||||
//! Ok(DateRange { from, to })
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! quickcheck! {
|
||||
//! fn date_range_is_well_defined(from: Date, to: Date) -> bool {
|
||||
//! let r = DateRange::new(from, to);
|
||||
//! if from <= to {
|
||||
//! r.is_ok()
|
||||
//! } else {
|
||||
//! r.is_err()
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! An implementation for `Instant` is intentionally omitted since its values are only meaningful in
|
||||
//! relation to a [`Duration`], and obtaining an `Instant` from a [`Duration`] is very simple
|
||||
//! anyway.
|
||||
|
||||
use alloc::boxed::Box;
|
||||
|
||||
use quickcheck_dep::{empty_shrinker, single_shrinker, Arbitrary, Gen};
|
||||
|
||||
use crate::{Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset, Weekday};
|
||||
|
||||
/// Obtain an arbitrary value between the minimum and maximum inclusive.
|
||||
macro_rules! arbitrary_between {
|
||||
($type:ty; $gen:expr, $min:expr, $max:expr) => {{
|
||||
let min = $min;
|
||||
let max = $max;
|
||||
let range = max - min;
|
||||
<$type>::arbitrary($gen).rem_euclid(range + 1) + min
|
||||
}};
|
||||
}
|
||||
|
||||
impl Arbitrary for Date {
|
||||
fn arbitrary(g: &mut Gen) -> Self {
|
||||
Self::from_julian_day_unchecked(arbitrary_between!(
|
||||
i32;
|
||||
g,
|
||||
Self::MIN.to_julian_day(),
|
||||
Self::MAX.to_julian_day()
|
||||
))
|
||||
}
|
||||
|
||||
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
|
||||
Box::new(
|
||||
self.to_ordinal_date()
|
||||
.shrink()
|
||||
.flat_map(|(year, ordinal)| Self::from_ordinal_date(year, ordinal)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Arbitrary for Duration {
|
||||
fn arbitrary(g: &mut Gen) -> Self {
|
||||
Self::nanoseconds_i128(arbitrary_between!(
|
||||
i128;
|
||||
g,
|
||||
Self::MIN.whole_nanoseconds(),
|
||||
Self::MAX.whole_nanoseconds()
|
||||
))
|
||||
}
|
||||
|
||||
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
|
||||
Box::new(
|
||||
(self.subsec_nanoseconds(), self.whole_seconds())
|
||||
.shrink()
|
||||
.map(|(mut nanoseconds, seconds)| {
|
||||
// Coerce the sign if necessary.
|
||||
if (seconds > 0 && nanoseconds < 0) || (seconds < 0 && nanoseconds > 0) {
|
||||
nanoseconds *= -1;
|
||||
}
|
||||
|
||||
Self::new_unchecked(seconds, nanoseconds)
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Arbitrary for Time {
|
||||
fn arbitrary(g: &mut Gen) -> Self {
|
||||
Self::__from_hms_nanos_unchecked(
|
||||
arbitrary_between!(u8; g, 0, 23),
|
||||
arbitrary_between!(u8; g, 0, 59),
|
||||
arbitrary_between!(u8; g, 0, 59),
|
||||
arbitrary_between!(u32; g, 0, 999_999_999),
|
||||
)
|
||||
}
|
||||
|
||||
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
|
||||
Box::new(
|
||||
self.as_hms_nano()
|
||||
.shrink()
|
||||
.map(|(hour, minute, second, nanosecond)| {
|
||||
Self::__from_hms_nanos_unchecked(hour, minute, second, nanosecond)
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Arbitrary for PrimitiveDateTime {
|
||||
fn arbitrary(g: &mut Gen) -> Self {
|
||||
Self::new(<_>::arbitrary(g), <_>::arbitrary(g))
|
||||
}
|
||||
|
||||
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
|
||||
Box::new(
|
||||
(self.date, self.time)
|
||||
.shrink()
|
||||
.map(|(date, time)| Self { date, time }),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Arbitrary for UtcOffset {
|
||||
fn arbitrary(g: &mut Gen) -> Self {
|
||||
let seconds = arbitrary_between!(i32; g, -86_399, 86_399);
|
||||
Self::__from_hms_unchecked(
|
||||
(seconds / 3600) as _,
|
||||
((seconds % 3600) / 60) as _,
|
||||
(seconds % 60) as _,
|
||||
)
|
||||
}
|
||||
|
||||
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
|
||||
Box::new(
|
||||
self.as_hms().shrink().map(|(hours, minutes, seconds)| {
|
||||
Self::__from_hms_unchecked(hours, minutes, seconds)
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Arbitrary for OffsetDateTime {
|
||||
fn arbitrary(g: &mut Gen) -> Self {
|
||||
let datetime = PrimitiveDateTime::arbitrary(g);
|
||||
datetime.assume_offset(<_>::arbitrary(g))
|
||||
}
|
||||
|
||||
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
|
||||
Box::new(
|
||||
(self.utc_datetime.utc_to_offset(self.offset), self.offset)
|
||||
.shrink()
|
||||
.map(|(utc_datetime, offset)| utc_datetime.assume_offset(offset)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Arbitrary for Weekday {
|
||||
fn arbitrary(g: &mut Gen) -> Self {
|
||||
use Weekday::*;
|
||||
match arbitrary_between!(u8; g, 0, 6) {
|
||||
0 => Monday,
|
||||
1 => Tuesday,
|
||||
2 => Wednesday,
|
||||
3 => Thursday,
|
||||
4 => Friday,
|
||||
5 => Saturday,
|
||||
_ => Sunday,
|
||||
}
|
||||
}
|
||||
|
||||
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
|
||||
match self {
|
||||
Self::Monday => empty_shrinker(),
|
||||
_ => single_shrinker(self.previous()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Arbitrary for Month {
|
||||
fn arbitrary(g: &mut Gen) -> Self {
|
||||
use Month::*;
|
||||
match arbitrary_between!(u8; g, 1, 12) {
|
||||
1 => January,
|
||||
2 => February,
|
||||
3 => March,
|
||||
4 => April,
|
||||
5 => May,
|
||||
6 => June,
|
||||
7 => July,
|
||||
8 => August,
|
||||
9 => September,
|
||||
10 => October,
|
||||
11 => November,
|
||||
_ => December,
|
||||
}
|
||||
}
|
||||
|
||||
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
|
||||
match self {
|
||||
Self::January => empty_shrinker(),
|
||||
_ => single_shrinker(self.previous()),
|
||||
}
|
||||
}
|
||||
}
|
||||
93
zeroidc/vendor/time/src/rand.rs
vendored
Normal file
93
zeroidc/vendor/time/src/rand.rs
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
//! Implementation of [`Distribution`] for various structs.
|
||||
|
||||
use rand::distributions::{Distribution, Standard};
|
||||
use rand::Rng;
|
||||
|
||||
use crate::{Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset, Weekday};
|
||||
|
||||
impl Distribution<Time> for Standard {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Time {
|
||||
Time::__from_hms_nanos_unchecked(
|
||||
rng.gen_range(0..24),
|
||||
rng.gen_range(0..60),
|
||||
rng.gen_range(0..60),
|
||||
rng.gen_range(0..1_000_000_000),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Distribution<Date> for Standard {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Date {
|
||||
Date::from_julian_day_unchecked(
|
||||
rng.gen_range(Date::MIN.to_julian_day()..=Date::MAX.to_julian_day()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Distribution<UtcOffset> for Standard {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> UtcOffset {
|
||||
let seconds = rng.gen_range(-86399..=86399);
|
||||
UtcOffset::__from_hms_unchecked(
|
||||
(seconds / 3600) as _,
|
||||
((seconds % 3600) / 60) as _,
|
||||
(seconds % 60) as _,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Distribution<PrimitiveDateTime> for Standard {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> PrimitiveDateTime {
|
||||
PrimitiveDateTime::new(Self.sample(rng), Self.sample(rng))
|
||||
}
|
||||
}
|
||||
|
||||
impl Distribution<OffsetDateTime> for Standard {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> OffsetDateTime {
|
||||
let date_time: PrimitiveDateTime = Self.sample(rng);
|
||||
date_time.assume_offset(Self.sample(rng))
|
||||
}
|
||||
}
|
||||
|
||||
impl Distribution<Duration> for Standard {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Duration {
|
||||
Duration::nanoseconds_i128(
|
||||
rng.gen_range(Duration::MIN.whole_nanoseconds()..=Duration::MAX.whole_nanoseconds()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Distribution<Weekday> for Standard {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Weekday {
|
||||
use Weekday::*;
|
||||
|
||||
match rng.gen_range(0u8..7) {
|
||||
0 => Monday,
|
||||
1 => Tuesday,
|
||||
2 => Wednesday,
|
||||
3 => Thursday,
|
||||
4 => Friday,
|
||||
5 => Saturday,
|
||||
_ => Sunday,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Distribution<Month> for Standard {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Month {
|
||||
use Month::*;
|
||||
match rng.gen_range(1u8..=12) {
|
||||
1 => January,
|
||||
2 => February,
|
||||
3 => March,
|
||||
4 => April,
|
||||
5 => May,
|
||||
6 => June,
|
||||
7 => July,
|
||||
8 => August,
|
||||
9 => September,
|
||||
10 => October,
|
||||
11 => November,
|
||||
_ => December,
|
||||
}
|
||||
}
|
||||
}
|
||||
318
zeroidc/vendor/time/src/serde/mod.rs
vendored
Normal file
318
zeroidc/vendor/time/src/serde/mod.rs
vendored
Normal file
@@ -0,0 +1,318 @@
|
||||
//! Differential formats for serde.
|
||||
// This also includes the serde implementations for all types. This doesn't need to be externally
|
||||
// documented, though.
|
||||
|
||||
// Types with guaranteed stable serde representations. Strings are avoided to allow for optimal
|
||||
// representations in various binary forms.
|
||||
|
||||
/// Consume the next item in a sequence.
|
||||
macro_rules! item {
|
||||
($seq:expr, $name:literal) => {
|
||||
$seq.next_element()?
|
||||
.ok_or_else(|| <A::Error as serde::de::Error>::custom(concat!("expected ", $name)))
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde-well-known")]
|
||||
pub mod rfc2822;
|
||||
#[cfg(feature = "serde-well-known")]
|
||||
pub mod rfc3339;
|
||||
pub mod timestamp;
|
||||
mod visitor;
|
||||
|
||||
use core::marker::PhantomData;
|
||||
|
||||
#[cfg(feature = "serde-human-readable")]
|
||||
use serde::ser::Error as _;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
/// Generate a custom serializer and deserializer from the provided string.
|
||||
///
|
||||
/// The syntax accepted by this macro is the same as [`format_description::parse()`], which can
|
||||
/// be found in [the book](https://time-rs.github.io/book/api/format-description.html).
|
||||
///
|
||||
/// # Usage
|
||||
///
|
||||
/// Invoked as `serde::format_description!(mod_name, Date, "<format string>")`. This puts a
|
||||
/// module named `mod_name` in the current scope that can be used to format `Date` structs. A
|
||||
/// submodule (`mod_name::option`) is also generated for `Option<Date>`. Both modules are only
|
||||
/// visible in the current scope.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use time::OffsetDateTime;
|
||||
/// # use ::serde::{Serialize, Deserialize};
|
||||
/// use time::serde;
|
||||
///
|
||||
/// // Makes a module `mod my_format { ... }`.
|
||||
/// serde::format_description!(my_format, OffsetDateTime, "hour=[hour], minute=[minute]");
|
||||
///
|
||||
/// #[derive(Serialize, Deserialize)]
|
||||
/// struct SerializesWithCustom {
|
||||
/// #[serde(with = "my_format")]
|
||||
/// dt: OffsetDateTime,
|
||||
/// #[serde(with = "my_format::option")]
|
||||
/// maybe_dt: Option<OffsetDateTime>,
|
||||
/// }
|
||||
/// #
|
||||
/// # // otherwise rustdoc tests don't work because we put a module in `main()`
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// [`format_description::parse()`]: crate::format_description::parse()
|
||||
#[cfg(all(feature = "macros", feature = "serde-human-readable"))]
|
||||
pub use time_macros::serde_format_description as format_description;
|
||||
|
||||
use self::visitor::Visitor;
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::format_description::{modifier, Component, FormatItem};
|
||||
use crate::{Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset, Weekday};
|
||||
|
||||
// region: Date
|
||||
/// The format used when serializing and deserializing a human-readable `Date`.
|
||||
#[cfg(feature = "parsing")]
|
||||
const DATE_FORMAT: &[FormatItem<'_>] = &[
|
||||
FormatItem::Component(Component::Year(modifier::Year::default())),
|
||||
FormatItem::Literal(b"-"),
|
||||
FormatItem::Component(Component::Month(modifier::Month::default())),
|
||||
FormatItem::Literal(b"-"),
|
||||
FormatItem::Component(Component::Day(modifier::Day::default())),
|
||||
];
|
||||
|
||||
impl Serialize for Date {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
#[cfg(feature = "serde-human-readable")]
|
||||
if serializer.is_human_readable() {
|
||||
return serializer.serialize_str(&match self.format(&DATE_FORMAT) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return Err(S::Error::custom("failed formatting `Date`")),
|
||||
});
|
||||
}
|
||||
|
||||
(self.year(), self.ordinal()).serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deserialize<'a> for Date {
|
||||
fn deserialize<D: Deserializer<'a>>(deserializer: D) -> Result<Self, D::Error> {
|
||||
deserializer.deserialize_any(Visitor::<Self>(PhantomData))
|
||||
}
|
||||
}
|
||||
// endregion date
|
||||
|
||||
// region: Duration
|
||||
impl Serialize for Duration {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
#[cfg(feature = "serde-human-readable")]
|
||||
if serializer.is_human_readable() {
|
||||
return serializer.collect_str(&format_args!(
|
||||
"{}.{:>09}",
|
||||
self.whole_seconds(),
|
||||
self.subsec_nanoseconds().abs()
|
||||
));
|
||||
}
|
||||
|
||||
(self.whole_seconds(), self.subsec_nanoseconds()).serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deserialize<'a> for Duration {
|
||||
fn deserialize<D: Deserializer<'a>>(deserializer: D) -> Result<Self, D::Error> {
|
||||
deserializer.deserialize_any(Visitor::<Self>(PhantomData))
|
||||
}
|
||||
}
|
||||
// endregion Duration
|
||||
|
||||
// region: OffsetDateTime
|
||||
/// The format used when serializing and deserializing a human-readable `OffsetDateTime`.
|
||||
#[cfg(feature = "parsing")]
|
||||
const OFFSET_DATE_TIME_FORMAT: &[FormatItem<'_>] = &[
|
||||
FormatItem::Compound(DATE_FORMAT),
|
||||
FormatItem::Literal(b" "),
|
||||
FormatItem::Compound(TIME_FORMAT),
|
||||
FormatItem::Literal(b" "),
|
||||
FormatItem::Compound(UTC_OFFSET_FORMAT),
|
||||
];
|
||||
|
||||
impl Serialize for OffsetDateTime {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
#[cfg(feature = "serde-human-readable")]
|
||||
if serializer.is_human_readable() {
|
||||
return serializer.serialize_str(&match self.format(&OFFSET_DATE_TIME_FORMAT) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return Err(S::Error::custom("failed formatting `OffsetDateTime`")),
|
||||
});
|
||||
}
|
||||
|
||||
(
|
||||
self.year(),
|
||||
self.ordinal(),
|
||||
self.hour(),
|
||||
self.minute(),
|
||||
self.second(),
|
||||
self.nanosecond(),
|
||||
self.offset.whole_hours(),
|
||||
self.offset.minutes_past_hour(),
|
||||
self.offset.seconds_past_minute(),
|
||||
)
|
||||
.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deserialize<'a> for OffsetDateTime {
|
||||
fn deserialize<D: Deserializer<'a>>(deserializer: D) -> Result<Self, D::Error> {
|
||||
deserializer.deserialize_any(Visitor::<Self>(PhantomData))
|
||||
}
|
||||
}
|
||||
// endregion OffsetDateTime
|
||||
|
||||
// region: PrimitiveDateTime
|
||||
/// The format used when serializing and deserializing a human-readable `PrimitiveDateTime`.
|
||||
#[cfg(feature = "parsing")]
|
||||
const PRIMITIVE_DATE_TIME_FORMAT: &[FormatItem<'_>] = &[
|
||||
FormatItem::Compound(DATE_FORMAT),
|
||||
FormatItem::Literal(b" "),
|
||||
FormatItem::Compound(TIME_FORMAT),
|
||||
];
|
||||
|
||||
impl Serialize for PrimitiveDateTime {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
#[cfg(feature = "serde-human-readable")]
|
||||
if serializer.is_human_readable() {
|
||||
return serializer.serialize_str(&match self.format(&PRIMITIVE_DATE_TIME_FORMAT) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return Err(<S::Error>::custom("failed formatting `PrimitiveDateTime`")),
|
||||
});
|
||||
}
|
||||
|
||||
(
|
||||
self.year(),
|
||||
self.ordinal(),
|
||||
self.hour(),
|
||||
self.minute(),
|
||||
self.second(),
|
||||
self.nanosecond(),
|
||||
)
|
||||
.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deserialize<'a> for PrimitiveDateTime {
|
||||
fn deserialize<D: Deserializer<'a>>(deserializer: D) -> Result<Self, D::Error> {
|
||||
deserializer.deserialize_any(Visitor::<Self>(PhantomData))
|
||||
}
|
||||
}
|
||||
// endregion PrimitiveDateTime
|
||||
|
||||
// region: Time
|
||||
/// The format used when serializing and deserializing a human-readable `Time`.
|
||||
#[cfg(feature = "parsing")]
|
||||
const TIME_FORMAT: &[FormatItem<'_>] = &[
|
||||
FormatItem::Component(Component::Hour(<modifier::Hour>::default())),
|
||||
FormatItem::Literal(b":"),
|
||||
FormatItem::Component(Component::Minute(<modifier::Minute>::default())),
|
||||
FormatItem::Literal(b":"),
|
||||
FormatItem::Component(Component::Second(<modifier::Second>::default())),
|
||||
FormatItem::Literal(b"."),
|
||||
FormatItem::Component(Component::Subsecond(<modifier::Subsecond>::default())),
|
||||
];
|
||||
|
||||
impl Serialize for Time {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
#[cfg(feature = "serde-human-readable")]
|
||||
if serializer.is_human_readable() {
|
||||
return serializer.serialize_str(&match self.format(&TIME_FORMAT) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return Err(S::Error::custom("failed formatting `Time`")),
|
||||
});
|
||||
}
|
||||
|
||||
(self.hour(), self.minute(), self.second(), self.nanosecond()).serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deserialize<'a> for Time {
|
||||
fn deserialize<D: Deserializer<'a>>(deserializer: D) -> Result<Self, D::Error> {
|
||||
deserializer.deserialize_any(Visitor::<Self>(PhantomData))
|
||||
}
|
||||
}
|
||||
// endregion Time
|
||||
|
||||
// region: UtcOffset
|
||||
/// The format used when serializing and deserializing a human-readable `UtcOffset`.
|
||||
#[cfg(feature = "parsing")]
|
||||
const UTC_OFFSET_FORMAT: &[FormatItem<'_>] = &[
|
||||
FormatItem::Component(Component::OffsetHour(modifier::OffsetHour::default())),
|
||||
FormatItem::Literal(b":"),
|
||||
FormatItem::Component(Component::OffsetMinute(modifier::OffsetMinute::default())),
|
||||
FormatItem::Literal(b":"),
|
||||
FormatItem::Component(Component::OffsetSecond(modifier::OffsetSecond::default())),
|
||||
];
|
||||
|
||||
impl Serialize for UtcOffset {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
#[cfg(feature = "serde-human-readable")]
|
||||
if serializer.is_human_readable() {
|
||||
return serializer.serialize_str(&match self.format(&UTC_OFFSET_FORMAT) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return Err(S::Error::custom("failed formatting `UtcOffset`")),
|
||||
});
|
||||
}
|
||||
|
||||
(
|
||||
self.whole_hours(),
|
||||
self.minutes_past_hour(),
|
||||
self.seconds_past_minute(),
|
||||
)
|
||||
.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deserialize<'a> for UtcOffset {
|
||||
fn deserialize<D: Deserializer<'a>>(deserializer: D) -> Result<Self, D::Error> {
|
||||
deserializer.deserialize_any(Visitor::<Self>(PhantomData))
|
||||
}
|
||||
}
|
||||
// endregion UtcOffset
|
||||
|
||||
// region: Weekday
|
||||
impl Serialize for Weekday {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
#[cfg(feature = "serde-human-readable")]
|
||||
if serializer.is_human_readable() {
|
||||
#[cfg(not(feature = "std"))]
|
||||
use alloc::string::ToString;
|
||||
return self.to_string().serialize(serializer);
|
||||
}
|
||||
|
||||
self.number_from_monday().serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deserialize<'a> for Weekday {
|
||||
fn deserialize<D: Deserializer<'a>>(deserializer: D) -> Result<Self, D::Error> {
|
||||
deserializer.deserialize_any(Visitor::<Self>(PhantomData))
|
||||
}
|
||||
}
|
||||
// endregion Weekday
|
||||
|
||||
// region: Month
|
||||
impl Serialize for Month {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
#[cfg(feature = "serde-human-readable")]
|
||||
if serializer.is_human_readable() {
|
||||
#[cfg(not(feature = "std"))]
|
||||
use alloc::string::String;
|
||||
return self.to_string().serialize(serializer);
|
||||
}
|
||||
|
||||
(*self as u8).serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deserialize<'a> for Month {
|
||||
fn deserialize<D: Deserializer<'a>>(deserializer: D) -> Result<Self, D::Error> {
|
||||
deserializer.deserialize_any(Visitor::<Self>(PhantomData))
|
||||
}
|
||||
}
|
||||
// endregion Month
|
||||
62
zeroidc/vendor/time/src/serde/rfc2822.rs
vendored
Normal file
62
zeroidc/vendor/time/src/serde/rfc2822.rs
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
//! Use the well-known [RFC2822 format] when serializing and deserializing an [`OffsetDateTime`].
|
||||
//!
|
||||
//! Use this module in combination with serde's [`#[with]`][with] attribute.
|
||||
//!
|
||||
//! [RFC2822 format]: https://tools.ietf.org/html/rfc2822#section-3.3
|
||||
//! [with]: https://serde.rs/field-attrs.html#with
|
||||
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use serde::ser::Error as _;
|
||||
use serde::{Deserializer, Serialize, Serializer};
|
||||
|
||||
use super::Visitor;
|
||||
use crate::format_description::well_known::Rfc2822;
|
||||
use crate::OffsetDateTime;
|
||||
|
||||
/// Serialize an [`OffsetDateTime`] using the well-known RFC2822 format.
|
||||
pub fn serialize<S: Serializer>(
|
||||
datetime: &OffsetDateTime,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
datetime
|
||||
.format(&Rfc2822)
|
||||
.map_err(S::Error::custom)?
|
||||
.serialize(serializer)
|
||||
}
|
||||
|
||||
/// Deserialize an [`OffsetDateTime`] from its RFC2822 representation.
|
||||
pub fn deserialize<'a, D: Deserializer<'a>>(deserializer: D) -> Result<OffsetDateTime, D::Error> {
|
||||
deserializer.deserialize_any(Visitor::<Rfc2822>(PhantomData))
|
||||
}
|
||||
|
||||
/// Use the well-known [RFC2822 format] when serializing and deserializing an
|
||||
/// [`Option<OffsetDateTime>`].
|
||||
///
|
||||
/// Use this module in combination with serde's [`#[with]`][with] attribute.
|
||||
///
|
||||
/// [RFC2822 format]: https://tools.ietf.org/html/rfc2822#section-3.3
|
||||
/// [with]: https://serde.rs/field-attrs.html#with
|
||||
pub mod option {
|
||||
#[allow(clippy::wildcard_imports)]
|
||||
use super::*;
|
||||
|
||||
/// Serialize an [`Option<OffsetDateTime>`] using the well-known RFC2822 format.
|
||||
pub fn serialize<S: Serializer>(
|
||||
option: &Option<OffsetDateTime>,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
option
|
||||
.map(|odt| odt.format(&Rfc2822))
|
||||
.transpose()
|
||||
.map_err(S::Error::custom)?
|
||||
.serialize(serializer)
|
||||
}
|
||||
|
||||
/// Deserialize an [`Option<OffsetDateTime>`] from its RFC2822 representation.
|
||||
pub fn deserialize<'a, D: Deserializer<'a>>(
|
||||
deserializer: D,
|
||||
) -> Result<Option<OffsetDateTime>, D::Error> {
|
||||
deserializer.deserialize_option(Visitor::<Option<Rfc2822>>(PhantomData))
|
||||
}
|
||||
}
|
||||
62
zeroidc/vendor/time/src/serde/rfc3339.rs
vendored
Normal file
62
zeroidc/vendor/time/src/serde/rfc3339.rs
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
//! Use the well-known [RFC3339 format] when serializing and deserializing an [`OffsetDateTime`].
|
||||
//!
|
||||
//! Use this module in combination with serde's [`#[with]`][with] attribute.
|
||||
//!
|
||||
//! [RFC3339 format]: https://tools.ietf.org/html/rfc3339#section-5.6
|
||||
//! [with]: https://serde.rs/field-attrs.html#with
|
||||
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use serde::ser::Error as _;
|
||||
use serde::{Deserializer, Serialize, Serializer};
|
||||
|
||||
use super::Visitor;
|
||||
use crate::format_description::well_known::Rfc3339;
|
||||
use crate::OffsetDateTime;
|
||||
|
||||
/// Serialize an [`OffsetDateTime`] using the well-known RFC3339 format.
|
||||
pub fn serialize<S: Serializer>(
|
||||
datetime: &OffsetDateTime,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
datetime
|
||||
.format(&Rfc3339)
|
||||
.map_err(S::Error::custom)?
|
||||
.serialize(serializer)
|
||||
}
|
||||
|
||||
/// Deserialize an [`OffsetDateTime`] from its RFC3339 representation.
|
||||
pub fn deserialize<'a, D: Deserializer<'a>>(deserializer: D) -> Result<OffsetDateTime, D::Error> {
|
||||
deserializer.deserialize_any(Visitor::<Rfc3339>(PhantomData))
|
||||
}
|
||||
|
||||
/// Use the well-known [RFC3339 format] when serializing and deserializing an
|
||||
/// [`Option<OffsetDateTime>`].
|
||||
///
|
||||
/// Use this module in combination with serde's [`#[with]`][with] attribute.
|
||||
///
|
||||
/// [RFC3339 format]: https://tools.ietf.org/html/rfc3339#section-5.6
|
||||
/// [with]: https://serde.rs/field-attrs.html#with
|
||||
pub mod option {
|
||||
#[allow(clippy::wildcard_imports)]
|
||||
use super::*;
|
||||
|
||||
/// Serialize an [`Option<OffsetDateTime>`] using the well-known RFC3339 format.
|
||||
pub fn serialize<S: Serializer>(
|
||||
option: &Option<OffsetDateTime>,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
option
|
||||
.map(|odt| odt.format(&Rfc3339))
|
||||
.transpose()
|
||||
.map_err(S::Error::custom)?
|
||||
.serialize(serializer)
|
||||
}
|
||||
|
||||
/// Deserialize an [`Option<OffsetDateTime>`] from its RFC3339 representation.
|
||||
pub fn deserialize<'a, D: Deserializer<'a>>(
|
||||
deserializer: D,
|
||||
) -> Result<Option<OffsetDateTime>, D::Error> {
|
||||
deserializer.deserialize_option(Visitor::<Option<Rfc3339>>(PhantomData))
|
||||
}
|
||||
}
|
||||
60
zeroidc/vendor/time/src/serde/timestamp.rs
vendored
Normal file
60
zeroidc/vendor/time/src/serde/timestamp.rs
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
//! Treat an [`OffsetDateTime`] as a [Unix timestamp] for the purposes of serde.
|
||||
//!
|
||||
//! Use this module in combination with serde's [`#[with]`][with] attribute.
|
||||
//!
|
||||
//! When deserializing, the offset is assumed to be UTC.
|
||||
//!
|
||||
//! [Unix timestamp]: https://en.wikipedia.org/wiki/Unix_time
|
||||
//! [with]: https://serde.rs/field-attrs.html#with
|
||||
|
||||
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
use crate::OffsetDateTime;
|
||||
|
||||
/// Serialize an `OffsetDateTime` as its Unix timestamp
|
||||
pub fn serialize<S: Serializer>(
|
||||
datetime: &OffsetDateTime,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
datetime.unix_timestamp().serialize(serializer)
|
||||
}
|
||||
|
||||
/// Deserialize an `OffsetDateTime` from its Unix timestamp
|
||||
pub fn deserialize<'a, D: Deserializer<'a>>(deserializer: D) -> Result<OffsetDateTime, D::Error> {
|
||||
OffsetDateTime::from_unix_timestamp(<_>::deserialize(deserializer)?)
|
||||
.map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err))
|
||||
}
|
||||
|
||||
/// Treat an `Option<OffsetDateTime>` as a [Unix timestamp] for the purposes of
|
||||
/// serde.
|
||||
///
|
||||
/// Use this module in combination with serde's [`#[with]`][with] attribute.
|
||||
///
|
||||
/// When deserializing, the offset is assumed to be UTC.
|
||||
///
|
||||
/// [Unix timestamp]: https://en.wikipedia.org/wiki/Unix_time
|
||||
/// [with]: https://serde.rs/field-attrs.html#with
|
||||
pub mod option {
|
||||
#[allow(clippy::wildcard_imports)]
|
||||
use super::*;
|
||||
|
||||
/// Serialize an `Option<OffsetDateTime>` as its Unix timestamp
|
||||
pub fn serialize<S: Serializer>(
|
||||
option: &Option<OffsetDateTime>,
|
||||
serializer: S,
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
option
|
||||
.map(OffsetDateTime::unix_timestamp)
|
||||
.serialize(serializer)
|
||||
}
|
||||
|
||||
/// Deserialize an `Option<OffsetDateTime>` from its Unix timestamp
|
||||
pub fn deserialize<'a, D: Deserializer<'a>>(
|
||||
deserializer: D,
|
||||
) -> Result<Option<OffsetDateTime>, D::Error> {
|
||||
Option::deserialize(deserializer)?
|
||||
.map(OffsetDateTime::from_unix_timestamp)
|
||||
.transpose()
|
||||
.map_err(|err| de::Error::invalid_value(de::Unexpected::Signed(err.value), &err))
|
||||
}
|
||||
}
|
||||
329
zeroidc/vendor/time/src/serde/visitor.rs
vendored
Normal file
329
zeroidc/vendor/time/src/serde/visitor.rs
vendored
Normal file
@@ -0,0 +1,329 @@
|
||||
//! Serde visitor for various types.
|
||||
|
||||
use core::fmt;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use serde::de;
|
||||
#[cfg(feature = "serde-well-known")]
|
||||
use serde::Deserializer;
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
use super::{
|
||||
DATE_FORMAT, OFFSET_DATE_TIME_FORMAT, PRIMITIVE_DATE_TIME_FORMAT, TIME_FORMAT,
|
||||
UTC_OFFSET_FORMAT,
|
||||
};
|
||||
use crate::error::ComponentRange;
|
||||
#[cfg(feature = "serde-well-known")]
|
||||
use crate::format_description::well_known;
|
||||
use crate::{Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset, Weekday};
|
||||
|
||||
/// A serde visitor for various types.
|
||||
pub(super) struct Visitor<T: ?Sized>(pub(super) PhantomData<T>);
|
||||
|
||||
impl<'a> de::Visitor<'a> for Visitor<Date> {
|
||||
type Value = Date;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("a `Date`")
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
fn visit_str<E: de::Error>(self, value: &str) -> Result<Date, E> {
|
||||
Date::parse(value, &DATE_FORMAT).map_err(E::custom)
|
||||
}
|
||||
|
||||
fn visit_seq<A: de::SeqAccess<'a>>(self, mut seq: A) -> Result<Date, A::Error> {
|
||||
let year = item!(seq, "year")?;
|
||||
let ordinal = item!(seq, "day of year")?;
|
||||
Date::from_ordinal_date(year, ordinal).map_err(ComponentRange::into_de_error)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> de::Visitor<'a> for Visitor<Duration> {
|
||||
type Value = Duration;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("a `Duration`")
|
||||
}
|
||||
|
||||
fn visit_str<E: de::Error>(self, value: &str) -> Result<Duration, E> {
|
||||
let (seconds, nanoseconds) = value.split_once('.').ok_or_else(|| {
|
||||
de::Error::invalid_value(de::Unexpected::Str(value), &"a decimal point")
|
||||
})?;
|
||||
|
||||
let seconds = seconds
|
||||
.parse()
|
||||
.map_err(|_| de::Error::invalid_value(de::Unexpected::Str(seconds), &"seconds"))?;
|
||||
let mut nanoseconds = nanoseconds.parse().map_err(|_| {
|
||||
de::Error::invalid_value(de::Unexpected::Str(nanoseconds), &"nanoseconds")
|
||||
})?;
|
||||
|
||||
if seconds < 0 {
|
||||
nanoseconds *= -1;
|
||||
}
|
||||
|
||||
Ok(Duration::new(seconds, nanoseconds))
|
||||
}
|
||||
|
||||
fn visit_seq<A: de::SeqAccess<'a>>(self, mut seq: A) -> Result<Duration, A::Error> {
|
||||
let seconds = item!(seq, "seconds")?;
|
||||
let nanoseconds = item!(seq, "nanoseconds")?;
|
||||
Ok(Duration::new(seconds, nanoseconds))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> de::Visitor<'a> for Visitor<OffsetDateTime> {
|
||||
type Value = OffsetDateTime;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("an `OffsetDateTime`")
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
fn visit_str<E: de::Error>(self, value: &str) -> Result<OffsetDateTime, E> {
|
||||
OffsetDateTime::parse(value, &OFFSET_DATE_TIME_FORMAT).map_err(E::custom)
|
||||
}
|
||||
|
||||
fn visit_seq<A: de::SeqAccess<'a>>(self, mut seq: A) -> Result<OffsetDateTime, A::Error> {
|
||||
let year = item!(seq, "year")?;
|
||||
let ordinal = item!(seq, "day of year")?;
|
||||
let hour = item!(seq, "hour")?;
|
||||
let minute = item!(seq, "minute")?;
|
||||
let second = item!(seq, "second")?;
|
||||
let nanosecond = item!(seq, "nanosecond")?;
|
||||
let offset_hours = item!(seq, "offset hours")?;
|
||||
let offset_minutes = item!(seq, "offset minutes")?;
|
||||
let offset_seconds = item!(seq, "offset seconds")?;
|
||||
|
||||
Date::from_ordinal_date(year, ordinal)
|
||||
.and_then(|date| date.with_hms_nano(hour, minute, second, nanosecond))
|
||||
.and_then(|datetime| {
|
||||
UtcOffset::from_hms(offset_hours, offset_minutes, offset_seconds)
|
||||
.map(|offset| datetime.assume_offset(offset))
|
||||
})
|
||||
.map_err(ComponentRange::into_de_error)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> de::Visitor<'a> for Visitor<PrimitiveDateTime> {
|
||||
type Value = PrimitiveDateTime;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("a `PrimitiveDateTime`")
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
fn visit_str<E: de::Error>(self, value: &str) -> Result<PrimitiveDateTime, E> {
|
||||
PrimitiveDateTime::parse(value, &PRIMITIVE_DATE_TIME_FORMAT).map_err(E::custom)
|
||||
}
|
||||
|
||||
fn visit_seq<A: de::SeqAccess<'a>>(self, mut seq: A) -> Result<PrimitiveDateTime, A::Error> {
|
||||
let year = item!(seq, "year")?;
|
||||
let ordinal = item!(seq, "day of year")?;
|
||||
let hour = item!(seq, "hour")?;
|
||||
let minute = item!(seq, "minute")?;
|
||||
let second = item!(seq, "second")?;
|
||||
let nanosecond = item!(seq, "nanosecond")?;
|
||||
|
||||
Date::from_ordinal_date(year, ordinal)
|
||||
.and_then(|date| date.with_hms_nano(hour, minute, second, nanosecond))
|
||||
.map_err(ComponentRange::into_de_error)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> de::Visitor<'a> for Visitor<Time> {
|
||||
type Value = Time;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("a `Time`")
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
fn visit_str<E: de::Error>(self, value: &str) -> Result<Time, E> {
|
||||
Time::parse(value, &TIME_FORMAT).map_err(E::custom)
|
||||
}
|
||||
|
||||
fn visit_seq<A: de::SeqAccess<'a>>(self, mut seq: A) -> Result<Time, A::Error> {
|
||||
let hour = item!(seq, "hour")?;
|
||||
let minute = item!(seq, "minute")?;
|
||||
let second = item!(seq, "second")?;
|
||||
let nanosecond = item!(seq, "nanosecond")?;
|
||||
|
||||
Time::from_hms_nano(hour, minute, second, nanosecond).map_err(ComponentRange::into_de_error)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> de::Visitor<'a> for Visitor<UtcOffset> {
|
||||
type Value = UtcOffset;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("a `UtcOffset`")
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
fn visit_str<E: de::Error>(self, value: &str) -> Result<UtcOffset, E> {
|
||||
UtcOffset::parse(value, &UTC_OFFSET_FORMAT).map_err(E::custom)
|
||||
}
|
||||
|
||||
fn visit_seq<A: de::SeqAccess<'a>>(self, mut seq: A) -> Result<UtcOffset, A::Error> {
|
||||
let hours = item!(seq, "offset hours")?;
|
||||
let minutes = item!(seq, "offset minutes")?;
|
||||
let seconds = item!(seq, "offset seconds")?;
|
||||
|
||||
UtcOffset::from_hms(hours, minutes, seconds).map_err(ComponentRange::into_de_error)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> de::Visitor<'a> for Visitor<Weekday> {
|
||||
type Value = Weekday;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("a `Weekday`")
|
||||
}
|
||||
|
||||
fn visit_str<E: de::Error>(self, value: &str) -> Result<Weekday, E> {
|
||||
match value {
|
||||
"Monday" => Ok(Weekday::Monday),
|
||||
"Tuesday" => Ok(Weekday::Tuesday),
|
||||
"Wednesday" => Ok(Weekday::Wednesday),
|
||||
"Thursday" => Ok(Weekday::Thursday),
|
||||
"Friday" => Ok(Weekday::Friday),
|
||||
"Saturday" => Ok(Weekday::Saturday),
|
||||
"Sunday" => Ok(Weekday::Sunday),
|
||||
_ => Err(E::invalid_value(de::Unexpected::Str(value), &"a `Weekday`")),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_u8<E: de::Error>(self, value: u8) -> Result<Weekday, E> {
|
||||
match value {
|
||||
1 => Ok(Weekday::Monday),
|
||||
2 => Ok(Weekday::Tuesday),
|
||||
3 => Ok(Weekday::Wednesday),
|
||||
4 => Ok(Weekday::Thursday),
|
||||
5 => Ok(Weekday::Friday),
|
||||
6 => Ok(Weekday::Saturday),
|
||||
7 => Ok(Weekday::Sunday),
|
||||
_ => Err(E::invalid_value(
|
||||
de::Unexpected::Unsigned(value.into()),
|
||||
&"a value in the range 1..=7",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> de::Visitor<'a> for Visitor<Month> {
|
||||
type Value = Month;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("a `Month`")
|
||||
}
|
||||
|
||||
fn visit_str<E: de::Error>(self, value: &str) -> Result<Month, E> {
|
||||
match value {
|
||||
"January" => Ok(Month::January),
|
||||
"February" => Ok(Month::February),
|
||||
"March" => Ok(Month::March),
|
||||
"April" => Ok(Month::April),
|
||||
"May" => Ok(Month::May),
|
||||
"June" => Ok(Month::June),
|
||||
"July" => Ok(Month::July),
|
||||
"August" => Ok(Month::August),
|
||||
"September" => Ok(Month::September),
|
||||
"October" => Ok(Month::October),
|
||||
"November" => Ok(Month::November),
|
||||
"December" => Ok(Month::December),
|
||||
_ => Err(E::invalid_value(de::Unexpected::Str(value), &"a `Month`")),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_u8<E: de::Error>(self, value: u8) -> Result<Month, E> {
|
||||
match value {
|
||||
1 => Ok(Month::January),
|
||||
2 => Ok(Month::February),
|
||||
3 => Ok(Month::March),
|
||||
4 => Ok(Month::April),
|
||||
5 => Ok(Month::May),
|
||||
6 => Ok(Month::June),
|
||||
7 => Ok(Month::July),
|
||||
8 => Ok(Month::August),
|
||||
9 => Ok(Month::September),
|
||||
10 => Ok(Month::October),
|
||||
11 => Ok(Month::November),
|
||||
12 => Ok(Month::December),
|
||||
_ => Err(E::invalid_value(
|
||||
de::Unexpected::Unsigned(value.into()),
|
||||
&"a value in the range 1..=12",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde-well-known")]
|
||||
impl<'a> de::Visitor<'a> for Visitor<well_known::Rfc2822> {
|
||||
type Value = OffsetDateTime;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("an RFC2822-formatted `OffsetDateTime`")
|
||||
}
|
||||
|
||||
fn visit_str<E: de::Error>(self, value: &str) -> Result<OffsetDateTime, E> {
|
||||
OffsetDateTime::parse(value, &well_known::Rfc2822).map_err(E::custom)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde-well-known")]
|
||||
impl<'a> de::Visitor<'a> for Visitor<Option<well_known::Rfc2822>> {
|
||||
type Value = Option<OffsetDateTime>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("an RFC2822-formatted `Option<OffsetDateTime>`")
|
||||
}
|
||||
|
||||
fn visit_some<D: Deserializer<'a>>(
|
||||
self,
|
||||
deserializer: D,
|
||||
) -> Result<Option<OffsetDateTime>, D::Error> {
|
||||
deserializer
|
||||
.deserialize_any(Visitor::<well_known::Rfc2822>(PhantomData))
|
||||
.map(Some)
|
||||
}
|
||||
|
||||
fn visit_none<E: de::Error>(self) -> Result<Option<OffsetDateTime>, E> {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde-well-known")]
|
||||
impl<'a> de::Visitor<'a> for Visitor<well_known::Rfc3339> {
|
||||
type Value = OffsetDateTime;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("an RFC3339-formatted `OffsetDateTime`")
|
||||
}
|
||||
|
||||
fn visit_str<E: de::Error>(self, value: &str) -> Result<OffsetDateTime, E> {
|
||||
OffsetDateTime::parse(value, &well_known::Rfc3339).map_err(E::custom)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde-well-known")]
|
||||
impl<'a> de::Visitor<'a> for Visitor<Option<well_known::Rfc3339>> {
|
||||
type Value = Option<OffsetDateTime>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("an RFC3339-formatted `Option<OffsetDateTime>`")
|
||||
}
|
||||
|
||||
fn visit_some<D: Deserializer<'a>>(
|
||||
self,
|
||||
deserializer: D,
|
||||
) -> Result<Option<OffsetDateTime>, D::Error> {
|
||||
deserializer
|
||||
.deserialize_any(Visitor::<well_known::Rfc3339>(PhantomData))
|
||||
.map(Some)
|
||||
}
|
||||
|
||||
fn visit_none<E: de::Error>(self) -> Result<Option<OffsetDateTime>, E> {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
7
zeroidc/vendor/time/src/sys/local_offset_at/imp.rs
vendored
Normal file
7
zeroidc/vendor/time/src/sys/local_offset_at/imp.rs
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
//! A fallback for any OS not covered.
|
||||
|
||||
use crate::{OffsetDateTime, UtcOffset};
|
||||
|
||||
pub(super) fn local_offset_at(_datetime: OffsetDateTime) -> Option<UtcOffset> {
|
||||
None
|
||||
}
|
||||
13
zeroidc/vendor/time/src/sys/local_offset_at/mod.rs
vendored
Normal file
13
zeroidc/vendor/time/src/sys/local_offset_at/mod.rs
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
//! A method to obtain the local offset from UTC.
|
||||
|
||||
#[cfg_attr(target_family = "windows", path = "windows.rs")]
|
||||
#[cfg_attr(target_family = "unix", path = "unix.rs")]
|
||||
mod imp;
|
||||
|
||||
use crate::{OffsetDateTime, UtcOffset};
|
||||
|
||||
/// Attempt to obtain the system's UTC offset. If the offset cannot be determined, `None` is
|
||||
/// returned.
|
||||
pub(crate) fn local_offset_at(datetime: OffsetDateTime) -> Option<UtcOffset> {
|
||||
imp::local_offset_at(datetime)
|
||||
}
|
||||
126
zeroidc/vendor/time/src/sys/local_offset_at/unix.rs
vendored
Normal file
126
zeroidc/vendor/time/src/sys/local_offset_at/unix.rs
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
//! Get the system's UTC offset on Unix.
|
||||
|
||||
use core::convert::TryInto;
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use crate::{OffsetDateTime, UtcOffset};
|
||||
|
||||
/// Convert the given Unix timestamp to a `libc::tm`. Returns `None` on any error.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This method must only be called when the process is single-threaded.
|
||||
///
|
||||
/// This method will remain `unsafe` until `std::env::set_var` is deprecated or has its behavior
|
||||
/// altered. This method is, on its own, safe. It is the presence of a safe, unsound way to set
|
||||
/// environment variables that makes it unsafe.
|
||||
unsafe fn timestamp_to_tm(timestamp: i64) -> Option<libc::tm> {
|
||||
extern "C" {
|
||||
#[cfg_attr(target_os = "netbsd", link_name = "__tzset50")]
|
||||
fn tzset();
|
||||
}
|
||||
|
||||
// The exact type of `timestamp` beforehand can vary, so this conversion is necessary.
|
||||
#[allow(clippy::useless_conversion)]
|
||||
let timestamp = timestamp.try_into().ok()?;
|
||||
|
||||
let mut tm = MaybeUninit::uninit();
|
||||
|
||||
// Update timezone information from system. `localtime_r` does not do this for us.
|
||||
//
|
||||
// Safety: tzset is thread-safe.
|
||||
unsafe { tzset() };
|
||||
|
||||
// Safety: We are calling a system API, which mutates the `tm` variable. If a null
|
||||
// pointer is returned, an error occurred.
|
||||
let tm_ptr = unsafe { libc::localtime_r(×tamp, tm.as_mut_ptr()) };
|
||||
|
||||
if tm_ptr.is_null() {
|
||||
None
|
||||
} else {
|
||||
// Safety: The value was initialized, as we no longer have a null pointer.
|
||||
Some(unsafe { tm.assume_init() })
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a `libc::tm` to a `UtcOffset`. Returns `None` on any error.
|
||||
// `tm_gmtoff` extension
|
||||
#[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
|
||||
fn tm_to_offset(tm: libc::tm) -> Option<UtcOffset> {
|
||||
let seconds: i32 = tm.tm_gmtoff.try_into().ok()?;
|
||||
UtcOffset::from_hms(
|
||||
(seconds / 3_600) as _,
|
||||
((seconds / 60) % 60) as _,
|
||||
(seconds % 60) as _,
|
||||
)
|
||||
.ok()
|
||||
}
|
||||
|
||||
/// Convert a `libc::tm` to a `UtcOffset`. Returns `None` on any error.
|
||||
// Solaris/Illumos is unsound and requires opting into.
|
||||
#[cfg(all(
|
||||
not(unsound_local_offset),
|
||||
any(target_os = "solaris", target_os = "illumos")
|
||||
))]
|
||||
#[allow(unused_variables, clippy::missing_const_for_fn)]
|
||||
fn tm_to_offset(tm: libc::tm) -> Option<UtcOffset> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Convert a `libc::tm` to a `UtcOffset`. Returns `None` on any error.
|
||||
#[cfg(all(
|
||||
unsound_local_offset,
|
||||
any(target_os = "solaris", target_os = "illumos")
|
||||
))]
|
||||
fn tm_to_offset(tm: libc::tm) -> Option<UtcOffset> {
|
||||
use core::convert::TryFrom;
|
||||
|
||||
use crate::Date;
|
||||
|
||||
let mut tm = tm;
|
||||
if tm.tm_sec == 60 {
|
||||
// Leap seconds are not currently supported.
|
||||
tm.tm_sec = 59;
|
||||
}
|
||||
|
||||
let local_timestamp =
|
||||
Date::from_ordinal_date(1900 + tm.tm_year, u16::try_from(tm.tm_yday).ok()? + 1)
|
||||
.ok()?
|
||||
.with_hms(
|
||||
tm.tm_hour.try_into().ok()?,
|
||||
tm.tm_min.try_into().ok()?,
|
||||
tm.tm_sec.try_into().ok()?,
|
||||
)
|
||||
.ok()?
|
||||
.assume_utc()
|
||||
.unix_timestamp();
|
||||
|
||||
let diff_secs: i32 = (local_timestamp - datetime.unix_timestamp())
|
||||
.try_into()
|
||||
.ok()?;
|
||||
|
||||
UtcOffset::from_hms(
|
||||
(diff_secs / 3_600) as _,
|
||||
((diff_secs / 60) % 60) as _,
|
||||
(diff_secs % 60) as _,
|
||||
)
|
||||
.ok()
|
||||
}
|
||||
|
||||
/// Obtain the system's UTC offset.
|
||||
pub(super) fn local_offset_at(datetime: OffsetDateTime) -> Option<UtcOffset> {
|
||||
// Ensure that the process is single-threaded unless the user has explicitly opted out of this
|
||||
// check. This is to prevent issues with the environment being mutated by a different thread in
|
||||
// the process while execution of this function is taking place, which can cause a segmentation
|
||||
// fault by dereferencing a dangling pointer.
|
||||
// If the `num_threads` crate is incapable of determining the number of running threads, then
|
||||
// we conservatively return `None` to avoid a soundness bug.
|
||||
if !cfg!(unsound_local_offset) && num_threads::is_single_threaded() != Some(true) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Safety: We have just confirmed that the process is single-threaded or the user has explicitly
|
||||
// opted out of soundness.
|
||||
let tm = unsafe { timestamp_to_tm(datetime.unix_timestamp()) }?;
|
||||
tm_to_offset(tm)
|
||||
}
|
||||
115
zeroidc/vendor/time/src/sys/local_offset_at/windows.rs
vendored
Normal file
115
zeroidc/vendor/time/src/sys/local_offset_at/windows.rs
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
//! Get the system's UTC offset on Windows.
|
||||
|
||||
use core::convert::TryInto;
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use crate::{OffsetDateTime, UtcOffset};
|
||||
|
||||
// ffi: WINAPI FILETIME struct
|
||||
#[repr(C)]
|
||||
#[allow(non_snake_case)]
|
||||
struct FileTime {
|
||||
dwLowDateTime: u32,
|
||||
dwHighDateTime: u32,
|
||||
}
|
||||
|
||||
// ffi: WINAPI SYSTEMTIME struct
|
||||
#[repr(C)]
|
||||
#[allow(non_snake_case)]
|
||||
struct SystemTime {
|
||||
wYear: u16,
|
||||
wMonth: u16,
|
||||
wDayOfWeek: u16,
|
||||
wDay: u16,
|
||||
wHour: u16,
|
||||
wMinute: u16,
|
||||
wSecond: u16,
|
||||
wMilliseconds: u16,
|
||||
}
|
||||
|
||||
#[link(name = "kernel32")]
|
||||
extern "system" {
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/timezoneapi/nf-timezoneapi-systemtimetofiletime
|
||||
fn SystemTimeToFileTime(lpSystemTime: *const SystemTime, lpFileTime: *mut FileTime) -> i32;
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/timezoneapi/nf-timezoneapi-systemtimetotzspecificlocaltime
|
||||
fn SystemTimeToTzSpecificLocalTime(
|
||||
lpTimeZoneInformation: *const std::ffi::c_void, // We only pass `nullptr` here
|
||||
lpUniversalTime: *const SystemTime,
|
||||
lpLocalTime: *mut SystemTime,
|
||||
) -> i32;
|
||||
}
|
||||
|
||||
/// Convert a `SYSTEMTIME` to a `FILETIME`. Returns `None` if any error occurred.
|
||||
fn systemtime_to_filetime(systime: &SystemTime) -> Option<FileTime> {
|
||||
let mut ft = MaybeUninit::uninit();
|
||||
|
||||
// Safety: `SystemTimeToFileTime` is thread-safe.
|
||||
if 0 == unsafe { SystemTimeToFileTime(systime, ft.as_mut_ptr()) } {
|
||||
// failed
|
||||
None
|
||||
} else {
|
||||
// Safety: The call succeeded.
|
||||
Some(unsafe { ft.assume_init() })
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a `FILETIME` to an `i64`, representing a number of seconds.
|
||||
fn filetime_to_secs(filetime: &FileTime) -> i64 {
|
||||
/// FILETIME represents 100-nanosecond intervals
|
||||
const FT_TO_SECS: i64 = 10_000_000;
|
||||
((filetime.dwHighDateTime as i64) << 32 | filetime.dwLowDateTime as i64) / FT_TO_SECS
|
||||
}
|
||||
|
||||
/// Convert an [`OffsetDateTime`] to a `SYSTEMTIME`.
|
||||
fn offset_to_systemtime(datetime: OffsetDateTime) -> SystemTime {
|
||||
let (_, month, day_of_month) = datetime.to_offset(UtcOffset::UTC).date().to_calendar_date();
|
||||
SystemTime {
|
||||
wYear: datetime.year() as _,
|
||||
wMonth: month as _,
|
||||
wDay: day_of_month as _,
|
||||
wDayOfWeek: 0, // ignored
|
||||
wHour: datetime.hour() as _,
|
||||
wMinute: datetime.minute() as _,
|
||||
wSecond: datetime.second() as _,
|
||||
wMilliseconds: datetime.millisecond(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Obtain the system's UTC offset.
|
||||
pub(super) fn local_offset_at(datetime: OffsetDateTime) -> Option<UtcOffset> {
|
||||
// This function falls back to UTC if any system call fails.
|
||||
let systime_utc = offset_to_systemtime(datetime.to_offset(UtcOffset::UTC));
|
||||
|
||||
// Safety: `local_time` is only read if it is properly initialized, and
|
||||
// `SystemTimeToTzSpecificLocalTime` is thread-safe.
|
||||
let systime_local = unsafe {
|
||||
let mut local_time = MaybeUninit::uninit();
|
||||
|
||||
if 0 == SystemTimeToTzSpecificLocalTime(
|
||||
core::ptr::null(), // use system's current timezone
|
||||
&systime_utc,
|
||||
local_time.as_mut_ptr(),
|
||||
) {
|
||||
// call failed
|
||||
return None;
|
||||
} else {
|
||||
local_time.assume_init()
|
||||
}
|
||||
};
|
||||
|
||||
// Convert SYSTEMTIMEs to FILETIMEs so we can perform arithmetic on them.
|
||||
let ft_system = systemtime_to_filetime(&systime_utc)?;
|
||||
let ft_local = systemtime_to_filetime(&systime_local)?;
|
||||
|
||||
let diff_secs: i32 = (filetime_to_secs(&ft_local) - filetime_to_secs(&ft_system))
|
||||
.try_into()
|
||||
.ok()?;
|
||||
|
||||
UtcOffset::from_hms(
|
||||
(diff_secs / 3_600) as _,
|
||||
((diff_secs / 60) % 60) as _,
|
||||
(diff_secs % 60) as _,
|
||||
)
|
||||
.ok()
|
||||
}
|
||||
9
zeroidc/vendor/time/src/sys/mod.rs
vendored
Normal file
9
zeroidc/vendor/time/src/sys/mod.rs
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
//! Functions with a common interface that rely on system calls.
|
||||
|
||||
#![allow(unsafe_code)] // We're interfacing with system calls.
|
||||
|
||||
#[cfg(feature = "local-offset")]
|
||||
mod local_offset_at;
|
||||
|
||||
#[cfg(feature = "local-offset")]
|
||||
pub(crate) use local_offset_at::local_offset_at;
|
||||
752
zeroidc/vendor/time/src/time.rs
vendored
Normal file
752
zeroidc/vendor/time/src/time.rs
vendored
Normal file
@@ -0,0 +1,752 @@
|
||||
//! The [`Time`] struct and its associated `impl`s.
|
||||
|
||||
use core::fmt;
|
||||
use core::ops::{Add, Sub};
|
||||
use core::time::Duration as StdDuration;
|
||||
#[cfg(feature = "formatting")]
|
||||
use std::io;
|
||||
|
||||
#[cfg(feature = "formatting")]
|
||||
use crate::formatting::Formattable;
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::parsing::Parsable;
|
||||
use crate::util::DateAdjustment;
|
||||
use crate::{error, Duration};
|
||||
|
||||
/// By explicitly inserting this enum where padding is expected, the compiler is able to better
|
||||
/// perform niche value optimization.
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub(crate) enum Padding {
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
Optimize,
|
||||
}
|
||||
|
||||
/// The clock time within a given date. Nanosecond precision.
|
||||
///
|
||||
/// All minutes are assumed to have exactly 60 seconds; no attempt is made to handle leap seconds
|
||||
/// (either positive or negative).
|
||||
///
|
||||
/// When comparing two `Time`s, they are assumed to be in the same calendar date.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct Time {
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
hour: u8,
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
minute: u8,
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
second: u8,
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
nanosecond: u32,
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
padding: Padding,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Time {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Time")
|
||||
.field("hour", &self.hour)
|
||||
.field("minute", &self.minute)
|
||||
.field("second", &self.second)
|
||||
.field("nanosecond", &self.nanosecond)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Time {
|
||||
/// Create a `Time` that is exactly midnight.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{Time, macros::time};
|
||||
/// assert_eq!(Time::MIDNIGHT, time!(0:00));
|
||||
/// ```
|
||||
pub const MIDNIGHT: Self = Self::__from_hms_nanos_unchecked(0, 0, 0, 0);
|
||||
|
||||
/// The smallest value that can be represented by `Time`.
|
||||
///
|
||||
/// `00:00:00.0`
|
||||
pub(crate) const MIN: Self = Self::__from_hms_nanos_unchecked(0, 0, 0, 0);
|
||||
|
||||
/// The largest value that can be represented by `Time`.
|
||||
///
|
||||
/// `23:59:59.999_999_999`
|
||||
pub(crate) const MAX: Self = Self::__from_hms_nanos_unchecked(23, 59, 59, 999_999_999);
|
||||
|
||||
// region: constructors
|
||||
/// Create a `Time` from its components.
|
||||
#[doc(hidden)]
|
||||
pub const fn __from_hms_nanos_unchecked(
|
||||
hour: u8,
|
||||
minute: u8,
|
||||
second: u8,
|
||||
nanosecond: u32,
|
||||
) -> Self {
|
||||
Self {
|
||||
hour,
|
||||
minute,
|
||||
second,
|
||||
nanosecond,
|
||||
padding: Padding::Optimize,
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempt to create a `Time` from the hour, minute, and second.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::Time;
|
||||
/// assert!(Time::from_hms(1, 2, 3).is_ok());
|
||||
/// ```
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::Time;
|
||||
/// assert!(Time::from_hms(24, 0, 0).is_err()); // 24 isn't a valid hour.
|
||||
/// assert!(Time::from_hms(0, 60, 0).is_err()); // 60 isn't a valid minute.
|
||||
/// assert!(Time::from_hms(0, 0, 60).is_err()); // 60 isn't a valid second.
|
||||
/// ```
|
||||
pub const fn from_hms(hour: u8, minute: u8, second: u8) -> Result<Self, error::ComponentRange> {
|
||||
ensure_value_in_range!(hour in 0 => 23);
|
||||
ensure_value_in_range!(minute in 0 => 59);
|
||||
ensure_value_in_range!(second in 0 => 59);
|
||||
Ok(Self::__from_hms_nanos_unchecked(hour, minute, second, 0))
|
||||
}
|
||||
|
||||
/// Attempt to create a `Time` from the hour, minute, second, and millisecond.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::Time;
|
||||
/// assert!(Time::from_hms_milli(1, 2, 3, 4).is_ok());
|
||||
/// ```
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::Time;
|
||||
/// assert!(Time::from_hms_milli(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
|
||||
/// assert!(Time::from_hms_milli(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
|
||||
/// assert!(Time::from_hms_milli(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
|
||||
/// assert!(Time::from_hms_milli(0, 0, 0, 1_000).is_err()); // 1_000 isn't a valid millisecond.
|
||||
/// ```
|
||||
pub const fn from_hms_milli(
|
||||
hour: u8,
|
||||
minute: u8,
|
||||
second: u8,
|
||||
millisecond: u16,
|
||||
) -> Result<Self, error::ComponentRange> {
|
||||
ensure_value_in_range!(hour in 0 => 23);
|
||||
ensure_value_in_range!(minute in 0 => 59);
|
||||
ensure_value_in_range!(second in 0 => 59);
|
||||
ensure_value_in_range!(millisecond in 0 => 999);
|
||||
Ok(Self::__from_hms_nanos_unchecked(
|
||||
hour,
|
||||
minute,
|
||||
second,
|
||||
millisecond as u32 * 1_000_000,
|
||||
))
|
||||
}
|
||||
|
||||
/// Attempt to create a `Time` from the hour, minute, second, and microsecond.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::Time;
|
||||
/// assert!(Time::from_hms_micro(1, 2, 3, 4).is_ok());
|
||||
/// ```
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::Time;
|
||||
/// assert!(Time::from_hms_micro(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
|
||||
/// assert!(Time::from_hms_micro(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
|
||||
/// assert!(Time::from_hms_micro(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
|
||||
/// assert!(Time::from_hms_micro(0, 0, 0, 1_000_000).is_err()); // 1_000_000 isn't a valid microsecond.
|
||||
/// ```
|
||||
pub const fn from_hms_micro(
|
||||
hour: u8,
|
||||
minute: u8,
|
||||
second: u8,
|
||||
microsecond: u32,
|
||||
) -> Result<Self, error::ComponentRange> {
|
||||
ensure_value_in_range!(hour in 0 => 23);
|
||||
ensure_value_in_range!(minute in 0 => 59);
|
||||
ensure_value_in_range!(second in 0 => 59);
|
||||
ensure_value_in_range!(microsecond in 0 => 999_999);
|
||||
Ok(Self::__from_hms_nanos_unchecked(
|
||||
hour,
|
||||
minute,
|
||||
second,
|
||||
microsecond * 1_000,
|
||||
))
|
||||
}
|
||||
|
||||
/// Attempt to create a `Time` from the hour, minute, second, and nanosecond.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::Time;
|
||||
/// assert!(Time::from_hms_nano(1, 2, 3, 4).is_ok());
|
||||
/// ```
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::Time;
|
||||
/// assert!(Time::from_hms_nano(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
|
||||
/// assert!(Time::from_hms_nano(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
|
||||
/// assert!(Time::from_hms_nano(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
|
||||
/// assert!(Time::from_hms_nano(0, 0, 0, 1_000_000_000).is_err()); // 1_000_000_000 isn't a valid nanosecond.
|
||||
/// ```
|
||||
pub const fn from_hms_nano(
|
||||
hour: u8,
|
||||
minute: u8,
|
||||
second: u8,
|
||||
nanosecond: u32,
|
||||
) -> Result<Self, error::ComponentRange> {
|
||||
ensure_value_in_range!(hour in 0 => 23);
|
||||
ensure_value_in_range!(minute in 0 => 59);
|
||||
ensure_value_in_range!(second in 0 => 59);
|
||||
ensure_value_in_range!(nanosecond in 0 => 999_999_999);
|
||||
Ok(Self::__from_hms_nanos_unchecked(
|
||||
hour, minute, second, nanosecond,
|
||||
))
|
||||
}
|
||||
// endregion constructors
|
||||
|
||||
// region: getters
|
||||
/// Get the clock hour, minute, and second.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::time;
|
||||
/// assert_eq!(time!(0:00:00).as_hms(), (0, 0, 0));
|
||||
/// assert_eq!(time!(23:59:59).as_hms(), (23, 59, 59));
|
||||
/// ```
|
||||
pub const fn as_hms(self) -> (u8, u8, u8) {
|
||||
(self.hour, self.minute, self.second)
|
||||
}
|
||||
|
||||
/// Get the clock hour, minute, second, and millisecond.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::time;
|
||||
/// assert_eq!(time!(0:00:00).as_hms_milli(), (0, 0, 0, 0));
|
||||
/// assert_eq!(time!(23:59:59.999).as_hms_milli(), (23, 59, 59, 999));
|
||||
/// ```
|
||||
pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
|
||||
(
|
||||
self.hour,
|
||||
self.minute,
|
||||
self.second,
|
||||
(self.nanosecond / 1_000_000) as u16,
|
||||
)
|
||||
}
|
||||
|
||||
/// Get the clock hour, minute, second, and microsecond.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::time;
|
||||
/// assert_eq!(time!(0:00:00).as_hms_micro(), (0, 0, 0, 0));
|
||||
/// assert_eq!(
|
||||
/// time!(23:59:59.999_999).as_hms_micro(),
|
||||
/// (23, 59, 59, 999_999)
|
||||
/// );
|
||||
/// ```
|
||||
pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
|
||||
(self.hour, self.minute, self.second, self.nanosecond / 1_000)
|
||||
}
|
||||
|
||||
/// Get the clock hour, minute, second, and nanosecond.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::time;
|
||||
/// assert_eq!(time!(0:00:00).as_hms_nano(), (0, 0, 0, 0));
|
||||
/// assert_eq!(
|
||||
/// time!(23:59:59.999_999_999).as_hms_nano(),
|
||||
/// (23, 59, 59, 999_999_999)
|
||||
/// );
|
||||
/// ```
|
||||
pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
|
||||
(self.hour, self.minute, self.second, self.nanosecond)
|
||||
}
|
||||
|
||||
/// Get the clock hour.
|
||||
///
|
||||
/// The returned value will always be in the range `0..24`.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::time;
|
||||
/// assert_eq!(time!(0:00:00).hour(), 0);
|
||||
/// assert_eq!(time!(23:59:59).hour(), 23);
|
||||
/// ```
|
||||
pub const fn hour(self) -> u8 {
|
||||
self.hour
|
||||
}
|
||||
|
||||
/// Get the minute within the hour.
|
||||
///
|
||||
/// The returned value will always be in the range `0..60`.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::time;
|
||||
/// assert_eq!(time!(0:00:00).minute(), 0);
|
||||
/// assert_eq!(time!(23:59:59).minute(), 59);
|
||||
/// ```
|
||||
pub const fn minute(self) -> u8 {
|
||||
self.minute
|
||||
}
|
||||
|
||||
/// Get the second within the minute.
|
||||
///
|
||||
/// The returned value will always be in the range `0..60`.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::time;
|
||||
/// assert_eq!(time!(0:00:00).second(), 0);
|
||||
/// assert_eq!(time!(23:59:59).second(), 59);
|
||||
/// ```
|
||||
pub const fn second(self) -> u8 {
|
||||
self.second
|
||||
}
|
||||
|
||||
/// Get the milliseconds within the second.
|
||||
///
|
||||
/// The returned value will always be in the range `0..1_000`.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::time;
|
||||
/// assert_eq!(time!(0:00).millisecond(), 0);
|
||||
/// assert_eq!(time!(23:59:59.999).millisecond(), 999);
|
||||
/// ```
|
||||
pub const fn millisecond(self) -> u16 {
|
||||
(self.nanosecond / 1_000_000) as _
|
||||
}
|
||||
|
||||
/// Get the microseconds within the second.
|
||||
///
|
||||
/// The returned value will always be in the range `0..1_000_000`.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::time;
|
||||
/// assert_eq!(time!(0:00).microsecond(), 0);
|
||||
/// assert_eq!(time!(23:59:59.999_999).microsecond(), 999_999);
|
||||
/// ```
|
||||
pub const fn microsecond(self) -> u32 {
|
||||
self.nanosecond / 1_000
|
||||
}
|
||||
|
||||
/// Get the nanoseconds within the second.
|
||||
///
|
||||
/// The returned value will always be in the range `0..1_000_000_000`.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::time;
|
||||
/// assert_eq!(time!(0:00).nanosecond(), 0);
|
||||
/// assert_eq!(time!(23:59:59.999_999_999).nanosecond(), 999_999_999);
|
||||
/// ```
|
||||
pub const fn nanosecond(self) -> u32 {
|
||||
self.nanosecond
|
||||
}
|
||||
// endregion getters
|
||||
|
||||
// region: arithmetic helpers
|
||||
/// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning whether
|
||||
/// the date is different.
|
||||
pub(crate) const fn adjusting_add(self, duration: Duration) -> (DateAdjustment, Self) {
|
||||
let mut nanoseconds = self.nanosecond as i32 + duration.subsec_nanoseconds();
|
||||
let mut seconds = self.second as i8 + (duration.whole_seconds() % 60) as i8;
|
||||
let mut minutes = self.minute as i8 + (duration.whole_minutes() % 60) as i8;
|
||||
let mut hours = self.hour as i8 + (duration.whole_hours() % 24) as i8;
|
||||
let mut date_adjustment = DateAdjustment::None;
|
||||
|
||||
cascade!(nanoseconds in 0..1_000_000_000 => seconds);
|
||||
cascade!(seconds in 0..60 => minutes);
|
||||
cascade!(minutes in 0..60 => hours);
|
||||
if hours >= 24 {
|
||||
hours -= 24;
|
||||
date_adjustment = DateAdjustment::Next;
|
||||
} else if hours < 0 {
|
||||
hours += 24;
|
||||
date_adjustment = DateAdjustment::Previous;
|
||||
}
|
||||
|
||||
(
|
||||
date_adjustment,
|
||||
Self::__from_hms_nanos_unchecked(
|
||||
hours as _,
|
||||
minutes as _,
|
||||
seconds as _,
|
||||
nanoseconds as _,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/// Subtract the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning
|
||||
/// whether the date is different.
|
||||
pub(crate) const fn adjusting_sub(self, duration: Duration) -> (DateAdjustment, Self) {
|
||||
let mut nanoseconds = self.nanosecond as i32 - duration.subsec_nanoseconds();
|
||||
let mut seconds = self.second as i8 - (duration.whole_seconds() % 60) as i8;
|
||||
let mut minutes = self.minute as i8 - (duration.whole_minutes() % 60) as i8;
|
||||
let mut hours = self.hour as i8 - (duration.whole_hours() % 24) as i8;
|
||||
let mut date_adjustment = DateAdjustment::None;
|
||||
|
||||
cascade!(nanoseconds in 0..1_000_000_000 => seconds);
|
||||
cascade!(seconds in 0..60 => minutes);
|
||||
cascade!(minutes in 0..60 => hours);
|
||||
if hours >= 24 {
|
||||
hours -= 24;
|
||||
date_adjustment = DateAdjustment::Next;
|
||||
} else if hours < 0 {
|
||||
hours += 24;
|
||||
date_adjustment = DateAdjustment::Previous;
|
||||
}
|
||||
|
||||
(
|
||||
date_adjustment,
|
||||
Self::__from_hms_nanos_unchecked(
|
||||
hours as _,
|
||||
minutes as _,
|
||||
seconds as _,
|
||||
nanoseconds as _,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow,
|
||||
/// returning whether the date is the previous date as the first element of the tuple.
|
||||
pub(crate) const fn adjusting_add_std(self, duration: StdDuration) -> (bool, Self) {
|
||||
let mut nanosecond = self.nanosecond + duration.subsec_nanos();
|
||||
let mut second = self.second + (duration.as_secs() % 60) as u8;
|
||||
let mut minute = self.minute + ((duration.as_secs() / 60) % 60) as u8;
|
||||
let mut hour = self.hour + ((duration.as_secs() / 3_600) % 24) as u8;
|
||||
let mut is_next_day = false;
|
||||
|
||||
cascade!(nanosecond in 0..1_000_000_000 => second);
|
||||
cascade!(second in 0..60 => minute);
|
||||
cascade!(minute in 0..60 => hour);
|
||||
if hour >= 24 {
|
||||
hour -= 24;
|
||||
is_next_day = true;
|
||||
}
|
||||
|
||||
(
|
||||
is_next_day,
|
||||
Self::__from_hms_nanos_unchecked(hour, minute, second, nanosecond),
|
||||
)
|
||||
}
|
||||
|
||||
/// Subtract the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow,
|
||||
/// returning whether the date is the previous date as the first element of the tuple.
|
||||
pub(crate) const fn adjusting_sub_std(self, duration: StdDuration) -> (bool, Self) {
|
||||
let mut nanosecond = self.nanosecond as i32 - duration.subsec_nanos() as i32;
|
||||
let mut second = self.second as i8 - (duration.as_secs() % 60) as i8;
|
||||
let mut minute = self.minute as i8 - ((duration.as_secs() / 60) % 60) as i8;
|
||||
let mut hour = self.hour as i8 - ((duration.as_secs() / 3_600) % 24) as i8;
|
||||
let mut is_previous_day = false;
|
||||
|
||||
cascade!(nanosecond in 0..1_000_000_000 => second);
|
||||
cascade!(second in 0..60 => minute);
|
||||
cascade!(minute in 0..60 => hour);
|
||||
if hour < 0 {
|
||||
hour += 24;
|
||||
is_previous_day = true;
|
||||
}
|
||||
|
||||
(
|
||||
is_previous_day,
|
||||
Self::__from_hms_nanos_unchecked(hour as _, minute as _, second as _, nanosecond as _),
|
||||
)
|
||||
}
|
||||
// endregion arithmetic helpers
|
||||
|
||||
// region: replacement
|
||||
/// Replace the clock hour.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::time;
|
||||
/// assert_eq!(
|
||||
/// time!(01:02:03.004_005_006).replace_hour(7),
|
||||
/// Ok(time!(07:02:03.004_005_006))
|
||||
/// );
|
||||
/// assert!(time!(01:02:03.004_005_006).replace_hour(24).is_err()); // 24 isn't a valid hour
|
||||
/// ```
|
||||
#[must_use = "This method does not mutate the original `Time`."]
|
||||
pub const fn replace_hour(self, hour: u8) -> Result<Self, error::ComponentRange> {
|
||||
ensure_value_in_range!(hour in 0 => 23);
|
||||
Ok(Self::__from_hms_nanos_unchecked(
|
||||
hour,
|
||||
self.minute,
|
||||
self.second,
|
||||
self.nanosecond,
|
||||
))
|
||||
}
|
||||
|
||||
/// Replace the minutes within the hour.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::time;
|
||||
/// assert_eq!(
|
||||
/// time!(01:02:03.004_005_006).replace_minute(7),
|
||||
/// Ok(time!(01:07:03.004_005_006))
|
||||
/// );
|
||||
/// assert!(time!(01:02:03.004_005_006).replace_minute(60).is_err()); // 60 isn't a valid minute
|
||||
/// ```
|
||||
#[must_use = "This method does not mutate the original `Time`."]
|
||||
pub const fn replace_minute(self, minute: u8) -> Result<Self, error::ComponentRange> {
|
||||
ensure_value_in_range!(minute in 0 => 59);
|
||||
Ok(Self::__from_hms_nanos_unchecked(
|
||||
self.hour,
|
||||
minute,
|
||||
self.second,
|
||||
self.nanosecond,
|
||||
))
|
||||
}
|
||||
|
||||
/// Replace the seconds within the minute.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::time;
|
||||
/// assert_eq!(
|
||||
/// time!(01:02:03.004_005_006).replace_second(7),
|
||||
/// Ok(time!(01:02:07.004_005_006))
|
||||
/// );
|
||||
/// assert!(time!(01:02:03.004_005_006).replace_second(60).is_err()); // 60 isn't a valid second
|
||||
/// ```
|
||||
#[must_use = "This method does not mutate the original `Time`."]
|
||||
pub const fn replace_second(self, second: u8) -> Result<Self, error::ComponentRange> {
|
||||
ensure_value_in_range!(second in 0 => 59);
|
||||
Ok(Self::__from_hms_nanos_unchecked(
|
||||
self.hour,
|
||||
self.minute,
|
||||
second,
|
||||
self.nanosecond,
|
||||
))
|
||||
}
|
||||
|
||||
/// Replace the milliseconds within the second.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::time;
|
||||
/// assert_eq!(
|
||||
/// time!(01:02:03.004_005_006).replace_millisecond(7),
|
||||
/// Ok(time!(01:02:03.007))
|
||||
/// );
|
||||
/// assert!(time!(01:02:03.004_005_006).replace_millisecond(1_000).is_err()); // 1_000 isn't a valid millisecond
|
||||
/// ```
|
||||
#[must_use = "This method does not mutate the original `Time`."]
|
||||
pub const fn replace_millisecond(
|
||||
self,
|
||||
millisecond: u16,
|
||||
) -> Result<Self, error::ComponentRange> {
|
||||
ensure_value_in_range!(millisecond in 0 => 999);
|
||||
Ok(Self::__from_hms_nanos_unchecked(
|
||||
self.hour,
|
||||
self.minute,
|
||||
self.second,
|
||||
millisecond as u32 * 1_000_000,
|
||||
))
|
||||
}
|
||||
|
||||
/// Replace the microseconds within the second.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::time;
|
||||
/// assert_eq!(
|
||||
/// time!(01:02:03.004_005_006).replace_microsecond(7_008),
|
||||
/// Ok(time!(01:02:03.007_008))
|
||||
/// );
|
||||
/// assert!(time!(01:02:03.004_005_006).replace_microsecond(1_000_000).is_err()); // 1_000_000 isn't a valid microsecond
|
||||
/// ```
|
||||
#[must_use = "This method does not mutate the original `Time`."]
|
||||
pub const fn replace_microsecond(
|
||||
self,
|
||||
microsecond: u32,
|
||||
) -> Result<Self, error::ComponentRange> {
|
||||
ensure_value_in_range!(microsecond in 0 => 999_999);
|
||||
Ok(Self::__from_hms_nanos_unchecked(
|
||||
self.hour,
|
||||
self.minute,
|
||||
self.second,
|
||||
microsecond * 1000,
|
||||
))
|
||||
}
|
||||
|
||||
/// Replace the nanoseconds within the second.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::time;
|
||||
/// assert_eq!(
|
||||
/// time!(01:02:03.004_005_006).replace_nanosecond(7_008_009),
|
||||
/// Ok(time!(01:02:03.007_008_009))
|
||||
/// );
|
||||
/// assert!(time!(01:02:03.004_005_006).replace_nanosecond(1_000_000_000).is_err()); // 1_000_000_000 isn't a valid nanosecond
|
||||
/// ```
|
||||
#[must_use = "This method does not mutate the original `Time`."]
|
||||
pub const fn replace_nanosecond(self, nanosecond: u32) -> Result<Self, error::ComponentRange> {
|
||||
ensure_value_in_range!(nanosecond in 0 => 999_999_999);
|
||||
Ok(Self::__from_hms_nanos_unchecked(
|
||||
self.hour,
|
||||
self.minute,
|
||||
self.second,
|
||||
nanosecond,
|
||||
))
|
||||
}
|
||||
// endregion replacement
|
||||
}
|
||||
|
||||
// region: formatting & parsing
|
||||
#[cfg(feature = "formatting")]
|
||||
impl Time {
|
||||
/// Format the `Time` using the provided [format description](crate::format_description).
|
||||
pub fn format_into(
|
||||
self,
|
||||
output: &mut impl io::Write,
|
||||
format: &(impl Formattable + ?Sized),
|
||||
) -> Result<usize, crate::error::Format> {
|
||||
format.format_into(output, None, Some(self), None)
|
||||
}
|
||||
|
||||
/// Format the `Time` using the provided [format description](crate::format_description).
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{format_description, macros::time};
|
||||
/// let format = format_description::parse("[hour]:[minute]:[second]")?;
|
||||
/// assert_eq!(time!(12:00).format(&format)?, "12:00:00");
|
||||
/// # Ok::<_, time::Error>(())
|
||||
/// ```
|
||||
pub fn format(
|
||||
self,
|
||||
format: &(impl Formattable + ?Sized),
|
||||
) -> Result<String, crate::error::Format> {
|
||||
format.format(None, Some(self), None)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
impl Time {
|
||||
/// Parse a `Time` from the input using the provided [format
|
||||
/// description](crate::format_description).
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{format_description, macros::time, Time};
|
||||
/// let format = format_description::parse("[hour]:[minute]:[second]")?;
|
||||
/// assert_eq!(Time::parse("12:00:00", &format)?, time!(12:00));
|
||||
/// # Ok::<_, time::Error>(())
|
||||
/// ```
|
||||
pub fn parse(
|
||||
input: &str,
|
||||
description: &(impl Parsable + ?Sized),
|
||||
) -> Result<Self, error::Parse> {
|
||||
description.parse_time(input.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Time {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let (value, width) = match self.nanosecond() {
|
||||
nanos if nanos % 10 != 0 => (nanos, 9),
|
||||
nanos if (nanos / 10) % 10 != 0 => (nanos / 10, 8),
|
||||
nanos if (nanos / 100) % 10 != 0 => (nanos / 100, 7),
|
||||
nanos if (nanos / 1_000) % 10 != 0 => (nanos / 1_000, 6),
|
||||
nanos if (nanos / 10_000) % 10 != 0 => (nanos / 10_000, 5),
|
||||
nanos if (nanos / 100_000) % 10 != 0 => (nanos / 100_000, 4),
|
||||
nanos if (nanos / 1_000_000) % 10 != 0 => (nanos / 1_000_000, 3),
|
||||
nanos if (nanos / 10_000_000) % 10 != 0 => (nanos / 10_000_000, 2),
|
||||
nanos => (nanos / 100_000_000, 1),
|
||||
};
|
||||
write!(
|
||||
f,
|
||||
"{}:{:02}:{:02}.{:0width$}",
|
||||
self.hour,
|
||||
self.minute,
|
||||
self.second,
|
||||
value,
|
||||
width = width
|
||||
)
|
||||
}
|
||||
}
|
||||
// endregion formatting & parsing
|
||||
|
||||
// region: trait impls
|
||||
impl Add<Duration> for Time {
|
||||
type Output = Self;
|
||||
|
||||
/// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{ext::NumericalDuration, macros::time};
|
||||
/// assert_eq!(time!(12:00) + 2.hours(), time!(14:00));
|
||||
/// assert_eq!(time!(0:00:01) + (-2).seconds(), time!(23:59:59));
|
||||
/// ```
|
||||
fn add(self, duration: Duration) -> Self::Output {
|
||||
self.adjusting_add(duration).1
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<StdDuration> for Time {
|
||||
type Output = Self;
|
||||
|
||||
/// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{ext::NumericalStdDuration, macros::time};
|
||||
/// assert_eq!(time!(12:00) + 2.std_hours(), time!(14:00));
|
||||
/// assert_eq!(time!(23:59:59) + 2.std_seconds(), time!(0:00:01));
|
||||
/// ```
|
||||
fn add(self, duration: StdDuration) -> Self::Output {
|
||||
self.adjusting_add_std(duration).1
|
||||
}
|
||||
}
|
||||
|
||||
impl_add_assign!(Time: Duration, StdDuration);
|
||||
|
||||
impl Sub<Duration> for Time {
|
||||
type Output = Self;
|
||||
|
||||
/// Subtract the sub-day time of the [`Duration`] from the `Time`. Wraps on overflow.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{ext::NumericalDuration, macros::time};
|
||||
/// assert_eq!(time!(14:00) - 2.hours(), time!(12:00));
|
||||
/// assert_eq!(time!(23:59:59) - (-2).seconds(), time!(0:00:01));
|
||||
/// ```
|
||||
fn sub(self, duration: Duration) -> Self::Output {
|
||||
self.adjusting_sub(duration).1
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<StdDuration> for Time {
|
||||
type Output = Self;
|
||||
|
||||
/// Subtract the sub-day time of the [`std::time::Duration`] from the `Time`. Wraps on overflow.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{ext::NumericalStdDuration, macros::time};
|
||||
/// assert_eq!(time!(14:00) - 2.std_hours(), time!(12:00));
|
||||
/// assert_eq!(time!(0:00:01) - 2.std_seconds(), time!(23:59:59));
|
||||
/// ```
|
||||
fn sub(self, duration: StdDuration) -> Self::Output {
|
||||
self.adjusting_sub_std(duration).1
|
||||
}
|
||||
}
|
||||
|
||||
impl_sub_assign!(Time: Duration, StdDuration);
|
||||
|
||||
impl Sub for Time {
|
||||
type Output = Duration;
|
||||
|
||||
/// Subtract two `Time`s, returning the [`Duration`] between. This assumes both `Time`s are in
|
||||
/// the same calendar day.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{ext::NumericalDuration, macros::time};
|
||||
/// assert_eq!(time!(0:00) - time!(0:00), 0.seconds());
|
||||
/// assert_eq!(time!(1:00) - time!(0:00), 1.hours());
|
||||
/// assert_eq!(time!(0:00) - time!(1:00), (-1).hours());
|
||||
/// assert_eq!(time!(0:00) - time!(23:00), (-23).hours());
|
||||
/// ```
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
let hour_diff = (self.hour as i8) - (rhs.hour as i8);
|
||||
let minute_diff = (self.minute as i8) - (rhs.minute as i8);
|
||||
let mut second_diff = (self.second as i8) - (rhs.second as i8);
|
||||
let mut nanosecond_diff = (self.nanosecond as i32) - (rhs.nanosecond as i32);
|
||||
|
||||
cascade!(nanosecond_diff in 0..1_000_000_000 => second_diff);
|
||||
|
||||
Duration::new_unchecked(
|
||||
hour_diff as i64 * 3_600 + minute_diff as i64 * 60 + second_diff as i64,
|
||||
nanosecond_diff,
|
||||
)
|
||||
}
|
||||
}
|
||||
// endregion trait impls
|
||||
321
zeroidc/vendor/time/src/utc_offset.rs
vendored
Normal file
321
zeroidc/vendor/time/src/utc_offset.rs
vendored
Normal file
@@ -0,0 +1,321 @@
|
||||
//! The [`UtcOffset`] struct and its associated `impl`s.
|
||||
|
||||
use core::fmt;
|
||||
use core::ops::Neg;
|
||||
#[cfg(feature = "formatting")]
|
||||
use std::io;
|
||||
|
||||
use crate::error;
|
||||
#[cfg(feature = "formatting")]
|
||||
use crate::formatting::Formattable;
|
||||
#[cfg(feature = "parsing")]
|
||||
use crate::parsing::Parsable;
|
||||
#[cfg(feature = "local-offset")]
|
||||
use crate::sys::local_offset_at;
|
||||
#[cfg(feature = "local-offset")]
|
||||
use crate::OffsetDateTime;
|
||||
|
||||
/// An offset from UTC.
|
||||
///
|
||||
/// This struct can store values up to ±23:59:59. If you need support outside this range, please
|
||||
/// file an issue with your use case.
|
||||
// All three components _must_ have the same sign.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct UtcOffset {
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
hours: i8,
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
minutes: i8,
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
seconds: i8,
|
||||
}
|
||||
|
||||
impl UtcOffset {
|
||||
/// A `UtcOffset` that is UTC.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{UtcOffset, macros::offset};
|
||||
/// assert_eq!(UtcOffset::UTC, offset!(UTC));
|
||||
/// ```
|
||||
pub const UTC: Self = Self::__from_hms_unchecked(0, 0, 0);
|
||||
|
||||
// region: constructors
|
||||
/// Create a `UtcOffset` representing an offset of the hours, minutes, and seconds provided, the
|
||||
/// validity of which must be guaranteed by the caller. All three parameters must have the same
|
||||
/// sign.
|
||||
#[doc(hidden)]
|
||||
pub const fn __from_hms_unchecked(hours: i8, minutes: i8, seconds: i8) -> Self {
|
||||
Self {
|
||||
hours,
|
||||
minutes,
|
||||
seconds,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a `UtcOffset` representing an offset by the number of hours, minutes, and seconds
|
||||
/// provided.
|
||||
///
|
||||
/// The sign of all three components should match. If they do not, all smaller components will
|
||||
/// have their signs flipped.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::UtcOffset;
|
||||
/// assert_eq!(UtcOffset::from_hms(1, 2, 3)?.as_hms(), (1, 2, 3));
|
||||
/// assert_eq!(UtcOffset::from_hms(1, -2, -3)?.as_hms(), (1, 2, 3));
|
||||
/// # Ok::<_, time::Error>(())
|
||||
/// ```
|
||||
pub const fn from_hms(
|
||||
hours: i8,
|
||||
mut minutes: i8,
|
||||
mut seconds: i8,
|
||||
) -> Result<Self, error::ComponentRange> {
|
||||
ensure_value_in_range!(hours in -23 => 23);
|
||||
ensure_value_in_range!(minutes in -59 => 59);
|
||||
ensure_value_in_range!(seconds in -59 => 59);
|
||||
|
||||
if (hours > 0 && minutes < 0) || (hours < 0 && minutes > 0) {
|
||||
minutes *= -1;
|
||||
}
|
||||
if (hours > 0 && seconds < 0)
|
||||
|| (hours < 0 && seconds > 0)
|
||||
|| (minutes > 0 && seconds < 0)
|
||||
|| (minutes < 0 && seconds > 0)
|
||||
{
|
||||
seconds *= -1;
|
||||
}
|
||||
|
||||
Ok(Self::__from_hms_unchecked(hours, minutes, seconds))
|
||||
}
|
||||
|
||||
/// Create a `UtcOffset` representing an offset by the number of seconds provided.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::UtcOffset;
|
||||
/// assert_eq!(UtcOffset::from_whole_seconds(3_723)?.as_hms(), (1, 2, 3));
|
||||
/// # Ok::<_, time::Error>(())
|
||||
/// ```
|
||||
pub const fn from_whole_seconds(seconds: i32) -> Result<Self, error::ComponentRange> {
|
||||
ensure_value_in_range!(seconds in -86_399 => 86_399);
|
||||
|
||||
Ok(Self::__from_hms_unchecked(
|
||||
(seconds / 3_600) as _,
|
||||
((seconds / 60) % 60) as _,
|
||||
(seconds % 60) as _,
|
||||
))
|
||||
}
|
||||
// endregion constructors
|
||||
|
||||
// region: getters
|
||||
/// Obtain the UTC offset as its hours, minutes, and seconds. The sign of all three components
|
||||
/// will always match. A positive value indicates an offset to the east; a negative to the west.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::offset;
|
||||
/// assert_eq!(offset!(+1:02:03).as_hms(), (1, 2, 3));
|
||||
/// assert_eq!(offset!(-1:02:03).as_hms(), (-1, -2, -3));
|
||||
/// ```
|
||||
pub const fn as_hms(self) -> (i8, i8, i8) {
|
||||
(self.hours, self.minutes, self.seconds)
|
||||
}
|
||||
|
||||
/// Obtain the number of whole hours the offset is from UTC. A positive value indicates an
|
||||
/// offset to the east; a negative to the west.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::offset;
|
||||
/// assert_eq!(offset!(+1:02:03).whole_hours(), 1);
|
||||
/// assert_eq!(offset!(-1:02:03).whole_hours(), -1);
|
||||
/// ```
|
||||
pub const fn whole_hours(self) -> i8 {
|
||||
self.hours
|
||||
}
|
||||
|
||||
/// Obtain the number of whole minutes the offset is from UTC. A positive value indicates an
|
||||
/// offset to the east; a negative to the west.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::offset;
|
||||
/// assert_eq!(offset!(+1:02:03).whole_minutes(), 62);
|
||||
/// assert_eq!(offset!(-1:02:03).whole_minutes(), -62);
|
||||
/// ```
|
||||
pub const fn whole_minutes(self) -> i16 {
|
||||
self.hours as i16 * 60 + self.minutes as i16
|
||||
}
|
||||
|
||||
/// Obtain the number of minutes past the hour the offset is from UTC. A positive value
|
||||
/// indicates an offset to the east; a negative to the west.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::offset;
|
||||
/// assert_eq!(offset!(+1:02:03).minutes_past_hour(), 2);
|
||||
/// assert_eq!(offset!(-1:02:03).minutes_past_hour(), -2);
|
||||
/// ```
|
||||
pub const fn minutes_past_hour(self) -> i8 {
|
||||
self.minutes
|
||||
}
|
||||
|
||||
/// Obtain the number of whole seconds the offset is from UTC. A positive value indicates an
|
||||
/// offset to the east; a negative to the west.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::offset;
|
||||
/// assert_eq!(offset!(+1:02:03).whole_seconds(), 3723);
|
||||
/// assert_eq!(offset!(-1:02:03).whole_seconds(), -3723);
|
||||
/// ```
|
||||
// This may be useful for anyone manually implementing arithmetic, as it
|
||||
// would let them construct a `Duration` directly.
|
||||
pub const fn whole_seconds(self) -> i32 {
|
||||
self.hours as i32 * 3_600 + self.minutes as i32 * 60 + self.seconds as i32
|
||||
}
|
||||
|
||||
/// Obtain the number of seconds past the minute the offset is from UTC. A positive value
|
||||
/// indicates an offset to the east; a negative to the west.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::offset;
|
||||
/// assert_eq!(offset!(+1:02:03).seconds_past_minute(), 3);
|
||||
/// assert_eq!(offset!(-1:02:03).seconds_past_minute(), -3);
|
||||
/// ```
|
||||
pub const fn seconds_past_minute(self) -> i8 {
|
||||
self.seconds
|
||||
}
|
||||
// endregion getters
|
||||
|
||||
// region: is_{sign}
|
||||
/// Check if the offset is exactly UTC.
|
||||
///
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::offset;
|
||||
/// assert!(!offset!(+1:02:03).is_utc());
|
||||
/// assert!(!offset!(-1:02:03).is_utc());
|
||||
/// assert!(offset!(UTC).is_utc());
|
||||
/// ```
|
||||
pub const fn is_utc(self) -> bool {
|
||||
self.hours == 0 && self.minutes == 0 && self.seconds == 0
|
||||
}
|
||||
|
||||
/// Check if the offset is positive, or east of UTC.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::offset;
|
||||
/// assert!(offset!(+1:02:03).is_positive());
|
||||
/// assert!(!offset!(-1:02:03).is_positive());
|
||||
/// assert!(!offset!(UTC).is_positive());
|
||||
/// ```
|
||||
pub const fn is_positive(self) -> bool {
|
||||
self.hours > 0 || self.minutes > 0 || self.seconds > 0
|
||||
}
|
||||
|
||||
/// Check if the offset is negative, or west of UTC.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::macros::offset;
|
||||
/// assert!(!offset!(+1:02:03).is_negative());
|
||||
/// assert!(offset!(-1:02:03).is_negative());
|
||||
/// assert!(!offset!(UTC).is_negative());
|
||||
/// ```
|
||||
pub const fn is_negative(self) -> bool {
|
||||
self.hours < 0 || self.minutes < 0 || self.seconds < 0
|
||||
}
|
||||
// endregion is_{sign}
|
||||
|
||||
// region: local offset
|
||||
/// Attempt to obtain the system's UTC offset at a known moment in time. If the offset cannot be
|
||||
/// determined, an error is returned.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{UtcOffset, OffsetDateTime};
|
||||
/// let local_offset = UtcOffset::local_offset_at(OffsetDateTime::UNIX_EPOCH);
|
||||
/// # if false {
|
||||
/// assert!(local_offset.is_ok());
|
||||
/// # }
|
||||
/// ```
|
||||
#[cfg(feature = "local-offset")]
|
||||
pub fn local_offset_at(datetime: OffsetDateTime) -> Result<Self, error::IndeterminateOffset> {
|
||||
local_offset_at(datetime).ok_or(error::IndeterminateOffset)
|
||||
}
|
||||
|
||||
/// Attempt to obtain the system's current UTC offset. If the offset cannot be determined, an
|
||||
/// error is returned.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::UtcOffset;
|
||||
/// let local_offset = UtcOffset::current_local_offset();
|
||||
/// # if false {
|
||||
/// assert!(local_offset.is_ok());
|
||||
/// # }
|
||||
/// ```
|
||||
#[cfg(feature = "local-offset")]
|
||||
pub fn current_local_offset() -> Result<Self, error::IndeterminateOffset> {
|
||||
let now = OffsetDateTime::now_utc();
|
||||
local_offset_at(now).ok_or(error::IndeterminateOffset)
|
||||
}
|
||||
// endregion: local offset
|
||||
}
|
||||
|
||||
// region: formatting & parsing
|
||||
#[cfg(feature = "formatting")]
|
||||
impl UtcOffset {
|
||||
/// Format the `UtcOffset` using the provided [format description](crate::format_description).
|
||||
pub fn format_into(
|
||||
self,
|
||||
output: &mut impl io::Write,
|
||||
format: &(impl Formattable + ?Sized),
|
||||
) -> Result<usize, error::Format> {
|
||||
format.format_into(output, None, None, Some(self))
|
||||
}
|
||||
|
||||
/// Format the `UtcOffset` using the provided [format description](crate::format_description).
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{format_description, macros::offset};
|
||||
/// let format = format_description::parse("[offset_hour sign:mandatory]:[offset_minute]")?;
|
||||
/// assert_eq!(offset!(+1).format(&format)?, "+01:00");
|
||||
/// # Ok::<_, time::Error>(())
|
||||
/// ```
|
||||
pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
|
||||
format.format(None, None, Some(self))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "parsing")]
|
||||
impl UtcOffset {
|
||||
/// Parse a `UtcOffset` from the input using the provided [format
|
||||
/// description](crate::format_description).
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{format_description, macros::offset, UtcOffset};
|
||||
/// let format = format_description::parse("[offset_hour]:[offset_minute]")?;
|
||||
/// assert_eq!(UtcOffset::parse("-03:42", &format)?, offset!(-3:42));
|
||||
/// # Ok::<_, time::Error>(())
|
||||
/// ```
|
||||
pub fn parse(
|
||||
input: &str,
|
||||
description: &(impl Parsable + ?Sized),
|
||||
) -> Result<Self, error::Parse> {
|
||||
description.parse_offset(input.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for UtcOffset {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}{:02}:{:02}:{:02}",
|
||||
if self.is_negative() { '-' } else { '+' },
|
||||
self.hours.abs(),
|
||||
self.minutes.abs(),
|
||||
self.seconds.abs()
|
||||
)
|
||||
}
|
||||
}
|
||||
// endregion formatting & parsing
|
||||
|
||||
impl Neg for UtcOffset {
|
||||
type Output = Self;
|
||||
|
||||
fn neg(self) -> Self::Output {
|
||||
Self::__from_hms_unchecked(-self.hours, -self.minutes, -self.seconds)
|
||||
}
|
||||
}
|
||||
80
zeroidc/vendor/time/src/util.rs
vendored
Normal file
80
zeroidc/vendor/time/src/util.rs
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
//! Utility functions.
|
||||
|
||||
use crate::Month;
|
||||
|
||||
/// Whether to adjust the date, and in which direction. Useful when implementing arithmetic.
|
||||
pub(crate) enum DateAdjustment {
|
||||
/// The previous day should be used.
|
||||
Previous,
|
||||
/// The next day should be used.
|
||||
Next,
|
||||
/// The date should be used as-is.
|
||||
None,
|
||||
}
|
||||
|
||||
/// Get the number of days in the month of a given year.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::{Month, util};
|
||||
/// assert_eq!(util::days_in_year_month(2020, Month::February), 29);
|
||||
/// ```
|
||||
pub const fn days_in_year_month(year: i32, month: Month) -> u8 {
|
||||
use Month::*;
|
||||
match month {
|
||||
January | March | May | July | August | October | December => 31,
|
||||
April | June | September | November => 30,
|
||||
February if is_leap_year(year) => 29,
|
||||
February => 28,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns if the provided year is a leap year in the proleptic Gregorian calendar. Uses
|
||||
/// [astronomical year numbering](https://en.wikipedia.org/wiki/Astronomical_year_numbering).
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::util::is_leap_year;
|
||||
/// assert!(!is_leap_year(1900));
|
||||
/// assert!(is_leap_year(2000));
|
||||
/// assert!(is_leap_year(2004));
|
||||
/// assert!(!is_leap_year(2005));
|
||||
/// assert!(!is_leap_year(2100));
|
||||
/// ```
|
||||
pub const fn is_leap_year(year: i32) -> bool {
|
||||
year % 4 == 0 && (year % 25 != 0 || year % 16 == 0)
|
||||
}
|
||||
|
||||
/// Get the number of calendar days in a given year.
|
||||
///
|
||||
/// The returned value will always be either 365 or 366.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::util::days_in_year;
|
||||
/// assert_eq!(days_in_year(1900), 365);
|
||||
/// assert_eq!(days_in_year(2000), 366);
|
||||
/// assert_eq!(days_in_year(2004), 366);
|
||||
/// assert_eq!(days_in_year(2005), 365);
|
||||
/// assert_eq!(days_in_year(2100), 365);
|
||||
/// ```
|
||||
pub const fn days_in_year(year: i32) -> u16 {
|
||||
if is_leap_year(year) { 366 } else { 365 }
|
||||
}
|
||||
|
||||
/// Get the number of weeks in the ISO year.
|
||||
///
|
||||
/// The returned value will always be either 52 or 53.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::util::weeks_in_year;
|
||||
/// assert_eq!(weeks_in_year(2019), 52);
|
||||
/// assert_eq!(weeks_in_year(2020), 53);
|
||||
/// ```
|
||||
pub const fn weeks_in_year(year: i32) -> u8 {
|
||||
match year.rem_euclid(400) {
|
||||
4 | 9 | 15 | 20 | 26 | 32 | 37 | 43 | 48 | 54 | 60 | 65 | 71 | 76 | 82 | 88 | 93 | 99
|
||||
| 105 | 111 | 116 | 122 | 128 | 133 | 139 | 144 | 150 | 156 | 161 | 167 | 172 | 178
|
||||
| 184 | 189 | 195 | 201 | 207 | 212 | 218 | 224 | 229 | 235 | 240 | 246 | 252 | 257
|
||||
| 263 | 268 | 274 | 280 | 285 | 291 | 296 | 303 | 308 | 314 | 320 | 325 | 331 | 336
|
||||
| 342 | 348 | 353 | 359 | 364 | 370 | 376 | 381 | 387 | 392 | 398 => 53,
|
||||
_ => 52,
|
||||
}
|
||||
}
|
||||
148
zeroidc/vendor/time/src/weekday.rs
vendored
Normal file
148
zeroidc/vendor/time/src/weekday.rs
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
//! Days of the week.
|
||||
|
||||
use core::fmt::{self, Display};
|
||||
use core::str::FromStr;
|
||||
|
||||
use Weekday::*;
|
||||
|
||||
use crate::error;
|
||||
|
||||
/// Days of the week.
|
||||
///
|
||||
/// As order is dependent on context (Sunday could be either two days after or five days before
|
||||
/// Friday), this type does not implement `PartialOrd` or `Ord`.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum Weekday {
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
Monday,
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
Tuesday,
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
Wednesday,
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
Thursday,
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
Friday,
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
Saturday,
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
Sunday,
|
||||
}
|
||||
|
||||
impl Weekday {
|
||||
/// Get the previous weekday.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::Weekday;
|
||||
/// assert_eq!(Weekday::Tuesday.previous(), Weekday::Monday);
|
||||
/// ```
|
||||
pub const fn previous(self) -> Self {
|
||||
match self {
|
||||
Monday => Sunday,
|
||||
Tuesday => Monday,
|
||||
Wednesday => Tuesday,
|
||||
Thursday => Wednesday,
|
||||
Friday => Thursday,
|
||||
Saturday => Friday,
|
||||
Sunday => Saturday,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the next weekday.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::Weekday;
|
||||
/// assert_eq!(Weekday::Monday.next(), Weekday::Tuesday);
|
||||
/// ```
|
||||
pub const fn next(self) -> Self {
|
||||
match self {
|
||||
Monday => Tuesday,
|
||||
Tuesday => Wednesday,
|
||||
Wednesday => Thursday,
|
||||
Thursday => Friday,
|
||||
Friday => Saturday,
|
||||
Saturday => Sunday,
|
||||
Sunday => Monday,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the one-indexed number of days from Monday.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::Weekday;
|
||||
/// assert_eq!(Weekday::Monday.number_from_monday(), 1);
|
||||
/// ```
|
||||
#[doc(alias = "iso_weekday_number")]
|
||||
pub const fn number_from_monday(self) -> u8 {
|
||||
self.number_days_from_monday() + 1
|
||||
}
|
||||
|
||||
/// Get the one-indexed number of days from Sunday.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::Weekday;
|
||||
/// assert_eq!(Weekday::Monday.number_from_sunday(), 2);
|
||||
/// ```
|
||||
pub const fn number_from_sunday(self) -> u8 {
|
||||
self.number_days_from_sunday() + 1
|
||||
}
|
||||
|
||||
/// Get the zero-indexed number of days from Monday.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::Weekday;
|
||||
/// assert_eq!(Weekday::Monday.number_days_from_monday(), 0);
|
||||
/// ```
|
||||
pub const fn number_days_from_monday(self) -> u8 {
|
||||
self as _
|
||||
}
|
||||
|
||||
/// Get the zero-indexed number of days from Sunday.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use time::Weekday;
|
||||
/// assert_eq!(Weekday::Monday.number_days_from_sunday(), 1);
|
||||
/// ```
|
||||
pub const fn number_days_from_sunday(self) -> u8 {
|
||||
match self {
|
||||
Monday => 1,
|
||||
Tuesday => 2,
|
||||
Wednesday => 3,
|
||||
Thursday => 4,
|
||||
Friday => 5,
|
||||
Saturday => 6,
|
||||
Sunday => 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Weekday {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(match self {
|
||||
Monday => "Monday",
|
||||
Tuesday => "Tuesday",
|
||||
Wednesday => "Wednesday",
|
||||
Thursday => "Thursday",
|
||||
Friday => "Friday",
|
||||
Saturday => "Saturday",
|
||||
Sunday => "Sunday",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Weekday {
|
||||
type Err = error::InvalidVariant;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"Monday" => Ok(Monday),
|
||||
"Tuesday" => Ok(Tuesday),
|
||||
"Wednesday" => Ok(Wednesday),
|
||||
"Thursday" => Ok(Thursday),
|
||||
"Friday" => Ok(Friday),
|
||||
"Saturday" => Ok(Saturday),
|
||||
"Sunday" => Ok(Sunday),
|
||||
_ => Err(error::InvalidVariant),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user