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(),
}
}
}