stc/src/searchers/mod.rs

76 lines
2.1 KiB
Rust
Raw Normal View History

2017-02-26 16:55:17 -06:00
pub mod mtg;
pub mod yugioh;
use Link;
use std::any::Any;
use std::collections::BTreeMap;
pub trait Searcher<T: Link> {
fn fuzzy_search (&self, name: &str) -> Option<T> {
self.exact_search(name)
}
fn exact_search (&self, name: &str) -> Option<T>;
}
type SearchFn = Box<Fn(String, bool) -> Option<Box<Link>>>;
pub struct AggregateSearcher {
searchers: BTreeMap<String, SearchFn>
}
impl AggregateSearcher {
pub fn new () -> AggregateSearcher {
AggregateSearcher {
searchers: BTreeMap::new()
}
}
pub fn add_searcher<T: Link + 'static> (&mut self, prefix: &str, searcher: Box<Searcher<T>>) {
let searcher_closure = move |name: String, fuzzy: bool| {
(if fuzzy {
searcher.fuzzy_search(&name[..])
} else {
searcher.exact_search(&name[..])
}).map(|value| Box::new(value) as Box<Link>)
};
self.searchers.insert(String::from(prefix), Box::new(searcher_closure));
}
fn run_all_searchers (&self, name: &str) -> Option<Box<Link>> {
for (_, searcher) in &self.searchers {
let possible_value = searcher(String::from(name), false);
if possible_value.is_some() {
return possible_value;
}
}
None
}
}
impl Searcher<Box<Link>> for AggregateSearcher {
fn exact_search (&self, full_name: &str) -> Option<Box<Link>> {
match split_prefix(full_name, ":") {
Some((prefix, name)) => {
self.searchers.get(prefix).and_then(|searcher| searcher(String::from(name), true))
.or_else(|| self.run_all_searchers(full_name))
},
None => {
self.run_all_searchers(full_name)
}
}
}
}
pub fn split_prefix<'a> (input: &'a str, separator: &str) -> Option<(&'a str, &'a str)> {
if input.contains(separator) {
match input.split(separator).into_iter().next() {
Some(prefix) => { Some((prefix, input[prefix.len() + separator.len() ..].trim())) },
None => None
}
} else {
None
}
}