chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

56
vendor/futures-macro/src/executor.rs vendored Normal file
View File

@@ -0,0 +1,56 @@
use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::{quote, quote_spanned, ToTokens};
pub(crate) fn test(args: TokenStream, item: TokenStream) -> TokenStream {
if !args.is_empty() {
return syn::Error::new_spanned(proc_macro2::TokenStream::from(args), "invalid argument")
.to_compile_error()
.into();
}
let mut input = syn::parse_macro_input!(item as syn::ItemFn);
if input.sig.asyncness.take().is_none() {
return syn::Error::new_spanned(input.sig.fn_token, "Only async functions are supported")
.to_compile_error()
.into();
}
// If type mismatch occurs, the current rustc points to the last statement.
let (last_stmt_start_span, last_stmt_end_span) = {
let mut last_stmt = input
.block
.stmts
.last()
.map(ToTokens::into_token_stream)
.unwrap_or_default()
.into_iter();
// `Span` on stable Rust has a limitation that only points to the first
// token, not the whole tokens. We can work around this limitation by
// using the first/last span of the tokens like
// `syn::Error::new_spanned` does.
let start = last_stmt.next().map_or_else(Span::call_site, |t| t.span());
let end = last_stmt.last().map_or(start, |t| t.span());
(start, end)
};
let path = quote_spanned! {last_stmt_start_span=>
::futures_test::__private
};
let body = &input.block;
input.block.stmts = vec![syn::Stmt::Expr(
syn::parse2(quote_spanned! {last_stmt_end_span=>
#path::block_on(async #body)
})
.unwrap(),
None,
)];
let gen = quote! {
#[::core::prelude::v1::test]
#input
};
gen.into()
}

144
vendor/futures-macro/src/join.rs vendored Normal file
View File

@@ -0,0 +1,144 @@
//! The futures-rs `join!` macro implementation.
use proc_macro::TokenStream;
use proc_macro2::{Span, TokenStream as TokenStream2};
use quote::{format_ident, quote};
use syn::parse::{Parse, ParseStream};
use syn::{Expr, Ident, Token};
#[derive(Default)]
struct Join {
fut_exprs: Vec<Expr>,
}
impl Parse for Join {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
let mut join = Self::default();
while !input.is_empty() {
join.fut_exprs.push(input.parse::<Expr>()?);
if !input.is_empty() {
input.parse::<Token![,]>()?;
}
}
Ok(join)
}
}
fn bind_futures(fut_exprs: Vec<Expr>, span: Span) -> (Vec<TokenStream2>, Vec<Ident>) {
let mut future_let_bindings = Vec::with_capacity(fut_exprs.len());
let future_names: Vec<_> = fut_exprs
.into_iter()
.enumerate()
.map(|(i, expr)| {
let name = format_ident!("_fut{}", i, span = span);
future_let_bindings.push(quote! {
// Move future into a local so that it is pinned in one place and
// is no longer accessible by the end user.
let mut #name = __futures_crate::future::maybe_done(#expr);
let mut #name = unsafe { __futures_crate::Pin::new_unchecked(&mut #name) };
});
name
})
.collect();
(future_let_bindings, future_names)
}
/// The `join!` macro.
pub(crate) fn join(input: TokenStream) -> TokenStream {
let parsed = syn::parse_macro_input!(input as Join);
// should be def_site, but that's unstable
let span = Span::call_site();
let (future_let_bindings, future_names) = bind_futures(parsed.fut_exprs, span);
let poll_futures = future_names.iter().map(|fut| {
quote! {
__all_done &= __futures_crate::future::Future::poll(
#fut.as_mut(), __cx).is_ready();
}
});
let take_outputs = future_names.iter().map(|fut| {
quote! {
#fut.as_mut().take_output().unwrap(),
}
});
TokenStream::from(quote! { {
#( #future_let_bindings )*
__futures_crate::future::poll_fn(move |__cx: &mut __futures_crate::task::Context<'_>| {
let mut __all_done = true;
#( #poll_futures )*
if __all_done {
__futures_crate::task::Poll::Ready((
#( #take_outputs )*
))
} else {
__futures_crate::task::Poll::Pending
}
}).await
} })
}
/// The `try_join!` macro.
pub(crate) fn try_join(input: TokenStream) -> TokenStream {
let parsed = syn::parse_macro_input!(input as Join);
// should be def_site, but that's unstable
let span = Span::call_site();
let (future_let_bindings, future_names) = bind_futures(parsed.fut_exprs, span);
let poll_futures = future_names.iter().map(|fut| {
quote! {
if __futures_crate::future::Future::poll(
#fut.as_mut(), __cx).is_pending()
{
__all_done = false;
} else if #fut.as_mut().output_mut().unwrap().is_err() {
// `.err().unwrap()` rather than `.unwrap_err()` so that we don't introduce
// a `T: Debug` bound.
// Also, for an error type of ! any code after `err().unwrap()` is unreachable.
#[allow(unreachable_code)]
return __futures_crate::task::Poll::Ready(
__futures_crate::Err(
#fut.as_mut().take_output().unwrap().err().unwrap()
)
);
}
}
});
let take_outputs = future_names.iter().map(|fut| {
quote! {
// `.ok().unwrap()` rather than `.unwrap()` so that we don't introduce
// an `E: Debug` bound.
// Also, for an ok type of ! any code after `ok().unwrap()` is unreachable.
#[allow(unreachable_code)]
#fut.as_mut().take_output().unwrap().ok().unwrap(),
}
});
TokenStream::from(quote! { {
#( #future_let_bindings )*
#[allow(clippy::diverging_sub_expression)]
__futures_crate::future::poll_fn(move |__cx: &mut __futures_crate::task::Context<'_>| {
let mut __all_done = true;
#( #poll_futures )*
if __all_done {
__futures_crate::task::Poll::Ready(
__futures_crate::Ok((
#( #take_outputs )*
))
)
} else {
__futures_crate::task::Poll::Pending
}
}).await
} })
}

