-
Notifications
You must be signed in to change notification settings - Fork 186
Expand file tree
/
Copy patharbitrary.rs
More file actions
154 lines (143 loc) · 5.69 KB
/
Copy patharbitrary.rs
File metadata and controls
154 lines (143 loc) · 5.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: Copyright the Vortex contributors
//! Arbitrary scalar value generation.
//!
//! This module provides functions to generate arbitrary scalar values of various data types.
//! It is used by the fuzzer to test the correctness of the scalar value implementation.
use std::iter;
use arbitrary::Result;
use arbitrary::Unstructured;
use vortex_buffer::BufferString;
use vortex_buffer::ByteBuffer;
use vortex_error::VortexExpect;
use crate::dtype::DType;
use crate::dtype::DecimalDType;
use crate::dtype::NativeDecimalType;
use crate::dtype::PType;
use crate::dtype::half::f16;
use crate::match_each_decimal_value_type;
use crate::scalar::DecimalValue;
use crate::scalar::PValue;
use crate::scalar::Scalar;
use crate::scalar::ScalarValue;
/// Generates an arbitrary [`Scalar`] of the given [`DType`].
///
/// # Errors
///
/// Returns an error if the underlying arbitrary generation fails.
pub fn random_scalar(u: &mut Unstructured, dtype: &DType) -> Result<Scalar> {
// For nullable types, return null ~25% of the time. This is just to make sure we don't generate
// too few nulls.
if dtype.is_nullable() && u.ratio(1, 4)? {
return Ok(Scalar::null(dtype.clone()));
}
Ok(match dtype {
DType::Null => Scalar::null(dtype.clone()),
DType::Bool(_) => Scalar::try_new(dtype.clone(), Some(ScalarValue::Bool(u.arbitrary()?)))
.vortex_expect("unable to construct random `Scalar`_"),
DType::Primitive(p, _) => Scalar::try_new(
dtype.clone(),
Some(ScalarValue::Primitive(random_pvalue(u, p)?)),
)
.vortex_expect("unable to construct random `Scalar`_"),
DType::Decimal(decimal_type, _) => {
Scalar::try_new(dtype.clone(), Some(random_decimal(u, decimal_type)?))
.vortex_expect("unable to construct random `Scalar`_")
}
DType::Utf8(_) => Scalar::try_new(
dtype.clone(),
Some(ScalarValue::Utf8(BufferString::from(
u.arbitrary::<String>()?,
))),
)
.vortex_expect("unable to construct random `Scalar`_"),
DType::Binary(_) => Scalar::try_new(
dtype.clone(),
Some(ScalarValue::Binary(ByteBuffer::from(
u.arbitrary::<Vec<u8>>()?,
))),
)
.vortex_expect("unable to construct random `Scalar`_"),
DType::List(edt, _) => Scalar::try_new(
dtype.clone(),
Some(ScalarValue::Tuple(
iter::from_fn(|| {
// Generate elements with 1/4 probability.
u.arbitrary()
.unwrap_or(false)
.then(|| random_scalar(u, edt).map(|s| s.into_value()))
})
.collect::<Result<Vec<_>>>()?,
)),
)
.vortex_expect("unable to construct random `Scalar`_"),
DType::FixedSizeList(edt, size, _) => Scalar::try_new(
dtype.clone(),
Some(ScalarValue::Tuple(
(0..*size)
.map(|_| random_scalar(u, edt).map(|s| s.into_value()))
.collect::<Result<Vec<_>>>()?,
)),
)
.vortex_expect("unable to construct random `Scalar`_"),
DType::Struct(sdt, _) => Scalar::try_new(
dtype.clone(),
Some(ScalarValue::Tuple(
sdt.fields()
.map(|d| random_scalar(u, &d).map(|s| s.into_value()))
.collect::<Result<Vec<_>>>()?,
)),
)
.vortex_expect("unable to construct random `Scalar`_"),
DType::Union(variants) => {
let child_index = u.choose_index(variants.len())?;
let child_dtype = variants
.variant_by_index(child_index)
.vortex_expect("chosen union child index must be valid");
let child = random_scalar(u, &child_dtype)?;
Scalar::union(
variants.clone(),
variants.child_index_to_tag(child_index),
child,
)
.vortex_expect("generated union scalar must be valid")
}
DType::Variant(_) => todo!(),
DType::Extension(..) => {
unreachable!("Can't yet generate arbitrary scalars for ext dtype")
}
})
}
/// Generates an arbitrary [`PValue`] for the given [`PType`].
fn random_pvalue(u: &mut Unstructured, ptype: &PType) -> Result<PValue> {
Ok(match ptype {
PType::U8 => PValue::U8(u.arbitrary()?),
PType::U16 => PValue::U16(u.arbitrary()?),
PType::U32 => PValue::U32(u.arbitrary()?),
PType::U64 => PValue::U64(u.arbitrary()?),
PType::I8 => PValue::I8(u.arbitrary()?),
PType::I16 => PValue::I16(u.arbitrary()?),
PType::I32 => PValue::I32(u.arbitrary()?),
PType::I64 => PValue::I64(u.arbitrary()?),
PType::F16 => PValue::F16(f16::from_bits(u.arbitrary()?)),
PType::F32 => PValue::F32(u.arbitrary()?),
PType::F64 => PValue::F64(u.arbitrary()?),
})
}
/// Generates an arbitrary decimal scalar confined to the given bounds of precision and scale.
///
/// # Errors
///
/// Returns an error if the underlying arbitrary generation fails.
pub fn random_decimal(u: &mut Unstructured, decimal_type: &DecimalDType) -> Result<ScalarValue> {
let precision = decimal_type.precision();
let value = match_each_decimal_value_type!(
DecimalType::smallest_decimal_value_type(decimal_type),
|D| {
DecimalValue::from(u.int_in_range(
D::MIN_BY_PRECISION[precision as usize]..=D::MAX_BY_PRECISION[precision as usize],
)?)
}
);
Ok(ScalarValue::Decimal(value))
}