diff options
| author | Kit La Touche <kit@transneptune.net> | 2025-02-21 22:18:56 -0500 |
|---|---|---|
| committer | Kit La Touche <kit@transneptune.net> | 2025-02-21 22:53:49 -0500 |
| commit | 9d1dbac74866a6175c65a25bbd8a3ccbe8cf87e4 (patch) | |
| tree | f15b3f0695b948e335774aa4d92a5b064a1c0f10 /src/event/extract.rs | |
| parent | 743b59b69857da81b214970ec9252bc918ad243d (diff) | |
| parent | 36cadfe00cacc6a6523f9862d3f7a08a9d0ce611 (diff) | |
Merge branch 'main' into prop/preserve-state
Diffstat (limited to 'src/event/extract.rs')
| -rw-r--r-- | src/event/extract.rs | 45 |
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) |
