Skip to main content

sark_http/payload/response/headers/
list.rs

1use std::{borrow::Cow, slice};
2
3use o3::alloc;
4
5use crate::{
6    field::{self, Lower, Value, storage},
7    h1::{codec::decode::fields, field::Entry},
8    payload::response::headers,
9};
10
11type Field<'field, N> = (N, Value<Cow<'field, [u8]>>);
12
13#[derive(PartialEq, Eq)]
14pub struct List<'field, N = Lower<Cow<'field, str>>> {
15    entries: Vec<Field<'field, N>>,
16}
17
18impl<N> Default for List<'_, N> {
19    fn default() -> Self {
20        Self::new()
21    }
22}
23
24impl<'field, N> List<'field, N> {
25    pub fn new() -> Self {
26        Self {
27            entries: Vec::new(),
28        }
29    }
30
31    pub fn is_empty(&self) -> bool {
32        self.entries.is_empty()
33    }
34
35    pub fn len(&self) -> usize {
36        self.entries.len()
37    }
38
39    pub fn iter(&self) -> slice::Iter<'_, Field<'field, N>> {
40        self.entries.iter()
41    }
42
43    fn try_append(&mut self, field: Field<'field, N>) -> Result<(), alloc::Error> {
44        let slot = alloc::Vacant::try_new(&mut self.entries)?;
45        slot.insert(field);
46        Ok(())
47    }
48}
49
50impl<'field, N: AsRef<[u8]>> List<'field, N> {
51    pub fn get(&self, name: &str) -> Option<&Value<Cow<'field, [u8]>>> {
52        self.entries
53            .iter()
54            .find(|entry| entry.0.as_ref().eq_ignore_ascii_case(name.as_bytes()))
55            .map(|entry| &entry.1)
56    }
57
58    pub fn contains_key(&self, name: &str) -> bool {
59        self.get(name).is_some()
60    }
61}
62
63impl field::Source for List<'_> {
64    fn emit<'field>(&'field self, sink: &mut impl field::Sink<'field>) {
65        for (name, value) in &self.entries {
66            sink.entry(field::Entry::new(name.borrow(), value.borrow()));
67        }
68    }
69}
70
71impl headers::Source for List<'_, headers::Name<Cow<'_, str>>> {
72    fn emit<'field>(&'field self, sink: &mut impl headers::Sink<'field>) {
73        for (name, value) in &self.entries {
74            sink.entry(headers::Entry::new(name.borrow(), value.borrow()));
75        }
76    }
77}
78
79impl<'input> fields::Sink<'input> for List<'_> {
80    type Error = fields::Error;
81
82    fn push(&mut self, name: &'input [u8], value: &'input [u8]) -> Result<(), Self::Error> {
83        let name = Lower::try_copy(name).map_err(fields::Error::Name)?;
84        let value = Value::try_copy(value).map_err(fields::Error::Value)?;
85        self.try_append((name, value))
86            .map_err(fields::Error::Allocation)
87    }
88
89    fn entry(&mut self, field: Entry<'input>) -> Result<(), Self::Error> {
90        let name = Lower::try_entry(field)
91            .map_err(storage::Error::Allocation)
92            .map_err(fields::Error::Name)?;
93        let value = Value::try_entry(field)
94            .map_err(storage::Error::Allocation)
95            .map_err(fields::Error::Value)?;
96        self.try_append((name, value))
97            .map_err(fields::Error::Allocation)
98    }
99}
100
101impl<'a, 'field, N> IntoIterator for &'a List<'field, N> {
102    type Item = &'a Field<'field, N>;
103    type IntoIter = slice::Iter<'a, Field<'field, N>>;
104
105    fn into_iter(self) -> Self::IntoIter {
106        self.iter()
107    }
108}