fix some todos

This commit is contained in:
David Pedersen
2022-07-03 20:19:21 +02:00
parent e03cea82d2
commit 7e30205205
10 changed files with 76 additions and 88 deletions
-2
View File
@@ -22,8 +22,6 @@ use tower_service::Service;
/// that handles errors by converting them into responses. /// that handles errors by converting them into responses.
/// ///
/// See [module docs](self) for more details on axum's error handling model. /// See [module docs](self) for more details on axum's error handling model.
// TODO(david): cannot access state, is that bad? It leads to inference issues and one has to
// specify the type manually and risk getting it wrong. So its basically an Extension at that point
pub struct HandleErrorLayer<F, T> { pub struct HandleErrorLayer<F, T> {
f: F, f: F,
_extractor: PhantomData<fn() -> T>, _extractor: PhantomData<fn() -> T>,
+1 -2
View File
@@ -2,8 +2,7 @@ use super::{FromRequest, RequestParts};
use async_trait::async_trait; use async_trait::async_trait;
use std::convert::Infallible; use std::convert::Infallible;
/// TODO(david): docs // document how to extract this from middleware
// TODO(david): document how to extract this from middleware
#[derive(Clone, Copy, Debug, Default)] #[derive(Clone, Copy, Debug, Default)]
pub struct State<S>(pub S); pub struct State<S>(pub S);
+2 -13
View File
@@ -1,5 +1,5 @@
use super::Handler; use super::Handler;
use crate::{extract::State, response::Response}; use crate::{response::Response, util::extract_state_assume_present};
use http::Request; use http::Request;
use std::{ use std::{
convert::Infallible, convert::Infallible,
@@ -59,18 +59,7 @@ where
let handler = self.handler.clone(); let handler = self.handler.clone();
// TODO(david): this is duplicated in `axum/src/routing/mod.rs` let state = extract_state_assume_present::<S, _>(&req);
// extract into helper function
let State(state) = req
.extensions()
.get::<State<S>>()
.unwrap_or_else(|| {
panic!(
"no state of type `{}` was found. Please file an issue",
std::any::type_name::<State<S>>()
)
})
.clone();
let future = Handler::call(handler, state, req); let future = Handler::call(handler, state, req);
let future = future.map(Ok as _); let future = future.map(Ok as _);
+8 -8
View File
@@ -64,8 +64,7 @@ pub mod future;
/// See the [module docs](crate::handler) for more details. /// See the [module docs](crate::handler) for more details.
/// ///
#[doc = include_str!("../docs/debugging_handler_type_errors.md")] #[doc = include_str!("../docs/debugging_handler_type_errors.md")]
// TODO(david): Add back `B = Body` default pub trait Handler<S, T, B = Body>: Clone + Send + Sized + 'static {
pub trait Handler<S, T, B>: Clone + Send + Sized + 'static {
/// The type of future calling this handler returns. /// The type of future calling this handler returns.
type Future: Future<Output = Response> + Send + 'static; type Future: Future<Output = Response> + Send + 'static;
@@ -151,7 +150,6 @@ pub trait Handler<S, T, B>: Clone + Send + Sized + 'static {
/// ``` /// ```
/// ///
/// [`Router::fallback`]: crate::routing::Router::fallback /// [`Router::fallback`]: crate::routing::Router::fallback
// TODO(david): remove this
fn into_service(self, state: S) -> IntoService<Self, S, T, B> { fn into_service(self, state: S) -> IntoService<Self, S, T, B> {
IntoService::new(self, state) IntoService::new(self, state)
} }
@@ -179,7 +177,6 @@ pub trait Handler<S, T, B>: Clone + Send + Sized + 'static {
/// ``` /// ```
/// ///
/// [`MakeService`]: tower::make::MakeService /// [`MakeService`]: tower::make::MakeService
// TODO(david): remove this
fn into_make_service(self, state: S) -> IntoMakeService<IntoService<Self, S, T, B>> { fn into_make_service(self, state: S) -> IntoMakeService<IntoService<Self, S, T, B>> {
IntoMakeService::new(self.into_service(state)) IntoMakeService::new(self.into_service(state))
} }
@@ -212,7 +209,6 @@ pub trait Handler<S, T, B>: Clone + Send + Sized + 'static {
/// ///
/// [`MakeService`]: tower::make::MakeService /// [`MakeService`]: tower::make::MakeService
/// [`Router::into_make_service_with_connect_info`]: crate::routing::Router::into_make_service_with_connect_info /// [`Router::into_make_service_with_connect_info`]: crate::routing::Router::into_make_service_with_connect_info
// TODO(david): remove this
fn into_make_service_with_connect_info<C>( fn into_make_service_with_connect_info<C>(
self, self,
state: S, state: S,
@@ -350,16 +346,20 @@ where
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::test_helpers::*; use crate::{extract::State, test_helpers::*};
use http::StatusCode; use http::StatusCode;
#[tokio::test] #[tokio::test]
async fn handler_into_service() { async fn handler_into_service() {
async fn handle(body: String) -> impl IntoResponse { async fn handle(State(state): State<AppState>, body: String) -> impl IntoResponse {
assert_eq!(state.0, 1337);
format!("you said: {}", body) format!("you said: {}", body)
} }
let client = TestClient::new(handle.into_service(())); #[derive(Clone)]
struct AppState(i32);
let client = TestClient::new(handle.into_service(AppState(1337)));
let res = client.post("/").body("hi there!").send().await; let res = client.post("/").body("hi there!").send().await;
assert_eq!(res.status(), StatusCode::OK); assert_eq!(res.status(), StatusCode::OK);
+2 -2
View File
@@ -382,8 +382,8 @@
rust_2018_idioms, rust_2018_idioms,
future_incompatible, future_incompatible,
nonstandard_style, nonstandard_style,
// missing_debug_implementations, missing_debug_implementations,
// missing_docs missing_docs
)] )]
#![deny(unreachable_pub, private_in_public)] #![deny(unreachable_pub, private_in_public)]
#![allow(elided_lifetimes_in_paths, clippy::type_complexity)] #![allow(elided_lifetimes_in_paths, clippy::type_complexity)]
+1 -1
View File
@@ -400,7 +400,7 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn extracting_state() { async fn extracting_state() {
async fn access_state<B>(req: Request<B>, next: Next<B>) -> impl IntoResponse { async fn access_state<B>(req: Request<B>, _next: Next<B>) -> impl IntoResponse {
let State(state) = req.extensions().get::<State<AppState>>().unwrap().clone(); let State(state) = req.extensions().get::<State<AppState>>().unwrap().clone();
state.value state.value
} }
+1 -1
View File
@@ -61,7 +61,7 @@ impl<T> From<T> for Html<T> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::extract::Extension; use crate::extract::Extension;
use crate::{body::Body, routing::get, Router}; use crate::{routing::get, Router};
use axum_core::response::IntoResponse; use axum_core::response::IntoResponse;
use http::HeaderMap; use http::HeaderMap;
use http::{StatusCode, Uri}; use http::{StatusCode, Uri};
+31 -36
View File
@@ -76,7 +76,7 @@ macro_rules! top_level_service_fn {
$name:ident, $method:ident $name:ident, $method:ident
) => { ) => {
$(#[$m])+ $(#[$m])+
pub fn $name<T, ReqBody, ResBody, S>(svc: T) -> MethodRouter<S, ReqBody, T::Error, MissingState> pub fn $name<T, ReqBody, ResBody, S>(svc: T) -> MethodRouter<S, MissingState, ReqBody, T::Error>
where where
T: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone + Send + 'static, T: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone + Send + 'static,
T::Future: Send + 'static, T::Future: Send + 'static,
@@ -137,7 +137,7 @@ macro_rules! top_level_handler_fn {
$name:ident, $method:ident $name:ident, $method:ident
) => { ) => {
$(#[$m])+ $(#[$m])+
pub fn $name<H, S, T, B>(handler: H) -> MethodRouter<S, B, Infallible, MissingState> pub fn $name<H, S, T, B>(handler: H) -> MethodRouter<S, MissingState, B, Infallible>
where where
H: Handler<S, T, B>, H: Handler<S, T, B>,
B: Send + 'static, B: Send + 'static,
@@ -321,7 +321,7 @@ top_level_service_fn!(trace_service, TRACE);
pub fn on_service<T, ReqBody, ResBody, S>( pub fn on_service<T, ReqBody, ResBody, S>(
filter: MethodFilter, filter: MethodFilter,
svc: T, svc: T,
) -> MethodRouter<S, ReqBody, T::Error, MissingState> ) -> MethodRouter<S, MissingState, ReqBody, T::Error>
where where
T: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone + Send + 'static, T: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone + Send + 'static,
T::Future: Send + 'static, T::Future: Send + 'static,
@@ -386,7 +386,7 @@ where
/// ``` /// ```
pub fn any_service<T, ReqBody, ResBody, S>( pub fn any_service<T, ReqBody, ResBody, S>(
svc: T, svc: T,
) -> MethodRouter<S, ReqBody, T::Error, MissingState> ) -> MethodRouter<S, MissingState, ReqBody, T::Error>
where where
T: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone + Send + 'static, T: Service<Request<ReqBody>, Response = Response<ResBody>> + Clone + Send + 'static,
T::Future: Send + 'static, T::Future: Send + 'static,
@@ -429,7 +429,7 @@ top_level_handler_fn!(trace, TRACE);
pub fn on<H, S, T, B>( pub fn on<H, S, T, B>(
filter: MethodFilter, filter: MethodFilter,
handler: H, handler: H,
) -> MethodRouter<S, B, Infallible, MissingState> ) -> MethodRouter<S, MissingState, B, Infallible>
where where
H: Handler<S, T, B>, H: Handler<S, T, B>,
B: Send + 'static, B: Send + 'static,
@@ -476,7 +476,7 @@ where
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); /// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
/// # }; /// # };
/// ``` /// ```
pub fn any<H, S, T, B>(handler: H) -> MethodRouter<S, B, Infallible, MissingState> pub fn any<H, S, T, B>(handler: H) -> MethodRouter<S, MissingState, B, Infallible>
where where
H: Handler<S, T, B>, H: Handler<S, T, B>,
B: Send + 'static, B: Send + 'static,
@@ -490,9 +490,7 @@ where
/// A [`Service`] that accepts requests based on a [`MethodFilter`] and /// A [`Service`] that accepts requests based on a [`MethodFilter`] and
/// allows chaining additional handlers and services. /// allows chaining additional handlers and services.
// TODO(david): Bring back `B = Body, E = Infallible` defaults pub struct MethodRouter<S, R = MissingState, B = Body, E = Infallible> {
// TODO(david): think about ordering of type params here
pub struct MethodRouter<S, B, E, R> {
// Invariant: If `R == MissingState` then `state` is `None` // Invariant: If `R == MissingState` then `state` is `None`
// If `R == WithState` then state is `Some` // If `R == WithState` then state is `Some`
// `R` cannot have other values // `R` cannot have other values
@@ -520,7 +518,7 @@ enum AllowHeader {
Bytes(BytesMut), Bytes(BytesMut),
} }
impl<S, B, E, R> fmt::Debug for MethodRouter<S, B, E, R> impl<S, B, E, R> fmt::Debug for MethodRouter<S, R, B, E>
where where
S: fmt::Debug, S: fmt::Debug,
{ {
@@ -540,7 +538,7 @@ where
} }
} }
impl<S, B, E> MethodRouter<S, B, E, MissingState> { impl<S, B, E> MethodRouter<S, MissingState, B, E> {
/// Create a default `MethodRouter` that will respond with `405 Method Not Allowed` to all /// Create a default `MethodRouter` that will respond with `405 Method Not Allowed` to all
/// requests. /// requests.
pub fn new() -> Self { pub fn new() -> Self {
@@ -566,8 +564,7 @@ impl<S, B, E> MethodRouter<S, B, E, MissingState> {
} }
} }
/// TODO(david): docs pub fn state(self, state: S) -> MethodRouter<S, WithState, B, E> {
pub fn state(self, state: S) -> MethodRouter<S, B, E, WithState> {
MethodRouter { MethodRouter {
state: Some(state), state: Some(state),
get: self.get, get: self.get,
@@ -585,21 +582,19 @@ impl<S, B, E> MethodRouter<S, B, E, MissingState> {
} }
} }
impl<S, B, E> MethodRouter<S, B, E, WithState> { impl<S, B, E> MethodRouter<S, WithState, B, E> {
/// TODO(david): docs
pub fn with_state(state: S) -> Self { pub fn with_state(state: S) -> Self {
MethodRouter::new().state(state) MethodRouter::new().state(state)
} }
} }
impl<B, E> MethodRouter<(), B, E, WithState> { impl<B, E> MethodRouter<(), WithState, B, E> {
/// TODO(david): docs
pub fn without_state() -> Self { pub fn without_state() -> Self {
MethodRouter::with_state(()) MethodRouter::with_state(())
} }
} }
impl<S, B, R> MethodRouter<S, B, Infallible, R> impl<S, B, R> MethodRouter<S, R, B, Infallible>
where where
B: Send + 'static, B: Send + 'static,
S: Clone + Send + Sync + 'static, S: Clone + Send + Sync + 'static,
@@ -645,7 +640,7 @@ where
chained_handler_fn!(trace, TRACE); chained_handler_fn!(trace, TRACE);
#[doc = include_str!("../docs/routing/fallback.md")] #[doc = include_str!("../docs/routing/fallback.md")]
pub fn fallback<H, T>(mut self, handler: H) -> Self pub fn fallback<H, T>(self, handler: H) -> Self
where where
H: Handler<S, T, B>, H: Handler<S, T, B>,
T: 'static, T: 'static,
@@ -654,8 +649,8 @@ where
} }
} }
impl<S, B, R> MethodRouter<S, B, Infallible, R> { impl<S, B, R> MethodRouter<S, R, B, Infallible> {
pub(crate) fn change_state_marker<R2>(self) -> MethodRouter<S, B, Infallible, R2> { pub(crate) fn change_state_marker<R2>(self) -> MethodRouter<S, R2, B, Infallible> {
MethodRouter { MethodRouter {
state: self.state, state: self.state,
get: self.get, get: self.get,
@@ -673,8 +668,8 @@ impl<S, B, R> MethodRouter<S, B, Infallible, R> {
} }
} }
impl<S, B> MethodRouter<S, B, Infallible, MissingState> { impl<S, B> MethodRouter<S, MissingState, B, Infallible> {
pub(crate) fn change_state<S2>(self) -> MethodRouter<S2, B, Infallible, MissingState> { pub(crate) fn change_state<S2>(self) -> MethodRouter<S2, MissingState, B, Infallible> {
debug_assert!(self.state.is_none()); debug_assert!(self.state.is_none());
MethodRouter { MethodRouter {
state: None, state: None,
@@ -693,7 +688,7 @@ impl<S, B> MethodRouter<S, B, Infallible, MissingState> {
} }
} }
impl<S, B> MethodRouter<S, B, Infallible, WithState> impl<S, B> MethodRouter<S, WithState, B, Infallible>
where where
B: Send + 'static, B: Send + 'static,
S: Clone + Send + Sync + 'static, S: Clone + Send + Sync + 'static,
@@ -767,7 +762,7 @@ where
} }
} }
impl<S, B, E, R> MethodRouter<S, B, E, R> { impl<S, B, E, R> MethodRouter<S, R, B, E> {
/// Chain an additional service that will accept requests matching the given /// Chain an additional service that will accept requests matching the given
/// `MethodFilter`. /// `MethodFilter`.
/// ///
@@ -837,7 +832,7 @@ impl<S, B, E, R> MethodRouter<S, B, E, R> {
pub fn layer<L, NewReqBody, NewResBody, NewError>( pub fn layer<L, NewReqBody, NewResBody, NewError>(
self, self,
layer: L, layer: L,
) -> MethodRouter<S, NewReqBody, NewError, R> ) -> MethodRouter<S, R, NewReqBody, NewError>
where where
L: Layer<Route<B, E>>, L: Layer<Route<B, E>>,
L::Service: Service<Request<NewReqBody>, Response = Response<NewResBody>, Error = NewError> L::Service: Service<Request<NewReqBody>, Response = Response<NewResBody>, Error = NewError>
@@ -872,7 +867,7 @@ impl<S, B, E, R> MethodRouter<S, B, E, R> {
} }
#[doc = include_str!("../docs/method_routing/route_layer.md")] #[doc = include_str!("../docs/method_routing/route_layer.md")]
pub fn route_layer<L, NewResBody>(self, layer: L) -> MethodRouter<S, B, E, R> pub fn route_layer<L, NewResBody>(self, layer: L) -> MethodRouter<S, R, B, E>
where where
L: Layer<Route<B, E>>, L: Layer<Route<B, E>>,
L::Service: Service<Request<B>, Response = Response<NewResBody>, Error = E> L::Service: Service<Request<B>, Response = Response<NewResBody>, Error = E>
@@ -907,7 +902,7 @@ impl<S, B, E, R> MethodRouter<S, B, E, R> {
} }
#[doc = include_str!("../docs/method_routing/merge.md")] #[doc = include_str!("../docs/method_routing/merge.md")]
pub fn merge(self, other: MethodRouter<S, B, E, MissingState>) -> Self { pub fn merge(self, other: MethodRouter<S, MissingState, B, E>) -> Self {
macro_rules! merge { macro_rules! merge {
( $first:ident, $second:ident ) => { ( $first:ident, $second:ident ) => {
match ($first, $second) { match ($first, $second) {
@@ -1003,7 +998,7 @@ impl<S, B, E, R> MethodRouter<S, B, E, R> {
/// Apply a [`HandleErrorLayer`]. /// Apply a [`HandleErrorLayer`].
/// ///
/// This is a convenience method for doing `self.layer(HandleErrorLayer::new(f))`. /// This is a convenience method for doing `self.layer(HandleErrorLayer::new(f))`.
pub fn handle_error<F, T>(self, f: F) -> MethodRouter<S, B, Infallible, R> pub fn handle_error<F, T>(self, f: F) -> MethodRouter<S, R, B, Infallible>
where where
F: Clone + Send + 'static, F: Clone + Send + 'static,
HandleError<Route<B, E>, F, T>: HandleError<Route<B, E>, F, T>:
@@ -1120,7 +1115,7 @@ fn append_allow_header(allow_header: &mut AllowHeader, method: &'static str) {
} }
} }
impl<S, B, E, R> Clone for MethodRouter<S, B, E, R> impl<S, B, E, R> Clone for MethodRouter<S, R, B, E>
where where
S: Clone, S: Clone,
{ {
@@ -1142,7 +1137,7 @@ where
} }
} }
impl<S, B, E> Default for MethodRouter<S, B, E, MissingState> impl<S, B, E> Default for MethodRouter<S, MissingState, B, E>
where where
B: Send + 'static, B: Send + 'static,
{ {
@@ -1151,7 +1146,7 @@ where
} }
} }
impl<S, B, E> Service<Request<B>> for MethodRouter<S, B, E, WithState> impl<S, B, E> Service<Request<B>> for MethodRouter<S, WithState, B, E>
where where
B: HttpBody, B: HttpBody,
S: Clone + Send + Sync + 'static, S: Clone + Send + Sync + 'static,
@@ -1430,7 +1425,7 @@ mod tests {
expected = "Overlapping method route. Cannot add two method routes that both handle `GET`" expected = "Overlapping method route. Cannot add two method routes that both handle `GET`"
)] )]
async fn handler_overlaps() { async fn handler_overlaps() {
let _: MethodRouter<(), Body, Infallible, _> = get(ok).get(ok); let _: MethodRouter<(), _, Body, Infallible> = get(ok).get(ok);
} }
#[tokio::test] #[tokio::test]
@@ -1438,18 +1433,18 @@ mod tests {
expected = "Overlapping method route. Cannot add two method routes that both handle `POST`" expected = "Overlapping method route. Cannot add two method routes that both handle `POST`"
)] )]
async fn service_overlaps() { async fn service_overlaps() {
let _: MethodRouter<(), Body, Infallible, _> = let _: MethodRouter<(), _, Body, Infallible> =
post_service(ok.into_service(())).post_service(ok.into_service(())); post_service(ok.into_service(())).post_service(ok.into_service(()));
} }
#[tokio::test] #[tokio::test]
async fn get_head_does_not_overlap() { async fn get_head_does_not_overlap() {
let _: MethodRouter<(), Body, Infallible, _> = get(ok).head(ok); let _: MethodRouter<(), _, Body, Infallible> = get(ok).head(ok);
} }
#[tokio::test] #[tokio::test]
async fn head_get_does_not_overlap() { async fn head_get_does_not_overlap() {
let _: MethodRouter<(), Body, Infallible, _> = head(ok).get(ok); let _: MethodRouter<(), _, Body, Infallible> = head(ok).get(ok);
} }
async fn call<S>(method: Method, svc: &mut S) -> (StatusCode, HeaderMap, String) async fn call<S>(method: Method, svc: &mut S) -> (StatusCode, HeaderMap, String)
+6 -23
View File
@@ -7,7 +7,7 @@ use crate::{
handler::{Handler, IntoExtensionService}, handler::{Handler, IntoExtensionService},
response::Response, response::Response,
routing::strip_prefix::StripPrefix, routing::strip_prefix::StripPrefix,
util::try_downcast, util::{extract_state_assume_present, try_downcast},
BoxError, BoxError,
}; };
use http::Request; use http::Request;
@@ -207,23 +207,9 @@ where
_marker: PhantomData, _marker: PhantomData,
} }
.layer(MapRequestLayer::new(move |mut req: Request<_>| { .layer(MapRequestLayer::new(move |mut req: Request<_>| {
// TODO(david): this is duplicated in `axum/src/handler/into_extension_service.rs` let outer_state = extract_state_assume_present::<OuterState, _>(&req);
// extract into helper function
let State(outer_state) = req
.extensions()
.get::<State<OuterState>>()
.unwrap_or_else(|| {
panic!(
"no state of type `{}` was found. Please file an issue",
std::any::type_name::<State<OuterState>>()
)
})
.clone();
let inner_state = f(outer_state); let inner_state = f(outer_state);
req.extensions_mut().insert(State(inner_state)); req.extensions_mut().insert(State(inner_state));
req req
})) }))
} }
@@ -234,7 +220,6 @@ where
B: HttpBody + Send + 'static, B: HttpBody + Send + 'static,
S: Clone, S: Clone,
{ {
/// TODO(david): docs
pub fn with_state(state: S) -> Self { pub fn with_state(state: S) -> Self {
Router::new().state(state) Router::new().state(state)
} }
@@ -244,7 +229,6 @@ impl<B> Router<(), WithState, B>
where where
B: HttpBody + Send + 'static, B: HttpBody + Send + 'static,
{ {
/// TODO(david): docs
pub fn without_state() -> Self { pub fn without_state() -> Self {
Router::with_state(()) Router::with_state(())
} }
@@ -262,7 +246,7 @@ where
path: &str, path: &str,
// TODO(david): constrain this so it only accepts methods // TODO(david): constrain this so it only accepts methods
// routers containing handlers // routers containing handlers
method_router: MethodRouter<S, B, Infallible, MissingState>, method_router: MethodRouter<S, MissingState, B, Infallible>,
) -> Self { ) -> Self {
validate_path_for_route(path); validate_path_for_route(path);
@@ -301,7 +285,6 @@ where
} }
} }
/// TODO(david): docs
pub fn route_service<T>(mut self, path: &str, service: T) -> Self pub fn route_service<T>(mut self, path: &str, service: T) -> Self
where where
T: Service<Request<B>, Response = Response, Error = Infallible> + Clone + Send + 'static, T: Service<Request<B>, Response = Response, Error = Infallible> + Clone + Send + 'static,
@@ -530,8 +513,9 @@ where
} }
} }
// TODO(david): update docs
#[doc = include_str!("../docs/routing/fallback.md")] #[doc = include_str!("../docs/routing/fallback.md")]
pub fn fallback<H, T>(mut self, handler: H) -> Self pub fn fallback<H, T>(self, handler: H) -> Self
where where
H: Handler<S, T, B>, H: Handler<S, T, B>,
T: 'static, T: 'static,
@@ -540,7 +524,6 @@ where
self.fallback_service(IntoExtensionService::new(handler)) self.fallback_service(IntoExtensionService::new(handler))
} }
/// TODO(david): docs
pub fn fallback_service<T>(mut self, svc: T) -> Self pub fn fallback_service<T>(mut self, svc: T) -> Self
where where
T: Service<Request<B>, Response = Response, Error = Infallible> + Clone + Send + 'static, T: Service<Request<B>, Response = Response, Error = Infallible> + Clone + Send + 'static,
@@ -786,7 +769,7 @@ impl<B, E> Fallback<B, E> {
} }
enum Endpoint<S, R, B> { enum Endpoint<S, R, B> {
MethodRouter(MethodRouter<S, B, Infallible, R>), MethodRouter(MethodRouter<S, R, B, Infallible>),
Route(Route<B>), Route(Route<B>),
} }
+24
View File
@@ -1,6 +1,9 @@
use http::Request;
use pin_project_lite::pin_project; use pin_project_lite::pin_project;
use std::{ops::Deref, sync::Arc}; use std::{ops::Deref, sync::Arc};
use crate::extract::State;
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub(crate) struct PercentDecodedStr(Arc<str>); pub(crate) struct PercentDecodedStr(Arc<str>);
@@ -54,6 +57,27 @@ where
} }
} }
/// Extract the state from request extensions and panic if its not there.
///
/// This should only be called after `Router::call` or `MethodRouter::call` have been called.
pub(crate) fn extract_state_assume_present<S, B>(req: &Request<B>) -> S
where
S: Clone + Send + Sync + 'static,
{
let State(state) = req
.extensions()
.get::<State<S>>()
.unwrap_or_else(|| {
panic!(
"no state of type `{}` was found. Please file an issue",
std::any::type_name::<State<S>>()
)
})
.clone();
state
}
#[test] #[test]
fn test_try_downcast() { fn test_try_downcast() {
assert_eq!(try_downcast::<i32, _>(5_u32), Err(5_u32)); assert_eq!(try_downcast::<i32, _>(5_u32), Err(5_u32));