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 into_token_stream(self) -> TokenStream {
29        match self.version {
30            FormatDescriptionVersion::V1 | FormatDescriptionVersion::V2 => match self.inner {
31                OwnedFormatItemInner::Literal(bytes) => quote! {
32                    BorrowedFormatItem::Literal(#(Literal::byte_string(bytes.as_ref())))
33                },
34                OwnedFormatItemInner::StringLiteral(string) => quote! {
35                    BorrowedFormatItem::StringLiteral(#(string.as_ref()))
36                },
37                OwnedFormatItemInner::Component(component) => quote! {
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! {
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! {
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! {
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! {
78                    FormatDescriptionV3Inner::BorrowedLiteral(#(string.as_ref()))
79                },
80                OwnedFormatItemInner::Component(component) => {
81                    component.into_token_stream_with_enum_name("FormatDescriptionV3Inner")
82                }
83                OwnedFormatItemInner::Compound(items) => {
84                    let items = items
85                        .into_iter()
86                        .map(|item| {
87                            quote! { #S(Self { version: self.version, inner: item }), }
88                        })
89                        .collect::<TokenStream>();
90                    quote! {
91                        FormatDescriptionV3Inner::BorrowedCompound(const { &[#S(items)] })
92                    }
93                }
94                OwnedFormatItemInner::Optional { format, item } => {
95                    quote! {
96                        FormatDescriptionV3Inner::BorrowedOptional {
97                            format: #S(format),
98                            item: &#S(Self { version: self.version, inner: *item })
99                        }
100                    }
101                }
102                OwnedFormatItemInner::First(items) => {
103                    let items = items
104                        .into_iter()
105                        .map(|item| {
106                            quote! { #S(Self { version: self.version, inner: item }), }
107                        })
108                        .collect::<TokenStream>();
109                    quote! {
110                        FormatDescriptionV3Inner::BorrowedFirst(const { &[#S(items)] })
111                    }
112                }
113            },
114        }
115    }
116}