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
use syn::{self, punctuated::Punctuated}; use generator::Result; use spanned::Spanned; use proc_macro::Span; #[derive(Debug, Copy, Clone)] pub enum MetaItem<'a> { Ident(&'a syn::Ident), Literal(&'a syn::Lit), KeyValue(&'a syn::Ident, &'a syn::Lit), List(MetaItemList<'a>) } #[derive(Debug, Copy, Clone)] pub struct MetaItemList<'a> { pub ident: &'a syn::Ident, pub iter: &'a Punctuated<syn::NestedMeta, syn::token::Comma> } impl<'a> MetaItemList<'a> { pub fn iter(&self) -> impl Iterator<Item = MetaItem<'a>> { self.iter.iter().map(MetaItem::from) } } impl<'a> Spanned for MetaItemList<'a> { fn span(&self) -> Span { self.iter.span() } } impl<'a> From<&'a syn::Meta> for MetaItem<'a> { fn from(meta: &syn::Meta) -> MetaItem { match meta { syn::Meta::Word(i) => MetaItem::Ident(i), syn::Meta::NameValue(nv) => MetaItem::KeyValue(&nv.ident, &nv.lit), syn::Meta::List(list) => { MetaItem::List(MetaItemList { ident: &list.ident, iter: &list.nested }) } } } } impl<'a> From<&'a syn::NestedMeta> for MetaItem<'a> { fn from(nested: &syn::NestedMeta) -> MetaItem { match nested { syn::NestedMeta::Meta(meta) => MetaItem::from(meta), syn::NestedMeta::Literal(lit) => MetaItem::Literal(lit), } } } impl<'a> MetaItem<'a> { pub fn name(&self) -> Option<&syn::Ident> { use MetaItem::*; match self { Ident(i) | KeyValue(i, _) | List(MetaItemList { ident: i, .. }) => { Some(i) } _ => None } } pub fn description(&self) -> &'static str { match self { MetaItem::Ident(..) => "identifier", MetaItem::Literal(syn::Lit::Str(..)) => "string literal", MetaItem::Literal(syn::Lit::ByteStr(..)) => "byte string literal", MetaItem::Literal(syn::Lit::Byte(..)) => "byte literal", MetaItem::Literal(syn::Lit::Char(..)) => "character literal", MetaItem::Literal(syn::Lit::Int(..)) => "integer literal", MetaItem::Literal(syn::Lit::Float(..)) => "float literal", MetaItem::Literal(syn::Lit::Bool(..)) => "boolean literal", MetaItem::Literal(syn::Lit::Verbatim(..)) => "literal", MetaItem::KeyValue(..) => "key/value pair", MetaItem::List(..) => "list", } } pub fn is_bare(&self) -> bool { match self { MetaItem::Ident(..) | MetaItem::Literal(..) => true, MetaItem::KeyValue(..) | MetaItem::List(..) => false, } } pub fn lit(&self) -> Result<&syn::Lit> { match self { MetaItem::Literal(lit) | MetaItem::KeyValue(_, lit) => Ok(lit), _ => Err(self.span().error("expected literal or key/value pair")) } } pub fn value_span(&self) -> Span { match self { MetaItem::KeyValue(_, lit) => lit.span(), _ => self.span(), } } } impl<'a> Spanned for MetaItem<'a> { fn span(&self) -> Span { match self { MetaItem::Ident(i) => i.span(), MetaItem::Literal(l) => l.span(), MetaItem::KeyValue(i, l) => { i.span().join(l.span()).unwrap_or(Span::call_site()) } MetaItem::List(l) => l.span(), } } }