1#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2struct AsciiHeaderValue(::http::HeaderValue);
3impl AsciiHeaderValue {
4 fn from_value(value: ::http::HeaderValue) -> Option<Self> {
5 let bytes = value.as_bytes();
7 for &b in bytes {
8 if !(b >= 32 && b < 127 || b == b'\t') {
9 return None;
10 }
11 }
12 Some(AsciiHeaderValue(value))
13 }
14
15 fn from_str(s: &str) -> Option<Self> {
16 ::http::HeaderValue::from_str(s).ok().map(AsciiHeaderValue)
17 }
18
19 fn as_str(&self) -> &str {
20 let bytes = self.0.as_bytes();
21 unsafe { ::std::str::from_utf8_unchecked(bytes) }
23 }
24
25 fn into_value(self) -> ::http::HeaderValue {
26 self.0
27 }
28}
29
30macro_rules! str_header {
31 ($name:ident, $n:ident = $s:expr) => {
32 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
33 pub struct $name(crate::AsciiHeaderValue);
34 pub static $n: ::headers::HeaderName = ::headers::HeaderName::from_static($s);
35 impl $name {
36 pub fn as_str(&self) -> &str {
37 self.0.as_str()
38 }
39 pub fn into_value(self) -> ::http::HeaderValue {
40 self.0.into_value()
41 }
42 pub fn from_str(s: &str) -> Option<Self> {
43 crate::AsciiHeaderValue::from_str(s).map($name)
44 }
45 }
46 impl ::headers::Header for $name {
47 fn name() -> &'static http::HeaderName {
48 &$n
49 }
50 fn decode<'i, I>(values: &mut I) -> Result<Self, ::headers::Error>
51 where
52 Self: Sized,
53 I: Iterator<Item = &'i ::http::HeaderValue>,
54 {
55 values
56 .next()
57 .and_then(|one| values.next().is_none().then_some(one))
58 .cloned() .and_then(crate::AsciiHeaderValue::from_value)
60 .map($name)
61 .ok_or_else(::headers::Error::invalid)
62 }
63
64 fn encode<E: Extend<::http::HeaderValue>>(&self, values: &mut E) {
65 values.extend(std::iter::once(self.clone().into_value()))
66 }
67 }
68 };
69}
70
71macro_rules! true_header {
72 ($name:ident, $n:ident = $s:expr) => {
73 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
74 pub struct $name;
75 pub static $n: ::headers::HeaderName = ::headers::HeaderName::from_static($s);
76 impl $name {
77 pub fn into_value(self) -> ::http::HeaderValue {
78 ::http::HeaderValue::from_static("true")
79 }
80 }
81 impl ::headers::Header for $name {
82 fn name() -> &'static http::HeaderName {
83 &$n
84 }
85 fn decode<'i, I>(values: &mut I) -> Result<Self, ::headers::Error>
86 where
87 Self: Sized,
88 I: Iterator<Item = &'i ::http::HeaderValue>,
89 {
90 values
91 .next()
92 .and_then(|one| values.next().is_none().then_some(one))
93 .filter(|value| value.as_bytes() == b"true")
94 .is_some()
95 .then_some($name)
96 .ok_or_else(::headers::Error::invalid)
97 }
98
99 fn encode<E: Extend<::http::HeaderValue>>(&self, values: &mut E) {
100 values.extend(std::iter::once(self.clone().into_value()))
101 }
102 }
103 };
104}
105
106pub mod request {
107 true_header!(HxBoosted, HX_BOOSTED = "hx-boosted");
108 str_header!(HxCurrentUrl, HX_CURRENT_URL = "hx-current-url");
109 true_header!(
110 HxHistoryRestoreRequest,
111 HX_HISTORY_RESTORE_REQUEST = "hx-history-restore-request"
112 );
113 str_header!(HxPrompt, HX_PROMPT = "hx-prompt");
114 true_header!(HxRequest, HX_REQUEST = "hx-request");
115 str_header!(HxTarget, HX_TARGET = "hx-target");
116 str_header!(HxTriggerName, HX_TRIGGER_NAME = "hx-trigger-name");
117 str_header!(HxTrigger, HX_TRIGGER = "hx-trigger");
118}
119
120pub mod response {
121 str_header!(HxLocation, HX_LOCATION = "hx-location");
122 str_header!(HxPushUrl, HX_PUSH_URL = "hx-push-url");
123 str_header!(HxRedirect, HX_REDIRECT = "hx-redirect");
124 true_header!(HxRefresh, HX_REFRESH = "hx-refresh");
125 str_header!(HxReplaceUrl, HX_REPLACE_URL = "hx-replace-url");
126 str_header!(HxReswap, HX_RESWAP = "hx-reswap");
127 str_header!(HxRetarget, HX_RETARGET = "hx-retarget");
128 str_header!(HxReselect, HX_RESELECT = "hx-reselect");
129 str_header!(HxTrigger, HX_TRIGGER = "hx-trigger");
130 str_header!(
131 HxTriggerAfterSettle,
132 HX_TRIGGER_AFTER_SETTLE = "hx-trigger-after-settle"
133 );
134 str_header!(
135 HxTriggerAfterSwap,
136 HX_TRIGGER_AFTER_SWAP = "hx-trigger-after-swap"
137 );
138}