arc_slice/
buffer.rs

1use alloc::{borrow::Cow, boxed::Box, string::String, vec::Vec};
2use core::{mem, ptr, ptr::NonNull};
3
4use crate::error::TryReserveError;
5
6pub trait Buffer<T>: Send + 'static {
7    fn as_slice(&self) -> &[T];
8
9    #[doc(hidden)]
10    #[inline(always)]
11    fn is_array(&self) -> bool {
12        false
13    }
14
15    #[doc(hidden)]
16    #[inline(always)]
17    fn try_into_static(self) -> Result<&'static [T], Self>
18    where
19        Self: Sized,
20    {
21        Err(self)
22    }
23
24    #[doc(hidden)]
25    #[inline(always)]
26    fn try_into_vec(self) -> Result<Vec<T>, Self>
27    where
28        Self: Sized,
29    {
30        Err(self)
31    }
32}
33
34impl<T: Send + Sync + 'static> Buffer<T> for &'static [T] {
35    fn as_slice(&self) -> &[T] {
36        self
37    }
38
39    #[inline(always)]
40    fn try_into_static(self) -> Result<&'static [T], Self>
41    where
42        Self: Sized,
43    {
44        Ok(self)
45    }
46}
47
48impl<T: Send + Sync + 'static, const N: usize> Buffer<T> for [T; N] {
49    #[inline]
50    fn as_slice(&self) -> &[T] {
51        self
52    }
53
54    #[inline]
55    fn is_array(&self) -> bool {
56        true
57    }
58}
59
60impl<T: Send + Sync + 'static, const N: usize> Buffer<T> for &'static [T; N] {
61    #[inline]
62    fn as_slice(&self) -> &[T] {
63        *self
64    }
65
66    #[inline(always)]
67    fn try_into_static(self) -> Result<&'static [T], Self>
68    where
69        Self: Sized,
70    {
71        Ok(self)
72    }
73}
74
75impl<T: Send + Sync + 'static> Buffer<T> for Box<[T]> {
76    #[inline]
77    fn as_slice(&self) -> &[T] {
78        self
79    }
80
81    #[inline(always)]
82    fn try_into_vec(self) -> Result<Vec<T>, Self>
83    where
84        Self: Sized,
85    {
86        Ok(self.into_vec())
87    }
88}
89
90impl<T: Send + Sync + 'static> Buffer<T> for Vec<T> {
91    #[inline]
92    fn as_slice(&self) -> &[T] {
93        self
94    }
95
96    #[inline(always)]
97    fn try_into_vec(self) -> Result<Vec<T>, Self>
98    where
99        Self: Sized,
100    {
101        Ok(self)
102    }
103}
104
105impl<T: Clone + Send + Sync + 'static> Buffer<T> for Cow<'static, [T]> {
106    #[inline]
107    fn as_slice(&self) -> &[T] {
108        self
109    }
110
111    #[inline(always)]
112    fn try_into_static(self) -> Result<&'static [T], Self>
113    where
114        Self: Sized,
115    {
116        match self {
117            Cow::Borrowed(s) => Ok(s),
118            cow => Err(cow),
119        }
120    }
121
122    #[inline(always)]
123    fn try_into_vec(self) -> Result<Vec<T>, Self>
124    where
125        Self: Sized,
126    {
127        match self {
128            Cow::Owned(vec) => Ok(vec),
129            cow => Err(cow),
130        }
131    }
132}
133
134#[cfg(not(feature = "portable-atomic"))]
135impl<T: Send + Sync + 'static> Buffer<T> for alloc::sync::Arc<[T]> {
136    #[inline]
137    fn as_slice(&self) -> &[T] {
138        self
139    }
140}
141
142/// # Safety
143///
144/// - [`as_mut_ptr`] must point to the start of a memory buffer of [`capacity`],
145///   with the first [`len`] element initialized.
146/// - slice delimited by [`as_mut_ptr`] and [`len`] must be the same as [`Buffer::as_slice`]
147///
148/// [`as_mut_ptr`]: Self::as_mut_ptr
149/// [`capacity`]: Self::capacity
150/// [`len`]: Self::len
151#[allow(clippy::len_without_is_empty)]
152pub unsafe trait BufferMut<T>: Buffer<T> {
153    fn as_mut_ptr(&mut self) -> NonNull<T>;
154
155    fn len(&self) -> usize;
156
157    fn capacity(&self) -> usize;
158
159    /// # Safety
160    ///
161    /// - First `len` items of buffer slice must be initialized.
162    /// - If `mem::needs_drop::<T>()`, then `len` must be greater or equal to [`Self::len`].
163    unsafe fn set_len(&mut self, len: usize) -> bool;
164
165    fn reserve(&mut self, _additional: usize) -> bool;
166}
167
168unsafe impl<T: Send + Sync + 'static> BufferMut<T> for Vec<T> {
169    #[inline]
170    fn as_mut_ptr(&mut self) -> NonNull<T> {
171        NonNull::new(self.as_mut_ptr()).unwrap()
172    }
173
174    #[inline]
175    fn len(&self) -> usize {
176        self.len()
177    }
178
179    #[inline]
180    fn capacity(&self) -> usize {
181        self.capacity()
182    }
183
184    #[inline]
185    unsafe fn set_len(&mut self, len: usize) -> bool {
186        // SAFETY: same function contract
187        unsafe { self.set_len(len) };
188        true
189    }
190
191    #[inline]
192    fn reserve(&mut self, additional: usize) -> bool {
193        self.reserve(additional);
194        true
195    }
196}
197
198unsafe impl<T: Send + Sync + 'static, const N: usize> BufferMut<T> for [T; N] {
199    #[inline]
200    fn as_mut_ptr(&mut self) -> NonNull<T> {
201        NonNull::new(self.as_mut_slice().as_mut_ptr()).unwrap()
202    }
203
204    #[inline]
205    fn len(&self) -> usize {
206        self.as_slice().len()
207    }
208
209    #[inline]
210    fn capacity(&self) -> usize {
211        self.as_slice().len()
212    }
213
214    #[inline]
215    unsafe fn set_len(&mut self, _len: usize) -> bool {
216        false
217    }
218
219    #[inline]
220    fn reserve(&mut self, _additional: usize) -> bool {
221        false
222    }
223}
224
225pub(crate) trait BufferMutExt<T>: BufferMut<T> + Sized {
226    unsafe fn shift_left(&mut self, offset: usize, length: usize) -> bool {
227        let prev_len = self.len();
228        if !unsafe { self.set_len(length) } {
229            return false;
230        }
231        let buffer_ptr = self.as_mut_ptr().as_ptr();
232        if mem::needs_drop::<T>() {
233            unsafe {
234                ptr::drop_in_place(ptr::slice_from_raw_parts_mut(buffer_ptr, offset));
235                if prev_len > offset + length {
236                    ptr::drop_in_place(ptr::slice_from_raw_parts_mut(
237                        buffer_ptr.add(offset + length),
238                        prev_len - offset - length,
239                    ));
240                }
241            }
242        }
243        if offset >= length {
244            unsafe { ptr::copy_nonoverlapping(buffer_ptr.add(offset), buffer_ptr, length) };
245        } else {
246            unsafe { ptr::copy(buffer_ptr.add(offset), buffer_ptr, length) };
247        }
248        true
249    }
250
251    unsafe fn try_reclaim(&mut self, offset: usize, length: usize, additional: usize) -> bool {
252        self.capacity() - length >= additional
253            && offset >= length
254            && unsafe { self.shift_left(offset, length) }
255    }
256
257    unsafe fn try_reclaim_or_reserve(
258        &mut self,
259        offset: usize,
260        length: usize,
261        additional: usize,
262        allocate: bool,
263    ) -> Result<usize, TryReserveError> {
264        let capacity = self.capacity();
265        if capacity - offset - length >= additional {
266            return Ok(offset);
267        }
268        // conditions from `BytesMut::reserve_inner`
269        if self.capacity() - length >= additional
270            && offset >= length
271            && unsafe { self.shift_left(offset, length) }
272        {
273            return Ok(0);
274        }
275        if allocate && unsafe { self.shift_left(0, offset + length) } && self.reserve(additional) {
276            Ok(offset)
277        } else {
278            Err(TryReserveError::Unsupported)
279        }
280    }
281}
282
283impl<T, B: BufferMut<T>> BufferMutExt<T> for B {}
284
285pub trait StringBuffer: Send + 'static {
286    fn as_str(&self) -> &str;
287
288    #[doc(hidden)]
289    #[inline(always)]
290    fn try_into_static(self) -> Result<&'static str, Self>
291    where
292        Self: Sized,
293    {
294        Err(self)
295    }
296
297    #[doc(hidden)]
298    #[inline(always)]
299    fn try_into_string(self) -> Result<String, Self>
300    where
301        Self: Sized,
302    {
303        Err(self)
304    }
305}
306
307impl StringBuffer for &'static str {
308    #[inline]
309    fn as_str(&self) -> &str {
310        self
311    }
312
313    #[inline(always)]
314    fn try_into_static(self) -> Result<&'static str, Self>
315    where
316        Self: Sized,
317    {
318        Ok(self)
319    }
320}
321
322impl StringBuffer for Box<str> {
323    #[inline]
324    fn as_str(&self) -> &str {
325        self
326    }
327
328    #[inline(always)]
329    fn try_into_string(self) -> Result<String, Self>
330    where
331        Self: Sized,
332    {
333        Ok(self.into_string())
334    }
335}
336
337impl StringBuffer for String {
338    #[inline]
339    fn as_str(&self) -> &str {
340        self
341    }
342
343    #[inline(always)]
344    fn try_into_string(self) -> Result<String, Self>
345    where
346        Self: Sized,
347    {
348        Ok(self)
349    }
350}
351
352impl StringBuffer for Cow<'static, str> {
353    #[inline]
354    fn as_str(&self) -> &str {
355        self
356    }
357
358    #[inline(always)]
359    fn try_into_static(self) -> Result<&'static str, Self>
360    where
361        Self: Sized,
362    {
363        match self {
364            Cow::Borrowed(s) => Ok(s),
365            cow => Err(cow),
366        }
367    }
368
369    #[inline(always)]
370    fn try_into_string(self) -> Result<String, Self>
371    where
372        Self: Sized,
373    {
374        match self {
375            Cow::Owned(s) => Ok(s),
376            cow => Err(cow),
377        }
378    }
379}
380
381pub trait BorrowMetadata {
382    type Metadata: ?Sized + Sync + 'static;
383
384    fn borrow_metadata(&self) -> &Self::Metadata;
385}