use std::cmp::min;
use std::hash::Hash;
use bigdecimal::BigDecimal;
use num_bigint::BigInt;
use rand::Rng;
use rand::RngExt;
use rand::distr::SampleString;
use rand::distr::StandardUniform;
use rand::distr::weighted::WeightedIndex;
use rand::prelude::Distribution;
use crate::semantics::cfg::Cfg;
use crate::semantics::func::CompCtx;
use crate::semantics::func::CompFunc;
use crate::semantics::func::CompInput;
use crate::semantics::val::CompFuncVal;
use crate::semantics::val::FuncVal;
use crate::semantics::val::LinkVal;
use crate::semantics::val::Val;
use crate::type_::Bit;
use crate::type_::Byte;
use crate::type_::Call;
use crate::type_::Cell;
use crate::type_::Decimal;
use crate::type_::Either;
use crate::type_::Int;
use crate::type_::Key;
use crate::type_::List;
use crate::type_::Map;
use crate::type_::Pair;
use crate::type_::Quote;
use crate::type_::Text;
use crate::type_::Unit;
pub trait Arbitrary {
fn any<R: Rng + ?Sized>(rng: &mut R, depth: usize) -> Self;
}
impl Arbitrary for Val {
fn any<R: Rng + ?Sized>(rng: &mut R, depth: usize) -> Self {
let weight: usize = 1 << min(depth, 32);
let weights = [
weight, weight, weight, weight, weight, weight, weight, 1, 1, 1, 1, 1, 1, 1, 1, 1, ];
let i = sample(rng, weights);
let depth = depth + 1;
match i {
0 => Val::Unit(Unit::any(rng, depth)),
1 => Val::Bit(Bit::any(rng, depth)),
2 => Val::Key(Key::any(rng, depth)),
3 => Val::Text(Text::any(rng, depth).into()),
4 => Val::Int(Int::any(rng, depth).into()),
5 => Val::Decimal(Decimal::any(rng, depth).into()),
6 => Val::Byte(Byte::any(rng, depth).into()),
7 => Val::Cell(Cell::<Val>::any(rng, depth).into()),
8 => Val::Pair(Pair::<Val, Val>::any(rng, depth).into()),
9 => Val::List(List::<Val>::any(rng, depth).into()),
10 => Val::Map(Map::<Key, Val>::any(rng, depth).into()),
11 => Val::Quote(Quote::<Val>::any(rng, depth).into()),
12 => Val::Call(Call::<Val, Val>::any(rng, depth).into()),
13 => Val::Link(LinkVal::any(rng, depth)),
14 => Val::Cfg(Cfg::any(rng, depth).into()),
15 => Val::Func(FuncVal::any(rng, depth)),
_ => unreachable!(),
}
}
}
impl Arbitrary for Unit {
fn any<R: Rng + ?Sized>(_rng: &mut R, _depth: usize) -> Self {
Unit
}
}
impl Arbitrary for Bit {
fn any<R: Rng + ?Sized>(rng: &mut R, _depth: usize) -> Self {
Bit::from(rng.random::<bool>())
}
}
struct DistKey;
impl Distribution<u8> for DistKey {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u8 {
rng.random_range(Key::MIN ..= Key::MAX) as u8
}
}
impl SampleString for DistKey {
fn append_string<R: Rng + ?Sized>(&self, rng: &mut R, string: &mut String, len: usize) {
unsafe {
let v = string.as_mut_vec();
v.extend(self.sample_iter(rng).take(len));
}
}
}
impl Arbitrary for Key {
fn any<R: Rng + ?Sized>(rng: &mut R, _depth: usize) -> Self {
let len = any_len(rng);
let s = DistKey.sample_string(rng, len);
Key::from_string_unchecked(s)
}
}
impl Arbitrary for Text {
fn any<R: Rng + ?Sized>(rng: &mut R, _depth: usize) -> Self {
let len = any_len(rng);
let s: String = rng.sample_iter::<char, _>(StandardUniform).take(len).collect();
Text::from(s)
}
}
impl Arbitrary for Int {
fn any<R: Rng + ?Sized>(rng: &mut R, _depth: usize) -> Self {
Int::from(rng.random::<i128>())
}
}
impl Arbitrary for Decimal {
fn any<R: Rng + ?Sized>(rng: &mut R, _depth: usize) -> Self {
let int: i64 = rng.random();
let int = BigInt::from(int);
let exp: i8 = rng.random();
Decimal::new(BigDecimal::from_bigint(int, exp as i64))
}
}
impl Arbitrary for Byte {
fn any<R: Rng + ?Sized>(rng: &mut R, _depth: usize) -> Self {
let len = any_len(rng);
let mut byte = vec![0u8; len];
rng.fill(&mut byte);
Byte::from(byte)
}
}
impl<Value> Arbitrary for Cell<Value>
where Value: Arbitrary
{
fn any<R: Rng + ?Sized>(rng: &mut R, depth: usize) -> Self {
let depth = depth + 1;
Cell::new(Value::any(rng, depth))
}
}
impl<Value> Arbitrary for Quote<Value>
where Value: Arbitrary
{
fn any<R: Rng + ?Sized>(rng: &mut R, depth: usize) -> Self {
let depth = depth + 1;
Quote::new(Value::any(rng, depth))
}
}
impl<Left, Right> Arbitrary for Pair<Left, Right>
where
Left: Arbitrary,
Right: Arbitrary,
{
fn any<R: Rng + ?Sized>(rng: &mut R, depth: usize) -> Self {
let depth = depth + 1;
Pair::new(Left::any(rng, depth), Right::any(rng, depth))
}
}
impl<This, That> Arbitrary for Either<This, That>
where
This: Arbitrary,
That: Arbitrary,
{
fn any<R: Rng + ?Sized>(rng: &mut R, depth: usize) -> Self {
let depth = depth + 1;
if rng.random() {
Either::This(This::any(rng, depth))
} else {
Either::That(That::any(rng, depth))
}
}
}
impl<Func, Input> Arbitrary for Call<Func, Input>
where
Func: Arbitrary,
Input: Arbitrary,
{
fn any<R: Rng + ?Sized>(rng: &mut R, depth: usize) -> Self {
let depth = depth + 1;
Call { func: Func::any(rng, depth), input: Input::any(rng, depth) }
}
}
impl<T> Arbitrary for List<T>
where T: Arbitrary
{
fn any<R: Rng + ?Sized>(rng: &mut R, depth: usize) -> Self {
let len = any_len_weighted(rng, depth);
let depth = depth + 1;
let mut list = Vec::with_capacity(len);
for _ in 0 .. len {
list.push(T::any(rng, depth));
}
List::from(list)
}
}
impl<K, V> Arbitrary for Map<K, V>
where
K: Eq + Hash + Arbitrary,
V: Arbitrary,
{
fn any<R: Rng + ?Sized>(rng: &mut R, depth: usize) -> Self {
let len = any_len_weighted(rng, depth);
let depth = depth + 1;
let mut map = Map::with_capacity(len);
for _ in 0 .. len {
map.insert(K::any(rng, depth), V::any(rng, depth));
}
map
}
}
impl Arbitrary for LinkVal {
fn any<R: Rng + ?Sized>(rng: &mut R, depth: usize) -> Self {
let depth = depth + 1;
let val = Val::any(rng, depth);
let const_ = rng.random();
LinkVal::new(val, const_)
}
}
impl Arbitrary for Cfg {
fn any<R: Rng + ?Sized>(rng: &mut R, depth: usize) -> Self {
let depth = depth + 1;
Cfg::from(Map::any(rng, depth))
}
}
impl<T: Arbitrary> Arbitrary for Option<T> {
fn any<R: Rng + ?Sized>(rng: &mut R, depth: usize) -> Self {
let depth = depth + 1;
if rng.random() { None } else { Some(T::any(rng, depth)) }
}
}
impl<T: Arbitrary> Arbitrary for Box<T> {
fn any<R: Rng + ?Sized>(rng: &mut R, depth: usize) -> Self {
let depth = depth + 1;
Box::new(T::any(rng, depth))
}
}
impl Arbitrary for FuncVal {
fn any<R: Rng + ?Sized>(rng: &mut R, depth: usize) -> Self {
let depth = depth + 1;
let func = Arbitrary::any(rng, depth);
FuncVal::Comp(func)
}
}
impl Arbitrary for CompFuncVal {
fn any<R: Rng + ?Sized>(rng: &mut R, depth: usize) -> Self {
let depth = depth + 1;
let ctx = if rng.random() {
CompCtx::Aware { name: Arbitrary::any(rng, depth), const_: rng.random() }
} else {
CompCtx::Free
};
let input = if rng.random() {
CompInput::Aware { name: Arbitrary::any(rng, depth) }
} else {
CompInput::Free
};
let func = CompFunc {
prelude: Arbitrary::any(rng, depth),
body: Arbitrary::any(rng, depth),
input,
ctx,
};
CompFuncVal::from(func)
}
}
fn sample<const N: usize, R: Rng + ?Sized>(rng: &mut R, weights: [usize; N]) -> usize {
let dist = WeightedIndex::new(weights).unwrap();
dist.sample(rng)
}
fn any_len_weighted<R: Rng + ?Sized>(rng: &mut R, depth: usize) -> usize {
const WEIGHTS: [usize; 16] = [16, 16, 16, 16, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1];
let dist = WeightedIndex::new(WEIGHTS).unwrap();
let limit = 16usize.saturating_sub(depth);
let len = dist.sample(rng);
min(len, limit)
}
fn any_len<R: Rng + ?Sized>(rng: &mut R) -> usize {
let len: u8 = rng.random();
len as usize
}