1use bytes::Bytes;
2
3use std::{ops, str};
4
5#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
6pub(crate) struct ByteStr {
7 // Invariant: bytes contains valid UTF-8
8 bytes: Bytes,
9}
10
11impl ByteStr {
12 #[inline]
13 pub fn new() -> ByteStr {
14 ByteStr {
15 // Invariant: the empty slice is trivially valid UTF-8.
16 bytes: Bytes::new(),
17 }
18 }
19
20 #[inline]
21 pub const fn from_static(val: &'static str) -> ByteStr {
22 ByteStr {
23 // Invariant: val is a str so contains valid UTF-8.
24 bytes: Bytes::from_static(val.as_bytes()),
25 }
26 }
27
28 #[inline]
29 /// ## Panics
30 /// In a debug build this will panic if `bytes` is not valid UTF-8.
31 ///
32 /// ## Safety
33 /// `bytes` must contain valid UTF-8. In a release build it is undefined
34 /// behaviour to call this with `bytes` that is not valid UTF-8.
35 pub unsafe fn from_utf8_unchecked(bytes: Bytes) -> ByteStr {
36 if cfg!(debug_assertions) {
37 match str::from_utf8(&bytes) {
38 Ok(_) => (),
39 Err(err) => panic!(
40 "ByteStr::from_utf8_unchecked() with invalid bytes; error = {}, bytes = {:?}",
41 err, bytes
42 ),
43 }
44 }
45 // Invariant: assumed by the safety requirements of this function.
46 ByteStr { bytes: bytes }
47 }
48}
49
50impl ops::Deref for ByteStr {
51 type Target = str;
52
53 #[inline]
54 fn deref(&self) -> &str {
55 let b: &[u8] = self.bytes.as_ref();
56 // Safety: the invariant of `bytes` is that it contains valid UTF-8.
57 unsafe { str::from_utf8_unchecked(b) }
58 }
59}
60
61impl From<String> for ByteStr {
62 #[inline]
63 fn from(src: String) -> ByteStr {
64 ByteStr {
65 // Invariant: src is a String so contains valid UTF-8.
66 bytes: Bytes::from(src),
67 }
68 }
69}
70
71impl<'a> From<&'a str> for ByteStr {
72 #[inline]
73 fn from(src: &'a str) -> ByteStr {
74 ByteStr {
75 // Invariant: src is a str so contains valid UTF-8.
76 bytes: Bytes::copy_from_slice(src.as_bytes()),
77 }
78 }
79}
80
81impl From<ByteStr> for Bytes {
82 fn from(src: ByteStr) -> Self {
83 src.bytes
84 }
85}
86