Clean up LaunchError docs. Add Rocket::{config, routes} example.

This commit also:

  * Cleans up the stored URIs in routes.
  * Removes LaunchError as a root export.
  * Adds a URI::base() method.
This commit is contained in:
Sergio Benitez 2017-06-12 15:08:34 -07:00
parent 7cf3367183
commit 3fcf6c43dc
7 changed files with 99 additions and 30 deletions

View File

@ -36,7 +36,7 @@ pub enum LaunchErrorKind {
Unknown(Box<::std::error::Error + Send + Sync>) Unknown(Box<::std::error::Error + Send + Sync>)
} }
/// An error that occurred during launch. /// An error that occurs during launch.
/// ///
/// A `LaunchError` is returned by /// A `LaunchError` is returned by
/// [rocket::launch](/rocket/struct.Rocket.html#method.launch) when launching an /// [rocket::launch](/rocket/struct.Rocket.html#method.launch) when launching an
@ -64,7 +64,7 @@ pub enum LaunchErrorKind {
/// ``` /// ```
/// ///
/// When a value of this type panics, the corresponding error message is pretty /// When a value of this type panics, the corresponding error message is pretty
/// printed to the console. The following snippet illustrates this: /// printed to the console. The following illustrates this:
/// ///
/// ```rust /// ```rust
/// # if false { /// # if false {
@ -75,6 +75,18 @@ pub enum LaunchErrorKind {
/// drop(error); /// drop(error);
/// # } /// # }
/// ``` /// ```
///
/// # Usage
///
/// A `LaunchError` value should usually be allowed to `drop` without
/// inspection. There are two exceptions to this suggestion.
///
/// 1. If you are writing a library or high-level application on-top of
/// Rocket, you likely want to inspect the value before it drops to avoid a
/// Rocket-specific `panic!`. This typically means simply printing the
/// value.
///
/// 2. You want to display your own error messages.
pub struct LaunchError { pub struct LaunchError {
handled: AtomicBool, handled: AtomicBool,
kind: LaunchErrorKind kind: LaunchErrorKind

View File

@ -129,11 +129,11 @@ pub mod config;
pub mod data; pub mod data;
pub mod handler; pub mod handler;
pub mod fairing; pub mod fairing;
pub mod error;
mod router; mod router;
mod rocket; mod rocket;
mod codegen; mod codegen;
mod error;
mod catcher; mod catcher;
mod ext; mod ext;
@ -144,9 +144,9 @@ mod ext;
#[doc(inline)] pub use outcome::Outcome; #[doc(inline)] pub use outcome::Outcome;
#[doc(inline)] pub use data::Data; #[doc(inline)] pub use data::Data;
#[doc(inline)] pub use config::Config; #[doc(inline)] pub use config::Config;
#[doc(inline)] pub use error::Error;
pub use router::Route; pub use router::Route;
pub use request::{Request, State}; pub use request::{Request, State};
pub use error::{Error, LaunchError};
pub use catcher::Catcher; pub use catcher::Catcher;
pub use rocket::Rocket; pub use rocket::Rocket;

View File

@ -485,9 +485,10 @@ impl Rocket {
} }
for mut route in routes { for mut route in routes {
let path = format!("{}/{}", base, route.path); let uri = URI::new(format!("{}/{}", base, route.uri));
route.set_base(base); route.set_base(base);
route.set_path(path); route.set_uri(uri.to_string());
info_!("{}", route); info_!("{}", route);
self.router.add(route); self.router.add(route);
@ -605,9 +606,7 @@ impl Rocket {
/// fn main() { /// fn main() {
/// # if false { // We don't actually want to launch the server in an example. /// # if false { // We don't actually want to launch the server in an example.
/// rocket::ignite() /// rocket::ignite()
/// .attach(AdHoc::on_launch(|_| { /// .attach(AdHoc::on_launch(|_| println!("Rocket is launching!")))
/// println!("Rocket is about to launch! You just see...");
/// }))
/// .launch(); /// .launch();
/// # } /// # }
/// } /// }
@ -646,7 +645,7 @@ impl Rocket {
/// documentation](/rocket/struct.LaunchError.html) for more /// documentation](/rocket/struct.LaunchError.html) for more
/// information. /// information.
/// ///
/// # Examples /// # Example
/// ///
/// ```rust /// ```rust
/// # if false { /// # if false {
@ -691,13 +690,65 @@ impl Rocket {
}) })
} }
/// Retrieves all of the mounted routes. /// Returns an iterator over all of the routes mounted on this instance of
/// Rocket.
///
/// # Example
///
/// ```rust
/// # #![feature(plugin)]
/// # #![plugin(rocket_codegen)]
/// # extern crate rocket;
/// use rocket::Rocket;
/// use rocket::fairing::AdHoc;
///
/// #[get("/hello")]
/// fn hello() -> &'static str {
/// "Hello, world!"
/// }
///
/// fn main() {
/// let rocket = rocket::ignite()
/// .mount("/", routes![hello])
/// .mount("/hi", routes![hello]);
///
/// for route in rocket.routes() {
/// match route.base() {
/// "/" => assert_eq!(route.uri.path(), "/hello"),
/// "/hi" => assert_eq!(route.uri.path(), "/hi/hello"),
/// _ => unreachable!("only /hello, /hi/hello are expected")
/// }
/// }
///
/// assert_eq!(rocket.routes().count(), 2);
/// }
/// ```
#[inline(always)] #[inline(always)]
pub fn routes<'a>(&'a self) -> impl Iterator<Item=&'a Route> + 'a { pub fn routes<'a>(&'a self) -> impl Iterator<Item=&'a Route> + 'a {
self.router.routes() self.router.routes()
} }
/// Retrieve the active configuration. /// Returns the active configuration.
///
/// # Example
///
/// ```rust
/// # #![feature(plugin)]
/// # #![plugin(rocket_codegen)]
/// # extern crate rocket;
/// use rocket::Rocket;
/// use rocket::fairing::AdHoc;
///
/// fn main() {
/// # if false { // We don't actually want to launch the server in an example.
/// rocket::ignite()
/// .attach(AdHoc::on_launch(|rocket| {
/// println!("Rocket launch config: {:?}", rocket.config());
/// }))
/// .launch();
/// # }
/// }
/// ```
#[inline(always)] #[inline(always)]
pub fn config(&self) -> &Config { pub fn config(&self) -> &Config {
&self.config &self.config

View File

@ -94,7 +94,7 @@ impl Collider for Route {
fn collides_with(&self, b: &Route) -> bool { fn collides_with(&self, b: &Route) -> bool {
self.method == b.method self.method == b.method
&& self.rank == b.rank && self.rank == b.rank
&& self.path.collides_with(&b.path) && self.uri.collides_with(&b.uri)
&& match (self.format.as_ref(), b.format.as_ref()) { && match (self.format.as_ref(), b.format.as_ref()) {
(Some(mt_a), Some(mt_b)) => mt_a.collides_with(mt_b), (Some(mt_a), Some(mt_b)) => mt_a.collides_with(mt_b),
(Some(_), None) => true, (Some(_), None) => true,
@ -114,8 +114,8 @@ impl Collider for Route {
impl<'r> Collider<Request<'r>> for Route { impl<'r> Collider<Request<'r>> for Route {
fn collides_with(&self, req: &Request<'r>) -> bool { fn collides_with(&self, req: &Request<'r>) -> bool {
self.method == req.method() self.method == req.method()
&& self.path.collides_with(req.uri()) && self.uri.collides_with(req.uri())
&& self.path.query().map_or(true, |_| req.uri().query().is_some()) && self.uri.query().map_or(true, |_| req.uri().query().is_some())
&& match self.format { && match self.format {
Some(ref mt_a) => match req.format() { Some(ref mt_a) => match req.format() {
Some(ref mt_b) => mt_a.collides_with(mt_b), Some(ref mt_b) => mt_a.collides_with(mt_b),

View File

@ -241,7 +241,7 @@ mod test {
macro_rules! assert_ranked_routes { macro_rules! assert_ranked_routes {
($routes:expr, $to:expr, $want:expr) => ({ ($routes:expr, $to:expr, $want:expr) => ({
let router = router_with_routes($routes); let router = router_with_routes($routes);
let route_path = route(&router, Get, $to).unwrap().path.as_str(); let route_path = route(&router, Get, $to).unwrap().uri.as_str();
assert_eq!(route_path as &str, $want as &str); assert_eq!(route_path as &str, $want as &str);
}) })
} }
@ -296,7 +296,7 @@ mod test {
assert!(routed_to.len() == expected.len()); assert!(routed_to.len() == expected.len());
for (got, expected) in routed_to.iter().zip(expected.iter()) { for (got, expected) in routed_to.iter().zip(expected.iter()) {
assert_eq!(got.rank, expected.0); assert_eq!(got.rank, expected.0);
assert_eq!(got.path.as_str(), expected.1); assert_eq!(got.uri.as_str(), expected.1);
} }
}) })
} }
@ -365,7 +365,7 @@ mod test {
let expected = &[$($want),+]; let expected = &[$($want),+];
assert!(routed_to.len() == expected.len()); assert!(routed_to.len() == expected.len());
for (got, expected) in routed_to.iter().zip(expected.iter()) { for (got, expected) in routed_to.iter().zip(expected.iter()) {
assert_eq!(got.path.as_str(), expected as &str); assert_eq!(got.uri.as_str(), expected as &str);
} }
}) })
} }

View File

@ -16,9 +16,9 @@ pub struct Route {
pub handler: Handler, pub handler: Handler,
/// The base mount point of this `Route`. /// The base mount point of this `Route`.
pub base: URI<'static>, pub base: URI<'static>,
/// The path (in Rocket format) that should be matched against. This path /// The uri (in Rocket format) that should be matched against. This uri
/// already includes the base mount point. /// already includes the base mount point.
pub path: URI<'static>, pub uri: URI<'static>,
/// The rank of this route. Lower ranks have higher priorities. /// The rank of this route. Lower ranks have higher priorities.
pub rank: isize, pub rank: isize,
/// The media type this route matches against. /// The media type this route matches against.
@ -51,25 +51,31 @@ impl Route {
handler: handler, handler: handler,
rank: default_rank(&uri), rank: default_rank(&uri),
base: URI::from("/"), base: URI::from("/"),
path: uri, uri: uri,
format: None, format: None,
} }
} }
/// Creates a new route with the given rank, method, path, and handler. /// Creates a new route with the given rank, method, path, and handler.
pub fn ranked<S>(rank: isize, m: Method, path: S, handler: Handler) -> Route pub fn ranked<S>(rank: isize, m: Method, uri: S, handler: Handler) -> Route
where S: AsRef<str> where S: AsRef<str>
{ {
Route { Route {
method: m, method: m,
handler: handler, handler: handler,
base: URI::from("/"), base: URI::from("/"),
path: URI::from(path.as_ref().to_string()), uri: URI::from(uri.as_ref().to_string()),
rank: rank, rank: rank,
format: None, format: None,
} }
} }
/// Retrieves the base mount point of this route.
#[inline]
pub fn base(&self) -> &str {
self.base.path()
}
/// Sets the base mount point of the route. Does not update the rank or any /// Sets the base mount point of the route. Does not update the rank or any
/// other parameters. /// other parameters.
pub fn set_base<S>(&mut self, path: S) where S: AsRef<str> { pub fn set_base<S>(&mut self, path: S) where S: AsRef<str> {
@ -78,8 +84,8 @@ impl Route {
/// Sets the path of the route. Does not update the rank or any other /// Sets the path of the route. Does not update the rank or any other
/// parameters. /// parameters.
pub fn set_path<S>(&mut self, path: S) where S: AsRef<str> { pub fn set_uri<S>(&mut self, uri: S) where S: AsRef<str> {
self.path = URI::from(path.as_ref().to_string()); self.uri = URI::from(uri.as_ref().to_string());
} }
// FIXME: Decide whether a component has to be fully variable or not. That // FIXME: Decide whether a component has to be fully variable or not. That
@ -88,11 +94,11 @@ impl Route {
/// Given a URI, returns a vector of slices of that URI corresponding to the /// Given a URI, returns a vector of slices of that URI corresponding to the
/// dynamic segments in this route. /// dynamic segments in this route.
pub(crate) fn get_param_indexes(&self, uri: &URI) -> Vec<(usize, usize)> { pub(crate) fn get_param_indexes(&self, uri: &URI) -> Vec<(usize, usize)> {
let route_segs = self.path.segments(); let route_segs = self.uri.segments();
let uri_segs = uri.segments(); let uri_segs = uri.segments();
let start_addr = uri.path().as_ptr() as usize; let start_addr = uri.path().as_ptr() as usize;
let mut result = Vec::with_capacity(self.path.segment_count()); let mut result = Vec::with_capacity(self.uri.segment_count());
for (route_seg, uri_seg) in route_segs.zip(uri_segs) { for (route_seg, uri_seg) in route_segs.zip(uri_segs) {
let i = (uri_seg.as_ptr() as usize) - start_addr; let i = (uri_seg.as_ptr() as usize) - start_addr;
if route_seg.ends_with("..>") { if route_seg.ends_with("..>") {
@ -115,7 +121,7 @@ impl Clone for Route {
handler: self.handler, handler: self.handler,
rank: self.rank, rank: self.rank,
base: self.base.clone(), base: self.base.clone(),
path: self.path.clone(), uri: self.uri.clone(),
format: self.format.clone(), format: self.format.clone(),
} }
} }
@ -123,7 +129,7 @@ impl Clone for Route {
impl fmt::Display for Route { impl fmt::Display for Route {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {}", Green.paint(&self.method), Blue.paint(&self.path))?; write!(f, "{} {}", Green.paint(&self.method), Blue.paint(&self.uri))?;
if self.rank > 1 { if self.rank > 1 {
write!(f, " [{}]", White.paint(&self.rank))?; write!(f, " [{}]", White.paint(&self.rank))?;

View File

@ -8,7 +8,7 @@ use rocket::Route;
#[get("/<path..>")] #[get("/<path..>")]
fn files(route: &Route, path: PathBuf) -> String { fn files(route: &Route, path: PathBuf) -> String {
format!("{}/{}", route.base.path(), path.to_string_lossy()) format!("{}/{}", route.base(), path.to_string_lossy())
} }
mod route_guard_tests { mod route_guard_tests {