roftl/src/roftl.rs

118 lines
3.2 KiB
Rust
Raw Normal View History

use std::{collections::HashMap, sync::{Arc, Mutex, atomic::{AtomicUsize, Ordering}}, usize};
2021-10-17 11:46:56 +00:00
use log::debug;
use rayon::{iter::{IndexedParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelIterator}, slice::ParallelSliceMut};
2021-10-03 21:07:19 +00:00
use super::matcher::PrefixMatcher;
pub type SourceRef = Box<dyn Source>;
pub type MatcherRef = Box<dyn Matcher>;
2021-10-03 21:07:19 +00:00
#[derive(Clone, Debug)]
2021-09-12 14:33:52 +00:00
pub struct Entry {
2021-10-03 21:07:19 +00:00
pub source: &'static str,
2021-09-12 14:33:52 +00:00
pub name: String,
pub description: String,
2021-10-03 21:07:19 +00:00
pub identifier: u64,
2021-09-12 14:33:52 +00:00
}
#[derive(Debug)]
pub enum Action {
Primary,
}
pub trait Source: Send + Sync {
2021-10-03 21:07:19 +00:00
fn name(&self) -> &'static str;
fn entries(&mut self) -> Vec<Entry>;
2021-09-12 14:33:52 +00:00
fn action(&self, entry: &Entry, action: Action);
}
pub trait Matcher: Send + Sync {
fn try_match(&self, haystack: &str, needle: &str) -> Option<(f64, Vec<usize>)>;
}
2021-09-12 14:33:52 +00:00
pub struct Roftl {
sources: Vec<SourceRef>,
matcher: MatcherRef,
2021-09-12 14:33:52 +00:00
entries: Vec<Entry>,
2021-10-03 21:07:19 +00:00
narrow_map: Mutex<HashMap<usize, usize>>
2021-09-12 14:33:52 +00:00
}
impl Roftl {
pub fn new() -> Self {
Roftl {
sources: vec![],
matcher: PrefixMatcher::new(),
entries: vec![],
narrow_map: Mutex::default()
}
}
pub fn add_source(mut self, source: SourceRef) -> Self {
2021-10-03 21:07:19 +00:00
if self.sources.par_iter().any(|s| s.name().eq(source.name())) {
panic! {"Source with name '{}' already exists", source.name()}
2021-09-12 14:33:52 +00:00
}
self.sources.push(source);
self
}
pub fn with_matcher(mut self, matcher: MatcherRef) -> Self {
self.matcher = matcher;
self
}
pub fn source(&mut self) {
2021-09-12 14:33:52 +00:00
self.entries = self
.sources
2021-10-03 21:07:19 +00:00
.par_iter_mut()
.flat_map(|s| s.entries())
2021-09-12 14:33:52 +00:00
.collect();
2021-10-03 21:07:19 +00:00
debug!("Entries {:?}", self.entries);
2021-09-12 14:33:52 +00:00
}
pub fn narrow(&self, input: &str) -> Vec<(&Entry, Vec<usize>)> {
let count = Arc::new(AtomicUsize::new(0));
2021-10-03 21:07:19 +00:00
self.narrow_map.lock().unwrap().clear();
2021-10-17 11:46:56 +00:00
let mut scored_entries: Vec<(f64, usize, &Entry, Vec<usize>)> = self.entries
2021-10-03 21:07:19 +00:00
.par_iter()
.enumerate()
2021-10-17 11:46:56 +00:00
.filter_map(|(idx, entry)| {
let match_result = self.matcher.try_match(&entry.name, input);
return match_result.map(|(score, indices)| (score, idx, entry, indices) )
2021-10-03 21:07:19 +00:00
})
2021-10-17 11:46:56 +00:00
.collect();
scored_entries
.par_sort_by(|e1, e2| e1.0.partial_cmp(&e2.0).unwrap());
scored_entries
.par_iter()
.for_each(|se| {
self.narrow_map.lock().unwrap().insert(count.fetch_add(1, Ordering::Relaxed), se.1);
});
scored_entries
.par_iter()
.map(|se| (se.2, se.3.clone()))
2021-09-12 14:33:52 +00:00
.collect()
}
2021-10-17 17:23:50 +00:00
pub fn action(&self, entry_id: usize, action: Action) {
debug!{"NarrowMap {:?}", self.narrow_map.lock().unwrap()};
2021-10-03 21:07:19 +00:00
2021-10-17 17:23:50 +00:00
let real_id = *self.narrow_map.lock().unwrap().get(&entry_id).unwrap();
2021-10-03 21:07:19 +00:00
let entry = self.entries.get(real_id).unwrap();
let source = self
.sources
.iter()
.find(|&s| s.name().eq(entry.source))
.unwrap();
source.action(entry, action);
2021-09-12 14:33:52 +00:00
}
}