1use key_paths_core::KeyPaths;
4use crate::error::{KeyPathResult, KeyPathError};
5use crate::traits::KeyPathsOperable;
6use std::collections::{HashMap, HashSet, BTreeMap};
7
8pub trait KeyPathsCollectionExt<T> {
10 fn collect_keypath<V>(&self, keypath: KeyPaths<T, V>) -> KeyPathResult<Vec<V>>
12 where
13 V: Clone;
14
15 fn partition_by_keypath<V, F>(&self, keypath: KeyPaths<T, V>, predicate: F) -> KeyPathResult<(Vec<T>, Vec<T>)>
17 where
18 T: Clone,
19 F: Fn(&V) -> bool;
20
21 fn group_by_keypath<V, F>(&self, keypath: KeyPaths<T, V>, f: F) -> KeyPathResult<HashMap<V, Vec<T>>>
23 where
24 V: std::hash::Hash + Eq + Clone,
25 T: Clone,
26 F: Fn(&V) -> V;
27
28 fn sort_by_keypath<V, F>(&mut self, keypath: KeyPaths<T, V>, compare: F) -> KeyPathResult<()>
30 where
31 F: Fn(&V, &V) -> std::cmp::Ordering;
32
33 fn find_by_keypath<V, F>(&self, keypath: KeyPaths<T, V>, predicate: F) -> KeyPathResult<Option<&T>>
35 where
36 F: Fn(&V) -> bool;
37
38 fn any_by_keypath<V, F>(&self, keypath: KeyPaths<T, V>, predicate: F) -> KeyPathResult<bool>
40 where
41 F: Fn(&V) -> bool;
42
43 fn all_by_keypath<V, F>(&self, keypath: KeyPaths<T, V>, predicate: F) -> KeyPathResult<bool>
45 where
46 F: Fn(&V) -> bool;
47
48 fn count_by_keypath<V, F>(&self, keypath: KeyPaths<T, V>, predicate: F) -> KeyPathResult<usize>
50 where
51 F: Fn(&V) -> bool;
52
53 fn unique_by_keypath<V>(&self, keypath: KeyPaths<T, V>) -> KeyPathResult<HashSet<V>>
55 where
56 V: std::hash::Hash + Eq + Clone;
57
58 fn distinct_by_keypath<V>(&self, keypath: KeyPaths<T, V>) -> KeyPathResult<HashMap<V, usize>>
60 where
61 V: std::hash::Hash + Eq + Clone;
62
63 fn zip_with_keypath<U, V1, V2, F, R>(
65 &self,
66 other: &[U],
67 keypath1: KeyPaths<T, V1>,
68 keypath2: KeyPaths<U, V2>,
69 f: F,
70 ) -> KeyPathResult<Vec<R>>
71 where
72 F: Fn(&V1, &V2) -> R;
73
74 fn window_by_keypath<V, F, R>(
76 &self,
77 keypath: KeyPaths<T, V>,
78 window_size: usize,
79 f: F,
80 ) -> KeyPathResult<Vec<R>>
81 where
82 V: Clone,
83 F: Fn(&[V]) -> R;
84
85 fn rolling_by_keypath<V, F, R>(
87 &self,
88 keypath: KeyPaths<T, V>,
89 window_size: usize,
90 f: F,
91 ) -> KeyPathResult<Vec<R>>
92 where
93 V: Clone,
94 F: Fn(&[V]) -> R;
95}
96
97impl<T: KeyPathsOperable> KeyPathsCollectionExt<T> for Vec<T> {
98 fn collect_keypath<V>(&self, keypath: KeyPaths<T, V>) -> KeyPathResult<Vec<V>>
99 where
100 V: Clone,
101 {
102 let mut result = Vec::with_capacity(self.len());
103 for item in self {
104 let value = item.get_at_keypath(&keypath).unwrap_or_else(|_| {
105 panic!("KeyPath access failed in collect_keypath")
106 });
107 result.push(value.clone());
108 }
109 Ok(result)
110 }
111
112 fn partition_by_keypath<V, F>(&self, keypath: KeyPaths<T, V>, predicate: F) -> KeyPathResult<(Vec<T>, Vec<T>)>
113 where
114 T: Clone,
115 F: Fn(&V) -> bool,
116 {
117 let mut left = Vec::new();
118 let mut right = Vec::new();
119
120 for item in self {
121 let value = item.get_at_keypath(&keypath).unwrap_or_else(|_| {
122 panic!("KeyPath access failed in partition_by_keypath")
123 });
124 if predicate(value) {
125 left.push(item.clone());
126 } else {
127 right.push(item.clone());
128 }
129 }
130
131 Ok((left, right))
132 }
133
134 fn group_by_keypath<V, F>(&self, keypath: KeyPaths<T, V>, f: F) -> KeyPathResult<HashMap<V, Vec<T>>>
135 where
136 V: std::hash::Hash + Eq + Clone,
137 T: Clone,
138 F: Fn(&V) -> V,
139 {
140 let mut groups = HashMap::new();
141 for item in self {
142 let value = item.get_at_keypath(&keypath).unwrap_or_else(|_| {
143 panic!("KeyPath access failed in group_by_keypath")
144 });
145 let key = f(value);
146 groups.entry(key).or_insert_with(Vec::new).push(item.clone());
147 }
148 Ok(groups)
149 }
150
151 fn sort_by_keypath<V, F>(&mut self, keypath: KeyPaths<T, V>, compare: F) -> KeyPathResult<()>
152 where
153 F: Fn(&V, &V) -> std::cmp::Ordering,
154 {
155 self.sort_by(|a, b| {
156 let a_val = a.get_at_keypath(&keypath).unwrap_or_else(|_| {
157 panic!("KeyPath access failed in sort_by_keypath")
158 });
159 let b_val = b.get_at_keypath(&keypath).unwrap_or_else(|_| {
160 panic!("KeyPath access failed in sort_by_keypath")
161 });
162 compare(a_val, b_val)
163 });
164 Ok(())
165 }
166
167 fn find_by_keypath<V, F>(&self, keypath: KeyPaths<T, V>, predicate: F) -> KeyPathResult<Option<&T>>
168 where
169 F: Fn(&V) -> bool,
170 {
171 for item in self {
172 let value = item.get_at_keypath(&keypath).unwrap_or_else(|_| {
173 panic!("KeyPath access failed in find_by_keypath")
174 });
175 if predicate(value) {
176 return Ok(Some(item));
177 }
178 }
179 Ok(None)
180 }
181
182 fn any_by_keypath<V, F>(&self, keypath: KeyPaths<T, V>, predicate: F) -> KeyPathResult<bool>
183 where
184 F: Fn(&V) -> bool,
185 {
186 for item in self {
187 let value = item.get_at_keypath(&keypath).unwrap_or_else(|_| {
188 panic!("KeyPath access failed in any_by_keypath")
189 });
190 if predicate(value) {
191 return Ok(true);
192 }
193 }
194 Ok(false)
195 }
196
197 fn all_by_keypath<V, F>(&self, keypath: KeyPaths<T, V>, predicate: F) -> KeyPathResult<bool>
198 where
199 F: Fn(&V) -> bool,
200 {
201 for item in self {
202 let value = item.get_at_keypath(&keypath).unwrap_or_else(|_| {
203 panic!("KeyPath access failed in all_by_keypath")
204 });
205 if !predicate(value) {
206 return Ok(false);
207 }
208 }
209 Ok(true)
210 }
211
212 fn count_by_keypath<V, F>(&self, keypath: KeyPaths<T, V>, predicate: F) -> KeyPathResult<usize>
213 where
214 F: Fn(&V) -> bool,
215 {
216 let mut count = 0;
217 for item in self {
218 let value = item.get_at_keypath(&keypath).unwrap_or_else(|_| {
219 panic!("KeyPath access failed in count_by_keypath")
220 });
221 if predicate(value) {
222 count += 1;
223 }
224 }
225 Ok(count)
226 }
227
228 fn unique_by_keypath<V>(&self, keypath: KeyPaths<T, V>) -> KeyPathResult<HashSet<V>>
229 where
230 V: std::hash::Hash + Eq + Clone,
231 {
232 let mut unique = HashSet::new();
233 for item in self {
234 let value = item.get_at_keypath(&keypath).unwrap_or_else(|_| {
235 panic!("KeyPath access failed in unique_by_keypath")
236 });
237 unique.insert(value.clone());
238 }
239 Ok(unique)
240 }
241
242 fn distinct_by_keypath<V>(&self, keypath: KeyPaths<T, V>) -> KeyPathResult<HashMap<V, usize>>
243 where
244 V: std::hash::Hash + Eq + Clone,
245 {
246 let mut counts = HashMap::new();
247 for item in self {
248 let value = item.get_at_keypath(&keypath).unwrap_or_else(|_| {
249 panic!("KeyPath access failed in distinct_by_keypath")
250 });
251 *counts.entry(value.clone()).or_insert(0) += 1;
252 }
253 Ok(counts)
254 }
255
256 fn zip_with_keypath<U, V1, V2, F, R>(
257 &self,
258 other: &[U],
259 keypath1: KeyPaths<T, V1>,
260 keypath2: KeyPaths<U, V2>,
261 f: F,
262 ) -> KeyPathResult<Vec<R>>
263 where
264 U: KeyPathsOperable,
265 F: Fn(&V1, &V2) -> R,
266 {
267 let min_len = self.len().min(other.len());
268 let mut result = Vec::with_capacity(min_len);
269
270 for i in 0..min_len {
271 let value1 = self[i].get_at_keypath(&keypath1).unwrap_or_else(|_| {
272 panic!("KeyPath access failed in zip_with_keypath")
273 });
274 let value2 = other[i].get_at_keypath(&keypath2).unwrap_or_else(|_| {
275 panic!("KeyPath access failed in zip_with_keypath")
276 });
277 result.push(f(value1, value2));
278 }
279
280 Ok(result)
281 }
282
283 fn window_by_keypath<V, F, R>(
284 &self,
285 keypath: KeyPaths<T, V>,
286 window_size: usize,
287 f: F,
288 ) -> KeyPathResult<Vec<R>>
289 where
290 V: Clone,
291 F: Fn(&[V]) -> R,
292 {
293 if window_size == 0 || window_size > self.len() {
294 return Err(KeyPathError::CollectionError {
295 message: format!("Invalid window size: {}", window_size),
296 });
297 }
298
299 let mut result = Vec::new();
300 for i in 0..=self.len() - window_size {
301 let window: Vec<V> = self[i..i + window_size]
302 .iter()
303 .map(|item| item.get_at_keypath(&keypath).unwrap_or_else(|_| {
304 panic!("KeyPath access failed in window_by_keypath")
305 }).clone())
306 .collect();
307 result.push(f(&window));
308 }
309
310 Ok(result)
311 }
312
313 fn rolling_by_keypath<V, F, R>(
314 &self,
315 keypath: KeyPaths<T, V>,
316 window_size: usize,
317 f: F,
318 ) -> KeyPathResult<Vec<R>>
319 where
320 V: Clone,
321 F: Fn(&[V]) -> R,
322 {
323 if window_size == 0 {
324 return Err(KeyPathError::CollectionError {
325 message: "Window size must be greater than 0".to_string(),
326 });
327 }
328
329 let mut result = Vec::new();
330 let mut window = Vec::with_capacity(window_size);
331
332 for item in self {
333 let value = item.get_at_keypath(&keypath).unwrap_or_else(|_| {
334 panic!("KeyPath access failed in rolling_by_keypath")
335 }).clone();
336 window.push(value);
337
338 if window.len() == window_size {
339 result.push(f(&window));
340 window.remove(0);
341 }
342 }
343
344 Ok(result)
345 }
346}
347
348pub mod specialized {
350 use super::*;
351
352 pub trait KeyPathsHashMapExt<K, V> {
354 fn map_values_keypath<T, F, R>(&self, keypath: KeyPaths<V, T>, f: F) -> KeyPathResult<HashMap<K, R>>
356 where
357 K: Clone,
358 F: Fn(&T) -> R;
359
360 fn filter_values_keypath<T, F>(&self, keypath: KeyPaths<V, T>, predicate: F) -> KeyPathResult<HashMap<K, V>>
362 where
363 K: Clone,
364 V: Clone,
365 F: Fn(&T) -> bool;
366 }
367
368 impl<K: std::hash::Hash + std::cmp::Eq, V: KeyPathsOperable> KeyPathsHashMapExt<K, V> for HashMap<K, V> {
369 fn map_values_keypath<T, F, R>(&self, keypath: KeyPaths<V, T>, f: F) -> KeyPathResult<HashMap<K, R>>
370 where
371 K: Clone,
372 F: Fn(&T) -> R,
373 {
374 let mut result = HashMap::new();
375 for (key, value) in self {
376 let keypath_value = value.get_at_keypath(&keypath).unwrap_or_else(|_| {
377 panic!("KeyPath access failed in map_values_keypath")
378 });
379 result.insert(key.clone(), f(keypath_value));
380 }
381 Ok(result)
382 }
383
384 fn filter_values_keypath<T, F>(&self, keypath: KeyPaths<V, T>, predicate: F) -> KeyPathResult<HashMap<K, V>>
385 where
386 K: Clone,
387 V: Clone,
388 F: Fn(&T) -> bool,
389 {
390 let mut result = HashMap::new();
391 for (key, value) in self {
392 let keypath_value = keypath.get(value).unwrap_or_else(|| {
393 panic!("KeyPath access failed in filter_values_keypath")
394 });
395 if predicate(keypath_value) {
396 result.insert(key.clone(), value.clone());
397 }
398 }
399 Ok(result)
400 }
401 }
402
403 pub trait KeyPathsBTreeMapExt<K, V> {
405 fn map_values_keypath<T, F, R>(&self, keypath: KeyPaths<V, T>, f: F) -> KeyPathResult<BTreeMap<K, R>>
407 where
408 K: Clone + Ord,
409 F: Fn(&T) -> R;
410
411 fn filter_values_keypath<T, F>(&self, keypath: KeyPaths<V, T>, predicate: F) -> KeyPathResult<BTreeMap<K, V>>
413 where
414 K: Clone + Ord,
415 V: Clone,
416 F: Fn(&T) -> bool;
417 }
418
419 impl<K: std::cmp::Ord, V: KeyPathsOperable> KeyPathsBTreeMapExt<K, V> for BTreeMap<K, V> {
420 fn map_values_keypath<T, F, R>(&self, keypath: KeyPaths<V, T>, f: F) -> KeyPathResult<BTreeMap<K, R>>
421 where
422 K: Clone + Ord,
423 F: Fn(&T) -> R,
424 {
425 let mut result = BTreeMap::new();
426 for (key, value) in self {
427 let keypath_value = value.get_at_keypath(&keypath).unwrap_or_else(|_| {
428 panic!("KeyPath access failed in map_values_keypath")
429 });
430 result.insert(key.clone(), f(keypath_value));
431 }
432 Ok(result)
433 }
434
435 fn filter_values_keypath<T, F>(&self, keypath: KeyPaths<V, T>, predicate: F) -> KeyPathResult<BTreeMap<K, V>>
436 where
437 K: Clone + Ord,
438 V: Clone,
439 F: Fn(&T) -> bool,
440 {
441 let mut result = BTreeMap::new();
442 for (key, value) in self {
443 let keypath_value = keypath.get(value).unwrap_or_else(|| {
444 panic!("KeyPath access failed in filter_values_keypath")
445 });
446 if predicate(keypath_value) {
447 result.insert(key.clone(), value.clone());
448 }
449 }
450 Ok(result)
451 }
452 }
453}
454
455pub mod utils {
457 use super::*;
458
459 pub fn create_keypath_comparator<T: KeyPathsOperable, V, F>(
461 keypath: KeyPaths<T, V>,
462 compare: F,
463 ) -> impl Fn(&T, &T) -> std::cmp::Ordering
464 where
465 F: Fn(&V, &V) -> std::cmp::Ordering,
466 {
467 move |a, b| {
468 let a_val = a.get_at_keypath(&keypath).unwrap_or_else(|_| {
469 panic!("KeyPath access failed in create_keypath_comparator")
470 });
471 let b_val = b.get_at_keypath(&keypath).unwrap_or_else(|_| {
472 panic!("KeyPath access failed in create_keypath_comparator")
473 });
474 compare(a_val, b_val)
475 }
476 }
477
478 pub fn create_keypath_hasher<T: KeyPathsOperable, V, H>(
480 keypath: KeyPaths<T, V>,
481 hasher: H,
482 ) -> impl Fn(&T) -> u64
483 where
484 H: Fn(&V) -> u64,
485 {
486 move |item| {
487 let value = item.get_at_keypath(&keypath).unwrap_or_else(|_| {
488 panic!("KeyPath access failed in create_keypath_hasher")
489 });
490 hasher(value)
491 }
492 }
493
494 pub fn create_keypath_equality<T: KeyPathsOperable, V, E>(
496 keypath: KeyPaths<T, V>,
497 equality: E,
498 ) -> impl Fn(&T, &T) -> bool
499 where
500 E: Fn(&V, &V) -> bool,
501 {
502 move |a, b| {
503 let a_val = a.get_at_keypath(&keypath).unwrap_or_else(|_| {
504 panic!("KeyPath access failed in create_keypath_equality")
505 });
506 let b_val = b.get_at_keypath(&keypath).unwrap_or_else(|_| {
507 panic!("KeyPath access failed in create_keypath_equality")
508 });
509 equality(a_val, b_val)
510 }
511 }
512}