summaryrefslogtreecommitdiffstats
path: root/third_party/rust/async-trait/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/async-trait/src
parentInitial commit. (diff)
downloadfirefox-esr-upstream.tar.xz
firefox-esr-upstream.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--third_party/rust/async-trait/src/args.rs36
-rw-r--r--third_party/rust/async-trait/src/bound.rs48
-rw-r--r--third_party/rust/async-trait/src/expand.rs502
-rw-r--r--third_party/rust/async-trait/src/lib.rs340
-rw-r--r--third_party/rust/async-trait/src/lifetime.rs112
-rw-r--r--third_party/rust/async-trait/src/parse.rs34
-rw-r--r--third_party/rust/async-trait/src/receiver.rs179
7 files changed, 1251 insertions, 0 deletions
diff --git a/third_party/rust/async-trait/src/args.rs b/third_party/rust/async-trait/src/args.rs
new file mode 100644
index 0000000000..72d97e9525
--- /dev/null
+++ b/third_party/rust/async-trait/src/args.rs
@@ -0,0 +1,36 @@
+use proc_macro2::Span;
+use syn::parse::{Error, Parse, ParseStream, Result};
+use syn::Token;
+
+#[derive(Copy, Clone)]
+pub struct Args {
+ pub local: bool,
+}
+
+mod kw {
+ syn::custom_keyword!(Send);
+}
+
+impl Parse for Args {
+ fn parse(input: ParseStream) -> Result<Self> {
+ match try_parse(input) {
+ Ok(args) if input.is_empty() => Ok(args),
+ _ => Err(error()),
+ }
+ }
+}
+
+fn try_parse(input: ParseStream) -> Result<Args> {
+ if input.peek(Token![?]) {
+ input.parse::<Token![?]>()?;
+ input.parse::<kw::Send>()?;
+ Ok(Args { local: true })
+ } else {
+ Ok(Args { local: false })
+ }
+}
+
+fn error() -> Error {
+ let msg = "expected #[async_trait] or #[async_trait(?Send)]";
+ Error::new(Span::call_site(), msg)
+}
diff --git a/third_party/rust/async-trait/src/bound.rs b/third_party/rust/async-trait/src/bound.rs
new file mode 100644
index 0000000000..50182f6db8
--- /dev/null
+++ b/third_party/rust/async-trait/src/bound.rs
@@ -0,0 +1,48 @@
+use proc_macro2::{Ident, Span, TokenStream};
+use quote::quote_spanned;
+use syn::punctuated::Punctuated;
+use syn::{Token, TypeParamBound};
+
+pub type Supertraits = Punctuated<TypeParamBound, Token![+]>;
+
+pub enum InferredBound {
+ Send,
+ Sync,
+}
+
+pub fn has_bound(supertraits: &Supertraits, bound: &InferredBound) -> bool {
+ for supertrait in supertraits {
+ if let TypeParamBound::Trait(supertrait) = supertrait {
+ if supertrait.path.is_ident(bound)
+ || supertrait.path.segments.len() == 3
+ && (supertrait.path.segments[0].ident == "std"
+ || supertrait.path.segments[0].ident == "core")
+ && supertrait.path.segments[1].ident == "marker"
+ && supertrait.path.segments[2].ident == *bound
+ {
+ return true;
+ }
+ }
+ }
+ false
+}
+
+impl InferredBound {
+ fn as_str(&self) -> &str {
+ match self {
+ InferredBound::Send => "Send",
+ InferredBound::Sync => "Sync",
+ }
+ }
+
+ pub fn spanned_path(&self, span: Span) -> TokenStream {
+ let ident = Ident::new(self.as_str(), span);
+ quote_spanned!(span=> ::core::marker::#ident)
+ }
+}
+
+impl PartialEq<InferredBound> for Ident {
+ fn eq(&self, bound: &InferredBound) -> bool {
+ self == bound.as_str()
+ }
+}
diff --git a/third_party/rust/async-trait/src/expand.rs b/third_party/rust/async-trait/src/expand.rs
new file mode 100644
index 0000000000..88338db9bc
--- /dev/null
+++ b/third_party/rust/async-trait/src/expand.rs
@@ -0,0 +1,502 @@
+use crate::bound::{has_bound, InferredBound, Supertraits};
+use crate::lifetime::{AddLifetimeToImplTrait, CollectLifetimes};
+use crate::parse::Item;
+use crate::receiver::{has_self_in_block, has_self_in_sig, mut_pat, ReplaceSelf};
+use proc_macro2::{Span, TokenStream};
+use quote::{format_ident, quote, quote_spanned, ToTokens};
+use std::collections::BTreeSet as Set;
+use std::mem;
+use syn::punctuated::Punctuated;
+use syn::visit_mut::{self, VisitMut};
+use syn::{
+ parse_quote, parse_quote_spanned, Attribute, Block, FnArg, GenericArgument, GenericParam,
+ Generics, Ident, ImplItem, Lifetime, LifetimeDef, Pat, PatIdent, PathArguments, Receiver,
+ ReturnType, Signature, Stmt, Token, TraitItem, Type, TypePath, WhereClause,
+};
+
+impl ToTokens for Item {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match self {
+ Item::Trait(item) => item.to_tokens(tokens),
+ Item::Impl(item) => item.to_tokens(tokens),
+ }
+ }
+}
+
+#[derive(Clone, Copy)]
+enum Context<'a> {
+ Trait {
+ generics: &'a Generics,
+ supertraits: &'a Supertraits,
+ },
+ Impl {
+ impl_generics: &'a Generics,
+ associated_type_impl_traits: &'a Set<Ident>,
+ },
+}
+
+impl Context<'_> {
+ fn lifetimes<'a>(&'a self, used: &'a [Lifetime]) -> impl Iterator<Item = &'a LifetimeDef> {
+ let generics = match self {
+ Context::Trait { generics, .. } => generics,
+ Context::Impl { impl_generics, .. } => impl_generics,
+ };
+ generics.params.iter().filter_map(move |param| {
+ if let GenericParam::Lifetime(param) = param {
+ if used.contains(&param.lifetime) {
+ return Some(param);
+ }
+ }
+ None
+ })
+ }
+}
+
+pub fn expand(input: &mut Item, is_local: bool) {
+ match input {
+ Item::Trait(input) => {
+ let context = Context::Trait {
+ generics: &input.generics,
+ supertraits: &input.supertraits,
+ };
+ for inner in &mut input.items {
+ if let TraitItem::Method(method) = inner {
+ let sig = &mut method.sig;
+ if sig.asyncness.is_some() {
+ let block = &mut method.default;
+ let mut has_self = has_self_in_sig(sig);
+ method.attrs.push(parse_quote!(#[must_use]));
+ if let Some(block) = block {
+ has_self |= has_self_in_block(block);
+ transform_block(context, sig, block);
+ method.attrs.push(lint_suppress_with_body());
+ } else {
+ method.attrs.push(lint_suppress_without_body());
+ }
+ let has_default = method.default.is_some();
+ transform_sig(context, sig, has_self, has_default, is_local);
+ }
+ }
+ }
+ }
+ Item::Impl(input) => {
+ let mut lifetimes = CollectLifetimes::new("'impl");
+ lifetimes.visit_type_mut(&mut *input.self_ty);
+ lifetimes.visit_path_mut(&mut input.trait_.as_mut().unwrap().1);
+ let params = &input.generics.params;
+ let elided = lifetimes.elided;
+ input.generics.params = parse_quote!(#(#elided,)* #params);
+
+ let mut associated_type_impl_traits = Set::new();
+ for inner in &input.items {
+ if let ImplItem::Type(assoc) = inner {
+ if let Type::ImplTrait(_) = assoc.ty {
+ associated_type_impl_traits.insert(assoc.ident.clone());
+ }
+ }
+ }
+
+ let context = Context::Impl {
+ impl_generics: &input.generics,
+ associated_type_impl_traits: &associated_type_impl_traits,
+ };
+ for inner in &mut input.items {
+ if let ImplItem::Method(method) = inner {
+ let sig = &mut method.sig;
+ if sig.asyncness.is_some() {
+ let block = &mut method.block;
+ let has_self = has_self_in_sig(sig) || has_self_in_block(block);
+ transform_block(context, sig, block);
+ transform_sig(context, sig, has_self, false, is_local);
+ method.attrs.push(lint_suppress_with_body());
+ }
+ }
+ }
+ }
+ }
+}
+
+fn lint_suppress_with_body() -> Attribute {
+ parse_quote! {
+ #[allow(
+ clippy::async_yields_async,
+ clippy::let_unit_value,
+ clippy::no_effect_underscore_binding,
+ clippy::shadow_same,
+ clippy::type_complexity,
+ clippy::type_repetition_in_bounds,
+ clippy::used_underscore_binding
+ )]
+ }
+}
+
+fn lint_suppress_without_body() -> Attribute {
+ parse_quote! {
+ #[allow(
+ clippy::type_complexity,
+ clippy::type_repetition_in_bounds
+ )]
+ }
+}
+
+// Input:
+// async fn f<T>(&self, x: &T) -> Ret;
+//
+// Output:
+// fn f<'life0, 'life1, 'async_trait, T>(
+// &'life0 self,
+// x: &'life1 T,
+// ) -> Pin<Box<dyn Future<Output = Ret> + Send + 'async_trait>>
+// where
+// 'life0: 'async_trait,
+// 'life1: 'async_trait,
+// T: 'async_trait,
+// Self: Sync + 'async_trait;
+fn transform_sig(
+ context: Context,
+ sig: &mut Signature,
+ has_self: bool,
+ has_default: bool,
+ is_local: bool,
+) {
+ let default_span = sig.asyncness.take().unwrap().span;
+ sig.fn_token.span = default_span;
+
+ let (ret_arrow, ret) = match &sig.output {
+ ReturnType::Default => (Token![->](default_span), quote_spanned!(default_span=> ())),
+ ReturnType::Type(arrow, ret) => (*arrow, quote!(#ret)),
+ };
+
+ let mut lifetimes = CollectLifetimes::new("'life");
+ for arg in sig.inputs.iter_mut() {
+ match arg {
+ FnArg::Receiver(arg) => lifetimes.visit_receiver_mut(arg),
+ FnArg::Typed(arg) => lifetimes.visit_type_mut(&mut arg.ty),
+ }
+ }
+
+ for param in &mut sig.generics.params {
+ match param {
+ GenericParam::Type(param) => {
+ let param_name = &param.ident;
+ let span = match param.colon_token.take() {
+ Some(colon_token) => colon_token.span,
+ None => param_name.span(),
+ };
+ let bounds = mem::replace(&mut param.bounds, Punctuated::new());
+ where_clause_or_default(&mut sig.generics.where_clause)
+ .predicates
+ .push(parse_quote_spanned!(span=> #param_name: 'async_trait + #bounds));
+ }
+ GenericParam::Lifetime(param) => {
+ let param_name = &param.lifetime;
+ let span = match param.colon_token.take() {
+ Some(colon_token) => colon_token.span,
+ None => param_name.span(),
+ };
+ let bounds = mem::replace(&mut param.bounds, Punctuated::new());
+ where_clause_or_default(&mut sig.generics.where_clause)
+ .predicates
+ .push(parse_quote_spanned!(span=> #param: 'async_trait + #bounds));
+ }
+ GenericParam::Const(_) => {}
+ }
+ }
+
+ for param in context.lifetimes(&lifetimes.explicit) {
+ let param = &param.lifetime;
+ let span = param.span();
+ where_clause_or_default(&mut sig.generics.where_clause)
+ .predicates
+ .push(parse_quote_spanned!(span=> #param: 'async_trait));
+ }
+
+ if sig.generics.lt_token.is_none() {
+ sig.generics.lt_token = Some(Token![<](sig.ident.span()));
+ }
+ if sig.generics.gt_token.is_none() {
+ sig.generics.gt_token = Some(Token![>](sig.paren_token.span));
+ }
+
+ for elided in lifetimes.elided {
+ sig.generics.params.push(parse_quote!(#elided));
+ where_clause_or_default(&mut sig.generics.where_clause)
+ .predicates
+ .push(parse_quote_spanned!(elided.span()=> #elided: 'async_trait));
+ }
+
+ sig.generics
+ .params
+ .push(parse_quote_spanned!(default_span=> 'async_trait));
+
+ if has_self {
+ let bounds: &[InferredBound] = match sig.inputs.iter().next() {
+ Some(FnArg::Receiver(Receiver {
+ reference: Some(_),
+ mutability: None,
+ ..
+ })) => &[InferredBound::Sync],
+ Some(FnArg::Typed(arg))
+ if match arg.pat.as_ref() {
+ Pat::Ident(pat) => pat.ident == "self",
+ _ => false,
+ } =>
+ {
+ match arg.ty.as_ref() {
+ // self: &Self
+ Type::Reference(ty) if ty.mutability.is_none() => &[InferredBound::Sync],
+ // self: Arc<Self>
+ Type::Path(ty)
+ if {
+ let segment = ty.path.segments.last().unwrap();
+ segment.ident == "Arc"
+ && match &segment.arguments {
+ PathArguments::AngleBracketed(arguments) => {
+ arguments.args.len() == 1
+ && match &arguments.args[0] {
+ GenericArgument::Type(Type::Path(arg)) => {
+ arg.path.is_ident("Self")
+ }
+ _ => false,
+ }
+ }
+ _ => false,
+ }
+ } =>
+ {
+ &[InferredBound::Sync, InferredBound::Send]
+ }
+ _ => &[InferredBound::Send],
+ }
+ }
+ _ => &[InferredBound::Send],
+ };
+
+ let bounds = bounds.iter().filter_map(|bound| {
+ let assume_bound = match context {
+ Context::Trait { supertraits, .. } => !has_default || has_bound(supertraits, bound),
+ Context::Impl { .. } => true,
+ };
+ if assume_bound || is_local {
+ None
+ } else {
+ Some(bound.spanned_path(default_span))
+ }
+ });
+
+ where_clause_or_default(&mut sig.generics.where_clause)
+ .predicates
+ .push(parse_quote_spanned! {default_span=>
+ Self: #(#bounds +)* 'async_trait
+ });
+ }
+
+ for (i, arg) in sig.inputs.iter_mut().enumerate() {
+ match arg {
+ FnArg::Receiver(Receiver {
+ reference: Some(_), ..
+ }) => {}
+ FnArg::Receiver(arg) => arg.mutability = None,
+ FnArg::Typed(arg) => {
+ let type_is_reference = match *arg.ty {
+ Type::Reference(_) => true,
+ _ => false,
+ };
+ if let Pat::Ident(pat) = &mut *arg.pat {
+ if pat.ident == "self" || !type_is_reference {
+ pat.by_ref = None;
+ pat.mutability = None;
+ }
+ } else if !type_is_reference {
+ let positional = positional_arg(i, &arg.pat);
+ let m = mut_pat(&mut arg.pat);
+ arg.pat = parse_quote!(#m #positional);
+ }
+ AddLifetimeToImplTrait.visit_type_mut(&mut arg.ty);
+ }
+ }
+ }
+
+ let bounds = if is_local {
+ quote_spanned!(default_span=> 'async_trait)
+ } else {
+ quote_spanned!(default_span=> ::core::marker::Send + 'async_trait)
+ };
+ sig.output = parse_quote_spanned! {default_span=>
+ #ret_arrow ::core::pin::Pin<Box<
+ dyn ::core::future::Future<Output = #ret> + #bounds
+ >>
+ };
+}
+
+// Input:
+// async fn f<T>(&self, x: &T, (a, b): (A, B)) -> Ret {
+// self + x + a + b
+// }
+//
+// Output:
+// Box::pin(async move {
+// let ___ret: Ret = {
+// let __self = self;
+// let x = x;
+// let (a, b) = __arg1;
+//
+// __self + x + a + b
+// };
+//
+// ___ret
+// })
+fn transform_block(context: Context, sig: &mut Signature, block: &mut Block) {
+ if let Some(Stmt::Item(syn::Item::Verbatim(item))) = block.stmts.first() {
+ if block.stmts.len() == 1 && item.to_string() == ";" {
+ return;
+ }
+ }
+
+ let mut self_span = None;
+ let decls = sig
+ .inputs
+ .iter()
+ .enumerate()
+ .map(|(i, arg)| match arg {
+ FnArg::Receiver(Receiver {
+ self_token,
+ mutability,
+ ..
+ }) => {
+ let ident = Ident::new("__self", self_token.span);
+ self_span = Some(self_token.span);
+ quote!(let #mutability #ident = #self_token;)
+ }
+ FnArg::Typed(arg) => {
+ // If there is a #[cfg(...)] attribute that selectively enables
+ // the parameter, forward it to the variable.
+ //
+ // This is currently not applied to the `self` parameter.
+ let attrs = arg.attrs.iter().filter(|attr| attr.path.is_ident("cfg"));
+
+ if let Pat::Ident(PatIdent {
+ ident, mutability, ..
+ }) = &*arg.pat
+ {
+ if ident == "self" {
+ self_span = Some(ident.span());
+ let prefixed = Ident::new("__self", ident.span());
+ quote!(let #mutability #prefixed = #ident;)
+ } else if let Type::Reference(_) = *arg.ty {
+ quote!()
+ } else {
+ quote! {
+ #(#attrs)*
+ let #mutability #ident = #ident;
+ }
+ }
+ } else if let Type::Reference(_) = *arg.ty {
+ quote!()
+ } else {
+ let pat = &arg.pat;
+ let ident = positional_arg(i, pat);
+ if let Pat::Wild(_) = **pat {
+ quote! {
+ #(#attrs)*
+ let #ident = #ident;
+ }
+ } else {
+ quote! {
+ #(#attrs)*
+ let #pat = {
+ let #ident = #ident;
+ #ident
+ };
+ }
+ }
+ }
+ }
+ })
+ .collect::<Vec<_>>();
+
+ if let Some(span) = self_span {
+ let mut replace_self = ReplaceSelf(span);
+ replace_self.visit_block_mut(block);
+ }
+
+ let stmts = &block.stmts;
+ let let_ret = match &mut sig.output {
+ ReturnType::Default => quote_spanned! {block.brace_token.span=>
+ #(#decls)*
+ let _: () = { #(#stmts)* };
+ },
+ ReturnType::Type(_, ret) => {
+ if contains_associated_type_impl_trait(context, ret) {
+ if decls.is_empty() {
+ quote!(#(#stmts)*)
+ } else {
+ quote!(#(#decls)* { #(#stmts)* })
+ }
+ } else {
+ quote_spanned! {block.brace_token.span=>
+ if let ::core::option::Option::Some(__ret) = ::core::option::Option::None::<#ret> {
+ return __ret;
+ }
+ #(#decls)*
+ let __ret: #ret = { #(#stmts)* };
+ #[allow(unreachable_code)]
+ __ret
+ }
+ }
+ }
+ };
+ let box_pin = quote_spanned!(block.brace_token.span=>
+ Box::pin(async move { #let_ret })
+ );
+ block.stmts = parse_quote!(#box_pin);
+}
+
+fn positional_arg(i: usize, pat: &Pat) -> Ident {
+ let span: Span = syn::spanned::Spanned::span(pat);
+ #[cfg(not(no_span_mixed_site))]
+ let span = span.resolved_at(Span::mixed_site());
+ format_ident!("__arg{}", i, span = span)
+}
+
+fn contains_associated_type_impl_trait(context: Context, ret: &mut Type) -> bool {
+ struct AssociatedTypeImplTraits<'a> {
+ set: &'a Set<Ident>,
+ contains: bool,
+ }
+
+ impl<'a> VisitMut for AssociatedTypeImplTraits<'a> {
+ fn visit_type_path_mut(&mut self, ty: &mut TypePath) {
+ if ty.qself.is_none()
+ && ty.path.segments.len() == 2
+ && ty.path.segments[0].ident == "Self"
+ && self.set.contains(&ty.path.segments[1].ident)
+ {
+ self.contains = true;
+ }
+ visit_mut::visit_type_path_mut(self, ty);
+ }
+ }
+
+ match context {
+ Context::Trait { .. } => false,
+ Context::Impl {
+ associated_type_impl_traits,
+ ..
+ } => {
+ let mut visit = AssociatedTypeImplTraits {
+ set: associated_type_impl_traits,
+ contains: false,
+ };
+ visit.visit_type_mut(ret);
+ visit.contains
+ }
+ }
+}
+
+fn where_clause_or_default(clause: &mut Option<WhereClause>) -> &mut WhereClause {
+ clause.get_or_insert_with(|| WhereClause {
+ where_token: Default::default(),
+ predicates: Punctuated::new(),
+ })
+}
diff --git a/third_party/rust/async-trait/src/lib.rs b/third_party/rust/async-trait/src/lib.rs
new file mode 100644
index 0000000000..8ca503256e
--- /dev/null
+++ b/third_party/rust/async-trait/src/lib.rs
@@ -0,0 +1,340 @@
+//! [![github]](https://github.com/dtolnay/async-trait)&ensp;[![crates-io]](https://crates.io/crates/async-trait)&ensp;[![docs-rs]](https://docs.rs/async-trait)
+//!
+//! [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
+//!
+//! <br>
+//!
+//! <h5>Type erasure for async trait methods</h5>
+//!
+//! The initial round of stabilizations for the async/await language feature in
+//! Rust 1.39 did not include support for async fn in traits. Trying to include
+//! an async fn in a trait produces the following error:
+//!
+//! ```compile_fail
+//! trait MyTrait {
+//! async fn f() {}
+//! }
+//! ```
+//!
+//! ```text
+//! error[E0706]: trait fns cannot be declared `async`
+//! --> src/main.rs:4:5
+//! |
+//! 4 | async fn f() {}
+//! | ^^^^^^^^^^^^^^^
+//! ```
+//!
+//! This crate provides an attribute macro to make async fn in traits work.
+//!
+//! Please refer to [*why async fn in traits are hard*][hard] for a deeper
+//! analysis of how this implementation differs from what the compiler and
+//! language hope to deliver in the future.
+//!
+//! [hard]: https://smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-hard/
+//!
+//! <br>
+//!
+//! # Example
+//!
+//! This example implements the core of a highly effective advertising platform
+//! using async fn in a trait.
+//!
+//! The only thing to notice here is that we write an `#[async_trait]` macro on
+//! top of traits and trait impls that contain async fn, and then they work.
+//!
+//! ```
+//! use async_trait::async_trait;
+//!
+//! #[async_trait]
+//! trait Advertisement {
+//! async fn run(&self);
+//! }
+//!
+//! struct Modal;
+//!
+//! #[async_trait]
+//! impl Advertisement for Modal {
+//! async fn run(&self) {
+//! self.render_fullscreen().await;
+//! for _ in 0..4u16 {
+//! remind_user_to_join_mailing_list().await;
+//! }
+//! self.hide_for_now().await;
+//! }
+//! }
+//!
+//! struct AutoplayingVideo {
+//! media_url: String,
+//! }
+//!
+//! #[async_trait]
+//! impl Advertisement for AutoplayingVideo {
+//! async fn run(&self) {
+//! let stream = connect(&self.media_url).await;
+//! stream.play().await;
+//!
+//! // Video probably persuaded user to join our mailing list!
+//! Modal.run().await;
+//! }
+//! }
+//! #
+//! # impl Modal {
+//! # async fn render_fullscreen(&self) {}
+//! # async fn hide_for_now(&self) {}
+//! # }
+//! #
+//! # async fn remind_user_to_join_mailing_list() {}
+//! #
+//! # struct Stream;
+//! # async fn connect(_media_url: &str) -> Stream { Stream }
+//! # impl Stream {
+//! # async fn play(&self) {}
+//! # }
+//! ```
+//!
+//! <br><br>
+//!
+//! # Supported features
+//!
+//! It is the intention that all features of Rust traits should work nicely with
+//! #\[async_trait\], but the edge cases are numerous. Please file an issue if
+//! you see unexpected borrow checker errors, type errors, or warnings. There is
+//! no use of `unsafe` in the expanded code, so rest assured that if your code
+//! compiles it can't be that badly broken.
+//!
+//! > &#9745;&emsp;Self by value, by reference, by mut reference, or no self;<br>
+//! > &#9745;&emsp;Any number of arguments, any return value;<br>
+//! > &#9745;&emsp;Generic type parameters and lifetime parameters;<br>
+//! > &#9745;&emsp;Associated types;<br>
+//! > &#9745;&emsp;Having async and non-async functions in the same trait;<br>
+//! > &#9745;&emsp;Default implementations provided by the trait;<br>
+//! > &#9745;&emsp;Elided lifetimes;<br>
+//! > &#9745;&emsp;Dyn-capable traits.<br>
+//!
+//! <br>
+//!
+//! # Explanation
+//!
+//! Async fns get transformed into methods that return `Pin<Box<dyn Future +
+//! Send + 'async>>` and delegate to a private async freestanding function.
+//!
+//! For example the `impl Advertisement for AutoplayingVideo` above would be
+//! expanded as:
+//!
+//! ```
+//! # const IGNORE: &str = stringify! {
+//! impl Advertisement for AutoplayingVideo {
+//! fn run<'async>(
+//! &'async self,
+//! ) -> Pin<Box<dyn core::future::Future<Output = ()> + Send + 'async>>
+//! where
+//! Self: Sync + 'async,
+//! {
+//! async fn run(_self: &AutoplayingVideo) {
+//! /* the original method body */
+//! }
+//!
+//! Box::pin(run(self))
+//! }
+//! }
+//! # };
+//! ```
+//!
+//! <br><br>
+//!
+//! # Non-threadsafe futures
+//!
+//! Not all async traits need futures that are `dyn Future + Send`. To avoid
+//! having Send and Sync bounds placed on the async trait methods, invoke the
+//! async trait macro as `#[async_trait(?Send)]` on both the trait and the impl
+//! blocks.
+//!
+//! <br>
+//!
+//! # Elided lifetimes
+//!
+//! Be aware that async fn syntax does not allow lifetime elision outside of `&`
+//! and `&mut` references. (This is true even when not using #\[async_trait\].)
+//! Lifetimes must be named or marked by the placeholder `'_`.
+//!
+//! Fortunately the compiler is able to diagnose missing lifetimes with a good
+//! error message.
+//!
+//! ```compile_fail
+//! # use async_trait::async_trait;
+//! #
+//! type Elided<'a> = &'a usize;
+//!
+//! #[async_trait]
+//! trait Test {
+//! async fn test(not_okay: Elided, okay: &usize) {}
+//! }
+//! ```
+//!
+//! ```text
+//! error[E0726]: implicit elided lifetime not allowed here
+//! --> src/main.rs:9:29
+//! |
+//! 9 | async fn test(not_okay: Elided, okay: &usize) {}
+//! | ^^^^^^- help: indicate the anonymous lifetime: `<'_>`
+//! ```
+//!
+//! The fix is to name the lifetime or use `'_`.
+//!
+//! ```
+//! # use async_trait::async_trait;
+//! #
+//! # type Elided<'a> = &'a usize;
+//! #
+//! #[async_trait]
+//! trait Test {
+//! // either
+//! async fn test<'e>(elided: Elided<'e>) {}
+//! # }
+//! # #[async_trait]
+//! # trait Test2 {
+//! // or
+//! async fn test(elided: Elided<'_>) {}
+//! }
+//! ```
+//!
+//! <br><br>
+//!
+//! # Dyn traits
+//!
+//! Traits with async methods can be used as trait objects as long as they meet
+//! the usual requirements for dyn -- no methods with type parameters, no self
+//! by value, no associated types, etc.
+//!
+//! ```
+//! # use async_trait::async_trait;
+//! #
+//! #[async_trait]
+//! pub trait ObjectSafe {
+//! async fn f(&self);
+//! async fn g(&mut self);
+//! }
+//!
+//! # const IGNORE: &str = stringify! {
+//! impl ObjectSafe for MyType {...}
+//!
+//! let value: MyType = ...;
+//! # };
+//! #
+//! # struct MyType;
+//! #
+//! # #[async_trait]
+//! # impl ObjectSafe for MyType {
+//! # async fn f(&self) {}
+//! # async fn g(&mut self) {}
+//! # }
+//! #
+//! # let value: MyType = MyType;
+//! let object = &value as &dyn ObjectSafe; // make trait object
+//! ```
+//!
+//! The one wrinkle is in traits that provide default implementations of async
+//! methods. In order for the default implementation to produce a future that is
+//! Send, the async_trait macro must emit a bound of `Self: Sync` on trait
+//! methods that take `&self` and a bound `Self: Send` on trait methods that
+//! take `&mut self`. An example of the former is visible in the expanded code
+//! in the explanation section above.
+//!
+//! If you make a trait with async methods that have default implementations,
+//! everything will work except that the trait cannot be used as a trait object.
+//! Creating a value of type `&dyn Trait` will produce an error that looks like
+//! this:
+//!
+//! ```text
+//! error: the trait `Test` cannot be made into an object
+//! --> src/main.rs:8:5
+//! |
+//! 8 | async fn cannot_dyn(&self) {}
+//! | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+//! ```
+//!
+//! For traits that need to be object safe and need to have default
+//! implementations for some async methods, there are two resolutions. Either
+//! you can add Send and/or Sync as supertraits (Send if there are `&mut self`
+//! methods with default implementations, Sync if there are `&self` methods with
+//! default implementations) to constrain all implementors of the trait such that
+//! the default implementations are applicable to them:
+//!
+//! ```
+//! # use async_trait::async_trait;
+//! #
+//! #[async_trait]
+//! pub trait ObjectSafe: Sync { // added supertrait
+//! async fn can_dyn(&self) {}
+//! }
+//! #
+//! # struct MyType;
+//! #
+//! # #[async_trait]
+//! # impl ObjectSafe for MyType {}
+//! #
+//! # let value = MyType;
+//!
+//! let object = &value as &dyn ObjectSafe;
+//! ```
+//!
+//! or you can strike the problematic methods from your trait object by
+//! bounding them with `Self: Sized`:
+//!
+//! ```
+//! # use async_trait::async_trait;
+//! #
+//! #[async_trait]
+//! pub trait ObjectSafe {
+//! async fn cannot_dyn(&self) where Self: Sized {}
+//!
+//! // presumably other methods
+//! }
+//! #
+//! # struct MyType;
+//! #
+//! # #[async_trait]
+//! # impl ObjectSafe for MyType {}
+//! #
+//! # let value = MyType;
+//!
+//! let object = &value as &dyn ObjectSafe;
+//! ```
+
+#![allow(
+ clippy::default_trait_access,
+ clippy::doc_markdown,
+ clippy::explicit_auto_deref,
+ clippy::if_not_else,
+ clippy::items_after_statements,
+ clippy::module_name_repetitions,
+ clippy::shadow_unrelated,
+ clippy::similar_names,
+ clippy::too_many_lines
+)]
+
+extern crate proc_macro;
+
+mod args;
+mod bound;
+mod expand;
+mod lifetime;
+mod parse;
+mod receiver;
+
+use crate::args::Args;
+use crate::expand::expand;
+use crate::parse::Item;
+use proc_macro::TokenStream;
+use quote::quote;
+use syn::parse_macro_input;
+
+#[proc_macro_attribute]
+pub fn async_trait(args: TokenStream, input: TokenStream) -> TokenStream {
+ let args = parse_macro_input!(args as Args);
+ let mut item = parse_macro_input!(input as Item);
+ expand(&mut item, args.local);
+ TokenStream::from(quote!(#item))
+}
diff --git a/third_party/rust/async-trait/src/lifetime.rs b/third_party/rust/async-trait/src/lifetime.rs
new file mode 100644
index 0000000000..86eac24067
--- /dev/null
+++ b/third_party/rust/async-trait/src/lifetime.rs
@@ -0,0 +1,112 @@
+use proc_macro2::{Span, TokenStream};
+use std::mem;
+use syn::visit_mut::{self, VisitMut};
+use syn::{
+ parse_quote_spanned, token, Expr, GenericArgument, Lifetime, Receiver, ReturnType, Token, Type,
+ TypeBareFn, TypeImplTrait, TypeParen, TypePtr, TypeReference,
+};
+
+pub struct CollectLifetimes {
+ pub elided: Vec<Lifetime>,
+ pub explicit: Vec<Lifetime>,
+ pub name: &'static str,
+}
+
+impl CollectLifetimes {
+ pub fn new(name: &'static str) -> Self {
+ CollectLifetimes {
+ elided: Vec::new(),
+ explicit: Vec::new(),
+ name,
+ }
+ }
+
+ fn visit_opt_lifetime(&mut self, reference: Token![&], lifetime: &mut Option<Lifetime>) {
+ match lifetime {
+ None => *lifetime = Some(self.next_lifetime(reference.span)),
+ Some(lifetime) => self.visit_lifetime(lifetime),
+ }
+ }
+
+ fn visit_lifetime(&mut self, lifetime: &mut Lifetime) {
+ if lifetime.ident == "_" {
+ *lifetime = self.next_lifetime(lifetime.span());
+ } else {
+ self.explicit.push(lifetime.clone());
+ }
+ }
+
+ fn next_lifetime(&mut self, span: Span) -> Lifetime {
+ let name = format!("{}{}", self.name, self.elided.len());
+ let life = Lifetime::new(&name, span);
+ self.elided.push(life.clone());
+ life
+ }
+}
+
+impl VisitMut for CollectLifetimes {
+ fn visit_receiver_mut(&mut self, arg: &mut Receiver) {
+ if let Some((reference, lifetime)) = &mut arg.reference {
+ self.visit_opt_lifetime(*reference, lifetime);
+ }
+ }
+
+ fn visit_type_reference_mut(&mut self, ty: &mut TypeReference) {
+ self.visit_opt_lifetime(ty.and_token, &mut ty.lifetime);
+ visit_mut::visit_type_reference_mut(self, ty);
+ }
+
+ fn visit_generic_argument_mut(&mut self, gen: &mut GenericArgument) {
+ if let GenericArgument::Lifetime(lifetime) = gen {
+ self.visit_lifetime(lifetime);
+ }
+ visit_mut::visit_generic_argument_mut(self, gen);
+ }
+}
+
+pub struct AddLifetimeToImplTrait;
+
+impl VisitMut for AddLifetimeToImplTrait {
+ fn visit_type_impl_trait_mut(&mut self, ty: &mut TypeImplTrait) {
+ let span = ty.impl_token.span;
+ let lifetime = parse_quote_spanned!(span=> 'async_trait);
+ ty.bounds.insert(0, lifetime);
+ if let Some(punct) = ty.bounds.pairs_mut().next().unwrap().punct_mut() {
+ punct.span = span;
+ }
+ visit_mut::visit_type_impl_trait_mut(self, ty);
+ }
+
+ fn visit_type_reference_mut(&mut self, ty: &mut TypeReference) {
+ parenthesize_impl_trait(&mut ty.elem, ty.and_token.span);
+ visit_mut::visit_type_reference_mut(self, ty);
+ }
+
+ fn visit_type_ptr_mut(&mut self, ty: &mut TypePtr) {
+ parenthesize_impl_trait(&mut ty.elem, ty.star_token.span);
+ visit_mut::visit_type_ptr_mut(self, ty);
+ }
+
+ fn visit_type_bare_fn_mut(&mut self, ty: &mut TypeBareFn) {
+ if let ReturnType::Type(arrow, return_type) = &mut ty.output {
+ parenthesize_impl_trait(return_type, arrow.spans[0]);
+ }
+ visit_mut::visit_type_bare_fn_mut(self, ty);
+ }
+
+ fn visit_expr_mut(&mut self, _e: &mut Expr) {
+ // Do not recurse into impl Traits inside of an array length expression.
+ //
+ // fn outer(arg: [u8; { fn inner(_: impl Trait) {}; 0 }]);
+ }
+}
+
+fn parenthesize_impl_trait(elem: &mut Type, paren_span: Span) {
+ if let Type::ImplTrait(_) = *elem {
+ let placeholder = Type::Verbatim(TokenStream::new());
+ *elem = Type::Paren(TypeParen {
+ paren_token: token::Paren(paren_span),
+ elem: Box::new(mem::replace(elem, placeholder)),
+ });
+ }
+}
diff --git a/third_party/rust/async-trait/src/parse.rs b/third_party/rust/async-trait/src/parse.rs
new file mode 100644
index 0000000000..ebd253514f
--- /dev/null
+++ b/third_party/rust/async-trait/src/parse.rs
@@ -0,0 +1,34 @@
+use proc_macro2::Span;
+use syn::parse::{Error, Parse, ParseStream, Result};
+use syn::{Attribute, ItemImpl, ItemTrait, Token};
+
+pub enum Item {
+ Trait(ItemTrait),
+ Impl(ItemImpl),
+}
+
+impl Parse for Item {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let attrs = input.call(Attribute::parse_outer)?;
+ let mut lookahead = input.lookahead1();
+ if lookahead.peek(Token![unsafe]) {
+ let ahead = input.fork();
+ ahead.parse::<Token![unsafe]>()?;
+ lookahead = ahead.lookahead1();
+ }
+ if lookahead.peek(Token![pub]) || lookahead.peek(Token![trait]) {
+ let mut item: ItemTrait = input.parse()?;
+ item.attrs = attrs;
+ Ok(Item::Trait(item))
+ } else if lookahead.peek(Token![impl]) {
+ let mut item: ItemImpl = input.parse()?;
+ if item.trait_.is_none() {
+ return Err(Error::new(Span::call_site(), "expected a trait impl"));
+ }
+ item.attrs = attrs;
+ Ok(Item::Impl(item))
+ } else {
+ Err(lookahead.error())
+ }
+ }
+}
diff --git a/third_party/rust/async-trait/src/receiver.rs b/third_party/rust/async-trait/src/receiver.rs
new file mode 100644
index 0000000000..2230db6ea2
--- /dev/null
+++ b/third_party/rust/async-trait/src/receiver.rs
@@ -0,0 +1,179 @@
+use proc_macro2::{Group, Span, TokenStream, TokenTree};
+use std::iter::FromIterator;
+use syn::visit_mut::{self, VisitMut};
+use syn::{
+ Block, ExprPath, Ident, Item, Macro, Pat, PatIdent, PatPath, Path, Receiver, Signature, Token,
+ TypePath,
+};
+
+pub fn has_self_in_sig(sig: &mut Signature) -> bool {
+ let mut visitor = HasSelf(false);
+ visitor.visit_signature_mut(sig);
+ visitor.0
+}
+
+pub fn has_self_in_block(block: &mut Block) -> bool {
+ let mut visitor = HasSelf(false);
+ visitor.visit_block_mut(block);
+ visitor.0
+}
+
+fn has_self_in_token_stream(tokens: TokenStream) -> bool {
+ tokens.into_iter().any(|tt| match tt {
+ TokenTree::Ident(ident) => ident == "Self",
+ TokenTree::Group(group) => has_self_in_token_stream(group.stream()),
+ _ => false,
+ })
+}
+
+pub fn mut_pat(pat: &mut Pat) -> Option<Token![mut]> {
+ let mut visitor = HasMutPat(None);
+ visitor.visit_pat_mut(pat);
+ visitor.0
+}
+
+fn contains_fn(tokens: TokenStream) -> bool {
+ tokens.into_iter().any(|tt| match tt {
+ TokenTree::Ident(ident) => ident == "fn",
+ TokenTree::Group(group) => contains_fn(group.stream()),
+ _ => false,
+ })
+}
+
+struct HasMutPat(Option<Token![mut]>);
+
+impl VisitMut for HasMutPat {
+ fn visit_pat_ident_mut(&mut self, i: &mut PatIdent) {
+ if let Some(m) = i.mutability {
+ self.0 = Some(m);
+ } else {
+ visit_mut::visit_pat_ident_mut(self, i);
+ }
+ }
+}
+
+struct HasSelf(bool);
+
+impl VisitMut for HasSelf {
+ fn visit_expr_path_mut(&mut self, expr: &mut ExprPath) {
+ self.0 |= expr.path.segments[0].ident == "Self";
+ visit_mut::visit_expr_path_mut(self, expr);
+ }
+
+ fn visit_pat_path_mut(&mut self, pat: &mut PatPath) {
+ self.0 |= pat.path.segments[0].ident == "Self";
+ visit_mut::visit_pat_path_mut(self, pat);
+ }
+
+ fn visit_type_path_mut(&mut self, ty: &mut TypePath) {
+ self.0 |= ty.path.segments[0].ident == "Self";
+ visit_mut::visit_type_path_mut(self, ty);
+ }
+
+ fn visit_receiver_mut(&mut self, _arg: &mut Receiver) {
+ self.0 = true;
+ }
+
+ fn visit_item_mut(&mut self, _: &mut Item) {
+ // Do not recurse into nested items.
+ }
+
+ fn visit_macro_mut(&mut self, mac: &mut Macro) {
+ if !contains_fn(mac.tokens.clone()) {
+ self.0 |= has_self_in_token_stream(mac.tokens.clone());
+ }
+ }
+}
+
+pub struct ReplaceSelf(pub Span);
+
+impl ReplaceSelf {
+ #[cfg_attr(not(self_span_hack), allow(clippy::unused_self))]
+ fn prepend_underscore_to_self(&self, ident: &mut Ident) -> bool {
+ let modified = ident == "self";
+ if modified {
+ *ident = Ident::new("__self", ident.span());
+ #[cfg(self_span_hack)]
+ ident.set_span(self.0);
+ }
+ modified
+ }
+
+ fn visit_token_stream(&mut self, tokens: &mut TokenStream) -> bool {
+ let mut out = Vec::new();
+ let mut modified = false;
+ visit_token_stream_impl(self, tokens.clone(), &mut modified, &mut out);
+ if modified {
+ *tokens = TokenStream::from_iter(out);
+ }
+ return modified;
+
+ fn visit_token_stream_impl(
+ visitor: &mut ReplaceSelf,
+ tokens: TokenStream,
+ modified: &mut bool,
+ out: &mut Vec<TokenTree>,
+ ) {
+ for tt in tokens {
+ match tt {
+ TokenTree::Ident(mut ident) => {
+ *modified |= visitor.prepend_underscore_to_self(&mut ident);
+ out.push(TokenTree::Ident(ident));
+ }
+ TokenTree::Group(group) => {
+ let mut content = group.stream();
+ *modified |= visitor.visit_token_stream(&mut content);
+ let mut new = Group::new(group.delimiter(), content);
+ new.set_span(group.span());
+ out.push(TokenTree::Group(new));
+ }
+ other => out.push(other),
+ }
+ }
+ }
+ }
+}
+
+impl VisitMut for ReplaceSelf {
+ fn visit_ident_mut(&mut self, i: &mut Ident) {
+ self.prepend_underscore_to_self(i);
+ }
+
+ fn visit_path_mut(&mut self, p: &mut Path) {
+ if p.segments.len() == 1 {
+ // Replace `self`, but not `self::function`.
+ self.visit_ident_mut(&mut p.segments[0].ident);
+ }
+ for segment in &mut p.segments {
+ self.visit_path_arguments_mut(&mut segment.arguments);
+ }
+ }
+
+ fn visit_item_mut(&mut self, i: &mut Item) {
+ // Visit `macro_rules!` because locally defined macros can refer to
+ // `self`.
+ //
+ // Visit `futures::select` and similar select macros, which commonly
+ // appear syntactically like an item despite expanding to an expression.
+ //
+ // Otherwise, do not recurse into nested items.
+ if let Item::Macro(i) = i {
+ if i.mac.path.is_ident("macro_rules")
+ || i.mac.path.segments.last().unwrap().ident == "select"
+ {
+ self.visit_macro_mut(&mut i.mac);
+ }
+ }
+ }
+
+ fn visit_macro_mut(&mut self, mac: &mut Macro) {
+ // We can't tell in general whether `self` inside a macro invocation
+ // refers to the self in the argument list or a different self
+ // introduced within the macro. Heuristic: if the macro input contains
+ // `fn`, then `self` is more likely to refer to something other than the
+ // outer function's self argument.
+ if !contains_fn(mac.tokens.clone()) {
+ self.visit_token_stream(&mut mac.tokens);
+ }
+ }
+}