Move axum-debug into axum-macros (#724)

* Move axum-debug into axum-macros

* fix ref to axum-macros in changelog

* Apply suggestions from code review

Co-authored-by: Jonas Platte <jplatte@users.noreply.github.com>

Co-authored-by: Jonas Platte <jplatte@users.noreply.github.com>
This commit is contained in:
David Pedersen 2022-01-26 23:27:22 +01:00 committed by GitHub
parent b1283e9708
commit f6fc5ed80c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
60 changed files with 492 additions and 217 deletions

View file

@ -8,7 +8,6 @@ If your project isn't listed here and you would like it to be, please feel free
- [axum-typed-websockets](https://crates.io/crates/axum-typed-websockets): `axum::extract::ws` with type safe messages.
- [tower-cookies](https://crates.io/crates/tower-cookies): Cookie manager middleware
- [axum-flash](https://crates.io/crates/axum-flash): One-time notifications (aka flash messages) for axum.
- [axum-debug](https://crates.io/crates/axum-debug): Debugging crate that provides better error messages for axum.
- [axum-msgpack](https://crates.io/crates/axum-msgpack): MessagePack Extractors for axum.
## Project showcase

View file

@ -17,8 +17,3 @@ proc-macro = true
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "1.0", features = ["full"] }
[dev-dependencies]
axum = { path = "../axum", version = "0.4" }
trybuild = "1.0"
rustversion = "1.0"

View file

@ -7,6 +7,8 @@
This is a debugging crate that provides better error messages for [`axum`]
framework.
**Note:** this crate is deprecated. Use [axum-macros] instead.
More information about this crate can be found in the [crate documentation][docs].
## Safety
@ -44,3 +46,4 @@ additional terms or conditions.
[docs]: https://docs.rs/axum-debug
[license]: /axum-debug/LICENSE
[issue]: https://github.com/tokio-rs/axum/issues/new
[axum-macros]: https://crates.io/crates/axum-macros

View file

@ -1,148 +1,19 @@
//! This is a debugging crate that provides better error messages for [`axum`] framework.
//!
//! While using [`axum`], you can get long error messages for simple mistakes. For example:
//! **Note:** this crate is deprecated. Use [axum-macros] instead.
//!
//! ```rust,compile_fail
//! use axum::{routing::get, Router};
//! [axum-macros]: https://crates.io/crates/axum-macros
//!
//! #[tokio::main]
//! async fn main() {
//! let app = Router::new().route("/", get(handler));
//!
//! axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
//! .serve(app.into_make_service())
//! .await
//! .unwrap();
//! }
//!
//! fn handler() -> &'static str {
//! "Hello, world"
//! }
//! ```
//!
//! You will get a long error message about function not implementing [`Handler`] trait. But why
//! does this function not implement it? To figure it out, the [`debug_handler`] macro can be used.
//!
//! ```rust,compile_fail
//! # use axum::{routing::get, Router};
//! # use axum_debug::debug_handler;
//! #
//! # #[tokio::main]
//! # async fn main() {
//! # let app = Router::new().route("/", get(handler));
//! #
//! # axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
//! # .serve(app.into_make_service())
//! # .await
//! # .unwrap();
//! # }
//! #
//! #[debug_handler]
//! fn handler() -> &'static str {
//! "Hello, world"
//! }
//! ```
//!
//! ```text
//! error: handlers must be async functions
//! --> main.rs:xx:1
//! |
//! xx | fn handler() -> &'static str {
//! | ^^
//! ```
//!
//! As the error message says, handler function needs to be async.
//!
//! ```rust,compile_fail
//! use axum::{routing::get, Router};
//! use axum_debug::debug_handler;
//!
//! #[tokio::main]
//! async fn main() {
//! let app = Router::new().route("/", get(handler));
//!
//! axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
//! .serve(app.into_make_service())
//! .await
//! .unwrap();
//! }
//!
//! #[debug_handler]
//! async fn handler() -> &'static str {
//! "Hello, world"
//! }
//! ```
//!
//! # Changing request body type
//!
//! By default `#[debug_handler]` assumes your request body type is `axum::body::Body`. This will
//! work for most extractors but, for example, it wont work for `Request<axum::body::BoxBody>`,
//! which only implements `FromRequest<BoxBody>` and _not_ `FromRequest<Body>`.
//!
//! To work around that the request body type can be customized like so:
//!
//! ```rust
//! use axum::{body::BoxBody, http::Request};
//! # use axum_debug::debug_handler;
//!
//! #[debug_handler(body = BoxBody)]
//! async fn handler(request: Request<BoxBody>) {}
//! ```
//!
//! # Performance
//!
//! Macros in this crate have no effect when using release profile. (eg. `cargo build --release`)
//!
//! [`axum`]: https://docs.rs/axum/0.3
//! [`Handler`]: https://docs.rs/axum/0.3/axum/handler/trait.Handler.html
//! [`debug_handler`]: macro@debug_handler
#![warn(
clippy::all,
clippy::dbg_macro,
clippy::todo,
clippy::empty_enum,
clippy::enum_glob_use,
clippy::mem_forget,
clippy::unused_self,
clippy::filter_map_next,
clippy::needless_continue,
clippy::needless_borrow,
clippy::match_wildcard_for_single_variants,
clippy::if_let_mutex,
clippy::mismatched_target_os,
clippy::await_holding_lock,
clippy::match_on_vec_items,
clippy::imprecise_flops,
clippy::suboptimal_flops,
clippy::lossy_float_literal,
clippy::rest_pat_in_fully_bound_structs,
clippy::fn_params_excessive_bools,
clippy::exit,
clippy::inefficient_to_string,
clippy::linkedlist,
clippy::macro_use_imports,
clippy::option_option,
clippy::verbose_file_reads,
clippy::unnested_or_patterns,
clippy::str_to_string,
rust_2018_idioms,
future_incompatible,
nonstandard_style,
missing_debug_implementations,
missing_docs
)]
#![deny(unreachable_pub, private_in_public)]
#![allow(elided_lifetimes_in_paths, clippy::type_complexity)]
#![forbid(unsafe_code)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(test, allow(clippy::float_cmp))]
//! [`axum`]: https://docs.rs/axum/latest
use proc_macro::TokenStream;
/// Generates better error messages when applied to a handler function.
///
/// See the [module docs](self) for more details.
/// Note this crate is deprecated. Use [axum-macros] instead.
///
/// [axum-macros]: https://crates.io/crates/axum-macros
#[deprecated(since = "0.3.3", note = "Use the axum-macros crate instead")]
#[proc_macro_attribute]
pub fn debug_handler(_attr: TokenStream, input: TokenStream) -> TokenStream {
#[cfg(not(debug_assertions))]
@ -442,18 +313,3 @@ mod debug_handler {
None
}
}
#[test]
fn ui() {
#[rustversion::stable]
fn go() {
let t = trybuild::TestCases::new();
t.compile_fail("tests/fail/*.rs");
t.pass("tests/pass/*.rs");
}
#[rustversion::not(stable)]
fn go() {}
go();
}

View file

@ -1,5 +0,0 @@
error: expected `fn`
--> tests/fail/not_a_function.rs:4:1
|
4 | struct A;
| ^^^^^^

View file

@ -23,4 +23,5 @@ syn = { version = "1.0", features = ["full"] }
axum = { path = "../axum", version = "0.4", features = ["headers"] }
rustversion = "1.0"
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.0", features = ["full"] }
trybuild = "1.0"

View file

@ -1,4 +1,4 @@
Copyright 2021 Axum Debug Contributors
Copyright 2021 Axum Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

View file

@ -0,0 +1,288 @@
use proc_macro2::TokenStream;
use quote::{format_ident, quote, quote_spanned};
use syn::{parse::Parse, spanned::Spanned, FnArg, ItemFn, Token, Type};
pub(crate) fn expand(attr: Attrs, item_fn: ItemFn) -> syn::Result<TokenStream> {
check_extractor_count(&item_fn)?;
let check_inputs_impls_from_request = check_inputs_impls_from_request(&item_fn, &attr.body_ty);
let check_output_impls_into_response = check_output_impls_into_response(&item_fn);
let check_future_send = check_future_send(&item_fn);
let tokens = quote! {
#item_fn
#check_inputs_impls_from_request
#check_output_impls_into_response
#check_future_send
};
Ok(tokens)
}
pub(crate) struct Attrs {
body_ty: Type,
}
impl Parse for Attrs {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let mut body_ty = None;
while !input.is_empty() {
let ident = input.parse::<syn::Ident>()?;
if ident == "body" {
input.parse::<Token![=]>()?;
body_ty = Some(input.parse()?);
} else {
return Err(syn::Error::new_spanned(ident, "unknown argument"));
}
let _ = input.parse::<Token![,]>();
}
let body_ty = body_ty.unwrap_or_else(|| syn::parse_quote!(axum::body::Body));
Ok(Self { body_ty })
}
}
fn check_extractor_count(item_fn: &ItemFn) -> syn::Result<()> {
let max_extractors = 16;
if item_fn.sig.inputs.len() <= max_extractors {
Ok(())
} else {
Err(syn::Error::new_spanned(
&item_fn.sig.inputs,
format!(
"Handlers cannot take more than {} arguments. Use `(a, b): (ExtractorA, ExtractorA)` to further nest extractors",
max_extractors,
)
))
}
}
fn check_inputs_impls_from_request(item_fn: &ItemFn, body_ty: &Type) -> TokenStream {
if !item_fn.sig.generics.params.is_empty() {
return syn::Error::new_spanned(
&item_fn.sig.generics,
"`#[axum_macros::debug_handler]` doesn't support generic functions",
)
.into_compile_error();
}
item_fn
.sig
.inputs
.iter()
.enumerate()
.map(|(idx, arg)| {
let (span, ty) = match arg {
FnArg::Receiver(receiver) => {
if receiver.reference.is_some() {
return syn::Error::new_spanned(
receiver,
"Handlers must only take owned values",
)
.into_compile_error();
}
let span = receiver.span();
(span, syn::parse_quote!(Self))
}
FnArg::Typed(typed) => {
let ty = &typed.ty;
let span = ty.span();
(span, ty.clone())
}
};
let name = format_ident!(
"__axum_macros_check_{}_{}_from_request",
item_fn.sig.ident,
idx
);
quote_spanned! {span=>
#[allow(warnings)]
fn #name()
where
#ty: ::axum::extract::FromRequest<#body_ty> + Send,
{}
}
})
.collect::<TokenStream>()
}
fn check_output_impls_into_response(item_fn: &ItemFn) -> TokenStream {
let ty = match &item_fn.sig.output {
syn::ReturnType::Default => return quote! {},
syn::ReturnType::Type(_, ty) => ty,
};
let span = ty.span();
let declare_inputs = item_fn
.sig
.inputs
.iter()
.filter_map(|arg| match arg {
FnArg::Receiver(_) => None,
FnArg::Typed(pat_ty) => {
let pat = &pat_ty.pat;
let ty = &pat_ty.ty;
Some(quote! {
let #pat: #ty = panic!();
})
}
})
.collect::<TokenStream>();
let block = &item_fn.block;
let make_value_name = format_ident!(
"__axum_macros_check_{}_into_response_make_value",
item_fn.sig.ident
);
let make = if item_fn.sig.asyncness.is_some() {
quote_spanned! {span=>
#[allow(warnings)]
async fn #make_value_name() -> #ty {
#declare_inputs
#block
}
}
} else {
quote_spanned! {span=>
#[allow(warnings)]
fn #make_value_name() -> #ty {
#declare_inputs
#block
}
}
};
let name = format_ident!("__axum_macros_check_{}_into_response", item_fn.sig.ident);
if let Some(receiver) = self_receiver(item_fn) {
quote_spanned! {span=>
#make
#[allow(warnings)]
async fn #name() {
let value = #receiver #make_value_name().await;
fn check<T>(_: T)
where T: ::axum::response::IntoResponse
{}
check(value);
}
}
} else {
quote_spanned! {span=>
#[allow(warnings)]
async fn #name() {
#make
let value = #make_value_name().await;
fn check<T>(_: T)
where T: ::axum::response::IntoResponse
{}
check(value);
}
}
}
}
fn check_future_send(item_fn: &ItemFn) -> TokenStream {
if item_fn.sig.asyncness.is_none() {
match &item_fn.sig.output {
syn::ReturnType::Default => {
return syn::Error::new_spanned(
&item_fn.sig.fn_token,
"Handlers must be `async fn`s",
)
.into_compile_error();
}
syn::ReturnType::Type(_, ty) => ty,
};
}
let span = item_fn.span();
let handler_name = &item_fn.sig.ident;
let args = item_fn.sig.inputs.iter().map(|_| {
quote_spanned! {span=> panic!() }
});
let name = format_ident!("__axum_macros_check_{}_future", item_fn.sig.ident);
if let Some(receiver) = self_receiver(item_fn) {
quote_spanned! {span=>
#[allow(warnings)]
fn #name() {
let future = #receiver #handler_name(#(#args),*);
fn check<T>(_: T)
where T: ::std::future::Future + Send
{}
check(future);
}
}
} else {
quote_spanned! {span=>
#[allow(warnings)]
fn #name() {
#item_fn
let future = #handler_name(#(#args),*);
fn check<T>(_: T)
where T: ::std::future::Future + Send
{}
check(future);
}
}
}
}
fn self_receiver(item_fn: &ItemFn) -> Option<TokenStream> {
let takes_self = item_fn
.sig
.inputs
.iter()
.any(|arg| matches!(arg, syn::FnArg::Receiver(_)));
if takes_self {
return Some(quote! { Self:: });
}
if let syn::ReturnType::Type(_, ty) = &item_fn.sig.output {
if let syn::Type::Path(path) = &**ty {
let segments = &path.path.segments;
if segments.len() == 1 {
if let Some(last) = segments.last() {
match &last.arguments {
syn::PathArguments::None if last.ident == "Self" => {
return Some(quote! { Self:: });
}
_ => {}
}
}
}
}
}
None
}
#[test]
fn ui() {
#[rustversion::stable]
fn go() {
let t = trybuild::TestCases::new();
t.compile_fail("tests/debug_handler/fail/*.rs");
t.pass("tests/debug_handler/pass/*.rs");
}
#[rustversion::not(stable)]
fn go() {}
go();
}