55
vendor/futures-macro/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,55 @@
//! The futures-rs procedural macro implementations.
#![doc(test(
no_crate_inject,
attr(
deny(warnings, rust_2018_idioms, single_use_lifetimes),
allow(dead_code, unused_assignments, unused_variables)
)
))]
use proc_macro::TokenStream;
mod executor;
mod join;
mod select;
mod stream_select;
/// The `join!` macro.
#[proc_macro]
pub fn join_internal(input: TokenStream) -> TokenStream {
crate::join::join(input)
}
/// The `try_join!` macro.
#[proc_macro]
pub fn try_join_internal(input: TokenStream) -> TokenStream {
crate::join::try_join(input)
}
/// The `select!` macro.
#[proc_macro]
pub fn select_internal(input: TokenStream) -> TokenStream {
crate::select::select(input)
}
/// The `select_biased!` macro.
#[proc_macro]
pub fn select_biased_internal(input: TokenStream) -> TokenStream {
crate::select::select_biased(input)
}
// TODO: Change this to doc comment once rustdoc bug fixed: https://github.com/rust-lang/futures-rs/pull/2435
// The `test` attribute.
#[proc_macro_attribute]
pub fn test_internal(input: TokenStream, item: TokenStream) -> TokenStream {
crate::executor::test(input, item)
}
/// The `stream_select!` macro.
#[proc_macro]
pub fn stream_select_internal(input: TokenStream) -> TokenStream {
crate::stream_select::stream_select(input.into())
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}

330
vendor/futures-macro/src/select.rs vendored Normal file
View File

