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    /// Set a new [`Executor`] to the [`Context`].
296    pub fn set_executor(&mut self, exec: Executor) -> &mut Self {
297        self.executor = exec;
298        self
299    }
300
301    /// Set a new [`Executor`] to the [`Context`].
302    #[must_use]
303    pub fn with_executor(mut self, exec: Executor) -> Self {
304        self.executor = exec;
305        self
306    }
307
308    /// Spawn a future on the current executor,
309    /// this is spawned gracefully in case a shutdown guard has been registered.
310    pub fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
311    where
312        F: Future<Output: Send + 'static> + Send + 'static,
313    {
314        self.executor.spawn_task(future)
315    }
316
317    /// Returns true if the `Context` contains the given type.
318    ///
319    /// Use [`Self::get`] in case you want to have access to the type
320    /// or [`Self::get_mut`] if you also need to mutate it.
321    pub fn contains<T: Send + Sync + 'static>(&self) -> bool {
322        self.extensions.contains::<T>()
323    }
324
325    /// Get a shared reference to an extension.
326    ///
327    /// An extension is a type that implements `Send + Sync + 'static`,
328    /// and can be used to inject dynamic data into the [`Context`].
329    ///
330    /// Extensions are specific to this [`Context`]. It will be cloned when the [`Context`] is cloned,
331    /// but extensions inserted using [`Context::insert`] will not be visible the
332    /// original [`Context`], or any other cloned [`Context`].
333    ///
334    /// Please use the statically typed state (see [`Context::state`]) for data that is shared between
335    /// all context clones.
336    ///
337    /// # Example
338    ///
339    /// ```
340    /// # use rama_core::Context;
341    /// # let mut ctx = Context::default();
342    /// # ctx.insert(5i32);
343    /// assert_eq!(ctx.get::<i32>(), Some(&5i32));
344    /// ```
345    pub fn get<T: Send + Sync + 'static>(&self) -> Option<&T> {
346        self.extensions.get::<T>()
347    }
348
349    /// Get an exclusive reference to an extension.
350    ///
351    /// An extension is a type that implements `Send + Sync + 'static`,
352    /// and can be used to inject dynamic data into the [`Context`].
353    ///
354    /// Extensions are specific to this [`Context`]. It will be cloned when the [`Context`] is cloned,
355    /// but extensions inserted using [`Context::insert`] will not be visible the
356    /// original [`Context`], or any other cloned [`Context`].
357    ///
358    /// Please use the statically typed state (see [`Context::state`]) for data that is shared between
359    /// all context clones.
360    ///
361    /// # Example
362    ///
363    /// ```
364    /// # use rama_core::Context;
365    /// # let mut ctx = Context::default();
366    /// # ctx.insert(5i32);
367    /// let x = ctx.get_mut::<i32>().unwrap();
368    /// assert_eq!(*x, 5i32);
369    /// *x = 8;
370    /// assert_eq!(*x, 8i32);
371    /// assert_eq!(ctx.get::<i32>(), Some(&8i32));
372    /// ```
373    pub fn get_mut<T: Send + Sync + 'static>(&mut self) -> Option<&mut T> {
374        self.extensions.get_mut::<T>()
375    }
376
377    /// Inserts a value into the map computed from `f` into if it is [`None`],
378    /// then returns an exclusive reference to the contained value.
379    ///
380    /// # Example
381    ///
382    /// ```
383    /// # use rama_core::Context;
384    /// let mut ctx = Context::default();
385    /// let value: &i32 = ctx.get_or_insert_with(|| 42);
386    /// assert_eq!(*value, 42);
387    /// let existing_value: &mut i32 = ctx.get_or_insert_with(|| 0);
388    /// assert_eq!(*existing_value, 42);
389    /// ```
390    pub fn get_or_insert_with<T: Clone + Send + Sync + 'static>(
391        &mut self,
392        f: impl FnOnce() -> T,
393    ) -> &mut T {
394        self.extensions.get_or_insert_with(f)
395    }
396
397    /// Inserts a value into the map computed from `f` into if it is [`None`],
398    /// then returns an exclusive reference to the contained value.
399    ///
400    /// Use the cheaper [`Self::get_or_insert_with`] in case you do not need access to
401    /// the [`Context`] for the creation of `T`, as this function comes with
402    /// an extra cost.
403    ///
404    /// # Example
405    ///
406    /// ```
407    /// # use rama_core::Context;
408    /// # use std::sync::Arc;
409    /// # #[derive(Debug, Clone)]
410    /// struct State {
411    ///     mul: i32,
412    /// }
413    /// let mut ctx = Context::with_state(Arc::new(State{ mul: 2 }));
414    /// ctx.insert(true);
415    /// let value: &i32 = ctx.get_or_insert_with_ctx(|ctx| ctx.state().mul * 21);
416    /// assert_eq!(*value, 42);
417    /// let existing_value: &mut i32 = ctx.get_or_insert_default();
418    /// assert_eq!(*existing_value, 42);
419    /// ```
420    pub fn get_or_insert_with_ctx<T: Clone + Send + Sync + 'static>(
421        &mut self,
422        f: impl FnOnce(&Self) -> T,
423    ) -> &mut T {
424        if self.extensions.contains::<T>() {
425            // NOTE: once <https://github.com/rust-lang/polonius>
426            // is merged into rust we can use directly `if let Some(v) = self.extensions.get_mut()`,
427            // until then we need this work around.
428            return self.extensions.get_mut().unwrap();
429        }
430        let v = f(self);
431        self.extensions.insert(v);
432        self.extensions.get_mut().unwrap()
433    }
434
435    /// Try to insert a value into the map computed from `f` into if it is [`None`],
436    /// then returns an exclusive reference to the contained value.
437    ///
438    /// Similar to [`Self::get_or_insert_with_ctx`] but fallible.
439    pub fn get_or_try_insert_with_ctx<T: Clone + Send + Sync + 'static, E>(
440        &mut self,
441        f: impl FnOnce(&Self) -> Result<T, E>,
442    ) -> Result<&mut T, E> {
443        if self.extensions.contains::<T>() {
444            // NOTE: once <https://github.com/rust-lang/polonius>
445            // is merged into rust we can use directly `if let Some(v) = self.extensions.get_mut()`,
446            // until then we need this work around.
447            return Ok(self.extensions.get_mut().unwrap());
448        }
449        let v = f(self)?;
450        self.extensions.insert(v);
451        Ok(self.extensions.get_mut().unwrap())
452    }
453
454    /// Inserts a value into the map computed from converting `U` into `T if no value was already inserted is [`None`],
455    /// then returns an exclusive reference to the contained value.
456    pub fn get_or_insert_from<T, U>(&mut self, src: U) -> &mut T
457    where
458        T: Clone + Send + Sync + 'static,
459        U: Into<T>,
460    {
461        self.extensions.get_or_insert_from(src)
462    }
463
464    /// Retrieves a value of type `T` from the context.
465    ///
466    /// If the value does not exist, the provided value is inserted
467    /// and an exclusive reference to it is returned.
468    ///
469    /// See [`Context::get`] for more details.
470    ///
471    /// # Example
472    ///
473    /// ```
474    /// # use rama_core::Context;
475    /// let mut ctx = Context::default();
476    /// ctx.insert(5i32);
477    ///
478    /// assert_eq!(*ctx.get_or_insert::<i32>(10), 5);
479    /// assert_eq!(*ctx.get_or_insert::<f64>(2.5), 2.5);
480    /// ```
481    pub fn get_or_insert<T: Send + Sync + Clone + 'static>(&mut self, fallback: T) -> &mut T {
482        self.extensions.get_or_insert(fallback)
483    }
484
485    /// Get an extension or `T`'s [`Default`].
486    ///
487    /// See [`Context::get`] for more details.
488    ///
489    /// # Example
490    ///
491    /// ```
492    /// # use rama_core::Context;
493    /// # let mut ctx = Context::default();
494    /// # ctx.insert(5i32);
495    ///
496    /// assert_eq!(*ctx.get_or_insert_default::<i32>(), 5i32);
497    /// assert_eq!(*ctx.get_or_insert_default::<f64>(), 0f64);
498    /// ```
499    pub fn get_or_insert_default<T: Clone + Default + Send + Sync + 'static>(&mut self) -> &mut T {
500        self.extensions.get_or_insert_default()
501    }
502
503    /// Insert an extension into the [`Context`].
504    ///
505    /// If a extension of this type already existed, it will
506    /// be returned.
507    ///
508    /// See [`Context::get`] for more details regarding extensions.
509    ///
510    /// # Example
511    ///
512    /// ```
513    /// # use rama_core::Context;
514    /// let mut ctx = Context::default();
515    ///
516    /// assert_eq!(ctx.insert(5i32), None);
517    /// assert_eq!(ctx.get::<i32>(), Some(&5i32));
518    ///
519    /// assert_eq!(ctx.insert(4i32), Some(5i32));
520    /// assert_eq!(ctx.get::<i32>(), Some(&4i32));
521    /// ```
522    pub fn insert<T: Clone + Send + Sync + 'static>(&mut self, extension: T) -> Option<T> {
523        self.extensions.insert(extension)
524    }
525
526    /// Insert a type only into this [`Context`], if the extension is `Some(T)`.
527    ///
528    /// See [`Self::insert`] for more information.
529    pub fn maybe_insert<T: Clone + Send + Sync + 'static>(
530        &mut self,
531        extension: Option<T>,
532    ) -> Option<T> {
533        self.extensions.maybe_insert(extension)
534    }
535
536    /// Return the entire dynamic state of the [`Context`] by reference.
537    ///
538    /// Useful only in case you have a function which works with [`Extensions`] rather
539    /// then the [`Context`] itself. In case you want to have access to a specific dynamic state,
540    /// it is more suitable to use [`Context::get`] directly.
541    pub fn extensions(&self) -> &Extensions {
542        &self.extensions
543    }
544
545    /// Return the entire dynamic state of the [`Context`] by mutable reference.
546    ///
547    /// Useful only in case you have a function which works with [`Extensions`] rather
548    /// then the [`Context`] itself. In case you want to have access to a specific dynamic state,
549    /// it is more suitable to use [`Context::get_or_insert`] or [`Context::insert`] directly.
550    ///
551    /// # Rollback
552    ///
553    /// Extensions do not have "rollback" support. In case you are not yet certain if you want to keep
554    /// the to be inserted [`Extensions`], you are better to create a new [`Extensions`] object using
555    /// [`Extensions::default`] and use [`Context::extend`] once you wish to commit the new
556    /// dynamic data into the [`Context`].
557    pub fn extensions_mut(&mut self) -> &mut Extensions {
558        &mut self.extensions
559    }
560
561    /// Extend The [`Context`] [`Extensions`] with another [`Extensions`].
562    ///
563    /// # Example
564    ///
565    /// ```
566    /// # use rama_core::{context::Extensions, Context};
567    /// let mut ctx = Context::default();
568    /// let mut ext = Extensions::default();
569    ///
570    /// ctx.insert(true);
571    /// ext.insert(5i32);
572    /// ctx.extend(ext);
573    ///
574    /// assert_eq!(ctx.get::<bool>(), Some(&true));
575    /// assert_eq!(ctx.get::<i32>(), Some(&5i32));
576    /// ```
577    pub fn extend(&mut self, extensions: Extensions) {
578        self.extensions.extend(extensions);
579    }
580
581    /// Clear the [`Context`] of all inserted [`Extensions`].
582    ///
583    /// # Example
584    ///
585    /// ```
586    /// # use rama_core::Context;
587    /// let mut ctx = Context::default();
588    ///
589    /// ctx.insert(5i32);
590    /// assert_eq!(ctx.get::<i32>(), Some(&5i32));
591    ///
592    /// ctx.clear();
593    /// assert_eq!(ctx.get::<i32>(), None);
594    /// ```
595    pub fn clear(&mut self) {
596        self.extensions.clear();
597    }
598
599    /// Remove an extension from this [`Context`]
600    pub fn remove<T: Clone + Send + Sync + 'static>(&mut self) -> Option<T> {
601        self.extensions.remove()
602    }
603
604    /// Get a reference to the shutdown guard,
605    /// if and only if the context was created within a graceful environment.
606    pub fn guard(&self) -> Option<&ShutdownGuard> {
607        self.executor.guard()
608    }
609}
610
611impl<S: Clone> Context<S> {
612    /// Get a cloned reference to the state.
613    pub fn state_clone(&self) -> S {
614        self.state.clone()
615    }
616}