1use crate::buffer::ScalarBuffer;
19use crate::{ArrowNativeType, MutableBuffer, NullBuffer, OffsetBufferBuilder};
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 {
103 let len_bytes = len
104 .checked_add(1)
105 .and_then(|o| o.checked_mul(std::mem::size_of::<O>()))
106 .expect("overflow");
107 let buffer = MutableBuffer::from_len_zeroed(len_bytes);
108 Self(buffer.into_buffer().into())
109 }
110
111 pub fn from_lengths<I>(lengths: I) -> Self
126 where
127 I: IntoIterator<Item = usize>,
128 {
129 let iter = lengths.into_iter();
130 let mut out = Vec::with_capacity(iter.size_hint().0 + 1);
131 out.push(O::usize_as(0));
132
133 let mut acc = 0_usize;
134 for length in iter {
135 acc = acc.checked_add(length).expect("usize overflow");
136 out.push(O::usize_as(acc))
137 }
138 O::from_usize(acc).expect("offset overflow");
140 Self(out.into())
141 }
142
143 pub fn from_repeated_length(length: usize, n: usize) -> Self {
158 if n == 0 {
159 return Self::new_empty();
160 }
161
162 if length == 0 {
163 return Self::new_zeroed(n);
164 }
165
166 length.checked_mul(n).expect("usize overflow");
169
170 O::from_usize(length * n).expect("offset overflow");
172
173 let offsets = (0..=n)
174 .map(|index| O::usize_as(index * length))
175 .collect::<Vec<O>>();
176
177 Self(ScalarBuffer::from(offsets))
178 }
179
180 #[inline]
191 pub fn first(&self) -> O {
192 self.0
193 .first()
194 .copied()
195 .expect("An `OffsetBuffer` is never empty")
196 }
197
198 #[inline]
209 pub fn last(&self) -> O {
210 self.0
211 .last()
212 .copied()
213 .expect("An `OffsetBuffer` is never empty")
214 }
215
216 pub fn lengths(&self) -> impl ExactSizeIterator<Item = usize> + '_ {
245 self.0.windows(2).map(|x| x[1].as_usize() - x[0].as_usize())
246 }
247
248 pub fn shrink_to_fit(&mut self) {
250 self.0.shrink_to_fit();
251 }
252
253 pub fn inner(&self) -> &ScalarBuffer<O> {
255 &self.0
256 }
257
258 pub fn into_inner(self) -> ScalarBuffer<O> {
260 self.0
261 }
262
263 #[cfg(feature = "pool")]
265 pub fn claim(&self, pool: &dyn crate::MemoryPool) {
266 self.0.claim(pool);
267 }
268
269 pub fn slice(&self, offset: usize, len: usize) -> Self {
275 Self(self.0.slice(offset, len.saturating_add(1)))
276 }
277
278 #[inline]
282 pub fn ptr_eq(&self, other: &Self) -> bool {
283 self.0.ptr_eq(&other.0)
284 }
285
286 pub fn has_non_empty_nulls(&self, null_buffer: Option<&NullBuffer>) -> bool {
322 let Some(null_buffer) = null_buffer else {
323 return false;
324 };
325
326 assert_eq!(
327 self.len() - 1,
328 null_buffer.len(),
329 "The length of the offsets should be 1 more than the length of the null buffer"
330 );
331
332 if null_buffer.null_count() == 0 {
333 return false;
334 }
335
336 let initial_offset = self[0];
338 let last_offset = self[self.len() - 1];
339
340 if null_buffer.null_count() == self.len() - 1 {
342 return last_offset != initial_offset;
343 }
344
345 let mut valid_slices_iter = null_buffer.valid_slices();
346
347 let (start, end) = valid_slices_iter.next().unwrap();
349
350 if self[start] != initial_offset {
352 return true;
353 }
354
355 let mut end_offset_of_last_valid_value = self[end];
358
359 for (start, end) in valid_slices_iter {
360 if self[start] != end_offset_of_last_valid_value {
363 return true;
364 }
365
366 end_offset_of_last_valid_value = self[end];
369 }
370
371 end_offset_of_last_valid_value != last_offset
372 }
373
374 pub fn subtract(self, rhs: O) -> Self
396 where
397 O: std::ops::Sub<Output = O> + std::cmp::PartialOrd + num_traits::CheckedSub,
398 {
399 if rhs == O::usize_as(0) {
400 return self;
401 }
402
403 let len = self.len();
404
405 assert!(
407 self[0] >= rhs,
408 "shifted offsets will become negative which is not allowed"
409 );
410
411 if rhs < O::usize_as(0) {
413 self[len - 1].checked_sub(&rhs).expect("must not overflow");
414 }
415
416 let shifted_offsets: Vec<O> = match self.into_inner().into_inner().into_vec() {
418 Ok(mut v) => {
420 for offset in &mut v {
421 *offset = *offset - rhs;
422 }
423 v
424 }
425 Err(buffer) => {
427 let offsets = ScalarBuffer::<O>::from(buffer);
428 offsets.iter().map(|offset| *offset - rhs).collect()
429 }
430 };
431 let shifted_buffer = ScalarBuffer::from(shifted_offsets);
432 unsafe { Self::new_unchecked(shifted_buffer) }
437 }
438}
439
440impl<T: ArrowNativeType> Deref for OffsetBuffer<T> {
441 type Target = [T];
442
443 #[inline]
444 fn deref(&self) -> &Self::Target {
445 &self.0
446 }
447}
448
449impl<T: ArrowNativeType> AsRef<[T]> for OffsetBuffer<T> {
450 #[inline]
451 fn as_ref(&self) -> &[T] {
452 self
453 }
454}
455
456impl<O: ArrowNativeType> From<OffsetBufferBuilder<O>> for OffsetBuffer<O> {
457 fn from(value: OffsetBufferBuilder<O>) -> Self {
458 value.finish()
459 }
460}
461
462impl<O: ArrowNativeType> Default for OffsetBuffer<O> {
463 fn default() -> Self {
464 Self::new_empty()
465 }
466}
467
468#[cfg(test)]
469mod tests {
470 use super::*;
471
472 #[test]
473 #[should_panic(expected = "offsets cannot be empty")]
474 fn empty_offsets() {
475 OffsetBuffer::new(Vec::<i32>::new().into());
476 }
477
478 #[test]
479 #[should_panic(expected = "offsets must be greater than 0")]
480 fn negative_offsets() {
481 OffsetBuffer::new(vec![-1, 0, 1].into());
482 }
483
484 #[test]
485 fn offsets() {
486 OffsetBuffer::new(vec![0, 1, 2, 3].into());
487
488 let offsets = OffsetBuffer::<i32>::new_zeroed(3);
489 assert_eq!(offsets.as_ref(), &[0; 4]);
490
491 let offsets = OffsetBuffer::<i32>::new_zeroed(0);
492 assert_eq!(offsets.as_ref(), &[0; 1]);
493 }
494
495 #[test]
496 #[should_panic(expected = "overflow")]
497 fn offsets_new_zeroed_overflow() {
498 OffsetBuffer::<i32>::new_zeroed(usize::MAX);
499 }
500
501 #[test]
502 #[should_panic(expected = "offsets must be monotonically increasing")]
503 fn non_monotonic_offsets() {
504 OffsetBuffer::new(vec![1, 2, 0].into());
505 }
506
507 #[test]
508 fn from_lengths() {
509 let buffer = OffsetBuffer::<i32>::from_lengths([2, 6, 3, 7, 2]);
510 assert_eq!(buffer.as_ref(), &[0, 2, 8, 11, 18, 20]);
511
512 let half_max = i32::MAX / 2;
513 let buffer = OffsetBuffer::<i32>::from_lengths([half_max as usize, half_max as usize]);
514 assert_eq!(buffer.as_ref(), &[0, half_max, half_max * 2]);
515 }
516
517 #[test]
518 #[should_panic(expected = "offset overflow")]
519 fn from_lengths_offset_overflow() {
520 OffsetBuffer::<i32>::from_lengths([i32::MAX as usize, 1]);
521 }
522
523 #[test]
524 #[should_panic(expected = "usize overflow")]
525 fn from_lengths_usize_overflow() {
526 OffsetBuffer::<i32>::from_lengths([usize::MAX, 1]);
527 }
528
529 #[test]
530 #[should_panic(expected = "offset overflow")]
531 fn from_repeated_lengths_offset_length_overflow() {
532 OffsetBuffer::<i32>::from_repeated_length(i32::MAX as usize / 4, 5);
533 }
534
535 #[test]
536 #[should_panic(expected = "offset overflow")]
537 fn from_repeated_lengths_offset_repeat_overflow() {
538 OffsetBuffer::<i32>::from_repeated_length(1, i32::MAX as usize + 1);
539 }
540
541 #[test]
542 #[should_panic(expected = "offset overflow")]
543 fn from_repeated_lengths_usize_length_overflow() {
544 OffsetBuffer::<i32>::from_repeated_length(usize::MAX, 1);
545 }
546
547 #[test]
548 #[should_panic(expected = "usize overflow")]
549 fn from_repeated_lengths_usize_length_usize_overflow() {
550 OffsetBuffer::<i32>::from_repeated_length(usize::MAX, 2);
551 }
552
553 #[test]
554 #[should_panic(expected = "offset overflow")]
555 fn from_repeated_lengths_usize_repeat_overflow() {
556 OffsetBuffer::<i32>::from_repeated_length(1, usize::MAX);
557 }
558
559 #[test]
560 fn get_lengths() {
561 let offsets = OffsetBuffer::<i32>::new(ScalarBuffer::<i32>::from(vec![0, 1, 4, 9]));
562 assert_eq!(offsets.lengths().collect::<Vec<usize>>(), vec![1, 3, 5]);
563 }
564
565 #[test]
566 fn get_lengths_should_be_with_fixed_size() {
567 let offsets = OffsetBuffer::<i32>::new(ScalarBuffer::<i32>::from(vec![0, 1, 4, 9]));
568 let iter = offsets.lengths();
569 assert_eq!(iter.size_hint(), (3, Some(3)));
570 assert_eq!(iter.len(), 3);
571 }
572
573 #[test]
574 fn get_lengths_from_empty_offset_buffer_should_be_empty_iterator() {
575 let offsets = OffsetBuffer::<i32>::new_empty();
576 assert_eq!(offsets.lengths().collect::<Vec<usize>>(), vec![]);
577 }
578
579 #[test]
580 fn impl_eq() {
581 fn are_equal<T: Eq>(a: &T, b: &T) -> bool {
582 a.eq(b)
583 }
584
585 assert!(
586 are_equal(
587 &OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 1, 4, 9])),
588 &OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 1, 4, 9]))
589 ),
590 "OffsetBuffer should implement Eq."
591 );
592 }
593
594 #[test]
595 fn impl_default() {
596 let default = OffsetBuffer::<i32>::default();
597 assert_eq!(default.as_ref(), &[0]);
598 }
599
600 #[test]
601 fn from_repeated_length_basic() {
602 let buffer = OffsetBuffer::<i32>::from_repeated_length(4, 3);
604 assert_eq!(buffer.as_ref(), &[0, 4, 8, 12]);
605
606 let lengths: Vec<usize> = buffer.lengths().collect();
608 assert_eq!(lengths, vec![4, 4, 4]);
609 }
610
611 #[test]
612 fn from_repeated_length_single_repeat() {
613 let buffer = OffsetBuffer::<i32>::from_repeated_length(5, 1);
615 assert_eq!(buffer.as_ref(), &[0, 5]);
616
617 let lengths: Vec<usize> = buffer.lengths().collect();
618 assert_eq!(lengths, vec![5]);
619 }
620
621 #[test]
622 fn from_repeated_length_zero_repeats() {
623 let buffer = OffsetBuffer::<i32>::from_repeated_length(10, 0);
624 assert_eq!(buffer, OffsetBuffer::<i32>::new_empty());
625 }
626
627 #[test]
628 fn from_repeated_length_zero_length() {
629 let buffer = OffsetBuffer::<i32>::from_repeated_length(0, 5);
631 assert_eq!(buffer.as_ref(), &[0, 0, 0, 0, 0, 0]);
632
633 let lengths: Vec<usize> = buffer.lengths().collect();
635 assert_eq!(lengths, vec![0, 0, 0, 0, 0]);
636 }
637
638 #[test]
639 fn from_repeated_length_large_values() {
640 let buffer = OffsetBuffer::<i32>::from_repeated_length(1000, 100);
642 assert_eq!(buffer[0], 0);
643
644 let lengths: Vec<usize> = buffer.lengths().collect();
646 assert_eq!(lengths.len(), 100);
647 assert!(lengths.iter().all(|&len| len == 1000));
648 }
649
650 #[test]
651 fn from_repeated_length_unit_length() {
652 let buffer = OffsetBuffer::<i32>::from_repeated_length(1, 10);
654 assert_eq!(buffer.as_ref(), &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
655
656 let lengths: Vec<usize> = buffer.lengths().collect();
657 assert_eq!(lengths, vec![1; 10]);
658 }
659
660 #[test]
661 fn from_repeated_length_max_safe_values() {
662 let third_max = (i32::MAX / 3) as usize;
665 let buffer = OffsetBuffer::<i32>::from_repeated_length(third_max, 2);
666 assert_eq!(
667 buffer.as_ref(),
668 &[0, third_max as i32, (third_max * 2) as i32]
669 );
670 }
671
672 #[test]
677 fn has_non_empty_nulls_none_null_buffer() {
678 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 5, 8]));
680 assert!(!offsets.has_non_empty_nulls(None));
681 }
682
683 #[test]
684 fn has_non_empty_nulls_all_valid() {
685 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 5, 8]));
687 let nulls = NullBuffer::new_valid(3);
688 assert!(!offsets.has_non_empty_nulls(Some(&nulls)));
689 }
690
691 #[test]
692 fn has_non_empty_nulls_all_null_empty_offsets() {
693 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 0, 0, 0]));
695 let nulls = NullBuffer::new_null(3);
696 assert!(!offsets.has_non_empty_nulls(Some(&nulls)));
697 }
698
699 #[test]
700 fn has_non_empty_nulls_all_null_non_empty_offsets() {
701 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 2, 5, 7]));
703 let nulls = NullBuffer::new_null(3);
704 assert!(offsets.has_non_empty_nulls(Some(&nulls)));
705 }
706
707 #[test]
708 fn has_non_empty_nulls_all_null_nonzero_but_equal_offsets() {
709 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![5, 5, 5]));
711 let nulls = NullBuffer::new_null(2);
712 assert!(!offsets.has_non_empty_nulls(Some(&nulls)));
713 }
714
715 #[test]
716 fn has_non_empty_nulls_leading_nulls_with_data() {
717 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 5, 8]));
721 let nulls = NullBuffer::from(vec![false, true, true]);
722 assert!(offsets.has_non_empty_nulls(Some(&nulls)));
723 }
724
725 #[test]
726 fn has_non_empty_nulls_leading_nulls_without_data() {
727 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 0, 3, 6]));
731 let nulls = NullBuffer::from(vec![false, true, true]);
732 assert!(!offsets.has_non_empty_nulls(Some(&nulls)));
733 }
734
735 #[test]
736 fn has_non_empty_nulls_only_trailing_null_has_data() {
737 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 0, 3, 6, 8]));
741 let nulls = NullBuffer::from(vec![false, true, true, false]);
742 assert!(offsets.has_non_empty_nulls(Some(&nulls)));
743 }
744
745 #[test]
746 fn has_non_empty_nulls_trailing_nulls_without_data() {
747 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 6, 6]));
751 let nulls = NullBuffer::from(vec![true, true, false]);
752 assert!(!offsets.has_non_empty_nulls(Some(&nulls)));
753 }
754
755 #[test]
756 fn has_non_empty_nulls_middle_nulls_with_data() {
757 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 7, 10]));
761 let nulls = NullBuffer::from(vec![true, false, true]);
762 assert!(offsets.has_non_empty_nulls(Some(&nulls)));
763 }
764
765 #[test]
766 fn has_non_empty_nulls_middle_nulls_without_data() {
767 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 3, 6]));
771 let nulls = NullBuffer::from(vec![true, false, true]);
772 assert!(!offsets.has_non_empty_nulls(Some(&nulls)));
773 }
774
775 #[test]
776 fn has_non_empty_nulls_alternating_null_valid_all_empty() {
777 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 0, 3, 3, 6, 6]));
781 let nulls = NullBuffer::from(vec![false, true, false, true, false]);
782 assert!(!offsets.has_non_empty_nulls(Some(&nulls)));
783
784 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 0, 3, 3, 6, 6, 9]));
786 let nulls = NullBuffer::from(vec![false, true, false, true, false, true]);
787 assert!(!offsets.has_non_empty_nulls(Some(&nulls)));
788 }
789
790 #[test]
791 fn has_non_empty_nulls_multiple_null_regions_second_has_data() {
792 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 0, 3, 5, 6]));
796 let nulls = NullBuffer::from(vec![false, true, false, true]);
797 assert!(offsets.has_non_empty_nulls(Some(&nulls)));
798 }
799
800 #[test]
801 fn has_non_empty_nulls_multiple_null_regions_later_gap_has_data() {
802 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 0, 3, 3, 6, 8, 10]));
809 let nulls = NullBuffer::from(vec![false, true, false, true, false, true]);
810 assert!(offsets.has_non_empty_nulls(Some(&nulls)));
811 }
812
813 #[test]
814 fn has_non_empty_nulls_single_element_null_empty() {
815 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 0]));
817 let nulls = NullBuffer::new_null(1);
818 assert!(!offsets.has_non_empty_nulls(Some(&nulls)));
819 }
820
821 #[test]
822 fn has_non_empty_nulls_single_element_null_non_empty() {
823 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 5]));
825 let nulls = NullBuffer::new_null(1);
826 assert!(offsets.has_non_empty_nulls(Some(&nulls)));
827 }
828
829 #[test]
830 fn has_non_empty_nulls_single_element_valid() {
831 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 5]));
833 let nulls = NullBuffer::new_valid(1);
834 assert!(!offsets.has_non_empty_nulls(Some(&nulls)));
835 }
836
837 #[test]
838 fn has_non_empty_nulls_consecutive_nulls_between_valid_slices() {
839 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 2, 2, 2, 5, 8]));
844 let nulls = NullBuffer::from(vec![true, false, false, true, true]);
845 assert!(!offsets.has_non_empty_nulls(Some(&nulls)));
846 }
847
848 #[test]
849 fn has_non_empty_nulls_consecutive_nulls_between_valid_slices_with_data() {
850 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 2, 3, 4, 5, 8]));
857 let nulls = NullBuffer::from(vec![true, false, false, true, true]);
858 assert!(offsets.has_non_empty_nulls(Some(&nulls)));
859 }
860
861 #[test]
862 fn has_non_empty_nulls_nonzero_initial_offset_all_null_equal() {
863 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![10, 10, 10]));
865 let nulls = NullBuffer::new_null(2);
866 assert!(!offsets.has_non_empty_nulls(Some(&nulls)));
867 }
868
869 #[test]
870 fn has_non_empty_nulls_nonzero_initial_offset_with_data() {
871 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![10, 15, 20]));
875 let nulls = NullBuffer::from(vec![false, true]);
876 assert!(offsets.has_non_empty_nulls(Some(&nulls)));
877 }
878
879 #[test]
880 fn has_non_empty_nulls_sliced_no_nulls_in_null_region() {
881 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 3, 6, 6, 9]));
885 let sliced = offsets.slice(1, 3);
886 let nulls = NullBuffer::from(vec![false, true, false]);
887 assert!(!sliced.has_non_empty_nulls(Some(&nulls)));
888 }
889
890 #[test]
891 fn has_non_empty_nulls_sliced_null_has_data() {
892 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 7, 10, 15]));
896 let sliced = offsets.slice(1, 2);
897 let nulls = NullBuffer::from(vec![false, true]);
898 assert!(sliced.has_non_empty_nulls(Some(&nulls)));
899 }
900
901 #[test]
902 #[should_panic(
903 expected = "The length of the offsets should be 1 more than the length of the null buffer"
904 )]
905 fn has_non_empty_nulls_all_valid_mismatched_lengths_too_short() {
906 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 5, 8]));
908 let nulls = NullBuffer::new_valid(2); offsets.has_non_empty_nulls(Some(&nulls));
910 }
911
912 #[test]
913 #[should_panic(
914 expected = "The length of the offsets should be 1 more than the length of the null buffer"
915 )]
916 fn has_non_empty_nulls_all_valid_mismatched_lengths_too_long() {
917 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 5, 8]));
919 let nulls = NullBuffer::new_valid(5); offsets.has_non_empty_nulls(Some(&nulls));
921 }
922
923 #[test]
924 #[should_panic(expected = "shifted offsets will become negative which is not allowed")]
925 fn should_panic_for_subtract_by_value_that_will_cause_offsets_to_be_less_than_zero() {
926 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 6]));
928 offsets.subtract(1);
929 }
930
931 #[test]
932 fn subtract_by_value_that_will_cause_offsets_to_be_less_than_zero_for_outside_the_slice() {
933 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 1, 4, 7]));
934 let sliced = offsets.slice(1, 2); drop(offsets);
936 assert_eq!(sliced.as_ref(), &[1, 4, 7]);
937
938 let result = sliced.subtract(1);
939 assert_eq!(result.as_ref(), &[0, 3, 6]);
940 assert_eq!(result.len(), 3);
941 }
942
943 #[test]
944 #[should_panic(expected = "must not overflow")]
945 fn should_panic_subtract_by_value_that_will_cause_offsets_to_overflow() {
946 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 5, i32::MAX]));
949 offsets.subtract(-1);
950 }
951
952 #[test]
953 fn subtract_by_value_that_will_cause_offsets_to_overflow_outside_the_slice() {
954 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 6, i32::MAX]));
955 let sliced = offsets.slice(0, 2); assert_eq!(sliced.as_ref(), &[0, 3, 6]);
957
958 let result = sliced.subtract(-1);
959 assert_eq!(result.as_ref(), &[1, 4, 7]);
960 assert_eq!(result.len(), 3);
961 }
962
963 #[test]
964 fn when_shift_is_0_subtract_should_reuse_the_buffer_even_when_it_is_shared() {
965 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 6]));
968 let shared = offsets.clone(); let result = offsets.subtract(0);
970 assert!(
971 result.ptr_eq(&shared),
972 "subtract(0) must return the same underlying buffer, even when shared"
973 );
974 }
975
976 #[test]
977 fn should_reuse_the_underline_data_when_the_buffer_is_not_shared() {
978 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![2, 5, 8]));
981 let ptr_before = offsets.as_ptr();
982 let result = offsets.subtract(2);
983 assert_eq!(
984 ptr_before,
985 result.as_ptr(),
986 "a non-shared buffer should be mutated in place, reusing the allocation"
987 );
988 assert_eq!(result.as_ref(), &[0, 3, 6]);
989 }
990
991 #[test]
992 fn should_create_a_new_buffer_when_the_buffer_is_shared() {
993 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![2, 5, 8]));
994 let shared = offsets.clone();
995 let ptr_before = offsets.as_ptr();
996 let result = offsets.subtract(2);
997 assert_ne!(
998 ptr_before,
999 result.as_ptr(),
1000 "a shared buffer must not be mutated in place; a new allocation is created"
1001 );
1002 assert_eq!(result.as_ref(), &[0, 3, 6]);
1003 assert_eq!(shared.as_ref(), &[2, 5, 8]);
1005 }
1006
1007 #[test]
1008 fn when_shift_is_negative_it_should_shift_offsets_in_the_right_direction() {
1009 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 6]));
1011 let result = offsets.subtract(-2);
1012 assert_eq!(result.as_ref(), &[2, 5, 8]);
1013 }
1014
1015 #[test]
1017 fn for_sliced_unshared_buffer_shift_should_not_reuse_buffer() {
1018 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![1, 3, 6, 9, 12]));
1020 let sliced = offsets.slice(1, 2); drop(offsets); assert_eq!(sliced.as_ref(), &[3, 6, 9]);
1023
1024 let ptr_before = sliced.as_ptr();
1025 let result = sliced.subtract(1);
1026
1027 assert_ne!(
1028 ptr_before,
1029 result.as_ptr(),
1030 "should not be reused until #10118 is merged"
1031 );
1032
1033 assert_eq!(result.as_ref(), &[2, 5, 8]);
1034 }
1035
1036 #[test]
1037 fn for_sliced_but_start_at_0_unshared_buffer_shift_should_reuse_buffer() {
1038 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![1, 3, 6, 9, 12]));
1039 let sliced = offsets.slice(0, 2);
1040 drop(offsets); assert_eq!(sliced.as_ref(), &[1, 3, 6]);
1042
1043 let ptr_before = sliced.as_ptr();
1044 let result = sliced.subtract(1);
1045
1046 assert_eq!(ptr_before, result.as_ptr(), "should be reused");
1047
1048 assert_eq!(result.as_ref(), &[0, 2, 5]);
1049 }
1050
1051 #[test]
1052 fn for_sliced_shared_buffer_shifted_buffer_should_only_include_the_sliced_data() {
1053 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 3, 6, 9, 12]));
1058 let sliced = offsets.slice(1, 2);
1059 assert_eq!(sliced.as_ref(), &[3, 6, 9]);
1060
1061 let result = sliced.subtract(3);
1062
1063 assert_eq!(
1064 result.as_ref(),
1065 &[0, 3, 6],
1066 "shifted result should contain only the sliced data"
1067 );
1068 assert_eq!(result.len(), 3);
1069
1070 let underlying_buffer = result.inner().inner();
1072 assert_eq!(underlying_buffer.ptr_offset(), 0);
1073 assert_eq!(underlying_buffer.len(), 3 * std::mem::size_of::<i32>());
1074 }
1075}