Improve value and reference passing efficiency (#3406)

This commit is contained in:
Theodore Bjernhed
2025-07-11 05:38:45 +02:00
committed by GitHub
parent 420d7b6aaa
commit 6bc0717b06
17 changed files with 117 additions and 107 deletions
+12 -12
View File
@@ -8,16 +8,16 @@ use proc_macro2::{Ident, Span, TokenStream};
use quote::{format_ident, quote, quote_spanned};
use syn::{parse::Parse, spanned::Spanned, FnArg, ItemFn, ReturnType, Token, Type};
pub(crate) fn expand(attr: Attrs, item_fn: ItemFn, kind: FunctionKind) -> TokenStream {
pub(crate) fn expand(attr: Attrs, item_fn: &ItemFn, kind: FunctionKind) -> TokenStream {
let Attrs { state_ty } = attr;
let mut state_ty = state_ty.map(second);
let check_extractor_count = check_extractor_count(&item_fn, kind);
let check_path_extractor = check_path_extractor(&item_fn, kind);
let check_output_tuples = check_output_tuples(&item_fn);
let check_extractor_count = check_extractor_count(item_fn, kind);
let check_path_extractor = check_path_extractor(item_fn, kind);
let check_output_tuples = check_output_tuples(item_fn);
let check_output_impls_into_response = if check_output_tuples.is_empty() {
check_output_impls_into_response(&item_fn)
check_output_impls_into_response(item_fn)
} else {
check_output_tuples
};
@@ -28,7 +28,7 @@ pub(crate) fn expand(attr: Attrs, item_fn: ItemFn, kind: FunctionKind) -> TokenS
let mut err = None;
if state_ty.is_none() {
let state_types_from_args = state_types_from_args(&item_fn);
let state_types_from_args = state_types_from_args(item_fn);
#[allow(clippy::comparison_chain)]
if state_types_from_args.len() == 1 {
@@ -50,16 +50,16 @@ pub(crate) fn expand(attr: Attrs, item_fn: ItemFn, kind: FunctionKind) -> TokenS
err.unwrap_or_else(|| {
let state_ty = state_ty.unwrap_or_else(|| syn::parse_quote!(()));
let check_future_send = check_future_send(&item_fn, kind);
let check_future_send = check_future_send(item_fn, kind);
if let Some(check_input_order) = check_input_order(&item_fn, kind) {
if let Some(check_input_order) = check_input_order(item_fn, kind) {
quote! {
#check_input_order
#check_future_send
}
} else {
let check_inputs_impls_from_request =
check_inputs_impls_from_request(&item_fn, state_ty, kind);
check_inputs_impls_from_request(item_fn, &state_ty, kind);
quote! {
#check_inputs_impls_from_request
@@ -76,7 +76,7 @@ pub(crate) fn expand(attr: Attrs, item_fn: ItemFn, kind: FunctionKind) -> TokenS
};
let middleware_takes_next_as_last_arg =
matches!(kind, FunctionKind::Middleware).then(|| next_is_last_input(&item_fn));
matches!(kind, FunctionKind::Middleware).then(|| next_is_last_input(item_fn));
quote! {
#item_fn
@@ -104,7 +104,7 @@ impl fmt::Display for FunctionKind {
}
impl FunctionKind {
fn name_uppercase_plural(&self) -> &'static str {
fn name_uppercase_plural(self) -> &'static str {
match self {
Self::Handler => "Handlers",
Self::Middleware => "Middleware",
@@ -222,7 +222,7 @@ fn is_self_pat_type(typed: &syn::PatType) -> bool {
fn check_inputs_impls_from_request(
item_fn: &ItemFn,
state_ty: Type,
state_ty: &Type,
kind: FunctionKind,
) -> TokenStream {
let takes_self = item_fn.sig.inputs.first().is_some_and(|arg| match arg {
+34 -34
View File
@@ -19,7 +19,7 @@ pub(crate) enum Trait {
}
impl Trait {
fn via_marker_type(&self) -> Option<Type> {
fn via_marker_type(self) -> Option<Type> {
match self {
Self::FromRequest => Some(parse_quote!(M)),
Self::FromRequestParts => None,
@@ -132,17 +132,17 @@ pub(crate) fn expand(item: syn::Item, tr: Trait) -> syn::Result<TokenStream> {
let trait_impl = match (via.map(second), rejection.map(second)) {
(Some(via), rejection) => impl_struct_by_extracting_all_at_once(
ident,
&ident,
fields,
via,
rejection,
generic_ident,
&via,
rejection.as_ref(),
generic_ident.as_ref(),
&state,
tr,
)?,
(None, rejection) => {
error_on_generic_ident(generic_ident, tr)?;
impl_struct_by_extracting_each_field(ident, fields, rejection, &state, tr)?
impl_struct_by_extracting_each_field(&ident, &fields, rejection, &state, tr)?
}
};
@@ -206,11 +206,11 @@ pub(crate) fn expand(item: syn::Item, tr: Trait) -> syn::Result<TokenStream> {
match (via.map(second), rejection) {
(Some(via), rejection) => impl_enum_by_extracting_all_at_once(
ident,
&ident,
variants,
via,
rejection.map(second),
state,
&via,
rejection.map(second).as_ref(),
&state,
tr,
),
(None, Some((rejection_kw, _))) => Err(syn::Error::new_spanned(
@@ -328,8 +328,8 @@ fn error_on_generic_ident(generic_ident: Option<Ident>, tr: Trait) -> syn::Resul
}
fn impl_struct_by_extracting_each_field(
ident: syn::Ident,
fields: syn::Fields,
ident: &syn::Ident,
fields: &syn::Fields,
rejection: Option<syn::Path>,
state: &State,
tr: Trait,
@@ -339,7 +339,7 @@ fn impl_struct_by_extracting_each_field(
::std::unimplemented!()
}
} else {
let extract_fields = extract_fields(&fields, &rejection, tr)?;
let extract_fields = extract_fields(fields, rejection.as_ref(), tr)?;
quote! {
::std::result::Result::Ok(Self {
#(#extract_fields)*
@@ -349,7 +349,7 @@ fn impl_struct_by_extracting_each_field(
let rejection_ident = if let Some(rejection) = rejection {
quote!(#rejection)
} else if has_no_fields(&fields) {
} else if has_no_fields(fields) {
quote!(::std::convert::Infallible)
} else {
quote!(::axum::response::Response)
@@ -411,7 +411,7 @@ fn has_no_fields(fields: &syn::Fields) -> bool {
fn extract_fields(
fields: &syn::Fields,
rejection: &Option<syn::Path>,
rejection: Option<&syn::Path>,
tr: Trait,
) -> syn::Result<Vec<TokenStream>> {
fn member(field: &syn::Field, index: usize) -> TokenStream {
@@ -426,7 +426,7 @@ fn extract_fields(
}
}
fn into_inner(via: &Option<(attr::kw::via, syn::Path)>, ty_span: Span) -> TokenStream {
fn into_inner(via: Option<&(attr::kw::via, syn::Path)>, ty_span: Span) -> TokenStream {
if let Some((_, path)) = via {
let span = path.span();
quote_spanned! {span=>
@@ -440,7 +440,7 @@ fn extract_fields(
}
fn into_outer(
via: &Option<(attr::kw::via, syn::Path)>,
via: Option<&(attr::kw::via, syn::Path)>,
ty_span: Span,
field_ty: &Type,
) -> TokenStream {
@@ -472,10 +472,10 @@ fn extract_fields(
let member = member(field, index);
let ty_span = field.ty.span();
let into_inner = into_inner(&via, ty_span);
let into_inner = into_inner(via.as_ref(), ty_span);
if peel_option(&field.ty).is_some() {
let field_ty = into_outer(&via, ty_span, peel_option(&field.ty).unwrap());
let field_ty = into_outer(via.as_ref(), ty_span, peel_option(&field.ty).unwrap());
let tokens = match tr {
Trait::FromRequest => {
quote_spanned! {ty_span=>
@@ -510,7 +510,7 @@ fn extract_fields(
};
Ok(tokens)
} else if peel_result_ok(&field.ty).is_some() {
let field_ty = into_outer(&via,ty_span, peel_result_ok(&field.ty).unwrap());
let field_ty = into_outer(via.as_ref(), ty_span, peel_result_ok(&field.ty).unwrap());
let tokens = match tr {
Trait::FromRequest => {
quote_spanned! {ty_span=>
@@ -543,7 +543,7 @@ fn extract_fields(
};
Ok(tokens)
} else {
let field_ty = into_outer(&via,ty_span,&field.ty);
let field_ty = into_outer(via.as_ref(), ty_span, &field.ty);
let map_err = if let Some(rejection) = rejection {
quote! { <#rejection as ::std::convert::From<_>>::from }
} else {
@@ -593,10 +593,10 @@ fn extract_fields(
let member = member(field, fields.len() - 1);
let ty_span = field.ty.span();
let into_inner = into_inner(&via, ty_span);
let into_inner = into_inner(via.as_ref(), ty_span);
let item = if peel_option(&field.ty).is_some() {
let field_ty = into_outer(&via, ty_span, peel_option(&field.ty).unwrap());
let field_ty = into_outer(via.as_ref(), ty_span, peel_option(&field.ty).unwrap());
quote_spanned! {ty_span=>
#member: {
<#field_ty as ::axum::extract::FromRequest<_, _>>::from_request(req, state)
@@ -606,7 +606,7 @@ fn extract_fields(
},
}
} else if peel_result_ok(&field.ty).is_some() {
let field_ty = into_outer(&via, ty_span, peel_result_ok(&field.ty).unwrap());
let field_ty = into_outer(via.as_ref(), ty_span, peel_result_ok(&field.ty).unwrap());
quote_spanned! {ty_span=>
#member: {
<#field_ty as ::axum::extract::FromRequest<_, _>>::from_request(req, state)
@@ -615,7 +615,7 @@ fn extract_fields(
},
}
} else {
let field_ty = into_outer(&via, ty_span, &field.ty);
let field_ty = into_outer(via.as_ref(), ty_span, &field.ty);
let map_err = if let Some(rejection) = rejection {
quote! { <#rejection as ::std::convert::From<_>>::from }
} else {
@@ -697,11 +697,11 @@ fn peel_result_ok(ty: &syn::Type) -> Option<&syn::Type> {
}
fn impl_struct_by_extracting_all_at_once(
ident: syn::Ident,
ident: &syn::Ident,
fields: syn::Fields,
via_path: syn::Path,
rejection: Option<syn::Path>,
generic_ident: Option<Ident>,
via_path: &syn::Path,
rejection: Option<&syn::Path>,
generic_ident: Option<&Ident>,
state: &State,
tr: Trait,
) -> syn::Result<TokenStream> {
@@ -750,7 +750,7 @@ fn impl_struct_by_extracting_all_at_once(
// - `State`, not other extractors
//
// honestly not sure why but the tests all pass
let via_marker_type = if path_ident_is_state(&via_path) {
let via_marker_type = if path_ident_is_state(via_path) {
tr.via_marker_type()
} else {
None
@@ -868,11 +868,11 @@ fn impl_struct_by_extracting_all_at_once(
}
fn impl_enum_by_extracting_all_at_once(
ident: syn::Ident,
ident: &syn::Ident,
variants: Punctuated<syn::Variant, Token![,]>,
path: syn::Path,
rejection: Option<syn::Path>,
state: State,
path: &syn::Path,
rejection: Option<&syn::Path>,
state: &State,
tr: Trait,
) -> syn::Result<TokenStream> {
for variant in variants {
+3 -3
View File
@@ -579,7 +579,7 @@ pub fn debug_handler(_attr: TokenStream, input: TokenStream) -> TokenStream {
#[cfg(debug_assertions)]
return expand_attr_with(_attr, input, |attrs, item_fn| {
debug_handler::expand(attrs, item_fn, FunctionKind::Handler)
debug_handler::expand(attrs, &item_fn, FunctionKind::Handler)
});
}
@@ -635,7 +635,7 @@ pub fn debug_middleware(_attr: TokenStream, input: TokenStream) -> TokenStream {
#[cfg(debug_assertions)]
return expand_attr_with(_attr, input, |attrs, item_fn| {
debug_handler::expand(attrs, item_fn, FunctionKind::Middleware)
debug_handler::expand(attrs, &item_fn, FunctionKind::Middleware)
});
}
@@ -662,7 +662,7 @@ pub fn __private_axum_test(_attr: TokenStream, input: TokenStream) -> TokenStrea
/// [`axum_extra::routing::TypedPath`]: https://docs.rs/axum-extra/latest/axum_extra/routing/trait.TypedPath.html
#[proc_macro_derive(TypedPath, attributes(typed_path))]
pub fn derive_typed_path(input: TokenStream) -> TokenStream {
expand_with(input, typed_path::expand)
expand_with(input, |item_struct| typed_path::expand(&item_struct))
}
/// Derive an implementation of [`FromRef`] for each field in a struct.
+23 -18
View File
@@ -4,14 +4,14 @@ use syn::{parse::Parse, ItemStruct, LitStr, Token};
use crate::attr_parsing::{combine_attribute, parse_parenthesized_attribute, second, Combine};
pub(crate) fn expand(item_struct: ItemStruct) -> syn::Result<TokenStream> {
pub(crate) fn expand(item_struct: &ItemStruct) -> syn::Result<TokenStream> {
let ItemStruct {
attrs,
ident,
generics,
fields,
..
} = &item_struct;
} = item_struct;
if !generics.params.is_empty() || generics.where_clause.is_some() {
return Err(syn::Error::new_spanned(
@@ -34,13 +34,18 @@ pub(crate) fn expand(item_struct: ItemStruct) -> syn::Result<TokenStream> {
match fields {
syn::Fields::Named(_) => {
let segments = parse_path(&path)?;
Ok(expand_named_fields(ident, path, &segments, rejection))
Ok(expand_named_fields(
ident,
&path,
&segments,
rejection.as_ref(),
))
}
syn::Fields::Unnamed(fields) => {
let segments = parse_path(&path)?;
expand_unnamed_fields(fields, ident, path, &segments, rejection)
expand_unnamed_fields(fields, ident, &path, &segments, rejection.as_ref())
}
syn::Fields::Unit => expand_unit_fields(ident, path, rejection),
syn::Fields::Unit => expand_unit_fields(ident, &path, rejection.as_ref()),
}
}
@@ -95,9 +100,9 @@ impl Combine for Attrs {
fn expand_named_fields(
ident: &syn::Ident,
path: LitStr,
path: &LitStr,
segments: &[Segment],
rejection: Option<syn::Path>,
rejection: Option<&syn::Path>,
) -> TokenStream {
let format_str = format_str_from_path(segments);
let captures = captures_from_path(segments);
@@ -129,8 +134,8 @@ fn expand_named_fields(
}
};
let rejection_assoc_type = rejection_assoc_type(&rejection);
let map_err_rejection = map_err_rejection(&rejection);
let rejection_assoc_type = rejection_assoc_type(rejection);
let map_err_rejection = map_err_rejection(rejection);
let from_request_impl = quote! {
#[automatically_derived]
@@ -162,9 +167,9 @@ fn expand_named_fields(
fn expand_unnamed_fields(
fields: &syn::FieldsUnnamed,
ident: &syn::Ident,
path: LitStr,
path: &LitStr,
segments: &[Segment],
rejection: Option<syn::Path>,
rejection: Option<&syn::Path>,
) -> syn::Result<TokenStream> {
let num_captures = segments
.iter()
@@ -233,8 +238,8 @@ fn expand_unnamed_fields(
}
};
let rejection_assoc_type = rejection_assoc_type(&rejection);
let map_err_rejection = map_err_rejection(&rejection);
let rejection_assoc_type = rejection_assoc_type(rejection);
let map_err_rejection = map_err_rejection(rejection);
let from_request_impl = quote! {
#[automatically_derived]
@@ -273,10 +278,10 @@ fn simple_pluralize(count: usize, word: &str) -> String {
fn expand_unit_fields(
ident: &syn::Ident,
path: LitStr,
rejection: Option<syn::Path>,
path: &LitStr,
rejection: Option<&syn::Path>,
) -> syn::Result<TokenStream> {
for segment in parse_path(&path)? {
for segment in parse_path(path)? {
match segment {
Segment::Capture(_, span) => {
return Err(syn::Error::new(
@@ -409,14 +414,14 @@ fn path_rejection() -> TokenStream {
}
}
fn rejection_assoc_type(rejection: &Option<syn::Path>) -> TokenStream {
fn rejection_assoc_type(rejection: Option<&syn::Path>) -> TokenStream {
match rejection {
Some(rejection) => quote! { #rejection },
None => path_rejection(),
}
}
fn map_err_rejection(rejection: &Option<syn::Path>) -> TokenStream {
fn map_err_rejection(rejection: Option<&syn::Path>) -> TokenStream {
rejection
.as_ref()
.map(|rejection| {