From 452137553455ff90c63bdd725efade91d5a886f3 Mon Sep 17 00:00:00 2001 From: Katherine Philip Date: Mon, 15 Jul 2019 16:35:50 +0700 Subject: [PATCH 1/3] Update App State documentation --- content/docs/application.md | 37 +++++++++++++++------------- examples/application/src/state.rs | 41 ++++++++++++++++++++----------- 2 files changed, 46 insertions(+), 32 deletions(-) diff --git a/content/docs/application.md b/content/docs/application.md index 95df909..1d6fb44 100644 --- a/content/docs/application.md +++ b/content/docs/application.md @@ -43,30 +43,33 @@ as the first application, it would match all incoming requests. ## State Application state is shared with all routes and resources within the same scope. State -can be accessed with the `web::Data` extractor as read-only, but interior mutability with -`Cell` can be used to achieve state mutability. State is also available for route -matching guards and middlewares. +can be accessed with the `web::Data` extractor. State is also available for route matching guards and middlewares. -Let's write a simple application that uses shared state. We are going to store request count -in the state: +Let's write a simple application and store the application name in the state: {{< include-example example="application" file="state.rs" section="setup" >}} -When the app is initialized it needs to be passed the initial state: - -{{< include-example example="application" file="state.rs" section="make_app" >}} - -> **Note**: `HttpServer` accepts an application factory rather than an application -> instance. `HttpServer` constructs an application instance for each thread, thus -> application state must be constructed multiple times. If you want to share state between -> different threads, a shared object should be used, e.g. `Arc`. There is also an -> [Example][stateexample] using `Arc` for this. Application state does not need to be -> `Send` and `Sync`, but the application factory must be `Send` + `Sync`. - -To start the previous app, create it into a closure: +and pass in the state when initializing the App, and start the application: {{< include-example example="application" file="state.rs" section="start_app" >}} +## Shared Mutable State + +`HttpServer` accepts an application factory rather than an application instance. +Http server constructs an application instance for each thread, thus application data must be +constructed multiple times. If you want to share data between different threads, a shareable +object should be used, e.g. Send + Sync. + +Internally, `web::Data` uses Arc. Thus, in order to avoid double Arc, we should create our Data before registering it using `register_data()`. + +In the following example, we will write an application with mutable, shared state. First, we define our state and create our handler: + +{{< include-example example="application" file="state.rs" section="setup_mutable" >}} + +and initialize in in an App: + +{{< include-example example="application" file="state.rs" section="make_app_mutable" >}} + ## Combining applications with different state Combining multiple applications with different state is possible as well. diff --git a/examples/application/src/state.rs b/examples/application/src/state.rs index 6f5c278..3ca179c 100644 --- a/examples/application/src/state.rs +++ b/examples/application/src/state.rs @@ -1,42 +1,53 @@ // use actix_web::{web, App, HttpServer}; -use std::cell::Cell; // This struct represents state struct AppState { - counter: Cell, + app_name: String, } fn index(data: web::Data) -> String { - let count = data.counter.get() + 1; // <- get count - data.counter.set(count); // <- store new count in state + let app_name = data.app_name; // <- get app_name - format!("Request number: {}", count) // <- response with count + format!("Hello {}!", app_name) // <- response with app_name } // -// +// +struct AppStateWithCounter { + counter: Mutex, // <- Mutex is necessary to mutate safely across threads +} + +fn _index(data: web::Data) -> String { + let mut counter = state.counter.lock().unwrap(); // <- get counter's MutexGuard + *counter += 1; // <- access counter inside MutexGuard + + format!("Request number: {}", counter) // <- response with count +} +// + +// fn _main() { + let counter = web::Data::new(AppStateWithCounter { counter : Mutex::new(0)}); + App::new() - .data(AppState { - counter: Cell::new(0), - }) + .register_data(counter.clone()) // <- register the created data .route("/", web::get().to(index)); } -// +// // pub fn main() { HttpServer::new(|| { App::new() .data(AppState { - counter: Cell::new(0), + app_name: String::from("Actix-web") }) .route("/", web::get().to(index)) }) - .bind("127.0.0.1:8088") - .unwrap() - .run() - .unwrap(); + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // From 31630f61f8fd2cb4de2d9f3367c840afeb179e32 Mon Sep 17 00:00:00 2001 From: Katherine Philip Date: Mon, 15 Jul 2019 17:12:37 +0700 Subject: [PATCH 2/3] Minor tweaks --- content/docs/application.md | 2 +- examples/application/src/state.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/content/docs/application.md b/content/docs/application.md index 1d6fb44..4ba4f27 100644 --- a/content/docs/application.md +++ b/content/docs/application.md @@ -66,7 +66,7 @@ In the following example, we will write an application with mutable, shared stat {{< include-example example="application" file="state.rs" section="setup_mutable" >}} -and initialize in in an App: +and register the data in an App: {{< include-example example="application" file="state.rs" section="make_app_mutable" >}} diff --git a/examples/application/src/state.rs b/examples/application/src/state.rs index 3ca179c..f5702b3 100644 --- a/examples/application/src/state.rs +++ b/examples/application/src/state.rs @@ -45,9 +45,9 @@ pub fn main() { }) .route("/", web::get().to(index)) }) - .bind("127.0.0.1:8088") - .unwrap() - .run() - .unwrap(); + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // From 77b86e778f04d992e5eca90a3f92b41ce3956095 Mon Sep 17 00:00:00 2001 From: Katherine Philip Date: Thu, 18 Jul 2019 20:59:11 +0700 Subject: [PATCH 3/3] Fix examples --- examples/application/src/state.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/application/src/state.rs b/examples/application/src/state.rs index f5702b3..7138c39 100644 --- a/examples/application/src/state.rs +++ b/examples/application/src/state.rs @@ -1,5 +1,6 @@ // use actix_web::{web, App, HttpServer}; +use std::sync::{Mutex}; // This struct represents state struct AppState { @@ -19,7 +20,7 @@ struct AppStateWithCounter { } fn _index(data: web::Data) -> String { - let mut counter = state.counter.lock().unwrap(); // <- get counter's MutexGuard + let mut counter = data.counter.lock().unwrap(); // <- get counter's MutexGuard *counter += 1; // <- access counter inside MutexGuard format!("Request number: {}", counter) // <- response with count