Skip to main content

headers/util/
csv.rs

1use std::fmt;
2
3use http::HeaderValue;
4
5use crate::Error;
6
7/// Reads a comma-delimited raw header into a Vec.
8pub(crate) fn from_comma_delimited<'i, I, T, E>(values: &mut I) -> Result<E, Error>
9where
10    I: Iterator<Item = &'i HeaderValue>,
11    T: ::std::str::FromStr,
12    E: ::std::iter::FromIterator<T>,
13{
14    values
15        .flat_map(|value| {
16            value.to_str().into_iter().flat_map(|string| {
17                let mut in_quotes = false;
18                string
19                    .split(move |c| {
20                        #[allow(clippy::collapsible_else_if)]
21                        if in_quotes {
22                            if c == '"' {
23                                in_quotes = false;
24                            }
25                            false // dont split
26                        } else {
27                            if c == ',' {
28                                true // split
29                            } else {
30                                if c == '"' {
31                                    in_quotes = true;
32                                }
33                                false // dont split
34                            }
35                        }
36                    })
37                    .filter_map(|x| match x.trim() {
38                        "" => None,
39                        y => Some(y),
40                    })
41                    .map(|x| x.parse().map_err(|_| Error::invalid()))
42            })
43        })
44        .collect()
45}
46
47/// Format an array into a comma-delimited string.
48pub(crate) fn fmt_comma_delimited<T: fmt::Display>(
49    f: &mut fmt::Formatter,
50    mut iter: impl Iterator<Item = T>,
51) -> fmt::Result {
52    if let Some(part) = iter.next() {
53        fmt::Display::fmt(&part, f)?;
54    }
55    for part in iter {
56        f.write_str(", ")?;
57        fmt::Display::fmt(&part, f)?;
58    }
59    Ok(())
60}