Skip to content

Commit ac3a7fa

Browse files
committed
Ensure examples pass CI
1 parent 4cb3a3a commit ac3a7fa

File tree

5 files changed

+83
-26
lines changed

5 files changed

+83
-26
lines changed

core/codegen/src/attribute/catch/mod.rs

+12-5
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,21 @@ use crate::http_codegen::Optional;
88
use crate::syn_ext::ReturnTypeExt;
99
use crate::exports::*;
1010

11-
fn arg_ty(arg: &syn::FnArg) -> Result<&syn::Type> {
11+
fn error_arg_ty(arg: &syn::FnArg) -> Result<&syn::Type> {
1212
match arg {
1313
syn::FnArg::Receiver(_) => Err(Diagnostic::spanned(
1414
arg.span(),
1515
Level::Error,
16-
"Catcher cannot have self as a parameter"
16+
"Catcher cannot have self as a parameter",
1717
)),
18-
syn::FnArg::Typed(syn::PatType {ty, ..})=> Ok(ty.as_ref()),
18+
syn::FnArg::Typed(syn::PatType { ty, .. }) => match ty.as_ref() {
19+
syn::Type::Reference(syn::TypeReference { elem, .. }) => Ok(elem.as_ref()),
20+
_ => Err(Diagnostic::spanned(
21+
ty.span(),
22+
Level::Error,
23+
"Error type must be a reference",
24+
)),
25+
},
1926
}
2027
}
2128

@@ -58,9 +65,9 @@ pub fn _catch(
5865
}).rev();
5966
let (make_error, error_type) = if catch.function.sig.inputs.len() >= 3 {
6067
let arg = catch.function.sig.inputs.first().unwrap();
61-
let ty = arg_ty(arg)?;
68+
let ty = error_arg_ty(arg)?;
6269
(quote_spanned!(arg.span() =>
63-
let #__error = match ::rocket::catcher::downcast(__error_init.as_ref()) {
70+
let #__error: &#ty = match ::rocket::catcher::downcast(__error_init.as_ref()) {
6471
Some(v) => v,
6572
None => return #_Result::Err((#__status, __error_init)),
6673
};

core/lib/src/outcome.rs

+33-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,9 @@
8686
//! a type of `Option<S>`. If an `Outcome` is a `Forward`, the `Option` will be
8787
//! `None`.
8888
89-
use crate::catcher::default_error_type;
89+
use transient::{CanTranscendTo, Co, Transient};
90+
91+
use crate::catcher::{default_error_type, ErasedError};
9092
use crate::{route, request, response};
9193
use crate::data::{self, Data, FromData};
9294
use crate::http::Status;
@@ -809,3 +811,33 @@ impl<'r, 'o: 'r> IntoOutcome<route::Outcome<'r>> for response::Result<'o> {
809811
}
810812
}
811813
}
814+
815+
type RoutedOutcome<'r, T> = Outcome<
816+
T,
817+
(Status, ErasedError<'r>),
818+
(Data<'r>, Status, ErasedError<'r>)
819+
>;
820+
821+
impl<'r, T, E: Transient> IntoOutcome<RoutedOutcome<'r, T>> for Option<Result<T, E>>
822+
where E::Transience: CanTranscendTo<Co<'r>>,
823+
E: Send + Sync + 'r,
824+
{
825+
type Error = Status;
826+
type Forward = (Data<'r>, Status);
827+
828+
fn or_error(self, error: Self::Error) -> RoutedOutcome<'r, T> {
829+
match self {
830+
Some(Ok(v)) => Outcome::Success(v),
831+
Some(Err(e)) => Outcome::Error((error, Box::new(e))),
832+
None => Outcome::Error((error, default_error_type())),
833+
}
834+
}
835+
836+
fn or_forward(self, forward: Self::Forward) -> RoutedOutcome<'r, T> {
837+
match self {
838+
Some(Ok(v)) => Outcome::Success(v),
839+
Some(Err(e)) => Outcome::Forward((forward.0, forward.1, Box::new(e))),
840+
None => Outcome::Forward((forward.0, forward.1, default_error_type())),
841+
}
842+
}
843+
}

examples/error-handling/src/main.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
use rocket::{Rocket, Request, Build};
66
use rocket::response::{content, status};
7-
use rocket::http::{Status, uri::error::PathError};
7+
use rocket::http::Status;
88

99
// Custom impl so I can implement Static (or Transient) ---
1010
// We should upstream implementations for most common error types
@@ -13,6 +13,7 @@ use rocket::catcher::{Static};
1313
use std::num::ParseIntError;
1414

1515
#[derive(Debug)]
16+
#[allow(unused)]
1617
struct IntErr(ParseIntError);
1718
impl Static for IntErr {}
1819

@@ -45,7 +46,7 @@ fn general_not_found() -> content::RawHtml<&'static str> {
4546
}
4647

