sdecay-nolt 0.2.0

This is a helper proc-macro crate for `sdecay`
Documentation
#![allow(missing_docs, reason = "That's an internal procmacro crate")]

use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::ToTokens;
use syn::{
    AngleBracketedGenericArguments, AssocConst, AssocType, BareFnArg, BoundLifetimes, ConstParam,
    Constraint, GenericArgument, GenericParam, Ident, Lifetime, LifetimeParam,
    ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf, ReturnType, TraitBound,
    Type, TypeArray, TypeBareFn, TypeGroup, TypeImplTrait, TypeParam, TypeParamBound, TypeParen,
    TypePath, TypePtr, TypeReference, TypeSlice, TypeTraitObject, TypeTuple, parse_macro_input,
    punctuated::Punctuated,
};

trait Nolt {
    fn transform(&mut self);
}

impl<T: Nolt> Nolt for Box<T> {
    fn transform(&mut self) {
        T::transform(&mut **self);
    }
}

impl<T: Nolt> Nolt for Option<T> {
    fn transform(&mut self) {
        if let Some(s) = self.as_mut() {
            s.transform();
        }
    }
}

impl<T: Nolt> Nolt for Vec<T> {
    fn transform(&mut self) {
        self.iter_mut().for_each(T::transform);
    }
}

impl<T: Nolt, S> Nolt for Punctuated<T, S> {
    fn transform(&mut self) {
        self.iter_mut().for_each(T::transform);
    }
}

//

impl Nolt for Lifetime {
    fn transform(&mut self) {
        self.ident = Ident::new("static", Span::call_site());
    }
}

impl Nolt for GenericParam {
    fn transform(&mut self) {
        match self {
            GenericParam::Lifetime(LifetimeParam {
                lifetime, bounds, ..
            }) => {
                lifetime.transform();
                bounds.transform();
            }
            GenericParam::Type(TypeParam {
                bounds, default, ..
            }) => {
                bounds.transform();
                default.transform();
            }
            GenericParam::Const(ConstParam { ty, .. }) => {
                ty.transform();
            }
        }
    }
}

impl Nolt for BoundLifetimes {
    fn transform(&mut self) {
        self.lifetimes.transform();
    }
}

impl Nolt for BareFnArg {
    fn transform(&mut self) {
        self.ty.transform();
    }
}

impl Nolt for ReturnType {
    fn transform(&mut self) {
        match self {
            ReturnType::Default => {}
            ReturnType::Type(_, ty) => ty.transform(),
        }
    }
}

impl Nolt for GenericArgument {
    fn transform(&mut self) {
        match self {
            GenericArgument::Lifetime(lifetime) => lifetime.transform(),
            GenericArgument::Type(tp) => tp.transform(),
            GenericArgument::AssocType(AssocType { generics, ty, .. }) => {
                generics.transform();
                ty.transform();
            }
            GenericArgument::AssocConst(AssocConst { generics, .. }) => {
                generics.transform();
            }
            GenericArgument::Constraint(Constraint {
                generics, bounds, ..
            }) => {
                generics.transform();
                bounds.transform();
            }
            _ => {}
        }
    }
}

impl Nolt for AngleBracketedGenericArguments {
    fn transform(&mut self) {
        let Self { args, .. } = self;
        args.transform();
    }
}

impl Nolt for ParenthesizedGenericArguments {
    fn transform(&mut self) {
        let Self { inputs, output, .. } = self;
        inputs.transform();
        output.transform();
    }
}

impl Nolt for PathArguments {
    fn transform(&mut self) {
        match self {
            PathArguments::None => {}
            PathArguments::AngleBracketed(angle) => angle.transform(),
            PathArguments::Parenthesized(paren) => paren.transform(),
        }
    }
}

impl Nolt for PathSegment {
    fn transform(&mut self) {
        self.arguments.transform();
    }
}

impl Nolt for Path {
    fn transform(&mut self) {
        self.segments.transform();
    }
}

impl Nolt for TypeParamBound {
    fn transform(&mut self) {
        match self {
            syn::TypeParamBound::Trait(TraitBound {
                lifetimes, path, ..
            }) => {
                lifetimes.transform();
                path.transform();
            }
            syn::TypeParamBound::Lifetime(lifetime) => lifetime.transform(),
            _ => {}
        }
    }
}

impl Nolt for QSelf {
    fn transform(&mut self) {
        let Self { ty, .. } = self;
        ty.transform();
    }
}

impl Nolt for Type {
    fn transform(&mut self) {
        match self {
            Type::BareFn(TypeBareFn {
                lifetimes,
                inputs,
                output,
                ..
            }) => {
                lifetimes.transform();
                inputs.transform();
                output.transform();
            }
            Type::Group(TypeGroup { elem, .. })
            | Type::Paren(TypeParen { elem, .. })
            | Type::Ptr(TypePtr { elem, .. })
            | Type::Slice(TypeSlice { elem, .. })
            | Type::Array(TypeArray { elem, .. }) => {
                elem.transform();
            }
            Type::ImplTrait(TypeImplTrait { bounds, .. })
            | Type::TraitObject(TypeTraitObject { bounds, .. }) => bounds.transform(),
            Type::Path(TypePath { qself, path }) => {
                qself.transform();
                path.transform();
            }
            Type::Reference(TypeReference { lifetime, elem, .. }) => {
                lifetime.transform();
                elem.transform();
            }
            Type::Tuple(TypeTuple { elems, .. }) => elems.transform(),
            _ => {}
        }
    }
}

#[proc_macro]
pub fn nolt(input: TokenStream) -> TokenStream {
    let mut tp = parse_macro_input!(input as Type);
    tp.transform();
    tp.to_token_stream().into()
}