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