1use std::ops::Mul;
2
3use num_traits::PrimInt;
4use rayon::prelude::*;
5
6pub type IndexTuple = Box<[IndexKey]>;
15
16#[derive(Clone, Debug)]
21pub enum Set {
22 Range(Vec<i64>),
23 Strings(Vec<String>),
24 Tuples(Vec<IndexTuple>),
25}
26
27impl Set {
28 pub fn range<T: PrimInt>(r: std::ops::Range<T>) -> Self {
37 let start = r.start.to_i64().expect("range start out of i64 range");
38 let end = r.end.to_i64().expect("range end out of i64 range");
39 Self::Range((start..end).collect())
40 }
41
42 pub fn from_ints<T, I>(iter: I) -> Self
48 where
49 T: PrimInt,
50 I: IntoIterator<Item = T>,
51 {
52 Self::Range(
53 iter.into_iter().map(|v| v.to_i64().expect("element out of i64 range")).collect(),
54 )
55 }
56
57 pub fn strings<I, S>(iter: I) -> Self
58 where
59 I: IntoIterator<Item = S>,
60 S: Into<String>,
61 {
62 Self::Strings(iter.into_iter().map(Into::into).collect())
63 }
64
65 pub fn tuples<I, T>(iter: I) -> Self
67 where
68 I: IntoIterator<Item = T>,
69 T: Into<IndexTuple>,
70 {
71 Self::Tuples(iter.into_iter().map(Into::into).collect())
72 }
73
74 pub fn product(a: &Set, b: &Set) -> Self {
77 let mut out = Vec::new();
78 if let Some(capacity) = a.len().checked_mul(b.len()) {
79 let _ = out.try_reserve_exact(capacity);
81 }
82 for ka in a {
83 for kb in b {
84 let mut parts: Vec<IndexKey> = Vec::new();
85 push_flat(&mut parts, ka.clone());
86 push_flat(&mut parts, kb);
87 out.push(parts.into_boxed_slice());
88 }
89 }
90 Self::Tuples(out)
91 }
92
93 pub fn filter<F>(&self, mut f: F) -> Self
96 where
97 F: FnMut(&IndexKey) -> bool,
98 {
99 match self {
100 Self::Range(v) => {
101 Self::Range(v.iter().copied().filter(|i| f(&IndexKey::Int(*i))).collect())
102 }
103 Self::Strings(v) => Self::Strings(
104 v.iter()
105 .filter_map(|s| {
106 let key = IndexKey::Str(s.clone());
107 f(&key).then(|| match key {
108 IndexKey::Str(owned) => owned,
109 _ => unreachable!(),
110 })
111 })
112 .collect(),
113 ),
114 Self::Tuples(v) => Self::Tuples(
115 v.iter()
116 .filter_map(|t| {
117 let key = IndexKey::Tuple(t.clone());
118 f(&key).then(|| match key {
119 IndexKey::Tuple(owned) => owned,
120 _ => unreachable!(),
121 })
122 })
123 .collect(),
124 ),
125 }
126 }
127
128 pub fn len(&self) -> usize {
129 match self {
130 Self::Range(v) => v.len(),
131 Self::Strings(v) => v.len(),
132 Self::Tuples(v) => v.len(),
133 }
134 }
135
136 pub fn is_empty(&self) -> bool {
137 self.len() == 0
138 }
139}
140
141fn push_flat(dst: &mut Vec<IndexKey>, k: IndexKey) {
142 match k {
143 IndexKey::Tuple(inner) => dst.extend(inner.into_vec()),
144 other => dst.push(other),
145 }
146}
147
148fn make_tuple<I: IntoIterator<Item = IndexKey>>(items: I) -> IndexTuple {
149 let mut v: Vec<IndexKey> = Vec::new();
150 for k in items {
151 push_flat(&mut v, k);
152 }
153 v.into_boxed_slice()
154}
155
156impl Mul<&Set> for &Set {
157 type Output = Set;
158 fn mul(self, rhs: &Set) -> Set {
159 Set::product(self, rhs)
160 }
161}
162
163#[derive(Clone, Debug, PartialEq, Eq, Hash)]
165pub enum IndexKey {
166 Int(i64),
167 Str(String),
168 Tuple(IndexTuple),
169}
170
171impl IndexKey {
172 pub fn tuple<I, T>(iter: I) -> Self
175 where
176 I: IntoIterator<Item = T>,
177 T: Into<IndexKey>,
178 {
179 Self::Tuple(make_tuple(iter.into_iter().map(Into::into)))
180 }
181
182 pub fn as_i64(&self) -> Option<i64> {
183 if let Self::Int(v) = self { Some(*v) } else { None }
184 }
185
186 pub fn as_str(&self) -> Option<&str> {
187 if let Self::Str(s) = self { Some(s.as_str()) } else { None }
188 }
189
190 pub fn as_tuple(&self) -> Option<&[IndexKey]> {
191 if let Self::Tuple(t) = self { Some(&t[..]) } else { None }
192 }
193}
194
195impl From<i64> for IndexKey {
196 fn from(v: i64) -> Self {
197 Self::Int(v)
198 }
199}
200
201impl From<i32> for IndexKey {
202 fn from(v: i32) -> Self {
203 Self::Int(i64::from(v))
204 }
205}
206
207impl From<usize> for IndexKey {
208 fn from(v: usize) -> Self {
209 Self::Int(i64::try_from(v).expect("usize -> i64 overflow"))
210 }
211}
212
213impl From<&str> for IndexKey {
214 fn from(s: &str) -> Self {
215 Self::Str(s.to_owned())
216 }
217}
218
219impl From<String> for IndexKey {
220 fn from(s: String) -> Self {
221 Self::Str(s)
222 }
223}
224
225impl<A, B> From<(A, B)> for IndexKey
226where
227 A: Into<IndexKey>,
228 B: Into<IndexKey>,
229{
230 fn from(t: (A, B)) -> Self {
231 Self::Tuple(make_tuple([t.0.into(), t.1.into()]))
232 }
233}
234
235impl<A, B, C> From<(A, B, C)> for IndexKey
236where
237 A: Into<IndexKey>,
238 B: Into<IndexKey>,
239 C: Into<IndexKey>,
240{
241 fn from(t: (A, B, C)) -> Self {
242 Self::Tuple(make_tuple([t.0.into(), t.1.into(), t.2.into()]))
243 }
244}
245
246impl<A, B, C, D> From<(A, B, C, D)> for IndexKey
247where
248 A: Into<IndexKey>,
249 B: Into<IndexKey>,
250 C: Into<IndexKey>,
251 D: Into<IndexKey>,
252{
253 fn from(t: (A, B, C, D)) -> Self {
254 Self::Tuple(make_tuple([t.0.into(), t.1.into(), t.2.into(), t.3.into()]))
255 }
256}
257
258pub trait FromIndexKey: Sized {
272 fn from_index_key(k: &IndexKey) -> Self;
273}
274
275impl FromIndexKey for IndexKey {
276 fn from_index_key(k: &IndexKey) -> Self {
277 k.clone()
278 }
279}
280
281impl FromIndexKey for i64 {
282 fn from_index_key(k: &IndexKey) -> Self {
283 k.as_i64().unwrap_or_else(|| panic!("expected Int key, got {k:?}"))
284 }
285}
286
287impl FromIndexKey for i32 {
288 fn from_index_key(k: &IndexKey) -> Self {
289 let v = i64::from_index_key(k);
290 i32::try_from(v).unwrap_or_else(|_| panic!("key {v} out of i32 range"))
291 }
292}
293
294impl FromIndexKey for usize {
295 fn from_index_key(k: &IndexKey) -> Self {
296 let v = i64::from_index_key(k);
297 usize::try_from(v).unwrap_or_else(|_| panic!("key {v} out of usize range"))
298 }
299}
300
301impl FromIndexKey for String {
302 fn from_index_key(k: &IndexKey) -> Self {
303 k.as_str().unwrap_or_else(|| panic!("expected Str key, got {k:?}")).to_owned()
304 }
305}
306
307fn tuple_parts<'a>(k: &'a IndexKey, expected: usize) -> &'a [IndexKey] {
308 let p = k.as_tuple().unwrap_or_else(|| panic!("expected Tuple key, got {k:?}"));
309 assert_eq!(p.len(), expected, "expected tuple of arity {expected}, got arity {}", p.len());
310 p
311}
312
313impl<A, B> FromIndexKey for (A, B)
314where
315 A: FromIndexKey,
316 B: FromIndexKey,
317{
318 fn from_index_key(k: &IndexKey) -> Self {
319 let p = tuple_parts(k, 2);
320 (A::from_index_key(&p[0]), B::from_index_key(&p[1]))
321 }
322}
323
324impl<A, B, C> FromIndexKey for (A, B, C)
325where
326 A: FromIndexKey,
327 B: FromIndexKey,
328 C: FromIndexKey,
329{
330 fn from_index_key(k: &IndexKey) -> Self {
331 let p = tuple_parts(k, 3);
332 (A::from_index_key(&p[0]), B::from_index_key(&p[1]), C::from_index_key(&p[2]))
333 }
334}
335
336impl<A, B, C, D> FromIndexKey for (A, B, C, D)
337where
338 A: FromIndexKey,
339 B: FromIndexKey,
340 C: FromIndexKey,
341 D: FromIndexKey,
342{
343 fn from_index_key(k: &IndexKey) -> Self {
344 let p = tuple_parts(k, 4);
345 (
346 A::from_index_key(&p[0]),
347 B::from_index_key(&p[1]),
348 C::from_index_key(&p[2]),
349 D::from_index_key(&p[3]),
350 )
351 }
352}
353
354impl<'a> IntoIterator for &'a Set {
355 type Item = IndexKey;
356 type IntoIter = SetIter<'a>;
357 fn into_iter(self) -> Self::IntoIter {
358 self.iter()
359 }
360}
361
362impl Set {
363 pub fn iter(&self) -> SetIter<'_> {
364 SetIter { set: self, pos: 0 }
365 }
366
367 pub fn par_iter(&self) -> impl ParallelIterator<Item = IndexKey> + '_ {
368 match self {
369 Self::Range(v) => v.par_iter().map(|i| IndexKey::Int(*i)).collect::<Vec<_>>(),
370 Self::Strings(v) => v.par_iter().map(|s| IndexKey::Str(s.clone())).collect::<Vec<_>>(),
371 Self::Tuples(v) => v.par_iter().map(|t| IndexKey::Tuple(t.clone())).collect::<Vec<_>>(),
372 }
373 .into_par_iter()
374 }
375}
376
377#[derive(Debug)]
378pub struct SetIter<'a> {
379 set: &'a Set,
380 pos: usize,
381}
382
383impl<'a> Iterator for SetIter<'a> {
384 type Item = IndexKey;
385 fn next(&mut self) -> Option<Self::Item> {
386 let out = match self.set {
387 Set::Range(v) => v.get(self.pos).copied().map(IndexKey::Int),
388 Set::Strings(v) => v.get(self.pos).cloned().map(IndexKey::Str),
389 Set::Tuples(v) => v.get(self.pos).cloned().map(IndexKey::Tuple),
390 };
391 if out.is_some() {
392 self.pos += 1;
393 }
394 out
395 }
396}