4748
#[catch(404)]
48-
fn hello_not_found(s: Status, req: &Request<'_>) -> content::RawHtml<String> {
49+
fn hello_not_found(req: &Request<'_>) -> content::RawHtml<String> {
4950
content::RawHtml(format!("\
5051
<p>Sorry, but '{}' is not a valid path!</p>\
5152
<p>Try visiting /hello/&lt;name&gt;/&lt;age&gt; instead.</p>",
@@ -57,7 +58,7 @@ fn hello_not_found(s: Status, req: &Request<'_>) -> content::RawHtml<String> {
5758
// be present. I'm thinking about adding a param to the macro to indicate which (and whether)
5859
// param is a downcast error.
5960
#[catch(422)]
60-
fn param_error(e: &IntErr, s: Status, req: &Request<'_>) -> content::RawHtml<String> {
61+
fn param_error(e: &IntErr, _s: Status, req: &Request<'_>) -> content::RawHtml<String> {
6162
content::RawHtml(format!("\
6263
<p>Sorry, but '{}' is not a valid path!</p>\
6364
<p>Try visiting /hello/&lt;name&gt;/&lt;age&gt; instead.</p>\

examples/error-handling/src/tests.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use rocket::local::blocking::Client;
22
use rocket::http::Status;
3+
use super::{I8, IntErr};
34

45
#[test]
56
fn test_hello() {
@@ -10,7 +11,7 @@ fn test_hello() {
1011
let response = client.get(uri).dispatch();
1112

1213
assert_eq!(response.status(), Status::Ok);
13-
assert_eq!(response.into_string().unwrap(), super::hello(name, age));
14+
assert_eq!(response.into_string().unwrap(), super::hello(name, I8(age)));
1415
}
1516

1617
#[test]
@@ -48,10 +49,14 @@ fn test_hello_invalid_age() {
4849

4950
for path in &["Ford/-129", "Trillian/128"] {
5051
let request = client.get(format!("/hello/{}", path));
51-
let expected = super::default_catcher(Status::UnprocessableEntity, request.inner());
52+
let expected = super::param_error(
53+
&IntErr(path.split_once("/").unwrap().1.parse::<i8>().unwrap_err()),
54+
Status::UnprocessableEntity,
55+
request.inner()
56+
);
5257
let response = request.dispatch();
5358
assert_eq!(response.status(), Status::UnprocessableEntity);
54-
assert_eq!(response.into_string().unwrap(), expected.1);
59+
assert_eq!(response.into_string().unwrap(), expected.0);
5560
}
5661

5762
{

examples/manual-routing/src/main.rs

+26-14
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
#[cfg(test)]
22
mod tests;
33

4-
use rocket::{Request, Route, Catcher, route, catcher};
4+
use rocket::{Request, Route, Catcher, route, catcher, outcome::Outcome};
55
use rocket::data::{Data, ToByteUnit};
66
use rocket::http::{Status, Method::{Get, Post}};
77
use rocket::response::{Responder, status::Custom};
8-
use rocket::outcome::{try_outcome, IntoOutcome};
98
use rocket::tokio::fs::File;
109

1110
fn forward<'r>(_req: &'r Request, data: Data<'r>) -> route::BoxFuture<'r> {
@@ -25,12 +24,17 @@ fn name<'r>(req: &'r Request, _: Data<'r>) -> route::BoxFuture<'r> {
2524
}
2625

2726
fn echo_url<'r>(req: &'r Request, _: Data<'r>) -> route::BoxFuture<'r> {
28-
let param_outcome = req.param::<&str>(1)
29-
.and_then(Result::ok)
30-
.or_error(Status::BadRequest);
31-
3227
Box::pin(async move {
33-
route::Outcome::from(req, try_outcome!(param_outcome))
28+
let param_outcome = match req.param::<&str>(1) {
29+
Some(Ok(v)) => v,
30+
Some(Err(e)) => return Outcome::Error((
31+
Status::BadRequest,
32+
Box::new(e) as catcher::ErasedError
33+
)),
34+
None => return Outcome::Error((Status::BadRequest, catcher::default_error_type())),
35+
};
36+
37+
route::Outcome::from(req, param_outcome)
3438
})
3539
}
3640

@@ -62,9 +66,11 @@ fn get_upload<'r>(req: &'r Request, _: Data<'r>) -> route::BoxFuture<'r> {
6266
route::Outcome::from(req, std::fs::File::open(path).ok()).pin()
6367
}
6468

65-
fn not_found_handler<'r>(_: Status, req: &'r Request) -> catcher::BoxFuture<'r> {
69+
fn not_found_handler<'r>(_: Status, req: &'r Request, _e: catcher::ErasedError<'r>)
70+
-> catcher::BoxFuture<'r>
71+
{
6672
let responder = Custom(Status::NotFound, format!("Couldn't find: {}", req.uri()));
67-
Box::pin(async move { responder.respond_to(req) })
73+
Box::pin(async move { responder.respond_to(req).map_err(|s| (s, _e)) })
6874
}
6975

7076
#[derive(Clone)]
@@ -82,11 +88,17 @@ impl CustomHandler {
8288
impl route::Handler for CustomHandler {
8389
async fn handle<'r>(&self, req: &'r Request<'_>, data: Data<'r>) -> route::Outcome<'r> {
8490
let self_data = self.data;
85-
let id = req.param::<&str>(0)
86-
.and_then(Result::ok)
87-
.or_forward((data, Status::NotFound));
88-
89-
route::Outcome::from(req, format!("{} - {}", self_data, try_outcome!(id)))
91+
let id = match req.param::<&str>(1) {
92+
Some(Ok(v)) => v,
93+
Some(Err(e)) => return Outcome::Forward((data, Status::BadRequest, Box::new(e))),
94+
None => return Outcome::Forward((
95+
data,
96+
Status::BadRequest,
97+
catcher::default_error_type()
98+
)),
99+
};
100+
101+
route::Outcome::from(req, format!("{} - {}", self_data, id))
90102
}
91103
}
92104

0 commit comments

Comments
 (0)