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 f = match self.data_type {
336 DataType::FixedSizeList(f, _) => f,
337 _ => unreachable!(),
338 };
339 (f, self.value_length, self.values, self.nulls)
340 }
341
342 pub fn value_field(&self) -> &FieldRef {
344 match &self.data_type {
345 DataType::FixedSizeList(f, _) => f,
346 _ => unreachable!(),
347 }
348 }
349
350 pub fn values(&self) -> &ArrayRef {
352 &self.values
353 }
354
355 pub fn value_type(&self) -> DataType {
357 self.values.data_type().clone()
358 }
359
360 pub fn value(&self, i: usize) -> ArrayRef {
368 self.values
369 .slice(self.value_offset_at(i), self.value_length() as usize)
370 }
371
372 #[inline]
376 pub fn value_offset(&self, i: usize) -> i32 {
377 self.value_offset_at(i) as i32
378 }
379
380 #[inline]
384 pub const fn value_length(&self) -> i32 {
385 self.value_length
386 }
387
388 #[inline]
389 const fn value_offset_at(&self, i: usize) -> usize {
390 i * self.value_length as usize
391 }
392
393 pub fn slice(&self, offset: usize, len: usize) -> Self {
398 assert!(
399 offset.saturating_add(len) <= self.len,
400 "the length + offset of the sliced FixedSizeListArray cannot exceed the existing length"
401 );
402 let size = self.value_length as usize;
403
404 Self {
405 data_type: self.data_type.clone(),
406 values: self.values.slice(offset * size, len * size),
407 nulls: self.nulls.as_ref().map(|n| n.slice(offset, len)),
408 value_length: self.value_length,
409 len,
410 }
411 }
412
413 pub fn from_iter_primitive<T, P, I>(iter: I, length: i32) -> Self
429 where
430 T: ArrowPrimitiveType,
431 P: IntoIterator<Item = Option<<T as ArrowPrimitiveType>::Native>>,
432 I: IntoIterator<Item = Option<P>>,
433 {
434 let l = length as usize;
435 let iter = iter.into_iter();
436 let size_hint = iter.size_hint().0;
437 let mut builder = FixedSizeListBuilder::with_capacity(
438 PrimitiveBuilder::<T>::with_capacity(size_hint * l),
439 length,
440 size_hint,
441 );
442
443 for i in iter {
444 match i {
445 Some(p) => {
446 for t in p {
447 builder.values().append_option(t);
448 }
449 builder.append(true);
450 }
451 None => {
452 builder.values().append_nulls(l);
453 builder.append(false)
454 }
455 }
456 }
457 builder.finish()
458 }
459
460 pub fn iter(&self) -> FixedSizeListIter<'_> {
462 FixedSizeListIter::new(self)
463 }
464}
465
466impl From<ArrayData> for FixedSizeListArray {
467 fn from(data: ArrayData) -> Self {
468 let (data_type, len, nulls, offset, _buffers, child_data) = data.into_parts();
469
470 let value_length = match data_type {
471 DataType::FixedSizeList(_, len) => len,
472 data_type => {
473 panic!(
474 "FixedSizeListArray data should contain a FixedSizeList data type, got {data_type}"
475 )
476 }
477 };
478
479 let size = value_length as usize;
480 let values = make_array(child_data[0].slice(offset * size, len * size));
481 Self {
482 data_type,
483 values,
484 nulls,
485 value_length,
486 len,
487 }
488 }
489}
490
491impl From<FixedSizeListArray> for ArrayData {
492 fn from(array: FixedSizeListArray) -> Self {
493 let builder = ArrayDataBuilder::new(array.data_type)
494 .len(array.len)
495 .nulls(array.nulls)
496 .child_data(vec![array.values.to_data()]);
497
498 unsafe { builder.build_unchecked() }
499 }
500}
501
502unsafe impl Array for FixedSizeListArray {
504 fn as_any(&self) -> &dyn Any {
505 self
506 }
507
508 fn to_data(&self) -> ArrayData {
509 self.clone().into()
510 }
511
512 fn into_data(self) -> ArrayData {
513 self.into()
514 }
515
516 fn data_type(&self) -> &DataType {
517 &self.data_type
518 }
519
520 fn slice(&self, offset: usize, length: usize) -> ArrayRef {
521 Arc::new(self.slice(offset, length))
522 }
523
524 fn len(&self) -> usize {
525 self.len
526 }
527
528 fn is_empty(&self) -> bool {
529 self.len == 0
530 }
531
532 fn shrink_to_fit(&mut self) {
533 self.values.shrink_to_fit();
534 if let Some(nulls) = &mut self.nulls {
535 nulls.shrink_to_fit();
536 }
537 }
538
539 fn offset(&self) -> usize {
540 0
541 }
542
543 fn nulls(&self) -> Option<&NullBuffer> {
544 self.nulls.as_ref()
545 }
546
547 fn logical_null_count(&self) -> usize {
548 self.null_count()
550 }
551
552 fn get_buffer_memory_size(&self) -> usize {
553 let mut size = self.values.get_buffer_memory_size();
554 if let Some(n) = self.nulls.as_ref() {
555 size += n.buffer().capacity();
556 }
557 size
558 }
559
560 fn get_array_memory_size(&self) -> usize {
561 let mut size = std::mem::size_of::<Self>() + self.values.get_array_memory_size();
562 if let Some(n) = self.nulls.as_ref() {
563 size += n.buffer().capacity();
564 }
565 size
566 }
567
568 #[cfg(feature = "pool")]
569 fn claim(&self, pool: &dyn arrow_buffer::MemoryPool) {
570 self.values.claim(pool);
571 if let Some(nulls) = &self.nulls {
572 nulls.claim(pool);
573 }
574 }
575}
576
577impl super::ListLikeArray for FixedSizeListArray {
578 fn values(&self) -> &ArrayRef {
579 self.values()
580 }
581
582 fn element_range(&self, index: usize) -> std::ops::Range<usize> {
583 let value_length = self.value_length().as_usize();
584 let offset = index * value_length;
585 offset..(offset + value_length)
586 }
587}
588
589impl ArrayAccessor for FixedSizeListArray {
590 type Item = ArrayRef;
591
592 fn value(&self, index: usize) -> Self::Item {
593 FixedSizeListArray::value(self, index)
594 }
595
596 unsafe fn value_unchecked(&self, index: usize) -> Self::Item {
597 FixedSizeListArray::value(self, index)
598 }
599}
600
601impl std::fmt::Debug for FixedSizeListArray {
602 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
603 write!(f, "FixedSizeListArray<{}>\n[\n", self.value_length())?;
604 print_long_array(self, f, |array, index, f| {
605 std::fmt::Debug::fmt(&array.value(index), f)
606 })?;
607 write!(f, "]")
608 }
609}
610
611impl ArrayAccessor for &FixedSizeListArray {
612 type Item = ArrayRef;
613
614 fn value(&self, index: usize) -> Self::Item {
615 FixedSizeListArray::value(self, index)
616 }
617
618 unsafe fn value_unchecked(&self, index: usize) -> Self::Item {
619 FixedSizeListArray::value(self, index)
620 }
621}
622
623#[cfg(test)]
624mod tests {
625 use arrow_buffer::{BooleanBuffer, Buffer, bit_util};
626 use arrow_schema::Field;
627
628 use crate::cast::AsArray;
629 use crate::types::Int32Type;
630 use crate::{Int32Array, new_empty_array};
631
632 use super::*;
633
634 #[test]
635 fn test_fixed_size_list_array() {
636 let value_data = ArrayData::builder(DataType::Int32)
638 .len(9)
639 .add_buffer(Buffer::from_slice_ref([0, 1, 2, 3, 4, 5, 6, 7, 8]))
640 .build()
641 .unwrap();
642
643 let list_data_type =
645 DataType::FixedSizeList(Arc::new(Field::new_list_field(DataType::Int32, false)), 3);
646 let list_data = ArrayData::builder(list_data_type.clone())
647 .len(3)
648 .add_child_data(value_data.clone())
649 .build()
650 .unwrap();
651 let list_array = FixedSizeListArray::from(list_data);
652
653 assert_eq!(value_data, list_array.values().to_data());
654 assert_eq!(DataType::Int32, list_array.value_type());
655 assert_eq!(3, list_array.len());
656 assert_eq!(0, list_array.null_count());
657 assert_eq!(6, list_array.value_offset(2));
658 assert_eq!(3, list_array.value_length());
659 assert_eq!(0, list_array.value(0).as_primitive::<Int32Type>().value(0));
660 for i in 0..3 {
661 assert!(list_array.is_valid(i));
662 assert!(!list_array.is_null(i));
663 }
664
665 let list_data = ArrayData::builder(list_data_type)
667 .len(2)
668 .offset(1)
669 .add_child_data(value_data.clone())
670 .build()
671 .unwrap();
672 let list_array = FixedSizeListArray::from(list_data);
673
674 assert_eq!(value_data.slice(3, 6), list_array.values().to_data());
675 assert_eq!(DataType::Int32, list_array.value_type());
676 assert_eq!(2, list_array.len());
677 assert_eq!(0, list_array.null_count());
678 assert_eq!(3, list_array.value(0).as_primitive::<Int32Type>().value(0));
679 assert_eq!(3, list_array.value_offset(1));
680 assert_eq!(3, list_array.value_length());
681 }
682
683 #[test]
684 #[should_panic(expected = "assertion failed: end <= self.len()")]
685 #[cfg(not(feature = "force_validate"))]
688 fn test_fixed_size_list_array_unequal_children() {
689 let value_data = ArrayData::builder(DataType::Int32)
691 .len(8)
692 .add_buffer(Buffer::from_slice_ref([0, 1, 2, 3, 4, 5, 6, 7]))
693 .build()
694 .unwrap();
695
696 let list_data_type =
698 DataType::FixedSizeList(Arc::new(Field::new_list_field(DataType::Int32, false)), 3);
699 let list_data = unsafe {
700 ArrayData::builder(list_data_type)
701 .len(3)
702 .add_child_data(value_data)
703 .build_unchecked()
704 };
705 drop(FixedSizeListArray::from(list_data));
706 }
707
708 #[test]
709 fn test_fixed_size_list_array_slice() {
710 let value_data = ArrayData::builder(DataType::Int32)
712 .len(10)
713 .add_buffer(Buffer::from_slice_ref([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))
714 .build()
715 .unwrap();
716
717 let mut null_bits: [u8; 1] = [0; 1];
721 bit_util::set_bit(&mut null_bits, 0);
722 bit_util::set_bit(&mut null_bits, 3);
723 bit_util::set_bit(&mut null_bits, 4);
724
725 let list_data_type =
727 DataType::FixedSizeList(Arc::new(Field::new_list_field(DataType::Int32, false)), 2);
728 let list_data = ArrayData::builder(list_data_type)
729 .len(5)
730 .add_child_data(value_data.clone())
731 .null_bit_buffer(Some(Buffer::from(null_bits)))
732 .build()
733 .unwrap();
734 let list_array = FixedSizeListArray::from(list_data);
735
736 assert_eq!(value_data, list_array.values().to_data());
737 assert_eq!(DataType::Int32, list_array.value_type());
738 assert_eq!(5, list_array.len());
739 assert_eq!(2, list_array.null_count());
740 assert_eq!(6, list_array.value_offset(3));
741 assert_eq!(2, list_array.value_length());
742
743 let sliced_array = list_array.slice(1, 4);
744 assert_eq!(4, sliced_array.len());
745 assert_eq!(2, sliced_array.null_count());
746
747 for i in 0..sliced_array.len() {
748 if bit_util::get_bit(&null_bits, 1 + i) {
749 assert!(sliced_array.is_valid(i));
750 } else {
751 assert!(sliced_array.is_null(i));
752 }
753 }
754
755 let sliced_list_array = sliced_array
757 .as_any()
758 .downcast_ref::<FixedSizeListArray>()
759 .unwrap();
760 assert_eq!(2, sliced_list_array.value_length());
761 assert_eq!(4, sliced_list_array.value_offset(2));
762 assert_eq!(6, sliced_list_array.value_offset(3));
763 }
764
765 #[test]
766 #[should_panic(expected = "the offset of the new Buffer cannot exceed the existing length")]
767 fn test_fixed_size_list_array_index_out_of_bound() {
768 let value_data = ArrayData::builder(DataType::Int32)
770 .len(10)
771 .add_buffer(Buffer::from_slice_ref([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))
772 .build()
773 .unwrap();
774
775 let mut null_bits: [u8; 1] = [0; 1];
779 bit_util::set_bit(&mut null_bits, 0);
780 bit_util::set_bit(&mut null_bits, 3);
781 bit_util::set_bit(&mut null_bits, 4);
782
783 let list_data_type =
785 DataType::FixedSizeList(Arc::new(Field::new_list_field(DataType::Int32, false)), 2);
786 let list_data = ArrayData::builder(list_data_type)
787 .len(5)
788 .add_child_data(value_data)
789 .null_bit_buffer(Some(Buffer::from(null_bits)))
790 .build()
791 .unwrap();
792 let list_array = FixedSizeListArray::from(list_data);
793
794 list_array.value(10);
795 }
796
797 #[test]
798 fn test_fixed_size_list_constructors() {
799 let values = Arc::new(Int32Array::from_iter([
800 Some(1),
801 Some(2),
802 None,
803 None,
804 Some(3),
805 Some(4),
806 ]));
807
808 let field = Arc::new(Field::new_list_field(DataType::Int32, true));
809 let list = FixedSizeListArray::new(field.clone(), 2, values.clone(), None);
810 assert_eq!(list.len(), 3);
811
812 let nulls = NullBuffer::new_null(3);
813 let list = FixedSizeListArray::new(field.clone(), 2, values.clone(), Some(nulls));
814 assert_eq!(list.len(), 3);
815
816 let list = FixedSizeListArray::new(field.clone(), 3, values.clone(), None);
817 assert_eq!(list.len(), 2);
818
819 let err = FixedSizeListArray::try_new(field.clone(), 4, values.clone(), None).unwrap_err();
820 assert_eq!(
821 err.to_string(),
822 "Invalid argument error: Incorrect length of values buffer for FixedSizeListArray, \
823 expected a multiple of 4 got 6",
824 );
825
826 let err =
827 FixedSizeListArray::try_new_with_length(field.clone(), 4, values.clone(), None, 1)
828 .unwrap_err();
829 assert_eq!(
830 err.to_string(),
831 "Invalid argument error: Incorrect length of values buffer for FixedSizeListArray, expected 4 got 6"
832 );
833
834 let err = FixedSizeListArray::try_new(field.clone(), -1, values.clone(), None).unwrap_err();
835 assert_eq!(
836 err.to_string(),
837 "Invalid argument error: Size cannot be negative, got -1"
838 );
839
840 let nulls = NullBuffer::new_null(2);
841 let err = FixedSizeListArray::try_new(field, 2, values.clone(), Some(nulls)).unwrap_err();
842 assert_eq!(
843 err.to_string(),
844 "Invalid argument error: Incorrect length of values buffer for FixedSizeListArray, expected 4 got 6"
845 );
846
847 let field = Arc::new(Field::new_list_field(DataType::Int32, false));
848 let err = FixedSizeListArray::try_new(field.clone(), 2, values.clone(), None).unwrap_err();
849 assert_eq!(
850 err.to_string(),
851 "Invalid argument error: Found unmasked nulls for non-nullable FixedSizeListArray field \"item\""
852 );
853
854 let nulls = NullBuffer::new(BooleanBuffer::new(Buffer::from([0b0000101]), 0, 3));
856 FixedSizeListArray::new(field, 2, values.clone(), Some(nulls));
857
858 let field = Arc::new(Field::new_list_field(DataType::Int64, true));
859 let err = FixedSizeListArray::try_new(field, 2, values, None).unwrap_err();
860 assert_eq!(
861 err.to_string(),
862 "Invalid argument error: FixedSizeListArray expected data type Int64 got Int32 for \"item\""
863 );
864 }
865
866 #[test]
867 fn degenerate_fixed_size_list() {
868 let field = Arc::new(Field::new_list_field(DataType::Int32, true));
869 let nulls = NullBuffer::new_null(2);
870 let values = new_empty_array(&DataType::Int32);
871 let list = FixedSizeListArray::new(field.clone(), 0, values.clone(), Some(nulls.clone()));
872 assert_eq!(list.len(), 2);
873
874 let err = FixedSizeListArray::try_new_with_length(
876 field.clone(),
877 0,
878 values.clone(),
879 Some(nulls),
880 5,
881 )
882 .unwrap_err();
883 assert_eq!(
884 err.to_string(),
885 "Invalid argument error: Invalid null buffer for FixedSizeListArray, expected 5 found 2"
886 );
887
888 let non_empty_values = Arc::new(Int32Array::from(vec![1, 2, 3]));
890 let err =
891 FixedSizeListArray::try_new_with_length(field.clone(), 0, non_empty_values, None, 3)
892 .unwrap_err();
893 assert_eq!(
894 err.to_string(),
895 "Invalid argument error: An degenerate FixedSizeListArray should have no underlying values, found 3 values"
896 );
897 }
898
899 #[test]
900 fn test_fixed_size_list_new_null_len() {
901 let field = Arc::new(Field::new_list_field(DataType::Int32, true));
902 let array = FixedSizeListArray::new_null(field, 2, 5);
903 assert_eq!(array.len(), 5);
904 }
905}