Skip to main content

tower_http/on_early_drop/
traits.rs

1//! Hook traits invoked when a response future or response body is dropped
2//! Hook traits invoked when a response future or response body is dropped
3//! before completion.
4
5use http::{response, Request};
6
7/// Callback fired exactly once when an early-drop event is observed.
8///
9/// `FnOnce() + Send + 'static` closures implement this via a blanket impl.
10///
11/// # Panics
12///
13/// Implementations must not panic. Callbacks fire from [`Drop`]; panicking
14/// during a drop that occurs while another panic is unwinding aborts the
15/// process. The crate's built-in callbacks are panic-free.
16pub trait OnDropCallback: Send + 'static {
17    /// Fire the callback. Consumes `self`.
18    fn on_drop(self);
19}
20
21impl<F> OnDropCallback for F
22where
23    F: FnOnce() + Send + 'static,
24{
25    fn on_drop(self) {
26        self()
27    }
28}
29
30/// No-op callback used as the default for empty hook slots.
31#[derive(Debug, Clone, Copy)]
32pub struct NoopDropCallback;
33
34impl OnDropCallback for NoopDropCallback {
35    fn on_drop(self) {}
36}
37
38/// Hook fired when the response future is dropped before producing a result.
39///
40/// See the [module docs](super) for the example.
41pub trait OnFutureDrop<ReqB> {
42    /// The callback produced for each request.
43    type Callback: OnDropCallback;
44
45    /// Produce a callback for the given request.
46    fn make(&mut self, request: &Request<ReqB>) -> Self::Callback;
47}
48
49impl<F, C, ReqB> OnFutureDrop<ReqB> for F
50where
51    F: FnMut(&Request<ReqB>) -> C,
52    C: OnDropCallback,
53{
54    type Callback = C;
55
56    fn make(&mut self, request: &Request<ReqB>) -> Self::Callback {
57        (self)(request)
58    }
59}
60
61impl<ReqB> OnFutureDrop<ReqB> for () {
62    type Callback = NoopDropCallback;
63
64    fn make(&mut self, _request: &Request<ReqB>) -> Self::Callback {
65        NoopDropCallback
66    }
67}
68
69/// Hook fired when the response body is dropped before reaching
70/// end-of-stream.
71///
72/// See the [module docs](super) for the example and phase breakdown.
73pub trait OnBodyDrop<ReqB> {
74    /// State carried from [`make_at_call`](Self::make_at_call) to
75    /// [`make_at_response`](Self::make_at_response).
76    type Intermediate: Send + 'static;
77
78    /// The final callback produced for each response.
79    type Callback: OnDropCallback;
80
81    /// Capture request-time context.
82    fn make_at_call(&mut self, request: &Request<ReqB>) -> Self::Intermediate;
83
84    /// Capture response-time context and produce the final callback.
85    fn make_at_response(
86        &mut self,
87        intermediate: Self::Intermediate,
88        response_parts: &response::Parts,
89    ) -> Self::Callback;
90}
91
92impl<ReqB> OnBodyDrop<ReqB> for () {
93    type Intermediate = ();
94    type Callback = NoopDropCallback;
95
96    fn make_at_call(&mut self, _request: &Request<ReqB>) -> Self::Intermediate {}
97
98    fn make_at_response(
99        &mut self,
100        _intermediate: Self::Intermediate,
101        _response_parts: &response::Parts,
102    ) -> Self::Callback {
103        NoopDropCallback
104    }
105}
106
107/// Adapter making `FnMut(&Request) -> FnOnce(&Parts) -> FnOnce()` closure
108/// chains implement [`OnBodyDrop`].
109///
110/// See the [module docs](super) for the example.
111#[derive(Clone, Copy)]
112pub struct OnBodyDropFn<F>(F);
113
114impl<F> OnBodyDropFn<F> {
115    /// Wrap a closure chain as an [`OnBodyDrop`] hook.
116    pub fn new(f: F) -> Self {
117        Self(f)
118    }
119}
120
121impl<F> std::fmt::Debug for OnBodyDropFn<F> {
122    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
123        f.debug_struct("OnBodyDropFn").finish_non_exhaustive()
124    }
125}
126
127impl<F, G, C, ReqB> OnBodyDrop<ReqB> for OnBodyDropFn<F>
128where
129    F: FnMut(&Request<ReqB>) -> G,
130    G: FnOnce(&response::Parts) -> C + Send + 'static,
131    C: OnDropCallback,
132{
133    type Intermediate = G;
134    type Callback = C;
135
136    fn make_at_call(&mut self, request: &Request<ReqB>) -> Self::Intermediate {
137        (self.0)(request)
138    }
139
140    fn make_at_response(
141        &mut self,
142        intermediate: Self::Intermediate,
143        response_parts: &response::Parts,
144    ) -> Self::Callback {
145        (intermediate)(response_parts)
146    }
147}