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 #[cfg(feature = "databake")] 6 mod databake; 7 8 #[cfg(feature = "serde")] 9 mod serde; 10 11 mod slice; 12 13 pub use slice::ZeroSlice; 14 pub use slice::ZeroSliceIter; 15 16 use crate::ule::*; 17 #[cfg(feature = "alloc")] 18 use alloc::borrow::Cow; 19 #[cfg(feature = "alloc")] 20 use alloc::vec::Vec; 21 use core::cmp::{Ord, Ordering, PartialOrd}; 22 use core::fmt; 23 #[cfg(feature = "alloc")] 24 use core::iter::FromIterator; 25 use core::marker::PhantomData; 26 use core::num::NonZeroUsize; 27 use core::ops::Deref; 28 use core::ptr::NonNull; 29 30 /// A zero-copy, byte-aligned vector for fixed-width types. 31 /// 32 /// `ZeroVec<T>` is designed as a drop-in replacement for `Vec<T>` in situations where it is 33 /// desirable to borrow data from an unaligned byte slice, such as zero-copy deserialization. 34 /// 35 /// `T` must implement [`AsULE`], which is auto-implemented for a number of built-in types, 36 /// including all fixed-width multibyte integers. For variable-width types like [`str`], 37 /// see [`VarZeroVec`](crate::VarZeroVec). [`zerovec::make_ule`](crate::make_ule) may 38 /// be used to automatically implement [`AsULE`] for a type and generate the underlying [`ULE`] type. 39 /// 40 /// Typically, the zero-copy equivalent of a `Vec<T>` will simply be `ZeroVec<'a, T>`. 41 /// 42 /// Most of the methods on `ZeroVec<'a, T>` come from its [`Deref`] implementation to [`ZeroSlice<T>`](ZeroSlice). 43 /// 44 /// For creating zero-copy vectors of fixed-size types, see [`VarZeroVec`](crate::VarZeroVec). 45 /// 46 /// `ZeroVec<T>` behaves much like [`Cow`](alloc::borrow::Cow), where it can be constructed from 47 /// owned data (and then mutated!) but can also borrow from some buffer. 48 /// 49 /// # Example 50 /// 51 /// ``` 52 /// use zerovec::ZeroVec; 53 /// 54 /// // The little-endian bytes correspond to the numbers on the following line. 55 /// let nums: &[u16] = &[211, 281, 421, 461]; 56 /// 57 /// #[derive(serde::Serialize, serde::Deserialize)] 58 /// struct Data<'a> { 59 /// #[serde(borrow)] 60 /// nums: ZeroVec<'a, u16>, 61 /// } 62 /// 63 /// // The owned version will allocate 64 /// let data = Data { 65 /// nums: ZeroVec::alloc_from_slice(nums), 66 /// }; 67 /// let bincode_bytes = 68 /// bincode::serialize(&data).expect("Serialization should be successful"); 69 /// 70 /// // Will deserialize without allocations 71 /// let deserialized: Data = bincode::deserialize(&bincode_bytes) 72 /// .expect("Deserialization should be successful"); 73 /// 74 /// // This deserializes without allocation! 75 /// assert!(!deserialized.nums.is_owned()); 76 /// assert_eq!(deserialized.nums.get(2), Some(421)); 77 /// assert_eq!(deserialized.nums, nums); 78 /// ``` 79 /// 80 /// [`ule`]: crate::ule 81 /// 82 /// # How it Works 83 /// 84 /// `ZeroVec<T>` represents a slice of `T` as a slice of `T::ULE`. The difference between `T` and 85 /// `T::ULE` is that `T::ULE` must be encoded in little-endian with 1-byte alignment. When accessing 86 /// items from `ZeroVec<T>`, we fetch the `T::ULE`, convert it on the fly to `T`, and return `T` by 87 /// value. 88 /// 89 /// Benchmarks can be found in the project repository, with some results found in the [crate-level documentation](crate). 90 /// 91 /// See [the design doc](https://github.com/unicode-org/icu4x/blob/main/utils/zerovec/design_doc.md) for more details. 92 pub struct ZeroVec<'a, T> 93 where 94 T: AsULE, 95 { 96 vector: EyepatchHackVector<T::ULE>, 97 98 /// Marker type, signalling variance and dropck behavior 99 /// by containing all potential types this type represents 100 marker1: PhantomData<T::ULE>, 101 marker2: PhantomData<&'a T::ULE>, 102 } 103 104 // Send inherits as long as all fields are Send, but also references are Send only 105 // when their contents are Sync (this is the core purpose of Sync), so 106 // we need a Send+Sync bound since this struct can logically be a vector or a slice. 107 unsafe impl<'a, T: AsULE> Send for ZeroVec<'a, T> where T::ULE: Send + Sync {} 108 // Sync typically inherits as long as all fields are Sync 109 unsafe impl<'a, T: AsULE> Sync for ZeroVec<'a, T> where T::ULE: Sync {} 110 111 impl<'a, T: AsULE> Deref for ZeroVec<'a, T> { 112 type Target = ZeroSlice<T>; 113 #[inline] deref(&self) -> &Self::Target114 fn deref(&self) -> &Self::Target { 115 self.as_slice() 116 } 117 } 118 119 // Represents an unsafe potentially-owned vector/slice type, without a lifetime 120 // working around dropck limitations. 121 // 122 // Must either be constructed by deconstructing a Vec<U>, or from &[U] with capacity set to 123 // zero. Should not outlive its source &[U] in the borrowed case; this type does not in 124 // and of itself uphold this guarantee, but the .as_slice() method assumes it. 125 // 126 // After https://github.com/rust-lang/rust/issues/34761 stabilizes, 127 // we should remove this type and use #[may_dangle] 128 struct EyepatchHackVector<U> { 129 /// Pointer to data 130 /// This pointer is *always* valid, the reason it is represented as a raw pointer 131 /// is that it may logically represent an `&[T::ULE]` or the ptr,len of a `Vec<T::ULE>` 132 buf: NonNull<[U]>, 133 #[cfg(feature = "alloc")] 134 /// Borrowed if zero. Capacity of buffer above if not 135 capacity: usize, 136 } 137 138 impl<U> EyepatchHackVector<U> { 139 // Return a slice to the inner data for an arbitrary caller-specified lifetime 140 #[inline] as_arbitrary_slice<'a>(&self) -> &'a [U]141 unsafe fn as_arbitrary_slice<'a>(&self) -> &'a [U] { 142 self.buf.as_ref() 143 } 144 // Return a slice to the inner data 145 #[inline] as_slice<'a>(&'a self) -> &'a [U]146 const fn as_slice<'a>(&'a self) -> &'a [U] { 147 // Note: self.buf.as_ref() is not const until 1.73 148 unsafe { &*(self.buf.as_ptr() as *const [U]) } 149 } 150 151 /// Return this type as a vector 152 /// 153 /// Data MUST be known to be owned beforehand 154 /// 155 /// Because this borrows self, this is effectively creating two owners to the same 156 /// data, make sure that `self` is cleaned up after this 157 /// 158 /// (this does not simply take `self` since then it wouldn't be usable from the Drop impl) 159 #[cfg(feature = "alloc")] get_vec(&self) -> Vec<U>160 unsafe fn get_vec(&self) -> Vec<U> { 161 debug_assert!(self.capacity != 0); 162 let slice: &[U] = self.as_slice(); 163 let len = slice.len(); 164 // Safety: we are assuming owned, and in owned cases 165 // this always represents a valid vector 166 Vec::from_raw_parts(self.buf.as_ptr() as *mut U, len, self.capacity) 167 } 168 } 169 170 #[cfg(feature = "alloc")] 171 impl<U> Drop for EyepatchHackVector<U> { 172 #[inline] drop(&mut self)173 fn drop(&mut self) { 174 if self.capacity != 0 { 175 unsafe { 176 // we don't need to clean up self here since we're already in a Drop impl 177 let _ = self.get_vec(); 178 } 179 } 180 } 181 } 182 183 impl<'a, T: AsULE> Clone for ZeroVec<'a, T> { clone(&self) -> Self184 fn clone(&self) -> Self { 185 #[cfg(feature = "alloc")] 186 if self.is_owned() { 187 return ZeroVec::new_owned(self.as_ule_slice().into()); 188 } 189 Self { 190 vector: EyepatchHackVector { 191 buf: self.vector.buf, 192 #[cfg(feature = "alloc")] 193 capacity: 0, 194 }, 195 marker1: PhantomData, 196 marker2: PhantomData, 197 } 198 } 199 } 200 201 impl<'a, T: AsULE> AsRef<ZeroSlice<T>> for ZeroVec<'a, T> { as_ref(&self) -> &ZeroSlice<T>202 fn as_ref(&self) -> &ZeroSlice<T> { 203 self.as_slice() 204 } 205 } 206 207 impl<T> fmt::Debug for ZeroVec<'_, T> 208 where 209 T: AsULE + fmt::Debug, 210 { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result211 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 212 write!(f, "ZeroVec([")?; 213 let mut first = true; 214 for el in self.iter() { 215 if !first { 216 write!(f, ", ")?; 217 } 218 write!(f, "{el:?}")?; 219 first = false; 220 } 221 write!(f, "])") 222 } 223 } 224 225 impl<T> Eq for ZeroVec<'_, T> where T: AsULE + Eq {} 226 227 impl<'a, 'b, T> PartialEq<ZeroVec<'b, T>> for ZeroVec<'a, T> 228 where 229 T: AsULE + PartialEq, 230 { 231 #[inline] eq(&self, other: &ZeroVec<'b, T>) -> bool232 fn eq(&self, other: &ZeroVec<'b, T>) -> bool { 233 // Note: T implements PartialEq but not T::ULE 234 self.iter().eq(other.iter()) 235 } 236 } 237 238 impl<T> PartialEq<&[T]> for ZeroVec<'_, T> 239 where 240 T: AsULE + PartialEq, 241 { 242 #[inline] eq(&self, other: &&[T]) -> bool243 fn eq(&self, other: &&[T]) -> bool { 244 self.iter().eq(other.iter().copied()) 245 } 246 } 247 248 impl<T, const N: usize> PartialEq<[T; N]> for ZeroVec<'_, T> 249 where 250 T: AsULE + PartialEq, 251 { 252 #[inline] eq(&self, other: &[T; N]) -> bool253 fn eq(&self, other: &[T; N]) -> bool { 254 self.iter().eq(other.iter().copied()) 255 } 256 } 257 258 impl<'a, T: AsULE> Default for ZeroVec<'a, T> { 259 #[inline] default() -> Self260 fn default() -> Self { 261 Self::new() 262 } 263 } 264 265 impl<'a, T: AsULE + PartialOrd> PartialOrd for ZeroVec<'a, T> { partial_cmp(&self, other: &Self) -> Option<Ordering>266 fn partial_cmp(&self, other: &Self) -> Option<Ordering> { 267 self.iter().partial_cmp(other.iter()) 268 } 269 } 270 271 impl<'a, T: AsULE + Ord> Ord for ZeroVec<'a, T> { cmp(&self, other: &Self) -> Ordering272 fn cmp(&self, other: &Self) -> Ordering { 273 self.iter().cmp(other.iter()) 274 } 275 } 276 277 impl<'a, T: AsULE> AsRef<[T::ULE]> for ZeroVec<'a, T> { as_ref(&self) -> &[T::ULE]278 fn as_ref(&self) -> &[T::ULE] { 279 self.as_ule_slice() 280 } 281 } 282 283 impl<'a, T: AsULE> From<&'a [T::ULE]> for ZeroVec<'a, T> { from(other: &'a [T::ULE]) -> Self284 fn from(other: &'a [T::ULE]) -> Self { 285 ZeroVec::new_borrowed(other) 286 } 287 } 288 289 #[cfg(feature = "alloc")] 290 impl<'a, T: AsULE> From<Vec<T::ULE>> for ZeroVec<'a, T> { from(other: Vec<T::ULE>) -> Self291 fn from(other: Vec<T::ULE>) -> Self { 292 ZeroVec::new_owned(other) 293 } 294 } 295 296 impl<'a, T: AsULE> ZeroVec<'a, T> { 297 /// Creates a new, borrowed, empty `ZeroVec<T>`. 298 /// 299 /// # Examples 300 /// 301 /// ``` 302 /// use zerovec::ZeroVec; 303 /// 304 /// let zv: ZeroVec<u16> = ZeroVec::new(); 305 /// assert!(zv.is_empty()); 306 /// ``` 307 #[inline] new() -> Self308 pub const fn new() -> Self { 309 Self::new_borrowed(&[]) 310 } 311 312 /// Same as `ZeroSlice::len`, which is available through `Deref` and not `const`. const_len(&self) -> usize313 pub const fn const_len(&self) -> usize { 314 self.vector.as_slice().len() 315 } 316 317 /// Creates a new owned `ZeroVec` using an existing 318 /// allocated backing buffer 319 /// 320 /// If you have a slice of `&[T]`s, prefer using 321 /// [`Self::alloc_from_slice()`]. 322 #[inline] 323 #[cfg(feature = "alloc")] new_owned(vec: Vec<T::ULE>) -> Self324 pub fn new_owned(vec: Vec<T::ULE>) -> Self { 325 // Deconstruct the vector into parts 326 // This is the only part of the code that goes from Vec 327 // to ZeroVec, all other such operations should use this function 328 let capacity = vec.capacity(); 329 let len = vec.len(); 330 let ptr = core::mem::ManuallyDrop::new(vec).as_mut_ptr(); 331 // Safety: `ptr` comes from Vec::as_mut_ptr, which says: 332 // "Returns an unsafe mutable pointer to the vector’s buffer, 333 // or a dangling raw pointer valid for zero sized reads" 334 let ptr = unsafe { NonNull::new_unchecked(ptr) }; 335 let buf = NonNull::slice_from_raw_parts(ptr, len); 336 Self { 337 vector: EyepatchHackVector { buf, capacity }, 338 marker1: PhantomData, 339 marker2: PhantomData, 340 } 341 } 342 343 /// Creates a new borrowed `ZeroVec` using an existing 344 /// backing buffer 345 #[inline] new_borrowed(slice: &'a [T::ULE]) -> Self346 pub const fn new_borrowed(slice: &'a [T::ULE]) -> Self { 347 // Safety: references in Rust cannot be null. 348 // The safe function `impl From<&T> for NonNull<T>` is not const. 349 let slice = unsafe { NonNull::new_unchecked(slice as *const [_] as *mut [_]) }; 350 Self { 351 vector: EyepatchHackVector { 352 buf: slice, 353 #[cfg(feature = "alloc")] 354 capacity: 0, 355 }, 356 marker1: PhantomData, 357 marker2: PhantomData, 358 } 359 } 360 361 /// Creates a new, owned, empty `ZeroVec<T>`, with a certain capacity pre-allocated. 362 #[cfg(feature = "alloc")] with_capacity(capacity: usize) -> Self363 pub fn with_capacity(capacity: usize) -> Self { 364 Self::new_owned(Vec::with_capacity(capacity)) 365 } 366 367 /// Parses a `&[u8]` buffer into a `ZeroVec<T>`. 368 /// 369 /// This function is infallible for built-in integer types, but fallible for other types, 370 /// such as `char`. For more information, see [`ULE::parse_bytes_to_slice`]. 371 /// 372 /// The bytes within the byte buffer must remain constant for the life of the ZeroVec. 373 /// 374 /// # Endianness 375 /// 376 /// The byte buffer must be encoded in little-endian, even if running in a big-endian 377 /// environment. This ensures a consistent representation of data across platforms. 378 /// 379 /// # Example 380 /// 381 /// ``` 382 /// use zerovec::ZeroVec; 383 /// 384 /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x01]; 385 /// let zerovec: ZeroVec<u16> = 386 /// ZeroVec::parse_bytes(bytes).expect("infallible"); 387 /// 388 /// assert!(!zerovec.is_owned()); 389 /// assert_eq!(zerovec.get(2), Some(421)); 390 /// ``` parse_bytes(bytes: &'a [u8]) -> Result<Self, UleError>391 pub fn parse_bytes(bytes: &'a [u8]) -> Result<Self, UleError> { 392 let slice: &'a [T::ULE] = T::ULE::parse_bytes_to_slice(bytes)?; 393 Ok(Self::new_borrowed(slice)) 394 } 395 396 /// Uses a `&[u8]` buffer as a `ZeroVec<T>` without any verification. 397 /// 398 /// # Safety 399 /// 400 /// `bytes` need to be an output from [`ZeroSlice::as_bytes()`]. from_bytes_unchecked(bytes: &'a [u8]) -> Self401 pub const unsafe fn from_bytes_unchecked(bytes: &'a [u8]) -> Self { 402 // &[u8] and &[T::ULE] are the same slice with different length metadata. 403 Self::new_borrowed(core::slice::from_raw_parts( 404 bytes.as_ptr() as *const T::ULE, 405 bytes.len() / core::mem::size_of::<T::ULE>(), 406 )) 407 } 408 409 /// Converts a `ZeroVec<T>` into a `ZeroVec<u8>`, retaining the current ownership model. 410 /// 411 /// Note that the length of the ZeroVec may change. 412 /// 413 /// # Examples 414 /// 415 /// Convert a borrowed `ZeroVec`: 416 /// 417 /// ``` 418 /// use zerovec::ZeroVec; 419 /// 420 /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x01]; 421 /// let zerovec: ZeroVec<u16> = 422 /// ZeroVec::parse_bytes(bytes).expect("infallible"); 423 /// let zv_bytes = zerovec.into_bytes(); 424 /// 425 /// assert!(!zv_bytes.is_owned()); 426 /// assert_eq!(zv_bytes.get(0), Some(0xD3)); 427 /// ``` 428 /// 429 /// Convert an owned `ZeroVec`: 430 /// 431 /// ``` 432 /// use zerovec::ZeroVec; 433 /// 434 /// let nums: &[u16] = &[211, 281, 421, 461]; 435 /// let zerovec = ZeroVec::alloc_from_slice(nums); 436 /// let zv_bytes = zerovec.into_bytes(); 437 /// 438 /// assert!(zv_bytes.is_owned()); 439 /// assert_eq!(zv_bytes.get(0), Some(0xD3)); 440 /// ``` 441 #[cfg(feature = "alloc")] into_bytes(self) -> ZeroVec<'a, u8>442 pub fn into_bytes(self) -> ZeroVec<'a, u8> { 443 use alloc::borrow::Cow; 444 match self.into_cow() { 445 Cow::Borrowed(slice) => { 446 let bytes: &'a [u8] = T::ULE::slice_as_bytes(slice); 447 ZeroVec::new_borrowed(bytes) 448 } 449 Cow::Owned(vec) => { 450 let bytes = Vec::from(T::ULE::slice_as_bytes(&vec)); 451 ZeroVec::new_owned(bytes) 452 } 453 } 454 } 455 456 /// Returns this [`ZeroVec`] as a [`ZeroSlice`]. 457 /// 458 /// To get a reference with a longer lifetime from a borrowed [`ZeroVec`], 459 /// use [`ZeroVec::as_maybe_borrowed`]. 460 #[inline] as_slice(&self) -> &ZeroSlice<T>461 pub const fn as_slice(&self) -> &ZeroSlice<T> { 462 let slice: &[T::ULE] = self.vector.as_slice(); 463 ZeroSlice::from_ule_slice(slice) 464 } 465 466 /// Casts a `ZeroVec<T>` to a compatible `ZeroVec<P>`. 467 /// 468 /// `T` and `P` are compatible if they have the same `ULE` representation. 469 /// 470 /// If the `ULE`s of `T` and `P` are different types but have the same size, 471 /// use [`Self::try_into_converted()`]. 472 /// 473 /// # Examples 474 /// 475 /// ``` 476 /// use zerovec::ZeroVec; 477 /// 478 /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x80]; 479 /// 480 /// let zerovec_u16: ZeroVec<u16> = 481 /// ZeroVec::parse_bytes(bytes).expect("infallible"); 482 /// assert_eq!(zerovec_u16.get(3), Some(32973)); 483 /// 484 /// let zerovec_i16: ZeroVec<i16> = zerovec_u16.cast(); 485 /// assert_eq!(zerovec_i16.get(3), Some(-32563)); 486 /// ``` 487 #[cfg(feature = "alloc")] cast<P>(self) -> ZeroVec<'a, P> where P: AsULE<ULE = T::ULE>,488 pub fn cast<P>(self) -> ZeroVec<'a, P> 489 where 490 P: AsULE<ULE = T::ULE>, 491 { 492 match self.into_cow() { 493 Cow::Owned(v) => ZeroVec::new_owned(v), 494 Cow::Borrowed(v) => ZeroVec::new_borrowed(v), 495 } 496 } 497 498 /// Converts a `ZeroVec<T>` into a `ZeroVec<P>`, retaining the current ownership model. 499 /// 500 /// If `T` and `P` have the exact same `ULE`, use [`Self::cast()`]. 501 /// 502 /// # Panics 503 /// 504 /// Panics if `T::ULE` and `P::ULE` are not the same size. 505 /// 506 /// # Examples 507 /// 508 /// Convert a borrowed `ZeroVec`: 509 /// 510 /// ``` 511 /// use zerovec::ZeroVec; 512 /// 513 /// let bytes: &[u8] = &[0x7F, 0xF3, 0x01, 0x49, 0xF6, 0x01]; 514 /// let zv_char: ZeroVec<char> = 515 /// ZeroVec::parse_bytes(bytes).expect("valid code points"); 516 /// let zv_u8_3: ZeroVec<[u8; 3]> = 517 /// zv_char.try_into_converted().expect("infallible conversion"); 518 /// 519 /// assert!(!zv_u8_3.is_owned()); 520 /// assert_eq!(zv_u8_3.get(0), Some([0x7F, 0xF3, 0x01])); 521 /// ``` 522 /// 523 /// Convert an owned `ZeroVec`: 524 /// 525 /// ``` 526 /// use zerovec::ZeroVec; 527 /// 528 /// let chars: &[char] = &['', '']; 529 /// let zv_char = ZeroVec::alloc_from_slice(chars); 530 /// let zv_u8_3: ZeroVec<[u8; 3]> = 531 /// zv_char.try_into_converted().expect("length is divisible"); 532 /// 533 /// assert!(zv_u8_3.is_owned()); 534 /// assert_eq!(zv_u8_3.get(0), Some([0x7F, 0xF3, 0x01])); 535 /// ``` 536 /// 537 /// If the types are not the same size, we refuse to convert: 538 /// 539 /// ```should_panic 540 /// use zerovec::ZeroVec; 541 /// 542 /// let bytes: &[u8] = &[0x7F, 0xF3, 0x01, 0x49, 0xF6, 0x01]; 543 /// let zv_char: ZeroVec<char> = 544 /// ZeroVec::parse_bytes(bytes).expect("valid code points"); 545 /// 546 /// // Panics! core::mem::size_of::<char::ULE> != core::mem::size_of::<u16::ULE> 547 /// zv_char.try_into_converted::<u16>(); 548 /// ``` 549 /// 550 /// Instead, convert to bytes and then parse: 551 /// 552 /// ``` 553 /// use zerovec::ZeroVec; 554 /// 555 /// let bytes: &[u8] = &[0x7F, 0xF3, 0x01, 0x49, 0xF6, 0x01]; 556 /// let zv_char: ZeroVec<char> = 557 /// ZeroVec::parse_bytes(bytes).expect("valid code points"); 558 /// let zv_u16: ZeroVec<u16> = 559 /// zv_char.into_bytes().try_into_parsed().expect("infallible"); 560 /// 561 /// assert!(!zv_u16.is_owned()); 562 /// assert_eq!(zv_u16.get(0), Some(0xF37F)); 563 /// ``` 564 #[cfg(feature = "alloc")] try_into_converted<P: AsULE>(self) -> Result<ZeroVec<'a, P>, UleError>565 pub fn try_into_converted<P: AsULE>(self) -> Result<ZeroVec<'a, P>, UleError> { 566 assert_eq!( 567 core::mem::size_of::<<T as AsULE>::ULE>(), 568 core::mem::size_of::<<P as AsULE>::ULE>() 569 ); 570 match self.into_cow() { 571 Cow::Borrowed(old_slice) => { 572 let bytes: &'a [u8] = T::ULE::slice_as_bytes(old_slice); 573 let new_slice = P::ULE::parse_bytes_to_slice(bytes)?; 574 Ok(ZeroVec::new_borrowed(new_slice)) 575 } 576 Cow::Owned(old_vec) => { 577 let bytes: &[u8] = T::ULE::slice_as_bytes(&old_vec); 578 P::ULE::validate_bytes(bytes)?; 579 // Feature "vec_into_raw_parts" is not yet stable (#65816). Polyfill: 580 let (ptr, len, cap) = { 581 // Take ownership of the pointer 582 let mut v = core::mem::ManuallyDrop::new(old_vec); 583 // Fetch the pointer, length, and capacity 584 (v.as_mut_ptr(), v.len(), v.capacity()) 585 }; 586 // Safety checklist for Vec::from_raw_parts: 587 // 1. ptr came from a Vec<T> 588 // 2. P and T are asserted above to be the same size 589 // 3. length is what it was before 590 // 4. capacity is what it was before 591 let new_vec = unsafe { 592 let ptr = ptr as *mut P::ULE; 593 Vec::from_raw_parts(ptr, len, cap) 594 }; 595 Ok(ZeroVec::new_owned(new_vec)) 596 } 597 } 598 } 599 600 /// Check if this type is fully owned 601 #[inline] is_owned(&self) -> bool602 pub fn is_owned(&self) -> bool { 603 #[cfg(feature = "alloc")] 604 return self.vector.capacity != 0; 605 #[cfg(not(feature = "alloc"))] 606 return false; 607 } 608 609 /// If this is a borrowed [`ZeroVec`], return it as a slice that covers 610 /// its lifetime parameter. 611 /// 612 /// To infallibly get a [`ZeroSlice`] with a shorter lifetime, use 613 /// [`ZeroVec::as_slice`]. 614 #[inline] as_maybe_borrowed(&self) -> Option<&'a ZeroSlice<T>>615 pub fn as_maybe_borrowed(&self) -> Option<&'a ZeroSlice<T>> { 616 if self.is_owned() { 617 None 618 } else { 619 // We can extend the lifetime of the slice to 'a 620 // since we know it is borrowed 621 let ule_slice = unsafe { self.vector.as_arbitrary_slice() }; 622 Some(ZeroSlice::from_ule_slice(ule_slice)) 623 } 624 } 625 626 /// If the ZeroVec is owned, returns the capacity of the vector. 627 /// 628 /// Otherwise, if the ZeroVec is borrowed, returns `None`. 629 /// 630 /// # Examples 631 /// 632 /// ``` 633 /// use zerovec::ZeroVec; 634 /// 635 /// let mut zv = ZeroVec::<u8>::new_borrowed(&[0, 1, 2, 3]); 636 /// assert!(!zv.is_owned()); 637 /// assert_eq!(zv.owned_capacity(), None); 638 /// 639 /// // Convert to owned without appending anything 640 /// zv.with_mut(|v| ()); 641 /// assert!(zv.is_owned()); 642 /// assert_eq!(zv.owned_capacity(), Some(4.try_into().unwrap())); 643 /// 644 /// // Double the size by appending 645 /// zv.with_mut(|v| v.push(0)); 646 /// assert!(zv.is_owned()); 647 /// assert_eq!(zv.owned_capacity(), Some(8.try_into().unwrap())); 648 /// ``` 649 #[inline] owned_capacity(&self) -> Option<NonZeroUsize>650 pub fn owned_capacity(&self) -> Option<NonZeroUsize> { 651 #[cfg(feature = "alloc")] 652 return NonZeroUsize::try_from(self.vector.capacity).ok(); 653 #[cfg(not(feature = "alloc"))] 654 return None; 655 } 656 } 657 658 impl<'a> ZeroVec<'a, u8> { 659 /// Converts a `ZeroVec<u8>` into a `ZeroVec<T>`, retaining the current ownership model. 660 /// 661 /// Note that the length of the ZeroVec may change. 662 /// 663 /// # Examples 664 /// 665 /// Convert a borrowed `ZeroVec`: 666 /// 667 /// ``` 668 /// use zerovec::ZeroVec; 669 /// 670 /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x01]; 671 /// let zv_bytes = ZeroVec::new_borrowed(bytes); 672 /// let zerovec: ZeroVec<u16> = zv_bytes.try_into_parsed().expect("infallible"); 673 /// 674 /// assert!(!zerovec.is_owned()); 675 /// assert_eq!(zerovec.get(0), Some(211)); 676 /// ``` 677 /// 678 /// Convert an owned `ZeroVec`: 679 /// 680 /// ``` 681 /// use zerovec::ZeroVec; 682 /// 683 /// let bytes: Vec<u8> = vec![0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x01]; 684 /// let zv_bytes = ZeroVec::new_owned(bytes); 685 /// let zerovec: ZeroVec<u16> = zv_bytes.try_into_parsed().expect("infallible"); 686 /// 687 /// assert!(zerovec.is_owned()); 688 /// assert_eq!(zerovec.get(0), Some(211)); 689 /// ``` 690 #[cfg(feature = "alloc")] try_into_parsed<T: AsULE>(self) -> Result<ZeroVec<'a, T>, UleError>691 pub fn try_into_parsed<T: AsULE>(self) -> Result<ZeroVec<'a, T>, UleError> { 692 match self.into_cow() { 693 Cow::Borrowed(bytes) => { 694 let slice: &'a [T::ULE] = T::ULE::parse_bytes_to_slice(bytes)?; 695 Ok(ZeroVec::new_borrowed(slice)) 696 } 697 Cow::Owned(vec) => { 698 let slice = Vec::from(T::ULE::parse_bytes_to_slice(&vec)?); 699 Ok(ZeroVec::new_owned(slice)) 700 } 701 } 702 } 703 } 704 705 impl<'a, T> ZeroVec<'a, T> 706 where 707 T: AsULE, 708 { 709 /// Creates a `ZeroVec<T>` from a `&[T]` by allocating memory. 710 /// 711 /// This function results in an `Owned` instance of `ZeroVec<T>`. 712 /// 713 /// # Example 714 /// 715 /// ``` 716 /// use zerovec::ZeroVec; 717 /// 718 /// // The little-endian bytes correspond to the numbers on the following line. 719 /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x01]; 720 /// let nums: &[u16] = &[211, 281, 421, 461]; 721 /// 722 /// let zerovec = ZeroVec::alloc_from_slice(nums); 723 /// 724 /// assert!(zerovec.is_owned()); 725 /// assert_eq!(bytes, zerovec.as_bytes()); 726 /// ``` 727 #[inline] 728 #[cfg(feature = "alloc")] alloc_from_slice(other: &[T]) -> Self729 pub fn alloc_from_slice(other: &[T]) -> Self { 730 Self::new_owned(other.iter().copied().map(T::to_unaligned).collect()) 731 } 732 733 /// Creates a `Vec<T>` from a `ZeroVec<T>`. 734 /// 735 /// # Example 736 /// 737 /// ``` 738 /// use zerovec::ZeroVec; 739 /// 740 /// let nums: &[u16] = &[211, 281, 421, 461]; 741 /// let vec: Vec<u16> = ZeroVec::alloc_from_slice(nums).to_vec(); 742 /// 743 /// assert_eq!(nums, vec.as_slice()); 744 /// ``` 745 #[inline] 746 #[cfg(feature = "alloc")] to_vec(&self) -> Vec<T>747 pub fn to_vec(&self) -> Vec<T> { 748 self.iter().collect() 749 } 750 } 751 752 impl<'a, T> ZeroVec<'a, T> 753 where 754 T: EqULE, 755 { 756 /// Attempts to create a `ZeroVec<'a, T>` from a `&'a [T]` by borrowing the argument. 757 /// 758 /// If this is not possible, such as on a big-endian platform, `None` is returned. 759 /// 760 /// # Example 761 /// 762 /// ``` 763 /// use zerovec::ZeroVec; 764 /// 765 /// // The little-endian bytes correspond to the numbers on the following line. 766 /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x01]; 767 /// let nums: &[u16] = &[211, 281, 421, 461]; 768 /// 769 /// if let Some(zerovec) = ZeroVec::try_from_slice(nums) { 770 /// assert!(!zerovec.is_owned()); 771 /// assert_eq!(bytes, zerovec.as_bytes()); 772 /// } 773 /// ``` 774 #[inline] try_from_slice(slice: &'a [T]) -> Option<Self>775 pub fn try_from_slice(slice: &'a [T]) -> Option<Self> { 776 T::slice_to_unaligned(slice).map(|ule_slice| Self::new_borrowed(ule_slice)) 777 } 778 779 /// Creates a `ZeroVec<'a, T>` from a `&'a [T]`, either by borrowing the argument or by 780 /// allocating a new vector. 781 /// 782 /// This is a cheap operation on little-endian platforms, falling back to a more expensive 783 /// operation on big-endian platforms. 784 /// 785 /// # Example 786 /// 787 /// ``` 788 /// use zerovec::ZeroVec; 789 /// 790 /// // The little-endian bytes correspond to the numbers on the following line. 791 /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x01]; 792 /// let nums: &[u16] = &[211, 281, 421, 461]; 793 /// 794 /// let zerovec = ZeroVec::from_slice_or_alloc(nums); 795 /// 796 /// // Note: zerovec could be either borrowed or owned. 797 /// assert_eq!(bytes, zerovec.as_bytes()); 798 /// ``` 799 #[inline] 800 #[cfg(feature = "alloc")] from_slice_or_alloc(slice: &'a [T]) -> Self801 pub fn from_slice_or_alloc(slice: &'a [T]) -> Self { 802 Self::try_from_slice(slice).unwrap_or_else(|| Self::alloc_from_slice(slice)) 803 } 804 } 805 806 impl<'a, T> ZeroVec<'a, T> 807 where 808 T: AsULE, 809 { 810 /// Mutates each element according to a given function, meant to be 811 /// a more convenient version of calling `.iter_mut()` with 812 /// [`ZeroVec::with_mut()`] which serves fewer use cases. 813 /// 814 /// This will convert the ZeroVec into an owned ZeroVec if not already the case. 815 /// 816 /// # Example 817 /// 818 /// ``` 819 /// use zerovec::ZeroVec; 820 /// 821 /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x01]; 822 /// let mut zerovec: ZeroVec<u16> = 823 /// ZeroVec::parse_bytes(bytes).expect("infallible"); 824 /// 825 /// zerovec.for_each_mut(|item| *item += 1); 826 /// 827 /// assert_eq!(zerovec.to_vec(), &[212, 282, 422, 462]); 828 /// assert!(zerovec.is_owned()); 829 /// ``` 830 #[inline] 831 #[cfg(feature = "alloc")] for_each_mut(&mut self, mut f: impl FnMut(&mut T))832 pub fn for_each_mut(&mut self, mut f: impl FnMut(&mut T)) { 833 self.to_mut_slice().iter_mut().for_each(|item| { 834 let mut aligned = T::from_unaligned(*item); 835 f(&mut aligned); 836 *item = aligned.to_unaligned() 837 }) 838 } 839 840 /// Same as [`ZeroVec::for_each_mut()`], but bubbles up errors. 841 /// 842 /// # Example 843 /// 844 /// ``` 845 /// use zerovec::ZeroVec; 846 /// 847 /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x01]; 848 /// let mut zerovec: ZeroVec<u16> = 849 /// ZeroVec::parse_bytes(bytes).expect("infallible"); 850 /// 851 /// zerovec.try_for_each_mut(|item| { 852 /// *item = item.checked_add(1).ok_or(())?; 853 /// Ok(()) 854 /// })?; 855 /// 856 /// assert_eq!(zerovec.to_vec(), &[212, 282, 422, 462]); 857 /// assert!(zerovec.is_owned()); 858 /// # Ok::<(), ()>(()) 859 /// ``` 860 #[inline] 861 #[cfg(feature = "alloc")] try_for_each_mut<E>( &mut self, mut f: impl FnMut(&mut T) -> Result<(), E>, ) -> Result<(), E>862 pub fn try_for_each_mut<E>( 863 &mut self, 864 mut f: impl FnMut(&mut T) -> Result<(), E>, 865 ) -> Result<(), E> { 866 self.to_mut_slice().iter_mut().try_for_each(|item| { 867 let mut aligned = T::from_unaligned(*item); 868 f(&mut aligned)?; 869 *item = aligned.to_unaligned(); 870 Ok(()) 871 }) 872 } 873 874 /// Converts a borrowed ZeroVec to an owned ZeroVec. No-op if already owned. 875 /// 876 /// # Example 877 /// 878 /// ``` 879 /// use zerovec::ZeroVec; 880 /// 881 /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x01]; 882 /// let zerovec: ZeroVec<u16> = 883 /// ZeroVec::parse_bytes(bytes).expect("infallible"); 884 /// assert!(!zerovec.is_owned()); 885 /// 886 /// let owned = zerovec.into_owned(); 887 /// assert!(owned.is_owned()); 888 /// ``` 889 #[cfg(feature = "alloc")] into_owned(self) -> ZeroVec<'static, T>890 pub fn into_owned(self) -> ZeroVec<'static, T> { 891 use alloc::borrow::Cow; 892 match self.into_cow() { 893 Cow::Owned(vec) => ZeroVec::new_owned(vec), 894 Cow::Borrowed(b) => ZeroVec::new_owned(b.into()), 895 } 896 } 897 898 /// Allows the ZeroVec to be mutated by converting it to an owned variant, and producing 899 /// a mutable vector of ULEs. If you only need a mutable slice, consider using [`Self::to_mut_slice()`] 900 /// instead. 901 /// 902 /// # Example 903 /// 904 /// ```rust 905 /// # use crate::zerovec::ule::AsULE; 906 /// use zerovec::ZeroVec; 907 /// 908 /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x01]; 909 /// let mut zerovec: ZeroVec<u16> = 910 /// ZeroVec::parse_bytes(bytes).expect("infallible"); 911 /// assert!(!zerovec.is_owned()); 912 /// 913 /// zerovec.with_mut(|v| v.push(12_u16.to_unaligned())); 914 /// assert!(zerovec.is_owned()); 915 /// ``` 916 #[cfg(feature = "alloc")] with_mut<R>(&mut self, f: impl FnOnce(&mut alloc::vec::Vec<T::ULE>) -> R) -> R917 pub fn with_mut<R>(&mut self, f: impl FnOnce(&mut alloc::vec::Vec<T::ULE>) -> R) -> R { 918 use alloc::borrow::Cow; 919 // We're in danger if f() panics whilst we've moved a vector out of self; 920 // replace it with an empty dummy vector for now 921 let this = core::mem::take(self); 922 let mut vec = match this.into_cow() { 923 Cow::Owned(v) => v, 924 Cow::Borrowed(s) => s.into(), 925 }; 926 let ret = f(&mut vec); 927 *self = Self::new_owned(vec); 928 ret 929 } 930 931 /// Allows the ZeroVec to be mutated by converting it to an owned variant (if necessary) 932 /// and returning a slice to its backing buffer. [`Self::with_mut()`] allows for mutation 933 /// of the vector itself. 934 /// 935 /// # Example 936 /// 937 /// ```rust 938 /// # use crate::zerovec::ule::AsULE; 939 /// use zerovec::ZeroVec; 940 /// 941 /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x01]; 942 /// let mut zerovec: ZeroVec<u16> = 943 /// ZeroVec::parse_bytes(bytes).expect("infallible"); 944 /// assert!(!zerovec.is_owned()); 945 /// 946 /// zerovec.to_mut_slice()[1] = 5u16.to_unaligned(); 947 /// assert!(zerovec.is_owned()); 948 /// ``` 949 #[cfg(feature = "alloc")] to_mut_slice(&mut self) -> &mut [T::ULE]950 pub fn to_mut_slice(&mut self) -> &mut [T::ULE] { 951 if !self.is_owned() { 952 // `buf` is either a valid vector or slice of `T::ULE`s, either 953 // way it's always valid 954 let slice = self.vector.as_slice(); 955 *self = ZeroVec::new_owned(slice.into()); 956 } 957 unsafe { self.vector.buf.as_mut() } 958 } 959 /// Remove all elements from this ZeroVec and reset it to an empty borrowed state. clear(&mut self)960 pub fn clear(&mut self) { 961 *self = Self::new_borrowed(&[]) 962 } 963 964 /// Removes the first element of the ZeroVec. The ZeroVec remains in the same 965 /// borrowed or owned state. 966 /// 967 /// # Examples 968 /// 969 /// ``` 970 /// # use crate::zerovec::ule::AsULE; 971 /// use zerovec::ZeroVec; 972 /// 973 /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x01]; 974 /// let mut zerovec: ZeroVec<u16> = 975 /// ZeroVec::parse_bytes(bytes).expect("infallible"); 976 /// assert!(!zerovec.is_owned()); 977 /// 978 /// let first = zerovec.take_first().unwrap(); 979 /// assert_eq!(first, 0x00D3); 980 /// assert!(!zerovec.is_owned()); 981 /// 982 /// let mut zerovec = zerovec.into_owned(); 983 /// assert!(zerovec.is_owned()); 984 /// let first = zerovec.take_first().unwrap(); 985 /// assert_eq!(first, 0x0119); 986 /// assert!(zerovec.is_owned()); 987 /// ``` 988 #[cfg(feature = "alloc")] take_first(&mut self) -> Option<T>989 pub fn take_first(&mut self) -> Option<T> { 990 match core::mem::take(self).into_cow() { 991 Cow::Owned(mut vec) => { 992 if vec.is_empty() { 993 return None; 994 } 995 let ule = vec.remove(0); 996 let rv = T::from_unaligned(ule); 997 *self = ZeroVec::new_owned(vec); 998 Some(rv) 999 } 1000 Cow::Borrowed(b) => { 1001 let (ule, remainder) = b.split_first()?; 1002 let rv = T::from_unaligned(*ule); 1003 *self = ZeroVec::new_borrowed(remainder); 1004 Some(rv) 1005 } 1006 } 1007 } 1008 1009 /// Removes the last element of the ZeroVec. The ZeroVec remains in the same 1010 /// borrowed or owned state. 1011 /// 1012 /// # Examples 1013 /// 1014 /// ``` 1015 /// # use crate::zerovec::ule::AsULE; 1016 /// use zerovec::ZeroVec; 1017 /// 1018 /// let bytes: &[u8] = &[0xD3, 0x00, 0x19, 0x01, 0xA5, 0x01, 0xCD, 0x01]; 1019 /// let mut zerovec: ZeroVec<u16> = 1020 /// ZeroVec::parse_bytes(bytes).expect("infallible"); 1021 /// assert!(!zerovec.is_owned()); 1022 /// 1023 /// let last = zerovec.take_last().unwrap(); 1024 /// assert_eq!(last, 0x01CD); 1025 /// assert!(!zerovec.is_owned()); 1026 /// 1027 /// let mut zerovec = zerovec.into_owned(); 1028 /// assert!(zerovec.is_owned()); 1029 /// let last = zerovec.take_last().unwrap(); 1030 /// assert_eq!(last, 0x01A5); 1031 /// assert!(zerovec.is_owned()); 1032 /// ``` 1033 #[cfg(feature = "alloc")] take_last(&mut self) -> Option<T>1034 pub fn take_last(&mut self) -> Option<T> { 1035 match core::mem::take(self).into_cow() { 1036 Cow::Owned(mut vec) => { 1037 let ule = vec.pop()?; 1038 let rv = T::from_unaligned(ule); 1039 *self = ZeroVec::new_owned(vec); 1040 Some(rv) 1041 } 1042 Cow::Borrowed(b) => { 1043 let (ule, remainder) = b.split_last()?; 1044 let rv = T::from_unaligned(*ule); 1045 *self = ZeroVec::new_borrowed(remainder); 1046 Some(rv) 1047 } 1048 } 1049 } 1050 1051 /// Converts the type into a `Cow<'a, [T::ULE]>`, which is 1052 /// the logical equivalent of this type's internal representation 1053 #[inline] 1054 #[cfg(feature = "alloc")] into_cow(self) -> Cow<'a, [T::ULE]>1055 pub fn into_cow(self) -> Cow<'a, [T::ULE]> { 1056 let this = core::mem::ManuallyDrop::new(self); 1057 if this.is_owned() { 1058 let vec = unsafe { 1059 // safe to call: we know it's owned, 1060 // and `self`/`this` are thenceforth no longer used or dropped 1061 { this }.vector.get_vec() 1062 }; 1063 Cow::Owned(vec) 1064 } else { 1065 // We can extend the lifetime of the slice to 'a 1066 // since we know it is borrowed 1067 let slice = unsafe { { this }.vector.as_arbitrary_slice() }; 1068 Cow::Borrowed(slice) 1069 } 1070 } 1071 } 1072 1073 #[cfg(feature = "alloc")] 1074 impl<T: AsULE> FromIterator<T> for ZeroVec<'_, T> { 1075 /// Creates an owned [`ZeroVec`] from an iterator of values. from_iter<I>(iter: I) -> Self where I: IntoIterator<Item = T>,1076 fn from_iter<I>(iter: I) -> Self 1077 where 1078 I: IntoIterator<Item = T>, 1079 { 1080 ZeroVec::new_owned(iter.into_iter().map(|t| t.to_unaligned()).collect()) 1081 } 1082 } 1083 1084 /// Convenience wrapper for [`ZeroSlice::from_ule_slice`]. The value will be created at compile-time, 1085 /// meaning that all arguments must also be constant. 1086 /// 1087 /// # Arguments 1088 /// 1089 /// * `$aligned` - The type of an element in its canonical, aligned form, e.g., `char`. 1090 /// * `$convert` - A const function that converts an `$aligned` into its unaligned equivalent, e.g., 1091 /// `const fn from_aligned(a: CanonicalType) -> CanonicalType::ULE`. 1092 /// * `$x` - The elements that the `ZeroSlice` will hold. 1093 /// 1094 /// # Examples 1095 /// 1096 /// Using array-conversion functions provided by this crate: 1097 /// 1098 /// ``` 1099 /// use zerovec::{ZeroSlice, zeroslice, ule::AsULE}; 1100 /// 1101 /// const SIGNATURE: &ZeroSlice<char> = zeroslice!(char; <char as AsULE>::ULE::from_aligned; ['b', 'y', 'e', '✌']); 1102 /// const EMPTY: &ZeroSlice<u32> = zeroslice![]; 1103 /// 1104 /// let empty: &ZeroSlice<u32> = zeroslice![]; 1105 /// let nums = zeroslice!(u32; <u32 as AsULE>::ULE::from_unsigned; [1, 2, 3, 4, 5]); 1106 /// assert_eq!(nums.last().unwrap(), 5); 1107 /// ``` 1108 /// 1109 /// Using a custom array-conversion function: 1110 /// 1111 /// ``` 1112 /// use zerovec::{ule::AsULE, ule::RawBytesULE, zeroslice, ZeroSlice}; 1113 /// 1114 /// const fn be_convert(num: i16) -> <i16 as AsULE>::ULE { 1115 /// RawBytesULE(num.to_be_bytes()) 1116 /// } 1117 /// 1118 /// const NUMBERS_BE: &ZeroSlice<i16> = 1119 /// zeroslice!(i16; be_convert; [1, -2, 3, -4, 5]); 1120 /// ``` 1121 #[macro_export] 1122 macro_rules! zeroslice { 1123 () => ( 1124 $crate::ZeroSlice::new_empty() 1125 ); 1126 ($aligned:ty; $convert:expr; [$($x:expr),+ $(,)?]) => ( 1127 $crate::ZeroSlice::<$aligned>::from_ule_slice( 1128 {const X: &[<$aligned as $crate::ule::AsULE>::ULE] = &[ 1129 $($convert($x)),* 1130 ]; X} 1131 ) 1132 ); 1133 } 1134 1135 /// Creates a borrowed `ZeroVec`. Convenience wrapper for `zeroslice!(...).as_zerovec()`. The value 1136 /// will be created at compile-time, meaning that all arguments must also be constant. 1137 /// 1138 /// See [`zeroslice!`](crate::zeroslice) for more information. 1139 /// 1140 /// # Examples 1141 /// 1142 /// ``` 1143 /// use zerovec::{ZeroVec, zerovec, ule::AsULE}; 1144 /// 1145 /// const SIGNATURE: ZeroVec<char> = zerovec!(char; <char as AsULE>::ULE::from_aligned; ['a', 'y', 'e', '✌']); 1146 /// assert!(!SIGNATURE.is_owned()); 1147 /// 1148 /// const EMPTY: ZeroVec<u32> = zerovec![]; 1149 /// assert!(!EMPTY.is_owned()); 1150 /// ``` 1151 #[macro_export] 1152 macro_rules! zerovec { 1153 () => ( 1154 $crate::ZeroVec::new() 1155 ); 1156 ($aligned:ty; $convert:expr; [$($x:expr),+ $(,)?]) => ( 1157 $crate::zeroslice![$aligned; $convert; [$($x),+]].as_zerovec() 1158 ); 1159 } 1160 1161 #[cfg(test)] 1162 mod tests { 1163 use super::*; 1164 use crate::samples::*; 1165 1166 #[test] test_get()1167 fn test_get() { 1168 { 1169 let zerovec = ZeroVec::from_slice_or_alloc(TEST_SLICE); 1170 assert_eq!(zerovec.get(0), Some(TEST_SLICE[0])); 1171 assert_eq!(zerovec.get(1), Some(TEST_SLICE[1])); 1172 assert_eq!(zerovec.get(2), Some(TEST_SLICE[2])); 1173 } 1174 { 1175 let zerovec = ZeroVec::<u32>::parse_bytes(TEST_BUFFER_LE).unwrap(); 1176 assert_eq!(zerovec.get(0), Some(TEST_SLICE[0])); 1177 assert_eq!(zerovec.get(1), Some(TEST_SLICE[1])); 1178 assert_eq!(zerovec.get(2), Some(TEST_SLICE[2])); 1179 } 1180 } 1181 1182 #[test] test_binary_search()1183 fn test_binary_search() { 1184 { 1185 let zerovec = ZeroVec::from_slice_or_alloc(TEST_SLICE); 1186 assert_eq!(Ok(3), zerovec.binary_search(&0x0e0d0c)); 1187 assert_eq!(Err(3), zerovec.binary_search(&0x0c0d0c)); 1188 } 1189 { 1190 let zerovec = ZeroVec::<u32>::parse_bytes(TEST_BUFFER_LE).unwrap(); 1191 assert_eq!(Ok(3), zerovec.binary_search(&0x0e0d0c)); 1192 assert_eq!(Err(3), zerovec.binary_search(&0x0c0d0c)); 1193 } 1194 } 1195 1196 #[test] test_odd_alignment()1197 fn test_odd_alignment() { 1198 assert_eq!( 1199 Some(0x020100), 1200 ZeroVec::<u32>::parse_bytes(TEST_BUFFER_LE).unwrap().get(0) 1201 ); 1202 assert_eq!( 1203 Some(0x04000201), 1204 ZeroVec::<u32>::parse_bytes(&TEST_BUFFER_LE[1..77]) 1205 .unwrap() 1206 .get(0) 1207 ); 1208 assert_eq!( 1209 Some(0x05040002), 1210 ZeroVec::<u32>::parse_bytes(&TEST_BUFFER_LE[2..78]) 1211 .unwrap() 1212 .get(0) 1213 ); 1214 assert_eq!( 1215 Some(0x06050400), 1216 ZeroVec::<u32>::parse_bytes(&TEST_BUFFER_LE[3..79]) 1217 .unwrap() 1218 .get(0) 1219 ); 1220 assert_eq!( 1221 Some(0x060504), 1222 ZeroVec::<u32>::parse_bytes(&TEST_BUFFER_LE[4..]) 1223 .unwrap() 1224 .get(0) 1225 ); 1226 assert_eq!( 1227 Some(0x4e4d4c00), 1228 ZeroVec::<u32>::parse_bytes(&TEST_BUFFER_LE[75..79]) 1229 .unwrap() 1230 .get(0) 1231 ); 1232 assert_eq!( 1233 Some(0x4e4d4c00), 1234 ZeroVec::<u32>::parse_bytes(&TEST_BUFFER_LE[3..79]) 1235 .unwrap() 1236 .get(18) 1237 ); 1238 assert_eq!( 1239 Some(0x4e4d4c), 1240 ZeroVec::<u32>::parse_bytes(&TEST_BUFFER_LE[76..]) 1241 .unwrap() 1242 .get(0) 1243 ); 1244 assert_eq!( 1245 Some(0x4e4d4c), 1246 ZeroVec::<u32>::parse_bytes(TEST_BUFFER_LE).unwrap().get(19) 1247 ); 1248 // TODO(#1144): Check for correct slice length in RawBytesULE 1249 // assert_eq!( 1250 // None, 1251 // ZeroVec::<u32>::parse_bytes(&TEST_BUFFER_LE[77..]) 1252 // .unwrap() 1253 // .get(0) 1254 // ); 1255 assert_eq!( 1256 None, 1257 ZeroVec::<u32>::parse_bytes(TEST_BUFFER_LE).unwrap().get(20) 1258 ); 1259 assert_eq!( 1260 None, 1261 ZeroVec::<u32>::parse_bytes(&TEST_BUFFER_LE[3..79]) 1262 .unwrap() 1263 .get(19) 1264 ); 1265 } 1266 } 1267