Skip to main content

rama_core/
byte_str.rs

1//! [`ByteStr`]: a cheaply-cloneable, UTF-8 [`Bytes`] string slice.
2//!
3//! Forked verbatim from the `http` crate (v1.4.0, MIT) — generally useful on
4//! top of the [`bytes`](crate::bytes) re-export, so it lives in rama-core.
5//! See `docs/thirdparty/fork/README.md`.
6#![allow(
7    unreachable_pub,
8    clippy::allow_attributes,
9    clippy::style,
10    clippy::complexity,
11    clippy::perf,
12    clippy::suspicious,
13    clippy::pedantic,
14    clippy::nursery,
15    clippy::unwrap_used,
16    clippy::expect_used,
17    clippy::panic,
18    clippy::unreachable,
19    clippy::get_unwrap,
20    clippy::let_underscore_must_use,
21    clippy::multiple_unsafe_ops_per_block,
22    clippy::unnecessary_safety_comment,
23    dead_code,
24    unsafe_op_in_unsafe_fn
25)]
26
27use core::{ops, str};
28
29use crate::std::string::String;
30
31use bytes::Bytes;
32
33#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
34pub struct ByteStr {
35    // Invariant: bytes contains valid UTF-8
36    bytes: Bytes,
37}
38
39impl ByteStr {
40    #[inline]
41    pub fn new() -> ByteStr {
42        ByteStr {
43            // Invariant: the empty slice is trivially valid UTF-8.
44            bytes: Bytes::new(),
45        }
46    }
47
48    #[inline]
49    pub const fn from_static(val: &'static str) -> ByteStr {
50        ByteStr {
51            // Invariant: val is a str so contains valid UTF-8.
52            bytes: Bytes::from_static(val.as_bytes()),
53        }
54    }
55
56    #[inline]
57    /// ## Panics
58    /// In a debug build this will panic if `bytes` is not valid UTF-8.
59    ///
60    /// ## Safety
61    /// `bytes` must contain valid UTF-8. In a release build it is undefined
62    /// behavior to call this with `bytes` that is not valid UTF-8.
63    pub unsafe fn from_utf8_unchecked(bytes: Bytes) -> ByteStr {
64        if cfg!(debug_assertions) {
65            match str::from_utf8(&bytes) {
66                Ok(_) => (),
67                Err(err) => panic!(
68                    "ByteStr::from_utf8_unchecked() with invalid bytes; error = {}, bytes = {:?}",
69                    err, bytes
70                ),
71            }
72        }
73        // Invariant: assumed by the safety requirements of this function.
74        ByteStr { bytes }
75    }
76
77    pub fn from_utf8(bytes: Bytes) -> Result<ByteStr, core::str::Utf8Error> {
78        str::from_utf8(&bytes)?;
79        // Invariant: just checked is utf8
80        Ok(ByteStr { bytes })
81    }
82}
83
84impl ops::Deref for ByteStr {
85    type Target = str;
86
87    #[inline]
88    fn deref(&self) -> &str {
89        let b: &[u8] = self.bytes.as_ref();
90        // Safety: the invariant of `bytes` is that it contains valid UTF-8.
91        unsafe { str::from_utf8_unchecked(b) }
92    }
93}
94
95impl From<String> for ByteStr {
96    #[inline]
97    fn from(src: String) -> ByteStr {
98        ByteStr {
99            // Invariant: src is a String so contains valid UTF-8.
100            bytes: Bytes::from(src),
101        }
102    }
103}
104
105impl From<&str> for ByteStr {
106    #[inline]
107    fn from(src: &str) -> ByteStr {
108        ByteStr {
109            // Invariant: src is a str so contains valid UTF-8.
110            bytes: Bytes::copy_from_slice(src.as_bytes()),
111        }
112    }
113}
114
115impl From<ByteStr> for Bytes {
116    fn from(src: ByteStr) -> Self {
117        src.bytes
118    }
119}