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