vortex_buffer/
string.rs

1use std::fmt::{Debug, Formatter};
2use std::ops::Deref;
3use std::str::Utf8Error;
4
5use crate::ByteBuffer;
6
7/// A wrapper around a [`ByteBuffer`] that guarantees that the buffer contains valid UTF-8.
8#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
9pub struct BufferString(ByteBuffer);
10
11impl BufferString {
12    /// Creates a new `BufferString` from a [`ByteBuffer`].
13    ///
14    /// # Safety
15    /// Assumes that the buffer contains valid UTF-8.
16    pub const unsafe fn new_unchecked(buffer: ByteBuffer) -> Self {
17        Self(buffer)
18    }
19
20    /// Return a view of the contents of BufferString as an immutable `&str`.
21    pub fn as_str(&self) -> &str {
22        // SAFETY: We have already validated that the buffer is valid UTF-8
23        unsafe { std::str::from_utf8_unchecked(self.0.as_ref()) }
24    }
25
26    /// Returns the inner [`ByteBuffer`].
27    pub fn into_inner(self) -> ByteBuffer {
28        self.0
29    }
30}
31
32impl Debug for BufferString {
33    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
34        f.debug_struct("BufferString")
35            .field("string", &self.as_str())
36            .finish()
37    }
38}
39
40impl From<BufferString> for ByteBuffer {
41    fn from(value: BufferString) -> Self {
42        value.0
43    }
44}
45
46impl From<String> for BufferString {
47    fn from(value: String) -> Self {
48        Self(ByteBuffer::from(value.into_bytes()))
49    }
50}
51
52impl From<&str> for BufferString {
53    fn from(value: &str) -> Self {
54        Self(ByteBuffer::from(String::from(value).into_bytes()))
55    }
56}
57
58impl TryFrom<ByteBuffer> for BufferString {
59    type Error = Utf8Error;
60
61    fn try_from(value: ByteBuffer) -> Result<Self, Self::Error> {
62        let _ = std::str::from_utf8(value.as_ref())?;
63        Ok(Self(value))
64    }
65}
66
67impl Deref for BufferString {
68    type Target = str;
69
70    fn deref(&self) -> &Self::Target {
71        self.as_str()
72    }
73}
74
75impl AsRef<str> for BufferString {
76    fn as_ref(&self) -> &str {
77        self.as_str()
78    }
79}
80
81impl AsRef<[u8]> for BufferString {
82    fn as_ref(&self) -> &[u8] {
83        self.as_str().as_bytes()
84    }
85}
86
87#[cfg(test)]
88mod test {
89    use crate::{Alignment, BufferString, buffer};
90
91    #[test]
92    fn buffer_string() {
93        let buf = BufferString::from("hello");
94        assert_eq!(buf.len(), 5);
95        assert_eq!(buf.into_inner().alignment(), Alignment::of::<u8>());
96    }
97
98    #[test]
99    fn buffer_string_non_ut8() {
100        assert!(BufferString::try_from(buffer![0u8, 255]).is_err());
101    }
102}