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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
mod meta_item;

use syn::{self, Lit::*};

pub use self::meta_item::{MetaItem, MetaItemList};

use generator::Result;
use spanned::Spanned;
use proc_macro::Span;

// Spans of k/v pair, key, then value.
#[derive(Copy, Clone)]
pub struct SpanWrapped<T> {
    pub span: Span,
    pub full_span: Span,
    pub value: T,
}

pub trait FromMeta: Sized {
    fn from_meta(meta: MetaItem) -> Result<Self>;

    fn from_attr(name: &str, attr: &syn::Attribute) -> Result<Self> {
        let meta = attr.interpret_meta().ok_or_else(|| {
            attr.span()
                .error("malformed attribute")
                .help(format!("expected syntax: #[{}(key = value, ..)]", name))
        })?;

        if let syn::Meta::List(list) = meta {
            let list = MetaItemList { ident: &list.ident, iter: &list.nested };
            Self::from_meta(MetaItem::List(list))
        } else {
            Err(meta.span()
                    .error("malformed attribute: expected list")
                    .help(format!("expected syntax: #[{}(key = value, ..)]", name)))
        }
    }

    fn from_attrs(name: &str, attrs: &[syn::Attribute]) -> Option<Result<Self>> {
        let tokens = name.parse()
            .expect(&format!("`{}` contained invalid tokens", name));

        let path = syn::parse(tokens)
            .expect(&format!("`{}` was not a valid path", name));

        let mut matches = attrs.iter().filter(|attr| attr.path == path);
        let attr = matches.next()?;

        if let Some(extra) = matches.next() {
            let msg = format!("duplicate invocation of `{}` attribute", name);
            return Some(Err(extra.span().error(msg)));
        }

        Some(Self::from_attr(name, attr))
    }

    fn default() -> Option<Self> {
        None
    }
}

impl FromMeta for isize {
    fn from_meta(meta: MetaItem) -> Result<Self> {
        if let Int(i) = meta.lit()? {
            if i.value() <= isize::max_value() as u64 {
                return Ok(i.value() as isize);
            }

            return Err(meta.value_span().error("value is out of range for `isize`"));
        }

        Err(meta.value_span().error("invalid value: expected integer literal"))
    }
}

impl FromMeta for usize {
    fn from_meta(meta: MetaItem) -> Result<Self> {
        if let Int(i) = meta.lit()? {
            if i.value() <= usize::max_value() as u64 {
                return Ok(i.value() as usize);
            }

            return Err(meta.value_span().error("value is out of range for `usize`"));
        }

        Err(meta.value_span().error("invalid value: expected unsigned integer literal"))
    }
}

impl FromMeta for String {
    fn from_meta(meta: MetaItem) -> Result<Self> {
        if let Str(s) = meta.lit()? {
            return Ok(s.value());
        }

        Err(meta.value_span().error("invalid value: expected string literal"))
    }
}

impl FromMeta for bool {
    fn from_meta(meta: MetaItem) -> Result<Self> {
        if let MetaItem::Ident(_) = meta {
            return Ok(true);
        }

        if let Bool(b) = meta.lit()? {
            return Ok(b.value);
        }

        return Err(meta.value_span().error("invalid value: expected boolean"));
    }
}

impl<T: FromMeta> FromMeta for Option<T> {
    fn from_meta(meta: MetaItem) -> Result<Self> {
        T::from_meta(meta).map(Some)
    }

    fn default() -> Option<Self> {
        Some(None)
    }
}

impl<T: FromMeta> FromMeta for SpanWrapped<T> {
    fn from_meta(meta: MetaItem) -> Result<Self> {
        let span = meta.value_span();
        let full_span = meta.span();
        T::from_meta(meta).map(|value| SpanWrapped { full_span, span, value })
    }
}

impl<T: ::quote::ToTokens> ::quote::ToTokens for SpanWrapped<T> {
    fn to_tokens(&self, tokens: &mut ::proc_macro2::TokenStream) {
        self.value.to_tokens(tokens)
    }
}

use std::ops::Deref;

impl<T> Deref for SpanWrapped<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.value
    }
}

use std::fmt;

impl<T: fmt::Debug> fmt::Debug for SpanWrapped<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple("SpanWrapped")
            .field(&self.value)
            .finish()
    }
}