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(..) | DType::Variant(_) | DType::Extension(..) => Err(IncorrectFormat),
201 }
202}
203
204fn random_map(
205 u: &mut Unstructured,
206 map_dtype: MapDType,
207 nullability: Nullability,
208 chunk_len: Option<usize>,
209) -> Result<ArrayRef> {
210 let array_length = chunk_len.unwrap_or(u.int_in_range(0..=20)?);
211 let key_dtype = map_dtype.key_dtype();
212 let value_dtype = map_dtype.value_dtype();
213 let dtype = DType::Map(map_dtype.clone(), nullability);
214 let mut builder = MapBuilder::<u64, u64>::with_capacity_in(
215 map_dtype,
216 nullability,
217 array_length,
218 vortex_buffer::BufferAllocatorRef::static_ref(),
219 );
220
221 for _ in 0..array_length {
222 if nullability == Nullability::Nullable && u.arbitrary::<bool>()? {
223 builder.append_null();
224 } else {
225 let entry_count = u.int_in_range(0..=20)?;
226 let entries = (0..entry_count)
227 .map(|_| {
228 let key = random_scalar(u, &key_dtype)?;
229 let value = random_scalar(u, &value_dtype)?;
230 Ok((key, value))
231 })
232 .collect::<Result<Vec<_>>>()?;
233 let scalar = Scalar::try_map(dtype.clone(), entries)
234 .vortex_expect("generated map scalar should be valid");
235 builder
236 .append_scalar(&scalar)
237 .vortex_expect("generated map scalar should append");
238 }
239 }
240
241 Ok(builder.finish_into_map().into_array())
242}
243
244fn random_fixed_size_list(
248 u: &mut Unstructured,
249 elem_dtype: &Arc<DType>,
250 list_size: u32,
251 null: Nullability,
252 chunk_len: Option<usize>,
253) -> Result<ArrayRef> {
254 let array_length = chunk_len.unwrap_or(u.int_in_range(0..=20)?);
255
256 let mut builder = FixedSizeListBuilder::with_capacity_in(
257 Arc::clone(elem_dtype),
258 list_size,
259 null,
260 array_length,
261 vortex_buffer::BufferAllocatorRef::static_ref(),
262 );
263
264 for _ in 0..array_length {
265 if null == Nullability::Nullable && u.arbitrary::<bool>()? {
266 builder.append_null();
267 } else {
268 builder
269 .append_value(random_list_scalar(u, elem_dtype, list_size, null)?.as_list())
270 .vortex_expect("can append value");
271 }
272 }
273
274 Ok(builder.finish())
275}
276
277fn random_list(
281 u: &mut Unstructured,
282 elem_dtype: &Arc<DType>,
283 null: Nullability,
284 chunk_len: Option<usize>,
285) -> Result<ArrayRef> {
286 let array_length = chunk_len.unwrap_or(u.int_in_range(0..=20)?);
287 let max_total_elements = array_length as u64 * 20;
289
290 match u.int_in_range(0..=3)? {
291 0 if i32::max_value_as_u64() >= max_total_elements => {
292 random_list_with_offset_type::<i32>(u, elem_dtype, null, array_length)
293 }
294 1 if u32::max_value_as_u64() >= max_total_elements => {
295 random_list_with_offset_type::<u32>(u, elem_dtype, null, array_length)
296 }
297 _ => {
299 if u.arbitrary::<bool>()? {
300 random_list_with_offset_type::<i64>(u, elem_dtype, null, array_length)
301 } else {
302 random_list_with_offset_type::<u64>(u, elem_dtype, null, array_length)
303 }
304 }
305 }
306}
307
308fn random_list_with_offset_type<O: OffsetBuilderPType>(
310 u: &mut Unstructured,
311 elem_dtype: &Arc<DType>,
312 null: Nullability,
313 array_length: usize,
314) -> Result<ArrayRef> {
315 let mut builder = ListViewBuilder::<O, O>::with_capacity_in(
316 Arc::clone(elem_dtype),
317 null,
318 array_length,
319 10,
320 vortex_buffer::BufferAllocatorRef::static_ref(),
321 );
322
323 for _ in 0..array_length {
324 if null == Nullability::Nullable && u.arbitrary::<bool>()? {
325 builder.append_null();
326 } else {
327 let list_size = u.int_in_range(0..=20)?;
328 builder
329 .append_value(random_list_scalar(u, elem_dtype, list_size, null)?.as_list())
330 .vortex_expect("can append value");
331 }
332 }
333
334 Ok(builder.finish())
335}
336
337fn random_list_scalar(
339 u: &mut Unstructured,
340 elem_dtype: &Arc<DType>,
341 list_size: u32,
342 null: Nullability,
343) -> Result<Scalar> {
344 let elems = (0..list_size)
345 .map(|_| random_scalar(u, elem_dtype))
346 .collect::<Result<Vec<_>>>()?;
347 Ok(Scalar::list(Arc::clone(elem_dtype), elems, null))
348}
349
350fn random_string(
351 u: &mut Unstructured,
352 nullability: Nullability,
353 len: Option<usize>,
354) -> Result<ArrayRef> {
355 match nullability {
356 Nullability::NonNullable => {
357 let v = arbitrary_vec_of_len::<String>(u, len)?;
358 Ok(match u.int_in_range(0..=1)? {
359 0 => VarBinArray::from_vec(v, DType::Utf8(Nullability::NonNullable)).into_array(),
360 1 => VarBinViewArray::from_iter_str(v).into_array(),
361 _ => unreachable!(),
362 })
363 }
364 Nullability::Nullable => {
365 let v = arbitrary_vec_of_len::<Option<String>>(u, len)?;
366 Ok(match u.int_in_range(0..=1)? {
367 0 => VarBinArray::from_iter(v, DType::Utf8(Nullability::Nullable)).into_array(),
368 1 => VarBinViewArray::from_iter_nullable_str(v).into_array(),
369 _ => unreachable!(),
370 })
371 }
372 }
373}
374
375fn random_bytes(
376 u: &mut Unstructured,
377 nullability: Nullability,
378 len: Option<usize>,
379) -> Result<ArrayRef> {
380 match nullability {
381 Nullability::NonNullable => {
382 let v = arbitrary_vec_of_len::<Vec<u8>>(u, len)?;
383 Ok(match u.int_in_range(0..=1)? {
384 0 => VarBinArray::from_vec(v, DType::Binary(Nullability::NonNullable)).into_array(),
385 1 => VarBinViewArray::from_iter_bin(v).into_array(),
386 _ => unreachable!(),
387 })
388 }
389 Nullability::Nullable => {
390 let v = arbitrary_vec_of_len::<Option<Vec<u8>>>(u, len)?;
391 Ok(match u.int_in_range(0..=1)? {
392 0 => VarBinArray::from_iter(v, DType::Binary(Nullability::Nullable)).into_array(),
393 1 => VarBinViewArray::from_iter_nullable_bin(v).into_array(),
394 _ => unreachable!(),
395 })
396 }
397 }
398}
399
400fn random_primitive<'a, T: Arbitrary<'a> + NativePType>(
401 u: &mut Unstructured<'a>,
402 nullability: Nullability,
403 len: Option<usize>,
404) -> Result<ArrayRef> {
405 let v = arbitrary_vec_of_len::<T>(u, len)?;
406 let validity = random_validity(u, nullability, v.len())?;
407 Ok(PrimitiveArray::new(Buffer::copy_from(v), validity).into_array())
408}
409
410fn random_bool(
411 u: &mut Unstructured,
412 nullability: Nullability,
413 len: Option<usize>,
414) -> Result<ArrayRef> {
415 let v = arbitrary_vec_of_len(u, len)?;
416 let validity = random_validity(u, nullability, v.len())?;
417 Ok(BoolArray::new(BitBuffer::from(v), validity).into_array())
418}
419
420pub fn random_validity(
421 u: &mut Unstructured,
422 nullability: Nullability,
423 len: usize,
424) -> Result<Validity> {
425 match nullability {
426 Nullability::NonNullable => Ok(Validity::NonNullable),
427 Nullability::Nullable => Ok(match u.int_in_range(0..=2)? {
428 0 => Validity::AllValid,
429 1 => Validity::AllInvalid,
430 2 => Validity::from_iter(arbitrary_vec_of_len::<bool>(u, Some(len))?),
431 _ => unreachable!(),
432 }),
433 }
434}
435
436fn arbitrary_vec_of_len<'a, T: Arbitrary<'a>>(
437 u: &mut Unstructured<'a>,
438 len: Option<usize>,
439) -> Result<Vec<T>> {
440 len.map(|l| (0..l).map(|_| T::arbitrary(u)).collect::<Result<Vec<_>>>())
441 .unwrap_or_else(|| Vec::<T>::arbitrary(u))
442}