diff options
author | Dirkjan Ochtman <dirkjan@ochtman.nl> | 2018-06-25 14:19:31 +0200 |
---|---|---|
committer | Dirkjan Ochtman <dirkjan@ochtman.nl> | 2018-06-25 14:19:31 +0200 |
commit | 4ecd886c6f557eee0446315fd5ad6f132cdca578 (patch) | |
tree | b88aa93a23a3c9c20bb7cafe207731a28ba22100 /askama_derive | |
parent | 9a3c57ac34c3507282828de4ef4f7ebbfb014f81 (diff) | |
download | askama-4ecd886c6f557eee0446315fd5ad6f132cdca578.tar.gz askama-4ecd886c6f557eee0446315fd5ad6f132cdca578.tar.bz2 askama-4ecd886c6f557eee0446315fd5ad6f132cdca578.zip |
Improve attribute handling code for efficiency and robustness
Diffstat (limited to 'askama_derive')
-rw-r--r-- | askama_derive/src/input.rs | 104 |
1 files changed, 57 insertions, 47 deletions
diff --git a/askama_derive/src/input.rs b/askama_derive/src/input.rs index afa4226..be9446f 100644 --- a/askama_derive/src/input.rs +++ b/askama_derive/src/input.rs @@ -1,3 +1,7 @@ +use proc_macro2::TokenStream; + +use quote::ToTokens; + use shared::path; use std::path::{Path, PathBuf}; @@ -16,59 +20,65 @@ pub struct TemplateInput<'a> { impl<'a> TemplateInput<'a> { pub fn new(ast: &'a syn::DeriveInput) -> TemplateInput<'a> { - let attr = ast.attrs - .iter() - .find(|a| a.interpret_meta().unwrap().name() == "template"); - if attr.is_none() { - panic!(format!( - "'template' attribute not found on struct '{}'", - ast.ident - )); + let mut meta = None; + for attr in &ast.attrs { + match attr.interpret_meta() { + Some(m) => if m.name() == "template" { + meta = Some(m) + }, + None => { + let mut tokens = TokenStream::new(); + attr.to_tokens(&mut tokens); + panic!("unable to interpret attribute: {}", tokens) + } + } } - let attr = attr.unwrap(); + let meta_list = match meta.expect("no attribute 'template' found") { + syn::Meta::List(inner) => inner, + _ => panic!("attribute 'template' has incorrect type"), + }; + let mut source = None; let mut print = Print::None; let mut escaping = None; let mut ext = None; - if let syn::Meta::List(ref inner) = attr.interpret_meta().unwrap() { - for nm_item in inner.nested.iter() { - if let syn::NestedMeta::Meta(ref item) = *nm_item { - if let syn::Meta::NameValue(ref pair) = *item { - match pair.ident.to_string().as_ref() { - "path" => if let syn::Lit::Str(ref s) = pair.lit { - if source.is_some() { - panic!("must specify 'source' or 'path', not both"); - } - source = Some(Source::Path(s.value())); - } else { - panic!("template path must be string literal"); - }, - "source" => if let syn::Lit::Str(ref s) = pair.lit { - if source.is_some() { - panic!("must specify 'source' or 'path', not both"); - } - source = Some(Source::Source(s.value())); - } else { - panic!("template source must be string literal"); - }, - "print" => if let syn::Lit::Str(ref s) = pair.lit { - print = s.value().into(); - } else { - panic!("print value must be string literal"); - }, - "escape" => if let syn::Lit::Str(ref s) = pair.lit { - escaping = Some(s.value().into()); - } else { - panic!("escape value must be string literal"); - }, - "ext" => if let syn::Lit::Str(ref s) = pair.lit { - ext = Some(s.value()); - } else { - panic!("ext value must be string literal"); - }, - attr => panic!("unsupported annotation key '{}' found", attr), - } + for nm_item in meta_list.nested { + if let syn::NestedMeta::Meta(ref item) = nm_item { + if let syn::Meta::NameValue(ref pair) = item { + match pair.ident.to_string().as_ref() { + "path" => if let syn::Lit::Str(ref s) = pair.lit { + if source.is_some() { + panic!("must specify 'source' or 'path', not both"); + } + source = Some(Source::Path(s.value())); + } else { + panic!("template path must be string literal"); + }, + "source" => if let syn::Lit::Str(ref s) = pair.lit { + if source.is_some() { + panic!("must specify 'source' or 'path', not both"); + } + source = Some(Source::Source(s.value())); + } else { + panic!("template source must be string literal"); + }, + "print" => if let syn::Lit::Str(ref s) = pair.lit { + print = s.value().into(); + } else { + panic!("print value must be string literal"); + }, + "escape" => if let syn::Lit::Str(ref s) = pair.lit { + escaping = Some(s.value().into()); + } else { + panic!("escape value must be string literal"); + }, + "ext" => if let syn::Lit::Str(ref s) = pair.lit { + ext = Some(s.value()); + } else { + panic!("ext value must be string literal"); + }, + attr => panic!("unsupported annotation key '{}' found", attr), } } } |