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