ext_trait_proc_macros/
mod.rs1#![allow(nonstandard_style, unused_imports)]
4
5use ::core::{
6 ops::Not as _,
7};
8use ::proc_macro::{
9 TokenStream,
10};
11use ::proc_macro2::{
12 Span,
13 TokenStream as TokenStream2,
14 TokenTree as TT,
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 spanned::Spanned,
26 Result, };
28
29#[proc_macro_attribute] pub
31fn extension (
32 attrs: TokenStream,
33 input: TokenStream,
34) -> TokenStream
35{
36 extension_impl(attrs.into(), input.into())
37 .unwrap_or_else(|err| {
39 let mut errors =
40 err .into_iter()
41 .map(|err| Error::new(
42 err.span(),
43 format_args!("`#[extension(trait …)]`: {}", err),
44 ))
45 ;
46 let mut err = errors.next().unwrap();
47 errors.for_each(|cur| err.combine(cur));
48 err.to_compile_error()
49 })
50 .into()
51}
52
53struct Attrs {
54 pub_: Visibility,
55 trait_: Token![trait],
56 TraitName: Ident,
57}
58
59impl Parse for Attrs {
60 fn parse (input: ParseStream<'_>)
61 -> Result<Attrs>
62 {
63 Ok(Self {
64 pub_: input.parse()?,
65 trait_: input.parse()?,
66 TraitName: input.parse()?,
67 })
68 }
69}
70
71#[cfg(any())]
73const _: () = {
74 use ::ext_trait::extension;
75
76 #[extension(trait disregard_err)]
77 impl<T, E> Result<T, E> {
78 fn disregard_err(self) -> Option<T> { self }
79 }
80};
81
82fn extension_impl (
83 attrs: TokenStream2,
84 input: TokenStream2,
85) -> Result<TokenStream2>
86{
87 let trait_def_span = attrs.span();
88 let Attrs { pub_, trait_, TraitName } = parse2(attrs)?;
89 let ref mut item_impl: ItemImpl = parse2(input)?;
90 let (intro_generics, fwd_generics, where_clause) = item_impl.generics.split_for_impl();
91 match Option::replace(
92 &mut item_impl.trait_,
93 (None, parse_quote!( #TraitName #fwd_generics ), <_>::default()),
94 )
95 {
96 | Some((_, _, extraneous_for)) => return Err(Error::new_spanned(
97 extraneous_for,
98 "expected inherent `impl<…> Type<…>` syntax",
99 )),
100 | _ => {},
101 }
102 let ref item_impl = item_impl;
103 let each_entry = item_impl.items.iter().map(|it| Ok(match it {
104 | ImplItem::Const(ImplItemConst {
109 vis: pub_,
110 defaultness: default_,
111 const_token: const_,
112 ident: CONST_NAME @ _,
113 ty: Ty @ _,
114 ..
115 }) => quote!(
116 #pub_
117 #default_
118 #const_ #CONST_NAME: #Ty;
119 ),
120
121 | ImplItem::Method(ImplItemMethod {
122 vis: pub_,
123 defaultness: default_,
124 sig,
125 ..
126 }) => {
127 let mut sig = sig.clone();
128 sig.inputs.iter_mut().for_each(|fn_arg| match fn_arg {
129 | FnArg::Receiver(Receiver { reference, mutability, .. }) => {
130 if reference.is_none() {
131 *mutability = None;
132 }
133 },
134 | FnArg::Typed(PatType { pat, .. }) => {
135 *pat = parse_quote!( _ );
136 },
137 });
138 quote!(
139 #pub_
140 #default_
141 #sig;
142 )
143 },
144
145 | ImplItem::Type(ImplItemType {
146 vis: pub_,
147 defaultness: default_,
148 type_token: type_,
149 ident: TypeName @ _,
150 generics,
151 semi_token: SEMICOLON @ _,
152 ..
153 }) => quote! (
154 #pub_
155 #default_
156 #type_ #TypeName #generics
157 :
158 ?::ext_trait::__::core::marker::Sized
159 #SEMICOLON
160 ),
161
162 | _ => return Err(Error::new_spanned(it, "unsupported `impl` entry")),
163 })).collect::<Result<Vec<_>>>()?;
164 Ok(quote_spanned!(trait_def_span=>
165 #[allow(nonstandard_style)]
166 #pub_
167 #trait_ #TraitName #intro_generics
168 #where_clause
169 {
170 #(#each_entry)*
171 }
172
173 #item_impl
174 ))
175}