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    /// Returns reference to the inner [`ByteBuffer`].
32    pub fn inner(&self) -> &ByteBuffer {
33        &self.0
34    }
35}
36
37impl Debug for BufferString {
38    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
39        f.debug_struct("BufferString")
40            .field("string", &self.as_str())
41            .finish()
42    }
43}
44
45impl From<BufferString> for ByteBuffer {
46    fn from(value: BufferString) -> Self {
47        value.0
48    }
49}
50
51impl From<String> for BufferString {
52    fn from(value: String) -> Self {
53        Self(ByteBuffer::from(value.into_bytes()))
54    }
55}
56
57impl From<&str> for BufferString {
58    fn from(value: &str) -> Self {
59        Self(ByteBuffer::from(String::from(value).into_bytes()))
60    }
61}
62
63impl TryFrom<ByteBuffer> for BufferString {
64    type Error = Utf8Error;
65
66    fn try_from(value: ByteBuffer) -> Result<Self, Self::Error> {
67        let _ = std::str::from_utf8(value.as_ref())?;
68        Ok(Self(value))
69    }
70}
71
72impl Deref for BufferString {
73    type Target = str;
74
75    fn deref(&self) -> &Self::Target {
76        self.as_str()
77    }
78}
79
80impl AsRef<str> for BufferString {
81    fn as_ref(&self) -> &str {
82        self.as_str()
83    }
84}
85
86impl AsRef<[u8]> for BufferString {
87    fn as_ref(&self) -> &[u8] {
88        self.as_str().as_bytes()
89    }
90}
91
92#[cfg(test)]
93mod test {
94    use crate::{Alignment, BufferString, buffer};
95
96    #[test]
97    fn buffer_string() {
98        let buf = BufferString::from("hello");
99        assert_eq!(buf.len(), 5);
100        assert_eq!(buf.into_inner().alignment(), Alignment::of::<u8>());
101    }
102
103    #[test]
104    fn buffer_string_non_ut8() {
105        assert!(BufferString::try_from(buffer![0u8, 255]).is_err());
106    }
107}