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 let tokens = component.into_token_stream();
84 let mut iter = tokens.into_iter().peekable();
85 if let Some(first) = iter.peek_mut() {
86 *first = proc_macro::TokenTree::Ident(proc_macro::Ident::new(
87 "FormatDescriptionV3Inner",
88 proc_macro::Span::mixed_site(),
89 ));
90 } else {
91 bug!("component should have at least one token")
92 }
93 ts.extend(iter);
94 }
95 OwnedFormatItemInner::Compound(items) => {
96 let items = items
97 .into_iter()
98 .map(|item| {
99 quote_! { #S(Self { version: self.version, inner: item }), }
100 })
101 .collect::<TokenStream>();
102 quote_append! { ts
103 FormatDescriptionV3Inner::BorrowedCompound(const { &[#S(items)] })
104 }
105 }
106 OwnedFormatItemInner::Optional { format, item } => {
107 quote_append! { ts
108 FormatDescriptionV3Inner::BorrowedOptional {
109 format: #S(format),
110 item: &#S(Self { version: self.version, inner: *item })
111 }
112 }
113 }
114 OwnedFormatItemInner::First(items) => {
115 let items = items
116 .into_iter()
117 .map(|item| {
118 quote_! { #S(Self { version: self.version, inner: item }), }
119 })
120 .collect::<TokenStream>();
121 quote_append! { ts
122 FormatDescriptionV3Inner::BorrowedFirst(const { &[#S(items)] })
123 }
124 }
125 },
126 }
127 }
128}