1use std::fmt;
8
9#[derive(Debug, Clone, Default, PartialEq, Eq)]
12pub struct Headers {
13 entries: Vec<(String, String)>,
14}
15
16impl Headers {
17 pub fn new() -> Self {
19 Self::default()
20 }
21
22 pub fn from_pairs<I, N, V>(pairs: I) -> Self
33 where
34 I: IntoIterator<Item = (N, V)>,
35 N: Into<String>,
36 V: Into<String>,
37 {
38 let mut headers = Self::new();
39 for (name, value) in pairs {
40 headers.insert(name, value);
41 }
42 headers
43 }
44
45 pub fn get(&self, name: &str) -> Option<&str> {
47 self.entries
48 .iter()
49 .find(|(existing, _)| existing.eq_ignore_ascii_case(name))
50 .map(|(_, value)| value.as_str())
51 }
52
53 pub fn contains(&self, name: &str) -> bool {
55 self.get(name).is_some()
56 }
57
58 pub fn insert<N: Into<String>, V: Into<String>>(&mut self, name: N, value: V) {
60 let name = name.into();
61 let value = value.into();
62 match self
63 .entries
64 .iter_mut()
65 .find(|(existing, _)| existing.eq_ignore_ascii_case(&name))
66 {
67 Some(entry) => entry.1 = value,
68 None => self.entries.push((name, value)),
69 }
70 }
71
72 pub fn insert_missing<N: Into<String>, V: Into<String>>(&mut self, name: N, value: V) {
74 let name = name.into();
75 if !self.contains(&name) {
76 self.insert(name, value);
77 }
78 }
79
80 pub fn remove(&mut self, name: &str) -> Option<String> {
82 let index = self
83 .entries
84 .iter()
85 .position(|(existing, _)| existing.eq_ignore_ascii_case(name))?;
86 Some(self.entries.remove(index).1)
87 }
88
89 pub fn is_empty(&self) -> bool {
91 self.entries.is_empty()
92 }
93
94 pub fn len(&self) -> usize {
96 self.entries.len()
97 }
98
99 pub fn iter(&self) -> impl Iterator<Item = (&str, &str)> {
101 self.entries
102 .iter()
103 .map(|(name, value)| (name.as_str(), value.as_str()))
104 }
105
106 pub fn extend_missing(&mut self, other: &Headers) {
108 for (name, value) in other.iter() {
109 self.insert_missing(name.to_string(), value.to_string());
110 }
111 }
112}
113
114impl<'a> IntoIterator for &'a Headers {
115 type Item = (&'a str, &'a str);
116 type IntoIter = Box<dyn Iterator<Item = (&'a str, &'a str)> + 'a>;
117
118 fn into_iter(self) -> Self::IntoIter {
119 Box::new(self.iter())
120 }
121}
122
123impl fmt::Display for Headers {
124 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
125 for (name, value) in self.iter() {
126 writeln!(formatter, "{name}: {value}")?;
127 }
128 Ok(())
129 }
130}
131
132pub fn append_list_value(headers: &mut Headers, name: &str, value: &str) {
146 match headers.get(name) {
147 None => headers.insert(name.to_string(), value.to_string()),
148 Some(existing) => {
149 let already = existing
150 .split(',')
151 .any(|part| part.trim().eq_ignore_ascii_case(value));
152 if !already {
153 let merged = format!("{existing}, {value}");
154 headers.insert(name.to_string(), merged);
155 }
156 }
157 }
158}