1 use std::ops::Deref;
2 
3 use crate::Rocket;
4 use crate::request::{self, FromRequest, Request};
5 use crate::outcome::Outcome;
6 use crate::http::Status;
7 
8 /// Request guard to retrieve managed state.
9 ///
10 /// This type can be used as a request guard to retrieve the state Rocket is
11 /// managing for some type `T`. This allows for the sharing of state across any
12 /// number of handlers. A value for the given type must previously have been
13 /// registered to be managed by Rocket via
14 /// [`Rocket::manage()`]. The type being managed must be
15 /// thread safe and sendable across thread boundaries. In other words, it must
16 /// implement [`Send`] + [`Sync`] + `'static`.
17 ///
18 /// # Example
19 ///
20 /// Imagine you have some configuration struct of the type `MyConfig` that you'd
21 /// like to initialize at start-up and later access it in several handlers. The
22 /// following example does just this:
23 ///
24 /// ```rust
25 /// # #![feature(proc_macro_hygiene)]
26 /// # #[macro_use] extern crate rocket;
27 /// use rocket::State;
28 ///
29 /// // In a real application, this would likely be more complex.
30 /// struct MyConfig {
31 ///     user_val: String
32 /// }
33 ///
34 /// #[get("/")]
35 /// fn index(state: State<MyConfig>) -> String {
36 ///     format!("The config value is: {}", state.user_val)
37 /// }
38 ///
39 /// #[get("/raw")]
40 /// fn raw_config_value<'r>(state: State<'r, MyConfig>) -> &'r str {
41 ///     // use `inner()` to get a lifetime longer than `deref` gives us
42 ///     state.inner().user_val.as_str()
43 /// }
44 ///
45 /// fn main() {
46 ///     let config = MyConfig {
47 ///         user_val: "user input".to_string()
48 ///     };
49 ///
50 /// # if false { // We don't actually want to launch the server in an example.
51 ///     rocket::ignite()
52 ///         .mount("/", routes![index, raw_config_value])
53 ///         .manage(config)
54 ///         .launch();
55 /// # }
56 /// }
57 /// ```
58 ///
59 /// # Within Request Guards
60 ///
61 /// Because `State` is itself a request guard, managed state can be retrieved
62 /// from another request guard's implementation. In the following code example,
63 /// `Item` retrieves the `MyConfig` managed state in its [`FromRequest`]
64 /// implementation using the [`Request::guard()`] method.
65 ///
66 /// ```rust
67 /// use rocket::State;
68 /// use rocket::request::{self, Request, FromRequest};
69 ///
70 /// # struct MyConfig{ user_val: String };
71 /// struct Item(String);
72 ///
73 /// impl FromRequest<'_, '_> for Item {
74 ///     type Error = ();
75 ///
76 ///     fn from_request(request: &Request<'_>) -> request::Outcome<Item, ()> {
77 ///         request.guard::<State<MyConfig>>()
78 ///             .map(|my_config| Item(my_config.user_val.clone()))
79 ///     }
80 /// }
81 /// ```
82 ///
83 /// # Testing with `State`
84 ///
85 /// When unit testing your application, you may find it necessary to manually
86 /// construct a type of `State` to pass to your functions. To do so, use the
87 /// [`State::from()`] static method:
88 ///
89 /// ```rust
90 /// # #![feature(proc_macro_hygiene)]
91 /// # #[macro_use] extern crate rocket;
92 /// use rocket::State;
93 ///
94 /// struct MyManagedState(usize);
95 ///
96 /// #[get("/")]
97 /// fn handler(state: State<MyManagedState>) -> String {
98 ///     state.0.to_string()
99 /// }
100 ///
101 /// let rocket = rocket::ignite().manage(MyManagedState(127));
102 /// let state = State::from(&rocket).expect("managing `MyManagedState`");
103 /// assert_eq!(handler(state), "127");
104 /// ```
105 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
106 pub struct State<'r, T: Send + Sync + 'static>(&'r T);
107 
108 impl<'r, T: Send + Sync + 'static> State<'r, T> {
109     /// Retrieve a borrow to the underlying value with a lifetime of `'r`.
110     ///
111     /// Using this method is typically unnecessary as `State` implements
112     /// [`Deref`] with a [`Deref::Target`] of `T`. This means Rocket will
113     /// automatically coerce a `State<T>` to an `&T` as required. This method
114     /// should only be used when a longer lifetime is required.
115     ///
116     /// # Example
117     ///
118     /// ```rust
119     /// use rocket::State;
120     ///
121     /// struct MyConfig {
122     ///     user_val: String
123     /// }
124     ///
125     /// // Use `inner()` to get a lifetime of `'r`
126     /// fn handler1<'r>(config: State<'r, MyConfig>) -> &'r str {
127     ///     &config.inner().user_val
128     /// }
129     ///
130     /// // Use the `Deref` implementation which coerces implicitly
131     /// fn handler2(config: State<MyConfig>) -> String {
132     ///     config.user_val.clone()
133     /// }
134     /// ```
135     #[inline(always)]
inner(&self) -> &'r T136     pub fn inner(&self) -> &'r T {
137         self.0
138     }
139 
140     /// Returns the managed state value in `rocket` for the type `T` if it is
141     /// being managed by `rocket`. Otherwise, returns `None`.
142     ///
143     /// # Example
144     ///
145     /// ```rust
146     /// use rocket::State;
147     ///
148     /// #[derive(Debug, PartialEq)]
149     /// struct Managed(usize);
150     ///
151     /// #[derive(Debug, PartialEq)]
152     /// struct Unmanaged(usize);
153     ///
154     /// let rocket = rocket::ignite().manage(Managed(7));
155     ///
156     /// let state: Option<State<Managed>> = State::from(&rocket);
157     /// assert_eq!(state.map(|s| s.inner()), Some(&Managed(7)));
158     ///
159     /// let state: Option<State<Unmanaged>> = State::from(&rocket);
160     /// assert_eq!(state, None);
161     /// ```
162     #[inline(always)]
from(rocket: &'r Rocket) -> Option<Self>163     pub fn from(rocket: &'r Rocket) -> Option<Self> {
164         rocket.state.try_get::<T>().map(State)
165     }
166 }
167 
168 impl<'r, T: Send + Sync + 'static> FromRequest<'_, 'r> for State<'r, T> {
169     type Error = ();
170 
171     #[inline(always)]
from_request(req: &Request<'r>) -> request::Outcome<State<'r, T>, ()>172     fn from_request(req: &Request<'r>) -> request::Outcome<State<'r, T>, ()> {
173         match req.state.managed.try_get::<T>() {
174             Some(state) => Outcome::Success(State(state)),
175             None => {
176                 error_!("Attempted to retrieve unmanaged state!");
177                 Outcome::Failure((Status::InternalServerError, ()))
178             }
179         }
180     }
181 }
182 
183 impl<T: Send + Sync + 'static> Deref for State<'_, T> {
184     type Target = T;
185 
186     #[inline(always)]
deref(&self) -> &T187     fn deref(&self) -> &T {
188         self.0
189     }
190 }
191