whdp/
util.rs

1use std::collections::BTreeMap;
2use std::net::TcpStream;
3use std::str::Lines;
4
5use crate::{ParseErrorKind, Request};
6use crate::error::HttpParseError;
7use crate::error::ParseErrorKind::Util;
8
9pub(crate) const KEY_VALUE_DELIMITER: &str = ": ";
10pub(crate) const NEW_LINE: char = '\n';
11pub(crate) const EMPTY_CHAR: char = ' ';
12pub(crate) const OPTION_WAS_EMPTY: &str = "the Option<?> was empty and couldn't get unwrapped";
13pub(crate) const INDEX_WAS_WRONG: &str = "The provided index didn't match";
14
15pub(crate) trait ParseKeyValue {
16    fn parse_key_value(&self) -> String;
17}
18
19impl ParseKeyValue for BTreeMap<String, String> {
20    fn parse_key_value(&self) -> String {
21        let mut string = String::new();
22        for (key, value) in self {
23            string.push_str(key);
24            string.push_str(KEY_VALUE_DELIMITER);
25            string.push_str(value);
26            string.push(NEW_LINE);
27        }
28        string
29    }
30}
31
32/// Trait for destructing structs with private fields.
33/// It can also be used to run destroy logic <br>
34///
35/// Example:
36/// ```
37/// use whdp::Destruct;
38///
39/// struct ExampleType{
40///     code: u16,
41///     message: String,
42/// }
43///
44///impl Destruct for ExampleType {
45///    type Item = (u16, String);
46///    fn destruct(self) -> Self::Item {
47///        (self.code, self.message)
48///    }
49///}
50/// ```
51pub trait Destruct {
52    /// used for specifying what kind of for example tuple
53    /// will be returned from this function
54    type Item;
55    /// destructs the Struct into it's fields
56    fn destruct(self) -> Self::Item;
57}
58
59pub(crate) fn parse_body(lines: &mut Lines) -> String {
60    let mut string = String::new();
61    let mut first = true;
62    lines.for_each(|str| {
63        if !first {
64            string.push(NEW_LINE);
65        }
66        first = false;
67        string.push_str(str);
68    });
69    string
70}
71
72pub(crate) fn parse_header(lines: &mut Lines) -> Result<BTreeMap<String, String>, HttpParseError> {
73    let mut map: BTreeMap<String, String> = BTreeMap::new();
74    let mut opt_line = lines.next();
75    while opt_line.is_some() {
76        let line = opt_line.unwrap();
77        if !line.is_empty() {
78            let (key, val) = parse_key_value(line)?;
79            map.insert(key, val);
80            opt_line = lines.next();
81        } else {
82            opt_line = None
83        }
84    }
85    Ok(map)
86}
87
88pub(crate) fn parse_uri(str: Option<&str>) -> Result<String, HttpParseError> {
89    str.ok_or(error_option_empty(Util)).map(String::from)
90}
91
92fn parse_key_value(str: &str) -> Result<(String, String), HttpParseError> {
93    let mut key_value = str.split(KEY_VALUE_DELIMITER);
94    let key = key_value
95        .next()
96        .ok_or(error_option_empty(Util))
97        .map(String::from)?;
98    let value = key_value
99        .next()
100        .ok_or(error_option_empty(Util))
101        .map(String::from)?;
102    Ok((key, value))
103}
104
105pub(crate) fn error_option_empty(kind: ParseErrorKind) -> HttpParseError {
106    HttpParseError::from((kind, OPTION_WAS_EMPTY))
107}
108
109/// Trait for adding a method ro specific types to parse them automatically to a [Request]
110pub trait TryRequest {
111    /// trys to parse it to a [Request] otherwise returns a [HttpParseError]
112    fn try_to_request(&mut self) -> Result<Request, HttpParseError>;
113}
114
115impl TryRequest for TcpStream {
116    fn try_to_request(&mut self) -> Result<Request, HttpParseError> {
117        Request::try_from(self)
118    }
119}