use std::str::FromStr;
use http::HeaderMap;
use http::header::AsHeaderName;
pub trait HeaderMapExt: sealed::Sealed {
fn get_str_value(&self, header_name: impl AsHeaderName) -> Option<&str>;
fn get_str_value_or<'a>(&'a self, header_name: impl AsHeaderName, default: &'a str) -> &'a str {
self.get_str_value(header_name).unwrap_or(default)
}
fn get_value<T: FromStr>(&self, header_name: impl AsHeaderName) -> Option<T>;
fn get_value_or<T: FromStr>(&self, header_name: impl AsHeaderName, default: T) -> T {
self.get_value(header_name).unwrap_or(default)
}
}
impl HeaderMapExt for HeaderMap {
fn get_str_value(&self, header_name: impl AsHeaderName) -> Option<&str> {
self.get(header_name).and_then(|v| v.to_str().ok())
}
fn get_value<T: FromStr>(&self, header_name: impl AsHeaderName) -> Option<T> {
self.get(header_name).and_then(|v| v.to_str().ok()).and_then(|str| str.parse().ok())
}
}
pub(crate) mod sealed {
use super::*;
#[expect(unnameable_types, reason = "intentional, sealed trait pattern")]
pub trait Sealed {}
impl Sealed for HeaderMap {}
}
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
mod tests {
use super::*;
#[test]
fn get_str_value() {
let mut headers = HeaderMap::new();
headers.insert("XYZ", "dummy".parse().unwrap());
assert_eq!(headers.get_str_value_or("XYZ", ""), "dummy");
assert_eq!(headers.get_str_value_or("does_not_exist", "def"), "def");
}
#[test]
fn get_value_ok() {
let mut headers = HeaderMap::new();
headers.insert("XYZ", "10".parse().unwrap());
assert_eq!(headers.get_value_or("XYZ", 0), 10);
}
#[test]
fn get_value_invalid_returns_default() {
let mut headers = HeaderMap::new();
headers.insert("XYZ", "abc".parse().unwrap());
assert_eq!(headers.get_value_or("XYZ", 4), 4);
}
}