mirror of https://github.com/rwf2/Rocket.git
Allow custom generic bounds in 'Responder' derive.
This commit is contained in:
parent
02d6c4c6f1
commit
41d7138540
|
@ -14,7 +14,7 @@ proc-macro = true
|
|||
|
||||
[dependencies]
|
||||
quote = "1.0"
|
||||
devise = { git = "https://github.com/SergioBenitez/Devise.git", rev = "df00b5" }
|
||||
devise = { git = "https://github.com/SergioBenitez/Devise.git", rev = "f2431b" }
|
||||
|
||||
[dev-dependencies]
|
||||
version_check = "0.9"
|
||||
|
|
|
@ -19,12 +19,12 @@ indexmap = "1.0"
|
|||
quote = "1.0"
|
||||
syn = { version = "1.0.72", features = ["full", "visit", "visit-mut", "extra-traits"] }
|
||||
proc-macro2 = "1.0.27"
|
||||
devise = { git = "https://github.com/SergioBenitez/Devise.git", rev = "df00b5" }
|
||||
devise = { git = "https://github.com/SergioBenitez/Devise.git", rev = "f2431b" }
|
||||
rocket_http = { version = "0.5.0-dev", path = "../http/" }
|
||||
unicode-xid = "0.2"
|
||||
glob = "0.3"
|
||||
|
||||
[dev-dependencies]
|
||||
rocket = { version = "0.5.0-dev", path = "../lib" }
|
||||
rocket = { version = "0.5.0-dev", path = "../lib", features = ["json"] }
|
||||
version_check = "0.9"
|
||||
trybuild = "1.0"
|
||||
|
|
|
@ -47,8 +47,8 @@ fn context_type(input: Input<'_>) -> (TokenStream, Option<syn::WhereClause>) {
|
|||
}
|
||||
|
||||
let span = input.ident().span();
|
||||
gen.add_type_bound(&syn::parse_quote!(#_form::FromForm<#lifetime>));
|
||||
gen.add_type_bound(&syn::TypeParamBound::from(lifetime));
|
||||
gen.add_type_bound(syn::parse_quote!(#_form::FromForm<#lifetime>));
|
||||
gen.add_type_bound(syn::TypeParamBound::from(lifetime));
|
||||
let (_, ty_gen, where_clause) = gen.split_for_impl();
|
||||
(quote_spanned!(span => FromFormGeneratedContext #ty_gen), where_clause.cloned())
|
||||
}
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
use quote::ToTokens;
|
||||
use devise::{*, ext::{TypeExt, SpanDiagnosticExt}};
|
||||
use devise::{*, ext::{TypeExt, SpanDiagnosticExt, GenericsExt}};
|
||||
use proc_macro2::TokenStream;
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::parse::Parser;
|
||||
|
||||
use crate::exports::*;
|
||||
use crate::http_codegen::{ContentType, Status};
|
||||
|
||||
type WherePredicates = Punctuated<syn::WherePredicate, syn::Token![,]>;
|
||||
|
||||
#[derive(Debug, Default, FromMeta)]
|
||||
struct ItemAttr {
|
||||
bound: Option<SpanWrapped<String>>,
|
||||
content_type: Option<SpanWrapped<ContentType>>,
|
||||
status: Option<SpanWrapped<Status>>,
|
||||
}
|
||||
|
@ -17,20 +22,32 @@ struct FieldAttr {
|
|||
}
|
||||
|
||||
pub fn derive_responder(input: proc_macro::TokenStream) -> TokenStream {
|
||||
let impl_tokens = quote!(impl<'__r, '__o: '__r> ::rocket::response::Responder<'__r, '__o>);
|
||||
let impl_tokens = quote!(impl<'r, 'o: 'r> ::rocket::response::Responder<'r, 'o>);
|
||||
DeriveGenerator::build_for(input, impl_tokens)
|
||||
.support(Support::Struct | Support::Enum | Support::Lifetime | Support::Type)
|
||||
.replace_generic(1, 0)
|
||||
.type_bound(quote!(::rocket::response::Responder<'__r, '__o>))
|
||||
.type_bound_mapper(MapperBuild::new()
|
||||
.try_input_map(|_, input| {
|
||||
ItemAttr::one_from_attrs("response", input.attrs())?
|
||||
.and_then(|attr| attr.bound)
|
||||
.map(|bound| {
|
||||
let span = bound.span;
|
||||
let bounds = WherePredicates::parse_terminated.parse_str(&bound)
|
||||
.map_err(|e| span.error(format!("invalid bound syntax: {}", e)))?;
|
||||
Ok(quote_respanned!(span => #bounds))
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
let bound = quote!(::rocket::response::Responder<'r, 'o>);
|
||||
let preds = input.generics().parsed_bounded_types(bound)?;
|
||||
Ok(quote!(#preds))
|
||||
})
|
||||
})
|
||||
)
|
||||
.validator(ValidatorBuild::new()
|
||||
.input_validate(|_, i| match i.generics().lifetimes().count() > 1 {
|
||||
true => Err(i.generics().span().error("only one lifetime is supported")),
|
||||
false => Ok(())
|
||||
})
|
||||
.input_validate(|_, i| match i.generics().type_params().count() > 1 {
|
||||
true => Err(i.generics().span().error("only one type generic is supported")),
|
||||
false => Ok(())
|
||||
})
|
||||
.fields_validate(|_, fields| match fields.is_empty() {
|
||||
true => return Err(fields.span().error("need at least one field")),
|
||||
false => Ok(())
|
||||
|
@ -38,7 +55,7 @@ pub fn derive_responder(input: proc_macro::TokenStream) -> TokenStream {
|
|||
)
|
||||
.inner_mapper(MapperBuild::new()
|
||||
.with_output(|_, output| quote! {
|
||||
fn respond_to(self, __req: &'__r #Request<'_>) -> #_response::Result<'__o> {
|
||||
fn respond_to(self, __req: &'r #Request<'_>) -> #_response::Result<'o> {
|
||||
#output
|
||||
}
|
||||
})
|
||||
|
|
|
@ -758,29 +758,52 @@ pub fn derive_from_form(input: TokenStream) -> TokenStream {
|
|||
///
|
||||
/// # Generics
|
||||
///
|
||||
/// The derive accepts at most one type generic and at most one lifetime
|
||||
/// The derive accepts any number of type generics and at most one lifetime
|
||||
/// generic. If a type generic is present, the generated implementation will
|
||||
/// require a bound of `Responder` for the generic. As such, the generic should
|
||||
/// be used as a `Responder`:
|
||||
/// require a bound of `Responder<'r, 'o>` for each generic unless a
|
||||
/// `#[response(bound = ...)]` attribute as used:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[macro_use] extern crate rocket;
|
||||
/// use rocket::serde::Serialize;
|
||||
/// use rocket::serde::json::Json;
|
||||
/// use rocket::http::ContentType;
|
||||
/// use rocket::response::Responder;
|
||||
///
|
||||
/// // The bound `T: Responder` will be added to the generated implementation.
|
||||
/// #[derive(Responder)]
|
||||
/// #[response(status = 404, content_type = "html")]
|
||||
/// struct NotFoundHtml<T>(T);
|
||||
///
|
||||
/// // The bound `T: Serialize` will be added to the generated implementation.
|
||||
/// // This would fail to compile otherwise.
|
||||
/// #[derive(Responder)]
|
||||
/// #[response(bound = "T: Serialize", status = 404)]
|
||||
/// struct NotFoundJson<T>(Json<T>);
|
||||
///
|
||||
/// // The bounds `T: Serialize, E: Responder` will be added to the generated
|
||||
/// // implementation. This would fail to compile otherwise.
|
||||
/// #[derive(Responder)]
|
||||
/// #[response(bound = "T: Serialize, E: Responder<'r, 'o>")]
|
||||
/// enum MyResult<T, E> {
|
||||
/// Ok(Json<T>),
|
||||
/// #[response(status = 404)]
|
||||
/// Err(E, ContentType)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// If a lifetime generic is present, it will be used as the second lifetime
|
||||
/// paramter `'o` parameter in `impl Responder<'r, 'o>`:
|
||||
/// If a lifetime generic is present, it will be replace with `'o` in the
|
||||
/// generated implementation `impl Responder<'r, 'o>`:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[macro_use] extern crate rocket;
|
||||
/// // Generates `impl<'r, 'o> Responder<'r, 'o> for NotFoundHtmlString<'o>`.
|
||||
/// #[derive(Responder)]
|
||||
/// #[response(status = 404, content_type = "html")]
|
||||
/// struct NotFoundHtmlString<'o>(&'o str);
|
||||
/// struct NotFoundHtmlString<'a>(&'a str);
|
||||
/// ```
|
||||
///
|
||||
/// Both a type generic and lifetime generic may be used:
|
||||
/// Both type generics and lifetime generic may be used:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[macro_use] extern crate rocket;
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
// Rocket sometimes generates mangled identifiers that activate the
|
||||
// non_snake_case lint. We deny the lint in this test to ensure that
|
||||
// code generation uses #[allow(non_snake_case)] in the appropriate places.
|
||||
#![deny(non_snake_case)]
|
||||
|
||||
#[macro_use] extern crate rocket;
|
||||
|
||||
use rocket::{Request, Rocket, Build};
|
||||
use rocket::local::blocking::Client;
|
||||
use rocket::http::{Status, ContentType};
|
||||
|
||||
#[catch(404)] fn not_found_0() -> &'static str { "404-0" }
|
||||
#[catch(404)] fn not_found_1(_: &Request) -> &'static str { "404-1" }
|
||||
#[catch(404)] fn not_found_2(_: Status, _: &Request) -> &'static str { "404-2" }
|
||||
#[catch(default)] fn all(_: Status, r: &Request) -> String { r.uri().to_string() }
|
||||
|
||||
#[test]
|
||||
fn test_simple_catchers() {
|
||||
fn rocket() -> Rocket<Build> {
|
||||
rocket::build()
|
||||
.register("/0", catchers![not_found_0])
|
||||
.register("/1", catchers![not_found_1])
|
||||
.register("/2", catchers![not_found_2])
|
||||
.register("/", catchers![all])
|
||||
}
|
||||
|
||||
let client = Client::debug(rocket()).unwrap();
|
||||
for i in 0..6 {
|
||||
let response = client.get(format!("/{}", i)).dispatch();
|
||||
assert_eq!(response.status(), Status::NotFound);
|
||||
|
||||
match i {
|
||||
0..=2 => assert_eq!(response.into_string().unwrap(), format!("404-{}", i)),
|
||||
_ => assert_eq!(response.into_string().unwrap(), format!("/{}", i)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/<code>")] fn forward(code: u16) -> Status { Status::new(code) }
|
||||
#[catch(400)] fn forward_400(status: Status, _: &Request) -> String { status.code.to_string() }
|
||||
#[catch(404)] fn forward_404(status: Status, _: &Request) -> String { status.code.to_string() }
|
||||
#[catch(444)] fn forward_444(status: Status, _: &Request) -> String { status.code.to_string() }
|
||||
#[catch(500)] fn forward_500(status: Status, _: &Request) -> String { status.code.to_string() }
|
||||
|
||||
#[test]
|
||||
fn test_status_param() {
|
||||
fn rocket() -> Rocket<Build> {
|
||||
rocket::build()
|
||||
.mount("/", routes![forward])
|
||||
.register("/", catchers![forward_400, forward_404, forward_444, forward_500])
|
||||
}
|
||||
|
||||
let client = Client::debug(rocket()).unwrap();
|
||||
for code in &[400, 404, 444, 400, 800, 3480] {
|
||||
let response = client.get(uri!(forward(*code))).dispatch();
|
||||
let code = std::cmp::min(*code, 500);
|
||||
assert_eq!(response.status(), Status::new(code));
|
||||
assert_eq!(response.into_string().unwrap(), code.to_string());
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
use rocket::local::asynchronous::Client;
|
||||
use rocket::response::Responder;
|
||||
use rocket::http::{Status, ContentType, Cookie};
|
||||
use rocket::response::Responder;
|
||||
|
||||
#[derive(Responder)]
|
||||
pub enum Foo<'r> {
|
||||
|
@ -107,3 +107,42 @@ async fn responder_baz() {
|
|||
assert_eq!(r.content_type(), Some(ContentType::new("application", "x-custom")));
|
||||
assert_eq!(r.body_mut().to_string().await.unwrap(), "just a custom");
|
||||
}
|
||||
|
||||
use rocket::serde::json::Json;
|
||||
|
||||
// The bounds `T: Serialize, E: Responder` will be added to the generated
|
||||
// implementation. This would fail to compile otherwise.
|
||||
#[derive(Responder)]
|
||||
#[response(bound = "T: rocket::serde::Serialize, E: Responder<'r, 'o>")]
|
||||
enum MyResult<'a, T, E> {
|
||||
Ok(Json<T>),
|
||||
#[response(status = 404)]
|
||||
Err(E, ContentType),
|
||||
#[response(status = 500)]
|
||||
Other(&'a str),
|
||||
}
|
||||
|
||||
#[rocket::async_test]
|
||||
async fn generic_responder() {
|
||||
let client = Client::debug_with(vec![]).await.expect("valid rocket");
|
||||
let local_req = client.get("/");
|
||||
let req = local_req.inner();
|
||||
|
||||
let v: MyResult<_, ()> = MyResult::Ok(Json("hi"));
|
||||
let mut r = v.respond_to(req).unwrap();
|
||||
assert_eq!(r.status(), Status::Ok);
|
||||
assert_eq!(r.content_type().unwrap(), ContentType::JSON);
|
||||
assert_eq!(r.body_mut().to_string().await.unwrap(), "\"hi\"");
|
||||
|
||||
let v: MyResult<(), &[u8]> = MyResult::Err(&[7, 13, 23], ContentType::JPEG);
|
||||
let mut r = v.respond_to(req).unwrap();
|
||||
assert_eq!(r.status(), Status::NotFound);
|
||||
assert_eq!(r.content_type().unwrap(), ContentType::JPEG);
|
||||
assert_eq!(r.body_mut().to_bytes().await.unwrap(), vec![7, 13, 23]);
|
||||
|
||||
let v: MyResult<(), &[u8]> = MyResult::Other("beep beep");
|
||||
let mut r = v.respond_to(req).unwrap();
|
||||
assert_eq!(r.status(), Status::InternalServerError);
|
||||
assert_eq!(r.content_type().unwrap(), ContentType::Text);
|
||||
assert_eq!(r.body_mut().to_string().await.unwrap(), "beep beep");
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
../ui-fail/responder.rs
|
|
@ -1,158 +1,217 @@
|
|||
error: need at least one field
|
||||
--> $DIR/responder.rs:6:1
|
||||
--> $DIR/responder.rs:4:1
|
||||
|
|
||||
6 | struct Thing1;
|
||||
4 | struct Thing1;
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
note: error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:5:10
|
||||
--> $DIR/responder.rs:3:10
|
||||
|
|
||||
5 | #[derive(Responder)]
|
||||
3 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
= note: this error originates in the derive macro `Responder` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: need at least one field
|
||||
--> $DIR/responder.rs:10:14
|
||||
|
|
||||
10 | struct Thing2();
|
||||
| ^^
|
||||
|
|
||||
--> $DIR/responder.rs:7:14
|
||||
|
|
||||
7 | struct Thing2();
|
||||
| ^^
|
||||
|
|
||||
note: error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:9:10
|
||||
|
|
||||
9 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
--> $DIR/responder.rs:6:10
|
||||
|
|
||||
6 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
= note: this error originates in the derive macro `Responder` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: need at least one field
|
||||
--> $DIR/responder.rs:15:5
|
||||
--> $DIR/responder.rs:13:12
|
||||
|
|
||||
15 | Bark,
|
||||
| ^^^^
|
||||
13 | enum Foo { Bark, }
|
||||
| ^^^^
|
||||
|
|
||||
note: error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:13:10
|
||||
--> $DIR/responder.rs:12:10
|
||||
|
|
||||
13 | #[derive(Responder)]
|
||||
12 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
= note: this error originates in the derive macro `Responder` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: only one lifetime is supported
|
||||
--> $DIR/responder.rs:20:14
|
||||
--> $DIR/responder.rs:16:14
|
||||
|
|
||||
20 | struct Thing4<'a, 'b>(&'a str, &'b str);
|
||||
16 | struct Thing4<'a, 'b>(&'a str, &'b str);
|
||||
| ^^^^^^^^
|
||||
|
|
||||
note: error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:19:10
|
||||
--> $DIR/responder.rs:15:10
|
||||
|
|
||||
19 | #[derive(Responder)]
|
||||
15 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
= note: this error originates in the derive macro `Responder` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: type generics are not supported
|
||||
--> $DIR/responder.rs:24:15
|
||||
error: invalid or unknown content type
|
||||
--> $DIR/responder.rs:25:27
|
||||
|
|
||||
24 | struct Thing5<T>(T);
|
||||
| ^
|
||||
25 | #[response(content_type = "")]
|
||||
| ^^
|
||||
|
|
||||
note: error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:23:10
|
||||
--> $DIR/responder.rs:24:10
|
||||
|
|
||||
23 | #[derive(Responder)]
|
||||
24 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
= note: this error originates in the derive macro `Responder` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: type generics are not supported
|
||||
--> $DIR/responder.rs:28:23
|
||||
error: invalid or unknown content type
|
||||
--> $DIR/responder.rs:29:27
|
||||
|
|
||||
28 | struct Thing6<'a, 'b, T>(&'a str, &'b str, T);
|
||||
| ^
|
||||
29 | #[response(content_type = "idk")]
|
||||
| ^^^^^
|
||||
|
|
||||
note: error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:27:10
|
||||
--> $DIR/responder.rs:28:10
|
||||
|
|
||||
27 | #[derive(Responder)]
|
||||
28 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
= note: this error originates in the derive macro `Responder` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: invalid or unknown content-type
|
||||
--> $DIR/responder.rs:33:31
|
||||
error: invalid value: expected string literal
|
||||
--> $DIR/responder.rs:33:27
|
||||
|
|
||||
33 | #[response(content_type = "")]
|
||||
| ^^
|
||||
33 | #[response(content_type = 100)]
|
||||
| ^^^
|
||||
|
|
||||
note: error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:31:10
|
||||
--> $DIR/responder.rs:32:10
|
||||
|
|
||||
31 | #[derive(Responder)]
|
||||
32 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
= note: this error originates in the derive macro `Responder` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: invalid or unknown content-type
|
||||
--> $DIR/responder.rs:40:31
|
||||
error: status must be in range [100, 599]
|
||||
--> $DIR/responder.rs:37:21
|
||||
|
|
||||
40 | #[response(content_type = "idk")]
|
||||
| ^^^^^
|
||||
37 | #[response(status = 8)]
|
||||
| ^
|
||||
|
|
||||
note: error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:38:10
|
||||
--> $DIR/responder.rs:36:10
|
||||
|
|
||||
38 | #[derive(Responder)]
|
||||
36 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
= note: this error originates in the derive macro `Responder` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: invalid value: expected string
|
||||
--> $DIR/responder.rs:47:31
|
||||
error: invalid value: expected unsigned integer literal
|
||||
--> $DIR/responder.rs:41:21
|
||||
|
|
||||
47 | #[response(content_type = 100)]
|
||||
| ^^^
|
||||
41 | #[response(status = "404")]
|
||||
| ^^^^^
|
||||
|
|
||||
note: error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:45:10
|
||||
--> $DIR/responder.rs:40:10
|
||||
|
|
||||
45 | #[derive(Responder)]
|
||||
40 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
= note: this error originates in the derive macro `Responder` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: status must be in range [100, 600)
|
||||
--> $DIR/responder.rs:54:25
|
||||
error: invalid value: expected unsigned integer literal
|
||||
--> $DIR/responder.rs:45:21
|
||||
|
|
||||
54 | #[response(status = 8)]
|
||||
| ^
|
||||
45 | #[response(status = "404", content_type = "html")]
|
||||
| ^^^^^
|
||||
|
|
||||
note: error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:44:10
|
||||
|
|
||||
44 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
= note: this error originates in the derive macro `Responder` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: invalid value: expected string literal
|
||||
--> $DIR/responder.rs:49:41
|
||||
|
|
||||
49 | #[response(status = 404, content_type = 120)]
|
||||
| ^^^
|
||||
|
|
||||
note: error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:48:10
|
||||
|
|
||||
48 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
= note: this error originates in the derive macro `Responder` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: invalid value: expected string literal
|
||||
--> $DIR/responder.rs:53:20
|
||||
|
|
||||
53 | #[response(bound = 10)]
|
||||
| ^^
|
||||
|
|
||||
note: error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:52:10
|
||||
|
|
||||
52 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
= note: this error originates in the derive macro `Responder` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: invalid value: expected unsigned integer
|
||||
--> $DIR/responder.rs:61:25
|
||||
error: invalid bound syntax: expected `:`
|
||||
--> $DIR/responder.rs:65:20
|
||||
|
|
||||
61 | #[response(status = "404")]
|
||||
| ^^^^^
|
||||
65 | #[response(bound = "ponies are cool")]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:59:10
|
||||
--> $DIR/responder.rs:64:10
|
||||
|
|
||||
59 | #[derive(Responder)]
|
||||
64 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
= note: this error originates in the derive macro `Responder` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: invalid value: expected unsigned integer
|
||||
--> $DIR/responder.rs:68:25
|
||||
error: invalid bound syntax: expected `,`
|
||||
--> $DIR/responder.rs:69:20
|
||||
|
|
||||
68 | #[response(status = "404", content_type = "html")]
|
||||
| ^^^^^
|
||||
69 | #[response(bound = "T: ROCKETS + ARE COOLER")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:66:10
|
||||
--> $DIR/responder.rs:68:10
|
||||
|
|
||||
66 | #[derive(Responder)]
|
||||
68 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
= note: this error originates in the derive macro `Responder` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: invalid value: expected string
|
||||
--> $DIR/responder.rs:75:45
|
||||
error[E0277]: the trait bound `Header<'_>: From<E>` is not satisfied
|
||||
--> $DIR/responder.rs:22:24
|
||||
|
|
||||
75 | #[response(status = 404, content_type = 120)]
|
||||
| ^^^
|
||||
22 | struct Thing6<T, E>(T, E); // NO ERROR
|
||||
| ^ the trait `From<E>` is not implemented for `Header<'_>`
|
||||
|
|
||||
note: error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:73:10
|
||||
= note: required because of the requirements on the impl of `Into<Header<'_>>` for `E`
|
||||
help: consider extending the `where` bound, but there might be an alternative better way to express this requirement
|
||||
|
|
||||
73 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
21 | #[derive(Responder, Header<'_>: From<E>)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 13 previous errors
|
||||
error[E0277]: the trait bound `T: Responder<'_, '_>` is not satisfied
|
||||
--> $DIR/responder.rs:58:19
|
||||
|
|
||||
58 | struct Thing15<T>(T);
|
||||
| ^ the trait `Responder<'_, '_>` is not implemented for `T`
|
||||
|
|
||||
= note: required by `respond_to`
|
||||
help: consider further restricting this bound
|
||||
|
|
||||
57 | #[response(bound = "T: std::fmt::Display" + rocket::response::Responder<'_, '_>)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0277]: the trait bound `T: Responder<'_, '_>` is not satisfied
|
||||
--> $DIR/responder.rs:62:19
|
||||
|
|
||||
62 | struct Thing16<T>(T);
|
||||
| ^ the trait `Responder<'_, '_>` is not implemented for `T`
|
||||
|
|
||||
= note: required by `respond_to`
|
||||
help: consider further restricting this bound
|
||||
|
|
||||
61 | #[response(bound = "T: std::fmt::Display" + rocket::response::Responder<'_, '_>)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
../ui-fail/responder.rs
|
|
@ -0,0 +1,231 @@
|
|||
error: need at least one field
|
||||
--> $DIR/responder.rs:4:1
|
||||
|
|
||||
4 | struct Thing1;
|
||||
| ^^^^^^
|
||||
|
||||
error: [note] error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:3:10
|
||||
|
|
||||
3 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: need at least one field
|
||||
--> $DIR/responder.rs:7:14
|
||||
|
|
||||
7 | struct Thing2();
|
||||
| ^^
|
||||
|
||||
error: [note] error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:6:10
|
||||
|
|
||||
6 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: need at least one field
|
||||
--> $DIR/responder.rs:13:12
|
||||
|
|
||||
13 | enum Foo { Bark, }
|
||||
| ^^^^
|
||||
|
||||
error: [note] error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:12:10
|
||||
|
|
||||
12 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: only one lifetime is supported
|
||||
--> $DIR/responder.rs:16:14
|
||||
|
|
||||
16 | struct Thing4<'a, 'b>(&'a str, &'b str);
|
||||
| ^
|
||||
|
||||
error: [note] error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:15:10
|
||||
|
|
||||
15 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: invalid or unknown content type
|
||||
--> $DIR/responder.rs:25:27
|
||||
|
|
||||
25 | #[response(content_type = "")]
|
||||
| ^^
|
||||
|
||||
error: [note] error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:24:10
|
||||
|
|
||||
24 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: invalid or unknown content type
|
||||
--> $DIR/responder.rs:29:27
|
||||
|
|
||||
29 | #[response(content_type = "idk")]
|
||||
| ^^^^^
|
||||
|
||||
error: [note] error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:28:10
|
||||
|
|
||||
28 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: invalid value: expected string literal
|
||||
--> $DIR/responder.rs:33:27
|
||||
|
|
||||
33 | #[response(content_type = 100)]
|
||||
| ^^^
|
||||
|
||||
error: [note] error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:32:10
|
||||
|
|
||||
32 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: status must be in range [100, 599]
|
||||
--> $DIR/responder.rs:37:21
|
||||
|
|
||||
37 | #[response(status = 8)]
|
||||
| ^
|
||||
|
||||
error: [note] error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:36:10
|
||||
|
|
||||
36 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: invalid value: expected unsigned integer literal
|
||||
--> $DIR/responder.rs:41:21
|
||||
|
|
||||
41 | #[response(status = "404")]
|
||||
| ^^^^^
|
||||
|
||||
error: [note] error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:40:10
|
||||
|
|
||||
40 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: invalid value: expected unsigned integer literal
|
||||
--> $DIR/responder.rs:45:21
|
||||
|
|
||||
45 | #[response(status = "404", content_type = "html")]
|
||||
| ^^^^^
|
||||
|
||||
error: [note] error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:44:10
|
||||
|
|
||||
44 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: invalid value: expected string literal
|
||||
--> $DIR/responder.rs:49:41
|
||||
|
|
||||
49 | #[response(status = 404, content_type = 120)]
|
||||
| ^^^
|
||||
|
||||
error: [note] error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:48:10
|
||||
|
|
||||
48 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: invalid value: expected string literal
|
||||
--> $DIR/responder.rs:53:20
|
||||
|
|
||||
53 | #[response(bound = 10)]
|
||||
| ^^
|
||||
|
||||
error: [note] error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:52:10
|
||||
|
|
||||
52 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: invalid bound syntax: expected `:`
|
||||
--> $DIR/responder.rs:65:20
|
||||
|
|
||||
65 | #[response(bound = "ponies are cool")]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: [note] error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:64:10
|
||||
|
|
||||
64 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: invalid bound syntax: expected `,`
|
||||
--> $DIR/responder.rs:69:20
|
||||
|
|
||||
69 | #[response(bound = "T: ROCKETS + ARE COOLER")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: [note] error occurred while deriving `Responder`
|
||||
--> $DIR/responder.rs:68:10
|
||||
|
|
||||
68 | #[derive(Responder)]
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0277]: the trait bound `Header<'_>: From<E>` is not satisfied
|
||||
--> $DIR/responder.rs:22:24
|
||||
|
|
||||
22 | struct Thing6<T, E>(T, E); // NO ERROR
|
||||
| ^ the trait `From<E>` is not implemented for `Header<'_>`
|
||||
|
|
||||
= note: required because of the requirements on the impl of `Into<Header<'_>>` for `E`
|
||||
help: consider extending the `where` bound, but there might be an alternative better way to express this requirement
|
||||
|
|
||||
21 | #[derive(Responder, Header<'_>: From<E>)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0277]: the trait bound `T: Responder<'_, '_>` is not satisfied
|
||||
--> $DIR/responder.rs:58:19
|
||||
|
|
||||
58 | struct Thing15<T>(T);
|
||||
| ^ the trait `Responder<'_, '_>` is not implemented for `T`
|
||||
|
|
||||
= note: required by `respond_to`
|
||||
help: consider further restricting this bound
|
||||
|
|
||||
57 | #[response(bound = "T: std::fmt::Display" + Responder<'_, '_>)]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0277]: the trait bound `T: Responder<'_, '_>` is not satisfied
|
||||
--> $DIR/responder.rs:62:19
|
||||
|
|
||||
62 | struct Thing16<T>(T);
|
||||
| ^ the trait `Responder<'_, '_>` is not implemented for `T`
|
||||
|
|
||||
= note: required by `respond_to`
|
||||
help: consider further restricting this bound
|
||||
|
|
||||
61 | #[response(bound = "T: std::fmt::Display" + Responder<'_, '_>)]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
|
@ -0,0 +1,72 @@
|
|||
#[macro_use] extern crate rocket;
|
||||
|
||||
#[derive(Responder)]
|
||||
struct Thing1;
|
||||
|
||||
#[derive(Responder)]
|
||||
struct Thing2();
|
||||
|
||||
#[derive(Responder)]
|
||||
enum Bar { } // NO ERROR
|
||||
|
||||
#[derive(Responder)]
|
||||
enum Foo { Bark, }
|
||||
|
||||
#[derive(Responder)]
|
||||
struct Thing4<'a, 'b>(&'a str, &'b str);
|
||||
|
||||
#[derive(Responder)]
|
||||
struct Thing5<T>(T); // NO ERROR
|
||||
|
||||
#[derive(Responder)]
|
||||
struct Thing6<T, E>(T, E); // NO ERROR
|
||||
|
||||
#[derive(Responder)]
|
||||
#[response(content_type = "")]
|
||||
struct Thing7(());
|
||||
|
||||
#[derive(Responder)]
|
||||
#[response(content_type = "idk")]
|
||||
struct Thing8(());
|
||||
|
||||
#[derive(Responder)]
|
||||
#[response(content_type = 100)]
|
||||
struct Thing9(());
|
||||
|
||||
#[derive(Responder)]
|
||||
#[response(status = 8)]
|
||||
struct Thing10(());
|
||||
|
||||
#[derive(Responder)]
|
||||
#[response(status = "404")]
|
||||
struct Thing11(());
|
||||
|
||||
#[derive(Responder)]
|
||||
#[response(status = "404", content_type = "html")]
|
||||
struct Thing12(());
|
||||
|
||||
#[derive(Responder)]
|
||||
#[response(status = 404, content_type = 120)]
|
||||
struct Thing13(());
|
||||
|
||||
#[derive(Responder)]
|
||||
#[response(bound = 10)]
|
||||
struct Thing14(());
|
||||
|
||||
#[derive(Responder)]
|
||||
#[response(bound = "T: std::fmt::Display")]
|
||||
struct Thing15<T>(T);
|
||||
|
||||
#[derive(Responder)]
|
||||
#[response(bound = "T: std::fmt::Display")]
|
||||
struct Thing16<T>(T);
|
||||
|
||||
#[derive(Responder)]
|
||||
#[response(bound = "ponies are cool")]
|
||||
struct Thing17<T>(T);
|
||||
|
||||
#[derive(Responder)]
|
||||
#[response(bound = "T: ROCKETS + ARE COOLER")]
|
||||
struct Thing18<T>(T);
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,24 @@
|
|||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
# Symlinks all of the tests in this directory with those in sibling
|
||||
# `ui-fail-stable` and `ui-fail-nightly` directories.
|
||||
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
stable="${SCRIPT_DIR}/../ui-fail-stable"
|
||||
nightly="${SCRIPT_DIR}/../ui-fail-nightly"
|
||||
anchor="$(basename ${SCRIPT_DIR})"
|
||||
|
||||
echo ":: Synchronizing..."
|
||||
echo " stable: ${stable}"
|
||||
echo " nightly: ${nightly}"
|
||||
echo " anchor: ${anchor}"
|
||||
|
||||
for dir in "${stable}" "${nightly}"; do
|
||||
find "${dir}" -type l -delete
|
||||
|
||||
for file in "${SCRIPT_DIR}"/*.rs; do
|
||||
ln -s "../${anchor}/$(basename $file)" "${dir}/"
|
||||
done
|
||||
done
|
|
@ -160,6 +160,7 @@ impl<'r, T: Deserialize<'r>> MsgPack<T> {
|
|||
Self::from_bytes(local_cache!(req, bytes))
|
||||
}
|
||||
}
|
||||
|
||||
#[crate::async_trait]
|
||||
impl<'r, T: Deserialize<'r>> FromData<'r> for MsgPack<T> {
|
||||
type Error = Error;
|
||||
|
|
Loading…
Reference in New Issue