negative_proc_macros/
_mod.rs

1//! Crate not intended for direct use.
2//! Use https:://docs.rs/negative instead.
3// Templated by `cargo-generate` using https://github.com/danielhenrymantilla/proc-macro-template
4#![allow(nonstandard_style, unused_imports)]
5
6use ::core::{
7    mem,
8    ops::Not as _,
9};
10use ::proc_macro::{
11    TokenStream,
12};
13use ::proc_macro2::{*,
14    TokenStream as TokenStream2,
15};
16use ::quote::{
17    format_ident,
18    quote,
19    quote_spanned,
20    ToTokens,
21};
22use ::syn::{*,
23    parse::{Parse, Parser, ParseStream},
24    punctuated::Punctuated,
25    Result, // Explicitly shadow it
26    spanned::Spanned,
27};
28
29///
30#[proc_macro_attribute] pub
31fn negative_impl(
32    args: TokenStream,
33    input: TokenStream,
34) -> TokenStream
35{
36    negative_impl_impl(args.into(), input.into())
37    //  .map(|ret| { println!("{}", ret); ret })
38        .unwrap_or_else(|err| {
39            let mut errors =
40                err .into_iter()
41                    .map(|err| Error::new(
42                        err.span(),
43                        format_args!("`#[negative::negative_impl]`: {}", err),
44                    ))
45            ;
46            let mut err = errors.next().unwrap();
47            errors.for_each(|cur| err.combine(cur));
48            err.combine(Error::new(
49                Span::mixed_site(),
50                "expected syntax: `[unsafe] impl<…> !Trait for Type [where …] {}`",
51            ));
52            err.to_compile_error()
53        })
54        .into()
55}
56
57struct ItemImpl {
58    mb_unsafe: Option<Token![unsafe]>,
59    impl_: Token![impl],
60    generics: Generics,
61    bang_: Token![!],
62    Trait: Path,
63    for_: Token![for],
64    Receiver: Type,
65    where_: Option<Token![where]>,
66    rest: Vec<TokenTree>,
67}
68
69impl Parse for ItemImpl {
70    fn parse(input: ParseStream<'_>)
71      -> Result<Self>
72    {
73        let input = ItemImpl {
74            mb_unsafe: input.parse()?,
75            impl_: input.parse()?,
76            generics: input.parse()?,
77            bang_: input.parse()?,
78            Trait: input.parse()?,
79            for_: input.parse()?,
80            Receiver: input.parse()?,
81            where_: input.parse()?,
82            rest: input.parse::<TokenStream2>()?.into_iter().collect(),
83        };
84        let last = input.rest.last().ok_or_else(|| Error::new(
85            Span::mixed_site(),
86            "unexpected end of input",
87        ))?;
88        if  matches!(
89                last,
90                TokenTree::Group(g)
91                if g.delimiter() == Delimiter::Brace
92                && g.stream().is_empty()
93            )
94            .not()
95        {
96            return Err(Error::new_spanned(
97                last,
98                "expected `{}`",
99            ));
100        }
101        Ok(input)
102    }
103}
104
105fn negative_impl_impl(
106    args: TokenStream2,
107    input: TokenStream2,
108) -> Result<TokenStream2>
109{
110    // By default deny any attribute present.
111    let _: parse::Nothing = parse2(args)?;
112
113    let ItemImpl {
114        mb_unsafe,
115        impl_,
116        generics,
117        bang_,
118        Trait,
119        for_,
120        Receiver,
121        where_,
122        rest,
123    } = parse2(input)?;
124
125    let bang_span = bang_.span();
126    let where_ = where_.unwrap_or_else(|| Token![where](bang_span));
127    let trivially_false_extra_where_predicate = quote_spanned!(bang_span=>
128        for<'ඞ /* ' */> [()] : ::core::marker::Sized,
129    );
130
131    Ok(quote!(
132        #mb_unsafe
133        #impl_ #generics #Trait #for_ #Receiver
134        #where_
135            #trivially_false_extra_where_predicate
136        #(#rest)*
137    ))
138}