1 //- 2 // Copyright 2017, 2018 The proptest developers 3 // 4 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or 5 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license 6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your 7 // option. This file may not be copied, modified, or distributed 8 // except according to those terms. 9 10 //! Arbitrary implementations for `std::collections`. 11 12 //#![cfg_attr(feature="cargo-clippy", allow(implicit_hasher))] 13 14 //============================================================================== 15 // Imports: 16 //============================================================================== 17 18 use crate::std_facade::{ 19 binary_heap, btree_map, btree_set, fmt, linked_list, vec, vec_deque, Arc, 20 BTreeMap, BTreeSet, BinaryHeap, Box, LinkedList, Rc, Vec, VecDeque, 21 }; 22 use core::hash::Hash; 23 use core::ops::{Bound, RangeInclusive}; 24 25 #[cfg(feature = "std")] 26 use crate::std_facade::{hash_map, hash_set, HashMap, HashSet}; 27 28 use crate::arbitrary::*; 29 use crate::collection::*; 30 use crate::strategy::statics::static_map; 31 use crate::strategy::*; 32 33 //============================================================================== 34 // Macros: 35 //============================================================================== 36 37 /// Parameters for configuring the generation of `StrategyFor<...<A>>`. 38 type RangedParams1<A> = product_type![SizeRange, A]; 39 40 /// Parameters for configuring the generation of `StrategyFor<...<A, B>>`. 41 type RangedParams2<A, B> = product_type![SizeRange, A, B]; 42 43 macro_rules! impl_1 { 44 ($typ: ident, $strat: ident, $($bound : path),* => $fun: ident) => { 45 arbitrary!([A: Arbitrary $(+ $bound)*] $typ<A>, 46 $strat<A::Strategy>, RangedParams1<A::Parameters>; 47 args => { 48 let product_unpack![range, a] = args; 49 $fun(any_with::<A>(a), range) 50 }); 51 52 lift1!([$($bound+)*] $typ<A>, SizeRange; 53 base, args => $fun(base, args)); 54 }; 55 } 56 57 arbitrary!(SizeRange, MapInto<StrategyFor<RangeInclusive<usize>>, Self>; 58 any::<RangeInclusive<usize>>().prop_map_into() 59 ); 60 61 //============================================================================== 62 // Vec, VecDeque, LinkedList, BTreeSet, BinaryHeap, HashSet, HashMap: 63 //============================================================================== 64 65 macro_rules! dst_wrapped { 66 ($($w: ident),*) => { 67 $(arbitrary!([A: Arbitrary] $w<[A]>, 68 MapInto<StrategyFor<Vec<A>>, Self>, 69 <Vec<A> as Arbitrary>::Parameters; 70 a => any_with::<Vec<A>>(a).prop_map_into() 71 );)* 72 }; 73 } 74 75 impl_1!(Vec, VecStrategy, => vec); 76 dst_wrapped!(Box, Rc, Arc); 77 impl_1!(VecDeque, VecDequeStrategy, => vec_deque); 78 impl_1!(LinkedList, LinkedListStrategy, => linked_list); 79 impl_1!(BTreeSet, BTreeSetStrategy, Ord => btree_set); 80 impl_1!(BinaryHeap, BinaryHeapStrategy, Ord => binary_heap); 81 #[cfg(feature = "std")] 82 impl_1!(HashSet, HashSetStrategy, Hash, Eq => hash_set); 83 84 //============================================================================== 85 // IntoIterator: 86 //============================================================================== 87 88 macro_rules! into_iter_1 { 89 ($module: ident, $type: ident $(, $bound : path)*) => { 90 arbitrary!([A: Arbitrary $(+ $bound)*] 91 $module::IntoIter<A>, 92 SMapped<$type<A>, Self>, 93 <$type<A> as Arbitrary>::Parameters; 94 args => static_map(any_with::<$type<A>>(args), $type::into_iter)); 95 96 lift1!(['static + $($bound+)*] $module::IntoIter<A>, SizeRange; 97 base, args => 98 $module(base, args).prop_map($type::into_iter)); 99 }; 100 } 101 102 into_iter_1!(vec, Vec); 103 into_iter_1!(vec_deque, VecDeque); 104 into_iter_1!(linked_list, LinkedList); 105 into_iter_1!(btree_set, BTreeSet, Ord); 106 into_iter_1!(binary_heap, BinaryHeap, Ord); 107 #[cfg(feature = "std")] 108 into_iter_1!(hash_set, HashSet, Hash, Eq); 109 110 //============================================================================== 111 // HashMap: 112 //============================================================================== 113 114 #[cfg(feature = "std")] 115 arbitrary!([A: Arbitrary + Hash + Eq, B: Arbitrary] HashMap<A, B>, 116 HashMapStrategy<A::Strategy, B::Strategy>, 117 RangedParams2<A::Parameters, B::Parameters>; 118 args => { 119 let product_unpack![range, a, b] = args; 120 hash_map(any_with::<A>(a), any_with::<B>(b), range) 121 }); 122 123 #[cfg(feature = "std")] 124 arbitrary!([A: Arbitrary + Hash + Eq, B: Arbitrary] hash_map::IntoIter<A, B>, 125 SMapped<HashMap<A, B>, Self>, 126 <HashMap<A, B> as Arbitrary>::Parameters; 127 args => static_map(any_with::<HashMap<A, B>>(args), HashMap::into_iter)); 128 129 #[cfg(feature = "std")] 130 lift1!([, K: Hash + Eq + Arbitrary + 'static] HashMap<K, A>, 131 RangedParams1<K::Parameters>; 132 base, args => { 133 let product_unpack![range, k] = args; 134 hash_map(any_with::<K>(k), base, range) 135 } 136 ); 137 138 #[cfg(feature = "std")] 139 lift1!(['static, K: Hash + Eq + Arbitrary + 'static] hash_map::IntoIter<K, A>, 140 RangedParams1<K::Parameters>; 141 base, args => { 142 let product_unpack![range, k] = args; 143 static_map(hash_map(any_with::<K>(k), base, range), HashMap::into_iter) 144 } 145 ); 146 147 #[cfg(feature = "std")] 148 impl<A: fmt::Debug + Eq + Hash, B: fmt::Debug> functor::ArbitraryF2<A, B> 149 for HashMap<A, B> 150 { 151 type Parameters = SizeRange; 152 lift2_with<AS, BS>( fst: AS, snd: BS, args: Self::Parameters, ) -> BoxedStrategy<Self> where AS: Strategy<Value = A> + 'static, BS: Strategy<Value = B> + 'static,153 fn lift2_with<AS, BS>( 154 fst: AS, 155 snd: BS, 156 args: Self::Parameters, 157 ) -> BoxedStrategy<Self> 158 where 159 AS: Strategy<Value = A> + 'static, 160 BS: Strategy<Value = B> + 'static, 161 { 162 hash_map(fst, snd, args).boxed() 163 } 164 } 165 166 #[cfg(feature = "std")] 167 impl<A: fmt::Debug + Eq + Hash + 'static, B: fmt::Debug + 'static> 168 functor::ArbitraryF2<A, B> for hash_map::IntoIter<A, B> 169 { 170 type Parameters = SizeRange; 171 lift2_with<AS, BS>( fst: AS, snd: BS, args: Self::Parameters, ) -> BoxedStrategy<Self> where AS: Strategy<Value = A> + 'static, BS: Strategy<Value = B> + 'static,172 fn lift2_with<AS, BS>( 173 fst: AS, 174 snd: BS, 175 args: Self::Parameters, 176 ) -> BoxedStrategy<Self> 177 where 178 AS: Strategy<Value = A> + 'static, 179 BS: Strategy<Value = B> + 'static, 180 { 181 static_map(hash_map(fst, snd, args), HashMap::into_iter).boxed() 182 } 183 } 184 185 //============================================================================== 186 // BTreeMap: 187 //============================================================================== 188 189 arbitrary!([A: Arbitrary + Ord, B: Arbitrary] BTreeMap<A, B>, 190 BTreeMapStrategy<A::Strategy, B::Strategy>, 191 RangedParams2<A::Parameters, B::Parameters>; 192 args => { 193 let product_unpack![range, a, b] = args; 194 btree_map(any_with::<A>(a), any_with::<B>(b), range) 195 }); 196 197 lift1!([, K: Ord + Arbitrary + 'static] BTreeMap<K, A>, 198 RangedParams1<K::Parameters>; 199 base, args => { 200 let product_unpack![range, k] = args; 201 btree_map(any_with::<K>(k), base, range) 202 } 203 ); 204 205 impl<A: fmt::Debug + Ord, B: fmt::Debug> functor::ArbitraryF2<A, B> 206 for BTreeMap<A, B> 207 { 208 type Parameters = SizeRange; lift2_with<AS, BS>( fst: AS, snd: BS, args: Self::Parameters, ) -> BoxedStrategy<Self> where AS: Strategy<Value = A> + 'static, BS: Strategy<Value = B> + 'static,209 fn lift2_with<AS, BS>( 210 fst: AS, 211 snd: BS, 212 args: Self::Parameters, 213 ) -> BoxedStrategy<Self> 214 where 215 AS: Strategy<Value = A> + 'static, 216 BS: Strategy<Value = B> + 'static, 217 { 218 btree_map(fst, snd, args).boxed() 219 } 220 } 221 222 arbitrary!([A: Arbitrary + Ord, B: Arbitrary] btree_map::IntoIter<A, B>, 223 SMapped<BTreeMap<A, B>, Self>, 224 <BTreeMap<A, B> as Arbitrary>::Parameters; 225 args => static_map(any_with::<BTreeMap<A, B>>(args), BTreeMap::into_iter)); 226 227 impl<A: fmt::Debug + Ord + 'static, B: fmt::Debug + 'static> 228 functor::ArbitraryF2<A, B> for btree_map::IntoIter<A, B> 229 { 230 type Parameters = SizeRange; 231 lift2_with<AS, BS>( fst: AS, snd: BS, args: Self::Parameters, ) -> BoxedStrategy<Self> where AS: Strategy<Value = A> + 'static, BS: Strategy<Value = B> + 'static,232 fn lift2_with<AS, BS>( 233 fst: AS, 234 snd: BS, 235 args: Self::Parameters, 236 ) -> BoxedStrategy<Self> 237 where 238 AS: Strategy<Value = A> + 'static, 239 BS: Strategy<Value = B> + 'static, 240 { 241 static_map(btree_map(fst, snd, args), BTreeMap::into_iter).boxed() 242 } 243 } 244 245 //============================================================================== 246 // Bound: 247 //============================================================================== 248 249 arbitrary!([A: Arbitrary] Bound<A>, 250 TupleUnion<( 251 WA<SFnPtrMap<Arc<A::Strategy>, Self>>, 252 WA<SFnPtrMap<Arc<A::Strategy>, Self>>, 253 WA<LazyJustFn<Self>> 254 )>, 255 A::Parameters; 256 args => { 257 let base = Arc::new(any_with::<A>(args)); 258 prop_oneof![ 259 2 => static_map(base.clone(), Bound::Included), 260 2 => static_map(base, Bound::Excluded), 261 1 => LazyJust::new(|| Bound::Unbounded), 262 ] 263 } 264 ); 265 266 lift1!(['static] Bound<A>; base => { 267 let base = Rc::new(base); 268 prop_oneof![ 269 2 => base.clone().prop_map(Bound::Included), 270 2 => base.prop_map(Bound::Excluded), 271 1 => LazyJustFn::new(|| Bound::Unbounded), 272 ] 273 }); 274 275 #[cfg(test)] 276 mod test { 277 no_panic_test!( 278 size_bounds => SizeRange, 279 vec => Vec<u8>, 280 box_slice => Box<[u8]>, 281 rc_slice => Rc<[u8]>, 282 arc_slice => Arc<[u8]>, 283 vec_deque => VecDeque<u8>, 284 linked_list => LinkedList<u8>, 285 btree_set => BTreeSet<u8>, 286 btree_map => BTreeMap<u8, u8>, 287 bound => Bound<u8>, 288 binary_heap => BinaryHeap<u8>, 289 into_iter_vec => vec::IntoIter<u8>, 290 into_iter_vec_deque => vec_deque::IntoIter<u8>, 291 into_iter_linked_list => linked_list::IntoIter<u8>, 292 into_iter_binary_heap => binary_heap::IntoIter<u8>, 293 into_iter_btree_set => btree_set::IntoIter<u8>, 294 into_iter_btree_map => btree_map::IntoIter<u8, u8> 295 ); 296 297 #[cfg(feature = "std")] 298 no_panic_test!( 299 hash_set => HashSet<u8>, 300 hash_map => HashMap<u8, u8>, 301 into_iter_hash_set => hash_set::IntoIter<u8>, 302 into_iter_hash_map => hash_map::IntoIter<u8, u8> 303 ); 304 } 305