1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-24 07:53:00 +01:00

Allow to construct Data instances to avoid double Arc for Send + Sync types.

This commit is contained in:
Nikolay Kim 2019-04-29 09:26:12 -07:00
parent b51b5b763c
commit 29a841529f
4 changed files with 35 additions and 17 deletions

View File

@ -1,5 +1,10 @@
# Changes # Changes
### Changed
* Allow to construct `Data` instances to avoid double `Arc` for `Send + Sync` types.
## [1.0.0-beta.2] - 2019-04-24 ## [1.0.0-beta.2] - 2019-04-24
### Added ### Added

View File

@ -95,8 +95,8 @@ where
/// web::get().to(index))); /// web::get().to(index)));
/// } /// }
/// ``` /// ```
pub fn data<S: 'static>(mut self, data: S) -> Self { pub fn data<U: Into<Data<U>> + 'static>(mut self, data: U) -> Self {
self.data.push(Box::new(Data::new(data))); self.data.push(Box::new(data.into()));
self self
} }
@ -301,14 +301,14 @@ where
/// lifecycle (request -> response), modifying request/response as /// lifecycle (request -> response), modifying request/response as
/// necessary, across all requests managed by the *Application*. /// necessary, across all requests managed by the *Application*.
/// ///
/// Use middleware when you need to read or modify *every* request or /// Use middleware when you need to read or modify *every* request or
/// response in some way. /// response in some way.
/// ///
/// Notice that the keyword for registering middleware is `wrap`. As you /// Notice that the keyword for registering middleware is `wrap`. As you
/// register middleware using `wrap` in the App builder, imagine wrapping /// register middleware using `wrap` in the App builder, imagine wrapping
/// layers around an inner App. The first middleware layer exposed to a /// layers around an inner App. The first middleware layer exposed to a
/// Request is the outermost layer-- the *last* registered in /// Request is the outermost layer-- the *last* registered in
/// the builder chain. Consequently, the *first* middleware registered /// the builder chain. Consequently, the *first* middleware registered
/// in the builder chain is the *last* to execute during request processing. /// in the builder chain is the *last* to execute during request processing.
/// ///
/// ```rust /// ```rust

View File

@ -33,29 +33,33 @@ pub(crate) trait DataFactoryResult {
/// instance for each thread, thus application data must be constructed /// instance for each thread, thus application data must be constructed
/// multiple times. If you want to share data between different /// multiple times. If you want to share data between different
/// threads, a shareable object should be used, e.g. `Send + Sync`. Application /// threads, a shareable object should be used, e.g. `Send + Sync`. Application
/// data does not need to be `Send` or `Sync`. Internally `Data` instance /// data does not need to be `Send` or `Sync`. Internally `Data` type
/// uses `Arc`. /// uses `Arc`. if your data implements `Send` + `Sync` traits you can
/// use `web::Data::new()` and avoid double `Arc`.
/// ///
/// If route data is not set for a handler, using `Data<T>` extractor would /// If route data is not set for a handler, using `Data<T>` extractor would
/// cause *Internal Server Error* response. /// cause *Internal Server Error* response.
/// ///
/// ```rust /// ```rust
/// use std::cell::Cell; /// use std::sync::Mutex;
/// use actix_web::{web, App}; /// use actix_web::{web, App};
/// ///
/// struct MyData { /// struct MyData {
/// counter: Cell<usize>, /// counter: usize,
/// } /// }
/// ///
/// /// Use `Data<T>` extractor to access data in handler. /// /// Use `Data<T>` extractor to access data in handler.
/// fn index(data: web::Data<MyData>) { /// fn index(data: web::Data<Mutex<MyData>>) {
/// data.counter.set(data.counter.get() + 1); /// let mut data = data.lock().unwrap();
/// data.counter += 1;
/// } /// }
/// ///
/// fn main() { /// fn main() {
/// let data = web::Data::new(Mutex::new(MyData{ counter: 0 }));
///
/// let app = App::new() /// let app = App::new()
/// // Store `MyData` in application storage. /// // Store `MyData` in application storage.
/// .data(MyData{ counter: Cell::new(0) }) /// .data(data.clone())
/// .service( /// .service(
/// web::resource("/index.html").route( /// web::resource("/index.html").route(
/// web::get().to(index))); /// web::get().to(index)));
@ -65,7 +69,12 @@ pub(crate) trait DataFactoryResult {
pub struct Data<T>(Arc<T>); pub struct Data<T>(Arc<T>);
impl<T> Data<T> { impl<T> Data<T> {
pub(crate) fn new(state: 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)) Data(Arc::new(state))
} }
@ -89,6 +98,12 @@ impl<T> Clone for Data<T> {
} }
} }
impl<T> From<T> for Data<T> {
fn from(data: T) -> Self {
Data::new(data)
}
}
impl<T: 'static> FromRequest for Data<T> { impl<T: 'static> FromRequest for Data<T> {
type Config = (); type Config = ();
type Error = Error; type Error = Error;

View File

@ -555,7 +555,7 @@ mod tests {
web::resource("/index.html") web::resource("/index.html")
.route(web::put().to(|| HttpResponse::Ok().body("put!"))) .route(web::put().to(|| HttpResponse::Ok().body("put!")))
.route(web::patch().to(|| HttpResponse::Ok().body("patch!"))) .route(web::patch().to(|| HttpResponse::Ok().body("patch!")))
.route(web::delete().to(|| HttpResponse::Ok().body("delete!"))) .route(web::delete().to(|| HttpResponse::Ok().body("delete!"))),
), ),
); );
@ -575,9 +575,7 @@ mod tests {
let result = read_response(&mut app, patch_req); let result = read_response(&mut app, patch_req);
assert_eq!(result, Bytes::from_static(b"patch!")); assert_eq!(result, Bytes::from_static(b"patch!"));
let delete_req = TestRequest::delete() let delete_req = TestRequest::delete().uri("/index.html").to_request();
.uri("/index.html")
.to_request();
let result = read_response(&mut app, delete_req); let result = read_response(&mut app, delete_req);
assert_eq!(result, Bytes::from_static(b"delete!")); assert_eq!(result, Bytes::from_static(b"delete!"));
} }