diff --git a/examples/configuration.rs b/examples/configuration.rs index 463f5e1f7..2ec0a29fb 100644 --- a/examples/configuration.rs +++ b/examples/configuration.rs @@ -3,7 +3,7 @@ use tide::{head::Path, ExtractConfiguration}; /// A type that represents how much value will be added by the `add` handler. -#[derive(Clone, Default)] +#[derive(Clone, Debug, Default)] struct IncreaseBy(i32); async fn add( diff --git a/src/app.rs b/src/app.rs index 4d0acbb61..968ea467a 100644 --- a/src/app.rs +++ b/src/app.rs @@ -6,6 +6,7 @@ use futures::{ use hyper::service::Service; use std::{ any::Any, + fmt::Debug, ops::{Deref, DerefMut}, sync::Arc, }; @@ -147,12 +148,12 @@ impl App { } /// Add a default configuration `item` for the whole app. - pub fn config(&mut self, item: T) -> &mut Self { + pub fn config(&mut self, item: T) -> &mut Self { self.router.config(item); self } - pub fn get_item(&self) -> Option<&T> { + pub fn get_item(&self) -> Option<&T> { self.router.get_item() } diff --git a/src/configuration/mod.rs b/src/configuration/mod.rs index 069daa00c..519648460 100644 --- a/src/configuration/mod.rs +++ b/src/configuration/mod.rs @@ -2,6 +2,7 @@ use std::any::{Any, TypeId}; use std::collections::HashMap; +use std::fmt::{self, Debug}; use futures::future::FutureObj; @@ -15,11 +16,12 @@ trait StoreItem: Any + Send + Sync { fn clone_any(&self) -> Box; fn as_dyn_any(&self) -> &(dyn Any + Send + Sync); fn as_dyn_any_mut(&mut self) -> &mut (dyn Any + Send + Sync); + fn fmt_debug(&self, fmt: &mut fmt::Formatter) -> fmt::Result; } impl StoreItem for T where - T: Any + Clone + Send + Sync, + T: Any + Debug + Clone + Send + Sync, { fn clone_any(&self) -> Box { Box::new(self.clone()) @@ -32,6 +34,10 @@ where fn as_dyn_any_mut(&mut self) -> &mut (dyn Any + Send + Sync) { self } + + fn fmt_debug(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + self.fmt(fmt) + } } impl Clone for Box { @@ -40,12 +46,24 @@ impl Clone for Box { } } +impl Debug for Box { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + (&**self).fmt_debug(fmt) + } +} + /// A cloneable typemap for saving per-endpoint configuration. /// /// Store is mostly managed by `App` and `Router`, so this is normally not used directly. #[derive(Clone)] pub struct Store(HashMap>); +impl Debug for Store { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_set().entries(self.0.values()).finish() + } +} + impl Store { pub(crate) fn new() -> Self { Store(HashMap::new()) @@ -57,7 +75,7 @@ impl Store { } /// Retrieve the configuration item of given type, returning `None` if it is not found. - pub fn read(&self) -> Option<&T> { + pub fn read(&self) -> Option<&T> { let id = TypeId::of::(); self.0 .get(&id) @@ -65,7 +83,7 @@ impl Store { } /// Save the given configuration item. - pub fn write(&mut self, value: T) { + pub fn write(&mut self, value: T) { let id = TypeId::of::(); self.0.insert(id, Box::new(value) as Box); } @@ -77,7 +95,11 @@ impl Store { /// will be `None`. pub struct ExtractConfiguration(pub Option); -impl Extract for ExtractConfiguration { +impl Extract for ExtractConfiguration +where + S: 'static, + T: Any + Debug + Clone + Send + Sync + 'static, +{ type Fut = FutureObj<'static, Result>; fn extract( diff --git a/src/middleware/mod.rs b/src/middleware/mod.rs index aee3cf77c..03434509b 100644 --- a/src/middleware/mod.rs +++ b/src/middleware/mod.rs @@ -1,9 +1,10 @@ use std::any::Any; +use std::fmt::Debug; use std::sync::Arc; use futures::future::FutureObj; -use crate::{router::EndpointData, Request, Response, RouteMatch}; +use crate::{configuration::Store, router::EndpointData, Request, Response, RouteMatch}; mod default_headers; pub mod logger; @@ -35,10 +36,18 @@ pub struct RequestContext<'a, Data> { impl<'a, Data: Clone + Send> RequestContext<'a, Data> { /// Get a configuration item of given type from the endpoint. - pub fn get_item(&self) -> Option<&T> { + pub fn get_item(&self) -> Option<&T> { self.endpoint.store.read::() } + /// Get the configuration store for this request. + /// + /// This is for debug purposes. `Store` implements `Debug`, so the store can be inspected using + /// `{:?}` formatter. + pub fn store(&self) -> &Store { + &self.endpoint.store + } + /// Consume this context, and run remaining middleware chain to completion. pub fn next(mut self) -> FutureObj<'a, Response> { if let Some((current, next)) = self.next_middleware.split_first() { diff --git a/src/router.rs b/src/router.rs index dcf959822..5168603df 100644 --- a/src/router.rs +++ b/src/router.rs @@ -1,5 +1,6 @@ use std::any::Any; use std::collections::HashMap; +use std::fmt::Debug; use std::sync::Arc; use crate::{ @@ -158,7 +159,7 @@ impl Router { /// Add a default configuration `item` for this router. /// /// The default configuration will be applied when the router setup ends. - pub fn config(&mut self, item: T) -> &mut Self { + pub fn config(&mut self, item: T) -> &mut Self { self.store_base.write(item); self } @@ -186,7 +187,7 @@ impl Router { } } - pub(crate) fn get_item(&self) -> Option<&T> { + pub(crate) fn get_item(&self) -> Option<&T> { self.store_base.read() } } @@ -201,7 +202,7 @@ pub struct EndpointData { impl EndpointData { /// Add a configuration `item` for this endpoint. - pub fn config(&mut self, item: T) -> &mut Self { + pub fn config(&mut self, item: T) -> &mut Self { self.store.write(item); self }