#![cfg_attr(all(feature = "nightly", test), feature(test))]
extern crate sliding_windows;
#[cfg(all(feature = "nightly", test))] extern crate test;
pub mod algorithms;
pub(crate) mod util;
pub fn fuzzy_match<'a, T, It>(needle: &str, haystack: It) -> Option<T>
where It: IntoIterator<Item = (&'a str, T)>
{
fuzzy_match_with_algorithms::<T, algorithms::SorensenDice, algorithms::Levenshtein, It>(needle, haystack)
}
pub fn fuzzy_match_with_algorithms<'a, T, FST, SND, It>(
needle: &str,
haystack: It) -> Option<T>
where FST: algorithms::SimilarityAlgorithm,
SND: algorithms::SimilarityAlgorithm,
It: IntoIterator<Item = (&'a str, T)>
{
let mut iter = haystack.into_iter().peekable();
if iter.peek().is_none() {
panic!("No haystack provided!")
}
let mut highest_set: Vec<(&str, T)> = Vec::new();
let mut highest_weight = 0f32;
let mut first_algo = FST::new();
for (name, item) in iter {
let weight = first_algo.get_similarity(needle, name);
if weight == highest_weight {
highest_set.push((name, item))
} else if weight > highest_weight {
highest_weight = weight;
highest_set.clear();
highest_set.push((name, item));
}
}
if highest_set.is_empty() {
return None;
} else if highest_set.len() == 1 {
let (_, item) = highest_set.remove(0);
return Some(item);
}
let mut snd_highest_set: Vec<(&str, T)> = Vec::new();
let mut snd_highest_weight = 0f32;
let mut second_algo = SND::new();
for (name, item) in highest_set.drain(..) {
let weight = second_algo.get_similarity(needle, name);
if weight == snd_highest_weight {
snd_highest_set.push((name, item))
} else if weight > highest_weight {
snd_highest_weight = weight;
snd_highest_set.clear();
snd_highest_set.push((name, item));
}
}
if snd_highest_set.is_empty() || snd_highest_set.len() > 1 {
None
} else {
let (_, item) = snd_highest_set.remove(0);
Some(item)
}
}