1
0
mirror of https://github.com/fafhrd91/actix-web synced 2024-11-24 00:21:08 +01:00

rename State to a Data

This commit is contained in:
Nikolay Kim 2019-03-16 20:17:27 -07:00
parent d93fe157b9
commit b1e267bce4
4 changed files with 74 additions and 75 deletions

View File

@ -12,6 +12,7 @@ use futures::IntoFuture;
use crate::app_service::{AppChain, AppEntry, AppInit, AppRouting, AppRoutingFactory};
use crate::config::{AppConfig, AppConfigInner};
use crate::data::{Data, DataFactory};
use crate::dev::{PayloadStream, ResourceDef};
use crate::error::Error;
use crate::resource::Resource;
@ -20,7 +21,6 @@ use crate::service::{
HttpServiceFactory, ServiceFactory, ServiceFactoryWrapper, ServiceRequest,
ServiceResponse,
};
use crate::state::{State, StateFactory};
type HttpNewService<P> =
BoxedNewService<(), ServiceRequest<P>, ServiceResponse, Error, ()>;
@ -32,18 +32,17 @@ where
T: NewService<Request = ServiceRequest, Response = ServiceRequest<P>>,
{
chain: T,
state: Vec<Box<StateFactory>>,
data: Vec<Box<DataFactory>>,
config: AppConfigInner,
_t: PhantomData<(P,)>,
}
impl App<PayloadStream, AppChain> {
/// Create application builder with empty state. Application can
/// be configured with a builder-like pattern.
/// Create application builder. Application can be configured with a builder-like pattern.
pub fn new() -> Self {
App {
chain: AppChain,
state: Vec::new(),
data: Vec::new(),
config: AppConfigInner::default(),
_t: PhantomData,
}
@ -60,51 +59,51 @@ where
InitError = (),
>,
{
/// Set application state. Applicatin state could be accessed
/// by using `State<T>` extractor where `T` is state type.
/// Set application data. Applicatin data could be accessed
/// by using `Data<T>` extractor where `T` is data type.
///
/// **Note**: http server accepts an application factory rather than
/// an application instance. Http server constructs an application
/// instance for each thread, thus application state must be constructed
/// multiple times. If you want to share state between different
/// instance for each thread, thus application data must be constructed
/// multiple times. If you want to share data between different
/// threads, a shared object should be used, e.g. `Arc`. Application
/// state does not need to be `Send` or `Sync`.
/// data does not need to be `Send` or `Sync`.
///
/// ```rust
/// use std::cell::Cell;
/// use actix_web::{web, App};
///
/// struct MyState {
/// struct MyData {
/// counter: Cell<usize>,
/// }
///
/// fn index(state: web::State<MyState>) {
/// state.counter.set(state.counter.get() + 1);
/// fn index(data: web::Data<MyData>) {
/// data.counter.set(data.counter.get() + 1);
/// }
///
/// fn main() {
/// let app = App::new()
/// .state(MyState{ counter: Cell::new(0) })
/// .data(MyData{ counter: Cell::new(0) })
/// .service(
/// web::resource("/index.html").route(
/// web::get().to(index)));
/// }
/// ```
pub fn state<S: 'static>(mut self, state: S) -> Self {
self.state.push(Box::new(State::new(state)));
pub fn data<S: 'static>(mut self, data: S) -> Self {
self.data.push(Box::new(Data::new(data)));
self
}
/// Set application state factory. This function is
/// similar to `.state()` but it accepts state factory. State get
/// Set application data factory. This function is
/// similar to `.data()` but it accepts data factory. Data object get
/// constructed asynchronously during application initialization.
pub fn state_factory<F, Out>(mut self, state: F) -> Self
pub fn data_factory<F, Out>(mut self, data: F) -> Self
where
F: Fn() -> Out + 'static,
Out: IntoFuture + 'static,
Out::Error: std::fmt::Debug,
{
self.state.push(Box::new(state));
self.data.push(Box::new(data));
self
}
@ -138,7 +137,7 @@ where
AppRouter {
endpoint,
chain: self.chain,
state: self.state,
data: self.data,
services: Vec::new(),
default: None,
factory_ref: fref,
@ -174,7 +173,7 @@ where
let chain = self.chain.and_then(chain.into_new_service());
App {
chain,
state: self.state,
data: self.data,
config: self.config,
_t: PhantomData,
}
@ -183,7 +182,7 @@ where
/// Configure route for a specific path.
///
/// This is a simplified version of the `App::service()` method.
/// This method can not be could multiple times, in that case
/// This method can be used multiple times with same path, in that case
/// multiple resources with one route would be registered for same resource path.
///
/// ```rust
@ -223,7 +222,7 @@ where
default: None,
endpoint: AppEntry::new(fref.clone()),
factory_ref: fref,
state: self.state,
data: self.data,
config: self.config,
services: vec![Box::new(ServiceFactoryWrapper::new(service))],
external: Vec::new(),
@ -233,7 +232,7 @@ where
/// Set server host name.
///
/// Host name is used by application router aa a hostname for url
/// Host name is used by application router as a hostname for url
/// generation. Check [ConnectionInfo](./dev/struct.ConnectionInfo.
/// html#method.host) documentation for more information.
///
@ -252,7 +251,7 @@ pub struct AppRouter<C, P, B, T> {
services: Vec<Box<ServiceFactory<P>>>,
default: Option<Rc<HttpNewService<P>>>,
factory_ref: Rc<RefCell<Option<AppRoutingFactory<P>>>>,
state: Vec<Box<StateFactory>>,
data: Vec<Box<DataFactory>>,
config: AppConfigInner,
external: Vec<ResourceDef>,
_t: PhantomData<(P, B)>,
@ -344,7 +343,7 @@ where
AppRouter {
endpoint,
chain: self.chain,
state: self.state,
data: self.data,
services: self.services,
default: self.default,
factory_ref: self.factory_ref,
@ -429,7 +428,7 @@ where
fn into_new_service(self) -> AppInit<C, T, P, B> {
AppInit {
chain: self.chain,
state: self.state,
data: self.data,
endpoint: self.endpoint,
services: RefCell::new(self.services),
external: RefCell::new(self.external),
@ -489,10 +488,10 @@ mod tests {
}
#[test]
fn test_state() {
fn test_data() {
let mut srv =
init_service(App::new().state(10usize).service(
web::resource("/").to(|_: web::State<usize>| HttpResponse::Ok()),
init_service(App::new().data(10usize).service(
web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok()),
));
let req = TestRequest::default().to_request();
@ -500,8 +499,8 @@ mod tests {
assert_eq!(resp.status(), StatusCode::OK);
let mut srv =
init_service(App::new().state(10u32).service(
web::resource("/").to(|_: web::State<usize>| HttpResponse::Ok()),
init_service(App::new().data(10u32).service(
web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok()),
));
let req = TestRequest::default().to_request();
let resp = block_on(srv.call(req)).unwrap();
@ -509,18 +508,18 @@ mod tests {
}
#[test]
fn test_state_factory() {
fn test_data_factory() {
let mut srv =
init_service(App::new().state_factory(|| Ok::<_, ()>(10usize)).service(
web::resource("/").to(|_: web::State<usize>| HttpResponse::Ok()),
init_service(App::new().data_factory(|| Ok::<_, ()>(10usize)).service(
web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok()),
));
let req = TestRequest::default().to_request();
let resp = block_on(srv.call(req)).unwrap();
assert_eq!(resp.status(), StatusCode::OK);
let mut srv =
init_service(App::new().state_factory(|| Ok::<_, ()>(10u32)).service(
web::resource("/").to(|_: web::State<usize>| HttpResponse::Ok()),
init_service(App::new().data_factory(|| Ok::<_, ()>(10u32)).service(
web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok()),
));
let req = TestRequest::default().to_request();
let resp = block_on(srv.call(req)).unwrap();

View File

@ -11,11 +11,11 @@ use futures::future::{ok, Either, FutureResult};
use futures::{Async, Future, Poll};
use crate::config::{AppConfig, ServiceConfig};
use crate::data::{DataFactory, DataFactoryResult};
use crate::error::Error;
use crate::guard::Guard;
use crate::rmap::ResourceMap;
use crate::service::{ServiceFactory, ServiceRequest, ServiceResponse};
use crate::state::{StateFactory, StateFactoryResult};
type Guards = Vec<Box<Guard>>;
type HttpService<P> = BoxedService<ServiceRequest<P>, ServiceResponse, Error>;
@ -24,7 +24,7 @@ type HttpNewService<P> =
type BoxedResponse = Box<Future<Item = ServiceResponse, Error = Error>>;
/// Service factory to convert `Request` to a `ServiceRequest<S>`.
/// It also executes state factories.
/// It also executes data factories.
pub struct AppInit<C, T, P, B>
where
C: NewService<Request = ServiceRequest, Response = ServiceRequest<P>>,
@ -37,7 +37,7 @@ where
{
pub(crate) chain: C,
pub(crate) endpoint: T,
pub(crate) state: Vec<Box<StateFactory>>,
pub(crate) data: Vec<Box<DataFactory>>,
pub(crate) config: RefCell<AppConfig>,
pub(crate) services: RefCell<Vec<Box<ServiceFactory<P>>>>,
pub(crate) default: Option<Rc<HttpNewService<P>>>,
@ -121,7 +121,7 @@ where
chain_fut: self.chain.new_service(&()),
endpoint: None,
endpoint_fut: self.endpoint.new_service(&()),
state: self.state.iter().map(|s| s.construct()).collect(),
data: self.data.iter().map(|s| s.construct()).collect(),
config: self.config.borrow().clone(),
rmap,
_t: PhantomData,
@ -139,7 +139,7 @@ where
chain_fut: C::Future,
endpoint_fut: T::Future,
rmap: Rc<ResourceMap>,
state: Vec<Box<StateFactoryResult>>,
data: Vec<Box<DataFactoryResult>>,
config: AppConfig,
_t: PhantomData<(P, B)>,
}
@ -165,9 +165,9 @@ where
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let mut idx = 0;
let mut extensions = self.config.0.extensions.borrow_mut();
while idx < self.state.len() {
if let Async::Ready(_) = self.state[idx].poll_result(&mut extensions)? {
self.state.remove(idx);
while idx < self.data.len() {
if let Async::Ready(_) = self.data[idx].poll_result(&mut extensions)? {
self.data.remove(idx);
} else {
idx += 1;
}

View File

@ -8,21 +8,21 @@ use futures::{Async, Future, IntoFuture, Poll};
use crate::extract::FromRequest;
use crate::service::ServiceFromRequest;
/// Application state factory
pub(crate) trait StateFactory {
fn construct(&self) -> Box<StateFactoryResult>;
/// Application data factory
pub(crate) trait DataFactory {
fn construct(&self) -> Box<DataFactoryResult>;
}
pub(crate) trait StateFactoryResult {
pub(crate) trait DataFactoryResult {
fn poll_result(&mut self, extensions: &mut Extensions) -> Poll<(), ()>;
}
/// Application state
pub struct State<T>(Arc<T>);
pub struct Data<T>(Arc<T>);
impl<T> State<T> {
pub(crate) fn new(state: T) -> State<T> {
State(Arc::new(state))
impl<T> Data<T> {
pub(crate) fn new(state: T) -> Data<T> {
Data(Arc::new(state))
}
/// Get referecnce to inner state type.
@ -31,7 +31,7 @@ impl<T> State<T> {
}
}
impl<T> Deref for State<T> {
impl<T> Deref for Data<T> {
type Target = T;
fn deref(&self) -> &T {
@ -39,19 +39,19 @@ impl<T> Deref for State<T> {
}
}
impl<T> Clone for State<T> {
fn clone(&self) -> State<T> {
State(self.0.clone())
impl<T> Clone for Data<T> {
fn clone(&self) -> Data<T> {
Data(self.0.clone())
}
}
impl<T: 'static, P> FromRequest<P> for State<T> {
impl<T: 'static, P> FromRequest<P> for Data<T> {
type Error = Error;
type Future = Result<Self, Error>;
#[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
if let Some(st) = req.config().extensions().get::<State<T>>() {
if let Some(st) = req.config().extensions().get::<Data<T>>() {
Ok(st.clone())
} else {
Err(ErrorInternalServerError(
@ -61,37 +61,37 @@ impl<T: 'static, P> FromRequest<P> for State<T> {
}
}
impl<T: 'static> StateFactory for State<T> {
fn construct(&self) -> Box<StateFactoryResult> {
Box::new(StateFut { st: self.clone() })
impl<T: 'static> DataFactory for Data<T> {
fn construct(&self) -> Box<DataFactoryResult> {
Box::new(DataFut { st: self.clone() })
}
}
struct StateFut<T> {
st: State<T>,
struct DataFut<T> {
st: Data<T>,
}
impl<T: 'static> StateFactoryResult for StateFut<T> {
impl<T: 'static> DataFactoryResult for DataFut<T> {
fn poll_result(&mut self, extensions: &mut Extensions) -> Poll<(), ()> {
extensions.insert(self.st.clone());
Ok(Async::Ready(()))
}
}
impl<F, Out> StateFactory for F
impl<F, Out> DataFactory for F
where
F: Fn() -> Out + 'static,
Out: IntoFuture + 'static,
Out::Error: std::fmt::Debug,
{
fn construct(&self) -> Box<StateFactoryResult> {
Box::new(StateFactoryFut {
fn construct(&self) -> Box<DataFactoryResult> {
Box::new(DataFactoryFut {
fut: (*self)().into_future(),
})
}
}
struct StateFactoryFut<T, F>
struct DataFactoryFut<T, F>
where
F: Future<Item = T>,
F::Error: std::fmt::Debug,
@ -99,7 +99,7 @@ where
fut: F,
}
impl<T: 'static, F> StateFactoryResult for StateFactoryFut<T, F>
impl<T: 'static, F> DataFactoryResult for DataFactoryFut<T, F>
where
F: Future<Item = T>,
F::Error: std::fmt::Debug,
@ -107,7 +107,7 @@ where
fn poll_result(&mut self, extensions: &mut Extensions) -> Poll<(), ()> {
match self.fut.poll() {
Ok(Async::Ready(s)) => {
extensions.insert(State::new(s));
extensions.insert(Data::new(s));
Ok(Async::Ready(()))
}
Ok(Async::NotReady) => Ok(Async::NotReady),

View File

@ -3,6 +3,7 @@
mod app;
mod app_service;
mod config;
mod data;
pub mod error;
mod extract;
pub mod guard;
@ -17,7 +18,6 @@ mod route;
mod scope;
mod server;
mod service;
mod state;
pub mod test;
#[allow(unused_imports)]
@ -37,7 +37,6 @@ pub use crate::request::HttpRequest;
pub use crate::resource::Resource;
pub use crate::responder::{Either, Responder};
pub use crate::route::Route;
pub use crate::scope::Scope;
pub use crate::server::HttpServer;
pub mod dev {
@ -77,6 +76,7 @@ pub mod dev {
}
pub mod web {
//! Various types
use actix_http::{http::Method, Response};
use actix_rt::blocking;
use futures::{Future, IntoFuture};
@ -91,11 +91,11 @@ pub mod web {
use crate::route::Route;
use crate::scope::Scope;
pub use crate::data::Data;
pub use crate::error::{BlockingError, Error};
pub use crate::extract::{Form, Json, Path, Payload, Query};
pub use crate::extract::{FormConfig, JsonConfig, PayloadConfig};
pub use crate::request::HttpRequest;
pub use crate::state::State;
/// Create resource for a specific path.
///