aldrin-parser 0.4.0

Aldrin schema parser library.
Documentation
use crate::ast::Definition;
use crate::Schema;
use std::cmp::Ordering;
use std::collections::HashMap;
use std::hash::Hash;

const BUILTIN_TYPES: &[&str] = &[
    "bool",
    "bytes",
    "i16",
    "i32",
    "i64",
    "i8",
    "object_id",
    "service_id",
    "string",
    "u16",
    "u32",
    "u64",
    "u8",
    "uuid",
    "value",
];

pub fn did_you_mean<'a, I>(candidates: I, value: &str) -> Option<&'a str>
where
    I: IntoIterator<Item = &'a str>,
{
    if let Some((candidate, score)) = candidates
        .into_iter()
        .map(|s| (s, strsim::jaro_winkler(s, value)))
        .max_by(|s1, s2| s1.1.partial_cmp(&s2.1).unwrap_or(Ordering::Equal))
    {
        if score > 0.8 {
            return Some(candidate);
        }
    }

    None
}

pub fn did_you_mean_type<'a>(
    schema: &'a Schema,
    type_name: &str,
    with_builtins: bool,
) -> Option<&'a str> {
    let candidates = schema.definitions().iter().filter_map(|d| match d {
        Definition::Struct(d) => Some(d.name().value()),
        Definition::Enum(d) => Some(d.name().value()),
        Definition::Service(_) | Definition::Const(_) => None,
    });

    if with_builtins {
        did_you_mean(candidates.chain(BUILTIN_TYPES.iter().copied()), type_name)
    } else {
        did_you_mean(candidates, type_name)
    }
}

pub fn find_duplicates<I, KFN, K, DFN>(iter: I, mut key_fn: KFN, mut dup_fn: DFN)
where
    I: IntoIterator,
    KFN: FnMut(&I::Item) -> K,
    K: Hash + Eq,
    DFN: FnMut(I::Item, &I::Item),
{
    let mut candidates: HashMap<_, Vec<_>> = HashMap::new();

    for elem in iter {
        candidates.entry(key_fn(&elem)).or_default().push(elem);
    }

    for (_, candidates) in candidates {
        if candidates.len() <= 1 {
            continue;
        }

        let mut duplicates = candidates.into_iter();
        let first = duplicates.next().unwrap();
        for duplicate in duplicates {
            dup_fn(duplicate, &first);
        }
    }
}