1 | //! A format item with owned data. |
2 | |
3 | use alloc::boxed::Box; |
4 | use alloc::string::String; |
5 | use alloc::vec::Vec; |
6 | use core::fmt; |
7 | |
8 | use crate::error; |
9 | use crate::format_description::{Component, FormatItem}; |
10 | |
11 | /// A complete description of how to format and parse a type. |
12 | #[non_exhaustive ] |
13 | #[derive (Clone, PartialEq, Eq)] |
14 | pub enum OwnedFormatItem { |
15 | /// Bytes that are formatted as-is. |
16 | /// |
17 | /// **Note**: If you call the `format` method that returns a `String`, these bytes will be |
18 | /// passed through `String::from_utf8_lossy`. |
19 | Literal(Box<[u8]>), |
20 | /// A minimal representation of a single non-literal item. |
21 | Component(Component), |
22 | /// A series of literals or components that collectively form a partial or complete |
23 | /// description. |
24 | Compound(Box<[Self]>), |
25 | /// A `FormatItem` that may or may not be present when parsing. If parsing fails, there |
26 | /// will be no effect on the resulting `struct`. |
27 | /// |
28 | /// This variant has no effect on formatting, as the value is guaranteed to be present. |
29 | Optional(Box<Self>), |
30 | /// A series of `FormatItem`s where, when parsing, the first successful parse is used. When |
31 | /// formatting, the first element of the [`Vec`] is used. An empty [`Vec`] is a no-op when |
32 | /// formatting or parsing. |
33 | First(Box<[Self]>), |
34 | } |
35 | |
36 | impl fmt::Debug for OwnedFormatItem { |
37 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
38 | match self { |
39 | Self::Literal(literal: &Box<[u8]>) => f.write_str(&String::from_utf8_lossy(literal)), |
40 | Self::Component(component: &Component) => component.fmt(f), |
41 | Self::Compound(compound: &Box<[OwnedFormatItem]>) => compound.fmt(f), |
42 | Self::Optional(item: &Box) => f.debug_tuple(name:"Optional" ).field(item).finish(), |
43 | Self::First(items: &Box<[OwnedFormatItem]>) => f.debug_tuple(name:"First" ).field(items).finish(), |
44 | } |
45 | } |
46 | } |
47 | |
48 | // region: conversions from FormatItem |
49 | impl From<FormatItem<'_>> for OwnedFormatItem { |
50 | fn from(item: FormatItem<'_>) -> Self { |
51 | (&item).into() |
52 | } |
53 | } |
54 | |
55 | impl From<&FormatItem<'_>> for OwnedFormatItem { |
56 | fn from(item: &FormatItem<'_>) -> Self { |
57 | match item { |
58 | FormatItem::Literal(literal) => Self::Literal(literal.to_vec().into_boxed_slice()), |
59 | FormatItem::Component(component) => Self::Component(*component), |
60 | FormatItem::Compound(compound) => Self::Compound( |
61 | compound |
62 | .iter() |
63 | .cloned() |
64 | .map(Into::into) |
65 | .collect::<Vec<_>>() |
66 | .into_boxed_slice(), |
67 | ), |
68 | FormatItem::Optional(item) => Self::Optional(Box::new((*item).into())), |
69 | FormatItem::First(items) => Self::First( |
70 | items |
71 | .iter() |
72 | .cloned() |
73 | .map(Into::into) |
74 | .collect::<Vec<_>>() |
75 | .into_boxed_slice(), |
76 | ), |
77 | } |
78 | } |
79 | } |
80 | |
81 | impl From<Vec<FormatItem<'_>>> for OwnedFormatItem { |
82 | fn from(items: Vec<FormatItem<'_>>) -> Self { |
83 | items.as_slice().into() |
84 | } |
85 | } |
86 | |
87 | impl<'a, T: AsRef<[FormatItem<'a>]> + ?Sized> From<&T> for OwnedFormatItem { |
88 | fn from(items: &T) -> Self { |
89 | Self::Compound( |
90 | itemsVec |
91 | .as_ref() |
92 | .iter() |
93 | .cloned() |
94 | .map(Into::into) |
95 | .collect::<Vec<_>>() |
96 | .into_boxed_slice(), |
97 | ) |
98 | } |
99 | } |
100 | // endregion conversions from FormatItem |
101 | |
102 | // region: from variants |
103 | impl From<Component> for OwnedFormatItem { |
104 | fn from(component: Component) -> Self { |
105 | Self::Component(component) |
106 | } |
107 | } |
108 | |
109 | impl TryFrom<OwnedFormatItem> for Component { |
110 | type Error = error::DifferentVariant; |
111 | |
112 | fn try_from(value: OwnedFormatItem) -> Result<Self, Self::Error> { |
113 | match value { |
114 | OwnedFormatItem::Component(component: Component) => Ok(component), |
115 | _ => Err(error::DifferentVariant), |
116 | } |
117 | } |
118 | } |
119 | |
120 | impl From<Vec<Self>> for OwnedFormatItem { |
121 | fn from(items: Vec<Self>) -> Self { |
122 | Self::Compound(items.into_boxed_slice()) |
123 | } |
124 | } |
125 | |
126 | impl TryFrom<OwnedFormatItem> for Vec<OwnedFormatItem> { |
127 | type Error = error::DifferentVariant; |
128 | |
129 | fn try_from(value: OwnedFormatItem) -> Result<Self, Self::Error> { |
130 | match value { |
131 | OwnedFormatItem::Compound(items: Box<[OwnedFormatItem]>) => Ok(items.into_vec()), |
132 | _ => Err(error::DifferentVariant), |
133 | } |
134 | } |
135 | } |
136 | // endregion from variants |
137 | |
138 | // region: equality |
139 | impl PartialEq<Component> for OwnedFormatItem { |
140 | fn eq(&self, rhs: &Component) -> bool { |
141 | matches!(self, Self::Component(component) if component == rhs) |
142 | } |
143 | } |
144 | |
145 | impl PartialEq<OwnedFormatItem> for Component { |
146 | fn eq(&self, rhs: &OwnedFormatItem) -> bool { |
147 | rhs == self |
148 | } |
149 | } |
150 | |
151 | impl PartialEq<&[Self]> for OwnedFormatItem { |
152 | fn eq(&self, rhs: &&[Self]) -> bool { |
153 | matches!(self, Self::Compound(compound) if &&**compound == rhs) |
154 | } |
155 | } |
156 | |
157 | impl PartialEq<OwnedFormatItem> for &[OwnedFormatItem] { |
158 | fn eq(&self, rhs: &OwnedFormatItem) -> bool { |
159 | rhs == self |
160 | } |
161 | } |
162 | // endregion equality |
163 | |