1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
use HashMap;
use ;
use crate;
use crate*;
/// [`HashMap`] builder for [`dice::collection`].
///
/// [`dice::collection`]: dice::collection()
/// Generates a [`HashMap`] that uses a default pseudorandom [`BuildHasher`] and contains keys of
/// type `K` with values of type `V`.
///
/// The range specifies the number of tries to generate key-value entries with distinct keys.
///
/// # Panics
///
/// Panics if the range is empty.
///
/// # Hasher
///
/// [`HashMap`] requires a [`BuildHasher`] which determines the order of elements.
/// The default is [`RandomState`] and it has no deterministic constructor.
///
/// If deterministic behavior is required, you can use [`Prng`] as [`BuildHasher`]. Otherwise,
/// you can construct [`RandomState`] yourself.
///
/// ```
/// use std::collections::hash_map::RandomState;
///
/// use dicetest::prelude::*;
/// use dicetest::{Prng, Limit};
///
/// let mut prng = Prng::from_seed(0x5EED.into());
/// let limit = Limit::default();
/// let mut fate = Fate::new(&mut prng, limit);
///
/// let elem_die = dice::zip().two(dice::u8(..), dice::char());
///
/// let hasher = fate.fork_prng();
/// let deterministic_map_die = dice::hash_map(hasher, &elem_die, ..);
///
/// let hasher = RandomState::new(); // Warning: not deterministic!
/// let non_deterministic_map_die = dice::hash_map(hasher, &elem_die, ..);
/// ```
///
/// [`Prng`]: crate::Prng
/// [`RandomState`]: std::collections::hash_map::RandomState
///
/// # Examples
///
/// ```
/// use dicetest::prelude::*;
/// use dicetest::{Prng, Limit};
///
/// let mut prng = Prng::from_seed(0x5EED.into());
/// let limit = Limit::default();
/// let mut fate = Fate::new(&mut prng, limit);
///
/// let elem_die = dice::zip().two(dice::u8(..), dice::char());
///
/// let hasher = fate.fork_prng();
/// let map = fate.with_limit(100.into()).roll(dice::hash_map(hasher, &elem_die, ..));
/// assert!(map.len() <= 100);
///
/// let hasher = fate.fork_prng();
/// let map = fate.roll(dice::hash_map(hasher, &elem_die, ..=73));
/// assert!(map.len() <= 73);
///
/// let hasher = fate.fork_prng();
/// let map = fate.roll(dice::hash_map(hasher, &elem_die, 17..));
/// assert!(map.len() >= 17);
///
/// let hasher = fate.fork_prng();
/// let map = fate.roll(dice::hash_map(hasher, &elem_die, 42));
/// assert!(map.len() <= 42);
/// ```
/// Similar to [`dice::hash_map`] but each element is generated using only a random part of
/// [`Limit`].
///
/// If you want to generate a [`HashMap`] that contains other collections, then you should
/// consider using this generator for the outer [`HashMap`]. That way the overall length is
/// bounded by [`Limit`] (and not the square of [`Limit`]).
///
/// [`Limit`]: crate::Limit
/// [`dice::hash_map`]: dice::hash_map()
///
/// # Panics
///
/// Panics if the range is empty.
///
/// # Examples
///
/// ```
/// use dicetest::prelude::*;
/// use dicetest::{Prng, Limit};
///
/// let mut prng = Prng::from_seed(0x5EED.into());
/// let limit = Limit::default();
/// let mut fate = Fate::new(&mut prng, limit);
///
/// let elem_die = dice::char();
/// let vec_die = dice::zip().two(dice::u8(..), dice::vec(elem_die, ..));
/// let hasher = fate.fork_prng();
/// let map_of_vecs_die = dice::outer_hash_map(hasher, vec_die, ..);
///
/// let map_of_vecs = fate.roll(map_of_vecs_die);
/// assert!(map_of_vecs.values().flatten().count() <= 100);
/// ```