1use crate::buffer::ScalarBuffer;
19use crate::{ArrowNativeType, MutableBuffer, NullBuffer, OffsetBufferBuilder, OverflowError};
20use std::ops::Deref;
21
22#[derive(Debug, Clone, PartialEq, Eq)]
59pub struct OffsetBuffer<O: ArrowNativeType>(ScalarBuffer<O>);
60
61impl<O: ArrowNativeType> OffsetBuffer<O> {
62 pub fn new(buffer: ScalarBuffer<O>) -> Self {
69 assert!(!buffer.is_empty(), "offsets cannot be empty");
70 assert!(
71 buffer[0] >= O::usize_as(0),
72 "offsets must be greater than 0"
73 );
74 assert!(
75 buffer.windows(2).all(|w| w[0] <= w[1]),
76 "offsets must be monotonically increasing"
77 );
78 Self(buffer)
79 }
80
81 pub unsafe fn new_unchecked(buffer: ScalarBuffer<O>) -> Self {
88 Self(buffer)
89 }
90
91 pub fn new_empty() -> Self {
93 let buffer = MutableBuffer::from_len_zeroed(std::mem::size_of::<O>());
94 Self(buffer.into_buffer().into())
95 }
96
97 pub fn new_zeroed(len: usize) -> Self {
104 Self::try_new_zeroed(len).unwrap_or_else(|err| panic!("{err}"))
105 }
106
107 pub fn try_new_zeroed(len: usize) -> Result<Self, OverflowError> {
113 let len_bytes = len
114 .checked_add(1)
115 .and_then(|o| o.checked_mul(std::mem::size_of::<O>()))
116 .ok_or_else(|| OverflowError::new::<usize>("buffer length"))?;
117 let buffer = MutableBuffer::from_len_zeroed(len_bytes);
118 Ok(Self(buffer.into_buffer().into()))
119 }
120
121 pub fn from_lengths<I>(lengths: I) -> Self
136 where
137 I: IntoIterator<Item = usize>,
138 {
139 Self::try_from_lengths(lengths).unwrap_or_else(|err| panic!("{err}"))
140 }
141
142 pub fn try_from_lengths<I>(lengths: I) -> Result<Self, OverflowError>
155 where
156 I: IntoIterator<Item = usize>,
157 {
158 let iter = lengths.into_iter();
159 let mut out = Vec::with_capacity(iter.size_hint().0 + 1);
160 out.push(O::usize_as(0));
161
162 let mut acc = 0_usize;
163 for length in iter {
164 acc = acc
165 .checked_add(length)
166 .ok_or_else(|| OverflowError::new::<usize>("total length"))?;
167 out.push(O::usize_as(acc))
168 }
169 O::from_usize(acc).ok_or_else(|| OverflowError::new::<O>("offset").with_value(acc))?;
171 Ok(Self(out.into()))
172 }
173
174 pub fn from_repeated_length(length: usize, n: usize) -> Self {
189 Self::try_from_repeated_length(length, n).unwrap_or_else(|err| panic!("{err}"))
190 }
191
192 pub fn try_from_repeated_length(length: usize, n: usize) -> Result<Self, OverflowError> {
205 if n == 0 {
206 return Ok(Self::new_empty());
207 }
208
209 if length == 0 {
210 return Self::try_new_zeroed(n);
211 }
212
213 let total_length = length
215 .checked_mul(n)
216 .ok_or_else(|| OverflowError::new::<usize>("total length"))?;
217
218 O::from_usize(total_length)
219 .ok_or_else(|| OverflowError::new::<O>("offset").with_value(total_length))?;
220
221 let offsets = (0..=n)
222 .map(|index| O::usize_as(index * length))
223 .collect::<Vec<O>>();
224
225 Ok(Self(ScalarBuffer::from(offsets)))
226 }
227
228 #[inline]
239 pub fn first(&self) -> O {
240 self.0
241 .first()
242 .copied()
243 .expect("An `OffsetBuffer` is never empty")
244 }
245
246 #[inline]
257 pub fn last(&self) -> O {
258 self.0
259 .last()
260 .copied()
261 .expect("An `OffsetBuffer` is never empty")
262 }
263
264 pub fn lengths(&self) -> impl ExactSizeIterator<Item = usize> + '_ {
293 self.0.windows(2).map(|x| x[1].as_usize() - x[0].as_usize())
294 }
295
296 pub fn shrink_to_fit(&mut self) {
298 self.0.shrink_to_fit();
299 }
300
301 pub fn inner(&self) -> &ScalarBuffer<O> {
303 &self.0
304 }
305
306 pub fn into_inner(self) -> ScalarBuffer<O> {
308 self.0
309 }
310
311 #[cfg(feature = "pool")]
313 pub fn claim(&self, pool: &dyn crate::MemoryPool) {
314 self.0.claim(pool);
315 }
316
317 pub fn slice(&self, offset: usize, len: usize) -> Self {
323 Self(self.0.slice(offset, len.saturating_add(1)))
324 }
325
326 #[inline]
330 pub fn ptr_eq(&self, other: &Self) -> bool {
331 self.0.ptr_eq(&other.0)
332 }
333
334 pub fn has_non_empty_nulls(&self, null_buffer: Option<&NullBuffer>) -> bool {
370 let Some(null_buffer) = null_buffer else {
371 return false;
372 };
373
374 assert_eq!(
375 self.len() - 1,
376 null_buffer.len(),
377 "The length of the offsets should be 1 more than the length of the null buffer"
378 );
379
380 if null_buffer.null_count() == 0 {
381 return false;
382 }
383
384 let initial_offset = self[0];
386 let last_offset = self[self.len() - 1];
387
388 if null_buffer.null_count() == self.len() - 1 {
390 return last_offset != initial_offset;
391 }
392
393 let mut valid_slices_iter = null_buffer.valid_slices();
394
395 let (start, end) = valid_slices_iter.next().unwrap();
397
398 if self[start] != initial_offset {
400 return true;
401 }
402
403 let mut end_offset_of_last_valid_value = self[end];
406
407 for (start, end) in valid_slices_iter {
408 if self[start] != end_offset_of_last_valid_value {
411 return true;
412 }
413
414 end_offset_of_last_valid_value = self[end];
417 }
418
419 end_offset_of_last_valid_value != last_offset
420 }
421
422 pub fn subtract(self, rhs: O) -> Self
444 where
445 O: std::ops::Sub<Output = O> + std::cmp::PartialOrd + num_traits::CheckedSub,
446 {
447 if rhs == O::usize_as(0) {
448 return self;
449 }
450
451 let len = self.len();
452
453 assert!(
455 self[0] >= rhs,
456 "shifted offsets will become negative which is not allowed"
457 );
458
459 if rhs < O::usize_as(0) {
461 self[len - 1].checked_sub(&rhs).expect("must not overflow");
462 }
463
464 let shifted_offsets: Vec<O> = match self.into_inner().into_inner().into_vec() {
466 Ok(mut v) => {
468 for offset in &mut v {
469 *offset = *offset - rhs;
470 }
471 v
472 }
473 Err(buffer) => {
475 let offsets = ScalarBuffer::<O>::from(buffer);
476 offsets.iter().map(|offset| *offset - rhs).collect()
477 }
478 };
479 let shifted_buffer = ScalarBuffer::from(shifted_offsets);
480 unsafe { Self::new_unchecked(shifted_buffer) }
485 }
486}
487
488impl<T: ArrowNativeType> Deref for OffsetBuffer<T> {
489 type Target = [T];
490
491 #[inline]
492 fn deref(&self) -> &Self::Target {
493 &self.0
494 }
495}
496
497impl<T: ArrowNativeType> AsRef<[T]> for OffsetBuffer<T> {
498 #[inline]
499 fn as_ref(&self) -> &[T] {
500 self
501 }
502}
503
504impl<O: ArrowNativeType> From<OffsetBufferBuilder<O>> for OffsetBuffer<O> {
505 fn from(value: OffsetBufferBuilder<O>) -> Self {
506 value.finish()
507 }
508}
509
510impl<O: ArrowNativeType> Default for OffsetBuffer<O> {
511 fn default() -> Self {
512 Self::new_empty()
513 }
514}
515
516#[cfg(test)]
517mod tests {
518 use super::*;
519
520 #[test]
521 #[should_panic(expected = "offsets cannot be empty")]
522 fn empty_offsets() {
523 OffsetBuffer::new(Vec::<i32>::new().into());
524 }
525
526 #[test]
527 #[should_panic(expected = "offsets must be greater than 0")]
528 fn negative_offsets() {
529 OffsetBuffer::new(vec![-1, 0, 1].into());
530 }
531
532 #[test]
533 fn try_from_lengths_overflow() {
534 let lengths = [u32::MAX as usize, 1];
536
537 let err = OffsetBuffer::<i32>::try_from_lengths(lengths).unwrap_err();
538 assert_eq!(
539 err.to_string(),
540 "offset overflow: 4294967296 does not fit in i32"
541 );
542 assert!(OffsetBuffer::<i64>::try_from_lengths(lengths).is_ok());
543
544 let err = OffsetBuffer::<i32>::try_from_lengths([usize::MAX, 1]).unwrap_err();
545 assert_eq!(
546 err.to_string(),
547 "total length overflow: does not fit in usize"
548 );
549
550 assert!(std::panic::catch_unwind(|| OffsetBuffer::<i32>::from_lengths(lengths)).is_err());
552 }
553
554 #[test]
555 fn try_from_repeated_length_overflow() {
556 assert_eq!(
557 OffsetBuffer::<i32>::try_from_repeated_length(2, usize::MAX)
558 .unwrap_err()
559 .to_string(),
560 "total length overflow: does not fit in usize"
561 );
562 assert_eq!(
563 OffsetBuffer::<i32>::try_from_repeated_length(u32::MAX as usize, 2)
564 .unwrap_err()
565 .to_string(),
566 "offset overflow: 8589934590 does not fit in i32"
567 );
568 assert_eq!(
569 OffsetBuffer::<i32>::try_from_repeated_length(4, 3)
570 .unwrap()
571 .as_ref(),
572 &[0, 4, 8, 12]
573 );
574 }
575
576 #[test]
577 fn try_new_zeroed_overflow() {
578 assert_eq!(
579 OffsetBuffer::<i64>::try_new_zeroed(usize::MAX)
580 .unwrap_err()
581 .to_string(),
582 "buffer length overflow: does not fit in usize"
583 );
584 assert_eq!(
585 OffsetBuffer::<i32>::try_new_zeroed(3).unwrap().as_ref(),
586 &[0; 4]
587 );
588 }
589
590 #[test]
591 fn offsets() {
592 OffsetBuffer::new(vec![0, 1, 2, 3].into());
593
594 let offsets = OffsetBuffer::<i32>::new_zeroed(3);
595 assert_eq!(offsets.as_ref(), &[0; 4]);
596
597 let offsets = OffsetBuffer::<i32>::new_zeroed(0);
598 assert_eq!(offsets.as_ref(), &[0; 1]);
599 }
600
601 #[test]
602 #[should_panic(expected = "overflow")]
603 fn offsets_new_zeroed_overflow() {
604 OffsetBuffer::<i32>::new_zeroed(usize::MAX);
605 }
606
607 #[test]
608 #[should_panic(expected = "offsets must be monotonically increasing")]
609 fn non_monotonic_offsets() {
610 OffsetBuffer::new(vec![1, 2, 0].into());
611 }
612
613 #[test]
614 fn from_lengths() {
615 let buffer = OffsetBuffer::<i32>::from_lengths([2, 6, 3, 7, 2]);
616 assert_eq!(buffer.as_ref(), &[0, 2, 8, 11, 18, 20]);
617
618 let half_max = i32::MAX / 2;
619 let buffer = OffsetBuffer::<i32>::from_lengths([half_max as usize, half_max as usize]);
620 assert_eq!(buffer.as_ref(), &[0, half_max, half_max * 2]);
621 }
622
623 #[test]
624 #[should_panic(expected = "offset overflow")]
625 fn from_lengths_offset_overflow() {
626 OffsetBuffer::<i32>::from_lengths([i32::MAX as usize, 1]);
627 }
628
629 #[test]
630 #[should_panic(expected = "total length overflow: does not fit in usize")]
631 fn from_lengths_usize_overflow() {
632 OffsetBuffer::<i32>::from_lengths([usize::MAX, 1]);
633 }
634
635 #[test]
636 #[should_panic(expected = "offset overflow")]
637 fn from_repeated_lengths_offset_length_overflow() {
638 OffsetBuffer::<i32>::from_repeated_length(i32::MAX as usize / 4, 5);
639 }
640
641 #[test]
642 #[should_panic(expected = "offset overflow")]
643 fn from_repeated_lengths_offset_repeat_overflow() {
644 OffsetBuffer::<i32>::from_repeated_length(1, i32::MAX as usize + 1);
645 }
646
647 #[test]
648 #[should_panic(expected = "offset overflow")]
649 fn from_repeated_lengths_usize_length_overflow() {
650 OffsetBuffer::<i32>::from_repeated_length(usize::MAX, 1);
651 }
652
653 #[test]
654 #[should_panic(expected = "total length overflow: does not fit in usize")]
655 fn from_repeated_lengths_usize_length_usize_overflow() {
656 OffsetBuffer::<i32>::from_repeated_length(usize::MAX, 2);
657 }
658
659 #[test]
660 #[should_panic(expected = "offset overflow")]
661 fn from_repeated_lengths_usize_repeat_overflow() {
662 OffsetBuffer::<i32>::from_repeated_length(1, usize::MAX);
663 }
664
665 #[test]
666 fn get_lengths() {
667 let offsets = OffsetBuffer::<i32>::new(ScalarBuffer::<i32>::from(vec![0, 1, 4, 9]));
668 assert_eq!(offsets.lengths().collect::<Vec<usize>>(), vec![1, 3, 5]);
669 }
670
671 #[test]
672 fn get_lengths_should_be_with_fixed_size() {
673 let offsets = OffsetBuffer::<i32>::new(ScalarBuffer::<i32>::from(vec![0, 1, 4, 9]));
674 let iter = offsets.lengths();
675 assert_eq!(iter.size_hint(), (3, Some(3)));
676 assert_eq!(iter.len(), 3);
677 }
678
679 #[test]
680 fn get_lengths_from_empty_offset_buffer_should_be_empty_iterator() {
681 let offsets = OffsetBuffer::<i32>::new_empty();
682 assert_eq!(offsets.lengths().collect::<Vec<usize>>(), vec![]);
683 }
684
685 #[test]
686 fn impl_eq() {
687 fn are_equal<T: Eq>(a: &T, b: &T) -> bool {
688 a.eq(b)
689 }
690
691 assert!(
692 are_equal(
693 &OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 1, 4, 9])),
694 &OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 1, 4, 9]))
695 ),
696 "OffsetBuffer should implement Eq."
697 );
698 }
699
700 #[test]
701 fn impl_default() {
702 let default = OffsetBuffer::<i32>::default();
703 assert_eq!(default.as_ref(), &[0]);
704 }
705
706 #[test]
707 fn from_repeated_length_basic() {
708 let buffer = OffsetBuffer::<i32>::from_repeated_length(4, 3);
710 assert_eq!(buffer.as_ref(), &[0, 4, 8, 12]);
711
712 let lengths: Vec<usize> = buffer.lengths().collect();
714 assert_eq!(lengths, vec![4, 4, 4]);
715 }
716
717 #[test]
718 fn from_repeated_length_single_repeat() {
719 let buffer = OffsetBuffer::<i32>::from_repeated_length(5, 1);
721 assert_eq!(buffer.as_ref(), &[0, 5]);
722
723 let lengths: Vec<usize> = buffer.lengths().collect();
724 assert_eq!(lengths, vec![5]);
725 }
726
727 #[test]
728 fn from_repeated_length_zero_repeats() {
729 let buffer = OffsetBuffer::<i32>::from_repeated_length(10, 0);
730 assert_eq!(buffer, OffsetBuffer::<i32>::new_empty());
731 }
732
733 #[test]
734 fn from_repeated_length_zero_length() {
735 let buffer = OffsetBuffer::<i32>::from_repeated_length(0, 5);
737 assert_eq!(buffer.as_ref(), &[0, 0, 0, 0, 0, 0]);
738
739 let lengths: Vec<usize> = buffer.lengths().collect();
741 assert_eq!(lengths, vec![0, 0, 0, 0, 0]);
742 }
743
744 #[test]
745 fn from_repeated_length_large_values() {
746 let buffer = OffsetBuffer::<i32>::from_repeated_length(1000, 100);
748 assert_eq!(buffer[0], 0);
749
750 let lengths: Vec<usize> = buffer.lengths().collect();
752 assert_eq!(lengths.len(), 100);
753 assert!(lengths.iter().all(|&len| len == 1000));
754 }
755
756 #[test]
757 fn from_repeated_length_unit_length() {
758 let buffer = OffsetBuffer::<i32>::from_repeated_length(1, 10);
760 assert_eq!(buffer.as_ref(), &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
761
762 let lengths: Vec<usize> = buffer.lengths().collect();
763 assert_eq!(lengths, vec![1; 10]);
764 }
765
766 #[test]
767 fn from_repeated_length_max_safe_values() {
768 let third_max = (i32::MAX / 3) as usize;
771 let buffer = OffsetBuffer::<i32>::from_repeated_length(third_max, 2);
772 assert_eq!(
773 buffer.as_ref(),
774 &[0, third_max as i32, (third_max * 2) as i32]
775 );
776 }
777
778 #[test]
783 fn has_non_empty_nulls_none_null_buffer() {
784 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 5, 8]));
786 assert!(!offsets.has_non_empty_nulls(None));
787 }
788
789 #[test]
790 fn has_non_empty_nulls_all_valid() {
791 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 5, 8]));
793 let nulls = NullBuffer::new_valid(3);
794 assert!(!offsets.has_non_empty_nulls(Some(&nulls)));
795 }
796
797 #[test]
798 fn has_non_empty_nulls_all_null_empty_offsets() {
799 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 0, 0, 0]));
801 let nulls = NullBuffer::new_null(3);
802 assert!(!offsets.has_non_empty_nulls(Some(&nulls)));
803 }
804
805 #[test]
806 fn has_non_empty_nulls_all_null_non_empty_offsets() {
807 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 2, 5, 7]));
809 let nulls = NullBuffer::new_null(3);
810 assert!(offsets.has_non_empty_nulls(Some(&nulls)));
811 }
812
813 #[test]
814 fn has_non_empty_nulls_all_null_nonzero_but_equal_offsets() {
815 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![5, 5, 5]));
817 let nulls = NullBuffer::new_null(2);
818 assert!(!offsets.has_non_empty_nulls(Some(&nulls)));
819 }
820
821 #[test]
822 fn has_non_empty_nulls_leading_nulls_with_data() {
823 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 5, 8]));
827 let nulls = NullBuffer::from(vec![false, true, true]);
828 assert!(offsets.has_non_empty_nulls(Some(&nulls)));
829 }
830
831 #[test]
832 fn has_non_empty_nulls_leading_nulls_without_data() {
833 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 0, 3, 6]));
837 let nulls = NullBuffer::from(vec![false, true, true]);
838 assert!(!offsets.has_non_empty_nulls(Some(&nulls)));
839 }
840
841 #[test]
842 fn has_non_empty_nulls_only_trailing_null_has_data() {
843 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 0, 3, 6, 8]));
847 let nulls = NullBuffer::from(vec![false, true, true, false]);
848 assert!(offsets.has_non_empty_nulls(Some(&nulls)));
849 }
850
851 #[test]
852 fn has_non_empty_nulls_trailing_nulls_without_data() {
853 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 6, 6]));
857 let nulls = NullBuffer::from(vec![true, true, false]);
858 assert!(!offsets.has_non_empty_nulls(Some(&nulls)));
859 }
860
861 #[test]
862 fn has_non_empty_nulls_middle_nulls_with_data() {
863 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 7, 10]));
867 let nulls = NullBuffer::from(vec![true, false, true]);
868 assert!(offsets.has_non_empty_nulls(Some(&nulls)));
869 }
870
871 #[test]
872 fn has_non_empty_nulls_middle_nulls_without_data() {
873 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 3, 6]));
877 let nulls = NullBuffer::from(vec![true, false, true]);
878 assert!(!offsets.has_non_empty_nulls(Some(&nulls)));
879 }
880
881 #[test]
882 fn has_non_empty_nulls_alternating_null_valid_all_empty() {
883 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 0, 3, 3, 6, 6]));
887 let nulls = NullBuffer::from(vec![false, true, false, true, false]);
888 assert!(!offsets.has_non_empty_nulls(Some(&nulls)));
889
890 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 0, 3, 3, 6, 6, 9]));
892 let nulls = NullBuffer::from(vec![false, true, false, true, false, true]);
893 assert!(!offsets.has_non_empty_nulls(Some(&nulls)));
894 }
895
896 #[test]
897 fn has_non_empty_nulls_multiple_null_regions_second_has_data() {
898 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 0, 3, 5, 6]));
902 let nulls = NullBuffer::from(vec![false, true, false, true]);
903 assert!(offsets.has_non_empty_nulls(Some(&nulls)));
904 }
905
906 #[test]
907 fn has_non_empty_nulls_multiple_null_regions_later_gap_has_data() {
908 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 0, 3, 3, 6, 8, 10]));
915 let nulls = NullBuffer::from(vec![false, true, false, true, false, true]);
916 assert!(offsets.has_non_empty_nulls(Some(&nulls)));
917 }
918
919 #[test]
920 fn has_non_empty_nulls_single_element_null_empty() {
921 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 0]));
923 let nulls = NullBuffer::new_null(1);
924 assert!(!offsets.has_non_empty_nulls(Some(&nulls)));
925 }
926
927 #[test]
928 fn has_non_empty_nulls_single_element_null_non_empty() {
929 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 5]));
931 let nulls = NullBuffer::new_null(1);
932 assert!(offsets.has_non_empty_nulls(Some(&nulls)));
933 }
934
935 #[test]
936 fn has_non_empty_nulls_single_element_valid() {
937 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 5]));
939 let nulls = NullBuffer::new_valid(1);
940 assert!(!offsets.has_non_empty_nulls(Some(&nulls)));
941 }
942
943 #[test]
944 fn has_non_empty_nulls_consecutive_nulls_between_valid_slices() {
945 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 2, 2, 2, 5, 8]));
950 let nulls = NullBuffer::from(vec![true, false, false, true, true]);
951 assert!(!offsets.has_non_empty_nulls(Some(&nulls)));
952 }
953
954 #[test]
955 fn has_non_empty_nulls_consecutive_nulls_between_valid_slices_with_data() {
956 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 2, 3, 4, 5, 8]));
963 let nulls = NullBuffer::from(vec![true, false, false, true, true]);
964 assert!(offsets.has_non_empty_nulls(Some(&nulls)));
965 }
966
967 #[test]
968 fn has_non_empty_nulls_nonzero_initial_offset_all_null_equal() {
969 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![10, 10, 10]));
971 let nulls = NullBuffer::new_null(2);
972 assert!(!offsets.has_non_empty_nulls(Some(&nulls)));
973 }
974
975 #[test]
976 fn has_non_empty_nulls_nonzero_initial_offset_with_data() {
977 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![10, 15, 20]));
981 let nulls = NullBuffer::from(vec![false, true]);
982 assert!(offsets.has_non_empty_nulls(Some(&nulls)));
983 }
984
985 #[test]
986 fn has_non_empty_nulls_sliced_no_nulls_in_null_region() {
987 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 3, 6, 6, 9]));
991 let sliced = offsets.slice(1, 3);
992 let nulls = NullBuffer::from(vec![false, true, false]);
993 assert!(!sliced.has_non_empty_nulls(Some(&nulls)));
994 }
995
996 #[test]
997 fn has_non_empty_nulls_sliced_null_has_data() {
998 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 7, 10, 15]));
1002 let sliced = offsets.slice(1, 2);
1003 let nulls = NullBuffer::from(vec![false, true]);
1004 assert!(sliced.has_non_empty_nulls(Some(&nulls)));
1005 }
1006
1007 #[test]
1008 #[should_panic(
1009 expected = "The length of the offsets should be 1 more than the length of the null buffer"
1010 )]
1011 fn has_non_empty_nulls_all_valid_mismatched_lengths_too_short() {
1012 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 5, 8]));
1014 let nulls = NullBuffer::new_valid(2); offsets.has_non_empty_nulls(Some(&nulls));
1016 }
1017
1018 #[test]
1019 #[should_panic(
1020 expected = "The length of the offsets should be 1 more than the length of the null buffer"
1021 )]
1022 fn has_non_empty_nulls_all_valid_mismatched_lengths_too_long() {
1023 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 5, 8]));
1025 let nulls = NullBuffer::new_valid(5); offsets.has_non_empty_nulls(Some(&nulls));
1027 }
1028
1029 #[test]
1030 #[should_panic(expected = "shifted offsets will become negative which is not allowed")]
1031 fn should_panic_for_subtract_by_value_that_will_cause_offsets_to_be_less_than_zero() {
1032 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 6]));
1034 offsets.subtract(1);
1035 }
1036
1037 #[test]
1038 fn subtract_by_value_that_will_cause_offsets_to_be_less_than_zero_for_outside_the_slice() {
1039 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 1, 4, 7]));
1040 let sliced = offsets.slice(1, 2); drop(offsets);
1042 assert_eq!(sliced.as_ref(), &[1, 4, 7]);
1043
1044 let result = sliced.subtract(1);
1045 assert_eq!(result.as_ref(), &[0, 3, 6]);
1046 assert_eq!(result.len(), 3);
1047 }
1048
1049 #[test]
1050 #[should_panic(expected = "must not overflow")]
1051 fn should_panic_subtract_by_value_that_will_cause_offsets_to_overflow() {
1052 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 5, i32::MAX]));
1055 offsets.subtract(-1);
1056 }
1057
1058 #[test]
1059 fn subtract_by_value_that_will_cause_offsets_to_overflow_outside_the_slice() {
1060 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 6, i32::MAX]));
1061 let sliced = offsets.slice(0, 2); assert_eq!(sliced.as_ref(), &[0, 3, 6]);
1063
1064 let result = sliced.subtract(-1);
1065 assert_eq!(result.as_ref(), &[1, 4, 7]);
1066 assert_eq!(result.len(), 3);
1067 }
1068
1069 #[test]
1070 fn when_shift_is_0_subtract_should_reuse_the_buffer_even_when_it_is_shared() {
1071 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 6]));
1074 let shared = offsets.clone(); let result = offsets.subtract(0);
1076 assert!(
1077 result.ptr_eq(&shared),
1078 "subtract(0) must return the same underlying buffer, even when shared"
1079 );
1080 }
1081
1082 #[test]
1083 fn should_reuse_the_underline_data_when_the_buffer_is_not_shared() {
1084 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![2, 5, 8]));
1087 let ptr_before = offsets.as_ptr();
1088 let result = offsets.subtract(2);
1089 assert_eq!(
1090 ptr_before,
1091 result.as_ptr(),
1092 "a non-shared buffer should be mutated in place, reusing the allocation"
1093 );
1094 assert_eq!(result.as_ref(), &[0, 3, 6]);
1095 }
1096
1097 #[test]
1098 fn should_create_a_new_buffer_when_the_buffer_is_shared() {
1099 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![2, 5, 8]));
1100 let shared = offsets.clone();
1101 let ptr_before = offsets.as_ptr();
1102 let result = offsets.subtract(2);
1103 assert_ne!(
1104 ptr_before,
1105 result.as_ptr(),
1106 "a shared buffer must not be mutated in place; a new allocation is created"
1107 );
1108 assert_eq!(result.as_ref(), &[0, 3, 6]);
1109 assert_eq!(shared.as_ref(), &[2, 5, 8]);
1111 }
1112
1113 #[test]
1114 fn when_shift_is_negative_it_should_shift_offsets_in_the_right_direction() {
1115 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 6]));
1117 let result = offsets.subtract(-2);
1118 assert_eq!(result.as_ref(), &[2, 5, 8]);
1119 }
1120
1121 #[test]
1123 fn for_sliced_unshared_buffer_shift_should_not_reuse_buffer() {
1124 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![1, 3, 6, 9, 12]));
1126 let sliced = offsets.slice(1, 2); drop(offsets); assert_eq!(sliced.as_ref(), &[3, 6, 9]);
1129
1130 let ptr_before = sliced.as_ptr();
1131 let result = sliced.subtract(1);
1132
1133 assert_ne!(
1134 ptr_before,
1135 result.as_ptr(),
1136 "should not be reused until #10118 is merged"
1137 );
1138
1139 assert_eq!(result.as_ref(), &[2, 5, 8]);
1140 }
1141
1142 #[test]
1143 fn for_sliced_but_start_at_0_unshared_buffer_shift_should_reuse_buffer() {
1144 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![1, 3, 6, 9, 12]));
1145 let sliced = offsets.slice(0, 2);
1146 drop(offsets); assert_eq!(sliced.as_ref(), &[1, 3, 6]);
1148
1149 let ptr_before = sliced.as_ptr();
1150 let result = sliced.subtract(1);
1151
1152 assert_eq!(ptr_before, result.as_ptr(), "should be reused");
1153
1154 assert_eq!(result.as_ref(), &[0, 2, 5]);
1155 }
1156
1157 #[test]
1158 fn for_sliced_shared_buffer_shifted_buffer_should_only_include_the_sliced_data() {
1159 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 6, 9, 12]));
1164 let sliced = offsets.slice(1, 2);
1165 assert_eq!(sliced.as_ref(), &[3, 6, 9]);
1166
1167 let result = sliced.subtract(3);
1168
1169 assert_eq!(
1170 result.as_ref(),
1171 &[0, 3, 6],
1172 "shifted result should contain only the sliced data"
1173 );
1174 assert_eq!(result.len(), 3);
1175
1176 let underlying_buffer = result.inner().inner();
1178 assert_eq!(underlying_buffer.ptr_offset(), 0);
1179 assert_eq!(underlying_buffer.len(), 3 * std::mem::size_of::<i32>());
1180 }
1181}