summaryrefslogtreecommitdiff
path: root/src/event/extract.rs
diff options
context:
space:
mode:
authorKit La Touche <kit@transneptune.net>2025-02-21 22:18:56 -0500
committerKit La Touche <kit@transneptune.net>2025-02-21 22:53:49 -0500
commit9d1dbac74866a6175c65a25bbd8a3ccbe8cf87e4 (patch)
treef15b3f0695b948e335774aa4d92a5b064a1c0f10 /src/event/extract.rs
parent743b59b69857da81b214970ec9252bc918ad243d (diff)
parent36cadfe00cacc6a6523f9862d3f7a08a9d0ce611 (diff)
Merge branch 'main' into prop/preserve-state
Diffstat (limited to 'src/event/extract.rs')
-rw-r--r--src/event/extract.rs45
1 files changed, 37 insertions, 8 deletions
diff --git a/src/event/extract.rs b/src/event/extract.rs
index e3021e2..8fde1d5 100644
--- a/src/event/extract.rs
+++ b/src/event/extract.rs
@@ -1,11 +1,11 @@
use std::ops::Deref;
use axum::{
- extract::FromRequestParts,
- http::{request::Parts, HeaderName, HeaderValue},
+ extract::{FromRequestParts, OptionalFromRequestParts},
+ http::{HeaderName, HeaderValue, request::Parts},
};
use axum_extra::typed_header::TypedHeader;
-use serde::{de::DeserializeOwned, Serialize};
+use serde::{Serialize, de::DeserializeOwned};
// A typed header. When used as a bare extractor, reads from the
// `Last-Event-Id` HTTP header.
@@ -44,7 +44,6 @@ where
}
}
-#[async_trait::async_trait]
impl<S, T> FromRequestParts<S> for LastEventId<T>
where
S: Send + Sync,
@@ -53,12 +52,35 @@ where
type Rejection = <TypedHeader<Self> as FromRequestParts<S>>::Rejection;
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
- // This is purely for ergonomics: it allows `RequestedAt` to be extracted
- // without having to wrap it in `Extension<>`. Callers _can_ still do that,
+ // This is purely for ergonomics: it allows `LastEventId` to be extracted
+ // without having to wrap it in `TypedHeader<>`. Callers _can_ still do that,
// but they aren't forced to.
- let TypedHeader(requested_at) = TypedHeader::from_request_parts(parts, state).await?;
+ let header =
+ <TypedHeader<Self> as FromRequestParts<S>>::from_request_parts(parts, state).await?;
- Ok(requested_at)
+ Ok(header.into())
+ }
+}
+
+impl<S, T> OptionalFromRequestParts<S> for LastEventId<T>
+where
+ S: Send + Sync,
+ T: Serialize + DeserializeOwned,
+{
+ type Rejection = <TypedHeader<Self> as FromRequestParts<S>>::Rejection;
+
+ async fn from_request_parts(
+ parts: &mut Parts,
+ state: &S,
+ ) -> Result<Option<Self>, Self::Rejection> {
+ // This is purely for ergonomics: it allows `Option<LastEventId>` to be extracted
+ // without having to wrap it in `TypedHeader<>`. Callers _can_ still do that,
+ // but they aren't forced to.
+ let header =
+ <TypedHeader<Self> as OptionalFromRequestParts<S>>::from_request_parts(parts, state)
+ .await?;
+
+ Ok(header.map(Self::from))
}
}
@@ -71,6 +93,13 @@ impl<T> Deref for LastEventId<T> {
}
}
+impl<T> From<TypedHeader<LastEventId<T>>> for LastEventId<T> {
+ fn from(header: TypedHeader<Self>) -> Self {
+ let TypedHeader(value) = header;
+ value
+ }
+}
+
impl<T> From<T> for LastEventId<T> {
fn from(value: T) -> Self {
Self(value)