use crate::{
IdHashItem,
id_hash_map::IdHashMap,
support::{
alloc::{Allocator, Global},
hash_builder::DefaultHashBuilder,
},
};
use core::{fmt, hash::BuildHasher};
use proptest::{
arbitrary::{Arbitrary, StrategyFor, any_with},
collection::{SizeRange, VecStrategy, VecValueTree},
strategy::{NewTree, Strategy, ValueTree},
test_runner::TestRunner,
};
#[must_use = "strategies do nothing unless used"]
#[derive(Clone)]
pub struct IdHashMapStrategy<T, S = DefaultHashBuilder, A = Global>
where
T: Strategy,
{
inner: VecStrategy<T>,
hasher: S,
allocator: A,
}
impl<T, S, A> fmt::Debug for IdHashMapStrategy<T, S, A>
where
T: Strategy,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("IdHashMapStrategy")
.field("inner", &self.inner)
.finish_non_exhaustive()
}
}
#[cfg(feature = "default-hasher")]
pub fn prop_strategy<T: Strategy>(
element: T,
size: impl Into<SizeRange>,
) -> IdHashMapStrategy<T, DefaultHashBuilder, Global> {
IdHashMapStrategy {
inner: proptest::collection::vec(element, size),
hasher: DefaultHashBuilder::default(),
allocator: crate::support::alloc::global_alloc(),
}
}
pub fn prop_strategy_with_hasher<T: Strategy, S>(
element: T,
size: impl Into<SizeRange>,
hasher: S,
) -> IdHashMapStrategy<T, S, Global> {
let size = size.into();
IdHashMapStrategy {
inner: proptest::collection::vec(element, size),
hasher,
allocator: crate::support::alloc::global_alloc(),
}
}
pub fn prop_strategy_with_hasher_in<T: Strategy, S, A>(
element: T,
size: impl Into<SizeRange>,
hasher: S,
allocator: A,
) -> IdHashMapStrategy<T, S, A> {
let size = size.into();
IdHashMapStrategy {
inner: proptest::collection::vec(element, size),
hasher,
allocator,
}
}
impl<'a, T, S, A> Strategy for IdHashMapStrategy<T, S, A>
where
T: Strategy,
T::Value: 'a + IdHashItem,
<T::Value as IdHashItem>::Key<'a>: fmt::Debug,
S: Clone + BuildHasher,
A: Clone + Allocator,
{
type Tree = IdHashMapValueTree<T::Tree, S, A>;
type Value = IdHashMap<T::Value, S, A>;
fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
let inner = self.inner.new_tree(runner)?;
Ok(IdHashMapValueTree {
inner,
hasher: self.hasher.clone(),
allocator: self.allocator.clone(),
})
}
}
#[derive(Clone)]
pub struct IdHashMapValueTree<T, S = DefaultHashBuilder, A = Global>
where
T: ValueTree,
{
inner: VecValueTree<T>,
hasher: S,
allocator: A,
}
impl<T, S, A> fmt::Debug for IdHashMapValueTree<T, S, A>
where
T: ValueTree + fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("IdHashMapValueTree")
.field("inner", &self.inner)
.finish_non_exhaustive()
}
}
impl<'a, T, S, A> ValueTree for IdHashMapValueTree<T, S, A>
where
T: ValueTree,
T::Value: 'a + IdHashItem,
<T::Value as IdHashItem>::Key<'a>: fmt::Debug,
S: Clone + BuildHasher,
A: Clone + Allocator,
{
type Value = IdHashMap<T::Value, S, A>;
fn current(&self) -> Self::Value {
let items = self.inner.current();
let mut map = IdHashMap::with_capacity_and_hasher_in(
items.len(),
self.hasher.clone(),
self.allocator.clone(),
);
for item in items {
map.insert_overwrite(item);
}
map
}
fn simplify(&mut self) -> bool {
self.inner.simplify()
}
fn complicate(&mut self) -> bool {
self.inner.complicate()
}
}
impl<'a, T, S, A> Arbitrary for IdHashMap<T, S, A>
where
T: 'a + IdHashItem + Arbitrary,
<T as IdHashItem>::Key<'a>: fmt::Debug,
S: Clone + BuildHasher + Default,
A: Clone + Allocator + Default,
{
type Parameters = (SizeRange, T::Parameters);
type Strategy = IdHashMapStrategy<StrategyFor<T>, S, A>;
fn arbitrary_with(args: Self::Parameters) -> Self::Strategy {
let (size, element_args) = args;
prop_strategy_with_hasher_in(
any_with::<T>(element_args),
size,
S::default(),
A::default(),
)
}
}