1 | //! A format item with borrowed data. |
2 | |
3 | #[cfg (feature = "alloc" )] |
4 | use alloc::string::String; |
5 | #[cfg (feature = "alloc" )] |
6 | use core::fmt; |
7 | |
8 | use crate::error; |
9 | use 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, PartialEq, Eq)] |
15 | pub enum BorrowedFormatItem<'a> { |
16 | /// Bytes that are formatted as-is. |
17 | /// |
18 | /// **Note**: If you call the `format` method that returns a `String`, these bytes will be |
19 | /// passed through `String::from_utf8_lossy`. |
20 | Literal(&'a [u8]), |
21 | /// A minimal representation of a single non-literal item. |
22 | Component(Component), |
23 | /// A series of literals or components that collectively form a partial or complete |
24 | /// description. |
25 | Compound(&'a [Self]), |
26 | /// A `FormatItem` that may or may not be present when parsing. If parsing fails, there |
27 | /// will be no effect on the resulting `struct`. |
28 | /// |
29 | /// This variant has no effect on formatting, as the value is guaranteed to be present. |
30 | Optional(&'a Self), |
31 | /// A series of `FormatItem`s where, when parsing, the first successful parse is used. When |
32 | /// formatting, the first element of the slice is used. An empty slice is a no-op when |
33 | /// formatting or parsing. |
34 | First(&'a [Self]), |
35 | } |
36 | |
37 | #[cfg (feature = "alloc" )] |
38 | impl fmt::Debug for BorrowedFormatItem<'_> { |
39 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
40 | match self { |
41 | Self::Literal(literal: &&[u8]) => f.write_str(&String::from_utf8_lossy(literal)), |
42 | Self::Component(component: &Component) => component.fmt(f), |
43 | Self::Compound(compound: &&[BorrowedFormatItem<'_>]) => compound.fmt(f), |
44 | Self::Optional(item: &&BorrowedFormatItem<'_>) => f.debug_tuple(name:"Optional" ).field(item).finish(), |
45 | Self::First(items: &&[BorrowedFormatItem<'_>]) => f.debug_tuple(name:"First" ).field(items).finish(), |
46 | } |
47 | } |
48 | } |
49 | |
50 | impl From<Component> for BorrowedFormatItem<'_> { |
51 | fn from(component: Component) -> Self { |
52 | Self::Component(component) |
53 | } |
54 | } |
55 | |
56 | impl TryFrom<BorrowedFormatItem<'_>> for Component { |
57 | type Error = error::DifferentVariant; |
58 | |
59 | fn try_from(value: BorrowedFormatItem<'_>) -> Result<Self, Self::Error> { |
60 | match value { |
61 | BorrowedFormatItem::Component(component: Component) => Ok(component), |
62 | _ => Err(error::DifferentVariant), |
63 | } |
64 | } |
65 | } |
66 | |
67 | impl<'a> From<&'a [BorrowedFormatItem<'_>]> for BorrowedFormatItem<'a> { |
68 | fn from(items: &'a [BorrowedFormatItem<'_>]) -> Self { |
69 | Self::Compound(items) |
70 | } |
71 | } |
72 | |
73 | impl<'a> TryFrom<BorrowedFormatItem<'a>> for &[BorrowedFormatItem<'a>] { |
74 | type Error = error::DifferentVariant; |
75 | |
76 | fn try_from(value: BorrowedFormatItem<'a>) -> Result<Self, Self::Error> { |
77 | match value { |
78 | BorrowedFormatItem::Compound(items: &[BorrowedFormatItem<'_>]) => Ok(items), |
79 | _ => Err(error::DifferentVariant), |
80 | } |
81 | } |
82 | } |
83 | |
84 | impl PartialEq<Component> for BorrowedFormatItem<'_> { |
85 | fn eq(&self, rhs: &Component) -> bool { |
86 | matches!(self, Self::Component(component) if component == rhs) |
87 | } |
88 | } |
89 | |
90 | impl PartialEq<BorrowedFormatItem<'_>> for Component { |
91 | fn eq(&self, rhs: &BorrowedFormatItem<'_>) -> bool { |
92 | rhs == self |
93 | } |
94 | } |
95 | |
96 | impl PartialEq<&[Self]> for BorrowedFormatItem<'_> { |
97 | fn eq(&self, rhs: &&[Self]) -> bool { |
98 | matches!(self, Self::Compound(compound) if compound == rhs) |
99 | } |
100 | } |
101 | |
102 | impl PartialEq<BorrowedFormatItem<'_>> for &[BorrowedFormatItem<'_>] { |
103 | fn eq(&self, rhs: &BorrowedFormatItem<'_>) -> bool { |
104 | rhs == self |
105 | } |
106 | } |
107 | |