Armin Friedl
7a45982064
Filling the narrow map in parallel caused invalid indices. Also narrow map can be simplified to a Vec since it anyways only maps continous selection indices starting at 0 to entry indices.
114 lines
3 KiB
Rust
114 lines
3 KiB
Rust
use std::{collections::HashMap, sync::{Arc, Mutex, atomic::{AtomicUsize, Ordering}}, usize};
|
|
|
|
use log::debug;
|
|
use rayon::{iter::{IndexedParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelIterator}, slice::ParallelSliceMut};
|
|
|
|
use super::matcher::PrefixMatcher;
|
|
|
|
pub type SourceRef = Box<dyn Source>;
|
|
pub type MatcherRef = Box<dyn Matcher>;
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct Entry {
|
|
pub source: &'static str,
|
|
pub name: String,
|
|
pub description: String,
|
|
pub identifier: u64,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum Action {
|
|
Primary,
|
|
}
|
|
|
|
pub trait Source: Send + Sync {
|
|
fn name(&self) -> &'static str;
|
|
fn entries(&mut self) -> Vec<Entry>;
|
|
fn action(&self, entry: &Entry, action: Action);
|
|
}
|
|
|
|
pub trait Matcher: Send + Sync {
|
|
fn try_match(&self, haystack: &str, needle: &str) -> Option<(f64, Vec<usize>)>;
|
|
}
|
|
|
|
pub struct Roftl {
|
|
sources: Vec<SourceRef>,
|
|
matcher: MatcherRef,
|
|
entries: Vec<Entry>,
|
|
narrow_map: Vec<usize>
|
|
}
|
|
|
|
impl Roftl {
|
|
pub fn new() -> Self {
|
|
Roftl {
|
|
sources: vec![],
|
|
matcher: PrefixMatcher::new(),
|
|
entries: vec![],
|
|
narrow_map: vec![]
|
|
}
|
|
}
|
|
|
|
pub fn add_source(mut self, source: SourceRef) -> Self {
|
|
if self.sources.par_iter().any(|s| s.name().eq(source.name())) {
|
|
panic! {"Source with name '{}' already exists", source.name()}
|
|
}
|
|
|
|
self.sources.push(source);
|
|
self
|
|
}
|
|
|
|
pub fn with_matcher(mut self, matcher: MatcherRef) -> Self {
|
|
self.matcher = matcher;
|
|
self
|
|
}
|
|
|
|
pub fn source(&mut self) {
|
|
self.entries = self
|
|
.sources
|
|
.par_iter_mut()
|
|
.flat_map(|s| s.entries())
|
|
.collect();
|
|
|
|
debug!("Entries {:?}", self.entries);
|
|
}
|
|
|
|
pub fn narrow(&mut self, input: &str) -> Vec<(&Entry, Vec<usize>)> {
|
|
let mut scored_entries: Vec<(f64, usize, &Entry, Vec<usize>)> = self.entries
|
|
.par_iter()
|
|
.enumerate()
|
|
.filter_map(|(idx, entry)| {
|
|
if input.is_empty() { return Some((0.0, idx, entry, vec![])) }
|
|
|
|
let match_result = self.matcher.try_match(&entry.name, input);
|
|
return match_result.map(|(score, indices)| (score, idx, entry, indices) )
|
|
})
|
|
.collect();
|
|
|
|
scored_entries
|
|
.par_sort_by(|e1, e2| e1.0.partial_cmp(&e2.0).unwrap());
|
|
|
|
self.narrow_map.clear();
|
|
for se in &scored_entries {
|
|
self.narrow_map.push(se.1)
|
|
}
|
|
|
|
scored_entries
|
|
.par_iter()
|
|
.map(|se| (se.2, se.3.clone()))
|
|
.collect()
|
|
}
|
|
|
|
pub fn action(&self, selection_id: usize, action: Action) {
|
|
let entry_id = self.narrow_map[selection_id];
|
|
let entry = &self.entries[entry_id];
|
|
debug!{"Got entry {:?} for id {} ", entry, entry_id};
|
|
|
|
let source = self
|
|
.sources
|
|
.iter()
|
|
.find(|&s| s.name().eq(entry.source))
|
|
.unwrap();
|
|
|
|
source.action(&entry, action);
|
|
}
|
|
}
|