perf: reusing compiled config to save performance and time
This commit is contained in:
@@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
||||
- Better dynamic system which can handle dyn_id issues and reodering.
|
||||
- Added `std::math` module for mathematics related tasks.
|
||||
- Added `propagate_natural_height` property to scroll widget.
|
||||
- Faster re-evaluation of configuration by reusing compiled configuration.
|
||||
|
||||
### Changed
|
||||
|
||||
|
||||
@@ -343,6 +343,7 @@ impl<B: DisplayBackend> App<B> {
|
||||
// listening/polling
|
||||
let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel::<String>();
|
||||
let config_path = self.paths.get_rhai_path();
|
||||
let compiled_ast = self.ewwii_config.get_owned_compiled_ast();
|
||||
let store = iirhai::updates::handle_state_changes(self.ewwii_config.get_root_node()?, tx);
|
||||
|
||||
glib::MainContext::default().spawn_local(async move {
|
||||
@@ -350,7 +351,7 @@ impl<B: DisplayBackend> App<B> {
|
||||
log::debug!("Received update for var: {}", var_name);
|
||||
let vars = store.read().unwrap().clone();
|
||||
|
||||
match generate_new_widgetnode(&vars, &config_path).await {
|
||||
match generate_new_widgetnode(&vars, &config_path, compiled_ast.as_ref()).await {
|
||||
Ok(new_widget) => {
|
||||
let _ = widget_reg_store.update_widget_tree(new_widget);
|
||||
}
|
||||
@@ -559,7 +560,11 @@ fn initialize_window<B: DisplayBackend>(
|
||||
})
|
||||
}
|
||||
|
||||
async fn generate_new_widgetnode(all_vars: &HashMap<String, String>, code_path: &Path) -> Result<WidgetNode> {
|
||||
async fn generate_new_widgetnode(
|
||||
all_vars: &HashMap<String, String>,
|
||||
code_path: &Path,
|
||||
compiled_ast: Option<&rhai::AST>,
|
||||
) -> Result<WidgetNode> {
|
||||
let mut scope = Scope::new();
|
||||
for (name, val) in all_vars {
|
||||
scope.set_value(name.clone(), Dynamic::from(val.clone()));
|
||||
@@ -570,7 +575,8 @@ async fn generate_new_widgetnode(all_vars: &HashMap<String, String>, code_path:
|
||||
}
|
||||
|
||||
let mut reeval_parser = iirhai::parser::ParseConfig::new();
|
||||
let new_root_widget = reeval_parser.eval_file_with(code_path, scope, None);
|
||||
let rhai_code = reeval_parser.code_from_file(&code_path)?;
|
||||
let new_root_widget = reeval_parser.eval_code_with(&rhai_code, Some(scope), compiled_ast);
|
||||
|
||||
Ok(config::EwwiiConfig::get_windows_root_widget(new_root_widget?)?)
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ use crate::{
|
||||
|
||||
use iirhai::{parser::ParseConfig, widgetnode::WidgetNode};
|
||||
|
||||
use rhai::Map;
|
||||
use rhai::{Map, AST};
|
||||
|
||||
// use tokio::{net::UnixStream, runtime::Runtime, sync::mpsc};
|
||||
|
||||
@@ -28,6 +28,7 @@ pub fn read_from_ewwii_paths(eww_paths: &EwwPaths) -> Result<EwwiiConfig> {
|
||||
pub struct EwwiiConfig {
|
||||
windows: HashMap<String, WindowDefinition>,
|
||||
root_node: Option<WidgetNode>,
|
||||
compiled_ast: Option<AST>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -46,9 +47,16 @@ impl EwwiiConfig {
|
||||
bail!("The configuration file `{}` does not exist", rhai_path.display());
|
||||
}
|
||||
|
||||
// get the iirhai widget tree
|
||||
// initialize configuration parser
|
||||
let mut config_parser = ParseConfig::new();
|
||||
let config_tree = config_parser.eval_file(rhai_path)?;
|
||||
|
||||
// get code from file
|
||||
let rhai_code = config_parser.code_from_file(&rhai_path)?;
|
||||
|
||||
// get the iirhai widget tree
|
||||
let compiled_ast = config_parser.compile_code(&rhai_code)?;
|
||||
let poll_listen_scope = ParseConfig::initial_poll_listen_scope(&rhai_code)?;
|
||||
let config_tree = config_parser.eval_code_with(&rhai_code, Some(poll_listen_scope), Some(&compiled_ast))?;
|
||||
|
||||
let mut window_definitions = HashMap::new();
|
||||
|
||||
@@ -68,7 +76,7 @@ impl EwwiiConfig {
|
||||
bail!("Expected root node to be `Enter`, but got something else.");
|
||||
}
|
||||
|
||||
Ok(EwwiiConfig { windows: window_definitions, root_node: Some(config_tree) })
|
||||
Ok(EwwiiConfig { windows: window_definitions, root_node: Some(config_tree), compiled_ast: Some(compiled_ast) })
|
||||
}
|
||||
|
||||
pub fn get_windows(&self) -> &HashMap<String, WindowDefinition> {
|
||||
@@ -101,4 +109,8 @@ impl EwwiiConfig {
|
||||
bail!("Expected root node to be `Enter`, but got something else.");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_owned_compiled_ast(&self) -> Option<AST> {
|
||||
self.compiled_ast.clone()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +146,9 @@ fn reload_config_and_css(ui_send: &UnboundedSender<DaemonCommand>) -> Result<()>
|
||||
ui_send.send(DaemonCommand::ReloadConfigAndCss(daemon_resp_sender))?;
|
||||
tokio::spawn(async move {
|
||||
match daemon_resp_response.recv().await {
|
||||
Some(daemon_response::DaemonResponse::Success(_)) => log::info!("Reloaded config successfully"),
|
||||
Some(daemon_response::DaemonResponse::Success(_)) => {
|
||||
log::info!("Reloaded config successfully")
|
||||
}
|
||||
Some(daemon_response::DaemonResponse::Failure(e)) => eprintln!("{}", e),
|
||||
None => log::error!("No response to reload configuration-reload request"),
|
||||
}
|
||||
|
||||
@@ -48,7 +48,9 @@ impl From<&MonitorIdentifier> for DynVal {
|
||||
impl fmt::Display for MonitorIdentifier {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::List(l) => write!(f, "[{}]", l.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(" ")),
|
||||
Self::List(l) => {
|
||||
write!(f, "[{}]", l.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(" "))
|
||||
}
|
||||
Self::Numeric(n) => write!(f, "{}", n),
|
||||
Self::Name(n) => write!(f, "{}", n),
|
||||
Self::Primary => write!(f, "<primary>"),
|
||||
|
||||
@@ -26,36 +26,22 @@ impl ParseConfig {
|
||||
}
|
||||
|
||||
pub fn eval_code(&mut self, code: &str) -> Result<WidgetNode> {
|
||||
// Setting the initial value of poll/listen
|
||||
let mut scope = Scope::new();
|
||||
for (var, initial) in extract_poll_and_listen_vars(code)? {
|
||||
let value = match initial {
|
||||
Some(val) => Dynamic::from(val),
|
||||
None => Dynamic::UNIT,
|
||||
};
|
||||
scope.set_value(var, value);
|
||||
}
|
||||
|
||||
self.engine
|
||||
.eval_with_scope::<WidgetNode>(&mut scope, code)
|
||||
.map_err(|e| anyhow!(format_rhai_error(&e, code, &self.engine)))
|
||||
}
|
||||
|
||||
pub fn eval_file<P: AsRef<Path>>(&mut self, file_path: P) -> Result<WidgetNode> {
|
||||
let code = fs::read_to_string(&file_path).map_err(|e| anyhow!("Failed to read {:?}: {}", file_path.as_ref(), e))?;
|
||||
self.eval_code(&code)
|
||||
}
|
||||
|
||||
pub fn compile_code(&mut self, code: &str) -> Result<AST> {
|
||||
Ok(self.engine.compile(code)?)
|
||||
}
|
||||
|
||||
pub fn compile_file<P: AsRef<Path>>(&mut self, file_path: P) -> Result<AST> {
|
||||
let code = fs::read_to_string(&file_path).map_err(|e| anyhow!("Failed to read {:?}: {}", file_path.as_ref(), e))?;
|
||||
self.compile_code(&code)
|
||||
}
|
||||
pub fn eval_code_with(&mut self, code: &str, rhai_scope: Option<Scope>, compiled_ast: Option<&AST>) -> Result<WidgetNode> {
|
||||
let mut scope = match rhai_scope {
|
||||
Some(s) => s,
|
||||
None => Scope::new(),
|
||||
};
|
||||
|
||||
pub fn eval_code_with(&mut self, code: &str, mut scope: Scope, compiled_ast: Option<AST>) -> Result<WidgetNode> {
|
||||
match compiled_ast {
|
||||
Some(ast) => self
|
||||
.engine
|
||||
@@ -68,13 +54,21 @@ impl ParseConfig {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eval_file_with<P: AsRef<Path>>(
|
||||
&mut self,
|
||||
file_path: P,
|
||||
scope: Scope,
|
||||
compiled_ast: Option<AST>,
|
||||
) -> Result<WidgetNode> {
|
||||
let code = fs::read_to_string(&file_path).map_err(|e| anyhow!("Failed to read {:?}: {}", file_path.as_ref(), e))?;
|
||||
self.eval_code_with(&code, scope, compiled_ast)
|
||||
pub fn code_from_file<P: AsRef<Path>>(&mut self, file_path: P) -> Result<String> {
|
||||
Ok(fs::read_to_string(&file_path).map_err(|e| anyhow!("Failed to read {:?}: {}", file_path.as_ref(), e))?)
|
||||
}
|
||||
|
||||
pub fn initial_poll_listen_scope(code: &str) -> Result<Scope> {
|
||||
// Setting the initial value of poll/listen
|
||||
let mut scope = Scope::new();
|
||||
for (var, initial) in extract_poll_and_listen_vars(code)? {
|
||||
let value = match initial {
|
||||
Some(val) => Dynamic::from(val),
|
||||
None => Dynamic::UNIT,
|
||||
};
|
||||
scope.set_value(var, value);
|
||||
}
|
||||
|
||||
Ok(scope)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user