devise_core/from_meta/
mod.rsmod meta_item;
use std::convert::TryFrom;
use std::ops::{Deref, DerefMut};
use syn::parse::Parse;
use syn::{self, Lit::*, spanned::Spanned};
use proc_macro2_diagnostics::SpanDiagnosticExt;
use proc_macro2::{Span, TokenStream};
use generator::Result;
pub use self::meta_item::MetaItem;
#[derive(Copy, Clone)]
pub struct SpanWrapped<T> {
pub span: Span,
pub key_span: Option<Span>,
pub full_span: Span,
pub value: T,
}
pub trait FromMeta: Sized {
fn from_meta(meta: &MetaItem) -> Result<Self>;
fn from_attr(attr: &syn::Attribute) -> Result<Self> {
Self::from_meta(&MetaItem::try_from(attr.meta.clone())?)
}
fn from_attrs(name: &str, attrs: &[syn::Attribute]) -> Result<Vec<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 items = attrs.iter()
.filter(|attr| attr.path() == &path)
.map(|attr| Self::from_attr(attr))
.collect::<Result<Vec<_>>>()?;
if items.is_empty() {
if let Some(default) = Self::default() {
return Ok(vec![default]);
}
}
Ok(items)
}
fn one_from_attrs(name: &str, attrs: &[syn::Attribute]) -> Result<Option<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 raw_attrs = attrs.iter().filter(|attr| attr.path() == &path);
if let Some(attr) = raw_attrs.nth(1) {
let msg = format!("duplicate invocation of `{}` attribute", name);
return Err(attr.span().error(msg));
}
Ok(Self::from_attrs(name, attrs)?.pop())
}
fn default() -> Option<Self> {
None
}
}
impl FromMeta for isize {
fn from_meta(meta: &MetaItem) -> Result<Self> {
if let Int(i) = meta.lit()? {
if let Ok(v) = i.base10_parse::<isize>() {
return Ok(v);
}
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 let Ok(v) = i.base10_parse::<usize>() {
return Ok(v);
}
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::Path(_) = 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 FromMeta for syn::Expr {
fn from_meta(meta: &MetaItem) -> Result<Self> {
meta.expr().map(|v| v.clone())
}
}
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: Parse, P: Parse> FromMeta for syn::punctuated::Punctuated<T, P> {
fn from_meta(meta: &MetaItem) -> Result<Self> {
meta.parse_value_with(Self::parse_terminated, "punctuated list")
}
}
impl<T: FromMeta> FromMeta for SpanWrapped<T> {
fn from_meta(meta: &MetaItem) -> Result<Self> {
let span = meta.value_span();
let key_span = meta.attr_path().map(|i| i.span());
let full_span = meta.span();
T::from_meta(meta).map(|value| SpanWrapped { full_span, key_span, span, value })
}
}
impl FromMeta for TokenStream {
fn from_meta(meta: &MetaItem) -> Result<Self> {
meta.parse_value("token stream")
}
}
impl<T: ::quote::ToTokens> ::quote::ToTokens for SpanWrapped<T> {
fn to_tokens(&self, tokens: &mut ::proc_macro2::TokenStream) {
self.value.to_tokens(tokens)
}
}
impl<T> Deref for SpanWrapped<T> {
type Target = T;
fn deref(&self) -> &T {
&self.value
}
}
impl<T> DerefMut for SpanWrapped<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut 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()
}
}