rocket_community/outcome.rs
1//! Success, error, and forward handling.
2//!
3//! The `Outcome<S, E, F>` type is similar to the standard library's `Result<S,
4//! E>` type. It is an enum with three variants, each containing a value:
5//! `Success(S)`, which represents a successful outcome, `Error(E)`, which
6//! represents an erroring outcome, and `Forward(F)`, which represents neither a
7//! success or error, but instead, indicates that processing could not be
8//! handled and should instead be _forwarded_ to whatever can handle the
9//! processing next.
10//!
11//! The `Outcome` type is the return type of many of the core Rocket traits,
12//! including [`FromRequest`](crate::request::FromRequest), [`FromData`]
13//! [`Responder`]. It is also the return type of request handlers via the
14//! [`Response`](crate::response::Response) type.
15//!
16//! [`FromData`]: crate::data::FromData
17//! [`Responder`]: crate::response::Responder
18//!
19//! # Success
20//!
21//! A successful `Outcome<S, E, F>`, `Success(S)`, is returned from functions
22//! that complete successfully. The meaning of a `Success` outcome depends on
23//! the context. For instance, the `Outcome` of the `from_data` method of the
24//! [`FromData`] trait will be matched against the type expected by
25//! the user. For example, consider the following handler:
26//!
27//! ```rust
28//! # extern crate rocket_community as rocket;
29//! # use rocket::post;
30//! # type S = String;
31//! #[post("/", data = "<my_val>")]
32//! fn hello(my_val: S) { /* ... */ }
33//! ```
34//!
35//! The [`FromData`] implementation for the type `S` returns an `Outcome` with a
36//! `Success(S)`. If `from_data` returns a `Success`, the `Success` value will
37//! be unwrapped and the value will be used as the value of `my_val`.
38//!
39//! # Error
40//!
41//! An error `Outcome<S, E, F>`, `Error(E)`, is returned when a function
42//! fails with some error and no processing can or should continue as a result.
43//! The meaning of an error depends on the context.
44//!
45//! In Rocket, an `Error` generally means that a request is taken out of normal
46//! processing. The request is then given to the catcher corresponding to some
47//! status code. Users can catch errors by requesting a type of `Result<S, E>`
48//! or `Option<S>` in request handlers. For example, if a user's handler looks
49//! like:
50//!
51//! ```rust
52//! # extern crate rocket_community as rocket;
53//! # use rocket::post;
54//! # type S = Option<String>;
55//! # type E = std::convert::Infallible;
56//! #[post("/", data = "<my_val>")]
57//! fn hello(my_val: Result<S, E>) { /* ... */ }
58//! ```
59//!
60//! The [`FromData`] implementation for the type `S` returns an `Outcome` with a
61//! `Success(S)` and `Error(E)`. If `from_data` returns an `Error`, the `Error`
62//! value will be unwrapped and the value will be used as the `Err` value of
63//! `my_val` while a `Success` will be unwrapped and used the `Ok` value.
64//!
65//! # Forward
66//!
67//! A forward `Outcome<S, E, F>`, `Forward(F)`, is returned when a function
68//! wants to indicate that the requested processing should be _forwarded_ to the
69//! next available processor. Again, the exact meaning depends on the context.
70//!
71//! In Rocket, a `Forward` generally means that a request is forwarded to the
72//! next available request handler. For example, consider the following request
73//! handler:
74//!
75//! ```rust
76//! # extern crate rocket_community as rocket;
77//! # use rocket::post;
78//! # type S = String;
79//! #[post("/", data = "<my_val>")]
80//! fn hello(my_val: S) { /* ... */ }
81//! ```
82//!
83//! The [`FromData`] implementation for the type `S` returns an `Outcome` with a
84//! `Success(S)`, `Error(E)`, and `Forward(F)`. If the `Outcome` is a
85//! `Forward`, the `hello` handler isn't called. Instead, the incoming request
86//! is forwarded, or passed on to, the next matching route, if any. Ultimately,
87//! if there are no non-forwarding routes, forwarded requests are handled by the
88//! 404 catcher. Similar to `Error`s, users can catch `Forward`s by requesting
89//! a type of `Option<S>`. If an `Outcome` is a `Forward`, the `Option` will be
90//! `None`.
91
92use crate::data::{self, Data, FromData};
93use crate::http::Status;
94use crate::{request, response, route};
95
96use self::Outcome::*;
97
98/// An enum representing success (`Success`), error (`Error`), or forwarding
99/// (`Forward`).
100///
101/// See the [top level documentation](crate::outcome) for detailed information.
102#[must_use]
103#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
104pub enum Outcome<S, E, F> {
105 /// Contains the success value.
106 Success(S),
107 /// Contains the error error value.
108 Error(E),
109 /// Contains the value to forward on.
110 Forward(F),
111}
112
113impl<S, E, F> Outcome<S, E, F> {
114 /// Unwraps the Outcome, yielding the contents of a Success.
115 ///
116 /// # Panics
117 ///
118 /// Panics if the value is not `Success`.
119 ///
120 /// # Examples
121 ///
122 /// ```rust
123 /// # extern crate rocket_community as rocket;
124 /// # use rocket::outcome::Outcome;
125 /// # use rocket::outcome::Outcome::*;
126 /// #
127 /// let x: Outcome<i32, &str, usize> = Success(10);
128 /// assert_eq!(x.unwrap(), 10);
129 /// ```
130 #[inline]
131 #[track_caller]
132 pub fn unwrap(self) -> S {
133 match self {
134 Success(val) => val,
135 _ => panic!("unwrapped a non-successful outcome"),
136 }
137 }
138
139 /// Unwraps the Outcome, yielding the contents of a Success.
140 ///
141 /// # Panics
142 ///
143 /// If the value is not `Success`, panics with the given `message`.
144 ///
145 /// # Examples
146 ///
147 /// ```rust
148 /// # extern crate rocket_community as rocket;
149 /// # use rocket::outcome::Outcome;
150 /// # use rocket::outcome::Outcome::*;
151 /// #
152 /// let x: Outcome<i32, &str, usize> = Success(10);
153 /// assert_eq!(x.expect("success value"), 10);
154 /// ```
155 #[inline]
156 #[track_caller]
157 pub fn expect(self, message: &str) -> S {
158 match self {
159 Success(val) => val,
160 _ => panic!("unwrapped a non-successful outcome: {}", message),
161 }
162 }
163
164 /// Return true if this `Outcome` is a `Success`.
165 ///
166 /// # Examples
167 ///
168 /// ```rust
169 /// # extern crate rocket_community as rocket;
170 /// # use rocket::outcome::Outcome;
171 /// # use rocket::outcome::Outcome::*;
172 /// #
173 /// let x: Outcome<i32, &str, usize> = Success(10);
174 /// assert_eq!(x.is_success(), true);
175 ///
176 /// let x: Outcome<i32, &str, usize> = Error("Hi! I'm an error.");
177 /// assert_eq!(x.is_success(), false);
178 ///
179 /// let x: Outcome<i32, &str, usize> = Forward(25);
180 /// assert_eq!(x.is_success(), false);
181 /// ```
182 #[inline]
183 pub fn is_success(&self) -> bool {
184 matches!(self, Success(_))
185 }
186
187 /// Return true if this `Outcome` is an `Error`.
188 ///
189 /// # Examples
190 ///
191 /// ```rust
192 /// # extern crate rocket_community as rocket;
193 /// # use rocket::outcome::Outcome;
194 /// # use rocket::outcome::Outcome::*;
195 /// #
196 /// let x: Outcome<i32, &str, usize> = Success(10);
197 /// assert_eq!(x.is_error(), false);
198 ///
199 /// let x: Outcome<i32, &str, usize> = Error("Hi! I'm an error.");
200 /// assert_eq!(x.is_error(), true);
201 ///
202 /// let x: Outcome<i32, &str, usize> = Forward(25);
203 /// assert_eq!(x.is_error(), false);
204 /// ```
205 #[inline]
206 pub fn is_error(&self) -> bool {
207 matches!(self, Error(_))
208 }
209
210 /// Return true if this `Outcome` is a `Forward`.
211 ///
212 /// # Examples
213 ///
214 /// ```rust
215 /// # extern crate rocket_community as rocket;
216 /// # use rocket::outcome::Outcome;
217 /// # use rocket::outcome::Outcome::*;
218 /// #
219 /// let x: Outcome<i32, &str, usize> = Success(10);
220 /// assert_eq!(x.is_forward(), false);
221 ///
222 /// let x: Outcome<i32, &str, usize> = Error("Hi! I'm an error.");
223 /// assert_eq!(x.is_forward(), false);
224 ///
225 /// let x: Outcome<i32, &str, usize> = Forward(25);
226 /// assert_eq!(x.is_forward(), true);
227 /// ```
228 #[inline]
229 pub fn is_forward(&self) -> bool {
230 matches!(self, Forward(_))
231 }
232
233 /// Converts from `Outcome<S, E, F>` to `Option<S>`.
234 ///
235 /// Returns the `Some` of the `Success` if this is a `Success`, otherwise
236 /// returns `None`. `self` is consumed, and all other values are discarded.
237 ///
238 /// ```rust
239 /// # extern crate rocket_community as rocket;
240 /// # use rocket::outcome::Outcome;
241 /// # use rocket::outcome::Outcome::*;
242 /// #
243 /// let x: Outcome<i32, &str, usize> = Success(10);
244 /// assert_eq!(x.succeeded(), Some(10));
245 ///
246 /// let x: Outcome<i32, &str, usize> = Error("Hi! I'm an error.");
247 /// assert_eq!(x.succeeded(), None);
248 ///
249 /// let x: Outcome<i32, &str, usize> = Forward(25);
250 /// assert_eq!(x.succeeded(), None);
251 /// ```
252 #[inline]
253 pub fn succeeded(self) -> Option<S> {
254 match self {
255 Success(val) => Some(val),
256 _ => None,
257 }
258 }
259
260 /// Converts from `Outcome<S, E, F>` to `Option<E>`.
261 ///
262 /// Returns the `Some` of the `Error` if this is an `Error`, otherwise
263 /// returns `None`. `self` is consumed, and all other values are discarded.
264 ///
265 /// ```rust
266 /// # extern crate rocket_community as rocket;
267 /// # use rocket::outcome::Outcome;
268 /// # use rocket::outcome::Outcome::*;
269 /// #
270 /// let x: Outcome<i32, &str, usize> = Success(10);
271 /// assert_eq!(x.failed(), None);
272 ///
273 /// let x: Outcome<i32, &str, usize> = Error("Hi! I'm an error.");
274 /// assert_eq!(x.failed(), Some("Hi! I'm an error."));
275 ///
276 /// let x: Outcome<i32, &str, usize> = Forward(25);
277 /// assert_eq!(x.failed(), None);
278 /// ```
279 #[inline]
280 pub fn failed(self) -> Option<E> {
281 match self {
282 Error(val) => Some(val),
283 _ => None,
284 }
285 }
286
287 /// Converts from `Outcome<S, E, F>` to `Option<F>`.
288 ///
289 /// Returns the `Some` of the `Forward` if this is a `Forward`, otherwise
290 /// returns `None`. `self` is consumed, and all other values are discarded.
291 ///
292 /// ```rust
293 /// # extern crate rocket_community as rocket;
294 /// # use rocket::outcome::Outcome;
295 /// # use rocket::outcome::Outcome::*;
296 /// #
297 /// let x: Outcome<i32, &str, usize> = Success(10);
298 /// assert_eq!(x.forwarded(), None);
299 ///
300 /// let x: Outcome<i32, &str, usize> = Error("Hi! I'm an error.");
301 /// assert_eq!(x.forwarded(), None);
302 ///
303 /// let x: Outcome<i32, &str, usize> = Forward(25);
304 /// assert_eq!(x.forwarded(), Some(25));
305 /// ```
306 #[inline]
307 pub fn forwarded(self) -> Option<F> {
308 match self {
309 Forward(val) => Some(val),
310 _ => None,
311 }
312 }
313
314 /// Returns a `Success` value as `Ok()` or `value` in `Err`. Converts from
315 /// `Outcome<S, E, F>` to `Result<S, T>` for a given `T`.
316 ///
317 /// Returns `Ok` with the `Success` value if this is a `Success`, otherwise
318 /// returns an `Err` with the provided value. `self` is consumed, and all
319 /// other values are discarded.
320 ///
321 /// ```rust
322 /// # extern crate rocket_community as rocket;
323 /// # use rocket::outcome::Outcome;
324 /// # use rocket::outcome::Outcome::*;
325 /// #
326 /// let x: Outcome<i32, &str, usize> = Success(10);
327 /// assert_eq!(x.success_or(false), Ok(10));
328 ///
329 /// let x: Outcome<i32, &str, usize> = Error("Hi! I'm an error.");
330 /// assert_eq!(x.success_or(false), Err(false));
331 ///
332 /// let x: Outcome<i32, &str, usize> = Forward(25);
333 /// assert_eq!(x.success_or("whoops"), Err("whoops"));
334 /// ```
335 #[inline]
336 pub fn success_or<T>(self, value: T) -> Result<S, T> {
337 match self {
338 Success(val) => Ok(val),
339 _ => Err(value),
340 }
341 }
342
343 /// Returns a `Success` value as `Ok()` or `f()` in `Err`. Converts from
344 /// `Outcome<S, E, F>` to `Result<S, T>` for a given `T` produced from a
345 /// supplied function or closure.
346 ///
347 /// Returns `Ok` with the `Success` value if this is a `Success`, otherwise
348 /// returns an `Err` with the result of calling `f`. `self` is consumed, and
349 /// all other values are discarded.
350 ///
351 /// ```rust
352 /// # extern crate rocket_community as rocket;
353 /// # use rocket::outcome::Outcome;
354 /// # use rocket::outcome::Outcome::*;
355 /// #
356 /// let x: Outcome<i32, &str, usize> = Success(10);
357 /// assert_eq!(x.success_or_else(|| false), Ok(10));
358 ///
359 /// let x: Outcome<i32, &str, usize> = Error("Hi! I'm an error.");
360 /// assert_eq!(x.success_or_else(|| false), Err(false));
361 ///
362 /// let x: Outcome<i32, &str, usize> = Forward(25);
363 /// assert_eq!(x.success_or_else(|| "whoops"), Err("whoops"));
364 /// ```
365 #[inline]
366 pub fn success_or_else<T, V: FnOnce() -> T>(self, f: V) -> Result<S, T> {
367 match self {
368 Success(val) => Ok(val),
369 _ => Err(f()),
370 }
371 }
372
373 /// Converts from `Outcome<S, E, F>` to `Outcome<&S, &E, &F>`.
374 ///
375 /// ```rust
376 /// # extern crate rocket_community as rocket;
377 /// # use rocket::outcome::Outcome;
378 /// # use rocket::outcome::Outcome::*;
379 /// #
380 /// let x: Outcome<i32, &str, usize> = Success(10);
381 /// assert_eq!(x.as_ref(), Success(&10));
382 ///
383 /// let x: Outcome<i32, &str, usize> = Error("Hi! I'm an error.");
384 /// assert_eq!(x.as_ref(), Error(&"Hi! I'm an error."));
385 /// ```
386 #[inline]
387 pub fn as_ref(&self) -> Outcome<&S, &E, &F> {
388 match *self {
389 Success(ref val) => Success(val),
390 Error(ref val) => Error(val),
391 Forward(ref val) => Forward(val),
392 }
393 }
394
395 /// Converts from `Outcome<S, E, F>` to `Outcome<&mut S, &mut E, &mut F>`.
396 ///
397 /// ```rust
398 /// # extern crate rocket_community as rocket;
399 /// # use rocket::outcome::Outcome;
400 /// # use rocket::outcome::Outcome::*;
401 /// #
402 /// let mut x: Outcome<i32, &str, usize> = Success(10);
403 /// if let Success(val) = x.as_mut() {
404 /// *val = 20;
405 /// }
406 ///
407 /// assert_eq!(x.unwrap(), 20);
408 /// ```
409 #[inline]
410 pub fn as_mut(&mut self) -> Outcome<&mut S, &mut E, &mut F> {
411 match *self {
412 Success(ref mut val) => Success(val),
413 Error(ref mut val) => Error(val),
414 Forward(ref mut val) => Forward(val),
415 }
416 }
417
418 /// Maps the `Success` value using `f`. Maps an `Outcome<S, E, F>` to an
419 /// `Outcome<T, E, F>` by applying the function `f` to the value of type `S`
420 /// in `self` if `self` is an `Outcome::Success`.
421 ///
422 /// ```rust
423 /// # extern crate rocket_community as rocket;
424 /// # use rocket::outcome::Outcome;
425 /// # use rocket::outcome::Outcome::*;
426 /// #
427 /// let x: Outcome<i32, &str, usize> = Success(10);
428 ///
429 /// let mapped = x.map(|v| if v == 10 { "10" } else { "not 10" });
430 /// assert_eq!(mapped, Success("10"));
431 /// ```
432 #[inline]
433 pub fn map<T, M: FnOnce(S) -> T>(self, f: M) -> Outcome<T, E, F> {
434 match self {
435 Success(val) => Success(f(val)),
436 Error(val) => Error(val),
437 Forward(val) => Forward(val),
438 }
439 }
440
441 /// Maps the `Error` value using `f`. Maps an `Outcome<S, E, F>` to an
442 /// `Outcome<S, T, F>` by applying the function `f` to the value of type `E`
443 /// in `self` if `self` is an `Outcome::Error`.
444 ///
445 /// ```rust
446 /// # extern crate rocket_community as rocket;
447 /// # use rocket::outcome::Outcome;
448 /// # use rocket::outcome::Outcome::*;
449 /// #
450 /// let x: Outcome<i32, &str, usize> = Error("hi");
451 ///
452 /// let mapped = x.map_error(|v| if v == "hi" { 10 } else { 0 });
453 /// assert_eq!(mapped, Error(10));
454 /// ```
455 #[inline]
456 pub fn map_error<T, M: FnOnce(E) -> T>(self, f: M) -> Outcome<S, T, F> {
457 match self {
458 Success(val) => Success(val),
459 Error(val) => Error(f(val)),
460 Forward(val) => Forward(val),
461 }
462 }
463
464 /// Maps the `Forward` value using `f`. Maps an `Outcome<S, E, F>` to an
465 /// `Outcome<S, E, T>` by applying the function `f` to the value of type `F`
466 /// in `self` if `self` is an `Outcome::Forward`.
467 ///
468 /// ```rust
469 /// # extern crate rocket_community as rocket;
470 /// # use rocket::outcome::Outcome;
471 /// # use rocket::outcome::Outcome::*;
472 /// #
473 /// let x: Outcome<i32, &str, usize> = Forward(5);
474 ///
475 /// let mapped = x.map_forward(|v| if v == 5 { "a" } else { "b" });
476 /// assert_eq!(mapped, Forward("a"));
477 /// ```
478 #[inline]
479 pub fn map_forward<T, M: FnOnce(F) -> T>(self, f: M) -> Outcome<S, E, T> {
480 match self {
481 Success(val) => Success(val),
482 Error(val) => Error(val),
483 Forward(val) => Forward(f(val)),
484 }
485 }
486
487 /// Converts from `Outcome<S, E, F>` to `Outcome<T, E, F>` using `f` to map
488 /// `Success(S)` to `Success(T)`.
489 ///
490 /// If `self` is not `Success`, `self` is returned.
491 ///
492 /// # Examples
493 ///
494 /// ```rust
495 /// # extern crate rocket_community as rocket;
496 /// # use rocket::outcome::Outcome;
497 /// # use rocket::outcome::Outcome::*;
498 /// #
499 /// let x: Outcome<i32, &str, bool> = Success(10);
500 ///
501 /// let mapped = x.and_then(|v| match v {
502 /// 10 => Success("10"),
503 /// 1 => Forward(false),
504 /// _ => Error("30")
505 /// });
506 ///
507 /// assert_eq!(mapped, Success("10"));
508 /// ```
509 #[inline]
510 pub fn and_then<T, M: FnOnce(S) -> Outcome<T, E, F>>(self, f: M) -> Outcome<T, E, F> {
511 match self {
512 Success(val) => f(val),
513 Error(val) => Error(val),
514 Forward(val) => Forward(val),
515 }
516 }
517
518 /// Converts from `Outcome<S, E, F>` to `Outcome<S, T, F>` using `f` to map
519 /// `Error(E)` to `Error(T)`.
520 ///
521 /// If `self` is not `Error`, `self` is returned.
522 ///
523 /// # Examples
524 ///
525 /// ```rust
526 /// # extern crate rocket_community as rocket;
527 /// # use rocket::outcome::Outcome;
528 /// # use rocket::outcome::Outcome::*;
529 /// #
530 /// let x: Outcome<i32, &str, bool> = Error("hi");
531 ///
532 /// let mapped = x.error_then(|v| match v {
533 /// "hi" => Error(10),
534 /// "test" => Forward(false),
535 /// _ => Success(10)
536 /// });
537 ///
538 /// assert_eq!(mapped, Error(10));
539 /// ```
540 #[inline]
541 pub fn error_then<T, M: FnOnce(E) -> Outcome<S, T, F>>(self, f: M) -> Outcome<S, T, F> {
542 match self {
543 Success(val) => Success(val),
544 Error(val) => f(val),
545 Forward(val) => Forward(val),
546 }
547 }
548
549 /// Converts from `Outcome<S, E, F>` to `Outcome<S, E, T>` using `f` to map
550 /// `Forward(F)` to `Forward(T)`.
551 ///
552 /// If `self` is not `Forward`, `self` is returned.
553 ///
554 /// # Examples
555 ///
556 /// ```rust
557 /// # extern crate rocket_community as rocket;
558 /// # use rocket::outcome::Outcome;
559 /// # use rocket::outcome::Outcome::*;
560 /// #
561 /// let x: Outcome<i32, &str, Option<bool>> = Forward(Some(false));
562 ///
563 /// let mapped = x.forward_then(|v| match v {
564 /// Some(true) => Success(10),
565 /// Some(false) => Forward(20),
566 /// None => Error("10")
567 /// });
568 ///
569 /// assert_eq!(mapped, Forward(20));
570 /// ```
571 #[inline]
572 pub fn forward_then<T, M: FnOnce(F) -> Outcome<S, E, T>>(self, f: M) -> Outcome<S, E, T> {
573 match self {
574 Success(val) => Success(val),
575 Error(val) => Error(val),
576 Forward(val) => f(val),
577 }
578 }
579
580 /// Converts `Outcome<S, E, F>` to `Result<S, E>` by identity mapping
581 /// `Success(S)` and `Error(E)` to `Result<T, E>` and mapping `Forward(F)`
582 /// to `Result<T, E>` using `f`.
583 ///
584 /// ```rust
585 /// # extern crate rocket_community as rocket;
586 /// # use rocket::outcome::Outcome;
587 /// # use rocket::outcome::Outcome::*;
588 /// #
589 /// let x: Outcome<i32, &str, usize> = Success(10);
590 /// assert_eq!(x.ok_map_forward(|x| Ok(x as i32 + 1)), Ok(10));
591 ///
592 /// let x: Outcome<i32, &str, usize> = Error("hello");
593 /// assert_eq!(x.ok_map_forward(|x| Ok(x as i32 + 1)), Err("hello"));
594 ///
595 /// let x: Outcome<i32, &str, usize> = Forward(0);
596 /// assert_eq!(x.ok_map_forward(|x| Ok(x as i32 + 1)), Ok(1));
597 /// ```
598 #[inline]
599 pub fn ok_map_forward<M>(self, f: M) -> Result<S, E>
600 where
601 M: FnOnce(F) -> Result<S, E>,
602 {
603 match self {
604 Outcome::Success(s) => Ok(s),
605 Outcome::Error(e) => Err(e),
606 Outcome::Forward(v) => f(v),
607 }
608 }
609
610 /// Converts `Outcome<S, E, F>` to `Result<S, E>` by identity mapping
611 /// `Success(S)` and `Forward(F)` to `Result<T, F>` and mapping `Error(E)`
612 /// to `Result<T, F>` using `f`.
613 ///
614 /// ```rust
615 /// # extern crate rocket_community as rocket;
616 /// # use rocket::outcome::Outcome;
617 /// # use rocket::outcome::Outcome::*;
618 /// #
619 /// let x: Outcome<i32, &str, usize> = Success(10);
620 /// assert_eq!(x.ok_map_error(|s| Ok(123)), Ok(10));
621 ///
622 /// let x: Outcome<i32, &str, usize> = Error("hello");
623 /// assert_eq!(x.ok_map_error(|s| Ok(123)), Ok(123));
624 ///
625 /// let x: Outcome<i32, &str, usize> = Forward(0);
626 /// assert_eq!(x.ok_map_error(|s| Ok(123)), Err(0));
627 /// ```
628 #[inline]
629 pub fn ok_map_error<M>(self, f: M) -> Result<S, F>
630 where
631 M: FnOnce(E) -> Result<S, F>,
632 {
633 match self {
634 Outcome::Success(s) => Ok(s),
635 Outcome::Error(e) => f(e),
636 Outcome::Forward(v) => Err(v),
637 }
638 }
639}
640
641impl<'a, S: Send + 'a, E: Send + 'a, F: Send + 'a> Outcome<S, E, F> {
642 /// Pins a future that resolves to `self`, returning a
643 /// [`BoxFuture`](crate::futures::future::BoxFuture) that resolves to
644 /// `self`.
645 #[inline]
646 pub fn pin(self) -> futures::future::BoxFuture<'a, Self> {
647 Box::pin(async move { self })
648 }
649}
650
651crate::export! {
652 /// Unwraps a [`Success`](Outcome::Success) or propagates a `Forward` or
653 /// `Error` by returning early.
654 ///
655 /// # Syntax
656 ///
657 /// The macro has the following "signature":
658 ///
659 /// ```rust
660 /// # extern crate rocket_community as rocket;
661 /// use rocket::outcome::Outcome;
662 ///
663 /// // Returns the inner `S` if `outcome` is `Outcome::Success`. Otherwise
664 /// // returns from the caller with `Outcome<impl From<E>, impl From<F>>`.
665 /// fn try_outcome<S, E, F>(outcome: Outcome<S, E, F>) -> S
666 /// # { unimplemented!() }
667 /// ```
668 ///
669 /// This is just like `?` (or previously, `try!`), but for `Outcome`. In the
670 /// case of a `Forward` or `Error` variant, the inner type is passed to
671 /// [`From`](std::convert::From), allowing for the conversion between
672 /// specific and more general types. The resulting forward/error is
673 /// immediately returned. Because of the early return, `try_outcome!` can
674 /// only be used in methods that return [`Outcome`].
675 ///
676 /// [`Outcome`]: crate::outcome::Outcome
677 ///
678 /// ## Example
679 ///
680 /// ```rust,no_run
681 /// # #[macro_use] extern crate rocket_community as rocket;
682 /// use std::sync::atomic::{AtomicUsize, Ordering};
683 ///
684 /// use rocket::State;
685 /// use rocket::request::{self, Request, FromRequest};
686 /// use rocket::outcome::{try_outcome, Outcome::*};
687 ///
688 /// #[derive(Default)]
689 /// struct Atomics {
690 /// uncached: AtomicUsize,
691 /// cached: AtomicUsize,
692 /// }
693 ///
694 /// struct Guard1;
695 /// struct Guard2;
696 ///
697 /// #[rocket::async_trait]
698 /// impl<'r> FromRequest<'r> for Guard1 {
699 /// type Error = ();
700 ///
701 /// async fn from_request(req: &'r Request<'_>) -> request::Outcome<Self, ()> {
702 /// // Attempt to fetch the guard, passing through any error or forward.
703 /// let atomics = try_outcome!(req.guard::<&State<Atomics>>().await);
704 /// atomics.uncached.fetch_add(1, Ordering::Relaxed);
705 /// req.local_cache(|| atomics.cached.fetch_add(1, Ordering::Relaxed));
706 ///
707 /// Success(Guard1)
708 /// }
709 /// }
710 ///
711 /// #[rocket::async_trait]
712 /// impl<'r> FromRequest<'r> for Guard2 {
713 /// type Error = ();
714 ///
715 /// async fn from_request(req: &'r Request<'_>) -> request::Outcome<Self, ()> {
716 /// // Attempt to fetch the guard, passing through any error or forward.
717 /// let guard1: Guard1 = try_outcome!(req.guard::<Guard1>().await);
718 /// Success(Guard2)
719 /// }
720 /// }
721 /// ```
722 macro_rules! try_outcome {
723 ($expr:expr $(,)?) => (match $expr {
724 $crate::outcome::Outcome::Success(val) => val,
725 $crate::outcome::Outcome::Error(e) => {
726 return $crate::outcome::Outcome::Error(::std::convert::From::from(e))
727 },
728 $crate::outcome::Outcome::Forward(f) => {
729 return $crate::outcome::Outcome::Forward(::std::convert::From::from(f))
730 },
731 });
732 }
733}
734
735/// Conversion trait from some type into an Outcome type.
736pub trait IntoOutcome<Outcome> {
737 /// The type to use when returning an `Outcome::Error`.
738 type Error: Sized;
739
740 /// The type to use when returning an `Outcome::Forward`.
741 type Forward: Sized;
742
743 /// Converts `self` into an `Outcome`. If `self` represents a success, an
744 /// `Outcome::Success` is returned. Otherwise, an `Outcome::Error` is
745 /// returned with `error` as the inner value.
746 fn or_error(self, error: Self::Error) -> Outcome;
747
748 /// Converts `self` into an `Outcome`. If `self` represents a success, an
749 /// `Outcome::Success` is returned. Otherwise, an `Outcome::Forward` is
750 /// returned with `forward` as the inner value.
751 fn or_forward(self, forward: Self::Forward) -> Outcome;
752}
753
754impl<S, E, F> IntoOutcome<Outcome<S, E, F>> for Option<S> {
755 type Error = E;
756 type Forward = F;
757
758 #[inline]
759 fn or_error(self, error: E) -> Outcome<S, E, F> {
760 match self {
761 Some(val) => Success(val),
762 None => Error(error),
763 }
764 }
765
766 #[inline]
767 fn or_forward(self, forward: F) -> Outcome<S, E, F> {
768 match self {
769 Some(val) => Success(val),
770 None => Forward(forward),
771 }
772 }
773}
774
775impl<'r, T: FromData<'r>> IntoOutcome<data::Outcome<'r, T>> for Result<T, T::Error> {
776 type Error = Status;
777 type Forward = (Data<'r>, Status);
778
779 #[inline]
780 fn or_error(self, error: Status) -> data::Outcome<'r, T> {
781 match self {
782 Ok(val) => Success(val),
783 Err(err) => Error((error, err)),
784 }
785 }
786
787 #[inline]
788 fn or_forward(self, (data, forward): (Data<'r>, Status)) -> data::Outcome<'r, T> {
789 match self {
790 Ok(val) => Success(val),
791 Err(_) => Forward((data, forward)),
792 }
793 }
794}
795
796impl<S, E> IntoOutcome<request::Outcome<S, E>> for Result<S, E> {
797 type Error = Status;
798 type Forward = Status;
799
800 #[inline]
801 fn or_error(self, error: Status) -> request::Outcome<S, E> {
802 match self {
803 Ok(val) => Success(val),
804 Err(err) => Error((error, err)),
805 }
806 }
807
808 #[inline]
809 fn or_forward(self, status: Status) -> request::Outcome<S, E> {
810 match self {
811 Ok(val) => Success(val),
812 Err(_) => Forward(status),
813 }
814 }
815}
816
817impl<'r, 'o: 'r> IntoOutcome<route::Outcome<'r>> for response::Result<'o> {
818 type Error = ();
819 type Forward = (Data<'r>, Status);
820
821 #[inline]
822 fn or_error(self, _: ()) -> route::Outcome<'r> {
823 match self {
824 Ok(val) => Success(val),
825 Err(status) => Error(status),
826 }
827 }
828
829 #[inline]
830 fn or_forward(self, (data, forward): (Data<'r>, Status)) -> route::Outcome<'r> {
831 match self {
832 Ok(val) => Success(val),
833 Err(_) => Forward((data, forward)),
834 }
835 }
836}