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