1use core::{marker::PhantomData, num::NonZeroUsize};
2
3use crate::{
4 errors::{self, ErrorKind},
5 impls::array_from_buffer,
6 slice_helpers::SliceWithStartOffset,
7 TableReadUnionVector, VectorReadUnion,
8};
9
10pub struct UnionVector<'buf, T: ?Sized> {
12 tags: SliceWithStartOffset<'buf>,
13 values: SliceWithStartOffset<'buf>,
14 len: usize,
15 _marker: PhantomData<&'buf T>,
16}
17
18impl<T: ?Sized> Copy for UnionVector<'_, T> {}
19impl<T: ?Sized> Clone for UnionVector<'_, T> {
20 #[inline]
21 fn clone(&self) -> Self {
22 *self
23 }
24}
25
26impl<'buf, T: ?Sized> UnionVector<'buf, T> {
27 #[inline]
32 #[must_use]
33 pub const fn new_empty() -> UnionVector<'buf, T> {
34 Self {
35 tags: SliceWithStartOffset {
36 buffer: &[],
37 offset_from_start: 0,
38 },
39 values: SliceWithStartOffset {
40 buffer: &[],
41 offset_from_start: 0,
42 },
43 len: 0,
44 _marker: PhantomData,
45 }
46 }
47
48 #[inline]
50 #[must_use]
51 pub fn is_empty(self) -> bool {
52 self.len == 0
53 }
54
55 #[inline]
57 #[must_use]
58 pub fn len(self) -> usize {
59 self.len
60 }
61}
62
63impl<'buf, T: VectorReadUnion<'buf>> UnionVector<'buf, T> {
64 #[inline]
66 #[must_use]
67 pub fn first(self) -> Option<crate::Result<T>> {
68 self.get(0)
69 }
70
71 #[inline]
73 #[must_use]
74 pub fn last(self) -> Option<crate::Result<T>> {
75 self.get(self.len().checked_sub(1)?)
76 }
77
78 #[inline]
86 #[must_use]
87 pub fn get<I>(self, index: I) -> Option<I::Output>
88 where
89 I: UnionVectorIndex<'buf, T>,
90 {
91 index.get(self)
92 }
93
94 #[inline]
106 #[must_use]
107 pub unsafe fn get_unchecked<I>(self, index: I) -> I::Output
108 where
109 I: UnionVectorIndex<'buf, T>,
110 {
111 index.get_unchecked(self)
112 }
113
114 #[inline]
116 #[must_use]
117 pub fn iter(self) -> super::Iter<'buf, T> {
118 super::Iter::new(self)
119 }
120
121 #[inline]
138 #[must_use]
139 pub fn chunks(self, chunk_size: usize) -> super::Chunks<'buf, T> {
140 let chunk_size = NonZeroUsize::new(chunk_size).expect("chunks cannot have a size of zero");
141 super::Chunks::new(self, chunk_size)
142 }
143
144 #[inline]
161 #[must_use]
162 pub fn rchunks(self, chunk_size: usize) -> super::RChunks<'buf, T> {
163 let chunk_size = NonZeroUsize::new(chunk_size).expect("chunks cannot have a size of zero");
164 super::RChunks::new(self, chunk_size)
165 }
166
167 #[inline]
187 #[must_use]
188 pub fn chunks_exact(self, chunk_size: usize) -> super::ChunksExact<'buf, T> {
189 let chunk_size = NonZeroUsize::new(chunk_size).expect("chunks cannot have a size of zero");
190 super::ChunksExact::new(self, chunk_size)
191 }
192
193 #[inline]
214 #[must_use]
215 pub fn rchunks_exact(self, chunk_size: usize) -> super::RChunksExact<'buf, T> {
216 let chunk_size = NonZeroUsize::new(chunk_size).expect("chunks cannot have a size of zero");
217 super::RChunksExact::new(self, chunk_size)
218 }
219
220 #[inline]
228 #[must_use]
229 pub fn windows(self, size: usize) -> super::Windows<'buf, T> {
230 let size = NonZeroUsize::new(size).expect("windows cannot have a size of zero");
231 super::Windows::new(self, size)
232 }
233
234 #[inline]
236 #[must_use]
237 pub fn split_first(self) -> Option<(crate::Result<T>, UnionVector<'buf, T>)> {
238 if self.is_empty() {
239 None
240 } else {
241 Some(unsafe { (self.get_unchecked(0), self.get_unchecked(1..)) })
242 }
243 }
244
245 #[inline]
247 #[must_use]
248 pub fn split_last(self) -> Option<(crate::Result<T>, UnionVector<'buf, T>)> {
249 if self.is_empty() {
250 None
251 } else {
252 Some(unsafe {
253 (
254 self.get_unchecked(self.len - 1),
255 self.get_unchecked(..self.len - 1),
256 )
257 })
258 }
259 }
260
261 #[inline]
267 #[must_use]
268 pub fn split_at(self, mid: usize) -> Option<(UnionVector<'buf, T>, UnionVector<'buf, T>)> {
269 if mid <= self.len {
270 Some(unsafe { self.split_at_unchecked(mid) })
271 } else {
272 None
273 }
274 }
275
276 #[inline]
293 #[must_use]
294 pub unsafe fn split_at_unchecked(
295 self,
296 mid: usize,
297 ) -> (UnionVector<'buf, T>, UnionVector<'buf, T>) {
298 (self.get_unchecked(..mid), self.get_unchecked(mid..))
299 }
300}
301
302impl<'buf, T: VectorReadUnion<'buf>> UnionVector<'buf, T> {
303 pub fn to_vec<O>(self) -> crate::Result<alloc::vec::Vec<O>>
305 where
306 O: core::convert::TryFrom<T>,
307 crate::errors::Error: From<O::Error>,
308 {
309 self.iter().map(|v| Ok(O::try_from(v?)?)).collect()
310 }
311}
312
313impl<'buf, T: VectorReadUnion<'buf>> IntoIterator for UnionVector<'buf, T> {
314 type Item = crate::Result<T>;
315 type IntoIter = super::Iter<'buf, T>;
316
317 #[inline]
318 fn into_iter(self) -> Self::IntoIter {
319 self.iter()
320 }
321}
322
323impl<'buf, T: VectorReadUnion<'buf> + core::fmt::Debug> core::fmt::Debug for UnionVector<'buf, T>
324where
325 T: core::fmt::Debug,
326{
327 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
328 f.debug_list().entries(*self).finish()
329 }
330}
331
332pub trait UnionVectorIndex<'buf, T: VectorReadUnion<'buf>>: private::Sealed {
334 type Output;
336
337 fn get(self, vector: UnionVector<'buf, T>) -> Option<Self::Output>;
339
340 unsafe fn get_unchecked(self, vector: UnionVector<'buf, T>) -> Self::Output;
347}
348
349fn into_range_unchecked(
351 len: usize,
352 (start, end): (core::ops::Bound<usize>, core::ops::Bound<usize>),
353) -> core::ops::Range<usize> {
354 use core::ops::Bound;
355 let start = match start {
356 Bound::Included(i) => i,
357 Bound::Excluded(i) => i + 1,
358 Bound::Unbounded => 0,
359 };
360 let end = match end {
361 Bound::Included(i) => i + 1,
362 Bound::Excluded(i) => i,
363 Bound::Unbounded => len,
364 };
365 start..end
366}
367
368fn into_range(
371 len: usize,
372 (start, end): (core::ops::Bound<usize>, core::ops::Bound<usize>),
373) -> Option<core::ops::Range<usize>> {
374 use core::ops::Bound;
375 let start = match start {
376 Bound::Included(start) => start,
377 Bound::Excluded(start) => start.checked_add(1)?,
378 Bound::Unbounded => 0,
379 };
380
381 let end = match end {
382 Bound::Included(end) => end.checked_add(1)?,
383 Bound::Excluded(end) => end,
384 Bound::Unbounded => len,
385 };
386
387 Some(start..end)
391}
392impl<'buf, T: VectorReadUnion<'buf>> UnionVectorIndex<'buf, T>
393 for (core::ops::Bound<usize>, core::ops::Bound<usize>)
394{
395 type Output = UnionVector<'buf, T>;
396
397 #[inline]
398 fn get(self, vector: UnionVector<'buf, T>) -> Option<Self::Output> {
399 into_range(vector.len, self)?.get(vector)
400 }
401
402 #[inline]
403 unsafe fn get_unchecked(self, vector: UnionVector<'buf, T>) -> Self::Output {
404 into_range_unchecked(vector.len, self).get_unchecked(vector)
405 }
406}
407
408impl<'buf, T: VectorReadUnion<'buf>> UnionVectorIndex<'buf, T> for usize {
409 type Output = crate::Result<T>;
410
411 #[inline]
412 fn get(self, vector: UnionVector<'buf, T>) -> Option<Self::Output> {
413 if self < vector.len {
414 Some(unsafe { self.get_unchecked(vector) })
415 } else {
416 None
417 }
418 }
419
420 #[inline]
421 unsafe fn get_unchecked(self, vector: UnionVector<'buf, T>) -> Self::Output {
422 debug_assert!(self < vector.len);
423 debug_assert!(vector.len.checked_mul(4).unwrap() <= vector.tags.len());
424 debug_assert!(vector.len.checked_mul(4).unwrap() <= vector.values.len());
425 let tag = *vector.tags.buffer.get_unchecked(self);
426 <T as VectorReadUnion>::from_buffer(vector.values, tag, 4 * self)
427 }
428}
429
430impl<'buf, T: VectorReadUnion<'buf>> UnionVectorIndex<'buf, T> for core::ops::Range<usize> {
431 type Output = UnionVector<'buf, T>;
432
433 #[inline]
434 fn get(self, vector: UnionVector<'buf, T>) -> Option<Self::Output> {
435 if self.start > self.end || self.end > vector.len {
436 None
437 } else {
438 unsafe { Some(self.get_unchecked(vector)) }
440 }
441 }
442
443 #[inline]
444 unsafe fn get_unchecked(self, vector: UnionVector<'buf, T>) -> Self::Output {
445 debug_assert!(self.start <= self.end);
446 debug_assert!(self.end <= vector.len);
447 UnionVector {
448 tags: vector
449 .tags
450 .advance(self.start)
451 .expect("IMPOSSIBLE: the length was checked on creation"),
452 values: vector
453 .values
454 .advance(4 * self.start)
455 .expect("IMPOSSIBLE: the length was checked on creation"),
456 len: self.end - self.start,
457 _marker: PhantomData,
458 }
459 }
460}
461
462impl<'buf, T: VectorReadUnion<'buf>> UnionVectorIndex<'buf, T> for core::ops::RangeFrom<usize> {
463 type Output = UnionVector<'buf, T>;
464
465 #[inline]
466 fn get(self, vector: UnionVector<'buf, T>) -> Option<Self::Output> {
467 (self.start..vector.len).get(vector)
468 }
469
470 #[inline]
471 unsafe fn get_unchecked(self, vector: UnionVector<'buf, T>) -> Self::Output {
472 (self.start..vector.len).get_unchecked(vector)
473 }
474}
475
476impl<'buf, T: VectorReadUnion<'buf>> UnionVectorIndex<'buf, T> for core::ops::RangeFull {
477 type Output = UnionVector<'buf, T>;
478
479 #[inline]
480 fn get(self, vector: UnionVector<'buf, T>) -> Option<Self::Output> {
481 Some(vector)
482 }
483
484 #[inline]
485 unsafe fn get_unchecked(self, vector: UnionVector<'buf, T>) -> Self::Output {
486 vector
487 }
488}
489
490impl<'buf, T: VectorReadUnion<'buf>> UnionVectorIndex<'buf, T>
491 for core::ops::RangeInclusive<usize>
492{
493 type Output = UnionVector<'buf, T>;
494
495 #[inline]
496 fn get(self, vector: UnionVector<'buf, T>) -> Option<Self::Output> {
497 (*self.start()..self.end().checked_add(1)?).get(vector)
498 }
499
500 #[inline]
501 unsafe fn get_unchecked(self, vector: UnionVector<'buf, T>) -> Self::Output {
502 (*self.start()..self.end() + 1).get_unchecked(vector)
503 }
504}
505
506impl<'buf, T: VectorReadUnion<'buf>> UnionVectorIndex<'buf, T> for core::ops::RangeTo<usize> {
507 type Output = UnionVector<'buf, T>;
508
509 #[inline]
510 fn get(self, vector: UnionVector<'buf, T>) -> Option<Self::Output> {
511 (0..self.end).get(vector)
512 }
513
514 #[inline]
515 unsafe fn get_unchecked(self, vector: UnionVector<'buf, T>) -> Self::Output {
516 (0..self.end).get_unchecked(vector)
517 }
518}
519
520impl<'buf, T: VectorReadUnion<'buf>> UnionVectorIndex<'buf, T>
521 for core::ops::RangeToInclusive<usize>
522{
523 type Output = UnionVector<'buf, T>;
524
525 #[inline]
526 fn get(self, vector: UnionVector<'buf, T>) -> Option<Self::Output> {
527 (0..=self.end).get(vector)
528 }
529
530 #[inline]
531 unsafe fn get_unchecked(self, vector: UnionVector<'buf, T>) -> Self::Output {
532 (0..=self.end).get_unchecked(vector)
533 }
534}
535
536impl<'buf, T: VectorReadUnion<'buf>, O> TryFrom<UnionVector<'buf, T>> for alloc::vec::Vec<O>
537where
538 O: core::convert::TryFrom<T>,
539 errors::Error: From<O::Error>,
540{
541 type Error = crate::errors::Error;
542
543 fn try_from(value: UnionVector<'buf, T>) -> Result<Self, Self::Error> {
544 value.iter().map(|v| Ok(O::try_from(v?)?)).collect()
545 }
546}
547
548impl<'buf, T: VectorReadUnion<'buf>> TableReadUnionVector<'buf> for UnionVector<'buf, T> {
549 fn from_buffer(
550 buffer: SliceWithStartOffset<'buf>,
551 tag_offset: usize,
552 values_offset: usize,
553 ) -> core::result::Result<Self, ErrorKind> {
554 let (tags_buffer, tags_len) = array_from_buffer(buffer, tag_offset)?;
555 let (values_buffer, values_len) = array_from_buffer(buffer, values_offset)?;
556 if tags_len > tags_buffer.len() {
557 return Err(ErrorKind::InvalidLength);
558 }
559 if values_len.checked_mul(4).ok_or(ErrorKind::InvalidLength)? > values_buffer.len() {
560 return Err(ErrorKind::InvalidLength);
561 }
562 if tags_len != values_len {
563 return Err(ErrorKind::UnionVectorLengthsMismatched {
564 tags_len,
565 values_len,
566 });
567 }
568 Ok(UnionVector {
569 tags: tags_buffer,
570 values: values_buffer,
571 len: tags_len,
572 _marker: PhantomData,
573 })
574 }
575}
576
577mod private {
578 pub trait Sealed {}
579
580 impl Sealed for (core::ops::Bound<usize>, core::ops::Bound<usize>) {}
582 impl Sealed for usize {}
583 impl Sealed for core::ops::Range<usize> {}
584 impl Sealed for core::ops::RangeFrom<usize> {}
585 impl Sealed for core::ops::RangeFull {}
586 impl Sealed for core::ops::RangeInclusive<usize> {}
587 impl Sealed for core::ops::RangeTo<usize> {}
588 impl Sealed for core::ops::RangeToInclusive<usize> {}
589}