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 {
134 Self::try_new(field, size, values, nulls).unwrap()
135 }
136
137 pub fn try_new(
146 field: FieldRef,
147 size: i32,
148 values: ArrayRef,
149 nulls: Option<NullBuffer>,
150 ) -> Result<Self, ArrowError> {
151 let s = size.to_usize().ok_or_else(|| {
152 ArrowError::InvalidArgumentError(format!("Size cannot be negative, got {size}"))
153 })?;
154
155 let len = match s {
156 0 => nulls.as_ref().map(|x| x.len()).unwrap_or_default(),
157 _ => {
158 let len = values.len() / s.max(1);
159 if let Some(n) = nulls.as_ref() {
160 if n.len() != len {
161 return Err(ArrowError::InvalidArgumentError(format!(
162 "Incorrect length of null buffer for FixedSizeListArray, expected {} got {}",
163 len,
164 n.len(),
165 )));
166 }
167 }
168 len
169 }
170 };
171
172 if field.data_type() != values.data_type() {
173 return Err(ArrowError::InvalidArgumentError(format!(
174 "FixedSizeListArray expected data type {} got {} for {:?}",
175 field.data_type(),
176 values.data_type(),
177 field.name()
178 )));
179 }
180
181 if let Some(a) = values.logical_nulls() {
182 let nulls_valid = field.is_nullable()
183 || nulls
184 .as_ref()
185 .map(|n| n.expand(size as _).contains(&a))
186 .unwrap_or_default()
187 || (nulls.is_none() && a.null_count() == 0);
188
189 if !nulls_valid {
190 return Err(ArrowError::InvalidArgumentError(format!(
191 "Found unmasked nulls for non-nullable FixedSizeListArray field {:?}",
192 field.name()
193 )));
194 }
195 }
196
197 let data_type = DataType::FixedSizeList(field, size);
198 Ok(Self {
199 data_type,
200 values,
201 value_length: size,
202 nulls,
203 len,
204 })
205 }
206
207 pub fn new_null(field: FieldRef, size: i32, len: usize) -> Self {
216 let capacity = size.to_usize().unwrap().checked_mul(len).unwrap();
217 Self {
218 values: make_array(ArrayData::new_null(field.data_type(), capacity)),
219 data_type: DataType::FixedSizeList(field, size),
220 nulls: Some(NullBuffer::new_null(len)),
221 value_length: size,
222 len,
223 }
224 }
225
226 pub fn into_parts(self) -> (FieldRef, i32, ArrayRef, Option<NullBuffer>) {
228 let f = match self.data_type {
229 DataType::FixedSizeList(f, _) => f,
230 _ => unreachable!(),
231 };
232 (f, self.value_length, self.values, self.nulls)
233 }
234
235 pub fn values(&self) -> &ArrayRef {
237 &self.values
238 }
239
240 pub fn value_type(&self) -> DataType {
242 self.values.data_type().clone()
243 }
244
245 pub fn value(&self, i: usize) -> ArrayRef {
253 self.values
254 .slice(self.value_offset_at(i), self.value_length() as usize)
255 }
256
257 #[inline]
261 pub fn value_offset(&self, i: usize) -> i32 {
262 self.value_offset_at(i) as i32
263 }
264
265 #[inline]
269 pub const fn value_length(&self) -> i32 {
270 self.value_length
271 }
272
273 #[inline]
274 const fn value_offset_at(&self, i: usize) -> usize {
275 i * self.value_length as usize
276 }
277
278 pub fn slice(&self, offset: usize, len: usize) -> Self {
280 assert!(
281 offset.saturating_add(len) <= self.len,
282 "the length + offset of the sliced FixedSizeListArray cannot exceed the existing length"
283 );
284 let size = self.value_length as usize;
285
286 Self {
287 data_type: self.data_type.clone(),
288 values: self.values.slice(offset * size, len * size),
289 nulls: self.nulls.as_ref().map(|n| n.slice(offset, len)),
290 value_length: self.value_length,
291 len,
292 }
293 }
294
295 pub fn from_iter_primitive<T, P, I>(iter: I, length: i32) -> Self
311 where
312 T: ArrowPrimitiveType,
313 P: IntoIterator<Item = Option<<T as ArrowPrimitiveType>::Native>>,
314 I: IntoIterator<Item = Option<P>>,
315 {
316 let l = length as usize;
317 let iter = iter.into_iter();
318 let size_hint = iter.size_hint().0;
319 let mut builder = FixedSizeListBuilder::with_capacity(
320 PrimitiveBuilder::<T>::with_capacity(size_hint * l),
321 length,
322 size_hint,
323 );
324
325 for i in iter {
326 match i {
327 Some(p) => {
328 for t in p {
329 builder.values().append_option(t);
330 }
331 builder.append(true);
332 }
333 None => {
334 builder.values().append_nulls(l);
335 builder.append(false)
336 }
337 }
338 }
339 builder.finish()
340 }
341
342 pub fn iter(&self) -> FixedSizeListIter<'_> {
344 FixedSizeListIter::new(self)
345 }
346}
347
348impl From<ArrayData> for FixedSizeListArray {
349 fn from(data: ArrayData) -> Self {
350 let value_length = match data.data_type() {
351 DataType::FixedSizeList(_, len) => *len,
352 data_type => {
353 panic!(
354 "FixedSizeListArray data should contain a FixedSizeList data type, got {data_type}"
355 )
356 }
357 };
358
359 let size = value_length as usize;
360 let values =
361 make_array(data.child_data()[0].slice(data.offset() * size, data.len() * size));
362 Self {
363 data_type: data.data_type().clone(),
364 values,
365 nulls: data.nulls().cloned(),
366 value_length,
367 len: data.len(),
368 }
369 }
370}
371
372impl From<FixedSizeListArray> for ArrayData {
373 fn from(array: FixedSizeListArray) -> Self {
374 let builder = ArrayDataBuilder::new(array.data_type)
375 .len(array.len)
376 .nulls(array.nulls)
377 .child_data(vec![array.values.to_data()]);
378
379 unsafe { builder.build_unchecked() }
380 }
381}
382
383impl Array for FixedSizeListArray {
384 fn as_any(&self) -> &dyn Any {
385 self
386 }
387
388 fn to_data(&self) -> ArrayData {
389 self.clone().into()
390 }
391
392 fn into_data(self) -> ArrayData {
393 self.into()
394 }
395
396 fn data_type(&self) -> &DataType {
397 &self.data_type
398 }
399
400 fn slice(&self, offset: usize, length: usize) -> ArrayRef {
401 Arc::new(self.slice(offset, length))
402 }
403
404 fn len(&self) -> usize {
405 self.len
406 }
407
408 fn is_empty(&self) -> bool {
409 self.len == 0
410 }
411
412 fn shrink_to_fit(&mut self) {
413 self.values.shrink_to_fit();
414 if let Some(nulls) = &mut self.nulls {
415 nulls.shrink_to_fit();
416 }
417 }
418
419 fn offset(&self) -> usize {
420 0
421 }
422
423 fn nulls(&self) -> Option<&NullBuffer> {
424 self.nulls.as_ref()
425 }
426
427 fn logical_null_count(&self) -> usize {
428 self.null_count()
430 }
431
432 fn get_buffer_memory_size(&self) -> usize {
433 let mut size = self.values.get_buffer_memory_size();
434 if let Some(n) = self.nulls.as_ref() {
435 size += n.buffer().capacity();
436 }
437 size
438 }
439
440 fn get_array_memory_size(&self) -> usize {
441 let mut size = std::mem::size_of::<Self>() + self.values.get_array_memory_size();
442 if let Some(n) = self.nulls.as_ref() {
443 size += n.buffer().capacity();
444 }
445 size
446 }
447}
448
449impl ArrayAccessor for FixedSizeListArray {
450 type Item = ArrayRef;
451
452 fn value(&self, index: usize) -> Self::Item {
453 FixedSizeListArray::value(self, index)
454 }
455
456 unsafe fn value_unchecked(&self, index: usize) -> Self::Item {
457 FixedSizeListArray::value(self, index)
458 }
459}
460
461impl std::fmt::Debug for FixedSizeListArray {
462 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
463 write!(f, "FixedSizeListArray<{}>\n[\n", self.value_length())?;
464 print_long_array(self, f, |array, index, f| {
465 std::fmt::Debug::fmt(&array.value(index), f)
466 })?;
467 write!(f, "]")
468 }
469}
470
471impl ArrayAccessor for &FixedSizeListArray {
472 type Item = ArrayRef;
473
474 fn value(&self, index: usize) -> Self::Item {
475 FixedSizeListArray::value(self, index)
476 }
477
478 unsafe fn value_unchecked(&self, index: usize) -> Self::Item {
479 FixedSizeListArray::value(self, index)
480 }
481}
482
483#[cfg(test)]
484mod tests {
485 use arrow_buffer::{BooleanBuffer, Buffer, bit_util};
486 use arrow_schema::Field;
487
488 use crate::cast::AsArray;
489 use crate::types::Int32Type;
490 use crate::{Int32Array, new_empty_array};
491
492 use super::*;
493
494 #[test]
495 fn test_fixed_size_list_array() {
496 let value_data = ArrayData::builder(DataType::Int32)
498 .len(9)
499 .add_buffer(Buffer::from_slice_ref([0, 1, 2, 3, 4, 5, 6, 7, 8]))
500 .build()
501 .unwrap();
502
503 let list_data_type =
505 DataType::FixedSizeList(Arc::new(Field::new_list_field(DataType::Int32, false)), 3);
506 let list_data = ArrayData::builder(list_data_type.clone())
507 .len(3)
508 .add_child_data(value_data.clone())
509 .build()
510 .unwrap();
511 let list_array = FixedSizeListArray::from(list_data);
512
513 assert_eq!(value_data, list_array.values().to_data());
514 assert_eq!(DataType::Int32, list_array.value_type());
515 assert_eq!(3, list_array.len());
516 assert_eq!(0, list_array.null_count());
517 assert_eq!(6, list_array.value_offset(2));
518 assert_eq!(3, list_array.value_length());
519 assert_eq!(0, list_array.value(0).as_primitive::<Int32Type>().value(0));
520 for i in 0..3 {
521 assert!(list_array.is_valid(i));
522 assert!(!list_array.is_null(i));
523 }
524
525 let list_data = ArrayData::builder(list_data_type)
527 .len(2)
528 .offset(1)
529 .add_child_data(value_data.clone())
530 .build()
531 .unwrap();
532 let list_array = FixedSizeListArray::from(list_data);
533
534 assert_eq!(value_data.slice(3, 6), list_array.values().to_data());
535 assert_eq!(DataType::Int32, list_array.value_type());
536 assert_eq!(2, list_array.len());
537 assert_eq!(0, list_array.null_count());
538 assert_eq!(3, list_array.value(0).as_primitive::<Int32Type>().value(0));
539 assert_eq!(3, list_array.value_offset(1));
540 assert_eq!(3, list_array.value_length());
541 }
542
543 #[test]
544 #[should_panic(expected = "assertion failed: (offset + length) <= self.len()")]
545 #[cfg(not(feature = "force_validate"))]
548 fn test_fixed_size_list_array_unequal_children() {
549 let value_data = ArrayData::builder(DataType::Int32)
551 .len(8)
552 .add_buffer(Buffer::from_slice_ref([0, 1, 2, 3, 4, 5, 6, 7]))
553 .build()
554 .unwrap();
555
556 let list_data_type =
558 DataType::FixedSizeList(Arc::new(Field::new_list_field(DataType::Int32, false)), 3);
559 let list_data = unsafe {
560 ArrayData::builder(list_data_type)
561 .len(3)
562 .add_child_data(value_data)
563 .build_unchecked()
564 };
565 drop(FixedSizeListArray::from(list_data));
566 }
567
568 #[test]
569 fn test_fixed_size_list_array_slice() {
570 let value_data = ArrayData::builder(DataType::Int32)
572 .len(10)
573 .add_buffer(Buffer::from_slice_ref([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))
574 .build()
575 .unwrap();
576
577 let mut null_bits: [u8; 1] = [0; 1];
581 bit_util::set_bit(&mut null_bits, 0);
582 bit_util::set_bit(&mut null_bits, 3);
583 bit_util::set_bit(&mut null_bits, 4);
584
585 let list_data_type =
587 DataType::FixedSizeList(Arc::new(Field::new_list_field(DataType::Int32, false)), 2);
588 let list_data = ArrayData::builder(list_data_type)
589 .len(5)
590 .add_child_data(value_data.clone())
591 .null_bit_buffer(Some(Buffer::from(null_bits)))
592 .build()
593 .unwrap();
594 let list_array = FixedSizeListArray::from(list_data);
595
596 assert_eq!(value_data, list_array.values().to_data());
597 assert_eq!(DataType::Int32, list_array.value_type());
598 assert_eq!(5, list_array.len());
599 assert_eq!(2, list_array.null_count());
600 assert_eq!(6, list_array.value_offset(3));
601 assert_eq!(2, list_array.value_length());
602
603 let sliced_array = list_array.slice(1, 4);
604 assert_eq!(4, sliced_array.len());
605 assert_eq!(2, sliced_array.null_count());
606
607 for i in 0..sliced_array.len() {
608 if bit_util::get_bit(&null_bits, 1 + i) {
609 assert!(sliced_array.is_valid(i));
610 } else {
611 assert!(sliced_array.is_null(i));
612 }
613 }
614
615 let sliced_list_array = sliced_array
617 .as_any()
618 .downcast_ref::<FixedSizeListArray>()
619 .unwrap();
620 assert_eq!(2, sliced_list_array.value_length());
621 assert_eq!(4, sliced_list_array.value_offset(2));
622 assert_eq!(6, sliced_list_array.value_offset(3));
623 }
624
625 #[test]
626 #[should_panic(expected = "the offset of the new Buffer cannot exceed the existing length")]
627 fn test_fixed_size_list_array_index_out_of_bound() {
628 let value_data = ArrayData::builder(DataType::Int32)
630 .len(10)
631 .add_buffer(Buffer::from_slice_ref([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))
632 .build()
633 .unwrap();
634
635 let mut null_bits: [u8; 1] = [0; 1];
639 bit_util::set_bit(&mut null_bits, 0);
640 bit_util::set_bit(&mut null_bits, 3);
641 bit_util::set_bit(&mut null_bits, 4);
642
643 let list_data_type =
645 DataType::FixedSizeList(Arc::new(Field::new_list_field(DataType::Int32, false)), 2);
646 let list_data = ArrayData::builder(list_data_type)
647 .len(5)
648 .add_child_data(value_data)
649 .null_bit_buffer(Some(Buffer::from(null_bits)))
650 .build()
651 .unwrap();
652 let list_array = FixedSizeListArray::from(list_data);
653
654 list_array.value(10);
655 }
656
657 #[test]
658 fn test_fixed_size_list_constructors() {
659 let values = Arc::new(Int32Array::from_iter([
660 Some(1),
661 Some(2),
662 None,
663 None,
664 Some(3),
665 Some(4),
666 ]));
667
668 let field = Arc::new(Field::new_list_field(DataType::Int32, true));
669 let list = FixedSizeListArray::new(field.clone(), 2, values.clone(), None);
670 assert_eq!(list.len(), 3);
671
672 let nulls = NullBuffer::new_null(3);
673 let list = FixedSizeListArray::new(field.clone(), 2, values.clone(), Some(nulls));
674 assert_eq!(list.len(), 3);
675
676 let list = FixedSizeListArray::new(field.clone(), 4, values.clone(), None);
677 assert_eq!(list.len(), 1);
678
679 let err = FixedSizeListArray::try_new(field.clone(), -1, values.clone(), None).unwrap_err();
680 assert_eq!(
681 err.to_string(),
682 "Invalid argument error: Size cannot be negative, got -1"
683 );
684
685 let list = FixedSizeListArray::new(field.clone(), 0, values.clone(), None);
686 assert_eq!(list.len(), 0);
687
688 let nulls = NullBuffer::new_null(2);
689 let err = FixedSizeListArray::try_new(field, 2, values.clone(), Some(nulls)).unwrap_err();
690 assert_eq!(
691 err.to_string(),
692 "Invalid argument error: Incorrect length of null buffer for FixedSizeListArray, expected 3 got 2"
693 );
694
695 let field = Arc::new(Field::new_list_field(DataType::Int32, false));
696 let err = FixedSizeListArray::try_new(field.clone(), 2, values.clone(), None).unwrap_err();
697 assert_eq!(
698 err.to_string(),
699 "Invalid argument error: Found unmasked nulls for non-nullable FixedSizeListArray field \"item\""
700 );
701
702 let nulls = NullBuffer::new(BooleanBuffer::new(Buffer::from([0b0000101]), 0, 3));
704 FixedSizeListArray::new(field, 2, values.clone(), Some(nulls));
705
706 let field = Arc::new(Field::new_list_field(DataType::Int64, true));
707 let err = FixedSizeListArray::try_new(field, 2, values, None).unwrap_err();
708 assert_eq!(
709 err.to_string(),
710 "Invalid argument error: FixedSizeListArray expected data type Int64 got Int32 for \"item\""
711 );
712 }
713
714 #[test]
715 fn empty_fixed_size_list() {
716 let field = Arc::new(Field::new_list_field(DataType::Int32, true));
717 let nulls = NullBuffer::new_null(2);
718 let values = new_empty_array(&DataType::Int32);
719 let list = FixedSizeListArray::new(field.clone(), 0, values, Some(nulls));
720 assert_eq!(list.len(), 2);
721 }
722}