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