headers/util/
value_string.rs

1use std::{
2    fmt,
3    str::{self, FromStr},
4};
5
6use bytes::Bytes;
7use http::header::HeaderValue;
8
9use super::IterExt;
10
11/// A value that is both a valid `HeaderValue` and `String`.
12#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
13pub(crate) struct HeaderValueString {
14    /// Care must be taken to only set this value when it is also
15    /// a valid `String`, since `as_str` will convert to a `&str`
16    /// in an unchecked manner.
17    value: HeaderValue,
18}
19
20impl HeaderValueString {
21    pub(crate) fn from_val(val: &HeaderValue) -> Result<Self, ::Error> {
22        if val.to_str().is_ok() {
23            Ok(HeaderValueString { value: val.clone() })
24        } else {
25            Err(::Error::invalid())
26        }
27    }
28
29    pub(crate) fn from_string(src: String) -> Option<Self> {
30        // A valid `str` (the argument)...
31        let bytes = Bytes::from(src);
32        HeaderValue::from_maybe_shared(bytes)
33            .ok()
34            .map(|value| HeaderValueString { value })
35    }
36
37    pub(crate) fn from_static(src: &'static str) -> HeaderValueString {
38        // A valid `str` (the argument)...
39        HeaderValueString {
40            value: HeaderValue::from_static(src),
41        }
42    }
43
44    pub(crate) fn as_str(&self) -> &str {
45        // HeaderValueString is only created from HeaderValues
46        // that have validated they are also UTF-8 strings.
47        unsafe { str::from_utf8_unchecked(self.value.as_bytes()) }
48    }
49}
50
51impl fmt::Debug for HeaderValueString {
52    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
53        fmt::Debug::fmt(self.as_str(), f)
54    }
55}
56
57impl fmt::Display for HeaderValueString {
58    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
59        fmt::Display::fmt(self.as_str(), f)
60    }
61}
62
63impl super::TryFromValues for HeaderValueString {
64    fn try_from_values<'i, I>(values: &mut I) -> Result<Self, ::Error>
65    where
66        I: Iterator<Item = &'i HeaderValue>,
67    {
68        values
69            .just_one()
70            .map(HeaderValueString::from_val)
71            .unwrap_or_else(|| Err(::Error::invalid()))
72    }
73}
74
75impl<'a> From<&'a HeaderValueString> for HeaderValue {
76    fn from(src: &'a HeaderValueString) -> HeaderValue {
77        src.value.clone()
78    }
79}
80
81#[derive(Debug)]
82pub(crate) struct FromStrError(());
83
84impl FromStr for HeaderValueString {
85    type Err = FromStrError;
86
87    fn from_str(src: &str) -> Result<Self, Self::Err> {
88        // A valid `str` (the argument)...
89        src.parse()
90            .map(|value| HeaderValueString { value })
91            .map_err(|_| FromStrError(()))
92    }
93}