|  | use proc_macro2::Ident; | 
|  | use quote::quote; | 
|  | use syn::parse::{Parse, ParseStream}; | 
|  | use syn::punctuated::Punctuated; | 
|  | use syn::spanned::Spanned; | 
|  | use syn::{ | 
|  | Attribute, Generics, ImplItem, Pat, PatIdent, Path, Signature, Token, TraitItem, | 
|  | TraitItemConst, TraitItemFn, TraitItemMacro, TraitItemType, Type, Visibility, WhereClause, | 
|  | braced, parse_macro_input, | 
|  | }; | 
|  |  | 
|  | pub(crate) fn extension( | 
|  | attr: proc_macro::TokenStream, | 
|  | input: proc_macro::TokenStream, | 
|  | ) -> proc_macro::TokenStream { | 
|  | let ExtensionAttr { vis, trait_ } = parse_macro_input!(attr as ExtensionAttr); | 
|  | let Impl { attrs, generics, self_ty, items, wc } = parse_macro_input!(input as Impl); | 
|  | let headers: Vec<_> = items | 
|  | .iter() | 
|  | .map(|item| match item { | 
|  | ImplItem::Fn(f) => TraitItem::Fn(TraitItemFn { | 
|  | attrs: scrub_attrs(&f.attrs), | 
|  | sig: scrub_header(f.sig.clone()), | 
|  | default: None, | 
|  | semi_token: Some(Token)), | 
|  | }), | 
|  | ImplItem::Const(ct) => TraitItem::Const(TraitItemConst { | 
|  | attrs: scrub_attrs(&ct.attrs), | 
|  | const_token: ct.const_token, | 
|  | ident: ct.ident.clone(), | 
|  | generics: ct.generics.clone(), | 
|  | colon_token: ct.colon_token, | 
|  | ty: ct.ty.clone(), | 
|  | default: None, | 
|  | semi_token: ct.semi_token, | 
|  | }), | 
|  | ImplItem::Type(ty) => TraitItem::Type(TraitItemType { | 
|  | attrs: scrub_attrs(&ty.attrs), | 
|  | type_token: ty.type_token, | 
|  | ident: ty.ident.clone(), | 
|  | generics: ty.generics.clone(), | 
|  | colon_token: None, | 
|  | bounds: Punctuated::new(), | 
|  | default: None, | 
|  | semi_token: ty.semi_token, | 
|  | }), | 
|  | ImplItem::Macro(mac) => TraitItem::Macro(TraitItemMacro { | 
|  | attrs: scrub_attrs(&mac.attrs), | 
|  | mac: mac.mac.clone(), | 
|  | semi_token: mac.semi_token, | 
|  | }), | 
|  | ImplItem::Verbatim(stream) => TraitItem::Verbatim(stream.clone()), | 
|  | _ => unimplemented!(), | 
|  | }) | 
|  | .collect(); | 
|  |  | 
|  | quote! { | 
|  | #(#attrs)* | 
|  | #vis trait #trait_ { | 
|  | #(#headers)* | 
|  | } | 
|  |  | 
|  | impl #generics #trait_ for #self_ty #wc { | 
|  | #(#items)* | 
|  | } | 
|  | } | 
|  | .into() | 
|  | } | 
|  |  | 
|  | /// Only keep `#[doc]` attrs. | 
|  | fn scrub_attrs(attrs: &[Attribute]) -> Vec<Attribute> { | 
|  | attrs | 
|  | .into_iter() | 
|  | .cloned() | 
|  | .filter(|attr| { | 
|  | let ident = &attr.path().segments[0].ident; | 
|  | ident == "doc" || ident == "must_use" | 
|  | }) | 
|  | .collect() | 
|  | } | 
|  |  | 
|  | /// Scrub arguments so that they're valid for trait signatures. | 
|  | fn scrub_header(mut sig: Signature) -> Signature { | 
|  | for (idx, input) in sig.inputs.iter_mut().enumerate() { | 
|  | match input { | 
|  | syn::FnArg::Receiver(rcvr) => { | 
|  | // `mut self` -> `self` | 
|  | if rcvr.reference.is_none() { | 
|  | rcvr.mutability.take(); | 
|  | } | 
|  | } | 
|  | syn::FnArg::Typed(arg) => match &mut *arg.pat { | 
|  | Pat::Ident(arg) => { | 
|  | // `ref mut ident @ pat` -> `ident` | 
|  | arg.by_ref.take(); | 
|  | arg.mutability.take(); | 
|  | arg.subpat.take(); | 
|  | } | 
|  | _ => { | 
|  | // `pat` -> `__arg0` | 
|  | arg.pat = Box::new( | 
|  | PatIdent { | 
|  | attrs: vec![], | 
|  | by_ref: None, | 
|  | mutability: None, | 
|  | ident: Ident::new(&format!("__arg{idx}"), arg.pat.span()), | 
|  | subpat: None, | 
|  | } | 
|  | .into(), | 
|  | ) | 
|  | } | 
|  | }, | 
|  | } | 
|  | } | 
|  | sig | 
|  | } | 
|  |  | 
|  | struct ExtensionAttr { | 
|  | vis: Visibility, | 
|  | trait_: Path, | 
|  | } | 
|  |  | 
|  | impl Parse for ExtensionAttr { | 
|  | fn parse(input: ParseStream<'_>) -> syn::Result<Self> { | 
|  | let vis = input.parse()?; | 
|  | let _: Token![trait] = input.parse()?; | 
|  | let trait_ = input.parse()?; | 
|  | Ok(ExtensionAttr { vis, trait_ }) | 
|  | } | 
|  | } | 
|  |  | 
|  | struct Impl { | 
|  | attrs: Vec<Attribute>, | 
|  | generics: Generics, | 
|  | self_ty: Type, | 
|  | items: Vec<ImplItem>, | 
|  | wc: Option<WhereClause>, | 
|  | } | 
|  |  | 
|  | impl Parse for Impl { | 
|  | fn parse(input: ParseStream<'_>) -> syn::Result<Self> { | 
|  | let attrs = input.call(Attribute::parse_outer)?; | 
|  | let _: Token![impl] = input.parse()?; | 
|  | let generics = input.parse()?; | 
|  | let self_ty = input.parse()?; | 
|  | let wc = input.parse()?; | 
|  |  | 
|  | let content; | 
|  | let _brace_token = braced!(content in input); | 
|  | let mut items = Vec::new(); | 
|  | while !content.is_empty() { | 
|  | items.push(content.parse()?); | 
|  | } | 
|  |  | 
|  | Ok(Impl { attrs, generics, self_ty, items, wc }) | 
|  | } | 
|  | } |