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::<D>(*decimal, *n);
148 for _i in 0..elem_len {
149 let random_decimal = random_scalar(u, d)?;
150 builder.append_scalar(&random_decimal).vortex_expect(
151 "was somehow unable to append a decimal to a decimal builder",
152 );
153 }
154 Ok(builder.finish())
155 })
156 }
157 DType::Utf8(n) => random_string(u, *n, chunk_len),
158 DType::Binary(n) => random_bytes(u, *n, chunk_len),
159 DType::List(elem_dtype, null) => random_list(u, elem_dtype, *null, chunk_len),
160 DType::FixedSizeList(elem_dtype, list_size, null) => {
161 random_fixed_size_list(u, elem_dtype, *list_size, *null, chunk_len)
162 }
163 DType::Map(map_dtype, nullability) => {
164 random_map(u, map_dtype.clone(), *nullability, chunk_len)
165 }
166 DType::Struct(sdt, n) => {
167 let first_array = sdt
168 .fields()
169 .next()
170 .map(|d| random_array(u, &d, chunk_len))
171 .transpose()?;
172 let resolved_len = first_array
173 .as_ref()
174 .map(|a| a.len())
175 .or(chunk_len)
176 .map(Ok)
177 .unwrap_or_else(|| u.int_in_range(0..=100))?;
178 let children = first_array
179 .into_iter()
180 .map(Ok)
181 .chain(
182 sdt.fields()
183 .skip(1)
184 .map(|d| random_array(u, &d, Some(resolved_len))),
185 )
186 .collect::<Result<Vec<_>>>()?;
187 Ok(StructArray::try_new(
188 sdt.names().clone(),
189 children,
190 resolved_len,
191 random_validity(u, *n, resolved_len)?,
192 )
193 .vortex_expect("operation should succeed in arbitrary impl")
194 .into_array())
195 }
196 DType::Union(..) => todo!("TODO(connor)[Union]: unimplemented"),
197 DType::Variant(_) => {
198 unimplemented!("Variant arrays are not implemented")
199 }
200 DType::Extension(..) => {
201 unimplemented!("Extension arrays are not implemented")
202 }
203 }
204}
205
206fn random_map(
207 u: &mut Unstructured,
208 map_dtype: MapDType,
209 nullability: Nullability,
210 chunk_len: Option<usize>,
211) -> Result<ArrayRef> {
212 let array_length = chunk_len.unwrap_or(u.int_in_range(0..=20)?);
213 let key_dtype = map_dtype.key_dtype();
214 let value_dtype = map_dtype.value_dtype();
215 let dtype = DType::Map(map_dtype.clone(), nullability);
216 let mut builder = MapBuilder::<u64, u64>::with_capacity(map_dtype, nullability, array_length);
217
218 for _ in 0..array_length {
219 if nullability == Nullability::Nullable && u.arbitrary::<bool>()? {
220 builder.append_null();
221 } else {
222 let entry_count = u.int_in_range(0..=20)?;
223 let entries = (0..entry_count)
224 .map(|_| {
225 let key = random_scalar(u, &key_dtype)?;
226 let value = random_scalar(u, &value_dtype)?;
227 Ok((key, value))
228 })
229 .collect::<Result<Vec<_>>>()?;
230 let scalar = Scalar::try_map(dtype.clone(), entries)
231 .vortex_expect("generated map scalar should be valid");
232 builder
233 .append_scalar(&scalar)
234 .vortex_expect("generated map scalar should append");
235 }
236 }
237
238 Ok(builder.finish_into_map().into_array())
239}
240
241fn random_fixed_size_list(
245 u: &mut Unstructured,
246 elem_dtype: &Arc<DType>,
247 list_size: u32,
248 null: Nullability,
249 chunk_len: Option<usize>,
250) -> Result<ArrayRef> {
251 let array_length = chunk_len.unwrap_or(u.int_in_range(0..=20)?);
252
253 let mut builder =
254 FixedSizeListBuilder::with_capacity(Arc::clone(elem_dtype), list_size, null, array_length);
255
256 for _ in 0..array_length {
257 if null == Nullability::Nullable && u.arbitrary::<bool>()? {
258 builder.append_null();
259 } else {
260 builder
261 .append_value(random_list_scalar(u, elem_dtype, list_size, null)?.as_list())
262 .vortex_expect("can append value");
263 }
264 }
265
266 Ok(builder.finish())
267}
268
269fn random_list(
273 u: &mut Unstructured,
274 elem_dtype: &Arc<DType>,
275 null: Nullability,
276 chunk_len: Option<usize>,
277) -> Result<ArrayRef> {
278 let array_length = chunk_len.unwrap_or(u.int_in_range(0..=20)?);
279 let max_total_elements = array_length as u64 * 20;
281
282 match u.int_in_range(0..=3)? {
283 0 if i32::max_value_as_u64() >= max_total_elements => {
284 random_list_with_offset_type::<i32>(u, elem_dtype, null, array_length)
285 }
286 1 if u32::max_value_as_u64() >= max_total_elements => {
287 random_list_with_offset_type::<u32>(u, elem_dtype, null, array_length)
288 }
289 _ => {
291 if u.arbitrary::<bool>()? {
292 random_list_with_offset_type::<i64>(u, elem_dtype, null, array_length)
293 } else {
294 random_list_with_offset_type::<u64>(u, elem_dtype, null, array_length)
295 }
296 }
297 }
298}
299
300fn random_list_with_offset_type<O: OffsetBuilderPType>(
302 u: &mut Unstructured,
303 elem_dtype: &Arc<DType>,
304 null: Nullability,
305 array_length: usize,
306) -> Result<ArrayRef> {
307 let mut builder =
308 ListViewBuilder::<O, O>::with_capacity(Arc::clone(elem_dtype), null, array_length, 10);
309
310 for _ in 0..array_length {
311 if null == Nullability::Nullable && u.arbitrary::<bool>()? {
312 builder.append_null();
313 } else {
314 let list_size = u.int_in_range(0..=20)?;
315 builder
316 .append_value(random_list_scalar(u, elem_dtype, list_size, null)?.as_list())
317 .vortex_expect("can append value");
318 }
319 }
320
321 Ok(builder.finish())
322}
323
324fn random_list_scalar(
326 u: &mut Unstructured,
327 elem_dtype: &Arc<DType>,
328 list_size: u32,
329 null: Nullability,
330) -> Result<Scalar> {
331 let elems = (0..list_size)
332 .map(|_| random_scalar(u, elem_dtype))
333 .collect::<Result<Vec<_>>>()?;
334 Ok(Scalar::list(Arc::clone(elem_dtype), elems, null))
335}
336
337fn random_string(
338 u: &mut Unstructured,
339 nullability: Nullability,
340 len: Option<usize>,
341) -> Result<ArrayRef> {
342 match nullability {
343 Nullability::NonNullable => {
344 let v = arbitrary_vec_of_len::<String>(u, len)?;
345 Ok(match u.int_in_range(0..=1)? {
346 0 => VarBinArray::from_vec(v, DType::Utf8(Nullability::NonNullable)).into_array(),
347 1 => VarBinViewArray::from_iter_str(v).into_array(),
348 _ => unreachable!(),
349 })
350 }
351 Nullability::Nullable => {
352 let v = arbitrary_vec_of_len::<Option<String>>(u, len)?;
353 Ok(match u.int_in_range(0..=1)? {
354 0 => VarBinArray::from_iter(v, DType::Utf8(Nullability::Nullable)).into_array(),
355 1 => VarBinViewArray::from_iter_nullable_str(v).into_array(),
356 _ => unreachable!(),
357 })
358 }
359 }
360}
361
362fn random_bytes(
363 u: &mut Unstructured,
364 nullability: Nullability,
365 len: Option<usize>,
366) -> Result<ArrayRef> {
367 match nullability {
368 Nullability::NonNullable => {
369 let v = arbitrary_vec_of_len::<Vec<u8>>(u, len)?;
370 Ok(match u.int_in_range(0..=1)? {
371 0 => VarBinArray::from_vec(v, DType::Binary(Nullability::NonNullable)).into_array(),
372 1 => VarBinViewArray::from_iter_bin(v).into_array(),
373 _ => unreachable!(),
374 })
375 }
376 Nullability::Nullable => {
377 let v = arbitrary_vec_of_len::<Option<Vec<u8>>>(u, len)?;
378 Ok(match u.int_in_range(0..=1)? {
379 0 => VarBinArray::from_iter(v, DType::Binary(Nullability::Nullable)).into_array(),
380 1 => VarBinViewArray::from_iter_nullable_bin(v).into_array(),
381 _ => unreachable!(),
382 })
383 }
384 }
385}
386
387fn random_primitive<'a, T: Arbitrary<'a> + NativePType>(
388 u: &mut Unstructured<'a>,
389 nullability: Nullability,
390 len: Option<usize>,
391) -> Result<ArrayRef> {
392 let v = arbitrary_vec_of_len::<T>(u, len)?;
393 let validity = random_validity(u, nullability, v.len())?;
394 Ok(PrimitiveArray::new(Buffer::copy_from(v), validity).into_array())
395}
396
397fn random_bool(
398 u: &mut Unstructured,
399 nullability: Nullability,
400 len: Option<usize>,
401) -> Result<ArrayRef> {
402 let v = arbitrary_vec_of_len(u, len)?;
403 let validity = random_validity(u, nullability, v.len())?;
404 Ok(BoolArray::new(BitBuffer::from(v), validity).into_array())
405}
406
407pub fn random_validity(
408 u: &mut Unstructured,
409 nullability: Nullability,
410 len: usize,
411) -> Result<Validity> {
412 match nullability {
413 Nullability::NonNullable => Ok(Validity::NonNullable),
414 Nullability::Nullable => Ok(match u.int_in_range(0..=2)? {
415 0 => Validity::AllValid,
416 1 => Validity::AllInvalid,
417 2 => Validity::from_iter(arbitrary_vec_of_len::<bool>(u, Some(len))?),
418 _ => unreachable!(),
419 }),
420 }
421}
422
423fn arbitrary_vec_of_len<'a, T: Arbitrary<'a>>(
424 u: &mut Unstructured<'a>,
425 len: Option<usize>,
426) -> Result<Vec<T>> {
427 len.map(|l| (0..l).map(|_| T::arbitrary(u)).collect::<Result<Vec<_>>>())
428 .unwrap_or_else(|| Vec::<T>::arbitrary(u))
429}