Skip to main content

time_macros/format_description/public/
mod.rs

1mod 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}