#![cfg_attr(doctest, doc = " ````no_test")]
#![cfg_attr(doctest, doc = " ````no_test")]
#![deny(clippy::correctness, clippy::suspicious)]
#![warn(clippy::complexity, clippy::perf, clippy::style, clippy::pedantic)]
#![warn(missing_docs)]
use proc_macro::TokenStream as TokenStream1;
use proc_macro2::{Ident, Span, TokenStream};
use quote::{quote, ToTokens};
use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated;
use syn::{parse_macro_input, parse_quote, Error, GenericParam, ItemTrait, Token, TypeParamBound};
#[proc_macro_attribute]
pub fn marker_trait(_: TokenStream1, input: TokenStream1) -> TokenStream1 {
parse_macro_input!(input as MarkerTrait)
.into_tokens()
.into()
}
struct MarkerTrait(ItemTrait);
impl MarkerTrait {
pub fn into_tokens(mut self) -> TokenStream {
let appendage = self.produce_appended_output();
let mut tokens = self.0.into_token_stream();
tokens.extend(appendage);
tokens
}
fn produce_appended_output(&mut self) -> TokenStream {
let ItemTrait {
ref unsafety,
ref ident,
ref generics,
ref mut supertraits,
..
} = self.0;
let g2 = generics.split_for_impl().1;
let mut generics = generics.clone();
let out_ident = Ident::new("__MarkerTrait__", Span::call_site());
generics
.params
.push(make_generic_param(&out_ident, supertraits));
let (g1, _, g3) = generics.split_for_impl();
quote! {
#[automatically_derived]
#[allow(clippy::all)]
#unsafety impl #g1 #ident #g2 for #out_ident #g3 {}
}
}
}
impl Parse for MarkerTrait {
fn parse(input: ParseStream) -> syn::Result<Self> {
const MSG_AUTO: &str = "auto trait is not allowed";
const MSG_SUPER: &str = "Expected at least one supertrait";
const MSG_EMPTY: &str = "Expected empty trait";
let trait_def = input.parse::<ItemTrait>()?;
if trait_def.auto_token.is_some() {
return Err(Error::new(Span::call_site(), MSG_AUTO));
}
if trait_def.supertraits.is_empty() {
return Err(Error::new(Span::call_site(), MSG_SUPER));
}
if !trait_def.items.is_empty() {
return Err(Error::new(Span::call_site(), MSG_EMPTY));
}
Ok(Self(trait_def))
}
}
fn make_generic_param(
ident: &Ident,
bounds: &Punctuated<TypeParamBound, Token![+]>,
) -> GenericParam {
parse_quote!(#ident: #bounds)
}