planus/impls/
str.rs

1use core::mem::MaybeUninit;
2
3use crate::{
4    builder::Builder, errors::ErrorKind, slice_helpers::SliceWithStartOffset, traits::*, Cursor,
5    Offset,
6};
7
8impl WriteAsOffset<str> for str {
9    #[inline]
10    #[allow(clippy::let_and_return)]
11    fn prepare(&self, builder: &mut Builder) -> Offset<str> {
12        #[cfg(feature = "string-cache")]
13        let hash = {
14            let hash = builder.string_cache.hash(self.as_bytes());
15            if let Some(offset) =
16                builder
17                    .string_cache
18                    .get(builder.inner.as_slice(), hash, self.as_bytes())
19            {
20                return offset.into();
21            }
22            hash
23        };
24
25        let size_including_len_and_null = self.len().checked_add(5).unwrap();
26        // SAFETY: We make sure to write the 4+len+1 bytes inside the closure
27        unsafe {
28            builder.write_with(
29                size_including_len_and_null,
30                u32::ALIGNMENT_MASK,
31                |buffer_position, bytes| {
32                    let bytes = bytes.as_mut_ptr();
33
34                    (self.len() as u32).write(
35                        Cursor::new(&mut *(bytes as *mut [MaybeUninit<u8>; 4])),
36                        buffer_position,
37                    );
38                    core::ptr::copy_nonoverlapping(
39                        self.as_bytes().as_ptr() as *const MaybeUninit<u8>,
40                        bytes.add(4),
41                        self.len(),
42                    );
43                    bytes.add(4 + self.len()).write(MaybeUninit::new(0));
44                },
45            )
46        }
47        let offset = builder.current_offset();
48
49        #[cfg(feature = "string-cache")]
50        builder
51            .string_cache
52            .insert(hash, offset.into(), builder.inner.as_slice());
53
54        offset
55    }
56}
57
58impl WriteAs<Offset<str>> for str {
59    type Prepared = Offset<str>;
60
61    #[inline]
62    fn prepare(&self, builder: &mut Builder) -> Offset<str> {
63        WriteAsOffset::prepare(self, builder)
64    }
65}
66
67impl WriteAsOptional<Offset<str>> for str {
68    type Prepared = Offset<str>;
69    #[inline]
70    fn prepare(&self, builder: &mut Builder) -> Option<Offset<str>> {
71        Some(WriteAsOffset::prepare(self, builder))
72    }
73}
74
75impl WriteAsDefault<Offset<str>, str> for str {
76    type Prepared = Offset<str>;
77
78    #[inline]
79    fn prepare(&self, builder: &mut Builder, default: &str) -> Option<Offset<str>> {
80        if self == default {
81            None
82        } else {
83            Some(WriteAsOffset::prepare(self, builder))
84        }
85    }
86}
87
88impl<'buf> TableRead<'buf> for &'buf str {
89    fn from_buffer(
90        buffer: SliceWithStartOffset<'buf>,
91        offset: usize,
92    ) -> core::result::Result<Self, ErrorKind> {
93        let (buffer, len) = super::array_from_buffer(buffer, offset)?;
94        #[cfg(feature = "extra-validation")]
95        if buffer.as_slice().get(len) != Some(&0) {
96            return Err(ErrorKind::MissingNullTerminator);
97        }
98        let slice = buffer
99            .as_slice()
100            .get(..len)
101            .ok_or(ErrorKind::InvalidLength)?;
102        Ok(core::str::from_utf8(slice)?)
103    }
104}
105
106impl<'buf> VectorReadInner<'buf> for &'buf str {
107    type Error = crate::errors::Error;
108
109    const STRIDE: usize = 4;
110    #[inline]
111    unsafe fn from_buffer(
112        buffer: SliceWithStartOffset<'buf>,
113        offset: usize,
114    ) -> crate::Result<&'buf str> {
115        let add_context =
116            |e: ErrorKind| e.with_error_location("[str]", "get", buffer.offset_from_start);
117        let (slice, len) = super::array_from_buffer(buffer, offset).map_err(add_context)?;
118        #[cfg(feature = "extra-validation")]
119        if slice.as_slice().get(len) != Some(&0) {
120            return Err(add_context(ErrorKind::MissingNullTerminator));
121        }
122        let slice = slice
123            .as_slice()
124            .get(..len)
125            .ok_or(ErrorKind::InvalidLength)
126            .map_err(add_context)?;
127        let str = core::str::from_utf8(slice)
128            .map_err(|source| ErrorKind::InvalidUtf8 { source })
129            .map_err(add_context)?;
130        Ok(str)
131    }
132}
133
134/// # Safety
135/// The implementation of `write_values` initializes all the bytes.
136unsafe impl VectorWrite<Offset<str>> for str {
137    type Value = Offset<str>;
138
139    const STRIDE: usize = 4;
140    #[inline]
141    fn prepare(&self, builder: &mut Builder) -> Self::Value {
142        WriteAs::prepare(self, builder)
143    }
144
145    #[inline]
146    unsafe fn write_values(
147        values: &[Offset<str>],
148        bytes: *mut MaybeUninit<u8>,
149        buffer_position: u32,
150    ) {
151        let bytes = bytes as *mut [MaybeUninit<u8>; 4];
152        for (i, v) in values.iter().enumerate() {
153            v.write(
154                Cursor::new(&mut *bytes.add(i)),
155                buffer_position - (4 * i) as u32,
156            );
157        }
158    }
159}