musli_zerocopy/slice/
slice.rs

1use crate::buf::Load;
2use crate::endian::ByteOrder;
3use crate::error::CoerceError;
4use crate::pointer::{Ref, Size};
5use crate::traits::ZeroCopy;
6
7mod sealed {
8    use crate::endian::ByteOrder;
9    use crate::pointer::{Ref, Size};
10    use crate::slice::Packed;
11    use crate::traits::ZeroCopy;
12
13    pub trait Sealed {}
14
15    impl<T, E, O> Sealed for Ref<[T], E, O>
16    where
17        T: ZeroCopy,
18        E: ByteOrder,
19        O: Size,
20    {
21    }
22
23    impl<T, O, L, E> Sealed for Packed<[T], O, L, E>
24    where
25        O: Size,
26        L: Size,
27        E: ByteOrder,
28    {
29    }
30}
31
32/// A trait implemented by slice-like types.
33pub trait Slice: self::sealed::Sealed + Copy + ZeroCopy + Load<Target = [Self::Item]> {
34    /// The item in an unsized slice, or the `T` in `[T]`.
35    type Item;
36
37    /// A returned reference to an item in a slice.
38    type ItemRef: Load<Target = Self::Item>;
39
40    /// Construct a slice from a [`Ref<[Self::Item]>`].
41    ///
42    /// # Panics
43    ///
44    /// This method panics if construction of the slice would overflow any of
45    /// its parameters.
46    ///
47    /// # Examples
48    ///
49    /// ```
50    /// use musli_zerocopy::{Ref, ZeroCopy};
51    /// use musli_zerocopy::slice::Slice;
52    ///
53    /// fn generic<S>(r: Ref<[S::Item]>) -> S
54    /// where
55    ///     S: Slice,
56    ///     S::Item: ZeroCopy
57    /// {
58    ///     S::from_ref(r)
59    /// }
60    /// ```
61    fn from_ref<E, O>(slice: Ref<[Self::Item], E, O>) -> Self
62    where
63        Self::Item: ZeroCopy,
64        E: ByteOrder,
65        O: Size;
66
67    /// Try to construct a slice from a [`Ref<[Self::Item]>`].
68    ///
69    /// # Errors
70    ///
71    /// This method errors if construction of the slice would overflow any of
72    /// its parameters.
73    ///
74    /// # Examples
75    ///
76    /// ```
77    /// use musli_zerocopy::{Error, Ref, ZeroCopy};
78    /// use musli_zerocopy::slice::Slice;
79    ///
80    /// fn generic<S>(r: Ref<[S::Item]>) -> Result<S, Error>
81    /// where
82    ///     S: Slice<Item: ZeroCopy>
83    /// {
84    ///     Ok(S::try_from_ref(r)?)
85    /// }
86    /// ```
87    fn try_from_ref<E, O>(slice: Ref<[Self::Item], E, O>) -> Result<Self, CoerceError>
88    where
89        Self::Item: ZeroCopy,
90        E: ByteOrder,
91        O: Size;
92
93    /// Construct a slice from its `offset` and `len`.
94    ///
95    /// # Panics
96    ///
97    /// This method panics if construction of the slice would overflow any of
98    /// its parameters.
99    ///
100    /// # Examples
101    ///
102    /// ```
103    /// use musli_zerocopy::Ref;
104    /// use musli_zerocopy::slice::Slice;
105    ///
106    /// fn generic<S>() -> S where S: Slice {
107    ///     S::with_metadata(0usize, 10)
108    /// }
109    /// ```
110    fn with_metadata(offset: usize, len: usize) -> Self;
111
112    /// Construct a slice from its `offset` and `len`.
113    ///
114    /// # Errors
115    ///
116    /// This method errors if construction of the slice would overflow any of
117    /// its parameters.
118    ///
119    /// # Examples
120    ///
121    /// ```
122    /// use musli_zerocopy::Ref;
123    /// use musli_zerocopy::slice::Slice;
124    ///
125    /// fn generic<S>() -> S where S: Slice {
126    ///     S::with_metadata(0usize, 10)
127    /// }
128    /// ```
129    fn try_with_metadata(offset: usize, len: usize) -> Result<Self, CoerceError>;
130
131    /// Try to get a reference directly out of the slice without validation.
132    ///
133    /// This avoids having to validate every element in a slice in order to
134    /// address them.
135    ///
136    /// # Examples
137    ///
138    /// ```
139    /// use musli_zerocopy::{Buf, Error, OwnedBuf};
140    /// use musli_zerocopy::slice::Slice;
141    ///
142    /// fn generic<S>(buf: &Buf, slice: S) -> Result<(), Error>
143    /// where
144    ///     S: Slice<Item = i32>
145    /// {
146    ///     let two = slice.get(2).expect("Missing element 2");
147    ///     assert_eq!(buf.load(two)?, &3);
148    ///
149    ///     assert!(slice.get(4).is_none());
150    ///     Ok(())
151    /// }
152    ///
153    /// let mut buf = OwnedBuf::new();
154    /// let slice = buf.store_slice(&[1, 2, 3, 4]);
155    ///
156    /// generic(&buf, slice)?;
157    /// # Ok::<_, musli_zerocopy::Error>(())
158    /// ```
159    fn get(self, index: usize) -> Option<Self::ItemRef>;
160
161    /// Split the slice at the given position `at`.
162    ///
163    /// # Panics
164    ///
165    /// This panics if the given range is out of bounds.
166    ///
167    /// # Examples
168    ///
169    /// ```
170    /// use musli_zerocopy::{Buf, Error, OwnedBuf};
171    /// use musli_zerocopy::slice::Slice;
172    ///
173    /// fn generic<S>(buf: &Buf, slice: S) -> Result<(), Error>
174    /// where
175    ///     S: Slice<Item = i32>
176    /// {
177    ///     let (a, b) = slice.split_at(3);
178    ///     let (c, d) = slice.split_at(4);
179    ///
180    ///     assert_eq!(buf.load(a)?, &[1, 2, 3]);
181    ///     assert_eq!(buf.load(b)?, &[4]);
182    ///     assert_eq!(buf.load(c)?, &[1, 2, 3, 4]);
183    ///     assert_eq!(buf.load(d)?, &[]);
184    ///     Ok(())
185    /// }
186    ///
187    /// let mut buf = OwnedBuf::new();
188    /// let slice = buf.store_slice(&[1, 2, 3, 4]);
189    ///
190    /// buf.align_in_place();
191    ///
192    /// generic(&buf, slice)?;
193    /// # Ok::<_, musli_zerocopy::Error>(())
194    /// ```
195    fn split_at(self, at: usize) -> (Self, Self);
196
197    /// Get an unchecked reference directly out of the slice without validation.
198    ///
199    /// This avoids having to validate every element in a slice in order to
200    /// address them.
201    ///
202    /// In contrast to [`get()`], this does not check that the index is within
203    /// the bounds of the current slice, all though it's not unsafe since it
204    /// cannot lead to anything inherently unsafe. Only garbled data.
205    ///
206    /// [`get()`]: Slice::get
207    ///
208    /// # Examples
209    ///
210    /// ```
211    /// use musli_zerocopy::{Buf, Error, Ref, OwnedBuf};
212    /// use musli_zerocopy::slice::Slice;
213    ///
214    /// // A method generic over a specific slice implementation.
215    /// fn generic<S>(buf: &Buf, slice: S) -> Result<(), Error>
216    /// where
217    ///     S: Slice<Item = i32>
218    /// {
219    ///     let two = slice.get_unchecked(2);
220    ///     assert_eq!(buf.load(two)?, &3);
221    ///
222    ///     let oob = slice.get_unchecked(4);
223    ///     assert!(buf.load(oob).is_err());
224    ///     Ok(())
225    /// }
226    ///
227    /// let mut buf = OwnedBuf::new();
228    ///
229    /// let slice = buf.store_slice(&[1, 2, 3, 4]);
230    /// generic(&buf, slice)?;
231    /// # Ok::<_, musli_zerocopy::Error>(())
232    /// ```
233    fn get_unchecked(self, index: usize) -> Self::ItemRef;
234
235    /// Get the offset the slice points to.
236    ///
237    /// # Examples
238    ///
239    /// ```
240    /// use musli_zerocopy::Ref;
241    /// use musli_zerocopy::slice::Slice;
242    ///
243    /// // A method generic over a specific slice implementation.
244    /// fn generic<S>(slice: S) where S: Slice {
245    ///     assert_eq!(slice.offset(), 42);
246    /// }
247    ///
248    /// let slice = Ref::<[i32]>::with_metadata(42u32, 2);
249    /// generic(slice);
250    /// ```
251    fn offset(self) -> usize;
252
253    /// Return the number of elements in the slice.
254    ///
255    /// # Examples
256    ///
257    /// ```
258    /// use musli_zerocopy::Ref;
259    /// use musli_zerocopy::slice::Slice;
260    ///
261    /// // A method generic over a specific slice implementation.
262    /// fn generic<S>(slice: S) where S: Slice {
263    ///     assert_eq!(slice.len(), 2);
264    /// }
265    ///
266    /// let slice = Ref::<[i32]>::with_metadata(0u32, 2);
267    /// generic(slice);
268    /// ```
269    fn len(self) -> usize;
270
271    /// Test if the slice is empty.
272    ///
273    /// # Examples
274    ///
275    /// ```
276    /// use musli_zerocopy::Ref;
277    /// use musli_zerocopy::slice::Slice;
278    ///
279    /// // A method generic over a specific slice implementation.
280    /// fn generic<S>(a: S, b: S) where S: Slice {
281    ///     assert!(a.is_empty());
282    ///     assert!(!b.is_empty());
283    /// }
284    ///
285    /// let a = Ref::<[u32]>::with_metadata(0u32, 0);
286    /// let b = Ref::<[u32]>::with_metadata(0u32, 2);
287    /// generic(a, b);
288    /// ```
289    fn is_empty(self) -> bool;
290}
291
292impl<T, A: ByteOrder, B: Size> Slice for Ref<[T], A, B>
293where
294    T: ZeroCopy,
295{
296    type Item = T;
297    type ItemRef = Ref<T, A, B>;
298
299    #[inline]
300    fn from_ref<E, O>(slice: Ref<[T], E, O>) -> Self
301    where
302        T: ZeroCopy,
303        E: ByteOrder,
304        O: Size,
305    {
306        Ref::with_metadata(slice.offset(), slice.len())
307    }
308
309    #[inline]
310    fn try_from_ref<E, O>(slice: Ref<[T], E, O>) -> Result<Self, CoerceError>
311    where
312        T: ZeroCopy,
313        E: ByteOrder,
314        O: Size,
315    {
316        Ref::try_with_metadata(slice.offset(), slice.len())
317    }
318
319    #[inline]
320    fn with_metadata(offset: usize, len: usize) -> Self {
321        Ref::with_metadata(offset, len)
322    }
323
324    #[inline]
325    fn try_with_metadata(offset: usize, len: usize) -> Result<Self, CoerceError> {
326        Ref::try_with_metadata(offset, len)
327    }
328
329    #[inline]
330    fn get(self, index: usize) -> Option<Self::ItemRef> {
331        Ref::get(self, index)
332    }
333
334    #[inline]
335    fn split_at(self, at: usize) -> (Self, Self) {
336        Ref::split_at(self, at)
337    }
338
339    #[inline]
340    fn get_unchecked(self, index: usize) -> Self::ItemRef {
341        Ref::get_unchecked(self, index)
342    }
343
344    #[inline]
345    fn offset(self) -> usize {
346        Ref::<[T], _, _>::offset(self)
347    }
348
349    #[inline]
350    fn len(self) -> usize {
351        Ref::<[T], _, _>::len(self)
352    }
353
354    #[inline]
355    fn is_empty(self) -> bool {
356        Ref::<[T], _, _>::is_empty(self)
357    }
358}