Skip to content

Commit

Permalink
Change Router::with_state and impl Service for Router<()> (#1552)
Browse files Browse the repository at this point in the history
* Implement `Service` for `Router<(), B>`

* wip

* wip

* fix some tests

* fix examples

* fix doc tests

* clean up docs

* changelog

* fix

* also call `with_state` when converting `MethodRouter` into a `MakeService`

* suggestions from review
  • Loading branch information
davidpdrsn committed Nov 24, 2022
1 parent fde38f6 commit 0b26411
Show file tree
Hide file tree
Showing 45 changed files with 504 additions and 666 deletions.
2 changes: 1 addition & 1 deletion axum-extra/src/extract/cookie/private.rs
Expand Up @@ -68,7 +68,7 @@ use std::{convert::Infallible, fmt, marker::PhantomData};
/// .route("/set", post(set_secret))
/// .route("/get", get(get_secret))
/// .with_state(state);
/// # let _: axum::routing::RouterService = app;
/// # let _: axum::Router = app;
/// ```
///
/// If you have been using `Arc<AppState>` you cannot implement `FromRef<Arc<AppState>> for Key`.
Expand Down
2 changes: 1 addition & 1 deletion axum-extra/src/extract/cookie/signed.rs
Expand Up @@ -86,7 +86,7 @@ use std::{convert::Infallible, fmt, marker::PhantomData};
/// .route("/sessions", post(create_session))
/// .route("/me", get(me))
/// .with_state(state);
/// # let _: axum::routing::RouterService = app;
/// # let _: axum::Router = app;
/// ```
/// If you have been using `Arc<AppState>` you cannot implement `FromRef<Arc<AppState>> for Key`.
/// You can use a new type instead:
Expand Down
6 changes: 3 additions & 3 deletions axum-extra/src/routing/resource.rs
Expand Up @@ -147,7 +147,7 @@ impl<B> From<Resource<B>> for Router<B> {
mod tests {
#[allow(unused_imports)]
use super::*;
use axum::{extract::Path, http::Method, routing::RouterService, Router};
use axum::{extract::Path, http::Method, Router};
use http::Request;
use tower::{Service, ServiceExt};

Expand All @@ -162,7 +162,7 @@ mod tests {
.update(|Path(id): Path<u64>| async move { format!("users#update id={}", id) })
.destroy(|Path(id): Path<u64>| async move { format!("users#destroy id={}", id) });

let mut app = Router::new().merge(users).into_service();
let mut app = Router::new().merge(users);

assert_eq!(
call_route(&mut app, Method::GET, "/users").await,
Expand Down Expand Up @@ -205,7 +205,7 @@ mod tests {
);
}

async fn call_route(app: &mut RouterService, method: Method, uri: &str) -> String {
async fn call_route(app: &mut Router, method: Method, uri: &str) -> String {
let res = app
.ready()
.await
Expand Down
2 changes: 1 addition & 1 deletion axum-extra/src/routing/spa.rs
Expand Up @@ -270,7 +270,7 @@ mod tests {

#[allow(dead_code)]
fn works_with_router_with_state() {
let _: axum::RouterService = Router::new()
let _: Router = Router::new()
.merge(SpaRouter::new("/assets", "test_files"))
.route("/", get(|_: axum::extract::State<String>| async {}))
.with_state(String::new());
Expand Down
2 changes: 1 addition & 1 deletion axum-macros/src/lib.rs
Expand Up @@ -606,7 +606,7 @@ pub fn derive_typed_path(input: TokenStream) -> TokenStream {
/// let app = Router::new()
/// .route("/", get(handler).post(other_handler))
/// .with_state(state);
/// # let _: axum::routing::RouterService = app;
/// # let _: axum::Router = app;
/// ```
///
/// [`FromRef`]: https://docs.rs/axum/latest/axum/extract/trait.FromRef.html
Expand Down
2 changes: 1 addition & 1 deletion axum-macros/tests/from_ref/pass/basic.rs
Expand Up @@ -14,7 +14,7 @@ fn main() {
auth_token: Default::default(),
};

let _: axum::routing::RouterService = Router::new()
let _: axum::Router = Router::new()
.route("/", get(handler))
.with_state(state);
}
2 changes: 1 addition & 1 deletion axum-macros/tests/from_request/pass/state_enum_via.rs
Expand Up @@ -6,7 +6,7 @@ use axum::{
use axum_macros::FromRequest;

fn main() {
let _: axum::routing::RouterService = Router::new()
let _: axum::Router = Router::new()
.route("/a", get(|_: AppState| async {}))
.route("/b", get(|_: InnerState| async {}))
.with_state(AppState::default());
Expand Down
Expand Up @@ -6,7 +6,7 @@ use axum::{
use axum_macros::FromRequestParts;

fn main() {
let _: axum::routing::RouterService = Router::new()
let _: axum::Router = Router::new()
.route("/a", get(|_: AppState| async {}))
.route("/b", get(|_: InnerState| async {}))
.route("/c", get(|_: AppState, _: InnerState| async {}))
Expand Down
2 changes: 1 addition & 1 deletion axum-macros/tests/from_request/pass/state_explicit.rs
Expand Up @@ -6,7 +6,7 @@ use axum::{
};

fn main() {
let _: axum::routing::RouterService = Router::new()
let _: axum::Router = Router::new()
.route("/b", get(|_: Extractor| async {}))
.with_state(AppState::default());
}
Expand Down
Expand Up @@ -7,7 +7,7 @@ use axum::{
use std::collections::HashMap;

fn main() {
let _: axum::routing::RouterService = Router::new()
let _: axum::Router = Router::new()
.route("/b", get(|_: Extractor| async {}))
.with_state(AppState::default());
}
Expand Down
Expand Up @@ -6,7 +6,7 @@ use axum::{
use axum_macros::FromRequest;

fn main() {
let _: axum::routing::RouterService = Router::new()
let _: axum::Router = Router::new()
.route("/", get(|_: Extractor| async {}))
.with_state(AppState::default());
}
Expand Down
2 changes: 1 addition & 1 deletion axum-macros/tests/from_request/pass/state_field_infer.rs
Expand Up @@ -6,7 +6,7 @@ use axum::{
use axum_macros::FromRequest;

fn main() {
let _: axum::routing::RouterService = Router::new()
let _: axum::Router = Router::new()
.route("/", get(|_: Extractor| async {}))
.with_state(AppState::default());
}
Expand Down
2 changes: 1 addition & 1 deletion axum-macros/tests/from_request/pass/state_via.rs
Expand Up @@ -6,7 +6,7 @@ use axum::{
use axum_macros::FromRequest;

fn main() {
let _: axum::routing::RouterService = Router::new()
let _: axum::Router = Router::new()
.route("/b", get(|_: (), _: AppState| async {}))
.route("/c", get(|_: (), _: InnerState| async {}))
.with_state(AppState::default());
Expand Down
2 changes: 1 addition & 1 deletion axum-macros/tests/from_request/pass/state_via_infer.rs
Expand Up @@ -6,7 +6,7 @@ use axum::{
use axum_macros::FromRequest;

fn main() {
let _: axum::routing::RouterService = Router::new()
let _: axum::Router = Router::new()
.route("/b", get(|_: AppState| async {}))
.with_state(AppState::default());
}
Expand Down
2 changes: 1 addition & 1 deletion axum-macros/tests/from_request/pass/state_via_parts.rs
Expand Up @@ -6,7 +6,7 @@ use axum::{
use axum_macros::FromRequestParts;

fn main() {
let _: axum::routing::RouterService = Router::new()
let _: axum::Router = Router::new()
.route("/a", get(|_: AppState, _: InnerState, _: String| async {}))
.route("/b", get(|_: AppState, _: String| async {}))
.route("/c", get(|_: InnerState, _: String| async {}))
Expand Down
Expand Up @@ -8,7 +8,7 @@ use axum::{
use axum_macros::FromRequest;

fn main() {
let _: axum::routing::RouterService = Router::new()
let _: axum::Router = Router::new()
.route("/a", get(|_: Extractor| async {}))
.with_state(AppState::default());
}
Expand Down
6 changes: 4 additions & 2 deletions axum/CHANGELOG.md
Expand Up @@ -7,9 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

# Unreleased

- **added:** Add `RouterService::{layer, route_layer}` ([#1550])
- **breaking:** `RouterService` has been removed since `Router` now implements
`Service` when the state is `()`. Use `Router::with_state` to provide the
state and get a `Router<()>` ([#1552])

[#1550]: https://github.com/tokio-rs/axum/pull/1550
[#1552]: https://github.com/tokio-rs/axum/pull/1552

# 0.6.0-rc.5 (18. November, 2022)

Expand Down
43 changes: 16 additions & 27 deletions axum/benches/benches.rs
@@ -1,7 +1,7 @@
use axum::{
extract::State,
routing::{get, post},
Extension, Json, Router, RouterService, Server,
Extension, Json, Router, Server,
};
use hyper::server::conn::AddrIncoming;
use serde::{Deserialize, Serialize};
Expand All @@ -17,13 +17,9 @@ fn main() {
ensure_rewrk_is_installed();
}

benchmark("minimal").run(|| Router::new().into_service());
benchmark("minimal").run(Router::new);

benchmark("basic").run(|| {
Router::new()
.route("/", get(|| async { "Hello, World!" }))
.into_service()
});
benchmark("basic").run(|| Router::new().route("/", get(|| async { "Hello, World!" })));

benchmark("routing").path("/foo/bar/baz").run(|| {
let mut app = Router::new();
Expand All @@ -34,32 +30,26 @@ fn main() {
}
}
}
app.route("/foo/bar/baz", get(|| async {})).into_service()
app.route("/foo/bar/baz", get(|| async {}))
});

benchmark("receive-json")
.method("post")
.headers(&[("content-type", "application/json")])
.body(r#"{"n": 123, "s": "hi there", "b": false}"#)
.run(|| {
Router::new()
.route("/", post(|_: Json<Payload>| async {}))
.into_service()
});
.run(|| Router::new().route("/", post(|_: Json<Payload>| async {})));

benchmark("send-json").run(|| {
Router::new()
.route(
"/",
get(|| async {
Json(Payload {
n: 123,
s: "hi there".to_owned(),
b: false,
})
}),
)
.into_service()
Router::new().route(
"/",
get(|| async {
Json(Payload {
n: 123,
s: "hi there".to_owned(),
b: false,
})
}),
)
});

let state = AppState {
Expand All @@ -75,7 +65,6 @@ fn main() {
Router::new()
.route("/", get(|_: Extension<AppState>| async {}))
.layer(Extension(state.clone()))
.into_service()
});

benchmark("state").run(|| {
Expand Down Expand Up @@ -133,7 +122,7 @@ impl BenchmarkBuilder {

fn run<F>(self, f: F)
where
F: FnOnce() -> RouterService,
F: FnOnce() -> Router<()>,
{
// support only running some benchmarks with
// ```
Expand Down
51 changes: 45 additions & 6 deletions axum/src/boxed.rs
@@ -1,6 +1,14 @@
use std::{convert::Infallible, fmt};

use crate::{body::HttpBody, handler::Handler, routing::Route, Router};
use http::Request;
use tower::Service;

use crate::{
body::HttpBody,
handler::Handler,
routing::{future::RouteFuture, Route},
Router,
};

pub(crate) struct BoxedIntoRoute<S, B, E>(Box<dyn ErasedIntoRoute<S, B, E>>);

Expand All @@ -13,6 +21,7 @@ where
where
H: Handler<T, S, B>,
T: 'static,
B: HttpBody,
{
Self(Box::new(MakeErasedHandler {
handler,
Expand All @@ -30,6 +39,14 @@ where
into_route: |router, state| Route::new(router.with_state(state)),
}))
}

pub(crate) fn call_with_state(
self,
request: Request<B>,
state: S,
) -> RouteFuture<B, Infallible> {
self.0.call_with_state(request, state)
}
}

impl<S, B, E> BoxedIntoRoute<S, B, E> {
Expand All @@ -39,7 +56,7 @@ impl<S, B, E> BoxedIntoRoute<S, B, E> {
B: 'static,
E: 'static,
F: FnOnce(Route<B, E>) -> Route<B2, E2> + Clone + Send + 'static,
B2: 'static,
B2: HttpBody + 'static,
E2: 'static,
{
BoxedIntoRoute(Box::new(Map {
Expand Down Expand Up @@ -69,6 +86,8 @@ pub(crate) trait ErasedIntoRoute<S, B, E>: Send {
fn clone_box(&self) -> Box<dyn ErasedIntoRoute<S, B, E>>;

fn into_route(self: Box<Self>, state: S) -> Route<B, E>;

fn call_with_state(self: Box<Self>, request: Request<B>, state: S) -> RouteFuture<B, E>;
}

pub(crate) struct MakeErasedHandler<H, S, B> {
Expand All @@ -80,7 +99,7 @@ impl<H, S, B> ErasedIntoRoute<S, B, Infallible> for MakeErasedHandler<H, S, B>
where
H: Clone + Send + 'static,
S: 'static,
B: 'static,
B: HttpBody + 'static,
{
fn clone_box(&self) -> Box<dyn ErasedIntoRoute<S, B, Infallible>> {
Box::new(self.clone())
Expand All @@ -89,6 +108,14 @@ where
fn into_route(self: Box<Self>, state: S) -> Route<B> {
(self.into_route)(self.handler, state)
}

fn call_with_state(
self: Box<Self>,
request: Request<B>,
state: S,
) -> RouteFuture<B, Infallible> {
self.into_route(state).call(request)
}
}

impl<H, S, B> Clone for MakeErasedHandler<H, S, B>
Expand All @@ -110,8 +137,8 @@ pub(crate) struct MakeErasedRouter<S, B> {

impl<S, B> ErasedIntoRoute<S, B, Infallible> for MakeErasedRouter<S, B>
where
S: Clone + Send + 'static,
B: 'static,
S: Clone + Send + Sync + 'static,
B: HttpBody + Send + 'static,
{
fn clone_box(&self) -> Box<dyn ErasedIntoRoute<S, B, Infallible>> {
Box::new(self.clone())
Expand All @@ -120,6 +147,14 @@ where
fn into_route(self: Box<Self>, state: S) -> Route<B> {
(self.into_route)(self.router, state)
}

fn call_with_state(
mut self: Box<Self>,
request: Request<B>,
state: S,
) -> RouteFuture<B, Infallible> {
self.router.call_with_state(request, state)
}
}

impl<S, B> Clone for MakeErasedRouter<S, B>
Expand All @@ -144,7 +179,7 @@ where
S: 'static,
B: 'static,
E: 'static,
B2: 'static,
B2: HttpBody + 'static,
E2: 'static,
{
fn clone_box(&self) -> Box<dyn ErasedIntoRoute<S, B2, E2>> {
Expand All @@ -157,6 +192,10 @@ where
fn into_route(self: Box<Self>, state: S) -> Route<B2, E2> {
(self.layer)(self.inner.into_route(state))
}

fn call_with_state(self: Box<Self>, request: Request<B2>, state: S) -> RouteFuture<B2, E2> {
(self.layer)(self.inner.into_route(state)).call(request)
}
}

pub(crate) trait LayerFn<B, E, B2, E2>: FnOnce(Route<B, E>) -> Route<B2, E2> + Send {
Expand Down

0 comments on commit 0b26411

Please sign in to comment.