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, PartialEq, Eq)]
15pub 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")]
38impl 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
50impl From<Component> for BorrowedFormatItem<'_> {
51 fn from(component: Component) -> Self {
52 Self::Component(component)
53 }
54}
55
56impl 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
67impl<'a> From<&'a [BorrowedFormatItem<'_>]> for BorrowedFormatItem<'a> {
68 fn from(items: &'a [BorrowedFormatItem<'_>]) -> Self {
69 Self::Compound(items)
70 }
71}
72
73impl<'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
84impl PartialEq<Component> for BorrowedFormatItem<'_> {
85 fn eq(&self, rhs: &Component) -> bool {
86 matches!(self, Self::Component(component) if component == rhs)
87 }
88}
89
90impl PartialEq<BorrowedFormatItem<'_>> for Component {
91 fn eq(&self, rhs: &BorrowedFormatItem<'_>) -> bool {
92 rhs == self
93 }
94}
95
96impl PartialEq<&[Self]> for BorrowedFormatItem<'_> {
97 fn eq(&self, rhs: &&[Self]) -> bool {
98 matches!(self, Self::Compound(compound) if compound == rhs)
99 }
100}
101
102impl PartialEq<BorrowedFormatItem<'_>> for &[BorrowedFormatItem<'_>] {
103 fn eq(&self, rhs: &BorrowedFormatItem<'_>) -> bool {
104 rhs == self
105 }
106}
107