Skip to main content

hitbox_http/
cacheable.rs

1use hyper::body::Body as HttpBody;
2
3use crate::BufferedBody;
4
5/// Enables predicates and extractors to work uniformly with requests and responses.
6///
7/// This trait abstracts over the common pattern of decomposing an HTTP message into
8/// its metadata (headers, status, method, etc.) and body, then reconstructing it.
9/// Predicates that inspect the body use this to temporarily take ownership of the
10/// body, examine it, and return a potentially modified subject.
11///
12/// # For Implementors
13///
14/// Implementations must ensure round-trip consistency: calling `from_parts` with
15/// the result of `into_parts` must produce an equivalent subject.
16///
17/// ```
18/// use hitbox_http::CacheableSubject;
19///
20/// fn round_trip<S: CacheableSubject>(subject: S) -> S {
21///     let (parts, body) = subject.into_parts();
22///     S::from_parts(parts, body)
23///     // reconstructed should be equivalent to subject
24/// }
25/// ```
26///
27/// # For Callers
28///
29/// Use this trait when writing predicates or extractors that need to:
30/// - Inspect the body without fully consuming it
31/// - Pass the subject through a chain of operations
32/// - Work generically with both requests and responses
33///
34/// # Caveats
35///
36/// After `into_parts`, the body may be in a different state than before. If a
37/// predicate consumed bytes, the body transitions from `Passthrough` to `Partial`
38/// or `Complete`. Callers must handle all [`BufferedBody`] states.
39pub trait CacheableSubject {
40    /// The HTTP body type.
41    type Body: HttpBody;
42
43    /// The metadata type (e.g., [`http::request::Parts`] or [`http::response::Parts`]).
44    type Parts;
45
46    /// Decomposes this subject into metadata and body.
47    ///
48    /// After this call, the body may be in any [`BufferedBody`] state depending
49    /// on prior operations.
50    fn into_parts(self) -> (Self::Parts, BufferedBody<Self::Body>);
51
52    /// Reconstructs a subject from metadata and body.
53    ///
54    /// This is the inverse of [`into_parts`](Self::into_parts).
55    fn from_parts(parts: Self::Parts, body: BufferedBody<Self::Body>) -> Self;
56}