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
126
127
128
129
130
131
132
133
134
135
136
137
|
use path;
use std::borrow::Cow;
use std::path::PathBuf;
use syn;
pub struct TemplateInput<'a> {
pub ast: &'a syn::DeriveInput,
pub meta: TemplateMeta<'a>,
pub path: PathBuf,
pub source: Cow<'a, str>,
}
impl<'a> TemplateInput<'a> {
pub fn new(ast: &'a syn::DeriveInput) -> TemplateInput<'a> {
let meta = TemplateMeta::new(ast);
let (path, source) = match meta.source {
Source::Source(s) => (PathBuf::new(), Cow::Borrowed(s)),
Source::Path(s) => {
let path = path::find_template_from_path(&s, None);
let src = path::get_template_source(&path);
(path, Cow::Owned(src))
},
};
TemplateInput { ast, meta, path, source }
}
}
// Holds metadata for the template, based on the `template()` attribute.
pub struct TemplateMeta<'a> {
source: Source<'a>,
pub print: Print,
pub escaping: EscapeMode,
}
impl<'a> TemplateMeta<'a> {
fn new(ast: &'a syn::DeriveInput) -> TemplateMeta<'a> {
let attr = ast.attrs.iter().find(|a| a.name() == "template");
if attr.is_none() {
let msg = format!("'template' attribute not found on struct '{}'",
ast.ident.as_ref());
panic!(msg);
}
let attr = attr.unwrap();
let mut source = None;
let mut print = Print::None;
let mut escaping = EscapeMode::Html;
if let syn::MetaItem::List(_, ref inner) = attr.value {
for nm_item in inner {
if let syn::NestedMetaItem::MetaItem(ref item) = *nm_item {
if let syn::MetaItem::NameValue(ref key, ref val) = *item {
match key.as_ref() {
"path" => if let syn::Lit::Str(ref s, _) = *val {
if source.is_some() {
panic!("must specify 'source' or 'path', not both");
}
source = Some(Source::Path(s.as_ref()));
} else {
panic!("template path must be string literal");
},
"source" => if let syn::Lit::Str(ref s, _) = *val {
if source.is_some() {
panic!("must specify 'source' or 'path', not both");
}
source = Some(Source::Source(s.as_ref()));
} else {
panic!("template source must be string literal");
},
"print" => if let syn::Lit::Str(ref s, _) = *val {
print = (s.as_ref() as &str).into();
} else {
panic!("print value must be string literal");
},
"escape" => if let syn::Lit::Str(ref s, _) = *val {
escaping = (s.as_ref() as &str).into();
} else {
panic!("escape value must be string literal");
},
_ => { panic!("unsupported annotation key found") }
}
}
}
}
}
match source {
Some(s) => TemplateMeta { source: s, print, escaping },
None => panic!("template path or source not found in struct attributes"),
}
}
}
enum Source<'a> {
Path(&'a str),
Source(&'a str),
}
#[derive(PartialEq)]
pub enum EscapeMode {
Html,
None,
}
impl<'a> From<&'a str> for EscapeMode {
fn from(s: &'a str) -> EscapeMode {
use self::EscapeMode::*;
match s {
"html" => Html,
"none" => None,
v => panic!("invalid value for escape option: {}", v),
}
}
}
#[derive(PartialEq)]
pub enum Print {
All,
Ast,
Code,
None,
}
impl<'a> From<&'a str> for Print {
fn from(s: &'a str) -> Print {
use self::Print::*;
match s {
"all" => All,
"ast" => Ast,
"code" => Code,
"none" => None,
v => panic!("invalid value for print option: {}", v),
}
}
}
|