subtr_actor/util/search.rs
1use serde::Serialize;
2
3/// Enum to define the direction of searching within a collection.
4#[derive(Debug, Clone, Copy, PartialEq, Serialize)]
5pub enum SearchDirection {
6 Forward,
7 Backward,
8}
9
10/// Searches for an item in a slice in a specified direction and returns the
11/// first item that matches the provided predicate.
12///
13/// # Arguments
14///
15/// * `items` - The list of items to search.
16/// * `current_index` - The index to start the search from.
17/// * `direction` - The direction to search in.
18/// * `predicate` - A function that takes an item and returns an [`Option<R>`].
19/// When this function returns `Some(R)`, the item is considered a match.
20///
21/// # Returns
22///
23/// Returns a tuple of the index and the result `R` of the predicate for the first item that matches.
24pub fn find_in_direction<T, F, R>(
25 items: &[T],
26 current_index: usize,
27 direction: SearchDirection,
28 predicate: F,
29) -> Option<(usize, R)>
30where
31 F: Fn(&T) -> Option<R>,
32{
33 match direction {
34 SearchDirection::Forward => current_index.checked_add(1).and_then(|start| {
35 items
36 .iter()
37 .enumerate()
38 .skip(start)
39 .find_map(|(i, item)| predicate(item).map(|res| (i, res)))
40 }),
41 SearchDirection::Backward => items[..current_index.min(items.len())]
42 .iter()
43 .enumerate()
44 .rev()
45 .find_map(|(i, item)| predicate(item).map(|res| (i, res))),
46 }
47}
48
49#[cfg(test)]
50#[path = "search_tests.rs"]
51mod tests;