use std::collections::HashMap;
use std::str::FromStr;
use crate::error::{Error, Result};
#[cfg(test)]
use headers::HeaderName;
use headers::{HeaderMap, HeaderValue};
const HEADER_SEPARATOR: &str = ":";
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CaseSensitiveHeaderMap {
inner: HashMap<String, HeaderValue>,
}
impl Default for CaseSensitiveHeaderMap {
fn default() -> Self {
Self::new()
}
}
impl CaseSensitiveHeaderMap {
pub fn new() -> Self {
Self {
inner: HashMap::new(),
}
}
pub fn insert(&mut self, name: String, value: HeaderValue) -> Option<HeaderValue> {
self.inner.insert(name, value)
}
pub fn get(&self, k: &str) -> Option<&HeaderValue> {
self.inner.get(k)
}
}
impl FromStr for CaseSensitiveHeaderMap {
type Err = Error;
fn from_str(headers: &str) -> Result<Self> {
Ok(CaseSensitiveHeaderMap {
inner: headers
.lines()
.filter_map(|line| line.split_once(HEADER_SEPARATOR))
.map(|(header, value)| {
(
header.to_string(),
HeaderValue::from_str(value.trim()).unwrap(),
)
})
.collect(),
})
}
}
impl From<&str> for CaseSensitiveHeaderMap {
fn from(headers: &str) -> Self {
CaseSensitiveHeaderMap::from_str(headers).unwrap()
}
}
impl From<HeaderMap> for CaseSensitiveHeaderMap {
fn from(headers: HeaderMap) -> Self {
let mut cs_map = CaseSensitiveHeaderMap::new();
for (name, value) in headers.iter() {
cs_map.insert(name.as_str().to_string(), value.clone());
}
cs_map
}
}
impl From<&HeaderMap> for CaseSensitiveHeaderMap {
fn from(headers: &HeaderMap) -> Self {
let mut cs_map = CaseSensitiveHeaderMap::new();
for (name, value) in headers.iter() {
cs_map.insert(name.as_str().to_string(), value.clone());
}
cs_map
}
}
#[cfg(test)]
pub(crate) trait HeaderMapExt {
fn from_raw(raw: &str) -> Result<HeaderMap>;
}
#[cfg(test)]
impl HeaderMapExt for HeaderMap {
fn from_raw(raw: &str) -> Result<HeaderMap> {
let mut headers = HeaderMap::new();
for line in raw.lines() {
if !line.contains(HEADER_SEPARATOR) {
return Err(Error::HeaderWithoutColon(line.to_string()));
}
if let Some((name, value)) = line.split_once(HEADER_SEPARATOR) {
headers.insert(
HeaderName::from_str(name)?,
HeaderValue::from_str(value.trim())?,
);
}
}
Ok(headers)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_convert_from_header_map() {
let mut headers = HeaderMap::new();
headers.insert("X-RateLimit-Limit", "100".parse().unwrap());
headers.insert("X-RateLimit-Remaining", "99".parse().unwrap());
headers.insert("X-RateLimit-Reset", "1234567890".parse().unwrap());
let cs_headers = CaseSensitiveHeaderMap::from(&headers);
assert_eq!(
cs_headers,
CaseSensitiveHeaderMap {
inner: vec![
(
"x-ratelimit-limit".to_string(),
HeaderValue::from_static("100")
),
(
"x-ratelimit-remaining".to_string(),
HeaderValue::from_static("99")
),
(
"x-ratelimit-reset".to_string(),
HeaderValue::from_static("1234567890")
)
]
.into_iter()
.collect()
}
);
}
}