stream_httparse/header/
value.rs

1/// A single HeaderValue that can hold Data
2/// in a variety of forms allowing for easier
3/// and more flexible use
4#[derive(Debug, PartialEq, Clone)]
5pub enum HeaderValue<'a> {
6    /// Stores the Value as a reference to a String
7    StrRef(&'a str),
8    /// Stores the Value as an owned String
9    Str(String),
10    /// Stores the Value in its raw Number format
11    NumberUsize(usize),
12}
13
14impl<'a> From<&'a str> for HeaderValue<'a> {
15    fn from(val: &'a str) -> Self {
16        HeaderValue::StrRef(val)
17    }
18}
19impl<'a> From<String> for HeaderValue<'a> {
20    fn from(val: String) -> Self {
21        HeaderValue::Str(val)
22    }
23}
24impl<'a> From<usize> for HeaderValue<'a> {
25    fn from(val: usize) -> Self {
26        HeaderValue::NumberUsize(val)
27    }
28}
29
30impl<'a> HeaderValue<'a> {
31    /// Serializes the Value into the given Buffer by
32    /// appending the Data to it
33    pub fn serialize(&self, buf: &mut Vec<u8>) {
34        match *self {
35            Self::StrRef(ref value) => {
36                buf.extend_from_slice(value.as_bytes());
37            }
38            Self::Str(ref value) => {
39                buf.extend_from_slice(value.as_bytes());
40            }
41            Self::NumberUsize(ref value) => {
42                buf.extend_from_slice(value.to_string().as_bytes());
43            }
44        }
45    }
46
47    /// Turns the given Value, regardless of how it is stored,
48    /// into an owned String
49    pub fn to_string(&self) -> String {
50        match *self {
51            Self::StrRef(ref value) => value.to_string(),
52            Self::Str(ref value) => value.clone(),
53            Self::NumberUsize(ref value) => value.to_string(),
54        }
55    }
56
57    /// Compares the Two values without case
58    ///
59    /// Any number type in either of them immediately
60    /// returns false
61    pub fn eq_ignore_case(&self, other: &Self) -> bool {
62        let own_ref = match self.try_as_str_ref() {
63            Some(r) => r,
64            None => return false,
65        };
66
67        let other_ref = match other.try_as_str_ref() {
68            Some(r) => r,
69            None => return false,
70        };
71
72        caseless::default_caseless_match_str(own_ref, other_ref)
73    }
74
75    /// Tries to return a reference to the underlying String,
76    /// if it is a String, otherwise returns None
77    pub fn try_as_str_ref(&self) -> Option<&str> {
78        match self {
79            Self::StrRef(value) => Some(value),
80            Self::Str(value) => Some(&value),
81            Self::NumberUsize(_) => None,
82        }
83    }
84
85    /// Returns the amount of space in bytes that
86    /// this Value needs
87    pub fn length(&self) -> usize {
88        match self {
89            Self::Str(tmp) => tmp.len(),
90            Self::StrRef(tmp) => tmp.len(),
91            Self::NumberUsize(val) => {
92                let mut tmp = *val;
93                let mut result = 1;
94
95                loop {
96                    if tmp < 10 {
97                        return result;
98                    }
99                    if tmp < 100 {
100                        return result + 1;
101                    }
102                    if tmp < 1000 {
103                        return result + 2;
104                    }
105                    if tmp < 10000 {
106                        return result + 3;
107                    }
108
109                    tmp /= 10000;
110                    result += 4;
111                }
112            }
113        }
114    }
115
116    /// Clones all the needed Data in order to create a new
117    /// HeaderValue that is completly independant of the given
118    /// self reference
119    pub fn to_owned<'refed, 'owned>(&'refed self) -> HeaderValue<'owned> {
120        match self {
121            Self::Str(tmp) => HeaderValue::Str(tmp.clone()),
122            Self::StrRef(tmp) => HeaderValue::Str(tmp.to_string()),
123            Self::NumberUsize(tmp) => HeaderValue::NumberUsize(*tmp),
124        }
125    }
126}
127
128impl PartialEq<std::string::String> for HeaderValue<'_> {
129    fn eq(&self, other: &std::string::String) -> bool {
130        match *self {
131            Self::StrRef(ref value) => value == other,
132            Self::Str(ref value) => value == other,
133            _ => false,
134        }
135    }
136}
137
138#[cfg(test)]
139mod tests {
140    use super::*;
141
142    #[test]
143    fn serialize_str() {
144        let mut result: Vec<u8> = Vec::new();
145        HeaderValue::Str("test-value".to_owned()).serialize(&mut result);
146
147        assert_eq!("test-value".as_bytes(), &result);
148    }
149    #[test]
150    fn serialize_str_ref() {
151        let mut result: Vec<u8> = Vec::new();
152        HeaderValue::StrRef("test-value").serialize(&mut result);
153
154        assert_eq!("test-value".as_bytes(), &result);
155    }
156    #[test]
157    fn serialize_number_usize() {
158        let mut result: Vec<u8> = Vec::new();
159        HeaderValue::NumberUsize(80).serialize(&mut result);
160
161        assert_eq!("80".as_bytes(), &result);
162    }
163
164    #[test]
165    fn equals_ignore_case() {
166        assert_eq!(
167            true,
168            HeaderValue::StrRef("test").eq_ignore_case(&HeaderValue::StrRef("TEST"))
169        );
170        assert_eq!(
171            true,
172            HeaderValue::StrRef("test").eq_ignore_case(&HeaderValue::StrRef("test"))
173        );
174        assert_eq!(
175            true,
176            HeaderValue::StrRef("TeSt").eq_ignore_case(&HeaderValue::StrRef("test"))
177        );
178    }
179}