Add config caching

This commit is contained in:
Federico Terzi 2019-09-09 17:45:08 +02:00
parent f4fecccd99
commit 97841963b3
3 changed files with 54 additions and 21 deletions

View File

@ -12,6 +12,8 @@ use std::collections::HashSet;
use regex::Regex;
use std::process::exit;
use log::{debug, info, warn, error};
use std::cell::RefCell;
use std::time::SystemTime;
// TODO: add documentation link
const DEFAULT_CONFIG_FILE_CONTENT : &str = include_str!("res/config.yaml");
@ -171,23 +173,27 @@ impl ConfigSet { // TODO: tests
}
}
pub trait ConfigManager {
fn active_config(&self) -> &Configs;
fn default_config(&self) -> &Configs;
fn matches(&self) -> &Vec<Match>;
pub trait ConfigManager<'a> {
fn active_config(&'a self) -> &'a Configs;
fn default_config(&'a self) -> &'a Configs;
fn matches(&'a self) -> &'a Vec<Match>;
}
pub struct RuntimeConfigManager<S: SystemManager> {
pub struct RuntimeConfigManager<'a, S: SystemManager> {
set: ConfigSet,
title_regexps: Vec<Option<Regex>>,
class_regexps: Vec<Option<Regex>>,
exec_regexps: Vec<Option<Regex>>,
system_manager: S
system_manager: S,
// Cache
last_config_update: RefCell<SystemTime>,
last_config: RefCell<Option<&'a Configs>>
}
impl <S: SystemManager> RuntimeConfigManager<S> {
pub fn new(set: ConfigSet, system_manager: S) -> RuntimeConfigManager<S> {
impl <'a, S: SystemManager> RuntimeConfigManager<'a, S> {
pub fn new<'b>(set: ConfigSet, system_manager: S) -> RuntimeConfigManager<'b, S> {
// Compile all the regexps
let title_regexps = set.specific.iter().map(
|config| {
@ -237,18 +243,21 @@ impl <S: SystemManager> RuntimeConfigManager<S> {
}
).collect();
let last_config_update = RefCell::new(SystemTime::now());
let last_config = RefCell::new(None);
RuntimeConfigManager {
set,
title_regexps,
class_regexps,
exec_regexps,
system_manager
system_manager,
last_config_update,
last_config
}
}
}
impl <S: SystemManager> ConfigManager for RuntimeConfigManager<S> {
fn active_config(&self) -> &Configs {
fn calculate_active_config(&'a self) -> &'a Configs {
// TODO: optimize performance by avoiding some of these checks if no Configs use the filters
debug!("Requested config for window:");
@ -308,12 +317,36 @@ impl <S: SystemManager> ConfigManager for RuntimeConfigManager<S> {
debug!("No matches for custom configs, using default settings.");
&self.set.default
}
}
fn default_config(&self) -> &Configs {
impl <'a, S: SystemManager> ConfigManager<'a> for RuntimeConfigManager<'a, S> {
fn active_config(&'a self) -> &'a Configs {
let mut last_config_update = self.last_config_update.borrow_mut();
if let Ok(elapsed) = (*last_config_update).elapsed() {
*last_config_update = SystemTime::now();
if elapsed.as_millis() < 800 { // TODO: make config option
let last_config = self.last_config.borrow();
if let Some(cached_config) = *last_config {
debug!("Using cached config");
return cached_config;
}
}
}
let config = self.calculate_active_config();
let mut last_config = self.last_config.borrow_mut();
*last_config = Some(config);
config
}
fn default_config(&'a self) -> &'a Configs {
&self.set.default
}
fn matches(&self) -> &Vec<Match> {
fn matches(&'a self) -> &'a Vec<Match> {
&self.active_config().matches
}
}

View File

@ -6,7 +6,7 @@ use crate::clipboard::ClipboardManager;
use log::{info};
use crate::ui::UIManager;
pub struct Engine<'a, S: KeyboardSender, C: ClipboardManager, M: ConfigManager,
pub struct Engine<'a, S: KeyboardSender, C: ClipboardManager, M: ConfigManager<'a>,
U: UIManager> {
sender: S,
clipboard_manager: &'a C,
@ -14,14 +14,14 @@ pub struct Engine<'a, S: KeyboardSender, C: ClipboardManager, M: ConfigManager,
ui_manager: &'a U,
}
impl <'a, S: KeyboardSender, C: ClipboardManager, M: ConfigManager, U: UIManager>
impl <'a, S: KeyboardSender, C: ClipboardManager, M: ConfigManager<'a>, U: UIManager>
Engine<'a, S, C, M, U> {
pub fn new<'b>(sender: S, clipboard_manager: &'b C, config_manager: &'b M, ui_manager: &'b U) -> Engine<'b, S, C, M, U> {
pub fn new(sender: S, clipboard_manager: &'a C, config_manager: &'a M, ui_manager: &'a U) -> Engine<'a, S, C, M, U> {
Engine{sender, clipboard_manager, config_manager, ui_manager }
}
}
impl <'a, S: KeyboardSender, C: ClipboardManager, M: ConfigManager, U: UIManager>
impl <'a, S: KeyboardSender, C: ClipboardManager, M: ConfigManager<'a>, U: UIManager>
MatchReceiver for Engine<'a, S, C, M, U>{
fn on_match(&self, m: &Match) {

View File

@ -6,7 +6,7 @@ use crate::keyboard::KeyModifier::BACKSPACE;
use std::time::SystemTime;
use std::collections::VecDeque;
pub struct ScrollingMatcher<'a, R: MatchReceiver, M: ConfigManager> {
pub struct ScrollingMatcher<'a, R: MatchReceiver, M: ConfigManager<'a>> {
config_manager: &'a M,
receiver: R,
current_set_queue: RefCell<VecDeque<Vec<MatchEntry<'a>>>>,
@ -19,7 +19,7 @@ struct MatchEntry<'a> {
_match: &'a Match
}
impl <'a, R: MatchReceiver, M: ConfigManager> super::Matcher for ScrollingMatcher<'a, R, M> where{
impl <'a, R: MatchReceiver, M: ConfigManager<'a>> super::Matcher for ScrollingMatcher<'a, R, M> where{
fn handle_char(&self, c: char) {
// if not enabled, avoid any processing
if !*(self.is_enabled.borrow()) {
@ -100,7 +100,7 @@ impl <'a, R: MatchReceiver, M: ConfigManager> super::Matcher for ScrollingMatche
}
}
}
impl <'a, R: MatchReceiver, M: ConfigManager> ScrollingMatcher<'a, R, M> {
impl <'a, R: MatchReceiver, M: ConfigManager<'a>> ScrollingMatcher<'a, R, M> {
pub fn new(config_manager: &'a M, receiver: R) -> ScrollingMatcher<'a, R, M> {
let current_set_queue = RefCell::new(VecDeque::new());
let toggle_press_time = RefCell::new(SystemTime::now());