scraper_trail/
multi_value.rs

1use std::{borrow::Cow, marker::PhantomData};
2
3#[derive(Copy, Clone, Debug, thiserror::Error)]
4pub enum Error {
5    #[error("Empty values")]
6    Empty,
7}
8
9/// A set of values for a response header.
10///
11/// Typically each header name will map to a single value, but the same name may appear more than
12/// once, so we wish to handle that case, while still making it convenient to work with singleton
13/// values.
14#[derive(Clone, Debug, Eq, PartialEq, bounded_static_derive_more::ToStatic)]
15pub struct MultiValue<'a> {
16    pub first: Cow<'a, str>,
17    rest: Option<Vec<Cow<'a, str>>>,
18}
19
20impl<'a> MultiValue<'a> {
21    pub fn new<S: Into<Cow<'a, str>>>(value: S) -> Self {
22        Self {
23            first: value.into(),
24            rest: None,
25        }
26    }
27
28    pub fn push<S: Into<Cow<'a, str>>>(&mut self, value: S) {
29        match &mut self.rest {
30            None => {
31                self.rest = Some(vec![value.into()]);
32            }
33            Some(rest) => {
34                rest.push(value.into());
35            }
36        }
37    }
38
39    #[must_use]
40    pub fn iter(&'a self) -> Iter<'a> {
41        Iter {
42            first: Some(self.first.clone()),
43            rest: self.rest.as_ref().map(|rest| rest.iter()),
44        }
45    }
46}
47
48impl<'a> AsRef<Cow<'a, str>> for MultiValue<'a> {
49    fn as_ref(&self) -> &Cow<'a, str> {
50        &self.first
51    }
52}
53
54impl<'a, S: Into<Cow<'a, str>>> TryFrom<Vec<S>> for MultiValue<'a> {
55    type Error = Error;
56
57    fn try_from(mut value: Vec<S>) -> Result<Self, Self::Error> {
58        if value.is_empty() {
59            Err(Error::Empty)
60        } else {
61            let first = value.remove(0).into();
62            let rest = if value.is_empty() {
63                None
64            } else {
65                Some(value.into_iter().map(std::convert::Into::into).collect())
66            };
67
68            Ok(Self { first, rest })
69        }
70    }
71}
72
73impl<'a> IntoIterator for &'a MultiValue<'a> {
74    type Item = std::borrow::Cow<'a, str>;
75    type IntoIter = Iter<'a>;
76
77    fn into_iter(self) -> Self::IntoIter {
78        self.iter()
79    }
80}
81
82pub struct Iter<'a> {
83    first: Option<Cow<'a, str>>,
84    rest: Option<std::slice::Iter<'a, Cow<'a, str>>>,
85}
86
87impl<'a> Iterator for Iter<'a> {
88    type Item = Cow<'a, str>;
89
90    fn next(&mut self) -> Option<Self::Item> {
91        self.first.take().or_else(|| {
92            self.rest.take().and_then(|mut rest| {
93                let next = rest.next().cloned();
94                self.rest = Some(rest);
95                next
96            })
97        })
98    }
99}
100
101impl<'a, 'de: 'a> serde::de::Deserialize<'de> for MultiValue<'a> {
102    fn deserialize<D: serde::de::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
103        const EXPECTED: &str = "one or more header values";
104
105        struct MultiValueVisitor<'a> {
106            _lifetime: PhantomData<&'a ()>,
107        }
108
109        impl<'a, 'de: 'a> serde::de::Visitor<'de> for MultiValueVisitor<'a> {
110            type Value = MultiValue<'a>;
111
112            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113                formatter.write_str(EXPECTED)
114            }
115
116            fn visit_borrowed_str<E: serde::de::Error>(
117                self,
118                v: &'de str,
119            ) -> Result<Self::Value, E> {
120                Ok(MultiValue::new(v))
121            }
122
123            fn visit_seq<A: serde::de::SeqAccess<'de>>(
124                self,
125                mut seq: A,
126            ) -> Result<Self::Value, A::Error> {
127                let mut result: Option<MultiValue<'a>> = None;
128
129                while let Some(value) = seq.next_element::<Cow<'a, str>>()? {
130                    match result {
131                        Some(ref mut multi_value) => {
132                            multi_value.push(value);
133                        }
134                        None => {
135                            result = Some(MultiValue::new(value));
136                        }
137                    }
138                }
139
140                result.ok_or_else(|| {
141                    serde::de::Error::invalid_value(serde::de::Unexpected::Seq, &EXPECTED)
142                })
143            }
144
145            fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
146                Ok(MultiValue::new(v.to_string()))
147            }
148        }
149
150        deserializer.deserialize_any(MultiValueVisitor {
151            _lifetime: PhantomData,
152        })
153    }
154}
155
156impl serde::ser::Serialize for MultiValue<'_> {
157    fn serialize<S: serde::ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
158        use serde::ser::SerializeSeq;
159
160        match self.rest.as_ref() {
161            Some(rest) => {
162                let mut seq = serializer.serialize_seq(Some(rest.len() + 1))?;
163                seq.serialize_element(&self.first)?;
164
165                for element in rest {
166                    seq.serialize_element(&element)?;
167                }
168
169                seq.end()
170            }
171            None => self.first.serialize(serializer),
172        }
173    }
174}
175
176#[cfg(test)]
177mod tests {
178    use crate::multi_value::MultiValue;
179
180    #[derive(Debug, Eq, PartialEq, serde::Deserialize)]
181    struct Test<'a> {
182        #[serde(borrow)]
183        header_values: super::MultiValue<'a>,
184    }
185
186    #[test]
187    fn deserialize_multi_value() -> Result<(), Box<dyn std::error::Error>> {
188        let singleton_example = r#"{ "header_values": "test" }"#;
189        let multi_example = r#"{ "header_values": ["foo", "bar", "baz"] }"#;
190
191        let singleton_example_parsed = serde_json::from_str::<Test<'_>>(singleton_example)?;
192        let multi_example_parsed = serde_json::from_str::<Test<'_>>(multi_example)?;
193
194        let singleton_example_expected = Test {
195            header_values: MultiValue::new("test"),
196        };
197
198        let multi_example_expected = Test {
199            header_values: vec!["foo", "bar", "baz"].try_into()?,
200        };
201
202        assert_eq!(singleton_example_parsed, singleton_example_expected);
203        assert_eq!(multi_example_parsed, multi_example_expected);
204        Ok(())
205    }
206
207    #[test]
208    fn iter() -> Result<(), Box<dyn std::error::Error>> {
209        let singleton_example = MultiValue::new("test");
210
211        let multi_example: MultiValue<'_> = vec!["foo", "bar", "baz"].try_into()?;
212
213        assert_eq!(singleton_example.iter().collect::<Vec<_>>(), vec!["test"]);
214        assert_eq!(
215            multi_example.iter().collect::<Vec<_>>(),
216            vec!["foo", "bar", "baz"]
217        );
218        Ok(())
219    }
220}