1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#[macro_use]
extern crate lazy_static;
extern crate unicode_normalization;

use std::borrow::Borrow;
use unicode_normalization::UnicodeNormalization;

mod fuzz_search;
pub use fuzz_search::fuzzy_search_score;
use fuzz_search::fuzzy_search_score_no_norm;

pub fn best_matches<T>(pattern: &str, items: Vec<T>, n: usize) -> impl Iterator<Item = T>
where
    T: Borrow<str>,
{
    best_matches_scores(pattern, items, n).map(|(name, _)| name).take(n)
}

pub fn best_matches_scores<T>(
    pattern: &str,
    items: Vec<T>,
    n: usize,
) -> impl Iterator<Item = (T, isize)>
where
    T: Borrow<str>,
{
    let pattern = pattern.nfc().collect::<String>();

    let mut items_scores = items
        .into_iter()
        .map(|name| {
            let x = &name.borrow().nfc().collect::<String>();
            (name, fuzzy_search_score_no_norm(&pattern, x))
        })
        .collect::<Vec<_>>();

    items_scores.sort_by_key(|(_, x)| -x);

    items_scores.into_iter().take(n)
}

pub fn best_matches_scores_key<T, F, K>(
    pattern: &str,
    items: Vec<T>,
    f: F,
    n: usize,
) -> impl Iterator<Item = (T, isize)>
where
    F: Fn(&T) -> K,
    K: Borrow<str>,
{
    let pattern = pattern.nfc().collect::<String>();

    let mut items_scores = items
        .into_iter()
        .map(|name| {
            let x = &f(&name).borrow().nfc().collect::<String>();
            (name, fuzzy_search_score_no_norm(&pattern, x))
        })
        .collect::<Vec<_>>();

    items_scores.sort_by_key(|(_, x)| -x);

    items_scores.into_iter().take(n)
}