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}