aoc_parse/parsers/collections.rs
1//! Parsers that produce collections other than `Vec`s.
2
3use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque};
4use std::marker::PhantomData;
5
6use crate::parsers::map::{MapParser, Mapping};
7use crate::Parser;
8
9#[derive(Debug, Clone, Copy, Default)]
10pub struct Collect<C> {
11 phantom: PhantomData<fn() -> C>,
12}
13
14impl<V, C> Mapping<(V,)> for Collect<C>
15where
16 V: IntoIterator,
17 C: FromIterator<V::Item>,
18{
19 type RawOutput = (C,);
20
21 fn apply(&self, (value,): (V,)) -> (C,) {
22 (value.into_iter().collect(),)
23 }
24}
25
26/// Convert the output of `parser` from a `Vec<(K, V)>` or other collection of pairs
27/// into a `HashMap`.
28///
29/// For example, the parser `lines(alpha " = " u64)` produces a `Vec<(char, u64)>`.
30/// Wrapping that parser in `hash_map` makes it produce a `HashMap<char, u64>` instead:
31///
32/// ```
33/// # use aoc_parse::{parser, prelude::*};
34/// let p = parser!(hash_map(lines(alpha " = " u64)));
35///
36/// let h = p.parse("X = 33\nY = 75\n").unwrap();
37/// assert_eq!(h[&'X'], 33);
38/// assert_eq!(h[&'Y'], 75);
39/// ```
40pub fn hash_map<P, K, V>(parser: P) -> MapParser<P, Collect<HashMap<K, V>>>
41where
42 P: Parser,
43 P::Output: IntoIterator<Item = (K, V)>,
44{
45 MapParser {
46 inner: parser,
47 mapper: Collect::default(),
48 }
49}
50
51/// Convert the output of `parser` from a `Vec<V>` or other collection
52/// into a `HashSet`.
53///
54/// For example, the parser `alpha+` produces a `Vec<char>`,
55/// so `hash_set(alpha+)` produces a `HashSet<char>`:
56///
57/// ```
58/// # use aoc_parse::{parser, prelude::*};
59/// let p = parser!(hash_set(alpha+));
60///
61/// let set = p.parse("xZjZZd").unwrap();
62/// assert_eq!(set.len(), 4); // x Z j d
63/// assert!(set.contains(&'d'));
64/// assert!(!set.contains(&'r'));
65/// ```
66pub fn hash_set<P, V>(parser: P) -> MapParser<P, Collect<HashSet<V>>>
67where
68 P: Parser,
69 P::Output: IntoIterator<Item = V>,
70{
71 MapParser {
72 inner: parser,
73 mapper: Collect::default(),
74 }
75}
76
77/// Convert the output of `parser` from a `Vec<(K, V)>` or other collection of pairs
78/// into a `BTreeMap`.
79pub fn btree_map<P, K, V>(parser: P) -> MapParser<P, Collect<BTreeMap<K, V>>>
80where
81 P: Parser,
82 P::Output: IntoIterator<Item = (K, V)>,
83{
84 MapParser {
85 inner: parser,
86 mapper: Collect::default(),
87 }
88}
89
90/// Convert the output of `parser` from a `Vec<V>` or other collection
91/// into a `BTreeSet`.
92pub fn btree_set<P, V>(parser: P) -> MapParser<P, Collect<BTreeSet<V>>>
93where
94 P: Parser,
95 P::Output: IntoIterator<Item = V>,
96{
97 MapParser {
98 inner: parser,
99 mapper: Collect::default(),
100 }
101}
102
103/// Convert the output of `parser` from a `Vec<V>` or other collection
104/// into a `VecDeque`.
105pub fn vec_deque<P, V>(parser: P) -> MapParser<P, Collect<VecDeque<V>>>
106where
107 P: Parser,
108 P::Output: IntoIterator<Item = V>,
109{
110 // NOTE: A mapping that uses `Into` might be faster, but I'm not sure. The standard library has
111 // some specializations to do iterator-based colletion operations like this in-place.
112 MapParser {
113 inner: parser,
114 mapper: Collect::default(),
115 }
116}