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