1use std::ptr;
5
6use itertools::Itertools as _;
7use vortex_buffer::BitBufferMut;
8use vortex_buffer::BufferMut;
9use vortex_buffer::ByteBufferMut;
10use vortex_error::VortexExpect;
11use vortex_error::VortexResult;
12use vortex_error::vortex_ensure;
13use vortex_error::vortex_err;
14use vortex_error::vortex_panic;
15use vortex_mask::Mask;
16
17use crate::ArrayRef;
18use crate::Columnar;
19use crate::IntoArray;
20use crate::array::ArrayView;
21use crate::arrays::PiecewiseSequence;
22use crate::arrays::PrimitiveArray;
23use crate::arrays::VarBin;
24use crate::arrays::VarBinArray;
25use crate::arrays::dict::TakeExecute;
26use crate::arrays::piecewise_sequence::constant_unsigned_usize;
27use crate::arrays::piecewise_sequence::maybe_contiguous_slices;
28use crate::arrays::primitive::PrimitiveArrayExt;
29use crate::arrays::varbin::VarBinArrayExt;
30use crate::arrays::varbin::VarBinArraySlotsExt;
31use crate::dtype::DType;
32use crate::dtype::IntegerPType;
33use crate::dtype::PType;
34use crate::dtype::UnsignedPType;
35use crate::executor::ExecutionCtx;
36use crate::match_each_unsigned_integer_ptype;
37use crate::validity::Validity;
38
39fn taken_offset_ptype(offsets_ptype: PType) -> PType {
42 match offsets_ptype {
43 PType::U8 | PType::U16 | PType::U32 => PType::U32,
44 PType::U64 => PType::U64,
45 PType::I8 | PType::I16 | PType::I32 => PType::I32,
46 PType::I64 => PType::I64,
47 _ => unreachable!("invalid PType for offsets"),
48 }
49}
50
51impl TakeExecute for VarBin {
52 fn take(
53 array: ArrayView<'_, VarBin>,
54 indices: &ArrayRef,
55 ctx: &mut ExecutionCtx,
56 ) -> VortexResult<Option<ArrayRef>> {
57 if let Some(piecewise_indices) = indices.as_opt::<PiecewiseSequence>()
58 && let Some(taken) = take_contiguous_ranges(array, piecewise_indices, indices, ctx)?
59 {
60 return Ok(Some(taken));
61 }
62
63 let offsets = array.offsets().clone().execute::<PrimitiveArray>(ctx)?;
65 let data = array.bytes();
66 let indices = indices.clone().execute::<PrimitiveArray>(ctx)?;
67 let dtype = array
68 .dtype()
69 .clone()
70 .union_nullability(indices.dtype().nullability());
71 let array_validity = array
72 .varbin_validity()
73 .execute_mask(array.as_ref().len(), ctx)?;
74 let indices_validity = indices
75 .as_ref()
76 .validity()?
77 .execute_mask(indices.as_ref().len(), ctx)?;
78
79 let out_offset_ptype = taken_offset_ptype(offsets.ptype());
84 let offsets = offsets.reinterpret_cast(offsets.ptype().to_unsigned());
85 let indices = indices.reinterpret_cast(indices.ptype().to_unsigned());
86
87 let array = match_each_unsigned_integer_ptype!(indices.ptype(), |I| {
88 match offsets.ptype() {
89 PType::U8 => take::<I, u8, u32>(
90 dtype,
91 offsets.as_slice::<u8>(),
92 data.as_slice(),
93 indices.as_slice::<I>(),
94 array_validity,
95 indices_validity,
96 out_offset_ptype,
97 ),
98 PType::U16 => take::<I, u16, u32>(
99 dtype,
100 offsets.as_slice::<u16>(),
101 data.as_slice(),
102 indices.as_slice::<I>(),
103 array_validity,
104 indices_validity,
105 out_offset_ptype,
106 ),
107 PType::U32 => take::<I, u32, u32>(
108 dtype,
109 offsets.as_slice::<u32>(),
110 data.as_slice(),
111 indices.as_slice::<I>(),
112 array_validity,
113 indices_validity,
114 out_offset_ptype,
115 ),
116 PType::U64 => take::<I, u64, u64>(
117 dtype,
118 offsets.as_slice::<u64>(),
119 data.as_slice(),
120 indices.as_slice::<I>(),
121 array_validity,
122 indices_validity,
123 out_offset_ptype,
124 ),
125 _ => unreachable!("invalid PType for offsets"),
126 }
127 });
128
129 Ok(Some(array?.into_array()))
130 }
131}
132
133fn take_contiguous_ranges(
134 array: ArrayView<'_, VarBin>,
135 indices: ArrayView<'_, PiecewiseSequence>,
136 indices_ref: &ArrayRef,
137 ctx: &mut ExecutionCtx,
138) -> VortexResult<Option<ArrayRef>> {
139 let Some((starts, lengths)) = maybe_contiguous_slices(indices, ctx)? else {
140 return Ok(None);
141 };
142 let offsets = array.offsets().clone().execute::<PrimitiveArray>(ctx)?;
143 let out_offset_ptype = taken_offset_ptype(offsets.ptype());
144 let offsets = offsets.reinterpret_cast(offsets.ptype().to_unsigned());
145 let bytes = array.bytes();
146 let data = bytes.as_slice();
147 let dtype = array.dtype().clone();
148 let output_len = indices_ref.len();
149
150 let result = match lengths {
151 Columnar::Constant(lengths) => {
152 let length = constant_unsigned_usize(&lengths);
153 gather_slices_constant_dispatch(
154 &starts,
155 length,
156 &offsets,
157 data,
158 output_len,
159 out_offset_ptype,
160 )?
161 }
162 Columnar::Canonical(lengths) => {
163 let lengths = lengths.into_primitive();
164 gather_slices_dispatch(
165 &starts,
166 &lengths,
167 &offsets,
168 data,
169 output_len,
170 out_offset_ptype,
171 )?
172 }
173 };
174
175 let validity = array.validity()?.take(indices_ref)?;
176
177 unsafe {
180 Ok(Some(
181 VarBinArray::new_unchecked(result.offsets, result.data.freeze(), dtype, validity)
182 .into_array(),
183 ))
184 }
185}
186
187fn take<Index: IntegerPType, Offset: IntegerPType, NewOffset: IntegerPType>(
188 dtype: DType,
189 offsets: &[Offset],
190 data: &[u8],
191 indices: &[Index],
192 validity_mask: Mask,
193 indices_validity_mask: Mask,
194 out_offset_ptype: PType,
195) -> VortexResult<VarBinArray> {
196 if !validity_mask.all_true() || !indices_validity_mask.all_true() {
197 return Ok(take_nullable::<Index, Offset, NewOffset>(
198 dtype,
199 offsets,
200 data,
201 indices,
202 validity_mask,
203 indices_validity_mask,
204 out_offset_ptype,
205 ));
206 }
207
208 let mut new_offsets = BufferMut::<NewOffset>::with_capacity(indices.len() + 1);
209 new_offsets.push(NewOffset::zero());
210 let mut current_offset = NewOffset::zero();
211
212 for &idx in indices {
213 let idx = idx
214 .to_usize()
215 .unwrap_or_else(|| vortex_panic!("Failed to convert index to usize: {}", idx));
216 let start = offsets[idx];
217 let stop = offsets[idx + 1];
218
219 current_offset += NewOffset::from(stop - start).vortex_expect("offset type overflow");
220 new_offsets.push(current_offset);
221 }
222
223 let mut new_data = ByteBufferMut::with_capacity(current_offset.as_());
224
225 for idx in indices {
226 let idx = idx
227 .to_usize()
228 .unwrap_or_else(|| vortex_panic!("Failed to convert index to usize: {}", idx));
229 let start = offsets[idx]
230 .to_usize()
231 .vortex_expect("Failed to cast max offset to usize");
232 let stop = offsets[idx + 1]
233 .to_usize()
234 .vortex_expect("Failed to cast max offset to usize");
235 new_data.extend_from_slice(&data[start..stop]);
236 }
237
238 let array_validity = Validity::from(dtype.nullability());
239
240 let new_offsets = PrimitiveArray::new(new_offsets.freeze(), Validity::NonNullable)
242 .reinterpret_cast(out_offset_ptype)
243 .into_array();
244
245 unsafe {
248 Ok(VarBinArray::new_unchecked(
249 new_offsets,
250 new_data.freeze(),
251 dtype,
252 array_validity,
253 ))
254 }
255}
256
257struct GatheredPiecewiseVarBin {
258 offsets: ArrayRef,
259 data: ByteBufferMut,
260}
261
262fn gather_slices_constant_dispatch(
263 starts: &PrimitiveArray,
264 length: usize,
265 offsets: &PrimitiveArray,
266 data: &[u8],
267 output_len: usize,
268 out_offset_ptype: PType,
269) -> VortexResult<GatheredPiecewiseVarBin> {
270 match_each_unsigned_integer_ptype!(starts.ptype(), |S| {
271 gather_slices_constant_start_dispatch::<S>(
272 starts,
273 length,
274 offsets,
275 data,
276 output_len,
277 out_offset_ptype,
278 )
279 })
280}
281
282fn gather_slices_constant_start_dispatch<S>(
283 starts: &PrimitiveArray,
284 length: usize,
285 offsets: &PrimitiveArray,
286 data: &[u8],
287 output_len: usize,
288 out_offset_ptype: PType,
289) -> VortexResult<GatheredPiecewiseVarBin>
290where
291 S: UnsignedPType,
292{
293 match offsets.ptype() {
294 PType::U8 => gather_slices_constant_length::<S, u8, u32>(
295 offsets.as_slice::<u8>(),
296 data,
297 starts.as_slice::<S>(),
298 length,
299 output_len,
300 out_offset_ptype,
301 ),
302 PType::U16 => gather_slices_constant_length::<S, u16, u32>(
303 offsets.as_slice::<u16>(),
304 data,
305 starts.as_slice::<S>(),
306 length,
307 output_len,
308 out_offset_ptype,
309 ),
310 PType::U32 => gather_slices_constant_length::<S, u32, u32>(
311 offsets.as_slice::<u32>(),
312 data,
313 starts.as_slice::<S>(),
314 length,
315 output_len,
316 out_offset_ptype,
317 ),
318 PType::U64 => gather_slices_constant_length::<S, u64, u64>(
319 offsets.as_slice::<u64>(),
320 data,
321 starts.as_slice::<S>(),
322 length,
323 output_len,
324 out_offset_ptype,
325 ),
326 _ => unreachable!("offsets were reinterpreted to an unsigned integer ptype"),
327 }
328}
329
330fn gather_slices_dispatch(
331 starts: &PrimitiveArray,
332 lengths: &PrimitiveArray,
333 offsets: &PrimitiveArray,
334 data: &[u8],
335 output_len: usize,
336 out_offset_ptype: PType,
337) -> VortexResult<GatheredPiecewiseVarBin> {
338 match_each_unsigned_integer_ptype!(starts.ptype(), |S| {
339 gather_slices_start_dispatch::<S>(
340 starts,
341 lengths,
342 offsets,
343 data,
344 output_len,
345 out_offset_ptype,
346 )
347 })
348}
349
350fn gather_slices_start_dispatch<S>(
351 starts: &PrimitiveArray,
352 lengths: &PrimitiveArray,
353 offsets: &PrimitiveArray,
354 data: &[u8],
355 output_len: usize,
356 out_offset_ptype: PType,
357) -> VortexResult<GatheredPiecewiseVarBin>
358where
359 S: UnsignedPType,
360{
361 match_each_unsigned_integer_ptype!(lengths.ptype(), |L| {
362 gather_slices_start_length_dispatch::<S, L>(
363 starts,
364 lengths,
365 offsets,
366 data,
367 output_len,
368 out_offset_ptype,
369 )
370 })
371}
372
373fn gather_slices_start_length_dispatch<S, L>(
374 starts: &PrimitiveArray,
375 lengths: &PrimitiveArray,
376 offsets: &PrimitiveArray,
377 data: &[u8],
378 output_len: usize,
379 out_offset_ptype: PType,
380) -> VortexResult<GatheredPiecewiseVarBin>
381where
382 S: UnsignedPType,
383 L: UnsignedPType,
384{
385 match offsets.ptype() {
386 PType::U8 => gather_slices::<S, L, u8, u32>(
387 offsets.as_slice::<u8>(),
388 data,
389 starts.as_slice::<S>(),
390 lengths.as_slice::<L>(),
391 output_len,
392 out_offset_ptype,
393 ),
394 PType::U16 => gather_slices::<S, L, u16, u32>(
395 offsets.as_slice::<u16>(),
396 data,
397 starts.as_slice::<S>(),
398 lengths.as_slice::<L>(),
399 output_len,
400 out_offset_ptype,
401 ),
402 PType::U32 => gather_slices::<S, L, u32, u32>(
403 offsets.as_slice::<u32>(),
404 data,
405 starts.as_slice::<S>(),
406 lengths.as_slice::<L>(),
407 output_len,
408 out_offset_ptype,
409 ),
410 PType::U64 => gather_slices::<S, L, u64, u64>(
411 offsets.as_slice::<u64>(),
412 data,
413 starts.as_slice::<S>(),
414 lengths.as_slice::<L>(),
415 output_len,
416 out_offset_ptype,
417 ),
418 _ => unreachable!("offsets were reinterpreted to an unsigned integer ptype"),
419 }
420}
421
422fn gather_slices_constant_length<S, Offset, NewOffset>(
423 offsets: &[Offset],
424 data: &[u8],
425 starts: &[S],
426 length: usize,
427 output_len: usize,
428 out_offset_ptype: PType,
429) -> VortexResult<GatheredPiecewiseVarBin>
430where
431 S: UnsignedPType,
432 Offset: IntegerPType,
433 NewOffset: IntegerPType,
434{
435 let computed_len = starts
436 .len()
437 .checked_mul(length)
438 .ok_or_else(|| vortex_err!("PiecewiseSequenceArray output length overflows usize"))?;
439 vortex_ensure!(
440 computed_len == output_len,
441 "PiecewiseSequenceArray expanded length {computed_len} does not match declared length {output_len}"
442 );
443
444 let mut new_offsets = BufferMut::<NewOffset>::with_capacity(output_len + 1);
445 new_offsets.push(NewOffset::zero());
446 let mut output_bytes = 0usize;
447
448 for start in starts {
449 let start = start.as_();
450 if length == 0 {
451 continue;
452 }
453
454 let offset_range = &offsets[start..][..=length];
455 let byte_start = offset_range[0].as_();
456 let byte_end = offset_range[length].as_();
457 vortex_ensure!(
458 byte_start <= byte_end && byte_end <= data.len(),
459 "VarBin offsets range {byte_start}..{byte_end} exceeds data length {}",
460 data.len()
461 );
462
463 for &offset in &offset_range[1..] {
464 let offset = offset.as_();
465 let relative = offset.checked_sub(byte_start).ok_or_else(|| {
466 vortex_err!("VarBin offsets are not monotonic at offset {offset}")
467 })?;
468 let output_offset = output_bytes.checked_add(relative).ok_or_else(|| {
469 vortex_err!("PiecewiseSequence VarBin output byte length overflow")
470 })?;
471 new_offsets.push(new_offset_value::<NewOffset>(output_offset)?);
472 }
473
474 output_bytes = output_bytes
475 .checked_add(byte_end - byte_start)
476 .ok_or_else(|| vortex_err!("PiecewiseSequence VarBin output byte length overflow"))?;
477 }
478
479 let mut new_data = ByteBufferMut::with_capacity(output_bytes);
480 let spare = &mut new_data.spare_capacity_mut()[..output_bytes];
481 let mut cursor = 0usize;
482 for start in starts {
483 let start = start.as_();
484 if length == 0 {
485 continue;
486 }
487
488 let offset_range = &offsets[start..][..=length];
489 let byte_start = offset_range[0].as_();
490 let byte_end = offset_range[length].as_();
491 let src = &data[byte_start..byte_end];
492 unsafe {
494 ptr::copy_nonoverlapping(
495 src.as_ptr(),
496 spare[cursor..][..src.len()].as_mut_ptr().cast::<u8>(),
497 src.len(),
498 );
499 }
500 cursor += src.len();
501 }
502 unsafe { new_data.set_len(cursor) };
504 vortex_ensure!(
505 new_data.len() == output_bytes,
506 "PiecewiseSequenceArray gathered byte length {} does not match declared byte length {output_bytes}",
507 new_data.len()
508 );
509
510 let offsets = PrimitiveArray::new(new_offsets.freeze(), Validity::NonNullable)
511 .reinterpret_cast(out_offset_ptype)
512 .into_array();
513 Ok(GatheredPiecewiseVarBin {
514 offsets,
515 data: new_data,
516 })
517}
518
519fn gather_slices<S, L, Offset, NewOffset>(
520 offsets: &[Offset],
521 data: &[u8],
522 starts: &[S],
523 lengths: &[L],
524 output_len: usize,
525 out_offset_ptype: PType,
526) -> VortexResult<GatheredPiecewiseVarBin>
527where
528 S: UnsignedPType,
529 L: UnsignedPType,
530 Offset: IntegerPType,
531 NewOffset: IntegerPType,
532{
533 let mut new_offsets = BufferMut::<NewOffset>::with_capacity(output_len + 1);
534 new_offsets.push(NewOffset::zero());
535 let mut output_bytes = 0usize;
536
537 for (&start, &length) in starts.iter().zip_eq(lengths) {
538 let start = start.as_();
539 let length = length.as_();
540 if length == 0 {
541 continue;
542 }
543
544 let offset_range = &offsets[start..][..=length];
545 let byte_start = offset_range[0].as_();
546 let byte_end = offset_range[length].as_();
547 vortex_ensure!(
548 byte_start <= byte_end && byte_end <= data.len(),
549 "VarBin offsets range {byte_start}..{byte_end} exceeds data length {}",
550 data.len()
551 );
552
553 for &offset in &offset_range[1..] {
554 let offset = offset.as_();
555 let relative = offset.checked_sub(byte_start).ok_or_else(|| {
556 vortex_err!("VarBin offsets are not monotonic at offset {offset}")
557 })?;
558 let output_offset = output_bytes.checked_add(relative).ok_or_else(|| {
559 vortex_err!("PiecewiseSequence VarBin output byte length overflow")
560 })?;
561 new_offsets.push(new_offset_value::<NewOffset>(output_offset)?);
562 }
563
564 output_bytes = output_bytes
565 .checked_add(byte_end - byte_start)
566 .ok_or_else(|| vortex_err!("PiecewiseSequence VarBin output byte length overflow"))?;
567 }
568 vortex_ensure!(
569 new_offsets.len() == output_len + 1,
570 "PiecewiseSequenceArray expanded length {} does not match declared length {output_len}",
571 new_offsets.len() - 1
572 );
573
574 let mut new_data = ByteBufferMut::with_capacity(output_bytes);
575 let spare = &mut new_data.spare_capacity_mut()[..output_bytes];
576 let mut cursor = 0usize;
577 for (&start, &length) in starts.iter().zip_eq(lengths) {
578 let start = start.as_();
579 let length = length.as_();
580 if length == 0 {
581 continue;
582 }
583
584 let offset_range = &offsets[start..][..=length];
585 let byte_start = offset_range[0].as_();
586 let byte_end = offset_range[length].as_();
587 let src = &data[byte_start..byte_end];
588 unsafe {
590 ptr::copy_nonoverlapping(
591 src.as_ptr(),
592 spare[cursor..][..src.len()].as_mut_ptr().cast::<u8>(),
593 src.len(),
594 );
595 }
596 cursor += src.len();
597 }
598 unsafe { new_data.set_len(cursor) };
600 vortex_ensure!(
601 new_data.len() == output_bytes,
602 "PiecewiseSequenceArray gathered byte length {} does not match declared byte length {output_bytes}",
603 new_data.len()
604 );
605
606 let offsets = PrimitiveArray::new(new_offsets.freeze(), Validity::NonNullable)
607 .reinterpret_cast(out_offset_ptype)
608 .into_array();
609 Ok(GatheredPiecewiseVarBin {
610 offsets,
611 data: new_data,
612 })
613}
614
615fn new_offset_value<T: IntegerPType>(value: usize) -> VortexResult<T> {
616 T::from(value).ok_or_else(|| {
617 vortex_err!(
618 "PiecewiseSequence VarBin offset value {value} does not fit in {}",
619 T::PTYPE
620 )
621 })
622}
623
624fn take_nullable<Index: IntegerPType, Offset: IntegerPType, NewOffset: IntegerPType>(
625 dtype: DType,
626 offsets: &[Offset],
627 data: &[u8],
628 indices: &[Index],
629 data_validity: Mask,
630 indices_validity: Mask,
631 out_offset_ptype: PType,
632) -> VarBinArray {
633 let mut new_offsets = BufferMut::<NewOffset>::with_capacity(indices.len() + 1);
634 new_offsets.push(NewOffset::zero());
635 let mut current_offset = NewOffset::zero();
636
637 let mut validity_buffer = BitBufferMut::with_capacity(indices.len());
638
639 let mut valid_indices = Vec::with_capacity(indices.len());
641
642 for (data_idx, index_valid) in indices.iter().zip(indices_validity.iter()) {
644 if !index_valid {
645 validity_buffer.append(false);
646 new_offsets.push(current_offset);
647 continue;
648 }
649 let data_idx_usize = data_idx
650 .to_usize()
651 .unwrap_or_else(|| vortex_panic!("Failed to convert index to usize: {}", data_idx));
652 if data_validity.value(data_idx_usize) {
653 validity_buffer.append(true);
654 let start = offsets[data_idx_usize];
655 let stop = offsets[data_idx_usize + 1];
656 current_offset += NewOffset::from(stop - start).vortex_expect("offset type overflow");
657 new_offsets.push(current_offset);
658 valid_indices.push(data_idx_usize);
659 } else {
660 validity_buffer.append(false);
661 new_offsets.push(current_offset);
662 }
663 }
664
665 let mut new_data = ByteBufferMut::with_capacity(current_offset.as_());
666
667 for data_idx in valid_indices {
669 let start = offsets[data_idx]
670 .to_usize()
671 .vortex_expect("Failed to cast max offset to usize");
672 let stop = offsets[data_idx + 1]
673 .to_usize()
674 .vortex_expect("Failed to cast max offset to usize");
675 new_data.extend_from_slice(&data[start..stop]);
676 }
677
678 let array_validity = Validity::from(validity_buffer.freeze());
679
680 let new_offsets = PrimitiveArray::new(new_offsets.freeze(), Validity::NonNullable)
682 .reinterpret_cast(out_offset_ptype)
683 .into_array();
684
685 unsafe { VarBinArray::new_unchecked(new_offsets, new_data.freeze(), dtype, array_validity) }
688}
689
690#[cfg(test)]
691mod tests {
692 use std::iter;
693
694 use rstest::rstest;
695 use vortex_buffer::ByteBuffer;
696 use vortex_buffer::buffer;
697
698 use crate::IntoArray;
699 use crate::VortexSessionExecute;
700 use crate::array_session;
701 use crate::arrays::VarBinArray;
702 use crate::arrays::VarBinViewArray;
703 use crate::arrays::varbin::compute::take::PrimitiveArray;
704 use crate::assert_arrays_eq;
705 use crate::compute::conformance::take::test_take_conformance;
706 use crate::dtype::DType;
707 use crate::dtype::Nullability;
708 use crate::validity::Validity;
709
710 #[test]
711 fn test_null_take() {
712 let arr = VarBinArray::from_iter([Some("h")], DType::Utf8(Nullability::NonNullable));
713
714 let idx1: PrimitiveArray = (0..1).collect();
715
716 assert_eq!(
717 arr.take(idx1.into_array()).unwrap().dtype(),
718 &DType::Utf8(Nullability::NonNullable)
719 );
720
721 let idx2: PrimitiveArray = PrimitiveArray::from_option_iter(vec![Some(0)]);
722
723 assert_eq!(
724 arr.take(idx2.into_array()).unwrap().dtype(),
725 &DType::Utf8(Nullability::Nullable)
726 );
727 }
728
729 #[rstest]
730 #[case(VarBinArray::from_iter(
731 ["hello", "world", "test", "data", "array"].map(Some),
732 DType::Utf8(Nullability::NonNullable),
733 ))]
734 #[case(VarBinArray::from_iter(
735 [Some("hello"), None, Some("test"), Some("data"), None],
736 DType::Utf8(Nullability::Nullable),
737 ))]
738 #[case(VarBinArray::from_iter(
739 [b"hello".as_slice(), b"world", b"test", b"data", b"array"].map(Some),
740 DType::Binary(Nullability::NonNullable),
741 ))]
742 #[case(VarBinArray::from_iter(["single"].map(Some), DType::Utf8(Nullability::NonNullable)))]
743 fn test_take_varbin_conformance(#[case] array: VarBinArray) {
744 test_take_conformance(
745 &array.into_array(),
746 &mut array_session().create_execution_ctx(),
747 );
748 }
749
750 #[test]
751 fn test_take_overflow() {
752 let mut ctx = array_session().create_execution_ctx();
753 let scream = iter::once("a").cycle().take(128).collect::<String>();
754 let bytes = ByteBuffer::copy_from(scream.as_bytes());
755 let offsets = buffer![0u8, 128u8].into_array();
756
757 let array = VarBinArray::new(
758 offsets,
759 bytes,
760 DType::Utf8(Nullability::NonNullable),
761 Validity::NonNullable,
762 );
763
764 let indices = buffer![0u32; 3].into_array();
765 let taken = array.take(indices).unwrap();
766
767 let expected = VarBinViewArray::from_iter(
768 [Some(scream.clone()), Some(scream.clone()), Some(scream)],
769 DType::Utf8(Nullability::NonNullable),
770 );
771 assert_arrays_eq!(expected, taken, &mut ctx);
772 }
773}