Skip to main content

ureq_proto/
util.rs

1use std::fmt;
2use std::io::{self, Cursor};
3use std::ops::{Deref, DerefMut};
4
5pub(crate) fn find_crlf(b: &[u8]) -> Option<usize> {
6    let cr = b.iter().position(|c| *c == b'\r')?;
7    let maybe_lf = b.get(cr + 1)?;
8    if *maybe_lf == b'\n' { Some(cr) } else { None }
9}
10
11pub(crate) fn compare_lowercase_ascii(a: &str, lowercased: &str) -> bool {
12    if a.len() != lowercased.len() {
13        return false;
14    }
15
16    for (a, b) in a.chars().zip(lowercased.chars()) {
17        if !a.is_ascii() {
18            return false;
19        }
20        let norm = a.to_ascii_lowercase();
21        if norm != b {
22            return false;
23        }
24    }
25
26    true
27}
28
29pub(crate) struct Writer<'a>(pub Cursor<&'a mut [u8]>);
30
31impl<'a> Writer<'a> {
32    pub(crate) fn new(output: &'a mut [u8]) -> Writer<'a> {
33        Self(Cursor::new(output))
34    }
35
36    pub fn len(&self) -> usize {
37        self.0.position() as usize
38    }
39
40    pub fn available(&self) -> usize {
41        self.0.get_ref().len() - self.len()
42    }
43
44    pub(crate) fn try_write(&mut self, block: impl Fn(&mut Self) -> io::Result<()>) -> bool {
45        let pos = self.0.position();
46        let success = (block)(self).is_ok();
47        if !success {
48            self.0.set_position(pos);
49        }
50        success
51    }
52}
53
54impl<'a> io::Write for Writer<'a> {
55    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
56        self.0.write(buf)
57    }
58
59    fn flush(&mut self) -> io::Result<()> {
60        self.0.flush()
61    }
62}
63
64const CHARS_PER_ROW: usize = 16;
65
66impl<'a> Drop for Writer<'a> {
67    fn drop(&mut self) {
68        let len = self.len();
69        log_data(&self.0.get_ref()[..len]);
70    }
71}
72
73pub(crate) fn log_data(data: &[u8]) {
74    for row in data.chunks(CHARS_PER_ROW) {
75        trace!("{:?}", Row(row))
76    }
77}
78
79struct Row<'a>(&'a [u8]);
80
81impl<'a> fmt::Debug for Row<'a> {
82    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83        for i in 0..CHARS_PER_ROW {
84            if let Some(v) = self.0.get(i) {
85                write!(f, "{}", HEX[*v as usize])?
86            } else {
87                write!(f, "--")?;
88            }
89            if i % 2 == 1 {
90                write!(f, " ")?;
91            }
92        }
93        write!(f, " ")?;
94        for i in 0..CHARS_PER_ROW {
95            if let Some(v) = self.0.get(i) {
96                if v.is_ascii_alphanumeric() || v.is_ascii_punctuation() {
97                    write!(f, "{}", *v as char)?;
98                } else {
99                    write!(f, ".")?;
100                }
101            } else {
102                write!(f, ".")?;
103            }
104        }
105        Ok(())
106    }
107}
108
109const HEX: [&str; 256] = [
110    "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0a", "0b", "0c", "0d", "0e", "0f",
111    "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1a", "1b", "1c", "1d", "1e", "1f",
112    "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2a", "2b", "2c", "2d", "2e", "2f",
113    "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3a", "3b", "3c", "3d", "3e", "3f",
114    "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4a", "4b", "4c", "4d", "4e", "4f",
115    "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5a", "5b", "5c", "5d", "5e", "5f",
116    "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6a", "6b", "6c", "6d", "6e", "6f",
117    "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7a", "7b", "7c", "7d", "7e", "7f",
118    "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8a", "8b", "8c", "8d", "8e", "8f",
119    "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9a", "9b", "9c", "9d", "9e", "9f",
120    "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "aa", "ab", "ac", "ad", "ae", "af",
121    "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9", "ba", "bb", "bc", "bd", "be", "bf",
122    "c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf",
123    "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "da", "db", "dc", "dd", "de", "df",
124    "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef",
125    "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "fa", "fb", "fc", "fd", "fe", "ff",
126];
127
128/// Simple impl of an array behaving like a vec.
129pub struct ArrayVec<T, const N: usize> {
130    len: usize,
131    arr: [T; N],
132}
133
134impl<T, const N: usize> Deref for ArrayVec<T, N> {
135    type Target = [T];
136
137    fn deref(&self) -> &Self::Target {
138        &self.arr[..self.len]
139    }
140}
141
142impl<T, const N: usize> DerefMut for ArrayVec<T, N> {
143    fn deref_mut(&mut self) -> &mut Self::Target {
144        &mut self.arr[..self.len]
145    }
146}
147
148impl<T, const N: usize> ArrayVec<T, N> {
149    /// Construct the array.
150    ///
151    /// The function must produces placeholder elements of the type `T`.
152    pub fn from_fn(cb: impl FnMut(usize) -> T) -> Self {
153        Self {
154            len: 0,
155            arr: std::array::from_fn(cb),
156        }
157    }
158
159    /// Add a value T.
160    pub fn push(&mut self, value: T) {
161        self.arr[self.len] = value;
162        self.len += 1;
163    }
164
165    /// Shorten the vec.
166    ///
167    /// This does not drop the elements that are now unused.
168    pub fn truncate(&mut self, len: usize) {
169        assert!(len <= self.len);
170        self.len = len;
171    }
172}
173
174impl<T, const N: usize> fmt::Debug for ArrayVec<T, N>
175where
176    T: fmt::Debug,
177{
178    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
179        f.debug_struct("ArrayVec")
180            .field("len", &self.len)
181            .field("arr", &&self.arr[..self.len])
182            .finish()
183    }
184}
185
186impl<'a, T, const N: usize> IntoIterator for &'a ArrayVec<T, N> {
187    type Item = &'a T;
188    type IntoIter = core::slice::Iter<'a, T>;
189
190    fn into_iter(self) -> Self::IntoIter {
191        self[..self.len].iter()
192    }
193}