1use crate::array::print_long_array;
19use crate::builder::{FixedSizeListBuilder, PrimitiveBuilder};
20use crate::iterator::FixedSizeListIter;
21use crate::{Array, ArrayAccessor, ArrayRef, ArrowPrimitiveType, make_array};
22use arrow_buffer::ArrowNativeType;
23use arrow_buffer::buffer::NullBuffer;
24use arrow_data::{ArrayData, ArrayDataBuilder};
25use arrow_schema::{ArrowError, DataType, FieldRef};
26use std::any::Any;
27use std::sync::Arc;
28
29#[derive(Clone)]
119pub struct FixedSizeListArray {
120 data_type: DataType, values: ArrayRef,
122 nulls: Option<NullBuffer>,
123 value_length: i32,
124 len: usize,
125}
126
127impl FixedSizeListArray {
128 pub fn new(field: FieldRef, size: i32, values: ArrayRef, nulls: Option<NullBuffer>) -> Self {
142 Self::try_new(field, size, values, nulls).unwrap()
143 }
144
145 pub unsafe fn new_unchecked(
153 field: FieldRef,
154 size: i32,
155 values: ArrayRef,
156 nulls: Option<NullBuffer>,
157 len: usize,
158 ) -> Self {
159 if cfg!(feature = "force_validate") {
160 return Self::try_new_with_length(field, size, values, nulls, len).unwrap();
161 }
162 Self {
163 data_type: DataType::FixedSizeList(field, size),
164 values,
165 value_length: size,
166 nulls,
167 len,
168 }
169 }
170
171 pub fn try_new(
188 field: FieldRef,
189 size: i32,
190 values: ArrayRef,
191 nulls: Option<NullBuffer>,
192 ) -> Result<Self, ArrowError> {
193 let s = size.to_usize().ok_or_else(|| {
194 ArrowError::InvalidArgumentError(format!("Size cannot be negative, got {size}"))
195 })?;
196
197 if s == 0 {
198 let len = nulls.as_ref().map(|x| x.len()).unwrap_or_default();
201
202 Self::try_new_with_length(field, size, values, nulls, len)
203 } else {
204 if !values.len().is_multiple_of(s) {
205 return Err(ArrowError::InvalidArgumentError(format!(
206 "Incorrect length of values buffer for FixedSizeListArray, \
207 expected a multiple of {s} got {}",
208 values.len(),
209 )));
210 }
211
212 let len = values.len() / s;
213
214 if let Some(null_buffer) = &nulls
216 && s * null_buffer.len() != values.len()
217 {
218 return Err(ArrowError::InvalidArgumentError(format!(
219 "Incorrect length of values buffer for FixedSizeListArray, \
220 expected {} got {}",
221 s * null_buffer.len(),
222 values.len(),
223 )));
224 }
225
226 Self::try_new_with_length(field, size, values, nulls, len)
227 }
228 }
229
230 pub fn try_new_with_length(
246 field: FieldRef,
247 size: i32,
248 values: ArrayRef,
249 nulls: Option<NullBuffer>,
250 len: usize,
251 ) -> Result<Self, ArrowError> {
252 let s = size.to_usize().ok_or_else(|| {
253 ArrowError::InvalidArgumentError(format!("Size cannot be negative, got {size}"))
254 })?;
255
256 if let Some(null_buffer) = &nulls
257 && null_buffer.len() != len
258 {
259 return Err(ArrowError::InvalidArgumentError(format!(
260 "Invalid null buffer for FixedSizeListArray, expected {len} found {}",
261 null_buffer.len()
262 )));
263 }
264
265 if s == 0 && !values.is_empty() {
266 return Err(ArrowError::InvalidArgumentError(format!(
267 "An degenerate FixedSizeListArray should have no underlying values, found {} values",
268 values.len()
269 )));
270 }
271
272 if values.len() != len * s {
273 return Err(ArrowError::InvalidArgumentError(format!(
274 "Incorrect length of values buffer for FixedSizeListArray, expected {} got {}",
275 len * s,
276 values.len(),
277 )));
278 }
279
280 if field.data_type() != values.data_type() {
281 return Err(ArrowError::InvalidArgumentError(format!(
282 "FixedSizeListArray expected data type {} got {} for {:?}",
283 field.data_type(),
284 values.data_type(),
285 field.name()
286 )));
287 }
288
289 if let Some(a) = values.logical_nulls() {
290 let nulls_valid = field.is_nullable()
291 || nulls
292 .as_ref()
293 .is_some_and(|n| n.expand(size as _).contains(&a))
294 || (nulls.is_none() && a.null_count() == 0);
295
296 if !nulls_valid {
297 return Err(ArrowError::InvalidArgumentError(format!(
298 "Found unmasked nulls for non-nullable FixedSizeListArray field {:?}",
299 field.name()
300 )));
301 }
302 }
303
304 let data_type = DataType::FixedSizeList(field, size);
305 Ok(Self {
306 data_type,
307 values,
308 value_length: size,
309 nulls,
310 len,
311 })
312 }
313
314 pub fn new_null(field: FieldRef, size: i32, len: usize) -> Self {
323 let capacity = size.to_usize().unwrap().checked_mul(len).unwrap();
324 Self {
325 values: make_array(ArrayData::new_null(field.data_type(), capacity)),
326 data_type: DataType::FixedSizeList(field, size),
327 nulls: Some(NullBuffer::new_null(len)),
328 value_length: size,
329 len,
330 }
331 }
332
333 pub fn into_parts(self) -> (FieldRef, i32, ArrayRef, Option<NullBuffer>) {
335 let DataType::FixedSizeList(f, _) = self.data_type else {
336 unreachable!()
337 };
338 (f, self.value_length, self.values, self.nulls)
339 }
340
341 pub fn value_field(&self) -> &FieldRef {
343 match &self.data_type {
344 DataType::FixedSizeList(f, _) => f,
345 _ => unreachable!(),
346 }
347 }
348
349 pub fn values(&self) -> &ArrayRef {
351 &self.values
352 }
353
354 pub fn value_type(&self) -> DataType {
356 self.values.data_type().clone()
357 }
358
359 pub fn value(&self, i: usize) -> ArrayRef {
367 self.values
368 .slice(self.value_offset_at(i), self.value_length() as usize)
369 }
370
371 #[deprecated(since = "60.0.0", note = "Use value_offset_at instead")]
379 #[inline]
380 pub fn value_offset(&self, i: usize) -> i32 {
381 self.value_offset_at(i) as i32
382 }
383
384 #[inline]
388 pub const fn value_length(&self) -> i32 {
389 self.value_length
390 }
391
392 #[inline]
397 pub const fn value_offset_at(&self, i: usize) -> usize {
398 i * self.value_length as usize
399 }
400
401 pub fn slice(&self, offset: usize, len: usize) -> Self {
406 assert!(
407 offset.saturating_add(len) <= self.len,
408 "the length + offset of the sliced FixedSizeListArray cannot exceed the existing length"
409 );
410 let size = self.value_length as usize;
411
412 Self {
413 data_type: self.data_type.clone(),
414 values: self.values.slice(offset * size, len * size),
415 nulls: self.nulls.as_ref().map(|n| n.slice(offset, len)),
416 value_length: self.value_length,
417 len,
418 }
419 }
420
421 pub fn from_iter_primitive<T, P, I>(iter: I, length: i32) -> Self
437 where
438 T: ArrowPrimitiveType,
439 P: IntoIterator<Item = Option<<T as ArrowPrimitiveType>::Native>>,
440 I: IntoIterator<Item = Option<P>>,
441 {
442 let l = length as usize;
443 let iter = iter.into_iter();
444 let size_hint = iter.size_hint().0;
445 let mut builder = FixedSizeListBuilder::with_capacity(
446 PrimitiveBuilder::<T>::with_capacity(size_hint * l),
447 length,
448 size_hint,
449 );
450
451 for i in iter {
452 match i {
453 Some(p) => {
454 for t in p {
455 builder.values().append_option(t);
456 }
457 builder.append(true);
458 }
459 None => {
460 builder.values().append_nulls(l);
461 builder.append(false)
462 }
463 }
464 }
465 builder.finish()
466 }
467
468 pub fn iter(&self) -> FixedSizeListIter<'_> {
470 FixedSizeListIter::new(self)
471 }
472}
473
474impl<'a> IntoIterator for &'a FixedSizeListArray {
475 type Item = Option<ArrayRef>;
476 type IntoIter = FixedSizeListIter<'a>;
477
478 fn into_iter(self) -> Self::IntoIter {
479 FixedSizeListIter::new(self)
480 }
481}
482
483impl From<ArrayData> for FixedSizeListArray {
484 fn from(data: ArrayData) -> Self {
485 let (data_type, len, nulls, offset, _buffers, child_data) = data.into_parts();
486
487 let value_length = match data_type {
488 DataType::FixedSizeList(_, len) => len,
489 data_type => {
490 panic!(
491 "FixedSizeListArray data should contain a FixedSizeList data type, got {data_type}"
492 )
493 }
494 };
495
496 let size = value_length as usize;
497 let values = make_array(child_data[0].slice(offset * size, len * size));
498 Self {
499 data_type,
500 values,
501 nulls,
502 value_length,
503 len,
504 }
505 }
506}
507
508impl From<FixedSizeListArray> for ArrayData {
509 fn from(array: FixedSizeListArray) -> Self {
510 let builder = ArrayDataBuilder::new(array.data_type)
511 .len(array.len)
512 .nulls(array.nulls)
513 .child_data(vec![array.values.to_data()]);
514
515 unsafe { builder.build_unchecked() }
516 }
517}
518
519unsafe impl Array for FixedSizeListArray {
521 fn as_any(&self) -> &dyn Any {
522 self
523 }
524
525 fn to_data(&self) -> ArrayData {
526 self.clone().into()
527 }
528
529 fn into_data(self) -> ArrayData {
530 self.into()
531 }
532
533 fn data_type(&self) -> &DataType {
534 &self.data_type
535 }
536
537 fn slice(&self, offset: usize, length: usize) -> ArrayRef {
538 Arc::new(self.slice(offset, length))
539 }
540
541 fn len(&self) -> usize {
542 self.len
543 }
544
545 fn is_empty(&self) -> bool {
546 self.len == 0
547 }
548
549 fn shrink_to_fit(&mut self) {
550 self.values.shrink_to_fit();
551 if let Some(nulls) = &mut self.nulls {
552 nulls.shrink_to_fit();
553 }
554 }
555
556 fn offset(&self) -> usize {
557 0
558 }
559
560 fn nulls(&self) -> Option<&NullBuffer> {
561 self.nulls.as_ref()
562 }
563
564 fn logical_null_count(&self) -> usize {
565 self.null_count()
567 }
568
569 fn get_buffer_memory_size(&self) -> usize {
570 let mut size = self.values.get_buffer_memory_size();
571 if let Some(n) = self.nulls.as_ref() {
572 size += n.buffer().capacity();
573 }
574 size
575 }
576
577 fn get_array_memory_size(&self) -> usize {
578 let mut size = std::mem::size_of::<Self>() + self.values.get_array_memory_size();
579 if let Some(n) = self.nulls.as_ref() {
580 size += n.buffer().capacity();
581 }
582 size
583 }
584
585 #[cfg(feature = "pool")]
586 fn claim(&self, pool: &dyn arrow_buffer::MemoryPool) {
587 self.values.claim(pool);
588 if let Some(nulls) = &self.nulls {
589 nulls.claim(pool);
590 }
591 }
592}
593
594impl super::ListLikeArray for FixedSizeListArray {
595 fn values(&self) -> &ArrayRef {
596 self.values()
597 }
598
599 fn element_range(&self, index: usize) -> std::ops::Range<usize> {
600 let value_length = self.value_length().as_usize();
601 let offset = index * value_length;
602 offset..(offset + value_length)
603 }
604}
605
606impl ArrayAccessor for FixedSizeListArray {
607 type Item = ArrayRef;
608
609 fn value(&self, index: usize) -> Self::Item {
610 FixedSizeListArray::value(self, index)
611 }
612
613 unsafe fn value_unchecked(&self, index: usize) -> Self::Item {
614 FixedSizeListArray::value(self, index)
615 }
616}
617
618impl std::fmt::Debug for FixedSizeListArray {
619 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
620 write!(f, "FixedSizeListArray<{}>\n[\n", self.value_length())?;
621 print_long_array(self, f, &mut |index, f| {
622 std::fmt::Debug::fmt(&self.value(index), f)
623 })?;
624 write!(f, "]")
625 }
626}
627
628impl ArrayAccessor for &FixedSizeListArray {
629 type Item = ArrayRef;
630
631 fn value(&self, index: usize) -> Self::Item {
632 FixedSizeListArray::value(self, index)
633 }
634
635 unsafe fn value_unchecked(&self, index: usize) -> Self::Item {
636 FixedSizeListArray::value(self, index)
637 }
638}
639
640#[cfg(test)]
641mod tests {
642 use arrow_buffer::{BooleanBuffer, Buffer, bit_util};
643 use arrow_schema::Field;
644
645 use crate::cast::AsArray;
646 use crate::types::Int32Type;
647 use crate::{Int32Array, new_empty_array};
648
649 use super::*;
650
651 #[test]
652 fn test_fixed_size_list_array() {
653 let value_data = ArrayData::builder(DataType::Int32)
655 .len(9)
656 .add_buffer(Buffer::from_slice_ref([0, 1, 2, 3, 4, 5, 6, 7, 8]))
657 .build()
658 .unwrap();
659
660 let list_data_type =
662 DataType::FixedSizeList(Arc::new(Field::new_list_field(DataType::Int32, false)), 3);
663 let list_data = ArrayData::builder(list_data_type.clone())
664 .len(3)
665 .add_child_data(value_data.clone())
666 .build()
667 .unwrap();
668 let list_array = FixedSizeListArray::from(list_data);
669
670 assert_eq!(value_data, list_array.values().to_data());
671 assert_eq!(DataType::Int32, list_array.value_type());
672 assert_eq!(3, list_array.len());
673 assert_eq!(0, list_array.null_count());
674 assert_eq!(6, list_array.value_offset_at(2));
675 assert_eq!(3, list_array.value_length());
676 assert_eq!(0, list_array.value(0).as_primitive::<Int32Type>().value(0));
677 for i in 0..3 {
678 assert!(list_array.is_valid(i));
679 assert!(!list_array.is_null(i));
680 }
681
682 let list_data = ArrayData::builder(list_data_type)
684 .len(2)
685 .offset(1)
686 .add_child_data(value_data.clone())
687 .build()
688 .unwrap();
689 let list_array = FixedSizeListArray::from(list_data);
690
691 assert_eq!(value_data.slice(3, 6), list_array.values().to_data());
692 assert_eq!(DataType::Int32, list_array.value_type());
693 assert_eq!(2, list_array.len());
694 assert_eq!(0, list_array.null_count());
695 assert_eq!(3, list_array.value(0).as_primitive::<Int32Type>().value(0));
696 assert_eq!(3, list_array.value_offset_at(1));
697 assert_eq!(3, list_array.value_length());
698 }
699
700 #[test]
701 #[should_panic(expected = "assertion failed: end <= self.len()")]
702 #[cfg(not(feature = "force_validate"))]
705 fn test_fixed_size_list_array_unequal_children() {
706 let value_data = ArrayData::builder(DataType::Int32)
708 .len(8)
709 .add_buffer(Buffer::from_slice_ref([0, 1, 2, 3, 4, 5, 6, 7]))
710 .build()
711 .unwrap();
712
713 let list_data_type =
715 DataType::FixedSizeList(Arc::new(Field::new_list_field(DataType::Int32, false)), 3);
716 let list_data = unsafe {
717 ArrayData::builder(list_data_type)
718 .len(3)
719 .add_child_data(value_data)
720 .build_unchecked()
721 };
722 drop(FixedSizeListArray::from(list_data));
723 }
724
725 #[test]
726 fn test_fixed_size_list_array_slice() {
727 let value_data = ArrayData::builder(DataType::Int32)
729 .len(10)
730 .add_buffer(Buffer::from_slice_ref([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))
731 .build()
732 .unwrap();
733
734 let mut null_bits: [u8; 1] = [0; 1];
738 bit_util::set_bit(&mut null_bits, 0);
739 bit_util::set_bit(&mut null_bits, 3);
740 bit_util::set_bit(&mut null_bits, 4);
741
742 let list_data_type =
744 DataType::FixedSizeList(Arc::new(Field::new_list_field(DataType::Int32, false)), 2);
745 let list_data = ArrayData::builder(list_data_type)
746 .len(5)
747 .add_child_data(value_data.clone())
748 .null_bit_buffer(Some(Buffer::from(null_bits)))
749 .build()
750 .unwrap();
751 let list_array = FixedSizeListArray::from(list_data);
752
753 assert_eq!(value_data, list_array.values().to_data());
754 assert_eq!(DataType::Int32, list_array.value_type());
755 assert_eq!(5, list_array.len());
756 assert_eq!(2, list_array.null_count());
757 assert_eq!(6, list_array.value_offset_at(3));
758 assert_eq!(2, list_array.value_length());
759
760 let sliced_array = list_array.slice(1, 4);
761 assert_eq!(4, sliced_array.len());
762 assert_eq!(2, sliced_array.null_count());
763
764 for i in 0..sliced_array.len() {
765 if bit_util::get_bit(&null_bits, 1 + i) {
766 assert!(sliced_array.is_valid(i));
767 } else {
768 assert!(sliced_array.is_null(i));
769 }
770 }
771
772 let sliced_list_array = sliced_array
774 .as_any()
775 .downcast_ref::<FixedSizeListArray>()
776 .unwrap();
777 assert_eq!(2, sliced_list_array.value_length());
778 assert_eq!(4, sliced_list_array.value_offset_at(2));
779 assert_eq!(6, sliced_list_array.value_offset_at(3));
780 }
781
782 #[test]
783 #[should_panic(expected = "the offset of the new Buffer cannot exceed the existing length")]
784 fn test_fixed_size_list_array_index_out_of_bound() {
785 let value_data = ArrayData::builder(DataType::Int32)
787 .len(10)
788 .add_buffer(Buffer::from_slice_ref([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))
789 .build()
790 .unwrap();
791
792 let mut null_bits: [u8; 1] = [0; 1];
796 bit_util::set_bit(&mut null_bits, 0);
797 bit_util::set_bit(&mut null_bits, 3);
798 bit_util::set_bit(&mut null_bits, 4);
799
800 let list_data_type =
802 DataType::FixedSizeList(Arc::new(Field::new_list_field(DataType::Int32, false)), 2);
803 let list_data = ArrayData::builder(list_data_type)
804 .len(5)
805 .add_child_data(value_data)
806 .null_bit_buffer(Some(Buffer::from(null_bits)))
807 .build()
808 .unwrap();
809 let list_array = FixedSizeListArray::from(list_data);
810
811 list_array.value(10);
812 }
813
814 #[test]
815 fn test_fixed_size_list_constructors() {
816 let values = Arc::new(Int32Array::from_iter([
817 Some(1),
818 Some(2),
819 None,
820 None,
821 Some(3),
822 Some(4),
823 ]));
824
825 let field = Arc::new(Field::new_list_field(DataType::Int32, true));
826 let list = FixedSizeListArray::new(field.clone(), 2, values.clone(), None);
827 assert_eq!(list.len(), 3);
828
829 let nulls = NullBuffer::new_null(3);
830 let list = FixedSizeListArray::new(field.clone(), 2, values.clone(), Some(nulls));
831 assert_eq!(list.len(), 3);
832
833 let list = FixedSizeListArray::new(field.clone(), 3, values.clone(), None);
834 assert_eq!(list.len(), 2);
835
836 let err = FixedSizeListArray::try_new(field.clone(), 4, values.clone(), None).unwrap_err();
837 assert_eq!(
838 err.to_string(),
839 "Invalid argument error: Incorrect length of values buffer for FixedSizeListArray, \
840 expected a multiple of 4 got 6",
841 );
842
843 let err =
844 FixedSizeListArray::try_new_with_length(field.clone(), 4, values.clone(), None, 1)
845 .unwrap_err();
846 assert_eq!(
847 err.to_string(),
848 "Invalid argument error: Incorrect length of values buffer for FixedSizeListArray, expected 4 got 6"
849 );
850
851 let err = FixedSizeListArray::try_new(field.clone(), -1, values.clone(), None).unwrap_err();
852 assert_eq!(
853 err.to_string(),
854 "Invalid argument error: Size cannot be negative, got -1"
855 );
856
857 let nulls = NullBuffer::new_null(2);
858 let err = FixedSizeListArray::try_new(field, 2, values.clone(), Some(nulls)).unwrap_err();
859 assert_eq!(
860 err.to_string(),
861 "Invalid argument error: Incorrect length of values buffer for FixedSizeListArray, expected 4 got 6"
862 );
863
864 let field = Arc::new(Field::new_list_field(DataType::Int32, false));
865 let err = FixedSizeListArray::try_new(field.clone(), 2, values.clone(), None).unwrap_err();
866 assert_eq!(
867 err.to_string(),
868 "Invalid argument error: Found unmasked nulls for non-nullable FixedSizeListArray field \"item\""
869 );
870
871 let nulls = NullBuffer::new(BooleanBuffer::new(Buffer::from([0b0000101]), 0, 3));
873 FixedSizeListArray::new(field, 2, values.clone(), Some(nulls));
874
875 let field = Arc::new(Field::new_list_field(DataType::Int64, true));
876 let err = FixedSizeListArray::try_new(field, 2, values, None).unwrap_err();
877 assert_eq!(
878 err.to_string(),
879 "Invalid argument error: FixedSizeListArray expected data type Int64 got Int32 for \"item\""
880 );
881 }
882
883 #[test]
884 fn degenerate_fixed_size_list() {
885 let field = Arc::new(Field::new_list_field(DataType::Int32, true));
886 let nulls = NullBuffer::new_null(2);
887 let values = new_empty_array(&DataType::Int32);
888 let list = FixedSizeListArray::new(field.clone(), 0, values.clone(), Some(nulls.clone()));
889 assert_eq!(list.len(), 2);
890
891 let err = FixedSizeListArray::try_new_with_length(
893 field.clone(),
894 0,
895 values.clone(),
896 Some(nulls),
897 5,
898 )
899 .unwrap_err();
900 assert_eq!(
901 err.to_string(),
902 "Invalid argument error: Invalid null buffer for FixedSizeListArray, expected 5 found 2"
903 );
904
905 let non_empty_values = Arc::new(Int32Array::from(vec![1, 2, 3]));
907 let err =
908 FixedSizeListArray::try_new_with_length(field.clone(), 0, non_empty_values, None, 3)
909 .unwrap_err();
910 assert_eq!(
911 err.to_string(),
912 "Invalid argument error: An degenerate FixedSizeListArray should have no underlying values, found 3 values"
913 );
914 }
915
916 #[test]
917 fn test_fixed_size_list_new_null_len() {
918 let field = Arc::new(Field::new_list_field(DataType::Int32, true));
919 let array = FixedSizeListArray::new_null(field, 2, 5);
920 assert_eq!(array.len(), 5);
921 }
922}