From bc2180d1e4fd2c174b6be32ee357d1a30abb6175 Mon Sep 17 00:00:00 2001
From: Jeff Weiss <me@jweiss.com>
Date: Fri, 6 Jan 2023 15:30:01 -0500
Subject: [PATCH 1/2] Now compiles against rocket-0.5.0-rc.2

---
 Cargo.toml                     |  6 +++---
 examples/dog_list/main.rs      | 13 ++++++-------
 examples/visit_counter/main.rs | 17 ++++++++---------
 src/lib.rs                     | 23 +++++++++++++----------
 4 files changed, 30 insertions(+), 29 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 96e8146..27963f4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,8 +1,8 @@
 [package]
 name = "rocket_session"
-version = "0.2.2"
+version = "0.3.0"
 authors = ["Ondřej Hruška <ondra@ondrovo.com>"]
-edition = "2018"
+edition = "2021"
 license = "MIT"
 description = "Rocket.rs plug-in for cookie-based sessions holding arbitrary data"
 repository = "https://git.ondrovo.com/packages/rocket_session"
@@ -17,5 +17,5 @@ categories = [
 
 [dependencies]
 rand = "0.8"
-rocket = "0.4"
+rocket = "0.5.0-rc.2"
 parking_lot = "0.11"
diff --git a/examples/dog_list/main.rs b/examples/dog_list/main.rs
index da9e1f5..d02dc62 100644
--- a/examples/dog_list/main.rs
+++ b/examples/dog_list/main.rs
@@ -1,21 +1,20 @@
-#![feature(proc_macro_hygiene, decl_macro)]
 #[macro_use]
 extern crate rocket;
 
-use rocket::response::content::Html;
+use rocket::response::content::RawHtml;
 use rocket::response::Redirect;
 
 type Session<'a> = rocket_session::Session<'a, Vec<String>>;
 
-fn main() {
-    rocket::ignite()
+#[launch]
+fn rocket() -> _ {
+    rocket::build()
         .attach(Session::fairing())
         .mount("/", routes![index, add, remove])
-        .launch();
 }
 
 #[get("/")]
-fn index(session: Session) -> Html<String> {
+fn index(session: Session) -> RawHtml<String> {
     let mut page = String::new();
     page.push_str(
         r#"
@@ -38,7 +37,7 @@ fn index(session: Session) -> Html<String> {
         }
     });
     page.push_str("</ul>");
-    Html(page)
+    RawHtml(page)
 }
 
 #[post("/add", data = "<dog>")]
diff --git a/examples/visit_counter/main.rs b/examples/visit_counter/main.rs
index e65d053..6502a1b 100644
--- a/examples/visit_counter/main.rs
+++ b/examples/visit_counter/main.rs
@@ -2,11 +2,10 @@
 //!
 //! The expiry time is set to 10 seconds to illustrate how a session is cleared if inactive.
 
-#![feature(proc_macro_hygiene, decl_macro)]
 #[macro_use]
 extern crate rocket;
 
-use rocket::response::content::Html;
+use rocket::response::content::RawHtml;
 use std::time::Duration;
 
 #[derive(Default, Clone)]
@@ -18,8 +17,9 @@ struct SessionData {
 // It's convenient to define a type alias:
 type Session<'a> = rocket_session::Session<'a, SessionData>;
 
-fn main() {
-    rocket::ignite()
+#[launch]
+fn rocket() -> _ {
+    rocket::build()
         .attach(
             Session::fairing()
                 // 10 seconds of inactivity until session expires
@@ -30,11 +30,10 @@ fn main() {
                 .with_cookie_len(20),
         )
         .mount("/", routes![index, about])
-        .launch();
 }
 
 #[get("/")]
-fn index(session: Session) -> Html<String> {
+fn index(session: Session) -> RawHtml<String> {
     // Here we build the entire response inside the 'tap' closure.
 
     // While inside, the session is locked to parallel changes, e.g.
@@ -42,7 +41,7 @@ fn index(session: Session) -> Html<String> {
     session.tap(|sess| {
         sess.visits1 += 1;
 
-        Html(format!(
+        RawHtml(format!(
             r##"
                 <!DOCTYPE html>
                 <h1>Home</h1>
@@ -55,14 +54,14 @@ fn index(session: Session) -> Html<String> {
 }
 
 #[get("/about")]
-fn about(session: Session) -> Html<String> {
+fn about(session: Session) -> RawHtml<String> {
     // Here we return a value from the tap function and use it below
     let count = session.tap(|sess| {
         sess.visits2 += 1;
         sess.visits2
     });
 
-    Html(format!(
+    RawHtml(format!(
         r##"
             <!DOCTYPE html>
             <h1>About</h1>
diff --git a/src/lib.rs b/src/lib.rs
index 44058da..5d408a1 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,11 +1,12 @@
 use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
-use rand::{Rng, rngs::OsRng};
+use rand::{rngs::OsRng, Rng};
 
 use rocket::{
     fairing::{self, Fairing, Info},
     http::{Cookie, Status},
+    outcome::Outcome,
     request::FromRequest,
-    Outcome, Request, Response, Rocket, State,
+    Build, Request, Response, Rocket, State,
 };
 
 use std::borrow::Cow;
@@ -114,19 +115,20 @@ where
     D: 'static + Sync + Send + Default,
 {
     /// The shared state reference
-    store: State<'a, SessionStore<D>>,
+    store: &'a State<SessionStore<D>>,
     /// Session ID
     id: &'a SessionID,
 }
 
-impl<'a, 'r, D> FromRequest<'a, 'r> for Session<'a, D>
+#[rocket::async_trait]
+impl<'r, D> FromRequest<'r> for Session<'r, D>
 where
     D: 'static + Sync + Send + Default,
 {
     type Error = ();
 
-    fn from_request(request: &'a Request<'r>) -> Outcome<Self, (Status, Self::Error), ()> {
-        let store: State<SessionStore<D>> = request.guard().unwrap();
+    async fn from_request(request: &'r Request<'_>) -> Outcome<Self, (Status, Self::Error), ()> {
+        let store = request.guard::<&State<SessionStore<D>>>().await.unwrap();
         Outcome::Success(Session {
             id: request.local_cache(|| {
                 let store_ug = store.inner.upgradable_read();
@@ -198,7 +200,7 @@ where
                     new_id
                 }
             }),
-            store,
+            store: store,
         })
     }
 }
@@ -295,6 +297,7 @@ where
     }
 }
 
+#[rocket::async_trait]
 impl<D> Fairing for SessionFairing<D>
 where
     D: 'static + Sync + Send + Default,
@@ -302,11 +305,11 @@ where
     fn info(&self) -> Info {
         Info {
             name: "Session",
-            kind: fairing::Kind::Attach | fairing::Kind::Response,
+            kind: fairing::Kind::Ignite | fairing::Kind::Response,
         }
     }
 
-    fn on_attach(&self, rocket: Rocket) -> Result<Rocket, Rocket> {
+    async fn on_ignite(&self, rocket: Rocket<Build>) -> Result<Rocket<Build>, Rocket<Build>> {
         // install the store singleton
         Ok(rocket.manage(SessionStore::<D> {
             inner: Default::default(),
@@ -314,7 +317,7 @@ where
         }))
     }
 
-    fn on_response<'r>(&self, request: &'r Request, response: &mut Response) {
+    async fn on_response<'r>(&self, request: &'r Request<'_>, response: &mut Response) {
         // send the session cookie, if session started
         let session = request.local_cache(|| SessionID("".to_string()));
 

From b0a2d8c910e943fd26825b796ae633f2e11d719f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= <ondra@ondrovo.com>
Date: Tue, 10 Jan 2023 10:08:44 +0100
Subject: [PATCH 2/2] Add minimal example, some formatting, bump parking_lot
 version

---
 Cargo.toml               |  2 +-
 README.md                | 30 +++++++++++++++---------------
 examples/minimal/main.rs | 28 ++++++++++++++++++++++++++++
 src/lib.rs               | 26 ++++++++++++--------------
 4 files changed, 56 insertions(+), 30 deletions(-)
 create mode 100644 examples/minimal/main.rs

diff --git a/Cargo.toml b/Cargo.toml
index 27963f4..e984ec8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -18,4 +18,4 @@ categories = [
 [dependencies]
 rand = "0.8"
 rocket = "0.5.0-rc.2"
-parking_lot = "0.11"
+parking_lot = "0.12"
diff --git a/README.md b/README.md
index 2c05c13..83212b5 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,8 @@ The implementation is generic to support any type as session data: a custom stru
 The session lifetime, cookie name, and other parameters can be configured by calling chained 
 methods on the fairing. When a session expires, the data associated with it is dropped.
 
+Example: `Session::fairing().with_lifetime(Duration::from_secs(15))`
+
 ## Usage
 
 To use session in a route, first make sure you have the fairing attached by calling
@@ -31,7 +33,7 @@ the session list does not waste memory.
 
 ## Examples
 
-(More examples are in the examples folder)
+More examples are in the "examples" folder - run with `cargo run --example=NAME`
 
 ### Basic Example
 
@@ -39,34 +41,32 @@ This simple example uses u64 as the session variable; note that it can be a stru
 it just needs to implement `Send + Sync + Default`. 
 
 ```rust
-#![feature(proc_macro_hygiene, decl_macro)]
-#[macro_use] extern crate rocket;
-
-use std::time::Duration;
+#[macro_use]
+extern crate rocket;
 
-// It's convenient to define a type alias:
-pub type Session<'a> = rocket_session::Session<'a, u64>;
+type Session<'a> = rocket_session::Session<'a, u64>;
 
-fn main() {
-    rocket::ignite()
+#[launch]
+fn rocket() -> _ {
+    rocket::build()
         .attach(Session::fairing())
         .mount("/", routes![index])
-        .launch();
 }
 
 #[get("/")]
 fn index(session: Session) -> String {
     let count = session.tap(|n| {
-        // Change the stored value (it is &mut) 
+        // Change the stored value (it is &mut)
         *n += 1;
 
-        // Return something to the caller. 
-        // This can be any type, 'tap' is generic.        
+        // Return something to the caller.
+        // This can be any type, 'tap' is generic.
         *n
     });
 
     format!("{} visits", count)
 }
+
 ```
 
 ## Extending Session by a Trait
@@ -76,8 +76,8 @@ The `.tap()` method is powerful, but sometimes you may wish for something more c
 Here is an example of using a custom trait and the `json_dotpath` crate to implement
 a polymorphic store based on serde serialization. 
 
-Note that this approach is prone to data races, since every method contains its own `.tap()`.
-It may be safer to simply call the `.dot_*()` methods manually in one shared closure.
+Note that this approach is prone to data races if you're accessing the session object multiple times per request, 
+since every method contains its own `.tap()`. It may be safer to simply call the `.dot_*()` methods manually in one shared closure.
 
 ```rust
 use serde_json::Value;
diff --git a/examples/minimal/main.rs b/examples/minimal/main.rs
new file mode 100644
index 0000000..05efd1b
--- /dev/null
+++ b/examples/minimal/main.rs
@@ -0,0 +1,28 @@
+#[macro_use]
+extern crate rocket;
+
+use std::time::Duration;
+
+type Session<'a> = rocket_session::Session<'a, u64>;
+
+#[launch]
+fn rocket() -> _ {
+    // This session expires in 15 seconds as a demonstration of session configuration
+    rocket::build()
+        .attach(Session::fairing().with_lifetime(Duration::from_secs(15)))
+        .mount("/", routes![index])
+}
+
+#[get("/")]
+fn index(session: Session) -> String {
+    let count = session.tap(|n| {
+        // Change the stored value (it is &mut)
+        *n += 1;
+
+        // Return something to the caller.
+        // This can be any type, 'tap' is generic.
+        *n
+    });
+
+    format!("{} visits", count)
+}
diff --git a/src/lib.rs b/src/lib.rs
index 5d408a1..60c1f3e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,6 +1,12 @@
+use std::borrow::Cow;
+use std::collections::HashMap;
+use std::fmt::{self, Display, Formatter};
+use std::marker::PhantomData;
+use std::ops::Add;
+use std::time::{Duration, Instant};
+
 use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
 use rand::{rngs::OsRng, Rng};
-
 use rocket::{
     fairing::{self, Fairing, Info},
     http::{Cookie, Status},
@@ -9,13 +15,6 @@ use rocket::{
     Build, Request, Response, Rocket, State,
 };
 
-use std::borrow::Cow;
-use std::collections::HashMap;
-use std::fmt::{self, Display, Formatter};
-use std::marker::PhantomData;
-use std::ops::Add;
-use std::time::{Duration, Instant};
-
 /// Session store (shared state)
 #[derive(Debug)]
 pub struct SessionStore<D>
@@ -134,11 +133,10 @@ where
                 let store_ug = store.inner.upgradable_read();
 
                 // Resolve session ID
-                let id = if let Some(cookie) = request.cookies().get(&store.config.cookie_name) {
-                    Some(SessionID(cookie.value().to_string()))
-                } else {
-                    None
-                };
+                let id = request
+                    .cookies()
+                    .get(&store.config.cookie_name)
+                    .map(|cookie| SessionID(cookie.value().to_string()));
 
                 let expires = Instant::now().add(store.config.lifespan);
 
@@ -200,7 +198,7 @@ where
                     new_id
                 }
             }),
-            store: store,
+            store,
         })
     }
 }