mirror of https://github.com/fafhrd91/actix-web
Add DataRaw type.
This commit is contained in:
parent
ace98e3a1e
commit
29b6c77067
11
src/app.rs
11
src/app.rs
|
@ -12,7 +12,7 @@ use futures::{Future, IntoFuture};
|
||||||
|
|
||||||
use crate::app_service::{AppEntry, AppInit, AppRoutingFactory};
|
use crate::app_service::{AppEntry, AppInit, AppRoutingFactory};
|
||||||
use crate::config::{AppConfig, AppConfigInner, ServiceConfig};
|
use crate::config::{AppConfig, AppConfigInner, ServiceConfig};
|
||||||
use crate::data::{Data, DataFactory};
|
use crate::data::{AppData, Data, DataFactory, DataRaw};
|
||||||
use crate::dev::ResourceDef;
|
use crate::dev::ResourceDef;
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::resource::Resource;
|
use crate::resource::Resource;
|
||||||
|
@ -104,6 +104,11 @@ where
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn data_raw<U: Send + Sync + Clone + 'static>(mut self, data: U) -> Self {
|
||||||
|
self.data.push(Box::new(DataRaw::new(data)));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Set application data factory. This function is
|
/// Set application data factory. This function is
|
||||||
/// similar to `.data()` but it accepts data factory. Data object get
|
/// similar to `.data()` but it accepts data factory. Data object get
|
||||||
/// constructed asynchronously during application initialization.
|
/// constructed asynchronously during application initialization.
|
||||||
|
@ -130,8 +135,8 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set application data. Application data could be accessed
|
/// Set application data. Application data could be accessed
|
||||||
/// by using `Data<T>` extractor where `T` is data type.
|
/// by using `Data<T>`or `DataRaw<T>` extractor where `T` is data type.
|
||||||
pub fn register_data<U: 'static>(mut self, data: Data<U>) -> Self {
|
pub fn register_data<U: AppData + Clone + 'static>(mut self, data: U) -> Self {
|
||||||
self.data.push(Box::new(data));
|
self.data.push(Box::new(data));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use actix_http::Extensions;
|
||||||
use actix_router::ResourceDef;
|
use actix_router::ResourceDef;
|
||||||
use actix_service::{boxed, IntoNewService, NewService};
|
use actix_service::{boxed, IntoNewService, NewService};
|
||||||
|
|
||||||
use crate::data::{Data, DataFactory};
|
use crate::data::{AppData, Data, DataFactory, DataRaw};
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::guard::Guard;
|
use crate::guard::Guard;
|
||||||
use crate::resource::Resource;
|
use crate::resource::Resource;
|
||||||
|
@ -197,6 +197,16 @@ impl ServiceConfig {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set raw application data. Raw application data could be accessed
|
||||||
|
/// by using `DataRaw<T>` extractor where `T` is data type.
|
||||||
|
/// T must be `Send + Sync + Clone` in order to be register as `DataRaw`
|
||||||
|
///
|
||||||
|
/// This is same as `App::data_raw()` method.
|
||||||
|
pub fn data_raw<U: Send + Sync + Clone + 'static>(&mut self, data: U) -> &mut Self {
|
||||||
|
self.data.push(Box::new(DataRaw::new(data)));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Configure route for a specific path.
|
/// Configure route for a specific path.
|
||||||
///
|
///
|
||||||
/// This is same as `App::route()` method.
|
/// This is same as `App::route()` method.
|
||||||
|
@ -241,6 +251,8 @@ impl ServiceConfig {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use actix_service::Service;
|
use actix_service::Service;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
|
|
||||||
|
@ -264,6 +276,21 @@ mod tests {
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_data_raw() {
|
||||||
|
let cfg = |cfg: &mut ServiceConfig| {
|
||||||
|
cfg.data_raw(Arc::new(Mutex::new(10usize)));
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut srv =
|
||||||
|
init_service(App::new().configure(cfg).service(
|
||||||
|
web::resource("/").to(|_: web::DataRaw<Arc<Mutex<usize>>>| HttpResponse::Ok()),
|
||||||
|
));
|
||||||
|
let req = TestRequest::default().to_request();
|
||||||
|
let resp = block_on(srv.call(req)).unwrap();
|
||||||
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
|
}
|
||||||
|
|
||||||
// #[test]
|
// #[test]
|
||||||
// fn test_data_factory() {
|
// fn test_data_factory() {
|
||||||
// let cfg = |cfg: &mut ServiceConfig| {
|
// let cfg = |cfg: &mut ServiceConfig| {
|
||||||
|
|
191
src/data.rs
191
src/data.rs
|
@ -13,6 +13,21 @@ pub(crate) trait DataFactory {
|
||||||
fn create(&self, extensions: &mut Extensions) -> bool;
|
fn create(&self, extensions: &mut Extensions) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// AppData is a trait generic over `Data<T>` and `DataRaw<T>`.
|
||||||
|
/// A type impl this trait can use `FromRequest` and `DataFactory` to extract and push data to extension
|
||||||
|
pub trait AppData {
|
||||||
|
type Data;
|
||||||
|
type Inner;
|
||||||
|
/// Create new `Data` instance.
|
||||||
|
fn new(state: Self::Data) -> Self;
|
||||||
|
|
||||||
|
/// Get reference to inner app data.
|
||||||
|
fn get_ref(&self) -> &Self::Data;
|
||||||
|
|
||||||
|
/// Convert to the internal Data.
|
||||||
|
fn into_inner(self) -> Self::Inner;
|
||||||
|
}
|
||||||
|
|
||||||
/// Application data.
|
/// Application data.
|
||||||
///
|
///
|
||||||
/// Application data is an arbitrary data attached to the app.
|
/// Application data is an arbitrary data attached to the app.
|
||||||
|
@ -37,7 +52,7 @@ pub(crate) trait DataFactory {
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use std::sync::Mutex;
|
/// use std::sync::Mutex;
|
||||||
/// use actix_web::{web, App};
|
/// use actix_web::{web::{self, AppData}, App};
|
||||||
///
|
///
|
||||||
/// struct MyData {
|
/// struct MyData {
|
||||||
/// counter: usize,
|
/// counter: usize,
|
||||||
|
@ -63,27 +78,6 @@ pub(crate) trait DataFactory {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Data<T>(Arc<T>);
|
pub struct Data<T>(Arc<T>);
|
||||||
|
|
||||||
impl<T> Data<T> {
|
|
||||||
/// Create new `Data` instance.
|
|
||||||
///
|
|
||||||
/// Internally `Data` type uses `Arc`. if your data implements
|
|
||||||
/// `Send` + `Sync` traits you can use `web::Data::new()` and
|
|
||||||
/// avoid double `Arc`.
|
|
||||||
pub fn new(state: T) -> Data<T> {
|
|
||||||
Data(Arc::new(state))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get reference to inner app data.
|
|
||||||
pub fn get_ref(&self) -> &T {
|
|
||||||
self.0.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convert to the internal Arc<T>
|
|
||||||
pub fn into_inner(self) -> Arc<T> {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Deref for Data<T> {
|
impl<T> Deref for Data<T> {
|
||||||
type Target = T;
|
type Target = T;
|
||||||
|
|
||||||
|
@ -98,7 +92,99 @@ impl<T> Clone for Data<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> FromRequest for Data<T> {
|
impl<T> AppData for Data<T> {
|
||||||
|
type Data = T;
|
||||||
|
type Inner = Arc<T>;
|
||||||
|
fn new(state: Self::Data) -> Self {
|
||||||
|
Data(Arc::new(state))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_ref(&self) -> &Self::Data {
|
||||||
|
self.0.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_inner(self) -> Self::Inner {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Raw Application data.
|
||||||
|
///
|
||||||
|
/// Raw Application data shares the same principle of Application data.
|
||||||
|
/// The difference is Raw Application data explicitly require the data type to be `Send + Sync + Clone`.
|
||||||
|
///
|
||||||
|
/// This is useful when you introduce a foreign type(from other crates for example) that is already thread safe.
|
||||||
|
/// By using Raw Application data you can avoid the additional layer of `Arc` provided by `web::Data`
|
||||||
|
/// ```rust
|
||||||
|
/// use std::sync::{Arc, Mutex};
|
||||||
|
/// use actix_web::{web::{self, AppData}, App};
|
||||||
|
///
|
||||||
|
/// struct ForeignType {
|
||||||
|
/// inner: Arc<Mutex<usize>>
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl Clone for ForeignType {
|
||||||
|
/// fn clone(&self) -> Self {
|
||||||
|
/// ForeignType {
|
||||||
|
/// inner: self.inner.clone()
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// /// Use `DataRaw<T>` extractor to access data in handler.
|
||||||
|
/// fn index(data: web::DataRaw<ForeignType>) {
|
||||||
|
/// let mut data = data.inner.lock().unwrap();
|
||||||
|
/// *data += 1;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let data = ForeignType {
|
||||||
|
/// inner: Arc::new(Mutex::new(1usize))
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// let app = App::new()
|
||||||
|
/// // Store `ForeignTypeType` in application storage.
|
||||||
|
/// .data_raw(data.clone())
|
||||||
|
/// .service(
|
||||||
|
/// web::resource("/index.html").route(
|
||||||
|
/// web::get().to(index)));
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DataRaw<T: Send + Sync + Clone>(T);
|
||||||
|
|
||||||
|
impl<T: Send + Sync + Clone> Clone for DataRaw<T> {
|
||||||
|
fn clone(&self) -> DataRaw<T> {
|
||||||
|
DataRaw(self.0.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Send + Sync + Clone> Deref for DataRaw<T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &T {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> AppData for DataRaw<T>
|
||||||
|
where T: Send + Sync + Clone {
|
||||||
|
type Data = T;
|
||||||
|
type Inner = T;
|
||||||
|
fn new(state: Self::Data) -> Self {
|
||||||
|
DataRaw(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_ref(&self) -> &Self::Data {
|
||||||
|
&*self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_inner(self) -> Self::Inner {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: AppData + Clone + 'static> FromRequest for T {
|
||||||
type Config = ();
|
type Config = ();
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
type Future = Result<Self, Error>;
|
type Future = Result<Self, Error>;
|
||||||
|
@ -120,10 +206,10 @@ impl<T: 'static> FromRequest for Data<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> DataFactory for Data<T> {
|
impl<T: AppData + Clone + 'static> DataFactory for T {
|
||||||
fn create(&self, extensions: &mut Extensions) -> bool {
|
fn create(&self, extensions: &mut Extensions) -> bool {
|
||||||
if !extensions.contains::<Data<T>>() {
|
if !extensions.contains::<T>() {
|
||||||
extensions.insert(Data(self.0.clone()));
|
extensions.insert(self.clone());
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
|
@ -133,6 +219,9 @@ impl<T: 'static> DataFactory for Data<T> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use std::sync::Mutex;
|
||||||
|
use std::sync::atomic::{AtomicUsize, AtomicU32};
|
||||||
|
|
||||||
use actix_service::Service;
|
use actix_service::Service;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -223,4 +312,54 @@ mod tests {
|
||||||
let resp = block_on(srv.call(req)).unwrap();
|
let resp = block_on(srv.call(req)).unwrap();
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_data_raw_extractor() {
|
||||||
|
let mut srv =
|
||||||
|
init_service(App::new().data_raw(Arc::new(Mutex::new(1usize))).service(
|
||||||
|
web::resource("/").to(|_: web::DataRaw<Arc<Mutex<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().data_raw(Arc::new(AtomicUsize::new(1))).service(
|
||||||
|
web::resource("/").to(|_: web::DataRaw<Arc<AtomicUsize>>| 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().data_raw(Arc::new(AtomicUsize::new(1))).service(
|
||||||
|
web::resource("/").to(|_: web::DataRaw<Arc<AtomicU32>>| HttpResponse::Ok()),
|
||||||
|
));
|
||||||
|
let req = TestRequest::default().to_request();
|
||||||
|
let resp = block_on(srv.call(req)).unwrap();
|
||||||
|
assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_register_data_raw_extractor() {
|
||||||
|
let mut srv =
|
||||||
|
init_service(App::new().register_data(DataRaw::new(Arc::new(AtomicUsize::new(1)))).service(
|
||||||
|
web::resource("/").to(|_: web::DataRaw<Arc<AtomicUsize>>| 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().register_data(DataRaw::new(Arc::new(AtomicUsize::new(1)))).service(
|
||||||
|
web::resource("/").to(|_: web::DataRaw<Arc<AtomicU32>>| HttpResponse::Ok()),
|
||||||
|
));
|
||||||
|
let req = TestRequest::default().to_request();
|
||||||
|
let resp = block_on(srv.call(req)).unwrap();
|
||||||
|
assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -218,8 +218,8 @@ impl HttpRequest {
|
||||||
|
|
||||||
/// Get an application data stored with `App::data()` method during
|
/// Get an application data stored with `App::data()` method during
|
||||||
/// application configuration.
|
/// application configuration.
|
||||||
pub fn get_app_data<T: 'static>(&self) -> Option<Data<T>> {
|
pub fn get_app_data<T: Clone + 'static>(&self) -> Option<T> {
|
||||||
if let Some(st) = self.0.app_data.get::<Data<T>>() {
|
if let Some(st) = self.0.app_data.get::<T>() {
|
||||||
Some(st.clone())
|
Some(st.clone())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
|
@ -10,7 +10,7 @@ use actix_service::{
|
||||||
use futures::future::{ok, Either, FutureResult};
|
use futures::future::{ok, Either, FutureResult};
|
||||||
use futures::{Async, Future, IntoFuture, Poll};
|
use futures::{Async, Future, IntoFuture, Poll};
|
||||||
|
|
||||||
use crate::data::Data;
|
use crate::data::{AppData, Data, DataRaw};
|
||||||
use crate::dev::{insert_slash, AppService, HttpServiceFactory, ResourceDef};
|
use crate::dev::{insert_slash, AppService, HttpServiceFactory, ResourceDef};
|
||||||
use crate::extract::FromRequest;
|
use crate::extract::FromRequest;
|
||||||
use crate::guard::Guard;
|
use crate::guard::Guard;
|
||||||
|
@ -193,13 +193,19 @@ where
|
||||||
self.register_data(Data::new(data))
|
self.register_data(Data::new(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The same usage as `Resource::data` method.
|
||||||
|
/// The difference is the `U` must be `Send + Sync + Clone` in order to register as `DataRaw`
|
||||||
|
pub fn data_raw<U: Send + Sync + Clone + 'static>(self, data: U) -> Self {
|
||||||
|
self.register_data(DataRaw::new(data))
|
||||||
|
}
|
||||||
|
|
||||||
/// Set or override application data.
|
/// Set or override application data.
|
||||||
///
|
///
|
||||||
/// This method has the same effect as [`Resource::data`](#method.data),
|
/// This method has the same effect as [`Resource::data`](#method.data),
|
||||||
/// except that instead of taking a value of some type `T`, it expects a
|
/// except that instead of taking a value of some type `T`, it expects a
|
||||||
/// value of type `Data<T>`. Use a `Data<T>` extractor to retrieve its
|
/// value of type `Data<T>` or `DataRaw<T>`. Use a `Data<T>` or `DataRaw<T>`
|
||||||
/// value.
|
/// extractor to retrieve its value.
|
||||||
pub fn register_data<U: 'static>(mut self, data: Data<U>) -> Self {
|
pub fn register_data<U: AppData + 'static>(mut self, data: U) -> Self {
|
||||||
if self.data.is_none() {
|
if self.data.is_none() {
|
||||||
self.data = Some(Extensions::new());
|
self.data = Some(Extensions::new());
|
||||||
}
|
}
|
||||||
|
@ -608,11 +614,13 @@ impl NewService for ResourceEndpoint {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use actix_service::Service;
|
use actix_service::Service;
|
||||||
use futures::{Future, IntoFuture};
|
use futures::{Future, IntoFuture};
|
||||||
use tokio_timer::sleep;
|
use tokio_timer::sleep;
|
||||||
|
|
||||||
|
use crate::data::AppData;
|
||||||
use crate::http::{header, HeaderValue, Method, StatusCode};
|
use crate::http::{header, HeaderValue, Method, StatusCode};
|
||||||
use crate::service::{ServiceRequest, ServiceResponse};
|
use crate::service::{ServiceRequest, ServiceResponse};
|
||||||
use crate::test::{call_service, init_service, TestRequest};
|
use crate::test::{call_service, init_service, TestRequest};
|
||||||
|
@ -803,4 +811,34 @@ mod tests {
|
||||||
let resp = call_service(&mut srv, req);
|
let resp = call_service(&mut srv, req);
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_data_raw() {
|
||||||
|
let mut srv = init_service(
|
||||||
|
App::new()
|
||||||
|
.data_raw(Arc::new(Mutex::new(1.0f64)))
|
||||||
|
.data_raw(Arc::new(Mutex::new(1usize)))
|
||||||
|
.register_data(web::DataRaw::new(Arc::new(Mutex::new('-'))))
|
||||||
|
.service(
|
||||||
|
web::resource("/test")
|
||||||
|
.data_raw(Arc::new(Mutex::new(10usize)))
|
||||||
|
.register_data(web::DataRaw::new(Arc::new(Mutex::new('*'))))
|
||||||
|
.guard(guard::Get())
|
||||||
|
.to(
|
||||||
|
|data1: web::DataRaw<Arc<Mutex<usize>>>,
|
||||||
|
data2: web::DataRaw<Arc<Mutex<char>>>,
|
||||||
|
data3: web::DataRaw<Arc<Mutex<f64>>>| {
|
||||||
|
assert_eq!(*(data1.lock().unwrap()), 10);
|
||||||
|
assert_eq!(*(data2.lock().unwrap()), '*');
|
||||||
|
assert_eq!(*(data3.lock().unwrap()), 1.0);
|
||||||
|
HttpResponse::Ok()
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
let req = TestRequest::get().uri("/test").to_request();
|
||||||
|
let resp = call_service(&mut srv, req);
|
||||||
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
56
src/scope.rs
56
src/scope.rs
|
@ -12,7 +12,7 @@ use futures::future::{ok, Either, Future, FutureResult};
|
||||||
use futures::{Async, IntoFuture, Poll};
|
use futures::{Async, IntoFuture, Poll};
|
||||||
|
|
||||||
use crate::config::ServiceConfig;
|
use crate::config::ServiceConfig;
|
||||||
use crate::data::Data;
|
use crate::data::{AppData, Data, DataRaw};
|
||||||
use crate::dev::{AppService, HttpServiceFactory};
|
use crate::dev::{AppService, HttpServiceFactory};
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::guard::Guard;
|
use crate::guard::Guard;
|
||||||
|
@ -152,12 +152,19 @@ where
|
||||||
self.register_data(Data::new(data))
|
self.register_data(Data::new(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The same usage as `Resource::data` method.
|
||||||
|
/// The difference is the `U` must be `Send + Sync + Clone` in order to register as `DataRaw`
|
||||||
|
pub fn data_raw<U: Send + Sync + Clone + 'static>(self, data: U) -> Self {
|
||||||
|
self.register_data(DataRaw::new(data))
|
||||||
|
}
|
||||||
|
|
||||||
/// Set or override application data.
|
/// Set or override application data.
|
||||||
///
|
///
|
||||||
/// This method has the same effect as [`Scope::data`](#method.data), except
|
/// This method has the same effect as [`Scope::data`](#method.data), except
|
||||||
/// that instead of taking a value of some type `T`, it expects a value of
|
/// that instead of taking a value of some type `T`, it expects a value of
|
||||||
/// type `Data<T>`. Use a `Data<T>` extractor to retrieve its value.
|
/// type `Data<T>` or `DataRaw<T>`. Use a `Data<T>` or `DataRaw<T>` extractor
|
||||||
pub fn register_data<U: 'static>(mut self, data: Data<U>) -> Self {
|
/// to retrieve its value.
|
||||||
|
pub fn register_data<U: AppData + 'static>(mut self, data: U) -> Self {
|
||||||
if self.data.is_none() {
|
if self.data.is_none() {
|
||||||
self.data = Some(Extensions::new());
|
self.data = Some(Extensions::new());
|
||||||
}
|
}
|
||||||
|
@ -655,10 +662,13 @@ impl NewService for ScopeEndpoint {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use actix_service::Service;
|
use actix_service::Service;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use futures::{Future, IntoFuture};
|
use futures::{Future, IntoFuture};
|
||||||
|
|
||||||
|
use crate::data::AppData;
|
||||||
use crate::dev::{Body, ResponseBody};
|
use crate::dev::{Body, ResponseBody};
|
||||||
use crate::http::{header, HeaderValue, Method, StatusCode};
|
use crate::http::{header, HeaderValue, Method, StatusCode};
|
||||||
use crate::service::{ServiceRequest, ServiceResponse};
|
use crate::service::{ServiceRequest, ServiceResponse};
|
||||||
|
@ -1113,6 +1123,46 @@ mod tests {
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_override_data_raw() {
|
||||||
|
let mut srv = init_service(App::new().data_raw(Arc::new(Mutex::new(1usize))).service(
|
||||||
|
web::scope("app").data_raw(Arc::new(Mutex::new(10usize))).route(
|
||||||
|
"/t",
|
||||||
|
web::get().to(|data: web::DataRaw<Arc<Mutex<usize>>>| {
|
||||||
|
assert_eq!(*(data.lock().unwrap()), 10);
|
||||||
|
let _ = data.clone();
|
||||||
|
HttpResponse::Ok()
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
let req = TestRequest::with_uri("/app/t").to_request();
|
||||||
|
let resp = call_service(&mut srv, req);
|
||||||
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_override_register_data_raw() {
|
||||||
|
let mut srv = init_service(
|
||||||
|
App::new().register_data(web::DataRaw::new(Arc::new(Mutex::new(1usize)))).service(
|
||||||
|
web::scope("app")
|
||||||
|
.register_data(web::DataRaw::new(Arc::new(Mutex::new(10usize))))
|
||||||
|
.route(
|
||||||
|
"/t",
|
||||||
|
web::get().to(|data: web::DataRaw<Arc<Mutex<usize>>>| {
|
||||||
|
assert_eq!(*(data.lock().unwrap()), 10);
|
||||||
|
let _ = data.clone();
|
||||||
|
HttpResponse::Ok()
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
let req = TestRequest::with_uri("/app/t").to_request();
|
||||||
|
let resp = call_service(&mut srv, req);
|
||||||
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_scope_config() {
|
fn test_scope_config() {
|
||||||
let mut srv =
|
let mut srv =
|
||||||
|
|
|
@ -19,7 +19,7 @@ pub use actix_http::test::TestBuffer;
|
||||||
pub use actix_testing::{block_fn, block_on, run_on};
|
pub use actix_testing::{block_fn, block_on, run_on};
|
||||||
|
|
||||||
use crate::config::{AppConfig, AppConfigInner};
|
use crate::config::{AppConfig, AppConfigInner};
|
||||||
use crate::data::Data;
|
use crate::data::{AppData, Data};
|
||||||
use crate::dev::{Body, MessageBody, Payload};
|
use crate::dev::{Body, MessageBody, Payload};
|
||||||
use crate::request::HttpRequestPool;
|
use crate::request::HttpRequestPool;
|
||||||
use crate::rmap::ResourceMap;
|
use crate::rmap::ResourceMap;
|
||||||
|
@ -521,8 +521,8 @@ mod tests {
|
||||||
assert!(req.headers().contains_key(header::DATE));
|
assert!(req.headers().contains_key(header::DATE));
|
||||||
assert_eq!(&req.match_info()["test"], "123");
|
assert_eq!(&req.match_info()["test"], "123");
|
||||||
assert_eq!(req.version(), Version::HTTP_2);
|
assert_eq!(req.version(), Version::HTTP_2);
|
||||||
let data = req.get_app_data::<u32>().unwrap();
|
let data = req.get_app_data::<web::Data<u32>>().unwrap();
|
||||||
assert!(req.get_app_data::<u64>().is_none());
|
assert!(req.get_app_data::<web::Data<u64>>().is_none());
|
||||||
assert_eq!(*data, 10);
|
assert_eq!(*data, 10);
|
||||||
assert_eq!(*data.get_ref(), 10);
|
assert_eq!(*data.get_ref(), 10);
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ use crate::scope::Scope;
|
||||||
use crate::service::WebService;
|
use crate::service::WebService;
|
||||||
|
|
||||||
pub use crate::config::ServiceConfig;
|
pub use crate::config::ServiceConfig;
|
||||||
pub use crate::data::Data;
|
pub use crate::data::{AppData, Data, DataRaw};
|
||||||
pub use crate::request::HttpRequest;
|
pub use crate::request::HttpRequest;
|
||||||
pub use crate::types::*;
|
pub use crate::types::*;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue