blob: e6186be0a2f5a3808bee416f9191200d1eed213b [file] [log] [blame]
Chris Wailes977026a2023-02-13 09:13:10 -08001// 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")]
6mod databake;
7
8#[cfg(feature = "serde")]
9mod serde;
10
11mod slice;
12
13pub use slice::ZeroSlice;
14
15use crate::ule::*;
16use alloc::borrow::Cow;
17use alloc::vec::Vec;
18use core::cmp::{Ord, Ordering, PartialOrd};
19use core::fmt;
20use core::iter::FromIterator;
21use core::marker::PhantomData;
22use core::mem;
Stephen Hines51393642024-02-02 00:10:59 -080023use core::num::NonZeroUsize;
Chris Wailes977026a2023-02-13 09:13:10 -080024use core::ops::Deref;
Stephen Hines51393642024-02-02 00:10:59 -080025use core::ptr;
Chris Wailes977026a2023-02-13 09:13:10 -080026
Chris Wailes5c0824a2023-04-24 16:30:59 -070027/// A zero-copy, byte-aligned vector for fixed-width types.
Chris Wailes977026a2023-02-13 09:13:10 -080028///
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.
89pub struct ZeroVec<'a, T>
90where
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.
104unsafe 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
106unsafe impl<'a, T: AsULE> Sync for ZeroVec<'a, T> where T::ULE: Sync {}
107
108impl<'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]
126struct 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
135impl<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 Hines51393642024-02-02 00:10:59 -0800143 const fn as_slice<'a>(&'a self) -> &'a [U] {
144 unsafe { &*(self.buf as *const [U]) }
Chris Wailes977026a2023-02-13 09:13:10 -0800145 }
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
165impl<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
177impl<'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
193impl<'a, T: AsULE> AsRef<ZeroSlice<T>> for ZeroVec<'a, T> {
194 fn as_ref(&self) -> &ZeroSlice<T> {
195 self.deref()
196 }
197}
198
199impl<T> fmt::Debug for ZeroVec<'_, T>
200where
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
208impl<T> Eq for ZeroVec<'_, T> where T: AsULE + Eq + ?Sized {}
209
210impl<'a, 'b, T> PartialEq<ZeroVec<'b, T>> for ZeroVec<'a, T>
211where
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
221impl<T> PartialEq<&[T]> for ZeroVec<'_, T>
222where
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
231impl<T, const N: usize> PartialEq<[T; N]> for ZeroVec<'_, T>
232where
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
241impl<'a, T: AsULE> Default for ZeroVec<'a, T> {
242 #[inline]
243 fn default() -> Self {
244 Self::new()
245 }
246}
247
248impl<'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
254impl<'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 Hines51393642024-02-02 00:10:59 -0800260impl<'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
266impl<'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
272impl<'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 Wailes977026a2023-02-13 09:13:10 -0800278impl<'a, T> ZeroVec<'a, T>
279where
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 Hines51393642024-02-02 00:10:59 -0800297 /// 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 Wailes977026a2023-02-13 09:13:10 -0800302 /// 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 Wailes977026a2023-02-13 09:13:10 -0800312 let capacity = vec.capacity();
Stephen Hines51393642024-02-02 00:10:59 -0800313 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 Wailes977026a2023-02-13 09:13:10 -0800316 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 Hines51393642024-02-02 00:10:59 -0800380 Self::new_borrowed(core::slice::from_raw_parts(
381 bytes.as_ptr() as *const T::ULE,
Chris Wailes977026a2023-02-13 09:13:10 -0800382 bytes.len() / core::mem::size_of::<T::ULE>(),
Stephen Hines51393642024-02-02 00:10:59 -0800383 ))
Chris Wailes977026a2023-02-13 09:13:10 -0800384 }
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 Hines51393642024-02-02 00:10:59 -0800582
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 Wailes977026a2023-02-13 09:13:10 -0800610}
611
612impl<'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
658impl<'a, T> ZeroVec<'a, T>
659where
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
703impl<'a, T> ZeroVec<'a, T>
704where
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
756impl<'a, T> ZeroVec<'a, T>
757where
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 Hines51393642024-02-02 00:10:59 -0800916 let this = mem::ManuallyDrop::new(self);
917 if this.is_owned() {
Chris Wailes977026a2023-02-13 09:13:10 -0800918 let vec = unsafe {
919 // safe to call: we know it's owned,
Stephen Hines51393642024-02-02 00:10:59 -0800920 // and `self`/`this` are thenceforth no longer used or dropped
921 { this }.vector.get_vec()
Chris Wailes977026a2023-02-13 09:13:10 -0800922 };
Chris Wailes977026a2023-02-13 09:13:10 -0800923 Cow::Owned(vec)
924 } else {
925 // We can extend the lifetime of the slice to 'a
926 // since we know it is borrowed
Stephen Hines51393642024-02-02 00:10:59 -0800927 let slice = unsafe { { this }.vector.as_arbitrary_slice() };
Chris Wailes977026a2023-02-13 09:13:10 -0800928 Cow::Borrowed(slice)
929 }
930 }
931}
932
933impl<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 Hines51393642024-02-02 00:10:59 -0800943/// 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]
987macro_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]
1017macro_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 Wailes977026a2023-02-13 09:13:10 -08001026#[cfg(test)]
1027mod 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}