matrix_sdk_ui/room_list_service/sorters/
lexicographic.rs

1// Copyright 2024 The Matrix.org Foundation C.I.C.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::cmp::Ordering;
16
17use super::{BoxedSorterFn, Sorter};
18
19/// Create a new sorter that will run multiple sorters. When the nth sorter
20/// returns [`Ordering::Equal`], the next sorter is called. It stops at soon as
21/// a sorter return [`Ordering::Greater`] or [`Ordering::Less`].
22///
23/// This is an implementation of a lexicographic order as defined for cartesian
24/// products ([learn more](https://en.wikipedia.org/wiki/Lexicographic_order#Cartesian_products)).
25pub fn new_sorter(sorters: Vec<BoxedSorterFn>) -> impl Sorter {
26    move |left, right| -> Ordering {
27        for sorter in &sorters {
28            match sorter(left, right) {
29                result @ Ordering::Greater | result @ Ordering::Less => return result,
30                Ordering::Equal => continue,
31            }
32        }
33
34        Ordering::Equal
35    }
36}
37
38#[cfg(test)]
39mod tests {
40    use matrix_sdk::test_utils::logged_in_client_with_server;
41    use matrix_sdk_test::async_test;
42    use ruma::room_id;
43
44    use super::{super::super::filters::new_rooms, *};
45
46    #[async_test]
47    async fn test_with_zero_sorter() {
48        let (client, server) = logged_in_client_with_server().await;
49        let [room_a, room_b] =
50            new_rooms([room_id!("!a:b.c"), room_id!("!d:e.f")], &client, &server).await;
51
52        let or = new_sorter(vec![]);
53
54        assert_eq!(or(&room_a, &room_b), Ordering::Equal);
55    }
56
57    #[async_test]
58    async fn test_with_one_sorter() {
59        let (client, server) = logged_in_client_with_server().await;
60        let [room_a, room_b] =
61            new_rooms([room_id!("!a:b.c"), room_id!("!d:e.f")], &client, &server).await;
62
63        let sorter_1 = |_: &_, _: &_| Ordering::Less;
64        let or = new_sorter(vec![Box::new(sorter_1)]);
65
66        assert_eq!(or(&room_a, &room_b), Ordering::Less);
67    }
68
69    #[async_test]
70    async fn test_with_two_sorters() {
71        let (client, server) = logged_in_client_with_server().await;
72        let [room_a, room_b] =
73            new_rooms([room_id!("!a:b.c"), room_id!("!d:e.f")], &client, &server).await;
74
75        let sorter_1 = |_: &_, _: &_| Ordering::Equal;
76        let sorter_2 = |_: &_, _: &_| Ordering::Greater;
77        let or = new_sorter(vec![Box::new(sorter_1), Box::new(sorter_2)]);
78
79        assert_eq!(or(&room_a, &room_b), Ordering::Greater);
80    }
81
82    #[async_test]
83    async fn test_with_more_sorters() {
84        let (client, server) = logged_in_client_with_server().await;
85        let [room_a, room_b] =
86            new_rooms([room_id!("!a:b.c"), room_id!("!d:e.f")], &client, &server).await;
87
88        let sorter_1 = |_: &_, _: &_| Ordering::Equal;
89        let sorter_2 = |_: &_, _: &_| Ordering::Equal;
90        let sorter_3 = |_: &_, _: &_| Ordering::Less;
91        let sorter_4 = |_: &_, _: &_| Ordering::Greater;
92        let or = new_sorter(vec![
93            Box::new(sorter_1),
94            Box::new(sorter_2),
95            Box::new(sorter_3),
96            Box::new(sorter_4),
97        ]);
98
99        assert_eq!(or(&room_a, &room_b), Ordering::Less);
100    }
101}