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::async_test;
41    use ruma::room_id;
42
43    use super::{
44        super::super::filters::{client_and_server_prelude, new_rooms},
45        *,
46    };
47
48    #[async_test]
49    async fn test_with_zero_sorter() {
50        let (client, server, sliding_sync) = client_and_server_prelude().await;
51        let [room_a, room_b] =
52            new_rooms([room_id!("!a:b.c"), room_id!("!d:e.f")], &client, &server, &sliding_sync)
53                .await;
54
55        let or = new_sorter(vec![]);
56
57        assert_eq!(or(&room_a, &room_b), Ordering::Equal);
58    }
59
60    #[async_test]
61    async fn test_with_one_sorter() {
62        let (client, server, sliding_sync) = client_and_server_prelude().await;
63        let [room_a, room_b] =
64            new_rooms([room_id!("!a:b.c"), room_id!("!d:e.f")], &client, &server, &sliding_sync)
65                .await;
66
67        let sorter_1 = |_: &_, _: &_| Ordering::Less;
68        let or = new_sorter(vec![Box::new(sorter_1)]);
69
70        assert_eq!(or(&room_a, &room_b), Ordering::Less);
71    }
72
73    #[async_test]
74    async fn test_with_two_sorters() {
75        let (client, server, sliding_sync) = client_and_server_prelude().await;
76        let [room_a, room_b] =
77            new_rooms([room_id!("!a:b.c"), room_id!("!d:e.f")], &client, &server, &sliding_sync)
78                .await;
79
80        let sorter_1 = |_: &_, _: &_| Ordering::Equal;
81        let sorter_2 = |_: &_, _: &_| Ordering::Greater;
82        let or = new_sorter(vec![Box::new(sorter_1), Box::new(sorter_2)]);
83
84        assert_eq!(or(&room_a, &room_b), Ordering::Greater);
85    }
86
87    #[async_test]
88    async fn test_with_more_sorters() {
89        let (client, server, sliding_sync) = client_and_server_prelude().await;
90        let [room_a, room_b] =
91            new_rooms([room_id!("!a:b.c"), room_id!("!d:e.f")], &client, &server, &sliding_sync)
92                .await;
93
94        let sorter_1 = |_: &_, _: &_| Ordering::Equal;
95        let sorter_2 = |_: &_, _: &_| Ordering::Equal;
96        let sorter_3 = |_: &_, _: &_| Ordering::Less;
97        let sorter_4 = |_: &_, _: &_| Ordering::Greater;
98        let or = new_sorter(vec![
99            Box::new(sorter_1),
100            Box::new(sorter_2),
101            Box::new(sorter_3),
102            Box::new(sorter_4),
103        ]);
104
105        assert_eq!(or(&room_a, &room_b), Ordering::Less);
106    }
107}