From 982997dbad1d206783d052741547c1531bc9905a Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Wed, 5 Apr 2017 01:19:33 -0700 Subject: [PATCH] Add Rocket::routes() method to get all routes. Add some internal benchmarks. --- lib/benches/format-routing.rs | 58 ++++++++++++++++++ lib/benches/ranked-routing.rs | 73 ++++++++++++++++++++++ lib/benches/simple-routing.rs | 112 ++++++++++++++++++++++++++++++++++ lib/src/rocket.rs | 6 ++ lib/src/router/mod.rs | 5 ++ 5 files changed, 254 insertions(+) create mode 100644 lib/benches/format-routing.rs create mode 100644 lib/benches/ranked-routing.rs create mode 100644 lib/benches/simple-routing.rs diff --git a/lib/benches/format-routing.rs b/lib/benches/format-routing.rs new file mode 100644 index 00000000..a10d0880 --- /dev/null +++ b/lib/benches/format-routing.rs @@ -0,0 +1,58 @@ +#![feature(test, plugin)] +#![plugin(rocket_codegen)] + +extern crate rocket; + +use rocket::config::{Environment, Config}; +use rocket::http::RawStr; + +#[get("/", format = "application/json")] +fn get() -> &'static str { "get" } + +#[post("/", format = "application/json")] +fn post() -> &'static str { "post" } + +fn rocket() -> rocket::Rocket { + let config = Config::new(Environment::Production).unwrap(); + rocket::custom(config, false) + .mount("/", routes![get, post]) +} + +#[cfg(feature = "testing")] +mod benches { + extern crate test; + + use super::rocket; + use self::test::Bencher; + use rocket::testing::MockRequest; + use rocket::http::Method::*; + use rocket::http::{Accept, ContentType}; + + #[bench] + fn accept_format(b: &mut Bencher) { + let rocket = rocket(); + let mut request = MockRequest::new(Get, "/").header(Accept::JSON); + b.iter(|| { request.dispatch_with(&rocket); }); + } + + #[bench] + fn wrong_accept_format(b: &mut Bencher) { + let rocket = rocket(); + let mut request = MockRequest::new(Get, "/").header(Accept::HTML); + b.iter(|| { request.dispatch_with(&rocket); }); + } + + #[bench] + fn content_type_format(b: &mut Bencher) { + let rocket = rocket(); + let mut request = MockRequest::new(Post, "/").header(ContentType::JSON); + b.iter(|| { request.dispatch_with(&rocket); }); + } + + #[bench] + fn wrong_content_type_format(b: &mut Bencher) { + let rocket = rocket(); + let mut request = MockRequest::new(Post, "/").header(ContentType::Plain); + b.iter(|| { request.dispatch_with(&rocket); }); + } +} diff --git a/lib/benches/ranked-routing.rs b/lib/benches/ranked-routing.rs new file mode 100644 index 00000000..d1d44503 --- /dev/null +++ b/lib/benches/ranked-routing.rs @@ -0,0 +1,73 @@ +#![feature(test, plugin)] +#![plugin(rocket_codegen)] + +extern crate rocket; + +use rocket::config::{Environment, Config}; +use rocket::http::RawStr; + +#[get("/", format = "application/json")] +fn get() -> &'static str { "json" } + +#[get("/", format = "text/html")] +fn get2() -> &'static str { "html" } + +#[get("/", format = "text/plain")] +fn get3() -> &'static str { "plain" } + +#[post("/", format = "application/json")] +fn post() -> &'static str { "json" } + +#[post("/", format = "text/html")] +fn post2() -> &'static str { "html" } + +#[post("/", format = "text/plain")] +fn post3() -> &'static str { "plain" } + +fn rocket() -> rocket::Rocket { + let config = Config::new(Environment::Production).unwrap(); + rocket::custom(config, false) + .mount("/", routes![get, get2, get3]) + .mount("/", routes![post, post2, post3]) +} + +#[cfg(feature = "testing")] +mod benches { + extern crate test; + + use super::rocket; + use self::test::Bencher; + use rocket::testing::MockRequest; + use rocket::http::Method::*; + use rocket::http::{Accept, ContentType}; + + #[bench] + fn accept_format(b: &mut Bencher) { + let rocket = rocket(); + let mut requests = vec![]; + requests.push(MockRequest::new(Get, "/").header(Accept::JSON)); + requests.push(MockRequest::new(Get, "/").header(Accept::HTML)); + requests.push(MockRequest::new(Get, "/").header(Accept::Plain)); + + b.iter(|| { + for request in requests.iter_mut() { + request.dispatch_with(&rocket); + } + }); + } + + #[bench] + fn content_type_format(b: &mut Bencher) { + let rocket = rocket(); + let mut requests = vec![]; + requests.push(MockRequest::new(Post, "/").header(ContentType::JSON)); + requests.push(MockRequest::new(Post, "/").header(ContentType::HTML)); + requests.push(MockRequest::new(Post, "/").header(ContentType::Plain)); + + b.iter(|| { + for request in requests.iter_mut() { + request.dispatch_with(&rocket); + } + }); + } +} diff --git a/lib/benches/simple-routing.rs b/lib/benches/simple-routing.rs new file mode 100644 index 00000000..6363a7b7 --- /dev/null +++ b/lib/benches/simple-routing.rs @@ -0,0 +1,112 @@ +#![feature(test, plugin)] +#![plugin(rocket_codegen)] + +extern crate rocket; + +use rocket::config::{Environment, Config}; +use rocket::http::RawStr; + +#[get("/")] +fn get_index() -> &'static str { "index" } + +#[put("/")] +fn put_index() -> &'static str { "index" } + +#[post("/")] +fn post_index() -> &'static str { "index" } + +#[get("/a")] +fn index_a() -> &'static str { "index" } + +#[get("/b")] +fn index_b() -> &'static str { "index" } + +#[get("/c")] +fn index_c() -> &'static str { "index" } + +#[get("/")] +fn index_dyn_a(a: &RawStr) -> &'static str { "index" } + +fn rocket() -> rocket::Rocket { + let config = Config::new(Environment::Production).unwrap(); + rocket::custom(config, false) + .mount("/", routes![get_index, put_index, post_index, index_a, + index_b, index_c, index_dyn_a]) +} + +#[cfg(feature = "testing")] +mod benches { + extern crate test; + + use super::rocket; + use self::test::Bencher; + use rocket::testing::MockRequest; + use rocket::http::Method::*; + + #[bench] + fn bench_single_get_index(b: &mut Bencher) { + let rocket = rocket(); + let mut request = MockRequest::new(Get, "/"); + + b.iter(|| { + request.dispatch_with(&rocket); + }); + } + + #[bench] + fn bench_get_put_post_index(b: &mut Bencher) { + let rocket = rocket(); + + // Hold all of the requests we're going to make during the benchmark. + let mut requests = vec![]; + requests.push(MockRequest::new(Get, "/")); + requests.push(MockRequest::new(Put, "/")); + requests.push(MockRequest::new(Post, "/")); + + b.iter(|| { + for request in requests.iter_mut() { + request.dispatch_with(&rocket); + } + }); + } + + #[bench] + fn bench_dynamic(b: &mut Bencher) { + let rocket = rocket(); + + // Hold all of the requests we're going to make during the benchmark. + let mut requests = vec![]; + requests.push(MockRequest::new(Get, "/abc")); + requests.push(MockRequest::new(Get, "/abcdefg")); + requests.push(MockRequest::new(Get, "/123")); + + b.iter(|| { + for request in requests.iter_mut() { + request.dispatch_with(&rocket); + } + }); + } + + #[bench] + fn bench_simple_routing(b: &mut Bencher) { + let rocket = rocket(); + + // Hold all of the requests we're going to make during the benchmark. + let mut requests = vec![]; + for route in rocket.routes() { + let request = MockRequest::new(route.method, route.path.path()); + requests.push(request); + } + + // A few more for the dynamic route. + requests.push(MockRequest::new(Get, "/abc")); + requests.push(MockRequest::new(Get, "/abcdefg")); + requests.push(MockRequest::new(Get, "/123")); + + b.iter(|| { + for request in requests.iter_mut() { + request.dispatch_with(&rocket); + } + }); + } +} diff --git a/lib/src/rocket.rs b/lib/src/rocket.rs index fe4fa4d5..22734ea6 100644 --- a/lib/src/rocket.rs +++ b/lib/src/rocket.rs @@ -570,4 +570,10 @@ impl Rocket { unreachable!("the call to `handle_threads` should block on success") } + + /// Retrieves all of the mounted routes. + #[inline(always)] + pub fn routes<'a>(&'a self) -> impl Iterator + 'a { + self.router.routes() + } } diff --git a/lib/src/router/mod.rs b/lib/src/router/mod.rs index 48495630..39dcd3eb 100644 --- a/lib/src/router/mod.rs +++ b/lib/src/router/mod.rs @@ -59,6 +59,11 @@ impl Router { result } + + #[inline] + pub fn routes<'a>(&'a self) -> impl Iterator + 'a { + self.routes.values().flat_map(|v| v.iter()) + } } #[cfg(test)]