use arbitrary::Error::IncorrectFormat;
use arbitrary::{Arbitrary, Result, Unstructured};
use num_traits::Float;
use strum::EnumCount as _;
use crate::encoder::model::StagedLayer;
use crate::encoder::optimizer::Presence;
use crate::encoder::{EncoderConfig, StagedId, StagedProperty, StagedSharedDict};
#[cfg(feature = "unstable-v2")]
use crate::encoder::{
StagedInterior, StagedLeaf, StagedList, StagedMValue, StagedNested, StagedNode, StagedStruct,
StagedValues,
};
impl Arbitrary<'_> for EncoderConfig {
fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self> {
let config = Self::default()
.with_tessellation(u.arbitrary()?)
.with_spatial_morton_sort(u.arbitrary()?)
.with_spatial_hilbert_sort(u.arbitrary()?)
.with_id_sort(u.arbitrary()?)
.with_fsst(u.arbitrary()?)
.with_fastpfor(u.arbitrary()?)
.with_shared_dict(u.arbitrary()?);
#[cfg(feature = "unstable-v2")]
let config = config
.with_wire_version(u.arbitrary()?)
.with_float_dict(u.arbitrary()?)
.with_float_alp(u.arbitrary()?)
.with_triangles_only(u.arbitrary()?);
Ok(config)
}
}
impl Arbitrary<'_> for StagedId {
fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self> {
let count = usize::from(u.int_in_range(0..=64u8)?);
let values: Vec<Option<u64>> = (0..count).map(|_| u.arbitrary()).collect::<Result<_>>()?;
Ok(Self::from_optional(values))
}
}
impl Arbitrary<'_> for StagedLayer {
fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self> {
let len = u.int_in_range(1..=32)?;
let name: String = (0..len)
.map(|_| u.arbitrary::<char>())
.collect::<Result<_>>()?;
let extent: u32 = if u.int_in_range(0..=7u8)? == 0 {
u.int_in_range(1..=u32::MAX)?
} else {
1 << u.int_in_range(6..=21u32)?
};
let geometry: crate::decoder::GeometryValues = u.arbitrary()?;
let fc = geometry.vector_types().len();
let id = if u.arbitrary::<bool>()? {
let ids: Vec<Option<u64>> = (0..fc)
.map(|_| -> Result<_> {
if u.arbitrary::<bool>()? {
Ok(Some(u.arbitrary::<u64>()?))
} else {
Ok(None)
}
})
.collect::<Result<_>>()?;
StagedId::from_optional(ids)
} else {
StagedId::None
};
let prop_count = usize::from(u.int_in_range(0..=4u8)?);
let properties: Vec<StagedProperty> = (0..prop_count)
.map(|i| generate_property(u, format!("prop{i}"), fc))
.collect::<Result<_>>()?;
#[cfg(not(feature = "unstable-v2"))]
return Self::new(name, extent, id, geometry, properties).map_err(|_| IncorrectFormat);
#[cfg(feature = "unstable-v2")]
{
let mut geometry = geometry;
if u.arbitrary()? {
let exponent =
u.int_in_range(crate::ZStep::MIN_EXPONENT..=crate::ZStep::MAX_EXPONENT)?;
let step = crate::ZStep::new(exponent).map_err(|_| IncorrectFormat)?;
let vertices = geometry.vertices().map_or(0, |v| v.len() / 2);
let z: Vec<i32> = generate_scalars(u, vertices)?;
geometry.add_z(step, &z).map_err(|_| IncorrectFormat)?;
}
let m_count = usize::from(u.int_in_range(0..=4u8)?);
let m_values: Vec<StagedMValue> = (0..m_count)
.map(|i| generate_m_value(u, format!("m{i}"), &geometry))
.collect::<Result<_>>()?;
let nested_count = usize::from(u.int_in_range(0..=2u8)?);
let nested: Vec<StagedNested> = (0..nested_count)
.map(|i| generate_nested(u, format!("n{i}"), fc))
.collect::<Result<_>>()?;
Self::with_nested(name, extent, id, geometry, properties, m_values, nested)
.map_err(|_| IncorrectFormat)
}
}
}
#[cfg(feature = "unstable-v2")]
fn generate_m_value(
u: &mut Unstructured<'_>,
name: String,
geometry: &crate::decoder::GeometryValues,
) -> Result<StagedMValue> {
let features = geometry.feature_count();
let presence: Option<Vec<bool>> = if u.arbitrary()? {
None
} else {
Some(generate_scalars(u, features)?)
};
let mut count = 0;
for index in 0..features {
if presence.as_ref().is_none_or(|mask| mask[index]) {
count += geometry.vertex_count(index).map_err(|_| IncorrectFormat)?;
}
}
Ok(StagedMValue::new(
name,
presence,
generate_values(u, count)?,
))
}
#[cfg(feature = "unstable-v2")]
fn generate_nested(u: &mut Unstructured<'_>, name: String, count: usize) -> Result<StagedNested> {
let root = match generate_node(u, count, 1)? {
StagedNode::Interior(interior) => interior,
StagedNode::Leaf(leaf) => StagedInterior::Struct(StagedStruct::new(
None,
vec![("f".to_string(), StagedNode::Leaf(leaf))],
)),
};
Ok(StagedNested::new(name, root))
}
#[cfg(feature = "unstable-v2")]
fn generate_node(u: &mut Unstructured<'_>, count: usize, depth: usize) -> Result<StagedNode> {
let presence: Option<Vec<bool>> = if u.arbitrary()? {
None
} else {
Some(generate_scalars(u, count)?)
};
let present = presence
.as_ref()
.map_or(count, |mask| mask.iter().filter(|&&bit| bit).count());
let interior = depth < 4 && u.arbitrary()?;
if !interior {
let values = generate_values(u, present)?;
return Ok(StagedNode::Leaf(StagedLeaf::new(presence, values)));
}
if u.arbitrary()? {
let field_count = usize::from(u.int_in_range(1..=3u8)?);
let fields = (0..field_count)
.map(|i| Ok((format!("f{i}"), generate_node(u, present, depth + 1)?)))
.collect::<Result<Vec<_>>>()?;
return Ok(StagedNode::Interior(StagedInterior::Struct(
StagedStruct::new(presence, fields),
)));
}
let lengths: Vec<u32> = (0..present)
.map(|_| Ok(u32::from(u.int_in_range(0..=3u8)?)))
.collect::<Result<_>>()?;
let entries = lengths.iter().sum::<u32>() as usize;
let element = generate_node(u, entries, depth + 1)?;
Ok(StagedNode::Interior(StagedInterior::List(StagedList::new(
presence, lengths, element,
))))
}
#[cfg(feature = "unstable-v2")]
fn generate_values(u: &mut Unstructured<'_>, count: usize) -> Result<StagedValues> {
const _: () = assert!(
StagedValues::COUNT == 10,
"needs new variant in match below"
);
Ok(match u.int_in_range(0..=StagedValues::COUNT - 1)? {
0 => StagedValues::Bool(generate_scalars(u, count)?),
1 => StagedValues::I8(generate_scalars(u, count)?),
2 => StagedValues::U8(generate_scalars(u, count)?),
3 => StagedValues::I32(generate_scalars(u, count)?),
4 => StagedValues::U32(generate_scalars(u, count)?),
5 => StagedValues::I64(generate_scalars(u, count)?),
6 => StagedValues::U64(generate_scalars(u, count)?),
7 => StagedValues::F32(generate_floats(u, count)?),
8 => StagedValues::F64(generate_floats(u, count)?),
_ => StagedValues::Str(generate_strings(u, count)?),
})
}
fn generate_property(
u: &mut Unstructured<'_>,
name: String,
count: usize,
) -> Result<StagedProperty> {
const _: () = assert!(
StagedProperty::COUNT == 21,
"needs new variant in match below"
);
Ok(match u.int_in_range(0..=StagedProperty::COUNT - 1)? {
0 => StagedProperty::bool(name, generate_scalars(u, count)?),
1 => StagedProperty::i8(name, generate_scalars(u, count)?),
2 => StagedProperty::u8(name, generate_scalars(u, count)?),
3 => StagedProperty::i32(name, generate_scalars(u, count)?),
4 => StagedProperty::u32(name, generate_scalars(u, count)?),
5 => StagedProperty::i64(name, generate_scalars(u, count)?),
6 => StagedProperty::u64(name, generate_scalars(u, count)?),
7 => StagedProperty::f32(name, generate_floats(u, count)?),
8 => StagedProperty::f64(name, generate_floats(u, count)?),
9 => StagedProperty::str(name, generate_strings(u, count)?),
10 => StagedProperty::opt_bool(name, generate_scalars(u, count)?),
11 => StagedProperty::opt_i8(name, generate_scalars(u, count)?),
12 => StagedProperty::opt_u8(name, generate_scalars(u, count)?),
13 => StagedProperty::opt_i32(name, generate_scalars(u, count)?),
14 => StagedProperty::opt_u32(name, generate_scalars(u, count)?),
15 => StagedProperty::opt_i64(name, generate_scalars(u, count)?),
16 => StagedProperty::opt_u64(name, generate_scalars(u, count)?),
17 => StagedProperty::opt_f32(name, generate_optional_floats(u, count)?),
18 => StagedProperty::opt_f64(name, generate_optional_floats(u, count)?),
19 => StagedProperty::opt_str(name, generate_optional_strings(u, count)?),
_ => StagedProperty::SharedDict(generate_shared_dict(u, name, count)?),
})
}
fn generate_shared_dict(
u: &mut Unstructured<'_>,
prefix: String,
count: usize,
) -> Result<StagedSharedDict> {
let item_count = usize::from(u.int_in_range(1..=4u8)?);
let items: Vec<(String, Vec<Option<String>>, Presence)> = (0..item_count)
.map(|i| -> Result<_> {
let values = generate_optional_strings(u, count)?;
let presence = if values.iter().all(Option::is_some) {
Presence::AllPresent
} else {
Presence::Mixed
};
Ok((format!("_{i}"), values, presence))
})
.collect::<Result<_>>()?;
StagedSharedDict::new(prefix, items).map_err(|_| IncorrectFormat)
}
fn generate_scalars<'a, T: Arbitrary<'a>>(
u: &mut Unstructured<'a>,
count: usize,
) -> Result<Vec<T>> {
(0..count).map(|_| u.arbitrary()).collect()
}
fn generate_floats<'a, T: Arbitrary<'a> + Float>(
u: &mut Unstructured<'a>,
count: usize,
) -> Result<Vec<T>> {
(0..count)
.map(|_| Ok(zero_if_nan(u.arbitrary()?)))
.collect()
}
fn generate_optional_floats<'a, T: Arbitrary<'a> + Float>(
u: &mut Unstructured<'a>,
count: usize,
) -> Result<Vec<Option<T>>> {
(0..count)
.map(|_| Ok(u.arbitrary::<Option<T>>()?.map(zero_if_nan)))
.collect()
}
fn zero_if_nan<T: Float>(value: T) -> T {
if value.is_nan() { T::zero() } else { value }
}
fn generate_strings(u: &mut Unstructured<'_>, count: usize) -> Result<Vec<String>> {
(0..count).map(|_| bounded_string(u, 64)).collect()
}
fn generate_optional_strings(
u: &mut Unstructured<'_>,
count: usize,
) -> Result<Vec<Option<String>>> {
(0..count)
.map(|_| -> Result<_> {
if u.arbitrary()? {
Ok(Some(bounded_string(u, 64)?))
} else {
Ok(None)
}
})
.collect()
}
fn bounded_string(u: &mut Unstructured<'_>, max_len: u8) -> Result<String> {
let len = usize::from(u.int_in_range(0..=max_len)?);
(0..len)
.map(|_| u.arbitrary::<char>())
.collect::<Result<_>>()
}