grafbase_sdk/types/
headers.rs

1use as_header_name::AsHeaderName;
2use into_header_name::IntoHeaderName;
3
4use crate::wit;
5
6/// HTTP headers.
7pub struct HttpHeaders(wit::Headers);
8
9/// HTTP headers for the gateway request.
10pub struct GatewayHeaders(HttpHeaders);
11
12impl From<wit::Headers> for GatewayHeaders {
13    fn from(headers: wit::Headers) -> Self {
14        Self(HttpHeaders(headers))
15    }
16}
17
18impl std::ops::Deref for GatewayHeaders {
19    type Target = HttpHeaders;
20    fn deref(&self) -> &Self::Target {
21        &self.0
22    }
23}
24
25impl std::ops::DerefMut for GatewayHeaders {
26    fn deref_mut(&mut self) -> &mut Self::Target {
27        &mut self.0
28    }
29}
30
31/// HTTP headers for the subgraph request.
32pub struct SubgraphHeaders(HttpHeaders);
33
34impl From<wit::Headers> for SubgraphHeaders {
35    fn from(headers: wit::Headers) -> Self {
36        Self(HttpHeaders(headers))
37    }
38}
39
40impl std::ops::Deref for SubgraphHeaders {
41    type Target = HttpHeaders;
42    fn deref(&self) -> &Self::Target {
43        &self.0
44    }
45}
46
47impl std::ops::DerefMut for SubgraphHeaders {
48    fn deref_mut(&mut self) -> &mut Self::Target {
49        &mut self.0
50    }
51}
52
53// Imitates as much as possible the http::HeaderMap API
54impl HttpHeaders {
55    /// Get the value associated with the given name. If there are multiple values associated with
56    /// the name, then the first one is returned. Use `get_all` to get all values associated with
57    /// a given name. Returns None if there are no values associated with the name.
58    pub fn get(&self, name: impl AsHeaderName) -> Option<http::HeaderValue> {
59        self.0
60            .get(name.as_str())
61            .into_iter()
62            .next()
63            .map(|value| value.try_into().unwrap())
64    }
65
66    /// Get all of the values corresponding to a name. If the name is not present,
67    /// an empty list is returned. However, if the name is present but empty, this
68    /// is represented by a list with one or more empty values present.
69    pub fn get_all(&self, name: impl AsHeaderName) -> impl Iterator<Item = http::HeaderValue> {
70        self.0
71            .get(name.as_str())
72            .into_iter()
73            .map(|value| value.try_into().unwrap())
74    }
75
76    /// Returns true if the map contains a value for the specified name.
77    pub fn has(&self, name: impl AsHeaderName) -> bool {
78        self.0.has(name.as_str())
79    }
80
81    /// Set all of the values for a name. Clears any existing values for that
82    /// name, if they have been set.
83    pub fn set(&mut self, name: impl IntoHeaderName, values: impl IntoIterator<Item = http::HeaderValue>) {
84        let name = name.into_header_name();
85        let values = values
86            .into_iter()
87            .map(|value| value.as_bytes().to_vec())
88            .collect::<Vec<_>>();
89        self.0
90            .set(name.as_str(), &values)
91            .expect("We have a mut ref & validated name and values.");
92    }
93
94    /// Removes a name from the map, returning the value associated with the name.
95    /// Returns None if the map does not contain the name. If there are multiple values associated with the name, then the first one is returned.
96    pub fn remove(&mut self, name: impl AsHeaderName) -> Option<http::HeaderValue> {
97        self.0
98            .get_and_delete(name.as_str())
99            .map(|values| values.into_iter().next().map(|value| value.try_into().unwrap()))
100            .expect("We have a mut ref & validated name and values.")
101    }
102
103    /// Append a value for a name. Does not change or delete any existing
104    /// values for that name.
105    pub fn append(&mut self, name: impl AsHeaderName, value: http::HeaderValue) {
106        self.0
107            .append(name.as_str(), value.as_bytes())
108            .expect("We have a mut ref & validated name and values.");
109    }
110
111    /// An iterator visiting all name-value pairs.
112    /// The iteration order is arbitrary, but consistent across platforms for the same crate version. Each name will be yielded once per associated value. So, if a name has 3 associated values, it will be yielded 3 times.
113    pub fn iter(&self) -> impl Iterator<Item = (http::HeaderName, http::HeaderValue)> {
114        self.0
115            .entries()
116            .into_iter()
117            .map(|(name, value)| (name.try_into().unwrap(), value.try_into().unwrap()))
118    }
119}
120
121impl From<&GatewayHeaders> for http::HeaderMap {
122    fn from(headers: &GatewayHeaders) -> Self {
123        headers.iter().collect()
124    }
125}
126
127impl From<&SubgraphHeaders> for http::HeaderMap {
128    fn from(headers: &SubgraphHeaders) -> Self {
129        headers.iter().collect()
130    }
131}
132
133impl From<SubgraphHeaders> for http::HeaderMap {
134    fn from(headers: SubgraphHeaders) -> Self {
135        headers.iter().collect()
136    }
137}
138
139/*
140* Imitating the http::HeaderMap API
141*
142* ===== impl IntoHeaderName / AsHeaderName =====
143*/
144
145mod into_header_name {
146    use http::HeaderName;
147
148    /// A marker trait used to identify values that can be used as insert keys
149    /// to a `HttpHeaders`.
150    pub trait IntoHeaderName: Sealed {}
151
152    // All methods are on this pub(super) trait, instead of `IntoHeaderName`,
153    // so that they aren't publicly exposed to the world.
154    //
155    // Being on the `IntoHeaderName` trait would mean users could call
156    // `"host".insert(&mut map, "localhost")`.
157    //
158    // Ultimately, this allows us to adjust the signatures of these methods
159    // without breaking any external crate.
160    pub trait Sealed {
161        #[doc(hidden)]
162        fn into_header_name(self) -> HeaderName;
163    }
164
165    // ==== impls ====
166
167    impl Sealed for HeaderName {
168        #[inline]
169        fn into_header_name(self) -> HeaderName {
170            self
171        }
172    }
173
174    impl IntoHeaderName for HeaderName {}
175
176    impl Sealed for &HeaderName {
177        #[inline]
178        fn into_header_name(self) -> HeaderName {
179            self.clone()
180        }
181    }
182
183    impl IntoHeaderName for &HeaderName {}
184
185    impl Sealed for &'static str {
186        #[inline]
187        fn into_header_name(self) -> HeaderName {
188            HeaderName::from_static(self)
189        }
190    }
191
192    impl IntoHeaderName for &'static str {}
193}
194
195mod as_header_name {
196    use http::HeaderName;
197
198    /// A marker trait used to identify values that can be used as search keys
199    /// to a `HttpHeaders`.
200    pub trait AsHeaderName: Sealed {}
201
202    // All methods are on this pub(super) trait, instead of `AsHeaderName`,
203    // so that they aren't publicly exposed to the world.
204    //
205    // Being on the `AsHeaderName` trait would mean users could call
206    // `"host".find(&map)`.
207    //
208    // Ultimately, this allows us to adjust the signatures of these methods
209    // without breaking any external crate.
210    pub trait Sealed {
211        #[doc(hidden)]
212        fn as_str(&self) -> &str;
213    }
214
215    // ==== impls ====
216
217    impl Sealed for HeaderName {
218        #[inline]
219        fn as_str(&self) -> &str {
220            HeaderName::as_str(self)
221        }
222    }
223
224    impl AsHeaderName for HeaderName {}
225
226    impl Sealed for &HeaderName {
227        #[inline]
228        fn as_str(&self) -> &str {
229            HeaderName::as_str(self)
230        }
231    }
232
233    impl AsHeaderName for &HeaderName {}
234
235    impl Sealed for &str {
236        #[inline]
237        fn as_str(&self) -> &str {
238            self
239        }
240    }
241
242    impl AsHeaderName for &str {}
243
244    impl Sealed for String {
245        #[inline]
246        fn as_str(&self) -> &str {
247            String::as_str(self)
248        }
249    }
250
251    impl AsHeaderName for String {}
252
253    impl Sealed for &String {
254        #[inline]
255        fn as_str(&self) -> &str {
256            String::as_str(self)
257        }
258    }
259
260    impl AsHeaderName for &String {}
261}