rama_core/context/mod.rs
1//! Context passed to and between services as input.
2//!
3//! # State
4//!
5//! [`rama`] supports two kinds of states:
6//!
7//! 1. type-safe state: this is the `S` generic parameter in [`Context`] and is to be used
8//! as much as possible, given its existence and type properties can be validated at compile time
9//! 2. dynamic state: these can be injected as [`Extensions`]s using methods such as [`Context::insert`]
10//!
11//! As a rule of thumb one should use the type-safe state (1) in case:
12//!
13//! - the state is always expected to exist at the point the middleware/service is called
14//! - the state is specific to the app or middleware
15//! - and the state can be constructed in a default/empty state
16//!
17//! The latter is important given the state is often created (or at least reserved) prior to
18//! it is actually being populated by the relevant middleware. This is not the case for app-specific state
19//! such as Database pools which are created since the start and shared among many different tasks.
20//!
21//! The rule could be be simplified to "if you need to `.unwrap()` you probably want type-safe state instead".
22//! It's however just a guideline and not a hard rule. As maintainers of [`rama`] we'll do our best to respect it though,
23//! and we recommend you to do the same.
24//!
25//! Any state that is optional, and especially optional state injected by middleware, can be inserted using extensions.
26//! It is however important to try as much as possible to then also consume this state in an approach that deals
27//! gracefully with its absence. Good examples of this are header-related inputs. Headers might be set or not,
28//! and so absence of [`Extensions`]s that might be created as a result of these might reasonably not exist.
29//! It might of course still mean the app returns an error response when it is absent, but it should not unwrap/panic.
30//!
31//! [`rama`]: crate
32//!
33//! # Examples
34//!
35//! ```
36//! use rama_core::Context;
37//!
38//! #[derive(Debug)]
39//! struct ServiceState {
40//! value: i32,
41//! }
42//!
43//! let state = ServiceState{ value: 5 };
44//! let ctx = Context::with_state(state);
45//! ```
46//!
47//! ## Example: Extensions
48//!
49//! The [`Context`] can be extended with additional data using the [`Extensions`] type.
50//!
51//! [`Context`]: crate::Context
52//! [`Extensions`]: crate::context::Extensions
53//!
54//! ```
55//! use rama_core::Context;
56//!
57//! let mut ctx = Context::default();
58//! ctx.insert(5i32);
59//! assert_eq!(ctx.get::<i32>(), Some(&5i32));
60//! ```
61//!
62//! ## State Wraps
63//!
64//! > 📖 [rustdoc link](https://ramaproxy.org/docs/rama/context/struct.Context.html#method.map_state)
65//!
66//! `rama` was built from the ground up to operate on and between different layers of the network stack.
67//! This has also an impact on state. Because sure, typed state is nice, but state leakage is not. What do I mean with that?
68//!
69//! When creating a `TcpListener` with state the state will be owned by that `TcpListener`. By default
70//! it will clone the state and pass a clone to each incoming `tcp` connection. You can however also
71//! inject your own state provider to customise that behaviour. Pretty much the same goes for an `HttpServer`,
72//! where it will do the same for each incoming http request. This is great for stuff that is okay to share, but it is not desired
73//! for state that you wish to have a narrower scope. Examples are state that are tied to a single _tcp_ connection and thus
74//! you do not wish to keep a global cache for this, as it would either be shared or get overly complicated to ensure
75//! you keep things separate and clean.
76//!
77//! One solution is to wrap your state.
78//!
79//! > See for reference: [/examples/http_conn_state.rs](https://github.com/plabayo/rama/tree/main/examples/http_conn_state.rs)
80//!
81//! In that example we make use of:
82//!
83//! - [`MapStateLayer`](https://ramaproxy.org/docs/rama/layer/struct.MapStateLayer.html):
84//! this generic layer allows you to map the state from one type to another,
85//! which is great in cases like this where you want the Application layer (http)
86//! to have a different type compared to the network layer (tpc).
87//! - the [`derive_more` third-party crate](https://docs.rs/derive_more/latest/derive_more/) is used
88//! as an example how one can use such crates to make services or layers which do not
89//! depend on a specific state type, but instead only require a reference (mutable or not)
90//! to specific properties they need, which can be useful in case that service
91//! is used in multiple branches, each with their own concrete _state_ type.
92
93use crate::graceful::ShutdownGuard;
94use crate::rt::Executor;
95use std::fmt;
96use std::ops::{Deref, DerefMut};
97use tokio::task::JoinHandle;
98
99mod extensions;
100#[doc(inline)]
101pub use extensions::Extensions;
102
103#[derive(Debug, Clone)]
104/// Wrapper type that can be injected into the dynamic extensions of a "Response",
105/// in order to preserve the [`Context`]'s extensions of the _Request_
106/// which was used to produce the _Response_.
107pub struct RequestContextExt(Extensions);
108
109impl From<Extensions> for RequestContextExt {
110 fn from(value: Extensions) -> Self {
111 Self(value)
112 }
113}
114
115impl From<RequestContextExt> for Extensions {
116 fn from(value: RequestContextExt) -> Self {
117 value.0
118 }
119}
120
121impl AsRef<Extensions> for RequestContextExt {
122 fn as_ref(&self) -> &Extensions {
123 &self.0
124 }
125}
126
127impl AsMut<Extensions> for RequestContextExt {
128 fn as_mut(&mut self) -> &mut Extensions {
129 &mut self.0
130 }
131}
132
133impl Deref for RequestContextExt {
134 type Target = Extensions;
135
136 fn deref(&self) -> &Self::Target {
137 &self.0
138 }
139}
140impl DerefMut for RequestContextExt {
141 fn deref_mut(&mut self) -> &mut Self::Target {
142 &mut self.0
143 }
144}
145
146/// Context passed to and between services as input.
147///
148/// See [`crate::context`] for more information.
149pub struct Context<S> {
150 state: S,
151 executor: Executor,
152 extensions: Extensions,
153}
154
155impl<S: fmt::Debug> fmt::Debug for Context<S> {
156 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
157 f.debug_struct("Context")
158 .field("state", &self.state)
159 .field("executor", &self.executor)
160 .field("extensions", &self.extensions)
161 .finish()
162 }
163}
164
165/// Component parts of [`Context`].
166pub struct Parts<S> {
167 pub state: S,
168 pub executor: Executor,
169 pub extensions: Extensions,
170}
171
172impl<S: fmt::Debug> fmt::Debug for Parts<S> {
173 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174 f.debug_struct("Parts")
175 .field("state", &self.state)
176 .field("executor", &self.executor)
177 .field("extensions", &self.extensions)
178 .finish()
179 }
180}
181
182impl Default for Context<()> {
183 fn default() -> Self {
184 Self::new((), Executor::default())
185 }
186}
187
188impl<S: Clone> Clone for Context<S> {
189 fn clone(&self) -> Self {
190 Self {
191 state: self.state.clone(),
192 executor: self.executor.clone(),
193 extensions: self.extensions.clone(),
194 }
195 }
196}
197
198impl<S> Context<S> {
199 /// Create a new [`Context`] with the given state.
200 pub fn new(state: S, executor: Executor) -> Self {
201 Self {
202 state,
203 executor,
204 extensions: Extensions::new(),
205 }
206 }
207
208 pub fn from_parts(parts: Parts<S>) -> Self {
209 Self {
210 state: parts.state,
211 executor: parts.executor,
212 extensions: parts.extensions,
213 }
214 }
215
216 pub fn into_parts(self) -> Parts<S> {
217 Parts {
218 state: self.state,
219 executor: self.executor,
220 extensions: self.extensions,
221 }
222 }
223
224 /// Create a new [`Context`] with the given state and default extension.
225 pub fn with_state(state: S) -> Self {
226 Self::new(state, Executor::default())
227 }
228
229 /// Get a reference to the state.
230 pub fn state(&self) -> &S {
231 &self.state
232 }
233
234 /// Get an exclusive reference to the state.
235 pub fn state_mut(&mut self) -> &mut S {
236 &mut self.state
237 }
238
239 /// Map the state from one type to another.
240 pub fn map_state<F, W>(self, f: F) -> Context<W>
241 where
242 F: FnOnce(S) -> W,
243 {
244 Context {
245 state: f(self.state),
246 executor: self.executor,
247 extensions: self.extensions,
248 }
249 }
250
251 /// Swap the state from one type to another,
252 /// returning the new object as well as the previously defined state.
253 pub fn swap_state<W>(self, state: W) -> (Context<W>, S) {
254 (
255 Context {
256 state,
257 executor: self.executor,
258 extensions: self.extensions,
259 },
260 self.state,
261 )
262 }
263
264 /// Clones the internals of this [`Context`]
265 /// to provide a new context, but while mapping the state
266 /// into a new state.
267 pub fn clone_map_state<F, W>(&self, f: F) -> Context<W>
268 where
269 S: Clone,
270 F: FnOnce(S) -> W,
271 {
272 Context {
273 state: f(self.state.clone()),
274 executor: self.executor.clone(),
275 extensions: self.extensions.clone(),
276 }
277 }
278
279 /// Clones the internals of this [`Context`]
280 /// to provide a new context, but using the given state, instead of
281 /// the one defined in the current [`Context`].
282 pub fn clone_with_state<W>(&self, state: W) -> Context<W> {
283 Context {
284 state,
285 executor: self.executor.clone(),
286 extensions: self.extensions.clone(),
287 }
288 }
289
290 /// Get a reference to the executor.
291 pub fn executor(&self) -> &Executor {
292 &self.executor
293 }
294
295 /// Spawn a future on the current executor,
296 /// this is spawned gracefully in case a shutdown guard has been registered.
297 pub fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
298 where
299 F: Future<Output: Send + 'static> + Send + 'static,
300 {
301 self.executor.spawn_task(future)
302 }
303
304 /// Returns true if the `Context` contains the given type.
305 ///
306 /// Use [`Self::get`] in case you want to have access to the type
307 /// or [`Self::get_mut`] if you also need to mutate it.
308 pub fn contains<T: Send + Sync + 'static>(&self) -> bool {
309 self.extensions.contains::<T>()
310 }
311
312 /// Get a shared reference to an extension.
313 ///
314 /// An extension is a type that implements `Send + Sync + 'static`,
315 /// and can be used to inject dynamic data into the [`Context`].
316 ///
317 /// Extensions are specific to this [`Context`]. It will be cloned when the [`Context`] is cloned,
318 /// but extensions inserted using [`Context::insert`] will not be visible the
319 /// original [`Context`], or any other cloned [`Context`].
320 ///
321 /// Please use the statically typed state (see [`Context::state`]) for data that is shared between
322 /// all context clones.
323 ///
324 /// # Example
325 ///
326 /// ```
327 /// # use rama_core::Context;
328 /// # let mut ctx = Context::default();
329 /// # ctx.insert(5i32);
330 /// assert_eq!(ctx.get::<i32>(), Some(&5i32));
331 /// ```
332 pub fn get<T: Send + Sync + 'static>(&self) -> Option<&T> {
333 self.extensions.get::<T>()
334 }
335
336 /// Get an exclusive reference to an extension.
337 ///
338 /// An extension is a type that implements `Send + Sync + 'static`,
339 /// and can be used to inject dynamic data into the [`Context`].
340 ///
341 /// Extensions are specific to this [`Context`]. It will be cloned when the [`Context`] is cloned,
342 /// but extensions inserted using [`Context::insert`] will not be visible the
343 /// original [`Context`], or any other cloned [`Context`].
344 ///
345 /// Please use the statically typed state (see [`Context::state`]) for data that is shared between
346 /// all context clones.
347 ///
348 /// # Example
349 ///
350 /// ```
351 /// # use rama_core::Context;
352 /// # let mut ctx = Context::default();
353 /// # ctx.insert(5i32);
354 /// let x = ctx.get_mut::<i32>().unwrap();
355 /// assert_eq!(*x, 5i32);
356 /// *x = 8;
357 /// assert_eq!(*x, 8i32);
358 /// assert_eq!(ctx.get::<i32>(), Some(&8i32));
359 /// ```
360 pub fn get_mut<T: Send + Sync + 'static>(&mut self) -> Option<&mut T> {
361 self.extensions.get_mut::<T>()
362 }
363
364 /// Inserts a value into the map computed from `f` into if it is [`None`],
365 /// then returns an exclusive reference to the contained value.
366 ///
367 /// # Example
368 ///
369 /// ```
370 /// # use rama_core::Context;
371 /// let mut ctx = Context::default();
372 /// let value: &i32 = ctx.get_or_insert_with(|| 42);
373 /// assert_eq!(*value, 42);
374 /// let existing_value: &mut i32 = ctx.get_or_insert_with(|| 0);
375 /// assert_eq!(*existing_value, 42);
376 /// ```
377 pub fn get_or_insert_with<T: Clone + Send + Sync + 'static>(
378 &mut self,
379 f: impl FnOnce() -> T,
380 ) -> &mut T {
381 self.extensions.get_or_insert_with(f)
382 }
383
384 /// Inserts a value into the map computed from `f` into if it is [`None`],
385 /// then returns an exclusive reference to the contained value.
386 ///
387 /// Use the cheaper [`Self::get_or_insert_with`] in case you do not need access to
388 /// the [`Context`] for the creation of `T`, as this function comes with
389 /// an extra cost.
390 ///
391 /// # Example
392 ///
393 /// ```
394 /// # use rama_core::Context;
395 /// # use std::sync::Arc;
396 /// # #[derive(Debug, Clone)]
397 /// struct State {
398 /// mul: i32,
399 /// }
400 /// let mut ctx = Context::with_state(Arc::new(State{ mul: 2 }));
401 /// ctx.insert(true);
402 /// let value: &i32 = ctx.get_or_insert_with_ctx(|ctx| ctx.state().mul * 21);
403 /// assert_eq!(*value, 42);
404 /// let existing_value: &mut i32 = ctx.get_or_insert_default();
405 /// assert_eq!(*existing_value, 42);
406 /// ```
407 pub fn get_or_insert_with_ctx<T: Clone + Send + Sync + 'static>(
408 &mut self,
409 f: impl FnOnce(&Self) -> T,
410 ) -> &mut T {
411 if self.extensions.contains::<T>() {
412 // NOTE: once <https://github.com/rust-lang/polonius>
413 // is merged into rust we can use directly `if let Some(v) = self.extensions.get_mut()`,
414 // until then we need this work around.
415 return self.extensions.get_mut().unwrap();
416 }
417 let v = f(self);
418 self.extensions.insert(v);
419 self.extensions.get_mut().unwrap()
420 }
421
422 /// Try to insert a value into the map computed from `f` into if it is [`None`],
423 /// then returns an exclusive reference to the contained value.
424 ///
425 /// Similar to [`Self::get_or_insert_with_ctx`] but fallible.
426 pub fn get_or_try_insert_with_ctx<T: Clone + Send + Sync + 'static, E>(
427 &mut self,
428 f: impl FnOnce(&Self) -> Result<T, E>,
429 ) -> Result<&mut T, E> {
430 if self.extensions.contains::<T>() {
431 // NOTE: once <https://github.com/rust-lang/polonius>
432 // is merged into rust we can use directly `if let Some(v) = self.extensions.get_mut()`,
433 // until then we need this work around.
434 return Ok(self.extensions.get_mut().unwrap());
435 }
436 let v = f(self)?;
437 self.extensions.insert(v);
438 Ok(self.extensions.get_mut().unwrap())
439 }
440
441 /// Inserts a value into the map computed from converting `U` into `T if no value was already inserted is [`None`],
442 /// then returns an exclusive reference to the contained value.
443 pub fn get_or_insert_from<T, U>(&mut self, src: U) -> &mut T
444 where
445 T: Clone + Send + Sync + 'static,
446 U: Into<T>,
447 {
448 self.extensions.get_or_insert_from(src)
449 }
450
451 /// Retrieves a value of type `T` from the context.
452 ///
453 /// If the value does not exist, the provided value is inserted
454 /// and an exclusive reference to it is returned.
455 ///
456 /// See [`Context::get`] for more details.
457 ///
458 /// # Example
459 ///
460 /// ```
461 /// # use rama_core::Context;
462 /// let mut ctx = Context::default();
463 /// ctx.insert(5i32);
464 ///
465 /// assert_eq!(*ctx.get_or_insert::<i32>(10), 5);
466 /// assert_eq!(*ctx.get_or_insert::<f64>(2.5), 2.5);
467 /// ```
468 pub fn get_or_insert<T: Send + Sync + Clone + 'static>(&mut self, fallback: T) -> &mut T {
469 self.extensions.get_or_insert(fallback)
470 }
471
472 /// Get an extension or `T`'s [`Default`].
473 ///
474 /// See [`Context::get`] for more details.
475 ///
476 /// # Example
477 ///
478 /// ```
479 /// # use rama_core::Context;
480 /// # let mut ctx = Context::default();
481 /// # ctx.insert(5i32);
482 ///
483 /// assert_eq!(*ctx.get_or_insert_default::<i32>(), 5i32);
484 /// assert_eq!(*ctx.get_or_insert_default::<f64>(), 0f64);
485 /// ```
486 pub fn get_or_insert_default<T: Clone + Default + Send + Sync + 'static>(&mut self) -> &mut T {
487 self.extensions.get_or_insert_default()
488 }
489
490 /// Insert an extension into the [`Context`].
491 ///
492 /// If a extension of this type already existed, it will
493 /// be returned.
494 ///
495 /// See [`Context::get`] for more details regarding extensions.
496 ///
497 /// # Example
498 ///
499 /// ```
500 /// # use rama_core::Context;
501 /// let mut ctx = Context::default();
502 ///
503 /// assert_eq!(ctx.insert(5i32), None);
504 /// assert_eq!(ctx.get::<i32>(), Some(&5i32));
505 ///
506 /// assert_eq!(ctx.insert(4i32), Some(5i32));
507 /// assert_eq!(ctx.get::<i32>(), Some(&4i32));
508 /// ```
509 pub fn insert<T: Clone + Send + Sync + 'static>(&mut self, extension: T) -> Option<T> {
510 self.extensions.insert(extension)
511 }
512
513 /// Insert a type only into this [`Context`], if the extension is `Some(T)`.
514 ///
515 /// See [`Self::insert`] for more information.
516 pub fn maybe_insert<T: Clone + Send + Sync + 'static>(
517 &mut self,
518 extension: Option<T>,
519 ) -> Option<T> {
520 self.extensions.maybe_insert(extension)
521 }
522
523 /// Return the entire dynamic state of the [`Context`] by reference.
524 ///
525 /// Useful only in case you have a function which works with [`Extensions`] rather
526 /// then the [`Context`] itself. In case you want to have access to a specific dynamic state,
527 /// it is more suitable to use [`Context::get`] directly.
528 pub fn extensions(&self) -> &Extensions {
529 &self.extensions
530 }
531
532 /// Return the entire dynamic state of the [`Context`] by mutable reference.
533 ///
534 /// Useful only in case you have a function which works with [`Extensions`] rather
535 /// then the [`Context`] itself. In case you want to have access to a specific dynamic state,
536 /// it is more suitable to use [`Context::get_or_insert`] or [`Context::insert`] directly.
537 ///
538 /// # Rollback
539 ///
540 /// Extensions do not have "rollback" support. In case you are not yet certain if you want to keep
541 /// the to be inserted [`Extensions`], you are better to create a new [`Extensions`] object using
542 /// [`Extensions::default`] and use [`Context::extend`] once you wish to commit the new
543 /// dynamic data into the [`Context`].
544 pub fn extensions_mut(&mut self) -> &mut Extensions {
545 &mut self.extensions
546 }
547
548 /// Extend The [`Context`] [`Extensions`] with another [`Extensions`].
549 ///
550 /// # Example
551 ///
552 /// ```
553 /// # use rama_core::{context::Extensions, Context};
554 /// let mut ctx = Context::default();
555 /// let mut ext = Extensions::default();
556 ///
557 /// ctx.insert(true);
558 /// ext.insert(5i32);
559 /// ctx.extend(ext);
560 ///
561 /// assert_eq!(ctx.get::<bool>(), Some(&true));
562 /// assert_eq!(ctx.get::<i32>(), Some(&5i32));
563 /// ```
564 pub fn extend(&mut self, extensions: Extensions) {
565 self.extensions.extend(extensions);
566 }
567
568 /// Clear the [`Context`] of all inserted [`Extensions`].
569 ///
570 /// # Example
571 ///
572 /// ```
573 /// # use rama_core::Context;
574 /// let mut ctx = Context::default();
575 ///
576 /// ctx.insert(5i32);
577 /// assert_eq!(ctx.get::<i32>(), Some(&5i32));
578 ///
579 /// ctx.clear();
580 /// assert_eq!(ctx.get::<i32>(), None);
581 /// ```
582 pub fn clear(&mut self) {
583 self.extensions.clear();
584 }
585
586 /// Remove an extension from this [`Context`]
587 pub fn remove<T: Clone + Send + Sync + 'static>(&mut self) -> Option<T> {
588 self.extensions.remove()
589 }
590
591 /// Get a reference to the shutdown guard,
592 /// if and only if the context was created within a graceful environment.
593 pub fn guard(&self) -> Option<&ShutdownGuard> {
594 self.executor.guard()
595 }
596}
597
598impl<S: Clone> Context<S> {
599 /// Get a cloned reference to the state.
600 pub fn state_clone(&self) -> S {
601 self.state.clone()
602 }
603}