1use key_paths_core::KeyPaths;
54use crate::error::{KeyPathResult, KeyPathError};
55
56pub trait KeyPathsOperable: Sized {
58 fn get_at_keypath<'a, V>(&'a self, keypath: &'a KeyPaths<Self, V>) -> KeyPathResult<&'a V> {
60 keypath.get(self).ok_or_else(|| KeyPathError::InvalidAccess {
61 message: "KeyPath access failed".to_string()
62 })
63 }
64
65 fn set_at_keypath<V>(&mut self, _keypath: KeyPaths<Self, V>, _value: V) -> KeyPathResult<()> {
67 Err(KeyPathError::InvalidAccess {
70 message: "KeyPath mutation not supported in this context".to_string()
71 })
72 }
73}
74
75pub trait KeyPathsIterator: Iterator {
77 fn map_keypath<V, F, R>(self, keypath: KeyPaths<Self::Item, V>, f: F) -> Vec<R>
79 where
80 Self: Sized,
81 Self::Item: KeyPathsOperable,
82 F: Fn(&V) -> R,
83 {
84 self.map(|item| {
85 let value = item.get_at_keypath(&keypath).unwrap_or_else(|_| {
86 panic!("KeyPath access failed in map_keypath")
87 });
88 f(value)
89 }).collect()
90 }
91
92 fn filter_by_keypath<V, F>(self, keypath: KeyPaths<Self::Item, V>, predicate: F) -> Vec<Self::Item>
94 where
95 Self: Sized,
96 Self::Item: KeyPathsOperable,
97 F: Fn(&V) -> bool,
98 {
99 self.filter(|item| {
100 let value = item.get_at_keypath(&keypath).unwrap_or_else(|_| {
101 panic!("KeyPath access failed in filter_by_keypath")
102 });
103 predicate(value)
104 }).collect()
105 }
106
107 fn find_by_keypath<V, F>(self, keypath: KeyPaths<Self::Item, V>, predicate: F) -> KeyPathResult<Option<Self::Item>>
109 where
110 Self: Sized,
111 Self::Item: KeyPathsOperable,
112 F: Fn(&V) -> bool,
113 {
114 for item in self {
115 if let Ok(value) = item.get_at_keypath(&keypath) {
116 if predicate(value) {
117 return Ok(Some(item));
118 }
119 }
120 }
121 Ok(None)
122 }
123
124 fn fold_keypath<V, F, B>(self, keypath: KeyPaths<Self::Item, V>, init: B, mut f: F) -> KeyPathResult<B>
126 where
127 Self: Sized,
128 Self::Item: KeyPathsOperable,
129 F: FnMut(B, &V) -> B,
130 {
131 let mut acc = init;
132 for item in self {
133 if let Ok(value) = item.get_at_keypath(&keypath) {
134 acc = f(acc, value);
135 }
136 }
137 Ok(acc)
138 }
139
140 fn collect_keypath<V>(self, keypath: KeyPaths<Self::Item, V>) -> KeyPathResult<Vec<V>>
142 where
143 Self: Sized,
144 Self::Item: KeyPathsOperable,
145 V: Clone,
146 {
147 let mut result = Vec::new();
148 for item in self {
149 if let Ok(value) = item.get_at_keypath(&keypath) {
150 result.push(value.clone());
151 }
152 }
153 Ok(result)
154 }
155}
156
157pub trait KeyPathsCollection<T> {
159 fn group_by_keypath<V, F>(&self, keypath: KeyPaths<T, V>, f: F) -> KeyPathResult<std::collections::HashMap<V, Vec<T>>>
161 where
162 V: std::hash::Hash + Eq + Clone,
163 T: Clone + KeyPathsOperable,
164 F: Fn(&V) -> V;
165
166 fn partition_by_keypath<V, F>(&self, keypath: KeyPaths<T, V>, predicate: F) -> KeyPathResult<(Vec<T>, Vec<T>)>
168 where
169 T: Clone + KeyPathsOperable,
170 F: Fn(&V) -> bool;
171
172 fn sort_by_keypath<V, F>(&mut self, keypath: KeyPaths<T, V>, compare: F) -> KeyPathResult<()>
174 where
175 T: KeyPathsOperable,
176 F: Fn(&V, &V) -> std::cmp::Ordering;
177}
178
179impl<T> KeyPathsOperable for T {}
181
182impl<I: Iterator> KeyPathsIterator for I {}
184
185impl<T> KeyPathsCollection<T> for Vec<T> {
187 fn group_by_keypath<V, F>(&self, keypath: KeyPaths<T, V>, f: F) -> KeyPathResult<std::collections::HashMap<V, Vec<T>>>
188 where
189 V: std::hash::Hash + Eq + Clone,
190 T: Clone + KeyPathsOperable,
191 F: Fn(&V) -> V,
192 {
193 let mut groups = std::collections::HashMap::new();
194 for item in self {
195 if let Ok(value) = item.get_at_keypath(&keypath) {
196 let key = f(value);
197 groups.entry(key).or_insert_with(Vec::new).push(item.clone());
198 }
199 }
200 Ok(groups)
201 }
202
203 fn partition_by_keypath<V, F>(&self, keypath: KeyPaths<T, V>, predicate: F) -> KeyPathResult<(Vec<T>, Vec<T>)>
204 where
205 T: Clone + KeyPathsOperable,
206 F: Fn(&V) -> bool,
207 {
208 let mut left = Vec::new();
209 let mut right = Vec::new();
210
211 for item in self {
212 if let Ok(value) = item.get_at_keypath(&keypath) {
213 if predicate(value) {
214 left.push(item.clone());
215 } else {
216 right.push(item.clone());
217 }
218 }
219 }
220
221 Ok((left, right))
222 }
223
224 fn sort_by_keypath<V, F>(&mut self, keypath: KeyPaths<T, V>, compare: F) -> KeyPathResult<()>
225 where
226 T: KeyPathsOperable,
227 F: Fn(&V, &V) -> std::cmp::Ordering,
228 {
229 self.sort_by(|a, b| {
230 let a_val = keypath.get(a).unwrap_or_else(|| {
231 panic!("KeyPath access failed in sort")
232 });
233 let b_val = keypath.get(b).unwrap_or_else(|| {
234 panic!("KeyPath access failed in sort")
235 });
236 compare(a_val, b_val)
237 });
238 Ok(())
239 }
240}