vortex_buffer/
string.rs

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