1use std::hash::Hash;
2use std::marker::PhantomData;
3
4use solverforge_core::score::Score;
5
6use super::collection_extract::{FlattenExtract, TrackedCollectionExtract};
7use super::existence_stream::{DirectExistenceStream, ExistenceMode, ExistsConstraintStream};
8use super::filter::UniFilter;
9use super::joiner::EqualJoiner;
10use super::uni_stream::UniConstraintStream;
11use crate::constraint::exists::SelfFlatten;
12
13pub struct FlattenedCollectionTarget<S, P, B, EP, FP, Flatten, Sc>
14where
15 Sc: Score,
16{
17 pub(crate) right_stream: UniConstraintStream<S, P, EP, FP, Sc>,
18 pub(crate) flatten: Flatten,
19 pub(crate) _phantom: PhantomData<(fn() -> B, fn() -> Sc)>,
20}
21
22pub trait ExistenceTarget<S, A, EA, FA, Sc: Score>
23where
24 EA: TrackedCollectionExtract<S, Item = A>,
25 FA: UniFilter<S, A>,
26{
27 type Output;
28
29 fn apply(self, mode: ExistenceMode, extractor_a: EA, filter_a: FA) -> Self::Output;
30}
31
32impl<S, A, B, EA, FA, EP, FP, K, KA, KB, Sc> ExistenceTarget<S, A, EA, FA, Sc>
33 for (
34 UniConstraintStream<S, B, EP, FP, Sc>,
35 EqualJoiner<KA, KB, K>,
36 )
37where
38 S: Send + Sync + 'static,
39 A: Clone + Send + Sync + 'static,
40 B: Clone + Send + Sync + 'static,
41 EA: TrackedCollectionExtract<S, Item = A>,
42 FA: UniFilter<S, A>,
43 EP: TrackedCollectionExtract<S, Item = B>,
44 FP: UniFilter<S, B>,
45 K: Eq + Hash + Clone + Send + Sync,
46 KA: Fn(&A) -> K + Send + Sync,
47 KB: Fn(&B) -> K + Send + Sync,
48 Sc: Score + 'static,
49{
50 type Output = DirectExistenceStream<S, A, B, K, EA, EP, KA, KB, FA, FP, Sc>;
51
52 fn apply(self, mode: ExistenceMode, extractor_a: EA, filter_a: FA) -> Self::Output {
53 let (right_stream, joiner) = self;
54 let (extractor_parent, filter_parent) = right_stream.into_parts();
55 let (key_a, key_b) = joiner.into_keys();
56 ExistsConstraintStream::new(
57 mode,
58 extractor_a,
59 extractor_parent,
60 (key_a, key_b),
61 filter_a,
62 filter_parent,
63 SelfFlatten,
64 )
65 }
66}
67
68impl<S, A, P, B, EA, FA, EP, FP, K, KA, KB, Flatten, Sc> ExistenceTarget<S, A, EA, FA, Sc>
69 for (
70 FlattenedCollectionTarget<S, P, B, EP, FP, Flatten, Sc>,
71 EqualJoiner<KA, KB, K>,
72 )
73where
74 S: Send + Sync + 'static,
75 A: Clone + Send + Sync + 'static,
76 P: Clone + Send + Sync + 'static,
77 B: Clone + Send + Sync + 'static,
78 EA: TrackedCollectionExtract<S, Item = A>,
79 FA: UniFilter<S, A>,
80 EP: TrackedCollectionExtract<S, Item = P>,
81 FP: UniFilter<S, P>,
82 K: Eq + Hash + Clone + Send + Sync,
83 KA: Fn(&A) -> K + Send + Sync,
84 KB: Fn(&B) -> K + Send + Sync,
85 Flatten: FlattenExtract<P, Item = B> + Send + Sync,
86 Sc: Score + 'static,
87{
88 type Output = ExistsConstraintStream<S, A, P, B, K, EA, EP, KA, KB, FA, FP, Flatten, Sc>;
89
90 fn apply(self, mode: ExistenceMode, extractor_a: EA, filter_a: FA) -> Self::Output {
91 let (target, joiner) = self;
92 let FlattenedCollectionTarget {
93 right_stream,
94 flatten,
95 ..
96 } = target;
97 let (extractor_parent, filter_parent) = right_stream.into_parts();
98 let (key_a, key_b) = joiner.into_keys();
99 ExistsConstraintStream::new(
100 mode,
101 extractor_a,
102 extractor_parent,
103 (key_a, key_b),
104 filter_a,
105 filter_parent,
106 flatten,
107 )
108 }
109}