From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- third_party/rust/inherent/src/expand.rs | 138 ++++++++++++++++++++++++++++++ third_party/rust/inherent/src/lib.rs | 100 ++++++++++++++++++++++ third_party/rust/inherent/src/parse.rs | 69 +++++++++++++++ third_party/rust/inherent/src/verbatim.rs | 34 ++++++++ 4 files changed, 341 insertions(+) create mode 100644 third_party/rust/inherent/src/expand.rs create mode 100644 third_party/rust/inherent/src/lib.rs create mode 100644 third_party/rust/inherent/src/parse.rs create mode 100644 third_party/rust/inherent/src/verbatim.rs (limited to 'third_party/rust/inherent/src') diff --git a/third_party/rust/inherent/src/expand.rs b/third_party/rust/inherent/src/expand.rs new file mode 100644 index 0000000000..c840123dee --- /dev/null +++ b/third_party/rust/inherent/src/expand.rs @@ -0,0 +1,138 @@ +use crate::parse::TraitImpl; +use crate::verbatim::VerbatimFn; +use proc_macro2::{Span, TokenStream}; +use quote::{quote, quote_spanned}; +use syn::{Attribute, FnArg, Ident, ImplItem, Pat, Path, Signature, Visibility}; + +pub fn inherent(mut input: TraitImpl) -> TokenStream { + let impl_token = &input.impl_token; + let generics = &input.generics; + let where_clause = &input.generics.where_clause; + let trait_ = &input.trait_; + let ty = &input.self_ty; + + let fwd_methods: Vec<_> = input + .items + .iter() + .filter_map(|item| match item { + ImplItem::Fn(method) => Some(fwd_method( + trait_, + &method.attrs, + &method.vis, + &method.sig, + method.block.brace_token.span.join(), + )), + ImplItem::Verbatim(tokens) => { + if let Ok(method) = syn::parse2::(tokens.clone()) { + Some(fwd_method( + trait_, + &method.attrs, + &method.vis, + &method.sig, + method.semi_token.span, + )) + } else { + None + } + } + _ => None, + }) + .collect(); + + input.items = input + .items + .into_iter() + .filter_map(|item| match item { + ImplItem::Fn(mut method) => { + method.vis = Visibility::Inherited; + Some(ImplItem::Fn(method)) + } + ImplItem::Verbatim(tokens) => { + if syn::parse2::(tokens.clone()).is_ok() { + None + } else { + Some(ImplItem::Verbatim(tokens)) + } + } + item => Some(item), + }) + .collect(); + + let body = quote_spanned!(input.brace_token.span=> { #(#fwd_methods)* }); + + quote! { + #impl_token #generics #ty #where_clause #body + + #input + } +} + +fn fwd_method( + trait_: &Path, + attrs: &[Attribute], + vis: &Visibility, + sig: &Signature, + body_span: Span, +) -> TokenStream { + let constness = &sig.constness; + let asyncness = &sig.asyncness; + let unsafety = &sig.unsafety; + let abi = &sig.abi; + let fn_token = sig.fn_token; + let ident = &sig.ident; + let generics = &sig.generics; + let output = &sig.output; + let where_clause = &sig.generics.where_clause; + + let (arg_pat, arg_val): (Vec<_>, Vec<_>) = sig + .inputs + .pairs() + .enumerate() + .map(|(i, pair)| { + let (input, comma_token) = pair.into_tuple(); + match input { + FnArg::Receiver(receiver) => { + let self_token = receiver.self_token; + if receiver.reference.is_some() { + (quote!(#receiver #comma_token), quote!(#self_token)) + } else { + (quote!(#self_token #comma_token), quote!(#self_token)) + } + } + FnArg::Typed(arg) => { + let var = match arg.pat.as_ref() { + Pat::Ident(pat) => pat.ident.clone(), + _ => Ident::new(&format!("__arg{}", i), Span::call_site()), + }; + let colon_token = arg.colon_token; + let ty = &arg.ty; + (quote!(#var #colon_token #ty #comma_token), quote!(#var)) + } + } + }) + .unzip(); + + let types = generics.type_params().map(|param| ¶m.ident); + let body = quote!(::#ident::<#(#types,)*>(#(#arg_val,)*)); + let block = quote_spanned!(body_span=> { #body }); + let args = quote_spanned!(sig.paren_token.span=> (#(#arg_pat)*)); + + let has_doc = attrs.iter().any(|attr| attr.path().is_ident("doc")); + let default_doc = if has_doc { + None + } else { + let mut link = String::new(); + for segment in &trait_.segments { + link += &segment.ident.to_string(); + link += "::"; + } + let msg = format!("See [`{}{}`]", link, ident); + Some(quote!(#[doc = #msg])) + }; + + quote! { + #(#attrs)* + #default_doc + #vis #constness #asyncness #unsafety #abi #fn_token #ident #generics #args #output #where_clause #block + } +} diff --git a/third_party/rust/inherent/src/lib.rs b/third_party/rust/inherent/src/lib.rs new file mode 100644 index 0000000000..4a334666f7 --- /dev/null +++ b/third_party/rust/inherent/src/lib.rs @@ -0,0 +1,100 @@ +//! [![github]](https://github.com/dtolnay/inherent) [![crates-io]](https://crates.io/crates/inherent) [![docs-rs]](https://docs.rs/inherent) +//! +//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github +//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust +//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs +//! +//!
+//! +//! ##### An attribute macro to make trait methods callable without the trait in scope. +//! +//! # Example +//! +//! ```rust +//! mod types { +//! use inherent::inherent; +//! +//! trait Trait { +//! fn f(self); +//! } +//! +//! pub struct Struct; +//! +//! #[inherent] +//! impl Trait for Struct { +//! pub fn f(self) {} +//! } +//! } +//! +//! fn main() { +//! // types::Trait is not in scope, but method can be called. +//! types::Struct.f(); +//! } +//! ``` +//! +//! Without the `inherent` macro on the trait impl, this would have failed with the +//! following error: +//! +//! ```console +//! error[E0599]: no method named `f` found for type `types::Struct` in the current scope +//! --> src/main.rs:18:19 +//! | +//! 8 | pub struct Struct; +//! | ------------------ method `f` not found for this +//! ... +//! 18 | types::Struct.f(); +//! | ^ +//! | +//! = help: items from traits can only be used if the trait is implemented and in scope +//! = note: the following trait defines an item `f`, perhaps you need to implement it: +//! candidate #1: `types::Trait` +//! ``` +//! +//! The `inherent` macro expands to inherent methods on the `Self` type of the trait +//! impl that forward to the trait methods. In the case above, the generated code +//! would be: +//! +//! ```rust +//! # trait Trait { +//! # fn f(self); +//! # } +//! # +//! # pub struct Struct; +//! # +//! # impl Trait for Struct { +//! # fn f(self) {} +//! # } +//! # +//! impl Struct { +//! pub fn f(self) { +//! ::f(self) +//! } +//! } +//! ``` + +#![doc(html_root_url = "https://docs.rs/inherent/1.0.7")] +#![allow( + clippy::default_trait_access, + clippy::module_name_repetitions, + clippy::needless_doctest_main, + clippy::needless_pass_by_value +)] + +extern crate proc_macro; + +mod expand; +mod parse; +mod verbatim; + +use proc_macro::TokenStream; +use syn::parse::Nothing; +use syn::parse_macro_input; + +use crate::parse::TraitImpl; + +#[proc_macro_attribute] +pub fn inherent(args: TokenStream, input: TokenStream) -> TokenStream { + parse_macro_input!(args as Nothing); + let input = parse_macro_input!(input as TraitImpl); + expand::inherent(input).into() +} diff --git a/third_party/rust/inherent/src/parse.rs b/third_party/rust/inherent/src/parse.rs new file mode 100644 index 0000000000..92a91f624b --- /dev/null +++ b/third_party/rust/inherent/src/parse.rs @@ -0,0 +1,69 @@ +use proc_macro2::{Span, TokenStream}; +use quote::ToTokens; +use syn::parse::{Error, Parse, ParseStream, Result}; +use syn::token::Brace; +use syn::{Attribute, Generics, ImplItem, ItemImpl, Path, Token, Type}; + +#[derive(Clone)] +pub struct TraitImpl { + pub attrs: Vec, + pub defaultness: Option, + pub unsafety: Option, + pub impl_token: Token![impl], + pub generics: Generics, + pub trait_: Path, + pub for_token: Token![for], + pub self_ty: Type, + pub brace_token: Brace, + pub items: Vec, +} + +impl Parse for TraitImpl { + fn parse(input: ParseStream) -> Result { + let imp: ItemImpl = input.parse()?; + + let (trait_, for_token) = match imp.trait_ { + Some((_bang_token, trait_, for_token)) => (trait_, for_token), + None => { + return Err(Error::new( + Span::call_site(), + "must be placed on a trait impl", + )) + } + }; + + Ok(TraitImpl { + attrs: imp.attrs, + defaultness: imp.defaultness, + unsafety: imp.unsafety, + impl_token: imp.impl_token, + generics: imp.generics, + trait_, + for_token, + self_ty: *imp.self_ty, + brace_token: imp.brace_token, + items: imp.items, + }) + } +} + +impl ToTokens for TraitImpl { + fn to_tokens(&self, tokens: &mut TokenStream) { + let imp = self.clone(); + + ItemImpl::to_tokens( + &ItemImpl { + attrs: imp.attrs, + defaultness: imp.defaultness, + unsafety: imp.unsafety, + impl_token: imp.impl_token, + generics: imp.generics, + trait_: Some((None, imp.trait_, imp.for_token)), + self_ty: Box::new(imp.self_ty), + brace_token: imp.brace_token, + items: imp.items, + }, + tokens, + ); + } +} diff --git a/third_party/rust/inherent/src/verbatim.rs b/third_party/rust/inherent/src/verbatim.rs new file mode 100644 index 0000000000..d064f6ee1f --- /dev/null +++ b/third_party/rust/inherent/src/verbatim.rs @@ -0,0 +1,34 @@ +use proc_macro2::TokenStream; +use quote::{ToTokens, TokenStreamExt}; +use syn::parse::{Parse, ParseStream, Result}; +use syn::{Attribute, Signature, Token, Visibility}; + +pub struct VerbatimFn { + pub attrs: Vec, + pub vis: Visibility, + pub defaultness: Option, + pub sig: Signature, + pub semi_token: Token![;], +} + +impl Parse for VerbatimFn { + fn parse(input: ParseStream) -> Result { + Ok(VerbatimFn { + attrs: input.call(Attribute::parse_outer)?, + vis: input.parse()?, + defaultness: input.parse()?, + sig: input.parse()?, + semi_token: input.parse()?, + }) + } +} + +impl ToTokens for VerbatimFn { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(&self.attrs); + self.vis.to_tokens(tokens); + self.defaultness.to_tokens(tokens); + self.sig.to_tokens(tokens); + self.semi_token.to_tokens(tokens); + } +} -- cgit v1.2.3