openapi_context/
context.rs

1//! Module for API context management.
2//!
3//! This module defines traits and structs that can be used  to manage
4//! contextual data related to a request, as it is passed through a series of
5//! hyper services.
6//!
7//! See the `context_tests` module below for examples of how to use.
8
9use crate::XSpanId;
10use crate::auth::{AuthData, Authorization};
11use std::marker::Sized;
12
13/// Defines methods for accessing, modifying, adding and removing the data stored
14/// in a context. Used to specify the requirements that a hyper service makes on
15/// a generic context type that it receives with a request, e.g.
16///
17/// ```rust
18/// # use openapi_context::context::*;
19/// # use futures::future::ok;
20/// # use std::future::Future;
21/// # use std::marker::PhantomData;
22/// #
23/// # struct MyItem;
24/// # fn do_something_with_my_item(item: &MyItem) {}
25/// #
26/// struct MyService<C> {
27///     marker: PhantomData<C>,
28/// }
29///
30/// impl<C> hyper::service::Service for MyService<C>
31///     where C: Has<MyItem> + Send + 'static
32/// {
33///     type ReqBody = ContextualPayload<hyper::Body, C>;
34///     type ResBody = hyper::Body;
35///     type Error = std::io::Error;
36///     type Future = Box<dyn Future<Item=hyper::Response<Self::ResBody>, Error=Self::Error>>;
37///     fn call(&mut self, req : hyper::Request<Self::ReqBody>) -> Self::Future {
38///         let (head, body) = req.into_parts();
39///         do_something_with_my_item(Has::<MyItem>::get(&body.context));
40///         Box::new(ok(hyper::Response::new(hyper::Body::empty())))
41///     }
42/// }
43///
44/// # fn main() {}
45/// ```
46pub trait Has<T> {
47    /// Get an immutable reference to the value.
48    fn get(&self) -> &T;
49    /// Get a mutable reference to the value.
50    fn get_mut(&mut self) -> &mut T;
51    /// Set the value.
52    fn set(&mut self, value: T);
53}
54
55/// Defines a method for permanently extracting a value, changing the resulting
56/// type. Used to specify that a hyper service consumes some data from the context,
57/// making it unavailable to later layers, e.g.
58///
59/// ```rust
60/// # extern crate hyper;
61/// # extern crate swagger;
62/// # extern crate futures;
63/// #
64/// # use swagger::context::*;
65/// # use futures::future::{Future, ok};
66/// # use std::marker::PhantomData;
67/// #
68/// struct MyItem1;
69/// struct MyItem2;
70/// struct MyItem3;
71///
72/// struct MiddlewareService<T, C> {
73///     inner: T,
74///     marker: PhantomData<C>,
75/// }
76///
77/// impl<T, C, D, E> hyper::service::Service for MiddlewareService<T, C>
78///     where
79///         C: Pop<MyItem1, Result=D> + Send + 'static,
80///         D: Pop<MyItem2, Result=E>,
81///         E: Pop<MyItem3>,
82///         E::Result: Send + 'static,
83///         T: hyper::service::Service<ReqBody=ContextualPayload<hyper::Body, E::Result>>
84/// {
85///     type ReqBody = ContextualPayload<hyper::Body, C>;
86///     type ResBody = T::ResBody;
87///     type Error = T::Error;
88///     type Future = T::Future;
89///     fn call(&mut self, req : hyper::Request<Self::ReqBody>) -> Self::Future {
90///         let (head, body) = req.into_parts();
91///         let context = body.context;
92///
93///         // type annotations optional, included for illustrative purposes
94///         let (_, context): (MyItem1, D) = context.pop();
95///         let (_, context): (MyItem2, E) = context.pop();
96///         let (_, context): (MyItem3, E::Result) = context.pop();
97///
98///         let req = hyper::Request::from_parts(head, ContextualPayload { inner: body.inner, context });
99///         self.inner.call(req)
100///     }
101/// }
102///
103/// # fn main() {}
104pub trait Pop<T> {
105    /// The type that remains after the value has been popped.
106    type Result;
107    /// Extracts a value.
108    fn pop(self) -> (T, Self::Result);
109}
110
111/// Defines a method for inserting a value, changing the resulting
112/// type. Used to specify that a hyper service adds some data from the context,
113/// making it available to later layers, e.g.
114///
115/// ```rust
116/// # extern crate hyper;
117/// # extern crate swagger;
118/// # extern crate futures;
119/// #
120/// # use swagger::context::*;
121/// # use futures::future::{Future, ok};
122/// # use std::marker::PhantomData;
123/// #
124/// struct MyItem1;
125/// struct MyItem2;
126/// struct MyItem3;
127///
128/// struct MiddlewareService<T, C> {
129///     inner: T,
130///     marker: PhantomData<C>,
131/// }
132///
133/// impl<T, C, D, E> hyper::service::Service for MiddlewareService<T, C>
134///     where
135///         C: Push<MyItem1, Result=D> + Send + 'static,
136///         D: Push<MyItem2, Result=E>,
137///         E: Push<MyItem3>,
138///         E::Result: Send + 'static,
139///         T: hyper::service::Service<ReqBody=ContextualPayload<hyper::Body, E::Result>>
140/// {
141///     type ReqBody = ContextualPayload<hyper::Body, C>;
142///     type ResBody = T::ResBody;
143///     type Error = T::Error;
144///     type Future = T::Future;
145///     fn call(&mut self, req : hyper::Request<Self::ReqBody>) -> Self::Future {
146///         let (head, body) = req.into_parts();
147///         let context = body.context
148///             .push(MyItem1{})
149///             .push(MyItem2{})
150///             .push(MyItem3{});
151///         let req = hyper::Request::from_parts(head, ContextualPayload { inner: body.inner, context });
152///         self.inner.call(req)
153///     }
154/// }
155///
156/// # fn main() {}
157pub trait Push<T> {
158    /// The type that results from adding an item.
159    type Result;
160    /// Inserts a value.
161    fn push(self, v: T) -> Self::Result;
162}
163
164/// Defines a struct that can be used to build up contexts recursively by
165/// adding one item to the context at a time, and a unit struct representing an
166/// empty context. The first argument is the name of the newly defined context struct
167/// that is used to add an item to the context, the second argument is the name of
168/// the empty context struct, and subsequent arguments are the types
169/// that can be stored in contexts built using these struct.
170///
171/// A cons list built using the generated context type will implement Has<T> and Pop<T>
172/// for each type T that appears in the list, provided that the list only
173/// contains the types that were passed to the macro invocation after the context
174/// type name.
175///
176/// All list types constructed using the generated types will implement `Push<T>`
177/// for all types `T` that appear in the list passed to the macro invocation.
178///
179/// E.g.
180///
181/// ```rust
182/// # use openapi_context::{new_context_type, Has, Pop, Push};
183///
184/// #[derive(Default)]
185/// struct MyType1;
186/// #[derive(Default)]
187/// struct MyType2;
188/// #[derive(Default)]
189/// struct MyType3;
190/// #[derive(Default)]
191/// struct MyType4;
192///
193/// new_context_type!(MyContext, MyEmpContext, MyType1, MyType2, MyType3);
194///
195/// fn use_has_my_type_1<T: Has<MyType1>> (_: &T) {}
196/// fn use_has_my_type_2<T: Has<MyType2>> (_: &T) {}
197/// fn use_has_my_type_3<T: Has<MyType3>> (_: &T) {}
198/// fn use_has_my_type_4<T: Has<MyType4>> (_: &T) {}
199///
200/// // will implement `Has<MyType1>` and `Has<MyType2>` because these appear
201/// // in the type, and were passed to `new_context_type!`. Will not implement
202/// // `Has<MyType3>` even though it was passed to `new_context_type!`, because
203/// // it is not included in the type.
204/// type ExampleContext = MyContext<MyType1, MyContext<MyType2,  MyEmpContext>>;
205///
206/// // Will not implement `Has<MyType4>` even though it appears in the type,
207/// // because `MyType4` was not passed to `new_context_type!`.
208/// type BadContext = MyContext<MyType1, MyContext<MyType4, MyEmpContext>>;
209///
210/// fn main() {
211///     let context : ExampleContext =
212///         MyEmpContext::default()
213///         .push(MyType2{})
214///         .push(MyType1{});
215///
216///     use_has_my_type_1(&context);
217///     use_has_my_type_2(&context);
218///     // use_has_my_type_3(&context);      // will fail
219///
220///     // Will fail because `MyType4`// was not passed to `new_context_type!`
221///     // let context = MyEmpContext::default().push(MyType4{});
222///
223///     let bad_context: BadContext = BadContext::default();
224///     // use_has_my_type_4(&bad_context);  // will fail
225///
226/// }
227/// ```
228///
229/// See the `context_tests` module for more usage examples.
230#[macro_export]
231macro_rules! new_context_type {
232    ($context_name:ident, $empty_context_name:ident, $($types:ty),+ ) => {
233
234        /// Wrapper type for building up contexts recursively, adding one item
235        /// to the context at a time.
236        #[derive(Debug, Clone, Default, PartialEq, Eq)]
237        pub struct $context_name<T, C> {
238            head: T,
239            tail: C,
240        }
241
242        /// Unit struct representing an empty context with no data in it.
243        #[derive(Debug, Clone, Default, PartialEq, Eq)]
244        pub struct $empty_context_name;
245
246        // implement `Push<T>` on the empty context type for each type `T` that
247        // was passed to the macro
248        $(
249        impl Push<$types> for $empty_context_name {
250            type Result = $context_name<$types, Self>;
251            fn push(self, item: $types) -> Self::Result {
252                $context_name{head: item, tail: Self::default()}
253            }
254        }
255
256        // implement `Has<T>` for a list where `T` is the type of the head
257        impl<C> $crate::Has<$types> for $context_name<$types, C> {
258            fn set(&mut self, item: $types) {
259                self.head = item;
260            }
261
262            fn get(&self) -> &$types {
263                &self.head
264            }
265
266            fn get_mut(&mut self) -> &mut $types {
267                &mut self.head
268            }
269        }
270
271        // implement `Pop<T>` for a list where `T` is the type of the head
272        impl<C> $crate::Pop<$types> for $context_name<$types, C> {
273            type Result = C;
274            fn pop(self) -> ($types, Self::Result) {
275                (self.head, self.tail)
276            }
277        }
278
279        // implement `Push<U>` for non-empty lists, for each type `U` that was passed
280        // to the macro
281        impl<C, T> Push<$types> for $context_name<T, C> {
282            type Result = $context_name<$types, Self>;
283            fn push(self, item: $types) -> Self::Result {
284                $context_name{head: item, tail: self}
285            }
286        }
287        )+
288
289        // Add implementations of `Has<T>` and `Pop<T>` when `T` is any type stored in
290        // the list, not just the head.
291        new_context_type!(impl extend_has $context_name, $empty_context_name, $($types),+);
292    };
293
294    // "HELPER" MACRO CASE - NOT FOR EXTERNAL USE
295    // takes a type `Type1` ($head) and a non-empty list of types `Types` ($tail). First calls
296    // another helper macro to define the following impls, for each `Type2` in `Types`:
297    // ```
298    // impl<C: Has<Type1> Has<Type1> for $context_name<Type2, C> {...}
299    // impl<C: Has<Type2> Has<Type2> for $context_name<Type1, C> {...}
300    // impl<C: Pop<Type1> Pop<Type1> for $context_name<Type2, C> {...}
301    // impl<C: Pop<Type2> Pop<Type2> for $context_name<Type1, C> {...}
302    // ```
303    // then calls itself again with the rest of the list. The end result is to define the above
304    // impls for all distinct pairs of types in the original list.
305    (impl extend_has $context_name:ident, $empty_context_name:ident, $head:ty, $($tail:ty),+ ) => {
306
307        new_context_type!(
308            impl extend_has_helper
309            $context_name,
310            $empty_context_name,
311            $head,
312            $($tail),+
313        );
314        new_context_type!(impl extend_has $context_name, $empty_context_name, $($tail),+);
315    };
316
317    // "HELPER" MACRO CASE - NOT FOR EXTERNAL USE
318    // base case of the preceding helper macro - was passed an empty list of types, so
319    // we don't need to do anything.
320    (impl extend_has $context_name:ident, $empty_context_name:ident, $head:ty) => {};
321
322    // "HELPER" MACRO CASE - NOT FOR EXTERNAL USE
323    // takes a type `Type1` ($type) and a non-empty list of types `Types` ($types). For
324    // each `Type2` in `Types`, defines the following impls:
325    // ```
326    // impl<C: Has<Type1> Has<Type1> for $context_name<Type2, C> {...}
327    // impl<C: Has<Type2> Has<Type2> for $context_name<Type1, C> {...}
328    // impl<C: Pop<Type1> Pop<Type1> for $context_name<Type2, C> {...}
329    // impl<C: Pop<Type2> Pop<Type2> for $context_name<Type1, C> {...}
330    // ```
331    //
332    (impl extend_has_helper
333        $context_name:ident,
334        $empty_context_name:ident,
335        $type:ty,
336        $($types:ty),+
337        ) => {
338        $(
339            impl<C: $crate::Has<$type>> $crate::Has<$type> for $context_name<$types, C> {
340                fn set(&mut self, item: $type) {
341                    self.tail.set(item);
342                }
343
344                fn get(&self) -> &$type {
345                    self.tail.get()
346                }
347
348                fn get_mut(&mut self) -> &mut $type {
349                    self.tail.get_mut()
350                }
351            }
352
353            impl<C: $crate::Has<$types>> $crate::Has<$types> for $context_name<$type, C> {
354                fn set(&mut self, item: $types) {
355                    self.tail.set(item);
356                }
357
358                fn get(&self) -> &$types {
359                    self.tail.get()
360                }
361
362                fn get_mut(&mut self) -> &mut $types {
363                    self.tail.get_mut()
364                }
365            }
366
367            impl<C> $crate::Pop<$type> for $context_name<$types, C> where C: Pop<$type> {
368                type Result = $context_name<$types, C::Result>;
369                fn pop(self) -> ($type, Self::Result) {
370                    let (value, tail) = self.tail.pop();
371                    (value, $context_name{ head: self.head, tail})
372                }
373            }
374
375            impl<C> $crate::Pop<$types> for $context_name<$type, C> where C: Pop<$types> {
376                type Result = $context_name<$type, C::Result>;
377                fn pop(self) -> ($types, Self::Result) {
378                    let (value, tail) = self.tail.pop();
379                    (value, $context_name{ head: self.head, tail})
380                }
381            }
382        )+
383    };
384}
385
386// Create a default context type to export.
387new_context_type!(
388    ContextBuilder,
389    EmptyContext,
390    XSpanId,
391    Option<AuthData>,
392    Option<Authorization>
393);
394
395/// Macro for easily defining context types. The first argument should be a
396/// context type created with `new_context_type!` and subsequent arguments are the
397/// types to be stored in the context, with the outermost first.
398///
399/// ```rust
400/// # use openapi_context::{new_context_type, make_context_ty, Has, Pop, Push};
401///
402/// # struct Type1;
403/// # struct Type2;
404/// # struct Type3;
405///
406/// # new_context_type!(MyContext, MyEmptyContext, Type1, Type2, Type3);
407///
408/// // the following two types are identical
409/// type ExampleContext1 = make_context_ty!(MyContext, MyEmptyContext, Type1, Type2, Type3);
410/// type ExampleContext2 = MyContext<Type1, MyContext<Type2, MyContext<Type3, MyEmptyContext>>>;
411///
412/// // e.g. this wouldn't compile if they were different types
413/// fn do_nothing(input: ExampleContext1) -> ExampleContext2 {
414///     input
415/// }
416///
417/// # fn main() {}
418/// ```
419#[macro_export]
420macro_rules! make_context_ty {
421    ($context_name:ident, $empty_context_name:ident, $type:ty $(, $types:ty)* $(,)* ) => {
422        $context_name<$type, make_context_ty!($context_name, $empty_context_name, $($types),*)>
423    };
424    ($context_name:ident, $empty_context_name:ident $(,)* ) => {
425        $empty_context_name
426    };
427}
428
429/// Macro for easily defining context values. The first argument should be a
430/// context type created with `new_context_type!` and subsequent arguments are the
431/// values to be stored in the context, with the outermost first.
432///
433/// ```rust
434/// # use openapi_context::{new_context_type, make_context, Has, Pop, Push};
435///
436/// # #[derive(PartialEq, Eq, Debug)]
437/// # struct Type1;
438/// # #[derive(PartialEq, Eq, Debug)]
439/// # struct Type2;
440/// # #[derive(PartialEq, Eq, Debug)]
441/// # struct Type3;
442///
443/// # new_context_type!(MyContext, MyEmptyContext, Type1, Type2, Type3);
444///
445/// fn main() {
446///     // the following are equivalent
447///     let context1 = make_context!(MyContext, MyEmptyContext, Type1 {}, Type2 {}, Type3 {});
448///     let context2 = MyEmptyContext::default()
449///         .push(Type3{})
450///         .push(Type2{})
451///         .push(Type1{});
452///
453///     assert_eq!(context1, context2);
454/// }
455/// ```
456#[macro_export]
457macro_rules! make_context {
458    ($context_name:ident, $empty_context_name:ident, $value:expr $(, $values:expr)* $(,)*) => {
459        make_context!($context_name, $empty_context_name, $($values),*).push($value)
460    };
461    ($context_name:ident, $empty_context_name:ident $(,)* ) => {
462        $empty_context_name::default()
463    };
464}
465
466/// Context wrapper, to bind an API with a context.
467#[derive(Debug)]
468pub struct ContextWrapper<T, C> {
469    api: T,
470    context: C,
471}
472
473impl<T, C> ContextWrapper<T, C> {
474    /// Create a new ContextWrapper, binding the API and context.
475    pub fn new(api: T, context: C) -> ContextWrapper<T, C> {
476        ContextWrapper { api, context }
477    }
478
479    /// Borrows the API.
480    pub fn api(&self) -> &T {
481        &self.api
482    }
483
484    /// Borrows the API mutably.
485    pub fn api_mut(&mut self) -> &mut T {
486        &mut self.api
487    }
488
489    /// Borrows the context.
490    pub fn context(&self) -> &C {
491        &self.context
492    }
493}
494
495impl<T: Clone, C: Clone> Clone for ContextWrapper<T, C> {
496    fn clone(&self) -> Self {
497        ContextWrapper {
498            api: self.api.clone(),
499            context: self.context.clone(),
500        }
501    }
502}
503
504/// Trait to extend an API to make it easy to bind it to a context.
505pub trait ContextWrapperExt<'a, C>
506where
507    Self: Sized,
508{
509    /// Binds this API to a context.
510    fn with_context(self: Self, context: C) -> ContextWrapper<Self, C> {
511        ContextWrapper::<Self, C>::new(self, context)
512    }
513}
514
515/// This represents context provided as part of the request or the response
516#[derive(Debug)]
517pub struct ContextualPayload<Ctx>
518    where Ctx: Send + 'static,
519{
520    /// The inner payload for this request/response
521    pub inner: hyper::Request<hyper::Body>,
522    /// Request or Response Context
523    pub context: Ctx,
524}
525
526#[cfg(test)]
527mod context_tests {
528    use super::*;
529
530    struct ContextItem1;
531    struct ContextItem2;
532    struct ContextItem3;
533
534    fn use_item_1_owned(_: ContextItem1) {}
535    fn use_item_2(_: &ContextItem2) {}
536    fn use_item_3_owned(_: ContextItem3) {}
537
538    // Example of use by a service in its main.rs file. At this point you know
539    // all the hyper service layers you will be using, and what requirements
540    // their contexts types have. Use the `new_context_type!` macro to create
541    // a context type and empty context type that are capable of containing all the
542    // types that your hyper services require.
543    new_context_type!(
544        MyContext,
545        MyEmptyContext,
546        ContextItem1,
547        ContextItem2,
548        ContextItem3
549    );
550
551}