1use serde::{Deserialize, Deserializer, Serialize, Serializer};
6use smol_str::SmolStr;
7use std::borrow::Cow;
8use std::fmt;
9
10#[derive(Debug, Clone, PartialEq, Eq, Hash)]
13pub struct HeaderValue(Cow<'static, str>);
14
15impl Serialize for HeaderValue {
16 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
17 serializer.serialize_str(&self.0)
18 }
19}
20
21impl<'de> Deserialize<'de> for HeaderValue {
22 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
23 let s = String::deserialize(deserializer)?;
24 Ok(HeaderValue::from_string(s))
25 }
26}
27
28impl HeaderValue {
29 pub const fn from_static(s: &'static str) -> Self {
31 Self(Cow::Borrowed(s))
32 }
33
34 pub fn from_string(s: String) -> Self {
36 Self(Cow::Owned(s))
37 }
38
39 pub fn as_str(&self) -> &str {
41 &self.0
42 }
43
44 pub fn len(&self) -> usize {
46 self.0.len()
47 }
48
49 pub fn is_empty(&self) -> bool {
51 self.0.is_empty()
52 }
53}
54
55impl fmt::Display for HeaderValue {
56 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 f.write_str(&self.0)
58 }
59}
60
61impl From<&'static str> for HeaderValue {
62 fn from(value: &'static str) -> Self {
63 Self::from_static(value)
64 }
65}
66
67impl From<String> for HeaderValue {
68 fn from(value: String) -> Self {
69 Self::from_string(value)
70 }
71}
72
73impl From<SmolStr> for HeaderValue {
74 fn from(value: SmolStr) -> Self {
75 Self(Cow::Owned(value.to_string()))
76 }
77}
78
79impl From<Cow<'static, str>> for HeaderValue {
80 fn from(value: Cow<'static, str>) -> Self {
81 Self(value)
82 }
83}
84
85impl From<&HeaderValue> for HeaderValue {
86 fn from(value: &HeaderValue) -> Self {
87 value.clone()
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94
95 #[test]
96 fn from_static_is_borrowed() {
97 let v = HeaderValue::from_static("application/json");
98 assert!(matches!(v.0, Cow::Borrowed(_)));
99 assert_eq!(v.as_str(), "application/json");
100 }
101
102 #[test]
103 fn from_string_is_owned() {
104 let v: HeaderValue = String::from("Bearer abc").into();
105 assert!(matches!(v.0, Cow::Owned(_)));
106 assert_eq!(v.as_str(), "Bearer abc");
107 }
108
109 #[test]
110 fn from_smol_str() {
111 let v: HeaderValue = SmolStr::new("ses_42").into();
112 assert_eq!(v.as_str(), "ses_42");
113 }
114
115 #[test]
116 fn equality_ignores_storage_kind() {
117 let a = HeaderValue::from_static("xyz");
118 let b: HeaderValue = String::from("xyz").into();
119 assert_eq!(a, b);
120 }
121}