interfacer-http-attribute 0.2.1

proc macro for interfacer-http
Documentation
use proc_macro::{Diagnostic, Level};
use proc_macro2::{Ident, TokenStream};
use quote::quote;
use std::convert::TryFrom;
use syn::parse::{Parse, Parser};
use syn::{punctuated::Punctuated, Attribute, Meta, NestedMeta, Path, Token};

#[derive(Clone)]
pub enum AttrMeta {
    Name(Ident),
    List {
        name: Ident,
        nested: Punctuated<NestedMeta, Token![,]>,
    },
}

pub fn try_parse<T: Parse>(token: TokenStream) -> Result<T, Diagnostic> {
    let copy = token.clone();
    <T as Parse>::parse.parse2(token).map_err(|err| {
        Diagnostic::new(
            Level::Error,
            format!("parse token({}) fail: {}", copy.to_string(), err),
        )
    })
}

impl TryFrom<Attribute> for AttrMeta {
    type Error = Diagnostic;
    fn try_from(attr: Attribute) -> Result<Self, Self::Error> {
        let raw_meta = attr.parse_meta().map_err(|err| {
            Diagnostic::new(
                Level::Error,
                format!("attr ({}) is not a meta: {}", quote!(#attr), err),
            )
        })?;
        match raw_meta {
            Meta::Path(ref path) => Ok(AttrMeta::Name(Self::parse_path(path)?)),
            Meta::List(list) => Ok(AttrMeta::List {
                name: Self::parse_path(&list.path)?,
                nested: list.nested,
            }),
            _ => Err(Diagnostic::new(
                Level::Error,
                format!("attr ({}) is not a valid AttrMeta", quote!(#attr)),
            )),
        }
    }
}

impl AttrMeta {
    pub fn name(&self) -> &Ident {
        match self {
            AttrMeta::Name(name) => name,
            AttrMeta::List { name, nested: _ } => name,
        }
    }

    pub fn parse_path(path: &Path) -> Result<Ident, Diagnostic> {
        if path.segments.len() != 1 {
            Err(Diagnostic::new(
                Level::Error,
                format!("path({}) is not a ident", quote!(#path)),
            ))
        } else {
            Ok(path.segments.first().unwrap().ident.clone())
        }
    }
}