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