1use std::iter;
5use std::ops::RangeInclusive;
6use std::sync::Arc;
7
8use arbitrary::Arbitrary;
9use arbitrary::Error::IncorrectFormat;
10use arbitrary::Result;
11use arbitrary::Unstructured;
12use vortex_buffer::BitBuffer;
13use vortex_buffer::Buffer;
14use vortex_error::VortexExpect;
15
16use crate::ArrayRef;
17use crate::IntoArray;
18use crate::arrays::BoolArray;
19use crate::arrays::ChunkedArray;
20use crate::arrays::NullArray;
21use crate::arrays::Primitive;
22use crate::arrays::PrimitiveArray;
23use crate::arrays::StructArray;
24use crate::arrays::VarBinArray;
25use crate::arrays::VarBinViewArray;
26use crate::arrays::primitive::PrimitiveArrayExt;
27use crate::builders::ArrayBuilder;
28use crate::builders::DecimalBuilder;
29use crate::builders::FixedSizeListBuilder;
30use crate::builders::ListViewBuilder;
31use crate::builders::MapBuilder;
32use crate::dtype::DType;
33use crate::dtype::IntegerPType;
34use crate::dtype::MapDType;
35use crate::dtype::NativePType;
36use crate::dtype::Nullability;
37use crate::dtype::OffsetBuilderPType;
38use crate::dtype::PType;
39use crate::match_each_decimal_value_type;
40use crate::scalar::Scalar;
41use crate::scalar::arbitrary::random_scalar;
42use crate::validity::Validity;
43
44#[derive(Clone, Debug)]
46pub struct ArbitraryArray(pub ArrayRef);
47
48pub trait ArbitraryWith<'a, C>: Sized {
50 fn arbitrary_with_config(u: &mut Unstructured<'a>, config: &C) -> Result<Self>;
52}
53
54#[derive(Clone, Debug)]
56pub struct ArbitraryArrayConfig {
57 pub dtype: Option<DType>,
59 pub len: RangeInclusive<usize>,
61}
62
63impl<'a> ArbitraryWith<'a, ArbitraryArrayConfig> for ArbitraryArray {
64 fn arbitrary_with_config(
65 u: &mut Unstructured<'a>,
66 config: &ArbitraryArrayConfig,
67 ) -> Result<Self> {
68 if config.len.is_empty() {
69 return Err(IncorrectFormat);
70 }
71
72 let dtype = match &config.dtype {
73 Some(dtype) => dtype.clone(),
74 None => u.arbitrary()?,
75 };
76 let len = u.int_in_range(config.len.clone())?;
77
78 random_array(u, &dtype, Some(len)).map(ArbitraryArray)
79 }
80}
81
82fn split_number_into_parts(n: usize, parts: usize) -> Vec<usize> {
83 let reminder = n % parts;
84 let division = (n - reminder) / parts;
85 iter::repeat_n(division, parts - reminder)
86 .chain(iter::repeat_n(division + 1, reminder))
87 .collect()
88}
89
90fn random_array(u: &mut Unstructured, dtype: &DType, len: Option<usize>) -> Result<ArrayRef> {
92 let num_chunks = u.int_in_range(1..=3)?;
93 let chunk_lens = len.map(|l| split_number_into_parts(l, num_chunks));
94 let mut chunks = (0..num_chunks)
95 .map(|i| {
96 let chunk_len = chunk_lens.as_ref().map(|c| c[i]);
97 random_array_chunk(u, dtype, chunk_len)
98 })
99 .collect::<Result<Vec<_>>>()?;
100
101 if chunks.len() == 1 {
102 Ok(chunks.remove(0))
103 } else {
104 let dtype = chunks[0].dtype().clone();
105 Ok(ChunkedArray::try_new(chunks, dtype)
106 .vortex_expect("operation should succeed in arbitrary impl")
107 .into_array())
108 }
109}
110
111fn random_array_chunk(
113 u: &mut Unstructured<'_>,
114 dtype: &DType,
115 chunk_len: Option<usize>,
116) -> Result<ArrayRef> {
117 match dtype {
118 DType::Null => Ok(NullArray::new(
119 chunk_len
120 .map(Ok)
121 .unwrap_or_else(|| u.int_in_range(0..=100))?,
122 )
123 .into_array()),
124 DType::Bool(n) => random_bool(u, *n, chunk_len),
125 DType::Primitive(ptype, n) => match ptype {
126 PType::U8 => random_primitive::<u8>(u, *n, chunk_len),
127 PType::U16 => random_primitive::<u16>(u, *n, chunk_len),
128 PType::U32 => random_primitive::<u32>(u, *n, chunk_len),
129 PType::U64 => random_primitive::<u64>(u, *n, chunk_len),
130 PType::I8 => random_primitive::<i8>(u, *n, chunk_len),
131 PType::I16 => random_primitive::<i16>(u, *n, chunk_len),
132 PType::I32 => random_primitive::<i32>(u, *n, chunk_len),
133 PType::I64 => random_primitive::<i64>(u, *n, chunk_len),
134 PType::F16 => {
135 let prim = random_primitive::<u16>(u, *n, chunk_len)?
136 .as_::<Primitive>()
137 .reinterpret_cast(PType::F16)
138 .into_array();
139 Ok(prim)
140 }
141 PType::F32 => random_primitive::<f32>(u, *n, chunk_len),
142 PType::F64 => random_primitive::<f64>(u, *n, chunk_len),
143 },
144 d @ DType::Decimal(decimal, n) => {
145 let elem_len = chunk_len.unwrap_or(u.int_in_range(0..=20)?);
146 match_each_decimal_value_type!(DecimalType::smallest_decimal_value_type(decimal), |D| {
147 let mut builder = DecimalBuilder::new_in::<D>(
148 *decimal,
149 *n,
150 vortex_buffer::BufferAllocatorRef::static_ref(),
151 );
152 for _i in 0..elem_len {
153 let random_decimal = random_scalar(u, d)?;
154 builder.append_scalar(&random_decimal).vortex_expect(
155 "was somehow unable to append a decimal to a decimal builder",
156 );
157 }
158 Ok(builder.finish())
159 })
160 }
161 DType::Utf8(n) => random_string(u, *n, chunk_len),
162 DType::Binary(n) => random_bytes(u, *n, chunk_len),
163 DType::List(elem_dtype, null) => random_list(u, elem_dtype, *null, chunk_len),
164 DType::FixedSizeList(elem_dtype, list_size, null) => {
165 random_fixed_size_list(u, elem_dtype, *list_size, *null, chunk_len)
166 }
167 DType::Map(map_dtype, nullability) => {
168 random_map(u, map_dtype.clone(), *nullability, chunk_len)
169 }
170 DType::Struct(sdt, n) => {
171 let first_array = sdt
172 .fields()
173 .next()
174 .map(|d| random_array(u, &d, chunk_len))
175 .transpose()?;
176 let resolved_len = first_array
177 .as_ref()
178 .map(|a| a.len())
179 .or(chunk_len)
180 .map(Ok)
181 .unwrap_or_else(|| u.int_in_range(0..=100))?;
182 let children = first_array
183 .into_iter()
184 .map(Ok)
185 .chain(
186 sdt.fields()
187 .skip(1)
188 .map(|d| random_array(u, &d, Some(resolved_len))),
189 )
190 .collect::<Result<Vec<_>>>()?;
191 Ok(StructArray::try_new(
192 sdt.names().clone(),
193 children,
194 resolved_len,
195 random_validity(u, *n, resolved_len)?,
196 )
197 .vortex_expect("operation should succeed in arbitrary impl")
198 .into_array())
199 }
200 DType::Union(..) => todo!("TODO(connor)[Union]: unimplemented"),
201 DType::Variant(_) => {
202 unimplemented!("Variant arrays are not implemented")
203 }
204 DType::Extension(..) => {
205 unimplemented!("Extension arrays are not implemented")
206 }
207 }
208}
209
210fn random_map(
211 u: &mut Unstructured,
212 map_dtype: MapDType,
213 nullability: Nullability,
214 chunk_len: Option<usize>,
215) -> Result<ArrayRef> {
216 let array_length = chunk_len.unwrap_or(u.int_in_range(0..=20)?);
217 let key_dtype = map_dtype.key_dtype();
218 let value_dtype = map_dtype.value_dtype();
219 let dtype = DType::Map(map_dtype.clone(), nullability);
220 let mut builder = MapBuilder::<u64, u64>::with_capacity_in(
221 map_dtype,
222 nullability,
223 array_length,
224 vortex_buffer::BufferAllocatorRef::static_ref(),
225 );
226
227 for _ in 0..array_length {
228 if nullability == Nullability::Nullable && u.arbitrary::<bool>()? {
229 builder.append_null();
230 } else {
231 let entry_count = u.int_in_range(0..=20)?;
232 let entries = (0..entry_count)
233 .map(|_| {
234 let key = random_scalar(u, &key_dtype)?;
235 let value = random_scalar(u, &value_dtype)?;
236 Ok((key, value))
237 })
238 .collect::<Result<Vec<_>>>()?;
239 let scalar = Scalar::try_map(dtype.clone(), entries)
240 .vortex_expect("generated map scalar should be valid");
241 builder
242 .append_scalar(&scalar)
243 .vortex_expect("generated map scalar should append");
244 }
245 }
246
247 Ok(builder.finish_into_map().into_array())
248}
249
250fn random_fixed_size_list(
254 u: &mut Unstructured,
255 elem_dtype: &Arc<DType>,
256 list_size: u32,
257 null: Nullability,
258 chunk_len: Option<usize>,
259) -> Result<ArrayRef> {
260 let array_length = chunk_len.unwrap_or(u.int_in_range(0..=20)?);
261
262 let mut builder = FixedSizeListBuilder::with_capacity_in(
263 Arc::clone(elem_dtype),
264 list_size,
265 null,
266 array_length,
267 vortex_buffer::BufferAllocatorRef::static_ref(),
268 );
269
270 for _ in 0..array_length {
271 if null == Nullability::Nullable && u.arbitrary::<bool>()? {
272 builder.append_null();
273 } else {
274 builder
275 .append_value(random_list_scalar(u, elem_dtype, list_size, null)?.as_list())
276 .vortex_expect("can append value");
277 }
278 }
279
280 Ok(builder.finish())
281}
282
283fn random_list(
287 u: &mut Unstructured,
288 elem_dtype: &Arc<DType>,
289 null: Nullability,
290 chunk_len: Option<usize>,
291) -> Result<ArrayRef> {
292 let array_length = chunk_len.unwrap_or(u.int_in_range(0..=20)?);
293 let max_total_elements = array_length as u64 * 20;
295
296 match u.int_in_range(0..=3)? {
297 0 if i32::max_value_as_u64() >= max_total_elements => {
298 random_list_with_offset_type::<i32>(u, elem_dtype, null, array_length)
299 }
300 1 if u32::max_value_as_u64() >= max_total_elements => {
301 random_list_with_offset_type::<u32>(u, elem_dtype, null, array_length)
302 }
303 _ => {
305 if u.arbitrary::<bool>()? {
306 random_list_with_offset_type::<i64>(u, elem_dtype, null, array_length)
307 } else {
308 random_list_with_offset_type::<u64>(u, elem_dtype, null, array_length)
309 }
310 }
311 }
312}
313
314fn random_list_with_offset_type<O: OffsetBuilderPType>(
316 u: &mut Unstructured,
317 elem_dtype: &Arc<DType>,
318 null: Nullability,
319 array_length: usize,
320) -> Result<ArrayRef> {
321 let mut builder = ListViewBuilder::<O, O>::with_capacity_in(
322 Arc::clone(elem_dtype),
323 null,
324 array_length,
325 10,
326 vortex_buffer::BufferAllocatorRef::static_ref(),
327 );
328
329 for _ in 0..array_length {
330 if null == Nullability::Nullable && u.arbitrary::<bool>()? {
331 builder.append_null();
332 } else {
333 let list_size = u.int_in_range(0..=20)?;
334 builder
335 .append_value(random_list_scalar(u, elem_dtype, list_size, null)?.as_list())
336 .vortex_expect("can append value");
337 }
338 }
339
340 Ok(builder.finish())
341}
342
343fn random_list_scalar(
345 u: &mut Unstructured,
346 elem_dtype: &Arc<DType>,
347 list_size: u32,
348 null: Nullability,
349) -> Result<Scalar> {
350 let elems = (0..list_size)
351 .map(|_| random_scalar(u, elem_dtype))
352 .collect::<Result<Vec<_>>>()?;
353 Ok(Scalar::list(Arc::clone(elem_dtype), elems, null))
354}
355
356fn random_string(
357 u: &mut Unstructured,
358 nullability: Nullability,
359 len: Option<usize>,
360) -> Result<ArrayRef> {
361 match nullability {
362 Nullability::NonNullable => {
363 let v = arbitrary_vec_of_len::<String>(u, len)?;
364 Ok(match u.int_in_range(0..=1)? {
365 0 => VarBinArray::from_vec(v, DType::Utf8(Nullability::NonNullable)).into_array(),
366 1 => VarBinViewArray::from_iter_str(v).into_array(),
367 _ => unreachable!(),
368 })
369 }
370 Nullability::Nullable => {
371 let v = arbitrary_vec_of_len::<Option<String>>(u, len)?;
372 Ok(match u.int_in_range(0..=1)? {
373 0 => VarBinArray::from_iter(v, DType::Utf8(Nullability::Nullable)).into_array(),
374 1 => VarBinViewArray::from_iter_nullable_str(v).into_array(),
375 _ => unreachable!(),
376 })
377 }
378 }
379}
380
381fn random_bytes(
382 u: &mut Unstructured,
383 nullability: Nullability,
384 len: Option<usize>,
385) -> Result<ArrayRef> {
386 match nullability {
387 Nullability::NonNullable => {
388 let v = arbitrary_vec_of_len::<Vec<u8>>(u, len)?;
389 Ok(match u.int_in_range(0..=1)? {
390 0 => VarBinArray::from_vec(v, DType::Binary(Nullability::NonNullable)).into_array(),
391 1 => VarBinViewArray::from_iter_bin(v).into_array(),
392 _ => unreachable!(),
393 })
394 }
395 Nullability::Nullable => {
396 let v = arbitrary_vec_of_len::<Option<Vec<u8>>>(u, len)?;
397 Ok(match u.int_in_range(0..=1)? {
398 0 => VarBinArray::from_iter(v, DType::Binary(Nullability::Nullable)).into_array(),
399 1 => VarBinViewArray::from_iter_nullable_bin(v).into_array(),
400 _ => unreachable!(),
401 })
402 }
403 }
404}
405
406fn random_primitive<'a, T: Arbitrary<'a> + NativePType>(
407 u: &mut Unstructured<'a>,
408 nullability: Nullability,
409 len: Option<usize>,
410) -> Result<ArrayRef> {
411 let v = arbitrary_vec_of_len::<T>(u, len)?;
412 let validity = random_validity(u, nullability, v.len())?;
413 Ok(PrimitiveArray::new(Buffer::copy_from(v), validity).into_array())
414}
415
416fn random_bool(
417 u: &mut Unstructured,
418 nullability: Nullability,
419 len: Option<usize>,
420) -> Result<ArrayRef> {
421 let v = arbitrary_vec_of_len(u, len)?;
422 let validity = random_validity(u, nullability, v.len())?;
423 Ok(BoolArray::new(BitBuffer::from(v), validity).into_array())
424}
425
426pub fn random_validity(
427 u: &mut Unstructured,
428 nullability: Nullability,
429 len: usize,
430) -> Result<Validity> {
431 match nullability {
432 Nullability::NonNullable => Ok(Validity::NonNullable),
433 Nullability::Nullable => Ok(match u.int_in_range(0..=2)? {
434 0 => Validity::AllValid,
435 1 => Validity::AllInvalid,
436 2 => Validity::from_iter(arbitrary_vec_of_len::<bool>(u, Some(len))?),
437 _ => unreachable!(),
438 }),
439 }
440}
441
442fn arbitrary_vec_of_len<'a, T: Arbitrary<'a>>(
443 u: &mut Unstructured<'a>,
444 len: Option<usize>,
445) -> Result<Vec<T>> {
446 len.map(|l| (0..l).map(|_| T::arbitrary(u)).collect::<Result<Vec<_>>>())
447 .unwrap_or_else(|| Vec::<T>::arbitrary(u))
448}