1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use quote::Tokens;
use syn;
mod parse;
use super::{get_elastic_attr_name_value, get_str_from_lit};
pub fn expand_derive(crate_root: Tokens, input: &syn::MacroInput) -> Result<Vec<Tokens>, DeriveDateFormatError> {
match input.body {
syn::Body::Struct(ref data) => match *data {
syn::VariantData::Unit => Ok(()),
_ => Err(DeriveDateFormatError::InvalidInput),
},
_ => Err(DeriveDateFormatError::InvalidInput),
}?;
let format = get_format_from_attr(input).ok_or(DeriveDateFormatError::MissingFormat)?;
let name = get_name_from_attr(input).unwrap_or(format);
let tokens: Vec<Tokens> = parse::to_tokens(format)?
.into_iter()
.map(|t| t.into_tokens(&crate_root))
.collect();
let derived = impl_date_format(crate_root, input, name, &tokens);
Ok(vec![derived])
}
fn impl_date_format(crate_root: Tokens, item: &syn::MacroInput, name: &str, format: &[Tokens]) -> Tokens {
let ty = &item.ident;
let parse_fn = quote!(
fn parse(date: &str) -> ::std::result::Result<#crate_root::derive::DateValue, #crate_root::derive::ParseError> {
let fmt = vec![ #(#format),* ];
#crate_root::derive::parse_from_tokens(date, fmt)
}
);
let format_fn = quote!(
fn format<'a>(date: &'a #crate_root::derive::DateValue) -> #crate_root::derive::FormattedDate<'a> {
let fmt = vec![ #(#format),* ];
#crate_root::derive::format_with_tokens(date, fmt)
}
);
let name_fn = quote!(
fn name() -> &'static str {
#name
}
);
quote!(
impl #crate_root::derive::DateFormat for #ty {
#parse_fn
#format_fn
#name_fn
}
)
}
fn get_format_from_attr<'a>(item: &'a syn::MacroInput) -> Option<&'a str> {
let val = get_elastic_attr_name_value("date_format", item);
val.and_then(|v| get_str_from_lit(v).ok())
}
fn get_name_from_attr<'a>(item: &'a syn::MacroInput) -> Option<&'a str> {
let val = get_elastic_attr_name_value("date_format_name", item);
val.and_then(|v| get_str_from_lit(v).ok())
}
impl<'a> parse::DateFormatToken<'a> {
fn into_tokens(self, crate_root: &Tokens) -> Tokens {
use self::parse::DateFormatToken::*;
match self {
Year => quote!(#crate_root::derive::Item::Numeric(#crate_root::derive::Numeric::Year, #crate_root::derive::Pad::Zero)),
Month => quote!(#crate_root::derive::Item::Numeric(#crate_root::derive::Numeric::Month, #crate_root::derive::Pad::Zero)),
DayOfMonth => quote!(#crate_root::derive::Item::Numeric(#crate_root::derive::Numeric::Day, #crate_root::derive::Pad::Zero)),
DayOfYear => quote!(#crate_root::derive::Item::Numeric(#crate_root::derive::Numeric::Ordinal, #crate_root::derive::Pad::Zero)),
Hour => quote!(#crate_root::derive::Item::Numeric(#crate_root::derive::Numeric::Hour, #crate_root::derive::Pad::Zero)),
Minute => quote!(#crate_root::derive::Item::Numeric(#crate_root::derive::Numeric::Minute, #crate_root::derive::Pad::Zero)),
Second => quote!(#crate_root::derive::Item::Numeric(#crate_root::derive::Numeric::Second, #crate_root::derive::Pad::Zero)),
Millisecond => quote!(#crate_root::derive::Item::Fixed(#crate_root::derive::Fixed::Nanosecond3)),
Utc => quote!(#crate_root::derive::Item::Literal("Z")),
Delim(s) => quote!(#crate_root::derive::Item::Literal(#s)),
Escaped(s) => quote!(#crate_root::derive::Item::Literal(#s)),
}
}
}
quick_error!{
#[derive(Debug)]
pub enum DeriveDateFormatError {
InvalidInput {
display("deriving a date format is only valid for unit structs")
}
MissingFormat {
display("missing date format. Add a `#[elastic(date_format=\"<format here>\")]`")
}
InvalidFormat(err: parse::Error) {
display("error parsing date format")
from()
}
}
}