     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85

    use bytes::Bytes;

    use std::{ops, str};

    #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
    pub(crate) struct ByteStr {
        // Invariant: bytes contains valid UTF-8
        bytes: Bytes,
    }

    impl ByteStr {
        #[inline]
        pub fn new() -> ByteStr {
            ByteStr {
                // Invariant: the empty slice is trivially valid UTF-8.
                bytes: Bytes::new(),
            }
        }

        #[inline]
        pub fn from_static(val: &'static str) -> ByteStr {
            ByteStr {
                // Invariant: val is a str so contains vaid UTF-8.
                bytes: Bytes::from_static(val.as_bytes()),
            }
        }

        #[inline]
        /// ## Panics
        /// In a debug build this will panic if `bytes` is not valid UTF-8.
        ///
        /// ## Safety
        /// `bytes` must contain valid UTF-8. In a release build it is undefined
        /// behaviour to call this with `bytes` that is not valid UTF-8.
        pub unsafe fn from_utf8_unchecked(bytes: Bytes) -> ByteStr {
            if cfg!(debug_assertions) {
                match str::from_utf8(&bytes) {
                    Ok(_) => (),
                    Err(err) => panic!(
                        "ByteStr::from_utf8_unchecked() with invalid bytes; error = {}, bytes = {:?}",
                        err, bytes
                    ),
                }
            }
            // Invariant: assumed by the safety requirements of this function.
            ByteStr { bytes: bytes }
        }
    }

    impl ops::Deref for ByteStr {
        type Target = str;

        #[inline]
        fn deref(&self) -> &str {
            let b: &[u8] = self.bytes.as_ref();
            // Safety: the invariant of `bytes` is that it contains valid UTF-8.
            unsafe { str::from_utf8_unchecked(b) }
        }
    }

    impl From<String> for ByteStr {
        #[inline]
        fn from(src: String) -> ByteStr {
            ByteStr {
                // Invariant: src is a String so contains valid UTF-8.
                bytes: Bytes::from(src),
            }
        }
    }

    impl<'a> From<&'a str> for ByteStr {
        #[inline]
        fn from(src: &'a str) -> ByteStr {
            ByteStr {
                // Invariant: src is a str so contains valid UTF-8.
                bytes: Bytes::copy_from_slice(src.as_bytes()),
            }
        }
    }

    impl From<ByteStr> for Bytes {
        fn from(src: ByteStr) -> Self {
            src.bytes
        }
    }