@@ -0,0 +1,330 @@
//! The futures-rs `select!` macro implementation.
use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::{format_ident, quote};
use syn::parse::{Parse, ParseStream};
use syn::{parse_quote, Expr, Ident, Pat, Token};
mod kw {
syn::custom_keyword!(complete);
}
struct Select {
// span of `complete`, then expression after `=> ...`
complete: Option<Expr>,
default: Option<Expr>,
normal_fut_exprs: Vec<Expr>,
normal_fut_handlers: Vec<(Pat, Expr)>,
}
#[allow(clippy::large_enum_variant)]
enum CaseKind {
Complete,
Default,
Normal(Pat, Expr),
}
impl Parse for Select {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
let mut select = Self {
complete: None,
default: None,
normal_fut_exprs: vec![],
normal_fut_handlers: vec![],
};
while !input.is_empty() {
let case_kind = if input.peek(kw::complete) {
// `complete`
if select.complete.is_some() {
return Err(input.error("multiple `complete` cases found, only one allowed"));
}
input.parse::<kw::complete>()?;
CaseKind::Complete
} else if input.peek(Token![default]) {
// `default`
if select.default.is_some() {
return Err(input.error("multiple `default` cases found, only one allowed"));
}
input.parse::<Ident>()?;
CaseKind::Default
} else {
// `<pat> = <expr>`
let pat = Pat::parse_multi_with_leading_vert(input)?;
input.parse::<Token![=]>()?;
let expr = input.parse()?;
CaseKind::Normal(pat, expr)
};
// `=> <expr>`
input.parse::<Token![=>]>()?;
let expr = Expr::parse_with_earlier_boundary_rule(input)?;
// Commas after the expression are only optional if it's a `Block`
// or it is the last branch in the `match`.
let is_block = match expr {
Expr::Block(_) => true,
_ => false,
};
if is_block || input.is_empty() {
input.parse::<Option<Token![,]>>()?;
} else {
input.parse::<Token![,]>()?;
}
match case_kind {
CaseKind::Complete => select.complete = Some(expr),
CaseKind::Default => select.default = Some(expr),
CaseKind::Normal(pat, fut_expr) => {
select.normal_fut_exprs.push(fut_expr);
select.normal_fut_handlers.push((pat, expr));
}
}
}
Ok(select)
}
}
// Enum over all the cases in which the `select!` waiting has completed and the result
// can be processed.
//
// `enum __PrivResult<_1, _2, ...> { _1(_1), _2(_2), ..., Complete }`
fn declare_result_enum(
result_ident: Ident,
variants: usize,
complete: bool,
span: Span,
) -> (Vec<Ident>, syn::ItemEnum) {
// "_0", "_1", "_2"
let variant_names: Vec<Ident> =
(0..variants).map(|num| format_ident!("_{}", num, span = span)).collect();
let type_parameters = &variant_names;
let variants = &variant_names;
let complete_variant = if complete { Some(quote!(Complete)) } else { None };
let enum_item = parse_quote! {
enum #result_ident<#(#type_parameters,)*> {
#(
#variants(#type_parameters),
)*
#complete_variant
}
};
(variant_names, enum_item)
}
/// The `select!` macro.
pub(crate) fn select(input: TokenStream) -> TokenStream {
select_inner(input, true)
}
/// The `select_biased!` macro.
pub(crate) fn select_biased(input: TokenStream) -> TokenStream {
select_inner(input, false)
}
fn select_inner(input: TokenStream, random: bool) -> TokenStream {
let parsed = syn::parse_macro_input!(input as Select);
// should be def_site, but that's unstable
let span = Span::call_site();
let enum_ident = Ident::new("__PrivResult", span);
let (variant_names, enum_item) = declare_result_enum(
enum_ident.clone(),
parsed.normal_fut_exprs.len(),
parsed.complete.is_some(),
span,
);
// bind non-`Ident` future exprs w/ `let`
let mut future_let_bindings = Vec::with_capacity(parsed.normal_fut_exprs.len());
let bound_future_names: Vec<_> = parsed
.normal_fut_exprs
.into_iter()
.zip(variant_names.iter())
.map(|(expr, variant_name)| {
match expr {
syn::Expr::Path(path) => {
// Don't bind futures that are already a path.
// This prevents creating redundant stack space
// for them.
// Passing Futures by path requires those Futures to implement Unpin.
// We check for this condition here in order to be able to
// safely use Pin::new_unchecked(&mut #path) later on.
future_let_bindings.push(quote! {
__futures_crate::async_await::assert_fused_future(&#path);
__futures_crate::async_await::assert_unpin(&#path);
});
path
}
_ => {
// Bind and pin the resulting Future on the stack. This is
// necessary to support direct select! calls on !Unpin
// Futures. The Future is not explicitly pinned here with
// a Pin call, but assumed as pinned. The actual Pin is
// created inside the poll() function below to defer the
// creation of the temporary pointer, which would otherwise
// increase the size of the generated Future.
// Safety: This is safe since the lifetime of the Future
// is totally constraint to the lifetime of the select!
// expression, and the Future can't get moved inside it
// (it is shadowed).
future_let_bindings.push(quote! {
let mut #variant_name = #expr;
});
parse_quote! { #variant_name }
}
}
})
.collect();
// For each future, make an `&mut dyn FnMut(&mut Context<'_>) -> Option<Poll<__PrivResult<...>>`
// to use for polling that individual future. These will then be put in an array.
let poll_functions = bound_future_names.iter().zip(variant_names.iter()).map(
|(bound_future_name, variant_name)| {
// Below we lazily create the Pin on the Future below.
// This is done in order to avoid allocating memory in the generator
// for the Pin variable.
// Safety: This is safe because one of the following condition applies:
// 1. The Future is passed by the caller by name, and we assert that
// it implements Unpin.
// 2. The Future is created in scope of the select! function and will
// not be moved for the duration of it. It is thereby stack-pinned
quote! {
let mut #variant_name = |__cx: &mut __futures_crate::task::Context<'_>| {
let mut #bound_future_name = unsafe {
__futures_crate::Pin::new_unchecked(&mut #bound_future_name)
};
if __futures_crate::future::FusedFuture::is_terminated(&#bound_future_name) {
__futures_crate::None
} else {
__futures_crate::Some(__futures_crate::future::FutureExt::poll_unpin(
&mut #bound_future_name,
__cx,
).map(#enum_ident::#variant_name))
}
};
let #variant_name: &mut dyn FnMut(
&mut __futures_crate::task::Context<'_>
) -> __futures_crate::Option<__futures_crate::task::Poll<_>> = &mut #variant_name;
}
},
);
let none_polled = if parsed.complete.is_some() {
quote! {
__futures_crate::task::Poll::Ready(#enum_ident::Complete)
}
} else {
quote! {
panic!("all futures in select! were completed, \
but no `complete =>` handler was provided")
}
};
let branches = parsed.normal_fut_handlers.into_iter().zip(variant_names.iter()).map(
|((pat, expr), variant_name)| {
quote! {
#enum_ident::#variant_name(#pat) => #expr,
}
},
);
let branches = quote! { #( #branches )* };
let complete_branch = parsed.complete.map(|complete_expr| {
quote! {
#enum_ident::Complete => { #complete_expr },
}
});
let branches = quote! {
#branches
#complete_branch
};
let await_select_fut = if parsed.default.is_some() {
// For select! with default this returns the Poll result
quote! {
__poll_fn(&mut __futures_crate::task::Context::from_waker(
__futures_crate::task::noop_waker_ref()
))
}
} else {
quote! {
__futures_crate::future::poll_fn(__poll_fn).await
}
};
let execute_result_expr = if let Some(default_expr) = &parsed.default {
// For select! with default __select_result is a Poll, otherwise not
quote! {
match __select_result {
__futures_crate::task::Poll::Ready(result) => match result {
#branches
},
_ => #default_expr
}
}
} else {
quote! {
match __select_result {
#branches
}
}
};
let shuffle = if random {
quote! {
__futures_crate::async_await::shuffle(&mut __select_arr);
}
} else {
quote!()
};
TokenStream::from(quote! { {
#enum_item
let __select_result = {
#( #future_let_bindings )*
let mut __poll_fn = |__cx: &mut __futures_crate::task::Context<'_>| {
let mut __any_polled = false;
#( #poll_functions )*
let mut __select_arr = [#( #variant_names ),*];
#shuffle
for poller in &mut __select_arr {
let poller: &mut &mut dyn FnMut(
&mut __futures_crate::task::Context<'_>
) -> __futures_crate::Option<__futures_crate::task::Poll<_>> = poller;
match poller(__cx) {
__futures_crate::Some(x @ __futures_crate::task::Poll::Ready(_)) =>
return x,
__futures_crate::Some(__futures_crate::task::Poll::Pending) => {
__any_polled = true;
}
__futures_crate::None => {}
}
}
if !__any_polled {
#none_polled
} else {
__futures_crate::task::Poll::Pending
}
};
#await_select_fut
};
#execute_result_expr
} })
}

View File

@@ -0,0 +1,113 @@
use proc_macro2::TokenStream;
use quote::{format_ident, quote, ToTokens};
use syn::{parse::Parser, punctuated::Punctuated, Expr, Index, Token};
/// The `stream_select!` macro.
pub(crate) fn stream_select(input: TokenStream) -> Result<TokenStream, syn::Error> {
let args = Punctuated::<Expr, Token![,]>::parse_terminated.parse2(input)?;
if args.len() < 2 {
return Ok(quote! {
compile_error!("stream select macro needs at least two arguments.")
});
}
let generic_idents = (0..args.len()).map(|i| format_ident!("_{}", i)).collect::<Vec<_>>();
let field_idents = (0..args.len()).map(|i| format_ident!("__{}", i)).collect::<Vec<_>>();
let field_idents_2 = (0..args.len()).map(|i| format_ident!("___{}", i)).collect::<Vec<_>>();
let field_indices = (0..args.len()).map(Index::from).collect::<Vec<_>>();
let args = args.iter().map(|e| e.to_token_stream());
Ok(quote! {
{
#[derive(Debug)]
struct StreamSelect<#(#generic_idents),*> (#(Option<#generic_idents>),*);
enum StreamEnum<#(#generic_idents),*> {
#(
#generic_idents(#generic_idents)
),*,
None,
}
impl<ITEM, #(#generic_idents),*> __futures_crate::stream::Stream for StreamEnum<#(#generic_idents),*>
where #(#generic_idents: __futures_crate::stream::Stream<Item=ITEM> + ::std::marker::Unpin,)*
{
type Item = ITEM;
fn poll_next(mut self: ::std::pin::Pin<&mut Self>, cx: &mut __futures_crate::task::Context<'_>) -> __futures_crate::task::Poll<Option<Self::Item>> {
match self.get_mut() {
#(
Self::#generic_idents(#generic_idents) => ::std::pin::Pin::new(#generic_idents).poll_next(cx)
),*,
Self::None => panic!("StreamEnum::None should never be polled!"),
}
}
}
impl<ITEM, #(#generic_idents),*> __futures_crate::stream::Stream for StreamSelect<#(#generic_idents),*>
where #(#generic_idents: __futures_crate::stream::Stream<Item=ITEM> + ::std::marker::Unpin,)*
{
type Item = ITEM;
fn poll_next(mut self: ::std::pin::Pin<&mut Self>, cx: &mut __futures_crate::task::Context<'_>) -> __futures_crate::task::Poll<Option<Self::Item>> {
let Self(#(ref mut #field_idents),*) = self.get_mut();
#(
let mut #field_idents_2 = false;
)*
let mut any_pending = false;
{
let mut stream_array = [#(#field_idents.as_mut().map(|f| StreamEnum::#generic_idents(f)).unwrap_or(StreamEnum::None)),*];
__futures_crate::async_await::shuffle(&mut stream_array);
for mut s in stream_array {
if let StreamEnum::None = s {
continue;
} else {
match __futures_crate::stream::Stream::poll_next(::std::pin::Pin::new(&mut s), cx) {
r @ __futures_crate::task::Poll::Ready(Some(_)) => {
return r;
},
__futures_crate::task::Poll::Pending => {
any_pending = true;
},
__futures_crate::task::Poll::Ready(None) => {
match s {
#(
StreamEnum::#generic_idents(_) => { #field_idents_2 = true; }
),*,
StreamEnum::None => panic!("StreamEnum::None should never be polled!"),
}
},
}
}
}
}
#(
if #field_idents_2 {
*#field_idents = None;
}
)*
if any_pending {
__futures_crate::task::Poll::Pending
} else {
__futures_crate::task::Poll::Ready(None)
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let mut s = (0, Some(0));
#(
if let Some(new_hint) = self.#field_indices.as_ref().map(|s| s.size_hint()) {
s.0 += new_hint.0;
// We can change this out for `.zip` when the MSRV is 1.46.0 or higher.
s.1 = s.1.and_then(|a| new_hint.1.map(|b| a + b));
}
)*
s
}
}
StreamSelect(#(Some(#args)),*)
}
})
}