1//! A format item with owned data.
2
3use alloc::boxed::Box;
4use alloc::string::String;
5use alloc::vec::Vec;
6use core::fmt;
7
8use crate::error;
9use 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)]
14pub 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
36impl 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
49impl From<FormatItem<'_>> for OwnedFormatItem {
50 fn from(item: FormatItem<'_>) -> Self {
51 (&item).into()
52 }
53}
54
55impl 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
81impl From<Vec<FormatItem<'_>>> for OwnedFormatItem {
82 fn from(items: Vec<FormatItem<'_>>) -> Self {
83 items.as_slice().into()
84 }
85}
86
87impl<'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
103impl From<Component> for OwnedFormatItem {
104 fn from(component: Component) -> Self {
105 Self::Component(component)
106 }
107}
108
109impl 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
120impl From<Vec<Self>> for OwnedFormatItem {
121 fn from(items: Vec<Self>) -> Self {
122 Self::Compound(items.into_boxed_slice())
123 }
124}
125
126impl 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
139impl PartialEq<Component> for OwnedFormatItem {
140 fn eq(&self, rhs: &Component) -> bool {
141 matches!(self, Self::Component(component) if component == rhs)
142 }
143}
144
145impl PartialEq<OwnedFormatItem> for Component {
146 fn eq(&self, rhs: &OwnedFormatItem) -> bool {
147 rhs == self
148 }
149}
150
151impl PartialEq<&[Self]> for OwnedFormatItem {
152 fn eq(&self, rhs: &&[Self]) -> bool {
153 matches!(self, Self::Compound(compound) if &&**compound == rhs)
154 }
155}
156
157impl PartialEq<OwnedFormatItem> for &[OwnedFormatItem] {
158 fn eq(&self, rhs: &OwnedFormatItem) -> bool {
159 rhs == self
160 }
161}
162// endregion equality
163