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}