summaryrefslogtreecommitdiff
path: root/vendor/tower/src/load/completion.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/tower/src/load/completion.rs')
-rw-r--r--vendor/tower/src/load/completion.rs95
1 files changed, 95 insertions, 0 deletions
diff --git a/vendor/tower/src/load/completion.rs b/vendor/tower/src/load/completion.rs
new file mode 100644
index 00000000..857e0553
--- /dev/null
+++ b/vendor/tower/src/load/completion.rs
@@ -0,0 +1,95 @@
+//! Application-specific request completion semantics.
+
+use futures_core::ready;
+use pin_project_lite::pin_project;
+use std::{
+ future::Future,
+ pin::Pin,
+ task::{Context, Poll},
+};
+
+/// Attaches `H`-typed completion tracker to `V` typed values.
+///
+/// Handles (of type `H`) are intended to be RAII guards that primarily implement [`Drop`] and update
+/// load metric state as they are dropped. This trait allows implementors to "forward" the handle
+/// to later parts of the request-handling pipeline, so that the handle is only dropped when the
+/// request has truly completed.
+///
+/// This utility allows load metrics to have a protocol-agnostic means to track streams past their
+/// initial response future. For example, if `V` represents an HTTP response type, an
+/// implementation could add `H`-typed handles to each response's extensions to detect when all the
+/// response's extensions have been dropped.
+///
+/// A base `impl<H, V> TrackCompletion<H, V> for CompleteOnResponse` is provided to drop the handle
+/// once the response future is resolved. This is appropriate when a response is discrete and
+/// cannot comprise multiple messages.
+///
+/// In many cases, the `Output` type is simply `V`. However, [`TrackCompletion`] may alter the type
+/// in order to instrument it appropriately. For example, an HTTP [`TrackCompletion`] may modify
+/// the body type: so a [`TrackCompletion`] that takes values of type
+/// [`http::Response<A>`][response] may output values of type [`http::Response<B>`][response].
+///
+/// [response]: https://docs.rs/http/latest/http/response/struct.Response.html
+pub trait TrackCompletion<H, V>: Clone {
+ /// The instrumented value type.
+ type Output;
+
+ /// Attaches a `H`-typed handle to a `V`-typed value.
+ fn track_completion(&self, handle: H, value: V) -> Self::Output;
+}
+
+/// A [`TrackCompletion`] implementation that considers the request completed when the response
+/// future is resolved.
+#[derive(Clone, Copy, Debug, Default)]
+#[non_exhaustive]
+pub struct CompleteOnResponse;
+
+pin_project! {
+ /// Attaches a `C`-typed completion tracker to the result of an `F`-typed [`Future`].
+ #[derive(Debug)]
+ pub struct TrackCompletionFuture<F, C, H> {
+ #[pin]
+ future: F,
+ handle: Option<H>,
+ completion: C,
+ }
+}
+
+// ===== impl InstrumentFuture =====
+
+impl<F, C, H> TrackCompletionFuture<F, C, H> {
+ /// Wraps a future, propagating the tracker into its value if successful.
+ pub const fn new(completion: C, handle: H, future: F) -> Self {
+ TrackCompletionFuture {
+ future,
+ completion,
+ handle: Some(handle),
+ }
+ }
+}
+
+impl<F, C, H, T, E> Future for TrackCompletionFuture<F, C, H>
+where
+ F: Future<Output = Result<T, E>>,
+ C: TrackCompletion<H, T>,
+{
+ type Output = Result<C::Output, E>;
+
+ fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+ let this = self.project();
+ let rsp = ready!(this.future.poll(cx))?;
+ let h = this.handle.take().expect("handle");
+ Poll::Ready(Ok(this.completion.track_completion(h, rsp)))
+ }
+}
+
+// ===== CompleteOnResponse =====
+
+impl<H, V> TrackCompletion<H, V> for CompleteOnResponse {
+ type Output = V;
+
+ fn track_completion(&self, handle: H, value: V) -> V {
+ drop(handle);
+ value
+ }
+}