//- // Copyright 2017, 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Arbitrary implementations for `std::collections`. //#![cfg_attr(feature="cargo-clippy", allow(implicit_hasher))] //============================================================================== // Imports: //============================================================================== use crate::std_facade::{ binary_heap, btree_map, btree_set, fmt, linked_list, vec, vec_deque, Arc, BTreeMap, BTreeSet, BinaryHeap, Box, LinkedList, Rc, Vec, VecDeque, }; use core::hash::Hash; use core::ops::{Bound, RangeInclusive}; #[cfg(feature = "std")] use crate::std_facade::{hash_map, hash_set, HashMap, HashSet}; use crate::arbitrary::*; use crate::collection::*; use crate::strategy::statics::static_map; use crate::strategy::*; //============================================================================== // Macros: //============================================================================== /// Parameters for configuring the generation of `StrategyFor<...>`. type RangedParams1 = product_type![SizeRange, A]; /// Parameters for configuring the generation of `StrategyFor<...>`. type RangedParams2 = product_type![SizeRange, A, B]; macro_rules! impl_1 { ($typ: ident, $strat: ident, $($bound : path),* => $fun: ident) => { arbitrary!([A: Arbitrary $(+ $bound)*] $typ, $strat, RangedParams1; args => { let product_unpack![range, a] = args; $fun(any_with::(a), range) }); lift1!([$($bound+)*] $typ, SizeRange; base, args => $fun(base, args)); }; } arbitrary!(SizeRange, MapInto>, Self>; any::>().prop_map_into() ); //============================================================================== // Vec, VecDeque, LinkedList, BTreeSet, BinaryHeap, HashSet, HashMap: //============================================================================== macro_rules! dst_wrapped { ($($w: ident),*) => { $(arbitrary!([A: Arbitrary] $w<[A]>, MapInto>, Self>, as Arbitrary>::Parameters; a => any_with::>(a).prop_map_into() );)* }; } impl_1!(Vec, VecStrategy, => vec); dst_wrapped!(Box, Rc, Arc); impl_1!(VecDeque, VecDequeStrategy, => vec_deque); impl_1!(LinkedList, LinkedListStrategy, => linked_list); impl_1!(BTreeSet, BTreeSetStrategy, Ord => btree_set); impl_1!(BinaryHeap, BinaryHeapStrategy, Ord => binary_heap); #[cfg(feature = "std")] impl_1!(HashSet, HashSetStrategy, Hash, Eq => hash_set); //============================================================================== // IntoIterator: //============================================================================== macro_rules! into_iter_1 { ($module: ident, $type: ident $(, $bound : path)*) => { arbitrary!([A: Arbitrary $(+ $bound)*] $module::IntoIter, SMapped<$type, Self>, <$type as Arbitrary>::Parameters; args => static_map(any_with::<$type>(args), $type::into_iter)); lift1!(['static + $($bound+)*] $module::IntoIter, SizeRange; base, args => $module(base, args).prop_map($type::into_iter)); }; } into_iter_1!(vec, Vec); into_iter_1!(vec_deque, VecDeque); into_iter_1!(linked_list, LinkedList); into_iter_1!(btree_set, BTreeSet, Ord); into_iter_1!(binary_heap, BinaryHeap, Ord); #[cfg(feature = "std")] into_iter_1!(hash_set, HashSet, Hash, Eq); //============================================================================== // HashMap: //============================================================================== #[cfg(feature = "std")] arbitrary!([A: Arbitrary + Hash + Eq, B: Arbitrary] HashMap, HashMapStrategy, RangedParams2; args => { let product_unpack![range, a, b] = args; hash_map(any_with::(a), any_with::(b), range) }); #[cfg(feature = "std")] arbitrary!([A: Arbitrary + Hash + Eq, B: Arbitrary] hash_map::IntoIter, SMapped, Self>, as Arbitrary>::Parameters; args => static_map(any_with::>(args), HashMap::into_iter)); #[cfg(feature = "std")] lift1!([, K: Hash + Eq + Arbitrary + 'static] HashMap, RangedParams1; base, args => { let product_unpack![range, k] = args; hash_map(any_with::(k), base, range) } ); #[cfg(feature = "std")] lift1!(['static, K: Hash + Eq + Arbitrary + 'static] hash_map::IntoIter, RangedParams1; base, args => { let product_unpack![range, k] = args; static_map(hash_map(any_with::(k), base, range), HashMap::into_iter) } ); #[cfg(feature = "std")] impl functor::ArbitraryF2 for HashMap { type Parameters = SizeRange; fn lift2_with( fst: AS, snd: BS, args: Self::Parameters, ) -> BoxedStrategy where AS: Strategy + 'static, BS: Strategy + 'static, { hash_map(fst, snd, args).boxed() } } #[cfg(feature = "std")] impl functor::ArbitraryF2 for hash_map::IntoIter { type Parameters = SizeRange; fn lift2_with( fst: AS, snd: BS, args: Self::Parameters, ) -> BoxedStrategy where AS: Strategy + 'static, BS: Strategy + 'static, { static_map(hash_map(fst, snd, args), HashMap::into_iter).boxed() } } //============================================================================== // BTreeMap: //============================================================================== arbitrary!([A: Arbitrary + Ord, B: Arbitrary] BTreeMap, BTreeMapStrategy, RangedParams2; args => { let product_unpack![range, a, b] = args; btree_map(any_with::(a), any_with::(b), range) }); lift1!([, K: Ord + Arbitrary + 'static] BTreeMap, RangedParams1; base, args => { let product_unpack![range, k] = args; btree_map(any_with::(k), base, range) } ); impl functor::ArbitraryF2 for BTreeMap { type Parameters = SizeRange; fn lift2_with( fst: AS, snd: BS, args: Self::Parameters, ) -> BoxedStrategy where AS: Strategy + 'static, BS: Strategy + 'static, { btree_map(fst, snd, args).boxed() } } arbitrary!([A: Arbitrary + Ord, B: Arbitrary] btree_map::IntoIter, SMapped, Self>, as Arbitrary>::Parameters; args => static_map(any_with::>(args), BTreeMap::into_iter)); impl functor::ArbitraryF2 for btree_map::IntoIter { type Parameters = SizeRange; fn lift2_with( fst: AS, snd: BS, args: Self::Parameters, ) -> BoxedStrategy where AS: Strategy + 'static, BS: Strategy + 'static, { static_map(btree_map(fst, snd, args), BTreeMap::into_iter).boxed() } } //============================================================================== // Bound: //============================================================================== arbitrary!([A: Arbitrary] Bound, TupleUnion<( WA, Self>>, WA, Self>>, WA> )>, A::Parameters; args => { let base = Arc::new(any_with::(args)); prop_oneof![ 2 => static_map(base.clone(), Bound::Included), 2 => static_map(base, Bound::Excluded), 1 => LazyJust::new(|| Bound::Unbounded), ] } ); lift1!(['static] Bound; base => { let base = Rc::new(base); prop_oneof![ 2 => base.clone().prop_map(Bound::Included), 2 => base.prop_map(Bound::Excluded), 1 => LazyJustFn::new(|| Bound::Unbounded), ] }); #[cfg(test)] mod test { no_panic_test!( size_bounds => SizeRange, vec => Vec, box_slice => Box<[u8]>, rc_slice => Rc<[u8]>, arc_slice => Arc<[u8]>, vec_deque => VecDeque, linked_list => LinkedList, btree_set => BTreeSet, btree_map => BTreeMap, bound => Bound, binary_heap => BinaryHeap, into_iter_vec => vec::IntoIter, into_iter_vec_deque => vec_deque::IntoIter, into_iter_linked_list => linked_list::IntoIter, into_iter_binary_heap => binary_heap::IntoIter, into_iter_btree_set => btree_set::IntoIter, into_iter_btree_map => btree_map::IntoIter ); #[cfg(feature = "std")] no_panic_test!( hash_set => HashSet, hash_map => HashMap, into_iter_hash_set => hash_set::IntoIter, into_iter_hash_map => hash_map::IntoIter ); }