time_macros/format_description/public/
mod.rs1mod component;
2pub(super) mod modifier;
3
4use proc_macro::TokenStream;
5
6pub(crate) use self::component::Component;
7use crate::FormatDescriptionVersion;
8use crate::to_tokens::ToTokenStream;
9
10#[derive(Clone)]
11pub(crate) struct OwnedFormatItem {
12 pub(crate) version: FormatDescriptionVersion,
13 pub(crate) inner: OwnedFormatItemInner,
14}
15
16#[derive(Clone)]
17pub(crate) enum OwnedFormatItemInner {
18 Literal(Box<[u8]>),
19 StringLiteral(Box<str>),
20 Component(Component),
21 Compound(Box<[Self]>),
22 Optional { format: bool, item: Box<Self> },
23 First(Box<[Self]>),
24}
25
26impl ToTokenStream for OwnedFormatItem {
27 fn append_to(self, ts: &mut TokenStream) {
28 match self.version {
29 FormatDescriptionVersion::V1 | FormatDescriptionVersion::V2 => match self.inner {
30 OwnedFormatItemInner::Literal(bytes) => quote_append! { ts
31 BorrowedFormatItem::Literal(#(Literal::byte_string(bytes.as_ref())))
32 },
33 OwnedFormatItemInner::StringLiteral(string) => quote_append! { ts
34 BorrowedFormatItem::StringLiteral(#(string.as_ref()))
35 },
36 OwnedFormatItemInner::Component(component) => quote_append! { ts
37 BorrowedFormatItem::Component { 0: #S(component) }
38 },
39 OwnedFormatItemInner::Compound(items) => {
40 let items = items
41 .into_vec()
42 .into_iter()
43 .map(|item| {
44 quote_! { #S(Self { version: self.version, inner: item }), }
45 })
46 .collect::<TokenStream>();
47 quote_append! { ts
48 BorrowedFormatItem::Compound { 0: &[#S(items)] }
49 }
50 }
51 OwnedFormatItemInner::Optional { format, item } => {
52 if !format {
53 bug!("v1 and v2 format descriptions must format optional items")
54 }
55 quote_append! { ts
56 BorrowedFormatItem::Optional {
57 0: &#S(Self { version: self.version, inner: *item })
58 }
59 }
60 }
61 OwnedFormatItemInner::First(items) => {
62 let items = items
63 .into_vec()
64 .into_iter()
65 .map(|item| {
66 quote_! { #S(Self { version: self.version, inner: item }), }
67 })
68 .collect::<TokenStream>();
69 quote_append! { ts
70 BorrowedFormatItem::First { 0: &[#S(items)] }
71 }
72 }
73 },
74 FormatDescriptionVersion::V3 => match self.inner {
75 OwnedFormatItemInner::Literal(_) => {
76 bug!("v3 format descriptions should never have non-UTF8 literals")
77 }
78 OwnedFormatItemInner::StringLiteral(string) => quote_append! { ts
79 FormatDescriptionV3Inner::BorrowedLiteral(#(string.as_ref()))
80 },
81 OwnedFormatItemInner::Component(component) => {
82 quote_append! { ts
83 FormatDescriptionV3Inner::Component(#S(component))
84 }
85 }
86 OwnedFormatItemInner::Compound(items) => {
87 let items = items
88 .into_iter()
89 .map(|item| {
90 quote_! { #S(Self { version: self.version, inner: item }), }
91 })
92 .collect::<TokenStream>();
93 quote_append! { ts
94 FormatDescriptionV3Inner::BorrowedCompound(const { &[#S(items)] })
95 }
96 }
97 OwnedFormatItemInner::Optional { format, item } => {
98 quote_append! { ts
99 FormatDescriptionV3Inner::BorrowedOptional {
100 format: #S(format),
101 item: &#S(Self { version: self.version, inner: *item })
102 }
103 }
104 }
105 OwnedFormatItemInner::First(items) => {
106 let items = items
107 .into_iter()
108 .map(|item| {
109 quote_! { #S(Self { version: self.version, inner: item }), }
110 })
111 .collect::<TokenStream>();
112 quote_append! { ts
113 FormatDescriptionV3Inner::BorrowedFirst(const { &[#S(items)] })
114 }
115 }
116 },
117 }
118 }
119}