1 //! Description of how types should be formatted and parsed. 2 //! 3 //! The formatted value will be output to the provided writer. Format descriptions can be 4 //! [well-known](crate::format_description::well_known) or obtained by using the 5 //! [`format_description!`](crate::macros::format_description) macro, the 6 //! [`format_description::parse`](crate::format_description::parse()) function. 7 8 mod component; 9 pub mod modifier; 10 #[cfg(feature = "alloc")] 11 pub(crate) mod parse; 12 13 #[cfg(feature = "alloc")] 14 use alloc::string::String; 15 use core::convert::TryFrom; 16 #[cfg(feature = "alloc")] 17 use core::fmt; 18 19 pub use self::component::Component; 20 #[cfg(feature = "alloc")] 21 pub use self::parse::parse; 22 use crate::error; 23 24 /// Helper methods. 25 #[cfg(feature = "alloc")] 26 mod helper { 27 /// Consume all leading whitespace, advancing `index` as appropriate. 28 #[must_use = "This does not modify the original slice."] consume_whitespace<'a>(bytes: &'a [u8], index: &mut usize) -> &'a [u8]29 pub(crate) fn consume_whitespace<'a>(bytes: &'a [u8], index: &mut usize) -> &'a [u8] { 30 let first_non_whitespace = bytes 31 .iter() 32 .position(|c| !c.is_ascii_whitespace()) 33 .unwrap_or(bytes.len()); 34 *index += first_non_whitespace; 35 &bytes[first_non_whitespace..] 36 } 37 } 38 39 /// Well-known formats, typically RFCs. 40 pub mod well_known { 41 /// The format described in [RFC 3339](https://tools.ietf.org/html/rfc3339#section-5.6). 42 /// 43 /// Format example: 1985-04-12T23:20:50.52Z 44 /// 45 /// ```rust 46 /// # use time::{format_description::well_known::Rfc3339, macros::datetime, OffsetDateTime}; 47 /// assert_eq!( 48 /// OffsetDateTime::parse("1985-04-12T23:20:50.52Z", &Rfc3339)?, 49 /// datetime!(1985-04-12 23:20:50.52 +00:00) 50 /// ); 51 /// # Ok::<_, time::Error>(()) 52 /// ``` 53 /// 54 /// ```rust 55 /// # use time::{format_description::well_known::Rfc3339, macros::datetime}; 56 /// assert_eq!( 57 /// datetime!(1985-04-12 23:20:50.52 +00:00).format(&Rfc3339)?, 58 /// "1985-04-12T23:20:50.52Z" 59 /// ); 60 /// # Ok::<_, time::Error>(()) 61 /// ``` 62 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 63 pub struct Rfc3339; 64 } 65 66 /// A complete description of how to format and parse a type. 67 #[non_exhaustive] 68 #[cfg_attr(not(feature = "alloc"), derive(Debug))] 69 #[derive(Clone, PartialEq, Eq)] 70 pub enum FormatItem<'a> { 71 /// Bytes that are formatted as-is. 72 /// 73 /// **Note**: If you call the `format` method that returns a `String`, these bytes will be 74 /// passed through `String::from_utf8_lossy`. 75 Literal(&'a [u8]), 76 /// A minimal representation of a single non-literal item. 77 Component(Component), 78 /// A series of literals or components that collectively form a partial or complete 79 /// description. 80 Compound(&'a [Self]), 81 /// A `FormatItem` that may or may not be present when parsing. If parsing fails, there will be 82 /// no effect on the resulting `struct`. 83 /// 84 /// This variant has no effect on formatting, as the value is guaranteed to be present. 85 Optional(&'a Self), 86 /// A series of `FormatItem`s where, when parsing, the first successful parse is used. When 87 /// formatting, the first element of the slice is used. An empty slice is a no-op when 88 /// formatting or parsing. 89 First(&'a [Self]), 90 } 91 92 #[cfg(feature = "alloc")] 93 impl fmt::Debug for FormatItem<'_> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result94 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 95 match self { 96 FormatItem::Literal(literal) => f.write_str(&String::from_utf8_lossy(literal)), 97 FormatItem::Component(component) => component.fmt(f), 98 FormatItem::Compound(compound) => compound.fmt(f), 99 FormatItem::Optional(item) => f.debug_tuple("Optional").field(item).finish(), 100 FormatItem::First(items) => f.debug_tuple("First").field(items).finish(), 101 } 102 } 103 } 104 105 impl From<Component> for FormatItem<'_> { from(component: Component) -> Self106 fn from(component: Component) -> Self { 107 Self::Component(component) 108 } 109 } 110 111 impl TryFrom<FormatItem<'_>> for Component { 112 type Error = error::DifferentVariant; 113 try_from(value: FormatItem<'_>) -> Result<Self, Self::Error>114 fn try_from(value: FormatItem<'_>) -> Result<Self, Self::Error> { 115 match value { 116 FormatItem::Component(component) => Ok(component), 117 _ => Err(error::DifferentVariant), 118 } 119 } 120 } 121 122 impl<'a> From<&'a [FormatItem<'_>]> for FormatItem<'a> { from(items: &'a [FormatItem<'_>]) -> FormatItem<'a>123 fn from(items: &'a [FormatItem<'_>]) -> FormatItem<'a> { 124 FormatItem::Compound(items) 125 } 126 } 127 128 impl<'a> TryFrom<FormatItem<'a>> for &[FormatItem<'a>] { 129 type Error = error::DifferentVariant; 130 try_from(value: FormatItem<'a>) -> Result<Self, Self::Error>131 fn try_from(value: FormatItem<'a>) -> Result<Self, Self::Error> { 132 match value { 133 FormatItem::Compound(items) => Ok(items), 134 _ => Err(error::DifferentVariant), 135 } 136 } 137 } 138 139 impl PartialEq<Component> for FormatItem<'_> { eq(&self, rhs: &Component) -> bool140 fn eq(&self, rhs: &Component) -> bool { 141 matches!(self, FormatItem::Component(component) if component == rhs) 142 } 143 } 144 145 impl PartialEq<FormatItem<'_>> for Component { eq(&self, rhs: &FormatItem<'_>) -> bool146 fn eq(&self, rhs: &FormatItem<'_>) -> bool { 147 rhs == self 148 } 149 } 150 151 impl PartialEq<&[FormatItem<'_>]> for FormatItem<'_> { eq(&self, rhs: &&[FormatItem<'_>]) -> bool152 fn eq(&self, rhs: &&[FormatItem<'_>]) -> bool { 153 matches!(self, FormatItem::Compound(compound) if compound == rhs) 154 } 155 } 156 157 impl PartialEq<FormatItem<'_>> for &[FormatItem<'_>] { eq(&self, rhs: &FormatItem<'_>) -> bool158 fn eq(&self, rhs: &FormatItem<'_>) -> bool { 159 rhs == self 160 } 161 } 162