devise_core/from_meta/
mod.rs1mod 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#[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}