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}