use strsim;
use super::{DistFn, KnownDist};
use std::cmp;
const JARO_SCALE_FACTOR: f64 = 100.;
#[derive(Copy, Clone)]
pub struct Hamming;
#[derive(Copy, Clone)]
pub struct Levenshtein;
#[derive(Copy, Clone)]
pub struct DamerauLevenshtein;
#[derive(Copy, Clone)]
pub struct Jaro;
#[derive(Copy, Clone)]
pub struct JaroWinkler;
macro_rules! impl_dist_fn {
($($ty:ty = $distfn:path),*) => (
$(
impl<'a> DistFn<&'a str> for $ty {
fn dist(&self, left: &&'a str, right: &&'a str) -> u64 {
$distfn(left, right) as u64
}
}
impl DistFn<String> for $ty {
fn dist(&self, left: &String, right: &String) -> u64 {
$distfn(left, right) as u64
}
}
)*
)
}
impl_dist_fn! {
Hamming = hamming_dist,
Levenshtein = strsim::levenshtein,
DamerauLevenshtein = strsim::damerau_levenshtein,
Jaro = jaro_factor,
JaroWinkler = jaro_winkler_factor
}
impl<'a> KnownDist for &'a str {
type DistFn = Hamming;
fn dist_fn() -> Hamming {
Hamming
}
}
impl KnownDist for String {
type DistFn = Hamming;
fn dist_fn() -> Hamming {
Hamming
}
}
fn hamming_dist(left: &str, right: &str) -> u64 {
let len = cmp::min(left.len(), right.len());
let diff = cmp::max(left.len(), right.len()) - len;
(strsim::hamming(&left[..len], &right[..len]).unwrap() + diff) as u64
}
fn jaro_factor(left: &str, right: &str) -> u64 {
strsim::jaro(left, right).mul_add(JARO_SCALE_FACTOR, -JARO_SCALE_FACTOR).round() as u64
}
fn jaro_winkler_factor(left: &str, right: &str) -> u64 {
strsim::jaro_winkler(left, right).mul_add(JARO_SCALE_FACTOR, -JARO_SCALE_FACTOR).round() as u64
}