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
//! Collect a list of key-value pairs into a mapping of keys to collections of values.
//!
//! If you have a set of data that you want to collect into a map, by default you'll only keep the
//! last value in the data for that key. But what if you want instead to keep a collection of all
//! the values for each key? Enter [`AggregateMap`]!
//!
//!
//! ```rust
//! # use std::collections::HashMap;
//! # use aggregate_map::AggregateMap;
//! let data = [
//! ("dog", "Terry"),
//! ("dog", "Zamboni"),
//! ("cat", "Jonathan"),
//! ("dog", "Priscilla"),
//! ];
//! let collected: AggregateMap<HashMap<_, Vec<_>>> = data.into_iter().collect();
//! let expected = HashMap::from([
//! ("dog", vec!["Terry", "Zamboni", "Priscilla"]),
//! ("cat", vec!["Jonathan"])
//! ]);
//! assert_eq!(collected.into_inner(), expected);
//! ```
//!
//! [`AggregateMap`] can be used with any map type that implements this crate's [`Map`] trait, such
//! as [`HashMap`][std::collections::HashMap] or [`BTreeMap`][std::collections::BTreeMap].
//!
//! The collection type doesn't have to be a [`Vec`], too, it can be anything that implements
//! [`Extend`] and [`Default`]. For instance, here's an example with a
//! [`HashSet`][std::collections::HashSet]:
//! ```rust
//! # use std::collections::{HashMap, HashSet};
//! # use aggregate_map::AggregateMap;
//! let data = [
//! ("dog", "Terry"),
//! ("dog", "Terry"),
//! ("dog", "Priscilla"),
//! ];
//! let collected: AggregateMap<HashMap<_, HashSet<_>>> = data.into_iter().collect();
//! let expected = HashMap::from([
//! ("dog", HashSet::from(["Terry", "Priscilla"])),
//! ]);
//! assert_eq!(collected.into_inner(), expected);
//! ```
//!
//! It can even be another [`AggregateMap`] for additional levels of aggregation!
//! ```rust
//! # use std::collections::HashMap;
//! # use aggregate_map::AggregateMap;
//! let data = [
//! ("pet", ("dog", "Terry")),
//! ("pet", ("dog", "Priscilla")),
//! ("stray", ("cat", "Jennifer")),
//! ("pet", ("cat", "Absalom")),
//! ];
//! let collected: AggregateMap<HashMap<_, AggregateMap<HashMap<_, Vec<_>>>>> =
//! data.into_iter().collect();
//! let expected = HashMap::from([
//! ("pet", HashMap::from([
//! ("dog", vec!["Terry", "Priscilla"]),
//! ("cat", vec!["Absalom"]),
//! ])),
//! ("stray", HashMap::from([
//! ("cat", vec!["Jennifer"]),
//! ])),
//! ]);
//! let collected: HashMap<_, _> = collected
//! .into_inner()
//! .into_iter()
//! .map(|(key, map)| (key, map.into_inner()))
//! .collect();
//! assert_eq!(collected, expected);
//! ```
/// A wrapper around a "map" type that lets you collect an iterator of key-value pairs into a
/// mapping between keys and collections of values, instead of just keys to values.
;
/// A trait for "map" types (such as [`HashMap`][std::collections::HashMap]) that you can collect
/// into with an [`AggregateMap`].
///
/// Implementations of this trait are provided for `std` maps, but if you have a custom map type you
/// can implement this trait for it to be able to use it with [`AggregateMap`].
///
/// Implementors of this trait will generally have a key of `K`, but a value of some collection type
/// (like [`Vec`] or [`HashSet`][std::collections::HashSet]), which contains multiple values of type
/// `V`.