Skip to main content

time/format_description/
borrowed_format_item.rs

1//! A format item with borrowed data.
2
3#[cfg(feature = "alloc")]
4use alloc::string::String;
5#[cfg(feature = "alloc")]
6use core::fmt;
7
8use crate::error;
9use crate::format_description::Component;
10
11/// A complete description of how to format and parse a type.
12#[non_exhaustive]
13#[cfg_attr(not(feature = "alloc"), derive(Debug))]
14#[derive(Clone, Eq)]
15pub enum BorrowedFormatItem<'a> {
16    /// Bytes that are formatted as-is.
17    ///
18    /// **Note**: These bytes **should** be UTF-8, but are not required to be. The value is passed
19    /// through `String::from_utf8_lossy` when necessary.
20    #[deprecated(
21        since = "0.3.48",
22        note = "use `StringLiteral` instead; raw bytes are not recommended"
23    )]
24    Literal(&'a [u8]),
25    /// A string that is formatted as-is.
26    StringLiteral(&'a str),
27    /// A minimal representation of a single non-literal item.
28    Component(Component),
29    /// A series of literals or components that collectively form a partial or complete
30    /// description.
31    Compound(&'a [Self]),
32    /// A `FormatItem` that may or may not be present when parsing. If parsing fails, there
33    /// will be no effect on the resulting `struct`.
34    ///
35    /// This variant has no effect on formatting, as the value is guaranteed to be present.
36    Optional(&'a Self),
37    /// A series of `FormatItem`s where, when parsing, the first successful parse is used. When
38    /// formatting, the first element of the slice is used.  An empty slice is a no-op when
39    /// formatting or parsing.
40    First(&'a [Self]),
41}
42
43#[cfg(feature = "alloc")]
44impl fmt::Debug for BorrowedFormatItem<'_> {
45    #[inline]
46    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47        match self {
48            #[expect(deprecated)]
49            Self::Literal(literal) => f.write_str(&String::from_utf8_lossy(literal)),
50            Self::StringLiteral(literal) => f.write_str(literal),
51            Self::Component(component) => component.fmt(f),
52            Self::Compound(compound) => compound.fmt(f),
53            Self::Optional(item) => f.debug_tuple("Optional").field(item).finish(),
54            Self::First(items) => f.debug_tuple("First").field(items).finish(),
55        }
56    }
57}
58
59impl PartialEq for BorrowedFormatItem<'_> {
60    fn eq(&self, other: &Self) -> bool {
61        match (self, other) {
62            // trivial equality checks
63            #[expect(deprecated)]
64            (Self::Literal(a), Self::Literal(b)) => a == b,
65            (Self::StringLiteral(a), Self::StringLiteral(b)) => a == b,
66            (Self::Component(a), Self::Component(b)) => a == b,
67            (Self::Compound(a), Self::Compound(b)) => a == b,
68            (Self::Optional(a), Self::Optional(b)) => a == b,
69            (Self::First(a), Self::First(b)) => a == b,
70            // bytes vs string (back-compatibility)
71            #[expect(deprecated)]
72            (Self::Literal(a), Self::StringLiteral(b)) => *a == b.as_bytes(),
73            #[expect(deprecated)]
74            (Self::StringLiteral(a), Self::Literal(b)) => a.as_bytes() == *b,
75            _ => false,
76        }
77    }
78}
79
80impl From<Component> for BorrowedFormatItem<'_> {
81    #[inline]
82    fn from(component: Component) -> Self {
83        Self::Component(component)
84    }
85}
86
87impl TryFrom<BorrowedFormatItem<'_>> for Component {
88    type Error = error::DifferentVariant;
89
90    #[inline]
91    fn try_from(value: BorrowedFormatItem<'_>) -> Result<Self, Self::Error> {
92        match value {
93            BorrowedFormatItem::Component(component) => Ok(component),
94            _ => Err(error::DifferentVariant),
95        }
96    }
97}
98
99impl<'a> From<&'a [BorrowedFormatItem<'_>]> for BorrowedFormatItem<'a> {
100    #[inline]
101    fn from(items: &'a [BorrowedFormatItem<'_>]) -> Self {
102        Self::Compound(items)
103    }
104}
105
106impl<'a> TryFrom<BorrowedFormatItem<'a>> for &[BorrowedFormatItem<'a>] {
107    type Error = error::DifferentVariant;
108
109    #[inline]
110    fn try_from(value: BorrowedFormatItem<'a>) -> Result<Self, Self::Error> {
111        match value {
112            BorrowedFormatItem::Compound(items) => Ok(items),
113            _ => Err(error::DifferentVariant),
114        }
115    }
116}
117
118impl PartialEq<Component> for BorrowedFormatItem<'_> {
119    #[inline]
120    fn eq(&self, rhs: &Component) -> bool {
121        matches!(self, Self::Component(component) if component == rhs)
122    }
123}
124
125impl PartialEq<BorrowedFormatItem<'_>> for Component {
126    #[inline]
127    fn eq(&self, rhs: &BorrowedFormatItem<'_>) -> bool {
128        rhs == self
129    }
130}
131
132impl PartialEq<&[Self]> for BorrowedFormatItem<'_> {
133    #[inline]
134    fn eq(&self, rhs: &&[Self]) -> bool {
135        matches!(self, Self::Compound(compound) if compound == rhs)
136    }
137}
138
139impl PartialEq<BorrowedFormatItem<'_>> for &[BorrowedFormatItem<'_>] {
140    #[inline]
141    fn eq(&self, rhs: &BorrowedFormatItem<'_>) -> bool {
142        rhs == self
143    }
144}