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; pub type MatcherRef = Box; #[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; fn action(&self, entry: &Entry, action: Action); } pub trait Matcher: Send + Sync { fn try_match(&self, haystack: &str, needle: &str) -> Option<(f64, Vec)>; } pub struct Roftl { sources: Vec, matcher: MatcherRef, entries: Vec, narrow_map: Vec } 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)> { let mut scored_entries: Vec<(f64, usize, &Entry, Vec)> = 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); } }