traitlit 0.2.2

This crate exposes an atribute for implementing traits for integer and float types.
Documentation
use syn::Attribute;
use syn::Type;
use syn::TypePath;
use syn::Path;
use syn::PathSegment;
use syn::PathArguments;
use syn::Ident;
use syn::parse::{ self, Parse, ParseStream };
use syn::punctuated::Punctuated;
use syn::Token;
use syn::bracketed;
use syn::token::Bracket;
use syn::punctuated::IntoIter;
use syn::punctuated::Pair;
use std::slice::Iter;
use proc_macro2::Span;

pub struct WithAttr<T>(pub Vec<Attribute>, pub T);

impl<T: Parse> Parse for WithAttr<T> {
    fn parse(input: ParseStream) -> parse::Result<Self> {
        Ok(WithAttr(input.call(Attribute::parse_outer)?, input.parse()?))
    }
}

enum LitSet {
    Named(Ident),
    Set(Bracket, Punctuated<WithAttr<Type>, Token!(,)>)
}

impl Parse for LitSet {
    fn parse(input: ParseStream) -> parse::Result<Self> {
        if input.peek(Ident) {
            input.parse().map(LitSet::Named)
        } else {
            let content;
            Ok(LitSet::Set(bracketed!(content in input), Punctuated::parse_terminated(&content)?))
        }
    }
}

impl IntoIterator for WithAttr<LitSet> {
    type Item = WithAttr<Type>;
    type IntoIter = SetIterator;
    fn into_iter(self) -> SetIterator {
        match self {
            WithAttr(attrs, LitSet::Named(ident)) => {
                if ident == "u_" {
                    SetIterator::Named(attrs, ident.span(), EMPTY_PATH, UINT.iter())
                } else if ident == "i_" {
                    SetIterator::Named(attrs, ident.span(), EMPTY_PATH, INT.iter())
                } else if ident == "f_" {
                    SetIterator::Named(attrs, ident.span(), EMPTY_PATH, FLOAT.iter())
                } else if ident == "NonZeroU_" {
                    SetIterator::Named(attrs, ident.span(), NUM_PATH, NON_ZERO_UINT.iter())
                } else if ident == "NonZeroI_" {
                    SetIterator::Named(attrs, ident.span(), NUM_PATH, NON_ZERO_INT.iter())
                } else {
                    ident.span().unwrap().error("Unknown type set").emit();
                    SetIterator::Set(attrs, Punctuated::new().into_iter())
                }
            },
            WithAttr(attrs, LitSet::Set(_, types)) => SetIterator::Set(attrs, types.into_iter()),
        }
    }
}

const EMPTY_PATH: &'static [&'static str] = &[];
const NUM_PATH: &'static [&'static str] = &["core", "num"];

const UINT: [&'static str; 6] = ["u8", "u16", "u32", "u64", "u128", "usize"];
const INT: [&'static str; 6] = ["i8", "i16", "i32", "i64", "i128", "isize"];
const FLOAT: [&'static str; 2] = ["f32", "f64"];

const NON_ZERO_UINT: [&'static str; 6] = ["NonZeroU8", "NonZeroU16", "NonZeroU32", "NonZeroU64", "NonZeroU128", "NonZeroUsize"];
const NON_ZERO_INT: [&'static str; 6] = ["NonZeroI8", "NonZeroI16", "NonZeroI32", "NonZeroI64", "NonZeroI128", "NonZeroIsize"];

enum SetIterator {
    Named(Vec<Attribute>, Span, &'static[&'static str], Iter<'static, &'static str>),
    Set(Vec<Attribute>, IntoIter<WithAttr<Type>, Token!(,)>),
}

impl Iterator for SetIterator {
    type Item = WithAttr<Type>;
    fn next(&mut self) -> Option<Self::Item> {
        match self {
            SetIterator::Set(attrs, types) => types.next().map(|WithAttr(a, t)|WithAttr({let mut attrs = attrs.clone(); attrs.extend(a); attrs}, t)),
            SetIterator::Named(attrs, span, path, iter) => iter.next().map(|name|
                WithAttr(attrs.clone(), Type::Path(TypePath {
                    qself: None,
                    path: Path {
                        leading_colon: None,
                        segments: path.iter()
                            .map(|name|Pair::new(PathSegment { ident: Ident::new(name, *span), arguments: PathArguments::None }, Some(Token!(::)(*span))))
                            .chain(::std::iter::once(Pair::new(PathSegment { ident: Ident::new(name, *span), arguments: PathArguments::None }, None)))
                            .collect()
                    }
                }))

            ),
        }
    }
}

pub struct Args {
    pub ident: Ident,
    _equal: Token!(=),
    pub types: Vec<WithAttr<Type>>,
}

impl Parse for Args {
    fn parse(input: ParseStream) -> parse::Result<Self> {
        Ok(Args {
            ident: input.parse()?,
            _equal: input.parse()?,
            types: Punctuated::<WithAttr<LitSet>, Token!(+)>::parse_separated_nonempty(input)?.into_iter().flatten().collect()
        })
    }
}