1use std::{hash::Hash, marker::PhantomData};
4
5use crate::{
6 map_query::{
7 BuildQueryRuntime, MapQuery,
8 properties::{ExactlyOne, PlanProperties, ZeroOrOne},
9 },
10 subscription::SubscriptionGuard,
11 traits::{
12 CellValue,
13 collections::internal::stateless_runtime::{
14 install_filter_map_values_runtime, install_map_values_runtime,
15 },
16 },
17};
18
19impl<S, K, V, U, F> PlanProperties for MapValuesPlan<S, K, V, U, F>
20where
21 S: MapQuery<Key = K, Value = V> + PlanProperties,
22 K: Hash + Eq + CellValue,
23 V: CellValue,
24 U: CellValue,
25 F: Fn(&K, &V) -> U + Send + Sync + 'static,
26{
27 type Cardinality = ExactlyOne;
28 type InputPartition = S::OutputPartition;
29 type OutputPartition = S::OutputPartition;
30}
31
32impl<S, K, V, U, F> PlanProperties for FilterMapValuesPlan<S, K, V, U, F>
33where
34 S: MapQuery<Key = K, Value = V> + PlanProperties,
35 K: Hash + Eq + CellValue,
36 V: CellValue,
37 U: CellValue,
38 F: Fn(&K, &V) -> Option<U> + Send + Sync + 'static,
39{
40 type Cardinality = ZeroOrOne;
41 type InputPartition = S::OutputPartition;
42 type OutputPartition = S::OutputPartition;
43}
44
45pub struct MapValuesPlan<S, K, V, U, F>
47where
48 S: MapQuery<Key = K, Value = V>,
49 K: Hash + Eq + CellValue,
50 V: CellValue,
51 U: CellValue,
52 F: Fn(&K, &V) -> U + Send + Sync + 'static,
53{
54 pub(crate) source: S,
55 pub(crate) f: F,
56 _types: PhantomData<fn() -> (K, V, U)>,
57}
58
59impl<S, K, V, U, F> BuildQueryRuntime<K, U> for MapValuesPlan<S, K, V, U, F>
60where
61 S: MapQuery<Key = K, Value = V>,
62 K: Hash + Eq + CellValue,
63 V: CellValue,
64 U: CellValue,
65 F: Fn(&K, &V) -> U + Send + Sync + 'static,
66{
67 fn build_into(
68 self,
69 cx: &mut crate::map_query::compiler::CompileContext,
70 sink: crate::map_query::BoxedMapDiffSink<K, U>,
71 ) -> Vec<SubscriptionGuard> {
72 install_map_values_runtime(cx, self.source, self.f, sink)
73 }
74}
75
76#[allow(private_bounds)]
77impl<S, K, V, U, F> MapQuery for MapValuesPlan<S, K, V, U, F>
78where
79 S: MapQuery<Key = K, Value = V>,
80 K: Hash + Eq + CellValue,
81 V: CellValue,
82 U: CellValue,
83 F: Fn(&K, &V) -> U + Send + Sync + 'static,
84{
85 type Key = K;
86 type Value = U;
87}
88
89impl<S, K, V, U, F> MapValuesPlan<S, K, V, U, F>
90where
91 S: MapQuery<Key = K, Value = V>,
92 K: Hash + Eq + CellValue,
93 V: CellValue,
94 U: CellValue,
95 F: Fn(&K, &V) -> U + Send + Sync + 'static,
96{
97 pub fn map_values<W, G>(
99 self,
100 g: G,
101 ) -> MapValuesPlan<S, K, V, W, impl Fn(&K, &V) -> W + Send + Sync + 'static>
102 where
103 W: CellValue,
104 G: Fn(&K, &U) -> W + Send + Sync + 'static,
105 {
106 let f = self.f;
107 MapValuesPlan {
108 source: self.source,
109 f: move |key, value| {
110 let value = f(key, value);
111 g(key, &value)
112 },
113 _types: PhantomData,
114 }
115 }
116
117 pub fn filter_map_values<W, G>(
119 self,
120 g: G,
121 ) -> FilterMapValuesPlan<S, K, V, W, impl Fn(&K, &V) -> Option<W> + Send + Sync + 'static>
122 where
123 W: CellValue,
124 G: Fn(&K, &U) -> Option<W> + Send + Sync + 'static,
125 {
126 let f = self.f;
127 FilterMapValuesPlan {
128 source: self.source,
129 f: move |key, value| {
130 let value = f(key, value);
131 g(key, &value)
132 },
133 _types: PhantomData,
134 }
135 }
136
137 pub fn select<G>(
139 self,
140 predicate: G,
141 ) -> FilterMapValuesPlan<S, K, V, U, impl Fn(&K, &V) -> Option<U> + Send + Sync + 'static>
142 where
143 G: Fn(&U) -> bool + Send + Sync + 'static,
144 {
145 let f = self.f;
146 FilterMapValuesPlan {
147 source: self.source,
148 f: move |key, value| {
149 let value = f(key, value);
150 predicate(&value).then_some(value)
151 },
152 _types: PhantomData,
153 }
154 }
155
156 pub fn select_by<G>(
158 self,
159 predicate: G,
160 ) -> FilterMapValuesPlan<S, K, V, U, impl Fn(&K, &V) -> Option<U> + Send + Sync + 'static>
161 where
162 G: Fn(&K, &U) -> bool + Send + Sync + 'static,
163 {
164 let f = self.f;
165 FilterMapValuesPlan {
166 source: self.source,
167 f: move |key, value| {
168 let value = f(key, value);
169 predicate(key, &value).then_some(value)
170 },
171 _types: PhantomData,
172 }
173 }
174}
175
176pub struct FilterMapValuesPlan<S, K, V, U, F>
178where
179 S: MapQuery<Key = K, Value = V>,
180 K: Hash + Eq + CellValue,
181 V: CellValue,
182 U: CellValue,
183 F: Fn(&K, &V) -> Option<U> + Send + Sync + 'static,
184{
185 pub(crate) source: S,
186 pub(crate) f: F,
187 pub(crate) _types: PhantomData<fn() -> (K, V, U)>,
188}
189
190impl<S, K, V, U, F> FilterMapValuesPlan<S, K, V, U, F>
191where
192 S: MapQuery<Key = K, Value = V>,
193 K: Hash + Eq + CellValue,
194 V: CellValue,
195 U: CellValue,
196 F: Fn(&K, &V) -> Option<U> + Send + Sync + 'static,
197{
198 pub fn map_values<W, G>(
200 self,
201 g: G,
202 ) -> FilterMapValuesPlan<S, K, V, W, impl Fn(&K, &V) -> Option<W> + Send + Sync + 'static>
203 where
204 W: CellValue,
205 G: Fn(&K, &U) -> W + Send + Sync + 'static,
206 {
207 let f = self.f;
208 FilterMapValuesPlan {
209 source: self.source,
210 f: move |key, value| f(key, value).map(|value| g(key, &value)),
211 _types: PhantomData,
212 }
213 }
214
215 pub fn filter_map_values<W, G>(
217 self,
218 g: G,
219 ) -> FilterMapValuesPlan<S, K, V, W, impl Fn(&K, &V) -> Option<W> + Send + Sync + 'static>
220 where
221 W: CellValue,
222 G: Fn(&K, &U) -> Option<W> + Send + Sync + 'static,
223 {
224 let f = self.f;
225 FilterMapValuesPlan {
226 source: self.source,
227 f: move |key, value| f(key, value).and_then(|value| g(key, &value)),
228 _types: PhantomData,
229 }
230 }
231
232 pub fn select<G>(
234 self,
235 predicate: G,
236 ) -> FilterMapValuesPlan<S, K, V, U, impl Fn(&K, &V) -> Option<U> + Send + Sync + 'static>
237 where
238 G: Fn(&U) -> bool + Send + Sync + 'static,
239 {
240 let f = self.f;
241 FilterMapValuesPlan {
242 source: self.source,
243 f: move |key, value| f(key, value).filter(|value| predicate(value)),
244 _types: PhantomData,
245 }
246 }
247
248 pub fn select_by<G>(
250 self,
251 predicate: G,
252 ) -> FilterMapValuesPlan<S, K, V, U, impl Fn(&K, &V) -> Option<U> + Send + Sync + 'static>
253 where
254 G: Fn(&K, &U) -> bool + Send + Sync + 'static,
255 {
256 let f = self.f;
257 FilterMapValuesPlan {
258 source: self.source,
259 f: move |key, value| f(key, value).filter(|value| predicate(key, value)),
260 _types: PhantomData,
261 }
262 }
263}
264
265impl<S, K, V, U, F> BuildQueryRuntime<K, U> for FilterMapValuesPlan<S, K, V, U, F>
266where
267 S: MapQuery<Key = K, Value = V>,
268 K: Hash + Eq + CellValue,
269 V: CellValue,
270 U: CellValue,
271 F: Fn(&K, &V) -> Option<U> + Send + Sync + 'static,
272{
273 fn build_into(
274 self,
275 cx: &mut crate::map_query::compiler::CompileContext,
276 sink: crate::map_query::BoxedMapDiffSink<K, U>,
277 ) -> Vec<SubscriptionGuard> {
278 install_filter_map_values_runtime(cx, self.source, self.f, sink)
279 }
280}
281
282#[allow(private_bounds)]
283impl<S, K, V, U, F> MapQuery for FilterMapValuesPlan<S, K, V, U, F>
284where
285 S: MapQuery<Key = K, Value = V>,
286 K: Hash + Eq + CellValue,
287 V: CellValue,
288 U: CellValue,
289 F: Fn(&K, &V) -> Option<U> + Send + Sync + 'static,
290{
291 type Key = K;
292 type Value = U;
293}
294
295pub trait MapValuesExt<K, V>: MapQuery<Key = K, Value = V>
301where
302 K: Hash + Eq + CellValue,
303 V: CellValue,
304{
305 fn map_values<U, F>(self, f: F) -> MapValuesPlan<Self, K, V, U, F>
307 where
308 U: CellValue,
309 F: Fn(&K, &V) -> U + Send + Sync + 'static,
310 {
311 MapValuesPlan {
312 source: self,
313 f,
314 _types: PhantomData,
315 }
316 }
317
318 fn filter_map_values<U, F>(self, f: F) -> FilterMapValuesPlan<Self, K, V, U, F>
320 where
321 U: CellValue,
322 F: Fn(&K, &V) -> Option<U> + Send + Sync + 'static,
323 {
324 FilterMapValuesPlan {
325 source: self,
326 f,
327 _types: PhantomData,
328 }
329 }
330}
331
332impl<K, V, M> MapValuesExt<K, V> for M
333where
334 K: Hash + Eq + CellValue,
335 V: CellValue,
336 M: MapQuery<Key = K, Value = V>,
337{
338}
339
340#[cfg(test)]
341mod tests {
342 use super::*;
343 use crate::CellMap;
344
345 #[test]
346 fn key_preserving_projections_track_membership_and_values() {
347 let source = CellMap::<u64, u64>::new();
348 source.insert(1, 5);
349 source.insert(2, 10);
350
351 let output = source
352 .clone()
353 .filter_map_values(|_key, value| (*value >= 10).then_some(value * 2))
354 .map_values(|_key, value| value + 1)
355 .materialize();
356
357 assert_eq!(output.get_value(&1), None);
358 assert_eq!(output.get_value(&2), Some(21));
359
360 source.insert(1, 12);
361 source.insert(2, 3);
362 assert_eq!(output.get_value(&1), Some(25));
363 assert_eq!(output.get_value(&2), None);
364 }
365}