grafbase_sdk/types/
headers.rs

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