devise_core/from_meta/
mod.rs

1mod meta_item;
2
3use std::convert::TryFrom;
4use std::ops::{Deref, DerefMut};
5
6use syn::parse::Parse;
7use syn::{self, Lit::*, spanned::Spanned};
8use proc_macro2_diagnostics::SpanDiagnosticExt;
9use proc_macro2::{Span, TokenStream};
10
11use generator::Result;
12
13pub use self::meta_item::MetaItem;
14
15// Spans of k/v pair, key, then value.
16#[derive(Copy, Clone)]
17pub struct SpanWrapped<T> {
18    pub span: Span,
19    pub key_span: Option<Span>,
20    pub full_span: Span,
21    pub value: T,
22}
23
24pub trait FromMeta: Sized {
25    fn from_meta(meta: &MetaItem) -> Result<Self>;
26
27    fn from_attr(attr: &syn::Attribute) -> Result<Self> {
28        Self::from_meta(&MetaItem::try_from(attr.meta.clone())?)
29    }
30
31    fn from_attrs(name: &str, attrs: &[syn::Attribute]) -> Result<Vec<Self>> {
32        let tokens = name.parse()
33            .expect(&format!("`{}` contained invalid tokens", name));
34
35        let path = syn::parse(tokens)
36            .expect(&format!("`{}` was not a valid path", name));
37
38        let items = attrs.iter()
39            .filter(|attr| attr.path() == &path)
40            .map(|attr| Self::from_attr(attr))
41            .collect::<Result<Vec<_>>>()?;
42
43        if items.is_empty() {
44            if let Some(default) = Self::default() {
45                return Ok(vec![default]);
46            }
47        }
48
49        Ok(items)
50    }
51
52    fn one_from_attrs(name: &str, attrs: &[syn::Attribute]) -> Result<Option<Self>> {
53        let tokens = name.parse()
54            .expect(&format!("`{}` contained invalid tokens", name));
55
56        let path = syn::parse(tokens)
57            .expect(&format!("`{}` was not a valid path", name));
58
59        let mut raw_attrs = attrs.iter().filter(|attr| attr.path() == &path);
60        if let Some(attr) = raw_attrs.nth(1) {
61            let msg = format!("duplicate invocation of `{}` attribute", name);
62            return Err(attr.span().error(msg));
63        }
64
65        Ok(Self::from_attrs(name, attrs)?.pop())
66    }
67
68    fn default() -> Option<Self> {
69        None
70    }
71}
72
73impl FromMeta for isize {
74    fn from_meta(meta: &MetaItem) -> Result<Self> {
75        if let Int(i) = meta.lit()? {
76            if let Ok(v) = i.base10_parse::<isize>() {
77                return Ok(v);
78            }
79
80            return Err(meta.value_span().error("value is out of range for `isize`"));
81        }
82
83        Err(meta.value_span().error("invalid value: expected integer literal"))
84    }
85}
86
87impl FromMeta for usize {
88    fn from_meta(meta: &MetaItem) -> Result<Self> {
89        if let Int(i) = meta.lit()? {
90            if let Ok(v) = i.base10_parse::<usize>() {
91                return Ok(v);
92            }
93
94            return Err(meta.value_span().error("value is out of range for `usize`"));
95        }
96
97        Err(meta.value_span().error("invalid value: expected unsigned integer literal"))
98    }
99}
100
101impl FromMeta for String {
102    fn from_meta(meta: &MetaItem) -> Result<Self> {
103        if let Str(s) = meta.lit()? {
104            return Ok(s.value());
105        }
106
107        Err(meta.value_span().error("invalid value: expected string literal"))
108    }
109}
110
111impl FromMeta for bool {
112    fn from_meta(meta: &MetaItem) -> Result<Self> {
113        if let MetaItem::Path(_) = meta {
114            return Ok(true);
115        }
116
117        if let Bool(b) = meta.lit()? {
118            return Ok(b.value);
119        }
120
121        return Err(meta.value_span().error("invalid value: expected boolean"));
122    }
123}
124
125impl FromMeta for syn::Expr {
126    fn from_meta(meta: &MetaItem) -> Result<Self> {
127        meta.expr().map(|v| v.clone())
128    }
129}
130
131impl<T: FromMeta> FromMeta for Option<T> {
132    fn from_meta(meta: &MetaItem) -> Result<Self> {
133        T::from_meta(meta).map(Some)
134    }
135
136    fn default() -> Option<Self> {
137        Some(None)
138    }
139}
140
141impl<T: Parse, P: Parse> FromMeta for syn::punctuated::Punctuated<T, P> {
142    fn from_meta(meta: &MetaItem) -> Result<Self> {
143        meta.parse_value_with(Self::parse_terminated, "punctuated list")
144    }
145}
146
147impl<T: FromMeta> FromMeta for SpanWrapped<T> {
148    fn from_meta(meta: &MetaItem) -> Result<Self> {
149        let span = meta.value_span();
150        let key_span = meta.attr_path().map(|i| i.span());
151        let full_span = meta.span();
152        T::from_meta(meta).map(|value| SpanWrapped { full_span, key_span, span, value })
153    }
154}
155
156impl FromMeta for TokenStream {
157    fn from_meta(meta: &MetaItem) -> Result<Self> {
158        meta.parse_value("token stream")
159    }
160}
161
162impl<T: ::quote::ToTokens> ::quote::ToTokens for SpanWrapped<T> {
163    fn to_tokens(&self, tokens: &mut ::proc_macro2::TokenStream) {
164        self.value.to_tokens(tokens)
165    }
166}
167
168impl<T> Deref for SpanWrapped<T> {
169    type Target = T;
170
171    fn deref(&self) -> &T {
172        &self.value
173    }
174}
175
176impl<T> DerefMut for SpanWrapped<T> {
177    fn deref_mut(&mut self) -> &mut Self::Target {
178        &mut self.value
179    }
180}
181
182use std::fmt;
183
184impl<T: fmt::Debug> fmt::Debug for SpanWrapped<T> {
185    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
186        f.debug_tuple("SpanWrapped")
187            .field(&self.value)
188            .finish()
189    }
190}