1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0
 */

//! Schedule pure-Python middlewares as [tower::Layer]s.
//!
//! # Moving data from Rust to Python and back
//!
//! In middlewares we need to move some data back-and-forth between Rust and Python.
//! When you move some data from Rust to Python you can't get its ownership back,
//! you can only get `&T` or `&mut T` but not `T` unless you clone it.
//!
//! In order to overcome this shortcoming we are using wrappers for Python that holds
//! pure-Rust types with [Option]s and provides `take_inner(&mut self) -> Option<T>`
//! method to get the ownership of `T` back.
//!
//! For example:
//! ```no_run
//! # use pyo3::prelude::*;
//! # use pyo3::exceptions::PyRuntimeError;
//! # enum PyMiddlewareError {
//! #     InnerGone
//! # }
//! # impl From<PyMiddlewareError> for PyErr {
//! #     fn from(_: PyMiddlewareError) -> PyErr {
//! #         PyRuntimeError::new_err("inner gone")
//! #     }
//! # }
//! // Pure Rust type
//! struct Inner {
//!     num: i32
//! }
//!
//! // Python wrapper
//! #[pyclass]
//! pub struct Wrapper(Option<Inner>);
//!
//! impl Wrapper {
//!     // Call when Python is done processing the `Wrapper`
//!     // to get ownership of `Inner` back
//!     pub fn take_inner(&mut self) -> Option<Inner> {
//!         self.0.take()
//!     }
//! }
//!
//! // Python exposed methods checks if `Wrapper` still has the `Inner` and
//! // fails with `InnerGone` otherwise.
//! #[pymethods]
//! impl Wrapper {
//!     #[getter]
//!     fn num(&self) -> PyResult<i32> {
//!         self.0
//!             .as_ref()
//!             .map(|inner| inner.num)
//!             .ok_or_else(|| PyMiddlewareError::InnerGone.into())
//!     }
//!
//!     #[setter]
//!     fn set_num(&mut self, num: i32) -> PyResult<()> {
//!         match self.0.as_mut() {
//!             Some(inner) => {
//!                 inner.num = num;
//!                 Ok(())
//!             }
//!             None => Err(PyMiddlewareError::InnerGone.into()),
//!         }
//!     }
//! }
//! ```
//!
//! You can see this pattern in [PyRequest], [PyResponse] and the others.
//!

mod error;
mod handler;
mod header_map;
mod layer;
mod request;
mod response;

pub use self::error::PyMiddlewareError;
pub use self::handler::PyMiddlewareHandler;
pub use self::header_map::PyHeaderMap;
pub use self::layer::PyMiddlewareLayer;
pub use self::request::PyRequest;
pub use self::response::PyResponse;