Skip to main content

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, E, O, L> Sealed for Packed<[T], E, O, L>
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<T>
34where
35    Self: Copy + ZeroCopy + Load<Target = [T]> + self::sealed::Sealed,
36{
37    /// A returned reference to an item in a slice.
38    type ItemRef: Load<Target = T>;
39
40    /// Try to construct a slice from a [`Ref<[T]>`].
41    ///
42    /// # Errors
43    ///
44    /// This method errors if construction of the slice would overflow any of
45    /// its parameters.
46    ///
47    /// # Examples
48    ///
49    /// ```
50    /// use musli_zerocopy::{Error, Ref, ZeroCopy};
51    /// use musli_zerocopy::slice::Slice;
52    ///
53    /// fn generic<S, T>(r: Ref<[T]>) -> Result<S, Error>
54    /// where
55    ///     S: Slice<T>,
56    ///     T: ZeroCopy,
57    /// {
58    ///     Ok(S::try_from_ref(r)?)
59    /// }
60    /// ```
61    fn try_from_ref<E, O>(slice: Ref<[T], E, O>) -> Result<Self, CoerceError>
62    where
63        T: ZeroCopy,
64        E: ByteOrder,
65        O: Size;
66
67    /// Construct a slice from its `offset` and `len`.
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::{CoerceError, Ref};
78    /// use musli_zerocopy::slice::Slice;
79    ///
80    /// fn generic<S>() -> Result<S, CoerceError> where S: Slice<u8> {
81    ///     S::try_with_metadata(0usize, 10)
82    /// }
83    /// ```
84    fn try_with_metadata(offset: usize, len: usize) -> Result<Self, CoerceError>;
85
86    /// Try to get a reference directly out of the slice without validation.
87    ///
88    /// This avoids having to validate every element in a slice in order to
89    /// address them.
90    ///
91    /// # Examples
92    ///
93    /// ```
94    /// use musli_zerocopy::{Buf, Error, OwnedBuf};
95    /// use musli_zerocopy::slice::Slice;
96    ///
97    /// fn generic<S>(buf: &Buf, slice: S) -> Result<(), Error>
98    /// where
99    ///     S: Slice<i32>
100    /// {
101    ///     let two = slice.get(2).expect("Missing element 2");
102    ///     assert_eq!(buf.load(two)?, &3);
103    ///
104    ///     assert!(slice.get(4).is_none());
105    ///     Ok(())
106    /// }
107    ///
108    /// let mut buf = OwnedBuf::new();
109    /// let slice = buf.store_slice(&[1, 2, 3, 4])?;
110    ///
111    /// generic(&buf, slice)?;
112    /// # Ok::<_, musli_zerocopy::Error>(())
113    /// ```
114    fn get(self, index: usize) -> Option<Self::ItemRef>;
115
116    /// Split the slice at the given position `at`.
117    ///
118    /// # Panics
119    ///
120    /// This panics if the given range is out of bounds.
121    ///
122    /// # Examples
123    ///
124    /// ```
125    /// use musli_zerocopy::{Buf, Error, OwnedBuf};
126    /// use musli_zerocopy::slice::Slice;
127    ///
128    /// fn generic<S>(buf: &Buf, slice: S) -> Result<(), Error>
129    /// where
130    ///     S: Slice<i32>
131    /// {
132    ///     let (a, b) = slice.split_at(3)?;
133    ///     let (c, d) = slice.split_at(4)?;
134    ///
135    ///     assert_eq!(buf.load(a)?, &[1, 2, 3]);
136    ///     assert_eq!(buf.load(b)?, &[4]);
137    ///     assert_eq!(buf.load(c)?, &[1, 2, 3, 4]);
138    ///     assert_eq!(buf.load(d)?, &[]);
139    ///     Ok(())
140    /// }
141    ///
142    /// let mut buf = OwnedBuf::new();
143    /// let slice = buf.store_slice(&[1, 2, 3, 4])?;
144    ///
145    /// buf.align_in_place()?;
146    ///
147    /// generic(&buf, slice)?;
148    /// # Ok::<_, musli_zerocopy::Error>(())
149    /// ```
150    fn split_at(self, at: usize) -> Result<(Self, Self), CoerceError>;
151
152    /// Get an unchecked reference directly out of the slice without validation.
153    ///
154    /// This avoids having to validate every element in a slice in order to
155    /// address them.
156    ///
157    /// In contrast to [`get()`], this does not check that the index is within
158    /// the bounds of the current slice, all though it's not unsafe since it
159    /// cannot lead to anything inherently unsafe. Only garbled data.
160    ///
161    /// [`get()`]: Slice::get
162    ///
163    /// # Examples
164    ///
165    /// ```
166    /// use musli_zerocopy::{Buf, Error, Ref, OwnedBuf};
167    /// use musli_zerocopy::slice::Slice;
168    ///
169    /// // A method generic over a specific slice implementation.
170    /// fn generic<S>(buf: &Buf, slice: S) -> Result<(), Error>
171    /// where
172    ///     S: Slice<i32>
173    /// {
174    ///     let two = slice.get_unchecked(2);
175    ///     assert_eq!(buf.load(two)?, &3);
176    ///
177    ///     let oob = slice.get_unchecked(4);
178    ///     assert!(buf.load(oob).is_err());
179    ///     Ok(())
180    /// }
181    ///
182    /// let mut buf = OwnedBuf::new();
183    ///
184    /// let slice = buf.store_slice(&[1, 2, 3, 4])?;
185    /// generic(&buf, slice)?;
186    /// # Ok::<_, musli_zerocopy::Error>(())
187    /// ```
188    fn get_unchecked(self, index: usize) -> Self::ItemRef;
189
190    /// Get the offset the slice points to.
191    ///
192    /// # Examples
193    ///
194    /// ```
195    /// use musli_zerocopy::Ref;
196    /// use musli_zerocopy::slice::Slice;
197    ///
198    /// // A method generic over a specific slice implementation.
199    /// fn generic<S>(slice: S) where S: Slice<i32> {
200    ///     assert_eq!(slice.offset(), 42);
201    /// }
202    ///
203    /// let slice = Ref::<[i32]>::with_metadata(42u32, 2);
204    /// generic(slice);
205    /// ```
206    fn offset(self) -> usize;
207
208    /// Return the number of elements in the slice.
209    ///
210    /// # Examples
211    ///
212    /// ```
213    /// use musli_zerocopy::Ref;
214    /// use musli_zerocopy::slice::Slice;
215    ///
216    /// // A method generic over a specific slice implementation.
217    /// fn generic<S>(slice: S) where S: Slice<i32> {
218    ///     assert_eq!(slice.len(), 2);
219    /// }
220    ///
221    /// let slice = Ref::<[i32]>::with_metadata(0u32, 2);
222    /// generic(slice);
223    /// ```
224    fn len(self) -> usize;
225
226    /// Test if the slice is empty.
227    ///
228    /// # Examples
229    ///
230    /// ```
231    /// use musli_zerocopy::Ref;
232    /// use musli_zerocopy::slice::Slice;
233    ///
234    /// // A method generic over a specific slice implementation.
235    /// fn generic<S>(a: S, b: S) where S: Slice<u32> {
236    ///     assert!(a.is_empty());
237    ///     assert!(!b.is_empty());
238    /// }
239    ///
240    /// let a = Ref::<[u32]>::with_metadata(0u32, 0);
241    /// let b = Ref::<[u32]>::with_metadata(0u32, 2);
242    /// generic(a, b);
243    /// ```
244    fn is_empty(self) -> bool;
245}
246
247impl<T, A: ByteOrder, B: Size> Slice<T> for Ref<[T], A, B>
248where
249    T: ZeroCopy,
250{
251    type ItemRef = Ref<T, A, B>;
252
253    #[inline]
254    fn try_from_ref<E, O>(slice: Ref<[T], E, O>) -> Result<Self, CoerceError>
255    where
256        T: ZeroCopy,
257        E: ByteOrder,
258        O: Size,
259    {
260        Ref::try_with_metadata(slice.offset(), slice.len())
261    }
262
263    #[inline]
264    fn try_with_metadata(offset: usize, len: usize) -> Result<Self, CoerceError> {
265        Ref::try_with_metadata(offset, len)
266    }
267
268    #[inline]
269    fn get(self, index: usize) -> Option<Self::ItemRef> {
270        Ref::get(self, index)
271    }
272
273    #[inline]
274    fn split_at(self, at: usize) -> Result<(Self, Self), CoerceError> {
275        Ref::split_at(self, at)
276    }
277
278    #[inline]
279    fn get_unchecked(self, index: usize) -> Self::ItemRef {
280        Ref::get_unchecked(self, index)
281    }
282
283    #[inline]
284    fn offset(self) -> usize {
285        Ref::<[T], _, _>::offset(self)
286    }
287
288    #[inline]
289    fn len(self) -> usize {
290        Ref::<[T], _, _>::len(self)
291    }
292
293    #[inline]
294    fn is_empty(self) -> bool {
295        Ref::<[T], _, _>::is_empty(self)
296    }
297}