View file

@ -508,8 +508,8 @@ fn ui() {
#[rustversion::stable]
fn go() {
let t = trybuild::TestCases::new();
t.compile_fail("tests/fail/*.rs");
t.pass("tests/pass/*.rs");
t.compile_fail("tests/from_request/fail/*.rs");
t.pass("tests/from_request/pass/*.rs");
}
#[rustversion::not(stable)]

View file

@ -43,9 +43,11 @@
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(test, allow(clippy::float_cmp))]
use proc_macro::TokenStream;
use quote::{quote, ToTokens};
use syn::parse::Parse;
mod debug_handler;
mod from_request;
/// Derive an implementation of [`FromRequest`].
@ -235,17 +237,148 @@ mod from_request;
/// [`FromRequest`]: https://docs.rs/axum/latest/axum/extract/trait.FromRequest.html
/// [`axum::extract::rejection::ExtensionRejection`]: https://docs.rs/axum/latest/axum/extract/rejection/enum.ExtensionRejection.html
#[proc_macro_derive(FromRequest, attributes(from_request))]
pub fn derive_from_request(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
pub fn derive_from_request(item: TokenStream) -> TokenStream {
expand_with(item, from_request::expand)
}
fn expand_with<F, T, K>(input: proc_macro::TokenStream, f: F) -> proc_macro::TokenStream
/// Generates better error messages when applied handler functions.
///
/// While using [`axum`], you can get long error messages for simple mistakes. For example:
///
/// ```compile_fail
/// use axum::{routing::get, Router};
///
/// #[tokio::main]
/// async fn main() {
/// let app = Router::new().route("/", get(handler));
///
/// axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
/// .serve(app.into_make_service())
/// .await
/// .unwrap();
/// }
///
/// fn handler() -> &'static str {
/// "Hello, world"
/// }
/// ```
///
/// You will get a long error message about function not implementing [`Handler`] trait. But why
/// does this function not implement it? To figure it out, the [`debug_handler`] macro can be used.
///
/// ```compile_fail
/// # use axum::{routing::get, Router};
/// # use axum_macros::debug_handler;
/// #
/// # #[tokio::main]
/// # async fn main() {
/// # let app = Router::new().route("/", get(handler));
/// #
/// # axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
/// # .serve(app.into_make_service())
/// # .await
/// # .unwrap();
/// # }
/// #
/// #[debug_handler]
/// fn handler() -> &'static str {
/// "Hello, world"
/// }
/// ```
///
/// ```text
/// error: handlers must be async functions
/// --> main.rs:xx:1
/// |
/// xx | fn handler() -> &'static str {
/// | ^^
/// ```
///
/// As the error message says, handler function needs to be async.
///
/// ```
/// use axum::{routing::get, Router};
/// use axum_macros::debug_handler;
///
/// #[tokio::main]
/// async fn main() {
/// # async {
/// let app = Router::new().route("/", get(handler));
///
/// axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
/// .serve(app.into_make_service())
/// .await
/// .unwrap();
/// # };
/// }
///
/// #[debug_handler]
/// async fn handler() -> &'static str {
/// "Hello, world"
/// }
/// ```
///
/// # Changing request body type
///
/// By default `#[debug_handler]` assumes your request body type is `axum::body::Body`. This will
/// work for most extractors but, for example, it wont work for `Request<axum::body::BoxBody>`,
/// which only implements `FromRequest<BoxBody>` and _not_ `FromRequest<Body>`.
///
/// To work around that the request body type can be customized like so:
///
/// ```
/// use axum::{body::BoxBody, http::Request};
/// # use axum_macros::debug_handler;
///
/// #[debug_handler(body = BoxBody)]
/// async fn handler(request: Request<BoxBody>) {}
/// ```
///
/// # Performance
///
/// This macro has no effect when compiled with the release profile. (eg. `cargo build --release`)
///
/// [`axum`]: https://docs.rs/axum/latest
/// [`Handler`]: https://docs.rs/axum/latest/axum/handler/trait.Handler.html
/// [`debug_handler`]: macro@debug_handler
#[proc_macro_attribute]
pub fn debug_handler(_attr: TokenStream, input: TokenStream) -> TokenStream {
#[cfg(not(debug_assertions))]
return input;
#[cfg(debug_assertions)]
return expand_attr_with(_attr, input, debug_handler::expand);
}
fn expand_with<F, I, K>(input: TokenStream, f: F) -> TokenStream
where
F: FnOnce(T) -> syn::Result<K>,
T: Parse,
F: FnOnce(I) -> syn::Result<K>,
I: Parse,
K: ToTokens,
{
match syn::parse(input).and_then(f) {
expand(syn::parse(input).and_then(f))
}
fn expand_attr_with<F, A, I, K>(attr: TokenStream, input: TokenStream, f: F) -> TokenStream
where
F: FnOnce(A, I) -> syn::Result<K>,
A: Parse,
I: Parse,
K: ToTokens,
{
let expand_result = (|| {
let attr = syn::parse(attr)?;
let input = syn::parse(input)?;
f(attr, input)
})();
expand(expand_result)
}
fn expand<T>(result: syn::Result<T>) -> TokenStream
where
T: ToTokens,
{
match result {
Ok(tokens) => {
let tokens = (quote! { #tokens }).into();
if std::env::var_os("AXUM_MACROS_DEBUG").is_some() {

View file

@ -1,4 +1,4 @@
use axum_debug::debug_handler;
use axum_macros::debug_handler;
#[debug_handler]
async fn handler(foo: bool) {}

View file

@ -1,5 +1,5 @@
error[E0277]: the trait bound `bool: FromRequest<Body>` is not satisfied
--> tests/fail/argument_not_extractor.rs:4:23
--> tests/debug_handler/fail/argument_not_extractor.rs:4:23
|
4 | async fn handler(foo: bool) {}
| ^^^^ the trait `FromRequest<Body>` is not implemented for `bool`

View file

@ -2,7 +2,7 @@ use axum::{
async_trait,
extract::{FromRequest, RequestParts},
};
use axum_debug::debug_handler;
use axum_macros::debug_handler;
struct A;

View file

@ -1,5 +1,5 @@
error: Handlers must only take owned values
--> tests/fail/extract_self_mut.rs:23:22
--> tests/debug_handler/fail/extract_self_mut.rs:23:22
|
23 | async fn handler(&mut self) {}
| ^^^^^^^^^

View file

@ -2,7 +2,7 @@ use axum::{
async_trait,
extract::{FromRequest, RequestParts},
};
use axum_debug::debug_handler;
use axum_macros::debug_handler;
struct A;

View file

@ -1,5 +1,5 @@
error: Handlers must only take owned values
--> tests/fail/extract_self_ref.rs:23:22
--> tests/debug_handler/fail/extract_self_ref.rs:23:22
|
23 | async fn handler(&self) {}
| ^^^^^

View file

@ -1,4 +1,4 @@
use axum_debug::debug_handler;
use axum_macros::debug_handler;
#[debug_handler]
async fn handler<T>() {}

View file

@ -1,11 +1,11 @@
error: `#[axum_debug::debug_handler]` doesn't support generic functions
--> tests/fail/generics.rs:4:17
error: `#[axum_macros::debug_handler]` doesn't support generic functions
--> tests/debug_handler/fail/generics.rs:4:17
|
4 | async fn handler<T>() {}
| ^^^
error[E0282]: type annotations needed
--> tests/fail/generics.rs:4:10
--> tests/debug_handler/fail/generics.rs:4:10
|
4 | async fn handler<T>() {}
| ----- ^^^^^^^ cannot infer type for type parameter `T` declared on the function `handler`

View file

@ -1,4 +1,4 @@
use axum_debug::debug_handler;
use axum_macros::debug_handler;
#[debug_handler(foo)]
async fn handler() {}

View file

@ -1,5 +1,5 @@
error: unknown argument
--> tests/fail/invalid_attrs.rs:3:17
--> tests/debug_handler/fail/invalid_attrs.rs:3:17
|
3 | #[debug_handler(foo)]
| ^^^

View file

@ -1,4 +1,4 @@
use axum_debug::debug_handler;
use axum_macros::debug_handler;
#[debug_handler]
struct A;

View file

@ -0,0 +1,5 @@
error: expected `fn`
--> tests/debug_handler/fail/not_a_function.rs:4:1
|
4 | struct A;
| ^^^^^^

View file

@ -1,4 +1,4 @@
use axum_debug::debug_handler;
use axum_macros::debug_handler;
#[debug_handler]
fn handler() {}

View file

@ -1,5 +1,5 @@
error: Handlers must be `async fn`s
--> tests/fail/not_async.rs:4:1
--> tests/debug_handler/fail/not_async.rs:4:1
|
4 | fn handler() {}
| ^^

View file

@ -1,4 +1,4 @@
use axum_debug::debug_handler;
use axum_macros::debug_handler;
#[debug_handler]
async fn handler() {

View file

@ -1,12 +1,12 @@
error: future cannot be sent between threads safely
--> tests/fail/not_send.rs:4:1
--> tests/debug_handler/fail/not_send.rs:4:1
|
4 | async fn handler() {
| ^^^^^ future returned by `handler` is not `Send`
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
note: future is not `Send` as this value is used across an await
--> tests/fail/not_send.rs:6:5
--> tests/debug_handler/fail/not_send.rs:6:5
|
5 | let rc = std::rc::Rc::new(());
| -- has type `Rc<()>` which is not `Send`
@ -15,7 +15,7 @@ note: future is not `Send` as this value is used across an await
7 | }
| - `rc` is later dropped here
note: required by a bound in `check`
--> tests/fail/not_send.rs:4:1
--> tests/debug_handler/fail/not_send.rs:4:1
|
4 | async fn handler() {
| ^^^^^ required by this bound in `check`

View file

@ -1,4 +1,4 @@
use axum_debug::debug_handler;
use axum_macros::debug_handler;
#[debug_handler]
async fn handler(

View file

@ -1,5 +1,5 @@
error: Handlers cannot take more than 16 arguments. Use `(a, b): (ExtractorA, ExtractorA)` to further nest extractors
--> tests/fail/too_many_extractors.rs:5:5
--> tests/debug_handler/fail/too_many_extractors.rs:5:5
|
5 | / e1: String,
6 | | e2: String,

View file

@ -1,4 +1,4 @@
use axum_debug::debug_handler;
use axum_macros::debug_handler;
#[debug_handler]
async fn handler() -> bool {

View file

@ -1,11 +1,11 @@
error[E0277]: the trait bound `bool: IntoResponse` is not satisfied
--> tests/fail/wrong_return_type.rs:4:23
--> tests/debug_handler/fail/wrong_return_type.rs:4:23
|
4 | async fn handler() -> bool {
| ^^^^ the trait `IntoResponse` is not implemented for `bool`
|
note: required by a bound in `__axum_debug_check_handler_into_response::{closure#0}::check`
--> tests/fail/wrong_return_type.rs:4:23
note: required by a bound in `__axum_macros_check_handler_into_response::{closure#0}::check`
--> tests/debug_handler/fail/wrong_return_type.rs:4:23
|
4 | async fn handler() -> bool {
| ^^^^ required by this bound in `__axum_debug_check_handler_into_response::{closure#0}::check`
| ^^^^ required by this bound in `__axum_macros_check_handler_into_response::{closure#0}::check`

View file

@ -1,4 +1,4 @@
use axum_debug::debug_handler;
use axum_macros::debug_handler;
struct A;

View file

@ -1,5 +1,5 @@
use axum::{body::BoxBody, http::Request};
use axum_debug::debug_handler;
use axum_macros::debug_handler;
#[debug_handler(body = BoxBody)]
async fn handler(_: Request<BoxBody>) {}

View file

@ -1,4 +1,4 @@
use axum_debug::debug_handler;
use axum_macros::debug_handler;
use std::future::Future;
#[debug_handler]

View file

@ -1,4 +1,4 @@
use axum_debug::debug_handler;
use axum_macros::debug_handler;
use axum::response::IntoResponse;
#[debug_handler]

View file

@ -1,4 +1,4 @@
use axum_debug::debug_handler;
use axum_macros::debug_handler;
#[debug_handler]
async fn handler(_one: String, _two: String, _three: String) {}

View file

@ -1,4 +1,4 @@
use axum_debug::debug_handler;
use axum_macros::debug_handler;
#[debug_handler]
async fn handler(mut foo: String) -> String {

View file

@ -1,4 +1,4 @@
use axum_debug::debug_handler;
use axum_macros::debug_handler;
use std::future::{Ready, ready};
#[debug_handler]

View file

@ -3,7 +3,7 @@ use axum::{
extract::{FromRequest, RequestParts},
response::IntoResponse,
};
use axum_debug::debug_handler;
use axum_macros::debug_handler;
fn main() {}

View file

@ -1,5 +1,5 @@
use axum::response::{IntoResponse, Response};
use axum_debug::debug_handler;
use axum_macros::debug_handler;
struct A;

View file

@ -2,7 +2,7 @@ use axum::{
async_trait,
extract::{FromRequest, RequestParts},
};
use axum_debug::debug_handler;
use axum_macros::debug_handler;
struct A;

View file

@ -1,11 +1,11 @@
error: `via` specified more than once
--> tests/fail/double_via_attr.rs:5:49
--> tests/from_request/fail/double_via_attr.rs:5:49
|
5 | struct Extractor(#[from_request(via(Extension), via(Extension))] State);
| ^^^
warning: unused import: `axum::extract::Extension`
--> tests/fail/double_via_attr.rs:2:5
--> tests/from_request/fail/double_via_attr.rs:2:5
|
2 | use axum::extract::Extension;
| ^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -1,5 +1,5 @@
error: `#[derive(FromRequest)] doesn't support generics
--> tests/fail/generic.rs:4:17
--> tests/from_request/fail/generic.rs:4:17
|
4 | struct Extractor<T>(Option<T>);
| ^^^

View file

@ -1,5 +1,5 @@
error: expected `via`
--> tests/fail/unknown_attr.rs:4:33
--> tests/from_request/fail/unknown_attr.rs:4:33
|
4 | struct Extractor(#[from_request(foo)] String);
| ^^^

View file

@ -1,11 +1,11 @@
error: `#[from_request(via(...))]` on a field cannot be used together with `#[from_request(...)]` on the container
--> tests/fail/via_on_container_and_field.rs:6:33
--> tests/from_request/fail/via_on_container_and_field.rs:6:33
|
6 | struct Extractor(#[from_request(via(Extension))] State);
| ^^^
warning: unused import: `axum::extract::Extension`
--> tests/fail/via_on_container_and_field.rs:2:5
--> tests/from_request/fail/via_on_container_and_field.rs:2:5
|
2 | use axum::extract::Extension;
| ^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -5,4 +5,4 @@ can be converted [into a response](crate::response).
Handlers is where your application logic lives and axum applications are built
by routing between handlers.
[`debug_handler`]: https://docs.rs/axum-debug/latest/axum_debug/attr.debug_handler.html
[`debug_handler`]: https://docs.rs/axum-macros/latest/axum_macros/attr.debug_handler.html

View file

@ -66,9 +66,9 @@
//!
//! This error doesn't tell you _why_ your function doesn't implement
//! [`Handler`]. It's possible to improve the error with the [`debug_handler`]
//! proc-macro from the [axum-debug] crate.
//! proc-macro from the [axum-macros] crate.
//!
//! [axum-debug]: https://docs.rs/axum-debug
//! [axum-macros]: https://docs.rs/axum-macros
use crate::{
body::{boxed, Body, Bytes, HttpBody},

View file

@ -406,8 +406,8 @@
//! [`HeaderMap`]: http::header::HeaderMap
//! [`Request`]: http::Request
//! [customize-extractor-error]: https://github.com/tokio-rs/axum/blob/main/examples/customize-extractor-error/src/main.rs
//! [axum-debug]: https://docs.rs/axum-debug
//! [`debug_handler`]: https://docs.rs/axum-debug/latest/axum_debug/attr.debug_handler.html
//! [axum-macros]: https://docs.rs/axum-macros
//! [`debug_handler`]: https://docs.rs/axum-macros/latest/axum_macros/attr.debug_handler.html
//! [`Handler`]: crate::handler::Handler
//! [`Infallible`]: std::convert::Infallible
//! [load shed]: tower::load_shed