mirror of https://github.com/rwf2/Rocket.git
Document the Rocket type. Add expect method to Outcome. Add custom method to Rocket.
This commit is contained in:
parent
5b8b41bcd8
commit
d7353c8c2d
|
@ -8,6 +8,7 @@ use std::fmt;
|
||||||
use term_painter::ToStyle;
|
use term_painter::ToStyle;
|
||||||
use term_painter::Color::*;
|
use term_painter::Color::*;
|
||||||
|
|
||||||
|
/// An error catching route.
|
||||||
pub struct Catcher {
|
pub struct Catcher {
|
||||||
pub code: u16,
|
pub code: u16,
|
||||||
handler: ErrorHandler,
|
handler: ErrorHandler,
|
||||||
|
@ -15,23 +16,32 @@ pub struct Catcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Catcher {
|
impl Catcher {
|
||||||
|
/// Creates a catcher for the given status code using the given error
|
||||||
|
/// handler.
|
||||||
|
#[inline(always)]
|
||||||
pub fn new(code: u16, handler: ErrorHandler) -> Catcher {
|
pub fn new(code: u16, handler: ErrorHandler) -> Catcher {
|
||||||
Catcher { code: code, handler: handler, is_default: false }
|
Catcher { code: code, handler: handler, is_default: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[inline(always)]
|
||||||
pub fn handle<'r>(&self, err: Error, request: &'r Request) -> Response<'r> {
|
pub fn handle<'r>(&self, err: Error, request: &'r Request) -> Response<'r> {
|
||||||
(self.handler)(err, request)
|
(self.handler)(err, request)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
fn new_default(code: u16, handler: ErrorHandler) -> Catcher {
|
fn new_default(code: u16, handler: ErrorHandler) -> Catcher {
|
||||||
Catcher { code: code, handler: handler, is_default: true, }
|
Catcher { code: code, handler: handler, is_default: true, }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[inline(always)]
|
||||||
pub fn is_default(&self) -> bool {
|
pub fn is_default(&self) -> bool {
|
||||||
self.is_default
|
self.is_default
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
impl<'a> From<&'a StaticCatchInfo> for Catcher {
|
impl<'a> From<&'a StaticCatchInfo> for Catcher {
|
||||||
fn from(info: &'a StaticCatchInfo) -> Catcher {
|
fn from(info: &'a StaticCatchInfo) -> Catcher {
|
||||||
Catcher::new(info.code, info.handler)
|
Catcher::new(info.code, info.handler)
|
||||||
|
|
|
@ -137,7 +137,14 @@ pub use error::Error;
|
||||||
pub use catcher::Catcher;
|
pub use catcher::Catcher;
|
||||||
pub use rocket::Rocket;
|
pub use rocket::Rocket;
|
||||||
|
|
||||||
/// Alias to Rocket::ignite().
|
/// Alias to [Rocket::ignite()](/rocket/struct.Rocket.html#method.ignite).
|
||||||
|
/// Creates a new instance of `Rocket`.
|
||||||
pub fn ignite() -> Rocket {
|
pub fn ignite() -> Rocket {
|
||||||
Rocket::ignite()
|
Rocket::ignite()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Alias to [Rocket::custom()](/rocket/struct.Rocket.html#method.custom).
|
||||||
|
/// Creates a new instance of `Rocket` with a custom configuration.
|
||||||
|
pub fn custom(config: &config::Config) -> Rocket {
|
||||||
|
Rocket::custom(config)
|
||||||
|
}
|
||||||
|
|
|
@ -129,6 +129,29 @@ impl<S, E, F> Outcome<S, E, F> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Unwraps the Outcome, yielding the contents of a Success.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// If the value is not `Success`, panics with the given `message`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # use rocket::outcome::Outcome;
|
||||||
|
/// # use rocket::outcome::Outcome::*;
|
||||||
|
/// #
|
||||||
|
/// let x: Outcome<i32, &str, usize> = Success(10);
|
||||||
|
/// assert_eq!(x.expect("success value"), 10);
|
||||||
|
/// ```
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn expect(self, message: &str) -> S {
|
||||||
|
match self {
|
||||||
|
Success(val) => val,
|
||||||
|
_ => panic!("Outcome::expect() failed: {}", message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Return true if this `Outcome` is a `Success`.
|
/// Return true if this `Outcome` is a `Success`.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
|
|
@ -6,8 +6,8 @@ use std::process;
|
||||||
use term_painter::Color::*;
|
use term_painter::Color::*;
|
||||||
use term_painter::ToStyle;
|
use term_painter::ToStyle;
|
||||||
|
|
||||||
use config;
|
|
||||||
use logger;
|
use logger;
|
||||||
|
use config::{self, Config};
|
||||||
use request::{Request, FormItems};
|
use request::{Request, FormItems};
|
||||||
use data::Data;
|
use data::Data;
|
||||||
use response::Responder;
|
use response::Responder;
|
||||||
|
@ -20,7 +20,7 @@ use http::{Method, StatusCode};
|
||||||
use http::hyper::{HyperRequest, FreshHyperResponse};
|
use http::hyper::{HyperRequest, FreshHyperResponse};
|
||||||
use http::hyper::{HyperServer, HyperHandler, HyperSetCookie, header};
|
use http::hyper::{HyperServer, HyperHandler, HyperSetCookie, header};
|
||||||
|
|
||||||
/// The Rocket type used to mount routes and catchers and launch the
|
/// The main `Rocket` type: used to mount routes and catchers and launch the
|
||||||
/// application.
|
/// application.
|
||||||
pub struct Rocket {
|
pub struct Rocket {
|
||||||
address: String,
|
address: String,
|
||||||
|
@ -32,6 +32,11 @@ pub struct Rocket {
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
impl HyperHandler for Rocket {
|
impl HyperHandler for Rocket {
|
||||||
|
// This function tries to hide all of the Hyper-ness from Rocket. It
|
||||||
|
// essentially converts Hyper types into Rocket types, then calls the
|
||||||
|
// `dispatch` function, which knows nothing about Hyper. Because responding
|
||||||
|
// depends on the `HyperResponse` type, this function does the actual
|
||||||
|
// response processing.
|
||||||
fn handle<'h, 'k>(&self,
|
fn handle<'h, 'k>(&self,
|
||||||
hyp_req: HyperRequest<'h, 'k>,
|
hyp_req: HyperRequest<'h, 'k>,
|
||||||
mut res: FreshHyperResponse<'h>) {
|
mut res: FreshHyperResponse<'h>) {
|
||||||
|
@ -115,6 +120,11 @@ impl Rocket {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Tries to find a `Responder` for a given `request`. It does this by
|
||||||
|
/// routing the request and calling the handler for each matching route
|
||||||
|
/// until one of the handlers returns success or failure. If a handler
|
||||||
|
/// returns a failure, or there are no matching handlers willing to accept
|
||||||
|
/// the request, this function returns an `Err` with the status code.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn dispatch<'r>(&self, request: &'r Request, mut data: Data)
|
pub fn dispatch<'r>(&self, request: &'r Request, mut data: Data)
|
||||||
-> Result<Box<Responder + 'r>, StatusCode> {
|
-> Result<Box<Responder + 'r>, StatusCode> {
|
||||||
|
@ -143,7 +153,11 @@ impl Rocket {
|
||||||
Err(StatusCode::NotFound)
|
Err(StatusCode::NotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call when no route was found. Returns true if there was a response.
|
// Attempts to send a response to the client by using the catcher for the
|
||||||
|
// given status code. If no catcher is found (including the defaults), the
|
||||||
|
// 500 internal server error catcher is used. If the catcher fails to
|
||||||
|
// respond, this function returns `false`. It returns `true` if a response
|
||||||
|
// was sucessfully sent to the client.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn handle_error<'r>(&self,
|
pub fn handle_error<'r>(&self,
|
||||||
code: StatusCode,
|
code: StatusCode,
|
||||||
|
@ -153,7 +167,7 @@ impl Rocket {
|
||||||
let catcher = self.catchers.get(&code.to_u16()).unwrap_or_else(|| {
|
let catcher = self.catchers.get(&code.to_u16()).unwrap_or_else(|| {
|
||||||
error_!("No catcher found for {}.", code);
|
error_!("No catcher found for {}.", code);
|
||||||
warn_!("Using internal server error catcher.");
|
warn_!("Using internal server error catcher.");
|
||||||
self.catchers.get(&500).expect("500 Catcher")
|
self.catchers.get(&500).expect("500 catcher should exist!")
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(mut responder) = catcher.handle(Error::NoRoute, req).responder() {
|
if let Some(mut responder) = catcher.handle(Error::NoRoute, req).responder() {
|
||||||
|
@ -169,12 +183,129 @@ impl Rocket {
|
||||||
let catcher = self.default_catchers.get(&code.to_u16())
|
let catcher = self.default_catchers.get(&code.to_u16())
|
||||||
.unwrap_or(self.default_catchers.get(&500).expect("500 default"));
|
.unwrap_or(self.default_catchers.get(&500).expect("500 default"));
|
||||||
let responder = catcher.handle(Error::Internal, req).responder();
|
let responder = catcher.handle(Error::Internal, req).responder();
|
||||||
responder.unwrap().respond(response).unwrap()
|
responder.unwrap().respond(response).expect("default catcher failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new `Rocket` application using the configuration information in
|
||||||
|
/// `Rocket.toml`. If the file does not exist or if there is an I/O error
|
||||||
|
/// reading the file, the defaults are used. See the
|
||||||
|
/// [config](/rocket/config/index.html) documentation for more information
|
||||||
|
/// on defaults.
|
||||||
|
///
|
||||||
|
/// This method is typically called through the `rocket::ignite` alias.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// If there is an error parsing the `Rocket.toml` file, this functions
|
||||||
|
/// prints a nice error message and then exits the process.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # {
|
||||||
|
/// rocket::ignite()
|
||||||
|
/// # };
|
||||||
|
/// ```
|
||||||
|
pub fn ignite() -> Rocket {
|
||||||
|
// Note: init() will exit the process under config errors.
|
||||||
|
let (config, initted) = config::init();
|
||||||
|
if initted {
|
||||||
|
logger::init(config.log_level);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rocket::custom(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new `Rocket` application using the supplied custom
|
||||||
|
/// configuration information. Ignores the `Rocket.toml` file.
|
||||||
|
///
|
||||||
|
/// This method is typically called through the `rocket::custom` alias.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use rocket::config::{Config, Environment};
|
||||||
|
/// # use rocket::config::ConfigError;
|
||||||
|
///
|
||||||
|
/// # fn try_config() -> Result<(), ConfigError> {
|
||||||
|
/// let config = Config::default_for(Environment::active()?, "/custom")?
|
||||||
|
/// .address("1.2.3.4".into())
|
||||||
|
/// .port(9234);
|
||||||
|
///
|
||||||
|
/// let app = rocket::custom(&config);
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
pub fn custom(config: &Config) -> Rocket {
|
||||||
|
logger::init(config.log_level);
|
||||||
|
|
||||||
|
info!("🔧 Configured for {}.", config.env);
|
||||||
|
info_!("listening: {}:{}",
|
||||||
|
White.paint(&config.address),
|
||||||
|
White.paint(&config.port));
|
||||||
|
info_!("logging: {:?}", White.paint(config.log_level));
|
||||||
|
info_!("session key: {}", White.paint(config.take_session_key().is_some()));
|
||||||
|
for (name, value) in config.extras() {
|
||||||
|
info_!("{} {}: {}", Yellow.paint("[extra]"), name, White.paint(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
Rocket {
|
||||||
|
address: config.address.clone(),
|
||||||
|
port: config.port,
|
||||||
|
router: Router::new(),
|
||||||
|
default_catchers: catcher::defaults::get(),
|
||||||
|
catchers: catcher::defaults::get(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mounts all of the routes in the supplied vector at the given `base`
|
||||||
|
/// path. Mounting a route with path `path` at path `base` makes the route
|
||||||
|
/// available at `base/path`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// Use the `routes!` macro to mount routes created using the code
|
||||||
|
/// generation facilities. Requests to the `/hello/world` URI will be
|
||||||
|
/// dispatched to the `hi` route.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # #![feature(plugin)]
|
||||||
|
/// # #![plugin(rocket_codegen)]
|
||||||
|
/// # extern crate rocket;
|
||||||
|
/// #
|
||||||
|
/// #[get("/world")]
|
||||||
|
/// fn hi() -> &'static str {
|
||||||
|
/// "Hello!"
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// # if false { // We don't actually want to launch the server in an example.
|
||||||
|
/// rocket::ignite().mount("/hello", routes![hi])
|
||||||
|
/// # .launch()
|
||||||
|
/// # }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Manually create a route named `hi` at path `"/world"` mounted at base
|
||||||
|
/// `"/hello"`. Requests to the `/hello/world` URI will be dispatched to the
|
||||||
|
/// `hi` route.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use rocket::{Request, Response, Route, Data};
|
||||||
|
/// use rocket::http::Method::*;
|
||||||
|
///
|
||||||
|
/// fn hi(_: &Request, _: Data) -> Response<'static> {
|
||||||
|
/// Response::success("Hello!")
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// # if false { // We don't actually want to launch the server in an example.
|
||||||
|
/// rocket::ignite().mount("/hello", vec![Route::new(Get, "/world", hi)])
|
||||||
|
/// # :.launch()
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
pub fn mount(mut self, base: &str, routes: Vec<Route>) -> Self {
|
pub fn mount(mut self, base: &str, routes: Vec<Route>) -> Self {
|
||||||
info!("🛰 {} '{}':", Magenta.paint("Mounting"), base);
|
info!("🛰 {} '{}':", Magenta.paint("Mounting"), base);
|
||||||
for mut route in routes {
|
for mut route in routes {
|
||||||
|
@ -188,6 +319,7 @@ impl Rocket {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Registers all of the catchers in the supplied vector.
|
||||||
pub fn catch(mut self, catchers: Vec<Catcher>) -> Self {
|
pub fn catch(mut self, catchers: Vec<Catcher>) -> Self {
|
||||||
info!("👾 {}:", Magenta.paint("Catchers"));
|
info!("👾 {}:", Magenta.paint("Catchers"));
|
||||||
for c in catchers {
|
for c in catchers {
|
||||||
|
@ -204,6 +336,22 @@ impl Rocket {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Starts the application server and begins listening for and dispatching
|
||||||
|
/// requests to mounted routes and catchers.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// If the server could not be started, this method prints the reason and
|
||||||
|
/// then exits the process.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # if false {
|
||||||
|
/// rocket::ignite().launch()
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[cfg(not(feature = "testing"))]
|
||||||
pub fn launch(self) {
|
pub fn launch(self) {
|
||||||
if self.router.has_collisions() {
|
if self.router.has_collisions() {
|
||||||
warn!("Route collisions detected!");
|
warn!("Route collisions detected!");
|
||||||
|
@ -226,29 +374,4 @@ impl Rocket {
|
||||||
server.handle(self).unwrap();
|
server.handle(self).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ignite() -> Rocket {
|
|
||||||
// Note: init() will exit the process under config errors.
|
|
||||||
let (config, initted) = config::init();
|
|
||||||
if initted {
|
|
||||||
logger::init(config.log_level);
|
|
||||||
}
|
|
||||||
|
|
||||||
info!("🔧 Configured for {}.", config.env);
|
|
||||||
info_!("listening: {}:{}",
|
|
||||||
White.paint(&config.address),
|
|
||||||
White.paint(&config.port));
|
|
||||||
info_!("logging: {:?}", White.paint(config.log_level));
|
|
||||||
info_!("session key: {}", White.paint(config.take_session_key().is_some()));
|
|
||||||
for (name, value) in config.extras() {
|
|
||||||
info_!("{} {}: {}", Yellow.paint("[extra]"), name, White.paint(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
Rocket {
|
|
||||||
address: config.address.clone(),
|
|
||||||
port: config.port,
|
|
||||||
router: Router::new(),
|
|
||||||
default_catchers: catcher::defaults::get(),
|
|
||||||
catchers: catcher::defaults::get(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,17 @@ use request::Request;
|
||||||
use http::{Method, ContentType};
|
use http::{Method, ContentType};
|
||||||
use http::uri::{URI, URIBuf};
|
use http::uri::{URI, URIBuf};
|
||||||
|
|
||||||
|
/// A route: a method, its handler, path, rank, and format/content type.
|
||||||
pub struct Route {
|
pub struct Route {
|
||||||
|
/// The method this route matches against.
|
||||||
pub method: Method,
|
pub method: Method,
|
||||||
|
/// A function that should be called when the route matches.
|
||||||
pub handler: Handler,
|
pub handler: Handler,
|
||||||
|
/// The path (in Rocket format) that should be matched against.
|
||||||
pub path: URIBuf,
|
pub path: URIBuf,
|
||||||
pub rank: isize, // Lower ranks have higher priorities.
|
/// The rank of this route. Lower ranks have higher priorities.
|
||||||
|
pub rank: isize,
|
||||||
|
/// The Content-Type this route matches against.
|
||||||
pub content_type: ContentType,
|
pub content_type: ContentType,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,18 +33,10 @@ fn default_rank(path: &str) -> isize {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Route {
|
impl Route {
|
||||||
pub fn ranked<S>(rank: isize, m: Method, path: S, handler: Handler) -> Route
|
/// Creates a new route with the method, path, and handler.
|
||||||
where S: AsRef<str>
|
///
|
||||||
{
|
/// The rank of the route will be `0` if the path contains no dynamic
|
||||||
Route {
|
/// segments, and `1` if it does.
|
||||||
method: m,
|
|
||||||
path: URIBuf::from(path.as_ref()),
|
|
||||||
handler: handler,
|
|
||||||
rank: rank,
|
|
||||||
content_type: ContentType::any(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new<S>(m: Method, path: S, handler: Handler) -> Route
|
pub fn new<S>(m: Method, path: S, handler: Handler) -> Route
|
||||||
where S: AsRef<str>
|
where S: AsRef<str>
|
||||||
{
|
{
|
||||||
|
@ -51,6 +49,21 @@ impl Route {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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
|
||||||
|
where S: AsRef<str>
|
||||||
|
{
|
||||||
|
Route {
|
||||||
|
method: m,
|
||||||
|
path: URIBuf::from(path.as_ref()),
|
||||||
|
handler: handler,
|
||||||
|
rank: rank,
|
||||||
|
content_type: ContentType::any(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the path of the route. Does not update the rank or any other
|
||||||
|
/// parameters.
|
||||||
pub fn set_path<S>(&mut self, path: S)
|
pub fn set_path<S>(&mut self, path: S)
|
||||||
where S: AsRef<str>
|
where S: AsRef<str>
|
||||||
{
|
{
|
||||||
|
@ -60,6 +73,9 @@ impl Route {
|
||||||
// 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
|
||||||
// is, whether you can have: /a<a>b/ or even /<a>:<b>/
|
// is, whether you can have: /a<a>b/ or even /<a>:<b>/
|
||||||
// TODO: Don't return a Vec...take in an &mut [&'a str] (no alloc!)
|
// TODO: Don't return a Vec...take in an &mut [&'a str] (no alloc!)
|
||||||
|
/// Given a URI, returns a vector of slices of that URI corresponding to the
|
||||||
|
/// dynamic segments in this route.
|
||||||
|
#[doc(hidden)]
|
||||||
pub fn get_params<'a>(&self, uri: URI<'a>) -> Vec<&'a str> {
|
pub fn get_params<'a>(&self, uri: URI<'a>) -> Vec<&'a str> {
|
||||||
let route_segs = self.path.as_uri().segments();
|
let route_segs = self.path.as_uri().segments();
|
||||||
let uri_segs = uri.segments();
|
let uri_segs = uri.segments();
|
||||||
|
@ -113,6 +129,7 @@ impl fmt::Debug for Route {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
impl<'a> From<&'a StaticRouteInfo> for Route {
|
impl<'a> From<&'a StaticRouteInfo> for Route {
|
||||||
fn from(info: &'a StaticRouteInfo) -> Route {
|
fn from(info: &'a StaticRouteInfo) -> Route {
|
||||||
let mut route = Route::new(info.method, info.path, info.handler);
|
let mut route = Route::new(info.method, info.path, info.handler);
|
||||||
|
|
Loading…
Reference in New Issue