1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
use std::cmp::Ordering;

/// Allows the HeaderKey to take the form of a variety of different
/// valid Types, mostly related to their lifetimes.
/// This however also gives more control over how they are compared
/// to each other, ignoring case in this case
///
/// ```rust
/// use stream_httparse::header::HeaderKey;
///
/// assert_eq!(HeaderKey::StrRef("TeSt"), HeaderKey::StrRef("test"));
/// ```
#[derive(Debug, Clone)]
pub enum HeaderKey<'a> {
    /// Stores the Key as a refernce to a String
    StrRef(&'a str),
    /// Stores the Key as an owned String
    Str(String),
}

impl<'a> From<&'a str> for HeaderKey<'a> {
    fn from(val: &'a str) -> Self {
        HeaderKey::StrRef(val)
    }
}
impl<'a> From<String> for HeaderKey<'a> {
    fn from(val: String) -> Self {
        HeaderKey::Str(val)
    }
}

impl<'a> HeaderKey<'a> {
    /// Serializes the Key into the Buffer by appending
    /// the Data to it
    pub fn serialize(&self, buf: &mut Vec<u8>) {
        match *self {
            Self::StrRef(ref value) => {
                buf.extend_from_slice(value.as_bytes());
            }
            Self::Str(ref value) => {
                buf.extend_from_slice(value.as_bytes());
            }
        }
    }
}

impl AsRef<str> for HeaderKey<'_> {
    fn as_ref(&self) -> &str {
        match *self {
            Self::Str(ref value) => &value,
            Self::StrRef(ref value) => value,
        }
    }
}

impl PartialEq for HeaderKey<'_> {
    fn eq(&self, other: &Self) -> bool {
        caseless::default_caseless_match_str(self.as_ref(), other.as_ref())
    }
}

impl Eq for HeaderKey<'_> {}

impl PartialOrd for HeaderKey<'_> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.as_ref().partial_cmp(other.as_ref())
    }
}

impl Ord for HeaderKey<'_> {
    fn cmp(&self, other: &Self) -> Ordering {
        self.as_ref().cmp(other.as_ref())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn equals_ignore_case() {
        assert_eq!(HeaderKey::StrRef("test"), HeaderKey::StrRef("test"));
        assert_eq!(HeaderKey::StrRef("TEST"), HeaderKey::StrRef("test"));
        assert_eq!(HeaderKey::StrRef("TeSt"), HeaderKey::StrRef("test"));
    }

    #[test]
    fn serialize_str() {
        let mut result: Vec<u8> = Vec::new();
        HeaderKey::Str("test-key".to_owned()).serialize(&mut result);

        assert_eq!("test-key".as_bytes(), &result);
    }
    #[test]
    fn serialize_str_ref() {
        let mut result: Vec<u8> = Vec::new();
        HeaderKey::StrRef("test-key").serialize(&mut result);

        assert_eq!("test-key".as_bytes(), &result);
    }

    #[test]
    fn partial_ord() {
        assert_eq!(
            "first" < "second",
            HeaderKey::StrRef("first") < HeaderKey::StrRef("second")
        );
    }
}