webparse/http/
value.rs

1// Copyright 2022 - 2023 Wenmeng See the COPYRIGHT
2// file at the top-level directory of this distribution.
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8//
9// Author: tickbh
10// -----
11// Created Date: 2023/08/18 10:06:47
12
13use std::hash::Hash;
14use std::{borrow::Cow, fmt};
15
16use crate::{Helper, WebError, WebResult};
17use algorithm::buf::{Bt, BtMut};
18
19#[derive(Clone, Debug)]
20pub enum HeaderValue {
21    Stand(&'static str),
22    Value(Vec<u8>),
23}
24
25impl HeaderValue {
26    pub fn from_static(s: &'static str) -> HeaderValue {
27        HeaderValue::Stand(s)
28    }
29
30    pub fn from_bytes(b: &[u8]) -> HeaderValue {
31        HeaderValue::Value(b.to_vec())
32    }
33
34    pub fn from_cow(b: Cow<[u8]>) -> HeaderValue {
35        HeaderValue::Value(Vec::from(b.to_owned()))
36    }
37
38    pub fn bytes_len(&self) -> usize {
39        match self {
40            Self::Stand(s) => s.as_bytes().len(),
41            Self::Value(s) => s.len(),
42        }
43    }
44
45    pub fn as_bytes(&self) -> &[u8] {
46        match self {
47            Self::Stand(s) => &s.as_bytes(),
48            Self::Value(s) => &s,
49        }
50    }
51
52    pub fn as_string(&self) -> Option<String> {
53        match self {
54            Self::Stand(s) => Some(s.to_string()),
55            Self::Value(s) => String::from_utf8(s.clone()).map_or(None, |s| Some(s)),
56        }
57    }
58
59    pub fn push(&mut self, value: HeaderValue) {
60        match self {
61            Self::Stand(s) => *self = Self::Value(s.as_bytes().to_vec()),
62            _ => {}
63        }
64        match self {
65            Self::Value(s) => {
66                s.push(b';');
67                s.append(&mut value.as_bytes().to_vec());
68            }
69            _ => unreachable!(),
70        }
71    }
72
73    pub fn encode<B: Bt + BtMut>(&self, buffer: &mut B) -> WebResult<usize> {
74        match self {
75            Self::Stand(name) => Ok(buffer.put_slice(name.as_bytes())),
76            Self::Value(vec) => Ok(buffer.put_slice(&**vec)),
77        }
78    }
79
80    pub fn contains(&self, bytes: &[u8]) -> bool {
81        Helper::contains_bytes(self.as_bytes(), bytes)
82    }
83}
84
85impl Hash for HeaderValue {
86    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
87        match self {
88            HeaderValue::Stand(stand) => {
89                (*stand.as_bytes()).hash(state);
90            }
91            HeaderValue::Value(val) => {
92                val.hash(state);
93            }
94        }
95    }
96}
97
98impl fmt::Display for HeaderValue {
99    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100        match &self {
101            Self::Stand(value) => f.write_str(value),
102            Self::Value(value) => f.write_str(&String::from_utf8_lossy(value)),
103        }
104    }
105}
106
107impl TryInto<usize> for &HeaderValue {
108    type Error = WebError;
109
110    fn try_into(self) -> Result<usize, WebError> {
111        match self {
112            HeaderValue::Stand(s) => s.parse().map_err(WebError::from),
113            HeaderValue::Value(v) => {
114                let mut result = 0usize;
115                for b in v {
116                    if !Helper::is_digit(*b) {
117                        return Err(WebError::IntoError);
118                    }
119                    match result.overflowing_mul(10) {
120                        (u, false) => {
121                            result = u + (b - Helper::DIGIT_0) as usize;
122                        }
123                        (_u, true) => return Err(WebError::IntoError),
124                    }
125                }
126                Ok(result)
127            }
128        }
129    }
130}
131
132impl TryInto<isize> for &HeaderValue {
133    type Error = WebError;
134
135    fn try_into(self) -> Result<isize, WebError> {
136        match self {
137            HeaderValue::Stand(s) => s.parse().map_err(WebError::from),
138            HeaderValue::Value(v) => {
139                let mut result = 0isize;
140                let mut is_neg = false;
141                for b in v {
142                    if !Helper::is_digit(*b) {
143                        if b == &b'-' && result == 0 {
144                            is_neg = true;
145                            continue;
146                        }
147                        return Err(WebError::IntoError);
148                    }
149                    match result.overflowing_mul(10) {
150                        (u, false) => {
151                            result = u + (b - Helper::DIGIT_0) as isize;
152                        }
153                        (_u, true) => return Err(WebError::IntoError),
154                    }
155                }
156                if is_neg {
157                    Ok(-result)
158                } else {
159                    Ok(result)
160                }
161            }
162        }
163    }
164}
165
166impl TryInto<String> for &HeaderValue {
167    type Error = WebError;
168
169    fn try_into(self) -> Result<String, WebError> {
170        match self {
171            HeaderValue::Stand(s) => Ok(s.to_string()),
172            HeaderValue::Value(v) => Ok(String::from_utf8_lossy(v).to_string()),
173        }
174    }
175}
176
177impl TryFrom<&'static str> for HeaderValue {
178    type Error = WebError;
179
180    fn try_from(value: &'static str) -> Result<Self, Self::Error> {
181        Ok(HeaderValue::Stand(value))
182    }
183}
184
185impl TryFrom<String> for HeaderValue {
186    type Error = WebError;
187    fn try_from(value: String) -> Result<Self, Self::Error> {
188        Ok(HeaderValue::Value(value.into_bytes()))
189    }
190}
191
192impl TryFrom<usize> for HeaderValue {
193    type Error = WebError;
194    fn try_from(value: usize) -> Result<Self, Self::Error> {
195        Ok(HeaderValue::Value(format!("{}", value).into_bytes()))
196    }
197}
198
199impl TryFrom<isize> for HeaderValue {
200    type Error = WebError;
201    fn try_from(value: isize) -> Result<Self, Self::Error> {
202        Ok(HeaderValue::Value(format!("{}", value).into_bytes()))
203    }
204}
205
206impl Eq for HeaderValue {}
207
208impl PartialEq<HeaderValue> for HeaderValue {
209    fn eq(&self, other: &HeaderValue) -> bool {
210        match (self, other) {
211            (Self::Stand(l0), Self::Stand(r0)) => l0 == r0,
212            (Self::Value(l0), Self::Value(r0)) => l0 == r0,
213            (Self::Stand(l0), Self::Value(r0)) => l0.as_bytes() == r0,
214            (Self::Value(l0), Self::Stand(r0)) => l0 == r0.as_bytes(),
215        }
216    }
217}
218
219impl PartialEq<&str> for HeaderValue {
220    fn eq(&self, other: &&str) -> bool {
221        match self {
222            HeaderValue::Stand(s) => s == other,
223            HeaderValue::Value(s) => &s[..] == other.as_bytes(),
224        }
225    }
226}
227
228impl PartialEq<HeaderValue> for [u8] {
229    fn eq(&self, other: &HeaderValue) -> bool {
230        other == self
231    }
232}
233
234impl PartialEq<[u8]> for HeaderValue {
235    fn eq(&self, other: &[u8]) -> bool {
236        match self {
237            HeaderValue::Stand(s) => s.as_bytes() == other,
238            HeaderValue::Value(s) => &s[..] == other,
239        }
240    }
241}
242
243impl PartialEq<HeaderValue> for &str {
244    fn eq(&self, url: &HeaderValue) -> bool {
245        url == self
246    }
247}