Skip to main content

trillium_http/headers/
shared_value.rs

1//! A reference-counted header value shared between a compression dynamic table and the
2//! [`Headers`](crate::Headers) it is emitted into.
3
4use super::header_value::HeaderValueInner;
5use crate::{HeaderValue, compact_cow::CompactCow, headers::field_section::FieldLineValue};
6use std::{
7    fmt::{self, Debug, Formatter},
8    sync::Arc,
9};
10
11/// UTF-8 validity is decided once, when the value is first shared, so every clone can be
12/// dropped straight into a [`HeaderValue`] without rescanning the bytes.
13#[derive(Clone, PartialEq, Eq, Hash)]
14pub(crate) enum SharedValue {
15    Utf8(Arc<str>),
16    Bytes(Arc<[u8]>),
17}
18
19impl SharedValue {
20    pub(in crate::headers) fn as_bytes(&self) -> &[u8] {
21        match self {
22            SharedValue::Utf8(s) => s.as_bytes(),
23            SharedValue::Bytes(b) => b,
24        }
25    }
26}
27
28impl Debug for SharedValue {
29    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
30        match self {
31            SharedValue::Utf8(s) => Debug::fmt(s, f),
32            SharedValue::Bytes(b) => Debug::fmt(&String::from_utf8_lossy(b), f),
33        }
34    }
35}
36
37impl From<&[u8]> for SharedValue {
38    fn from(bytes: &[u8]) -> Self {
39        match std::str::from_utf8(bytes) {
40            Ok(s) => SharedValue::Utf8(Arc::from(s)),
41            Err(_) => SharedValue::Bytes(Arc::from(bytes)),
42        }
43    }
44}
45
46impl From<Vec<u8>> for SharedValue {
47    fn from(bytes: Vec<u8>) -> Self {
48        match String::from_utf8(bytes) {
49            Ok(s) => SharedValue::Utf8(Arc::from(s)),
50            Err(e) => SharedValue::Bytes(Arc::from(e.into_bytes())),
51        }
52    }
53}
54
55impl From<FieldLineValue<'_>> for SharedValue {
56    fn from(value: FieldLineValue<'_>) -> Self {
57        match value {
58            FieldLineValue::Static(b) | FieldLineValue::Borrowed(b) => Self::from(b),
59            FieldLineValue::Owned(v) => Self::from(v),
60            FieldLineValue::Shared(shared) => shared,
61        }
62    }
63}
64
65impl From<SharedValue> for HeaderValue {
66    fn from(value: SharedValue) -> Self {
67        HeaderValue::from_inner(match value {
68            SharedValue::Utf8(s) => HeaderValueInner::Utf8(CompactCow::Shared(s)),
69            SharedValue::Bytes(b) => HeaderValueInner::Bytes(b),
70        })
71    }
72}