Skip to main content

solverforge_scoring/stream/joiner/
comparison.rs

1// Comparison joiners for less than / greater than matching.
2
3use std::marker::PhantomData;
4
5use super::Joiner;
6
7/* Creates a joiner that matches when `left(a) < right(b)`.
8
9# Example
10
11```
12use solverforge_scoring::stream::joiner::{Joiner, less_than};
13
14#[derive(Clone)]
15struct Task { end: i64, start: i64 }
16
17// Task A must end before Task B starts
18let sequential = less_than(|t: &Task| t.end, |t: &Task| t.start);
19
20assert!(sequential.matches(
21&Task { end: 10, start: 0 },
22&Task { end: 20, start: 15 }
23));
24
25assert!(!sequential.matches(
26&Task { end: 10, start: 0 },
27&Task { end: 20, start: 5 }
28));
29```
30*/
31pub fn less_than<T, Fa, Fb>(left: Fa, right: Fb) -> LessThanJoiner<Fa, Fb, T>
32where
33    T: Ord,
34    Fa: Send + Sync,
35    Fb: Send + Sync,
36{
37    LessThanJoiner {
38        left,
39        right,
40        _phantom: PhantomData,
41    }
42}
43
44/* Creates a joiner matching when the left row's key is less than the right's.
45
46Row-aware form of [`less_than`]: the left closure receives the whole
47borrowed left row, so a later comparison can inspect any earlier
48binding. Extractors stay accessible for ordered index planning.
49*/
50pub fn less_than_on<T, LK, KC>(left: LK, right: KC) -> LessThanJoiner<LK, KC, T>
51where
52    T: Ord,
53    LK: Send + Sync,
54    KC: Send + Sync,
55{
56    LessThanJoiner {
57        left,
58        right,
59        _phantom: PhantomData,
60    }
61}
62
63// A joiner that matches when `left(a) < right(b)`.
64pub struct LessThanJoiner<Fa, Fb, T> {
65    pub(super) left: Fa,
66    pub(super) right: Fb,
67    _phantom: PhantomData<fn() -> T>,
68}
69
70impl<Fa, Fb, T> LessThanJoiner<Fa, Fb, T> {
71    /// Compose without prematurely binding a borrowed row lifetime.
72    pub fn and<J>(self, other: J) -> super::AndJoiner<Self, J> {
73        super::AndJoiner {
74            first: self,
75            second: other,
76        }
77    }
78    /* Consumes the joiner and returns the key extractors for index planning. */
79    #[inline]
80    pub fn into_keys(self) -> (Fa, Fb) {
81        (self.left, self.right)
82    }
83}
84
85impl<A, B, T, Fa, Fb> Joiner<A, B> for LessThanJoiner<Fa, Fb, T>
86where
87    T: Ord,
88    Fa: Fn(&A) -> T + Send + Sync,
89    Fb: Fn(&B) -> T + Send + Sync,
90{
91    #[inline]
92    fn matches(&self, a: &A, b: &B) -> bool {
93        (self.left)(a) < (self.right)(b)
94    }
95}
96
97/* Creates a joiner that matches when `left(a) <= right(b)`.
98
99# Example
100
101```
102use solverforge_scoring::stream::joiner::{Joiner, less_than_or_equal};
103
104let joiner = less_than_or_equal(|x: &i32| *x, |y: &i32| *y);
105
106assert!(joiner.matches(&5, &10));
107assert!(joiner.matches(&5, &5));
108assert!(!joiner.matches(&10, &5));
109```
110*/
111pub fn less_than_or_equal<T, Fa, Fb>(left: Fa, right: Fb) -> LessThanOrEqualJoiner<Fa, Fb, T>
112where
113    T: Ord,
114    Fa: Send + Sync,
115    Fb: Send + Sync,
116{
117    LessThanOrEqualJoiner {
118        left,
119        right,
120        _phantom: PhantomData,
121    }
122}
123
124/* Row-aware form of [`less_than_or_equal`]: strict/inclusive direction
125preserved, left closure over the whole borrowed row. */
126pub fn less_than_or_equal_on<T, LK, KC>(left: LK, right: KC) -> LessThanOrEqualJoiner<LK, KC, T>
127where
128    T: Ord,
129    LK: Send + Sync,
130    KC: Send + Sync,
131{
132    LessThanOrEqualJoiner {
133        left,
134        right,
135        _phantom: PhantomData,
136    }
137}
138
139// A joiner that matches when `left(a) <= right(b)`.
140pub struct LessThanOrEqualJoiner<Fa, Fb, T> {
141    pub(super) left: Fa,
142    pub(super) right: Fb,
143    _phantom: PhantomData<fn() -> T>,
144}
145
146impl<Fa, Fb, T> LessThanOrEqualJoiner<Fa, Fb, T> {
147    /// Compose without prematurely binding a borrowed row lifetime.
148    pub fn and<J>(self, other: J) -> super::AndJoiner<Self, J> {
149        super::AndJoiner {
150            first: self,
151            second: other,
152        }
153    }
154    /* Consumes the joiner and returns the key extractors for index planning. */
155    #[inline]
156    pub fn into_keys(self) -> (Fa, Fb) {
157        (self.left, self.right)
158    }
159}
160
161impl<A, B, T, Fa, Fb> Joiner<A, B> for LessThanOrEqualJoiner<Fa, Fb, T>
162where
163    T: Ord,
164    Fa: Fn(&A) -> T + Send + Sync,
165    Fb: Fn(&B) -> T + Send + Sync,
166{
167    #[inline]
168    fn matches(&self, a: &A, b: &B) -> bool {
169        (self.left)(a) <= (self.right)(b)
170    }
171}
172
173/* Creates a joiner that matches when `left(a) > right(b)`.
174
175# Example
176
177```
178use solverforge_scoring::stream::joiner::{Joiner, greater_than};
179
180let joiner = greater_than(|x: &i32| *x, |y: &i32| *y);
181
182assert!(joiner.matches(&10, &5));
183assert!(!joiner.matches(&5, &10));
184assert!(!joiner.matches(&5, &5));
185```
186*/
187pub fn greater_than<T, Fa, Fb>(left: Fa, right: Fb) -> GreaterThanJoiner<Fa, Fb, T>
188where
189    T: Ord,
190    Fa: Send + Sync,
191    Fb: Send + Sync,
192{
193    GreaterThanJoiner {
194        left,
195        right,
196        _phantom: PhantomData,
197    }
198}
199
200/* Row-aware form of [`greater_than`]: direction preserved, left closure
201over the whole borrowed row. */
202pub fn greater_than_on<T, LK, KC>(left: LK, right: KC) -> GreaterThanJoiner<LK, KC, T>
203where
204    T: Ord,
205    LK: Send + Sync,
206    KC: Send + Sync,
207{
208    GreaterThanJoiner {
209        left,
210        right,
211        _phantom: PhantomData,
212    }
213}
214
215// A joiner that matches when `left(a) > right(b)`.
216pub struct GreaterThanJoiner<Fa, Fb, T> {
217    pub(super) left: Fa,
218    pub(super) right: Fb,
219    _phantom: PhantomData<fn() -> T>,
220}
221
222impl<Fa, Fb, T> GreaterThanJoiner<Fa, Fb, T> {
223    /// Compose without prematurely binding a borrowed row lifetime.
224    pub fn and<J>(self, other: J) -> super::AndJoiner<Self, J> {
225        super::AndJoiner {
226            first: self,
227            second: other,
228        }
229    }
230    /* Consumes the joiner and returns the key extractors for index planning. */
231    #[inline]
232    pub fn into_keys(self) -> (Fa, Fb) {
233        (self.left, self.right)
234    }
235}
236
237impl<A, B, T, Fa, Fb> Joiner<A, B> for GreaterThanJoiner<Fa, Fb, T>
238where
239    T: Ord,
240    Fa: Fn(&A) -> T + Send + Sync,
241    Fb: Fn(&B) -> T + Send + Sync,
242{
243    #[inline]
244    fn matches(&self, a: &A, b: &B) -> bool {
245        (self.left)(a) > (self.right)(b)
246    }
247}
248
249/* Creates a joiner that matches when `left(a) >= right(b)`.
250
251# Example
252
253```
254use solverforge_scoring::stream::joiner::{Joiner, greater_than_or_equal};
255
256let joiner = greater_than_or_equal(|x: &i32| *x, |y: &i32| *y);
257
258assert!(joiner.matches(&10, &5));
259assert!(joiner.matches(&5, &5));
260assert!(!joiner.matches(&5, &10));
261```
262*/
263pub fn greater_than_or_equal<T, Fa, Fb>(left: Fa, right: Fb) -> GreaterThanOrEqualJoiner<Fa, Fb, T>
264where
265    T: Ord,
266    Fa: Send + Sync,
267    Fb: Send + Sync,
268{
269    GreaterThanOrEqualJoiner {
270        left,
271        right,
272        _phantom: PhantomData,
273    }
274}
275
276/* Row-aware form of [`greater_than_or_equal`]: direction preserved, left
277closure over the whole borrowed row. */
278pub fn greater_than_or_equal_on<T, LK, KC>(
279    left: LK,
280    right: KC,
281) -> GreaterThanOrEqualJoiner<LK, KC, T>
282where
283    T: Ord,
284    LK: Send + Sync,
285    KC: Send + Sync,
286{
287    GreaterThanOrEqualJoiner {
288        left,
289        right,
290        _phantom: PhantomData,
291    }
292}
293
294// A joiner that matches when `left(a) >= right(b)`.
295pub struct GreaterThanOrEqualJoiner<Fa, Fb, T> {
296    pub(super) left: Fa,
297    pub(super) right: Fb,
298    _phantom: PhantomData<fn() -> T>,
299}
300
301impl<Fa, Fb, T> GreaterThanOrEqualJoiner<Fa, Fb, T> {
302    /// Compose without prematurely binding a borrowed row lifetime.
303    pub fn and<J>(self, other: J) -> super::AndJoiner<Self, J> {
304        super::AndJoiner {
305            first: self,
306            second: other,
307        }
308    }
309    /* Consumes the joiner and returns the key extractors for index planning. */
310    #[inline]
311    pub fn into_keys(self) -> (Fa, Fb) {
312        (self.left, self.right)
313    }
314}
315
316impl<A, B, T, Fa, Fb> Joiner<A, B> for GreaterThanOrEqualJoiner<Fa, Fb, T>
317where
318    T: Ord,
319    Fa: Fn(&A) -> T + Send + Sync,
320    Fb: Fn(&B) -> T + Send + Sync,
321{
322    #[inline]
323    fn matches(&self, a: &A, b: &B) -> bool {
324        (self.left)(a) >= (self.right)(b)
325    }
326}