use std::{iter::once, ops::Deref};
#[cfg(feature = "axum")]
use axum_core::extract::{FromRequestParts, OptionalFromRequestParts};
#[cfg(feature = "axum")]
use axum_extra::TypedHeader;
use headers_core::{Error, Header, HeaderName, HeaderValue};
#[cfg(feature = "axum")]
use http::request::Parts;
#[cfg(feature = "auto-vary")]
use crate::auto_vary::{AutoVaryNotify, HxRequestHeader};
use crate::util::{iter::IterExt, value_string::HeaderValueString};
static HX_TRIGGER: HeaderName = HeaderName::from_static("hx-trigger");
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct HxTrigger(HeaderValueString);
impl HxTrigger {
pub const fn from_static(src: &'static str) -> Self {
Self(HeaderValueString::from_static(src))
}
pub fn as_str(&self) -> &str {
self.0.as_str()
}
}
impl Deref for HxTrigger {
type Target = str;
fn deref(&self) -> &Self::Target {
self.as_str()
}
}
#[cfg(feature = "axum")]
#[cfg_attr(docsrs, doc(cfg(feature = "axum")))]
impl<S> FromRequestParts<S> for HxTrigger
where
S: Send + Sync,
{
type Rejection = <TypedHeader<Self> as FromRequestParts<S>>::Rejection;
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
#[cfg(feature = "auto-vary")]
parts.auto_vary_notify(HxRequestHeader::Trigger).await;
<TypedHeader<Self> as FromRequestParts<S>>::from_request_parts(parts, state)
.await
.map(|header| header.0)
}
}
#[cfg(feature = "axum")]
#[cfg_attr(docsrs, doc(cfg(feature = "axum")))]
impl<S> OptionalFromRequestParts<S> for HxTrigger
where
S: Send + Sync,
{
type Rejection = <TypedHeader<Self> as OptionalFromRequestParts<S>>::Rejection;
async fn from_request_parts(
parts: &mut Parts,
state: &S,
) -> Result<Option<Self>, Self::Rejection> {
#[cfg(feature = "auto-vary")]
parts.auto_vary_notify(HxRequestHeader::Trigger).await;
<TypedHeader<Self> as OptionalFromRequestParts<S>>::from_request_parts(parts, state)
.await
.map(|optional_header| optional_header.map(|header| header.0))
}
}
impl Header for HxTrigger {
fn name() -> &'static HeaderName {
&HX_TRIGGER
}
fn decode<'i, I>(values: &mut I) -> Result<Self, Error>
where
Self: Sized,
I: Iterator<Item = &'i HeaderValue>,
{
values
.just_one()
.map(|value| HeaderValueString::try_from_header_value(value).map(Self))
.transpose()?
.ok_or_else(Error::invalid)
}
fn encode<E: Extend<HeaderValue>>(&self, values: &mut E) {
values.extend(once(self.0.as_header_value().clone()));
}
}