• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // This file is part of ICU4X. For terms of use, please see the file
2 // called LICENSE at the top level of the ICU4X source tree
3 // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4 
5 use super::*;
6 use core::cmp::Ordering;
7 use core::ops::Range;
8 
9 /// A zero-copy "slice", i.e. the zero-copy version of `[T]`.
10 ///
11 /// This behaves
12 /// similarly to [`ZeroVec<T>`], however [`ZeroVec<T>`] is allowed to contain
13 /// owned data and as such is ideal for deserialization since most human readable
14 /// serialization formats cannot unconditionally deserialize zero-copy.
15 ///
16 /// This type can be used inside [`VarZeroVec<T>`](crate::VarZeroVec) and [`ZeroMap`](crate::ZeroMap):
17 /// This essentially allows for the construction of zero-copy types isomorphic to `Vec<Vec<T>>` by instead
18 /// using `VarZeroVec<ZeroSlice<T>>`. See the [`VarZeroVec`](crate::VarZeroVec) docs for an example.
19 ///
20 /// # Examples
21 ///
22 /// Const-construct a ZeroSlice of u16:
23 ///
24 /// ```
25 /// use zerovec::ule::AsULE;
26 /// use zerovec::ZeroSlice;
27 ///
28 /// const DATA: &ZeroSlice<u16> =
29 ///     ZeroSlice::<u16>::from_ule_slice(&<u16 as AsULE>::ULE::from_array([
30 ///         211, 281, 421, 32973,
31 ///     ]));
32 ///
33 /// assert_eq!(DATA.get(1), Some(281));
34 /// ```
35 #[repr(transparent)]
36 pub struct ZeroSlice<T: AsULE>([T::ULE]);
37 
38 impl<T> ZeroSlice<T>
39 where
40     T: AsULE,
41 {
42     /// Returns an empty slice.
new_empty() -> &'static Self43     pub const fn new_empty() -> &'static Self {
44         Self::from_ule_slice(&[])
45     }
46 
47     /// Get this [`ZeroSlice`] as a borrowed [`ZeroVec`]
48     ///
49     /// [`ZeroSlice`] does not have most of the methods that [`ZeroVec`] does,
50     /// so it is recommended to convert it to a [`ZeroVec`] before doing anything.
51     #[inline]
as_zerovec(&self) -> ZeroVec<'_, T>52     pub const fn as_zerovec(&self) -> ZeroVec<'_, T> {
53         ZeroVec::new_borrowed(&self.0)
54     }
55 
56     /// Attempt to construct a `&ZeroSlice<T>` from a byte slice, returning an error
57     /// if it's not a valid byte sequence
parse_bytes(bytes: &[u8]) -> Result<&Self, UleError>58     pub fn parse_bytes(bytes: &[u8]) -> Result<&Self, UleError> {
59         T::ULE::parse_bytes_to_slice(bytes).map(Self::from_ule_slice)
60     }
61 
62     /// Uses a `&[u8]` buffer as a `ZeroVec<T>` without any verification.
63     ///
64     /// # Safety
65     ///
66     /// `bytes` need to be an output from [`ZeroSlice::as_bytes()`].
from_bytes_unchecked(bytes: &[u8]) -> &Self67     pub const unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
68         // &[u8] and &[T::ULE] are the same slice with different length metadata.
69         Self::from_ule_slice(core::slice::from_raw_parts(
70             bytes.as_ptr() as *const T::ULE,
71             bytes.len() / core::mem::size_of::<T::ULE>(),
72         ))
73     }
74 
75     /// Construct a `&ZeroSlice<T>` from a slice of ULEs.
76     ///
77     /// This function can be used for constructing ZeroVecs in a const context, avoiding
78     /// parsing checks.
79     ///
80     /// See [`ZeroSlice`] for an example.
81     #[inline]
from_ule_slice(slice: &[T::ULE]) -> &Self82     pub const fn from_ule_slice(slice: &[T::ULE]) -> &Self {
83         // This is safe because ZeroSlice is transparent over [T::ULE]
84         // so &ZeroSlice<T> can be safely cast from &[T::ULE]
85         unsafe { &*(slice as *const _ as *const Self) }
86     }
87 
88     /// Construct a `Box<ZeroSlice<T>>` from a boxed slice of ULEs
89     #[inline]
90     #[cfg(feature = "alloc")]
from_boxed_slice(slice: alloc::boxed::Box<[T::ULE]>) -> alloc::boxed::Box<Self>91     pub fn from_boxed_slice(slice: alloc::boxed::Box<[T::ULE]>) -> alloc::boxed::Box<Self> {
92         // This is safe because ZeroSlice is transparent over [T::ULE]
93         // so Box<ZeroSlice<T>> can be safely cast from Box<[T::ULE]>
94         unsafe { alloc::boxed::Box::from_raw(alloc::boxed::Box::into_raw(slice) as *mut Self) }
95     }
96 
97     /// Returns this slice as its underlying `&[u8]` byte buffer representation.
98     ///
99     /// Useful for serialization.
100     ///
101     /// # Example
102     ///
103     /// ```
104     /// use zerovec::ZeroVec;
105     ///
106     /// // The little-endian bytes correspond to the numbers on the following line.
107     /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x80];
108     /// let nums: &[u16] = &[211, 281, 421, 32973];
109     ///
110     /// let zerovec = ZeroVec::alloc_from_slice(nums);
111     ///
112     /// assert_eq!(bytes, zerovec.as_bytes());
113     /// ```
114     #[inline]
as_bytes(&self) -> &[u8]115     pub fn as_bytes(&self) -> &[u8] {
116         T::ULE::slice_as_bytes(self.as_ule_slice())
117     }
118 
119     /// Dereferences this slice as `&[T::ULE]`.
120     #[inline]
as_ule_slice(&self) -> &[T::ULE]121     pub const fn as_ule_slice(&self) -> &[T::ULE] {
122         &self.0
123     }
124 
125     /// Returns the number of elements in this slice.
126     ///
127     /// # Example
128     ///
129     /// ```
130     /// use zerovec::ule::AsULE;
131     /// use zerovec::ZeroVec;
132     ///
133     /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x80];
134     /// let zerovec: ZeroVec<u16> =
135     ///     ZeroVec::parse_bytes(bytes).expect("infallible");
136     ///
137     /// assert_eq!(4, zerovec.len());
138     /// assert_eq!(
139     ///     bytes.len(),
140     ///     zerovec.len() * std::mem::size_of::<<u16 as AsULE>::ULE>()
141     /// );
142     /// ```
143     #[inline]
len(&self) -> usize144     pub const fn len(&self) -> usize {
145         self.as_ule_slice().len()
146     }
147 
148     /// Returns whether this slice is empty.
149     ///
150     /// # Example
151     ///
152     /// ```
153     /// use zerovec::ZeroVec;
154     ///
155     /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x80];
156     /// let zerovec: ZeroVec<u16> =
157     ///     ZeroVec::parse_bytes(bytes).expect("infallible");
158     /// assert!(!zerovec.is_empty());
159     ///
160     /// let emptyvec: ZeroVec<u16> = ZeroVec::parse_bytes(&[]).expect("infallible");
161     /// assert!(emptyvec.is_empty());
162     /// ```
163     #[inline]
is_empty(&self) -> bool164     pub const fn is_empty(&self) -> bool {
165         self.as_ule_slice().is_empty()
166     }
167 }
168 
169 impl<T> ZeroSlice<T>
170 where
171     T: AsULE,
172 {
173     /// Gets the element at the specified index. Returns `None` if out of range.
174     ///
175     /// # Example
176     ///
177     /// ```
178     /// use zerovec::ZeroVec;
179     ///
180     /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x80];
181     /// let zerovec: ZeroVec<u16> =
182     ///     ZeroVec::parse_bytes(bytes).expect("infallible");
183     ///
184     /// assert_eq!(zerovec.get(2), Some(421));
185     /// assert_eq!(zerovec.get(4), None);
186     /// ```
187     #[inline]
get(&self, index: usize) -> Option<T>188     pub fn get(&self, index: usize) -> Option<T> {
189         self.as_ule_slice()
190             .get(index)
191             .copied()
192             .map(T::from_unaligned)
193     }
194 
195     /// Gets the entire slice as an array of length `N`. Returns `None` if the slice
196     /// does not have exactly `N` elements.
197     ///
198     /// # Example
199     ///
200     /// ```
201     /// use zerovec::ZeroVec;
202     ///
203     /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x80];
204     /// let zerovec: ZeroVec<u16> =
205     ///     ZeroVec::parse_bytes(bytes).expect("infallible");
206     /// let array: [u16; 4] =
207     ///     zerovec.get_as_array().expect("should be 4 items in array");
208     ///
209     /// assert_eq!(array[2], 421);
210     /// ```
get_as_array<const N: usize>(&self) -> Option<[T; N]>211     pub fn get_as_array<const N: usize>(&self) -> Option<[T; N]> {
212         let ule_array = <&[T::ULE; N]>::try_from(self.as_ule_slice()).ok()?;
213         Some(ule_array.map(|u| T::from_unaligned(u)))
214     }
215 
216     /// Gets a subslice of elements within a certain range. Returns `None` if the range
217     /// is out of bounds of this `ZeroSlice`.
218     ///
219     /// # Example
220     ///
221     /// ```
222     /// use zerovec::ZeroVec;
223     ///
224     /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x80];
225     /// let zerovec: ZeroVec<u16> =
226     ///     ZeroVec::parse_bytes(bytes).expect("infallible");
227     ///
228     /// assert_eq!(
229     ///     zerovec.get_subslice(1..3),
230     ///     Some(&*ZeroVec::from_slice_or_alloc(&[0x0119, 0x01A5]))
231     /// );
232     /// assert_eq!(zerovec.get_subslice(3..5), None);
233     /// ```
234     #[inline]
get_subslice(&self, range: Range<usize>) -> Option<&ZeroSlice<T>>235     pub fn get_subslice(&self, range: Range<usize>) -> Option<&ZeroSlice<T>> {
236         self.0.get(range).map(ZeroSlice::from_ule_slice)
237     }
238 
239     /// Get a borrowed reference to the underlying ULE type at a specified index.
240     ///
241     /// Prefer [`Self::get()`] over this method where possible since working
242     /// directly with `ULE` types is less ergonomic
get_ule_ref(&self, index: usize) -> Option<&T::ULE>243     pub fn get_ule_ref(&self, index: usize) -> Option<&T::ULE> {
244         self.as_ule_slice().get(index)
245     }
246 
247     /// Casts a `ZeroSlice<T>` to a compatible `ZeroSlice<P>`.
248     ///
249     /// `T` and `P` are compatible if they have the same `ULE` representation.
250     ///
251     /// If the `ULE`s of `T` and `P` are different, use [`Self::try_as_converted()`].
252     ///
253     /// # Examples
254     ///
255     /// ```
256     /// use zerovec::ZeroSlice;
257     ///
258     /// const BYTES: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x80];
259     /// const ZS_U16: &ZeroSlice<u16> = {
260     ///     match ZeroSlice::<u16>::try_from_bytes(BYTES) {
261     ///         Ok(s) => s,
262     ///         Err(_) => unreachable!(),
263     ///     }
264     /// };
265     ///
266     /// let zs_i16: &ZeroSlice<i16> = ZS_U16.cast();
267     ///
268     /// assert_eq!(ZS_U16.get(3), Some(32973));
269     /// assert_eq!(zs_i16.get(3), Some(-32563));
270     /// ```
271     #[inline]
cast<P>(&self) -> &ZeroSlice<P> where P: AsULE<ULE = T::ULE>,272     pub const fn cast<P>(&self) -> &ZeroSlice<P>
273     where
274         P: AsULE<ULE = T::ULE>,
275     {
276         ZeroSlice::<P>::from_ule_slice(self.as_ule_slice())
277     }
278 
279     /// Converts a `&ZeroSlice<T>` into a `&ZeroSlice<P>`.
280     ///
281     /// The resulting slice will have the same length as the original slice
282     /// if and only if `T::ULE` and `P::ULE` are the same size.
283     ///
284     /// If `T` and `P` have the exact same `ULE`, use [`Self::cast()`].
285     ///
286     /// # Examples
287     ///
288     /// ```
289     /// use zerovec::ZeroSlice;
290     ///
291     /// const BYTES: &[u8] = &[0x7F, 0xF3, 0x01, 0x00, 0x49, 0xF6, 0x01, 0x00];
292     /// const ZS_U32: &ZeroSlice<u32> = {
293     ///     match ZeroSlice::<u32>::try_from_bytes(BYTES) {
294     ///         Ok(s) => s,
295     ///         Err(_) => unreachable!(),
296     ///     }
297     /// };
298     ///
299     /// let zs_u8_4: &ZeroSlice<[u8; 4]> =
300     ///     ZS_U32.try_as_converted().expect("valid code points");
301     ///
302     /// assert_eq!(ZS_U32.get(0), Some(127871));
303     /// assert_eq!(zs_u8_4.get(0), Some([0x7F, 0xF3, 0x01, 0x00]));
304     /// ```
305     #[inline]
try_as_converted<P: AsULE>(&self) -> Result<&ZeroSlice<P>, UleError>306     pub fn try_as_converted<P: AsULE>(&self) -> Result<&ZeroSlice<P>, UleError> {
307         let new_slice = P::ULE::parse_bytes_to_slice(self.as_bytes())?;
308         Ok(ZeroSlice::from_ule_slice(new_slice))
309     }
310 
311     /// Gets the first element. Returns `None` if empty.
312     ///
313     /// # Example
314     ///
315     /// ```
316     /// use zerovec::ZeroVec;
317     ///
318     /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x80];
319     /// let zerovec: ZeroVec<u16> =
320     ///     ZeroVec::parse_bytes(bytes).expect("infallible");
321     ///
322     /// assert_eq!(zerovec.first(), Some(211));
323     /// ```
324     #[inline]
first(&self) -> Option<T>325     pub fn first(&self) -> Option<T> {
326         self.as_ule_slice().first().copied().map(T::from_unaligned)
327     }
328 
329     /// Gets the last element. Returns `None` if empty.
330     ///
331     /// # Example
332     ///
333     /// ```
334     /// use zerovec::ZeroVec;
335     ///
336     /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x80];
337     /// let zerovec: ZeroVec<u16> =
338     ///     ZeroVec::parse_bytes(bytes).expect("infallible");
339     ///
340     /// assert_eq!(zerovec.last(), Some(32973));
341     /// ```
342     #[inline]
last(&self) -> Option<T>343     pub fn last(&self) -> Option<T> {
344         self.as_ule_slice().last().copied().map(T::from_unaligned)
345     }
346 
347     /// Gets an iterator over the elements.
348     ///
349     /// # Example
350     ///
351     /// ```
352     /// use zerovec::ZeroVec;
353     ///
354     /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x80];
355     /// let zerovec: ZeroVec<u16> =
356     ///     ZeroVec::parse_bytes(bytes).expect("infallible");
357     /// let mut it = zerovec.iter();
358     ///
359     /// assert_eq!(it.next(), Some(211));
360     /// assert_eq!(it.next(), Some(281));
361     /// assert_eq!(it.next(), Some(421));
362     /// assert_eq!(it.next(), Some(32973));
363     /// assert_eq!(it.next(), None);
364     /// ```
365     #[inline]
iter<'a>(&'a self) -> ZeroSliceIter<'a, T>366     pub fn iter<'a>(&'a self) -> ZeroSliceIter<'a, T> {
367         ZeroSliceIter(self.as_ule_slice().iter())
368     }
369 
370     /// Returns a tuple with the first element and a subslice of the remaining elements.
371     ///
372     /// # Example
373     ///
374     /// ```
375     /// use zerovec::ule::AsULE;
376     /// use zerovec::ZeroSlice;
377     ///
378     /// const DATA: &ZeroSlice<u16> =
379     ///     ZeroSlice::<u16>::from_ule_slice(&<u16 as AsULE>::ULE::from_array([
380     ///         211, 281, 421, 32973,
381     ///     ]));
382     /// const EXPECTED_VALUE: (u16, &ZeroSlice<u16>) = (
383     ///     211,
384     ///     ZeroSlice::<u16>::from_ule_slice(&<u16 as AsULE>::ULE::from_array([
385     ///         281, 421, 32973,
386     ///     ])),
387     /// );
388     /// assert_eq!(EXPECTED_VALUE, DATA.split_first().unwrap());
389     /// ```
390     #[inline]
split_first(&self) -> Option<(T, &ZeroSlice<T>)>391     pub fn split_first(&self) -> Option<(T, &ZeroSlice<T>)> {
392         if let Some(first) = self.first() {
393             return Some((
394                 first,
395                 // `unwrap()` must succeed, because `first()` returned `Some`.
396                 #[allow(clippy::unwrap_used)]
397                 self.get_subslice(1..self.len()).unwrap(),
398             ));
399         }
400         None
401     }
402 }
403 
404 /// An iterator over elements in a VarZeroVec
405 #[derive(Debug)]
406 pub struct ZeroSliceIter<'a, T: AsULE>(core::slice::Iter<'a, T::ULE>);
407 
408 impl<'a, T: AsULE> Iterator for ZeroSliceIter<'a, T> {
409     type Item = T;
next(&mut self) -> Option<T>410     fn next(&mut self) -> Option<T> {
411         self.0.next().copied().map(T::from_unaligned)
412     }
413 }
414 
415 impl<'a, T: AsULE> ExactSizeIterator for ZeroSliceIter<'a, T> {
len(&self) -> usize416     fn len(&self) -> usize {
417         self.0.len()
418     }
419 }
420 
421 impl<'a, T: AsULE> DoubleEndedIterator for ZeroSliceIter<'a, T> {
next_back(&mut self) -> Option<T>422     fn next_back(&mut self) -> Option<T> {
423         self.0.next_back().copied().map(T::from_unaligned)
424     }
425 }
426 
427 impl<T> ZeroSlice<T>
428 where
429     T: AsULE + Ord,
430 {
431     /// Binary searches a sorted `ZeroVec<T>` for the given element. For more information, see
432     /// the primitive function [`binary_search`].
433     ///
434     /// # Example
435     ///
436     /// ```
437     /// use zerovec::ZeroVec;
438     ///
439     /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x80];
440     /// let zerovec: ZeroVec<u16> =
441     ///     ZeroVec::parse_bytes(bytes).expect("infallible");
442     ///
443     /// assert_eq!(zerovec.binary_search(&281), Ok(1));
444     /// assert_eq!(zerovec.binary_search(&282), Err(2));
445     /// ```
446     ///
447     /// [`binary_search`]: https://doc.rust-lang.org/std/primitive.slice.html#method.binary_search
448     #[inline]
binary_search(&self, x: &T) -> Result<usize, usize>449     pub fn binary_search(&self, x: &T) -> Result<usize, usize> {
450         self.as_ule_slice()
451             .binary_search_by(|probe| T::from_unaligned(*probe).cmp(x))
452     }
453 }
454 
455 impl<T> ZeroSlice<T>
456 where
457     T: AsULE,
458 {
459     /// Binary searches a sorted `ZeroVec<T>` based on a given predicate. For more information, see
460     /// the primitive function [`binary_search_by`].
461     ///
462     /// # Example
463     ///
464     /// ```
465     /// use zerovec::ZeroVec;
466     ///
467     /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x80];
468     /// let zerovec: ZeroVec<u16> =
469     ///     ZeroVec::parse_bytes(bytes).expect("infallible");
470     ///
471     /// assert_eq!(zerovec.binary_search_by(|x| x.cmp(&281)), Ok(1));
472     /// assert_eq!(zerovec.binary_search_by(|x| x.cmp(&282)), Err(2));
473     /// ```
474     ///
475     /// [`binary_search_by`]: https://doc.rust-lang.org/std/primitive.slice.html#method.binary_search_by
476     #[inline]
binary_search_by( &self, mut predicate: impl FnMut(T) -> Ordering, ) -> Result<usize, usize>477     pub fn binary_search_by(
478         &self,
479         mut predicate: impl FnMut(T) -> Ordering,
480     ) -> Result<usize, usize> {
481         self.as_ule_slice()
482             .binary_search_by(|probe| predicate(T::from_unaligned(*probe)))
483     }
484 }
485 
486 // Safety (based on the safety checklist on the VarULE trait):
487 // (`ZeroSlice<T>` is a transparent wrapper around [T::ULE])
488 //  1. [T::ULE] does not include any uninitialized or padding bytes (achieved by being a slice of a ULE type)
489 //  2. [T::ULE] is aligned to 1 byte (achieved by being a slice of a ULE type)
490 //  3. The impl of `validate_bytes()` returns an error if any byte is not valid.
491 //  4. The impl of `validate_bytes()` returns an error if the slice cannot be used in its entirety
492 //  5. The impl of `from_bytes_unchecked()` returns a reference to the same data.
493 //  6. `as_bytes()` and `parse_bytes()` are defaulted
494 //  7. `[T::ULE]` byte equality is semantic equality (relying on the guideline of the underlying `ULE` type)
495 unsafe impl<T: AsULE + 'static> VarULE for ZeroSlice<T> {
496     #[inline]
validate_bytes(bytes: &[u8]) -> Result<(), UleError>497     fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> {
498         T::ULE::validate_bytes(bytes)
499     }
500 
501     #[inline]
from_bytes_unchecked(bytes: &[u8]) -> &Self502     unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
503         Self::from_ule_slice(T::ULE::slice_from_bytes_unchecked(bytes))
504     }
505 }
506 
507 impl<T> Eq for ZeroSlice<T> where T: AsULE + Eq {}
508 
509 impl<T> PartialEq<ZeroSlice<T>> for ZeroSlice<T>
510 where
511     T: AsULE + PartialEq,
512 {
513     #[inline]
eq(&self, other: &ZeroSlice<T>) -> bool514     fn eq(&self, other: &ZeroSlice<T>) -> bool {
515         self.as_zerovec().eq(&other.as_zerovec())
516     }
517 }
518 
519 impl<T> PartialEq<[T]> for ZeroSlice<T>
520 where
521     T: AsULE + PartialEq,
522 {
523     #[inline]
eq(&self, other: &[T]) -> bool524     fn eq(&self, other: &[T]) -> bool {
525         self.iter().eq(other.iter().copied())
526     }
527 }
528 
529 impl<'a, T> PartialEq<ZeroVec<'a, T>> for ZeroSlice<T>
530 where
531     T: AsULE + PartialEq,
532 {
533     #[inline]
eq(&self, other: &ZeroVec<'a, T>) -> bool534     fn eq(&self, other: &ZeroVec<'a, T>) -> bool {
535         self.as_zerovec().eq(other)
536     }
537 }
538 
539 impl<'a, T> PartialEq<ZeroSlice<T>> for ZeroVec<'a, T>
540 where
541     T: AsULE + PartialEq,
542 {
543     #[inline]
eq(&self, other: &ZeroSlice<T>) -> bool544     fn eq(&self, other: &ZeroSlice<T>) -> bool {
545         self.eq(&other.as_zerovec())
546     }
547 }
548 
549 impl<T> fmt::Debug for ZeroSlice<T>
550 where
551     T: AsULE + fmt::Debug,
552 {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result553     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
554         self.as_zerovec().fmt(f)
555     }
556 }
557 
558 impl<T: AsULE + PartialOrd> PartialOrd for ZeroSlice<T> {
partial_cmp(&self, other: &Self) -> Option<Ordering>559     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
560         self.iter().partial_cmp(other.iter())
561     }
562 }
563 
564 impl<T: AsULE + Ord> Ord for ZeroSlice<T> {
cmp(&self, other: &Self) -> Ordering565     fn cmp(&self, other: &Self) -> Ordering {
566         self.iter().cmp(other.iter())
567     }
568 }
569 
570 #[cfg(feature = "alloc")]
571 impl<T: AsULE> AsRef<ZeroSlice<T>> for alloc::vec::Vec<T::ULE> {
as_ref(&self) -> &ZeroSlice<T>572     fn as_ref(&self) -> &ZeroSlice<T> {
573         ZeroSlice::<T>::from_ule_slice(self)
574     }
575 }
576 
577 impl<T: AsULE> AsRef<ZeroSlice<T>> for &[T::ULE] {
as_ref(&self) -> &ZeroSlice<T>578     fn as_ref(&self) -> &ZeroSlice<T> {
579         ZeroSlice::<T>::from_ule_slice(self)
580     }
581 }
582 
583 impl<T> Default for &ZeroSlice<T>
584 where
585     T: AsULE,
586 {
default() -> Self587     fn default() -> Self {
588         ZeroSlice::from_ule_slice(&[])
589     }
590 }
591 
592 #[cfg(test)]
593 mod test {
594     use super::*;
595     use crate::zeroslice;
596 
597     #[test]
test_split_first()598     fn test_split_first() {
599         {
600             // empty slice.
601             assert_eq!(None, ZeroSlice::<u16>::new_empty().split_first());
602         }
603         {
604             // single element slice
605             const DATA: &ZeroSlice<u16> =
606                 zeroslice!(u16; <u16 as AsULE>::ULE::from_unsigned; [211]);
607             assert_eq!((211, zeroslice![]), DATA.split_first().unwrap());
608         }
609         {
610             // slice with many elements.
611             const DATA: &ZeroSlice<u16> =
612                 zeroslice!(u16; <u16 as AsULE>::ULE::from_unsigned; [211, 281, 421, 32973]);
613             const EXPECTED_VALUE: (u16, &ZeroSlice<u16>) = (
614                 211,
615                 zeroslice!(u16; <u16 as AsULE>::ULE::from_unsigned; [281, 421, 32973]),
616             );
617 
618             assert_eq!(EXPECTED_VALUE, DATA.split_first().unwrap());
619         }
620     }
621 }
622