1use axum_core::extract::FromRequestParts;
4use http::request::Parts;
5
6use crate::{
7 HX_BOOSTED, HX_CURRENT_URL, HX_HISTORY_RESTORE_REQUEST, HX_PROMPT, HX_REQUEST, HX_TARGET,
8 HX_TRIGGER, HX_TRIGGER_NAME,
9};
10
11#[derive(Debug, Clone, Copy)]
21pub struct HxBoosted(pub bool);
22
23impl<S> FromRequestParts<S> for HxBoosted
24where
25 S: Send + Sync,
26{
27 type Rejection = std::convert::Infallible;
28
29 async fn from_request_parts(parts: &mut Parts, _: &S) -> Result<Self, Self::Rejection> {
30 if parts.headers.contains_key(HX_BOOSTED) {
31 Ok(HxBoosted(true))
32 } else {
33 Ok(HxBoosted(false))
34 }
35 }
36}
37
38#[derive(Debug, Clone)]
46pub struct HxCurrentUrl(pub Option<http::Uri>);
47
48impl<S> FromRequestParts<S> for HxCurrentUrl
49where
50 S: Send + Sync,
51{
52 type Rejection = std::convert::Infallible;
53
54 async fn from_request_parts(parts: &mut Parts, _: &S) -> Result<Self, Self::Rejection> {
55 if let Some(url) = parts.headers.get(HX_CURRENT_URL) {
56 let url = url
57 .to_str()
58 .ok()
59 .and_then(|url| url.parse::<http::Uri>().ok());
60
61 return Ok(HxCurrentUrl(url));
62 }
63
64 Ok(HxCurrentUrl(None))
65 }
66}
67
68#[derive(Debug, Clone, Copy)]
73pub struct HxHistoryRestoreRequest(pub bool);
74
75impl<S> FromRequestParts<S> for HxHistoryRestoreRequest
76where
77 S: Send + Sync,
78{
79 type Rejection = std::convert::Infallible;
80
81 async fn from_request_parts(parts: &mut Parts, _: &S) -> Result<Self, Self::Rejection> {
82 if parts.headers.contains_key(HX_HISTORY_RESTORE_REQUEST) {
83 Ok(HxHistoryRestoreRequest(true))
84 } else {
85 Ok(HxHistoryRestoreRequest(false))
86 }
87 }
88}
89
90#[derive(Debug, Clone)]
98pub struct HxPrompt(pub Option<String>);
99
100impl<S> FromRequestParts<S> for HxPrompt
101where
102 S: Send + Sync,
103{
104 type Rejection = std::convert::Infallible;
105
106 async fn from_request_parts(parts: &mut Parts, _: &S) -> Result<Self, Self::Rejection> {
107 if let Some(prompt) = parts.headers.get(HX_PROMPT) {
108 if let Ok(prompt) = prompt.to_str() {
109 return Ok(HxPrompt(Some(prompt.to_string())));
110 }
111 }
112
113 Ok(HxPrompt(None))
114 }
115}
116
117#[derive(Debug, Clone, Copy)]
125pub struct HxRequest(pub bool);
126
127impl<S> FromRequestParts<S> for HxRequest
128where
129 S: Send + Sync,
130{
131 type Rejection = std::convert::Infallible;
132
133 async fn from_request_parts(parts: &mut Parts, _: &S) -> Result<Self, Self::Rejection> {
134 #[cfg(feature = "auto-vary")]
135 parts
136 .extensions
137 .get_mut::<crate::auto_vary::HxRequestExtracted>()
138 .map(crate::auto_vary::Notifier::notify);
139
140 if parts.headers.contains_key(HX_REQUEST) {
141 Ok(HxRequest(true))
142 } else {
143 Ok(HxRequest(false))
144 }
145 }
146}
147
148#[derive(Debug, Clone)]
157pub struct HxTarget(pub Option<String>);
158
159impl<S> FromRequestParts<S> for HxTarget
160where
161 S: Send + Sync,
162{
163 type Rejection = std::convert::Infallible;
164
165 async fn from_request_parts(parts: &mut Parts, _: &S) -> Result<Self, Self::Rejection> {
166 #[cfg(feature = "auto-vary")]
167 parts
168 .extensions
169 .get_mut::<crate::auto_vary::HxTargetExtracted>()
170 .map(crate::auto_vary::Notifier::notify);
171
172 if let Some(target) = parts.headers.get(HX_TARGET) {
173 if let Ok(target) = target.to_str() {
174 return Ok(HxTarget(Some(target.to_string())));
175 }
176 }
177
178 Ok(HxTarget(None))
179 }
180}
181
182#[derive(Debug, Clone)]
191pub struct HxTriggerName(pub Option<String>);
192
193impl<S> FromRequestParts<S> for HxTriggerName
194where
195 S: Send + Sync,
196{
197 type Rejection = std::convert::Infallible;
198
199 async fn from_request_parts(parts: &mut Parts, _: &S) -> Result<Self, Self::Rejection> {
200 #[cfg(feature = "auto-vary")]
201 parts
202 .extensions
203 .get_mut::<crate::auto_vary::HxTriggerNameExtracted>()
204 .map(crate::auto_vary::Notifier::notify);
205
206 if let Some(trigger_name) = parts.headers.get(HX_TRIGGER_NAME) {
207 if let Ok(trigger_name) = trigger_name.to_str() {
208 return Ok(HxTriggerName(Some(trigger_name.to_string())));
209 }
210 }
211
212 Ok(HxTriggerName(None))
213 }
214}
215
216#[derive(Debug, Clone)]
225pub struct HxTrigger(pub Option<String>);
226
227impl<S> FromRequestParts<S> for HxTrigger
228where
229 S: Send + Sync,
230{
231 type Rejection = std::convert::Infallible;
232
233 async fn from_request_parts(parts: &mut Parts, _: &S) -> Result<Self, Self::Rejection> {
234 #[cfg(feature = "auto-vary")]
235 parts
236 .extensions
237 .get_mut::<crate::auto_vary::HxTriggerExtracted>()
238 .map(crate::auto_vary::Notifier::notify);
239
240 if let Some(trigger) = parts.headers.get(HX_TRIGGER) {
241 if let Ok(trigger) = trigger.to_str() {
242 return Ok(HxTrigger(Some(trigger.to_string())));
243 }
244 }
245
246 Ok(HxTrigger(None))
247 }
248}