From 1f86c72ef6279c0b3ae335dae9ef3c08a2444fe0 Mon Sep 17 00:00:00 2001 From: elkowar <5300871+elkowar@users.noreply.github.com> Date: Tue, 6 Oct 2020 20:06:16 +0200 Subject: [PATCH] VarName newtype, nothing works RN just tmp --- Cargo.lock | 21 +++++++++ Cargo.toml | 2 + src/app.rs | 6 ++- src/config/element.rs | 5 +- src/config/mod.rs | 15 ++++-- src/eww_state.rs | 78 ++++++++++++++++++++----------- src/main.rs | 3 +- src/value.rs | 40 +++++++++++++++- src/widgets/mod.rs | 25 ++++++---- src/widgets/widget_definitions.rs | 2 +- 10 files changed, 148 insertions(+), 49 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index be09764..69ba7fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -319,6 +319,7 @@ dependencies = [ "num", "pretty_assertions", "pretty_env_logger", + "ref-cast", "regex", "roxmltree", "scheduled-executor", @@ -1428,6 +1429,26 @@ version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" +[[package]] +name = "ref-cast" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "745c1787167ddae5569661d5ffb8b25ae5fedbf46717eaa92d652221cec72623" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d21b475ab879ef0e315ad99067fa25778c3b0377f57f1b00207448dac1a3144" +dependencies = [ + "proc-macro2", + "quote 1.0.7", + "syn 1.0.41", +] + [[package]] name = "regex" version = "1.3.9" diff --git a/Cargo.toml b/Cargo.toml index afbe2bc..4a25298 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ gio = { version = "", features = ["v2_44"] } glib = { version = "", features = ["v2_44"] } gdk-pixbuf = "0.9" + regex = "1" try_match = "0.2.2" anyhow = "1.0" @@ -36,6 +37,7 @@ log = "0.4" pretty_env_logger = "0.4" lazy_static = "1.4.0" libc = "0.2" +ref-cast = "1.0" #thiserror = "1.0" diff --git a/src/app.rs b/src/app.rs index 924ff24..efe3f68 100644 --- a/src/app.rs +++ b/src/app.rs @@ -2,11 +2,12 @@ use crate::*; use debug_stub_derive::*; use script_var_handler::*; use std::collections::HashMap; +use value::VarName; #[derive(Debug)] pub enum EwwEvent { UserCommand(Opt), - UpdateVar(String, PrimitiveValue), + UpdateVar(VarName, PrimitiveValue), ReloadConfig(config::EwwConfig), ReloadCss(String), } @@ -33,6 +34,7 @@ impl App { std::process::exit(0) } } + Ok(()) } @@ -51,7 +53,7 @@ impl App { } } - fn update_state(&mut self, fieldname: String, value: PrimitiveValue) { + fn update_state(&mut self, fieldname: VarName, value: PrimitiveValue) { self.eww_state.update_value(fieldname, value); } diff --git a/src/config/element.rs b/src/config/element.rs index 7fd98a6..7020a62 100644 --- a/src/config/element.rs +++ b/src/config/element.rs @@ -4,6 +4,7 @@ use regex::Regex; use std::ops::Range; use crate::value::AttrValue; +use crate::value::VarName; use crate::with_text_pos_context; use maplit::hashmap; use std::collections::HashMap; @@ -140,7 +141,7 @@ impl StringOrVarRef { fn to_attr_value(self) -> AttrValue { match self { StringOrVarRef::String(x) => AttrValue::Concrete(PrimitiveValue::parse_string(&x)), - StringOrVarRef::VarRef(x) => AttrValue::VarRef(x), + StringOrVarRef::VarRef(x) => AttrValue::VarRef(VarName(x)), } } } @@ -214,7 +215,7 @@ mod test { #[test] fn test_text_with_var_refs() { let expected_attr_value1 = mk_attr_str("my text"); - let expected_attr_value2 = AttrValue::VarRef("var".to_owned()); + let expected_attr_value2 = AttrValue::VarRef(VarName("var".to_owned())); let widget = WidgetUse::from_text_with_var_refs("my text{{var}}"); assert_eq!( widget, diff --git a/src/config/mod.rs b/src/config/mod.rs index c8ee0fb..ed14e38 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,5 +1,6 @@ use crate::util; use crate::value::PrimitiveValue; +use crate::value::VarName; use anyhow::*; use element::*; use std::collections::HashMap; @@ -37,7 +38,7 @@ macro_rules! ensure_xml_tag_is { #[derive(Clone, Debug, PartialEq)] pub struct ScriptVar { - pub name: String, + pub name: VarName, pub command: String, pub interval: std::time::Duration, } @@ -46,7 +47,7 @@ impl ScriptVar { pub fn from_xml_element(xml: XmlElement) -> Result { ensure_xml_tag_is!(xml, "script-var"); - let name = xml.attr("name")?.to_owned(); + let name = VarName(xml.attr("name")?.to_owned()); let interval = util::parse_duration(xml.attr("interval")?)?; let command = xml.only_child()?.as_text()?.text(); Ok(ScriptVar { name, interval, command }) @@ -121,13 +122,17 @@ impl EwwConfig { } // TODO this is kinda ugly - pub fn generate_initial_state(&self) -> Result> { + pub fn generate_initial_state(&self) -> Result> { let mut vars = self .script_vars .iter() - .map(|var| Ok((var.name.to_string(), crate::eww_state::run_command(&var.command)?))) + .map(|var| Ok((var.name.clone(), crate::eww_state::run_command(&var.command)?))) .collect::>>()?; - vars.extend(self.get_default_vars().into_iter().map(|(k, v)| (k.clone(), v.clone()))); + vars.extend( + self.get_default_vars() + .into_iter() + .map(|(k, v)| (VarName(k.clone()), v.clone())), + ); Ok(vars) } diff --git a/src/eww_state.rs b/src/eww_state.rs index 2a2c424..71ef02f 100644 --- a/src/eww_state.rs +++ b/src/eww_state.rs @@ -1,15 +1,42 @@ +use crate::value::VarName; use anyhow::*; use std::collections::HashMap; -use std::convert::TryFrom; -use std::convert::TryInto; use std::process::Command; +use std::sync::Arc; use crate::value::{AttrValue, PrimitiveValue}; -#[derive(Default)] +//pub struct StateChangeHandler(Box) + 'static>); + +pub struct StateChangeHandlers { + handlers: HashMap) + 'static>>>, +} + +impl StateChangeHandlers { + fn put_handler(&mut self, var_names: Vec, handler: Arc) + 'static>) { + for var_name in var_names { + let entry: &mut Vec) + 'static>> = + self.handlers.entry(var_name).or_insert_with(Vec::new); + entry.push(handler); + } + } +} + pub struct EwwState { - on_change_handlers: HashMap>>, - state: HashMap, + state_change_handlers: StateChangeHandlers, + //on_change_handlers: HashMap>, + state: HashMap, +} + +impl Default for EwwState { + fn default() -> Self { + EwwState { + state_change_handlers: StateChangeHandlers { + handlers: HashMap::new(), + }, + state: HashMap::new(), + } + } } impl std::fmt::Debug for EwwState { @@ -19,7 +46,7 @@ impl std::fmt::Debug for EwwState { } impl EwwState { - pub fn from_default_vars(defaults: HashMap) -> Self { + pub fn from_default_vars(defaults: HashMap) -> Self { EwwState { state: defaults, ..EwwState::default() @@ -30,7 +57,7 @@ impl EwwState { self.on_change_handlers.clear(); } - pub fn update_value(&mut self, key: String, value: PrimitiveValue) { + pub fn update_value(&mut self, key: VarName, value: PrimitiveValue) { if let Some(handlers) = self.on_change_handlers.get(&key) { for on_change in handlers { on_change(value.clone()); @@ -41,20 +68,20 @@ impl EwwState { pub fn resolve( &mut self, - local_env: &HashMap, + local_env: &HashMap, value: &AttrValue, set_value: F, ) -> bool { match value { AttrValue::VarRef(name) => { // get value from globals - if let Some(value) = self.state.get(name).cloned() { + if let Some(value) = self.state.get(&name).cloned() { self.on_change_handlers - .entry(name.to_string()) + .entry(name.clone()) .or_insert_with(Vec::new) .push(Box::new(set_value.clone())); self.resolve(local_env, &value.into(), set_value) - } else if let Some(value) = local_env.get(name).cloned() { + } else if let Some(value) = local_env.get(&name).cloned() { // get value from local self.resolve(local_env, &value, set_value) } else { @@ -69,21 +96,20 @@ impl EwwState { } } - pub fn resolve_into, F: Fn(V) + 'static + Clone>( - &mut self, - local_env: &HashMap, - value: &AttrValue, - set_value: F, - ) -> bool { - self.resolve(local_env, value, move |x| { - if let Err(e) = x.try_into().map(|v| set_value(v)) { - eprintln!("error while resolving value: {:?}", e); - }; - }) - } + //pub fn resolve_attrs) + 'static + Clone>( + //&mut self, + //local_env: &HashMap, + //unresolved_attrs: HashMap, + //state_update_handler: F, + //) { + //let var_names = values.iter().filter_map(|value| value.as_var_ref().ok()).collect(); + //self.state_change_handlers + //.put_handler(var_names, Arc::new(state_update_handler)) + //} + pub fn resolve_f64( &mut self, - local_env: &HashMap, + local_env: &HashMap, value: &AttrValue, set_value: F, ) -> bool { @@ -97,7 +123,7 @@ impl EwwState { #[allow(dead_code)] pub fn resolve_bool( &mut self, - local_env: &HashMap, + local_env: &HashMap, value: &AttrValue, set_value: F, ) -> bool { @@ -109,7 +135,7 @@ impl EwwState { } pub fn resolve_str( &mut self, - local_env: &HashMap, + local_env: &HashMap, value: &AttrValue, set_value: F, ) -> bool { diff --git a/src/main.rs b/src/main.rs index 62905d1..88ab277 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,6 +17,7 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; use structopt::StructOpt; use value::PrimitiveValue; +use value::VarName; pub mod app; pub mod config; @@ -65,7 +66,7 @@ pub struct Opt { #[derive(StructOpt, Debug, Serialize, Deserialize)] pub enum OptAction { #[structopt(name = "update")] - Update { fieldname: String, value: PrimitiveValue }, + Update { fieldname: VarName, value: PrimitiveValue }, #[structopt(name = "open")] OpenWindow { window_name: String }, diff --git a/src/value.rs b/src/value.rs index 2b49f8a..3153c87 100644 --- a/src/value.rs +++ b/src/value.rs @@ -1,6 +1,7 @@ use anyhow::*; use derive_more; use lazy_static::lazy_static; +use ref_cast::RefCast; use regex::Regex; use serde::{Deserialize, Serialize}; use std::convert::TryFrom; @@ -103,10 +104,38 @@ impl PrimitiveValue { } } +#[repr(transparent)] +#[derive( + Debug, + Clone, + Hash, + PartialEq, + Eq, + derive_more::AsRef, + derive_more::From, + derive_more::FromStr, + Serialize, + Deserialize, + RefCast, +)] +pub struct VarName(pub String); + +impl std::borrow::Borrow for VarName { + fn borrow(&self) -> &str { + &self.0 + } +} + +impl fmt::Display for VarName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + #[derive(Clone, Debug, PartialEq)] pub enum AttrValue { Concrete(PrimitiveValue), - VarRef(String), + VarRef(VarName), } impl AttrValue { @@ -129,6 +158,13 @@ impl AttrValue { } } + pub fn as_var_ref(&self) -> Result { + match self { + AttrValue::VarRef(x) => Ok(x), + _ => Err(anyhow!("{:?} is not a variable reference", self)), + } + } + /// parses the value, trying to turn it into VarRef, /// a number and a boolean first, before deciding that it is a string. pub fn parse_string(s: String) -> Self { @@ -137,7 +173,7 @@ impl AttrValue { }; if let Some(ref_name) = PATTERN.captures(&s).and_then(|cap| cap.get(1)).map(|x| x.as_str()) { - AttrValue::VarRef(ref_name.to_owned()) + AttrValue::VarRef(VarName(ref_name.to_owned())) } else { AttrValue::Concrete(PrimitiveValue::String(s)) } diff --git a/src/widgets/mod.rs b/src/widgets/mod.rs index 3931252..67840c8 100644 --- a/src/widgets/mod.rs +++ b/src/widgets/mod.rs @@ -1,8 +1,10 @@ use crate::config::element; use crate::eww_state::*; -use crate::value::AttrValue; +use crate::value::{AttrValue, VarName}; use anyhow::*; use gtk::prelude::*; +use itertools::Itertools; +use ref_cast::RefCast; use std::{collections::HashMap, process::Command}; use widget_definitions::*; @@ -19,7 +21,7 @@ pub fn run_command(cmd: &str, arg: T) { struct BuilderArgs<'a, 'b, 'c> { eww_state: &'a mut EwwState, - local_env: &'b HashMap, + local_env: &'b HashMap, widget: &'c element::WidgetUse, unhandled_attrs: Vec<&'c str>, } @@ -27,7 +29,7 @@ struct BuilderArgs<'a, 'b, 'c> { pub fn element_to_gtk_thing( widget_definitions: &HashMap, eww_state: &mut EwwState, - local_env: &HashMap, + local_env: &HashMap, widget: &element::WidgetUse, ) -> Result { let gtk_container = build_gtk_widget(widget_definitions, eww_state, local_env, widget)?; @@ -36,7 +38,7 @@ pub fn element_to_gtk_thing( gtk_container } else if let Some(def) = widget_definitions.get(widget.name.as_str()) { let mut local_env = local_env.clone(); - local_env.extend(widget.attrs.clone()); + local_env.extend(widget.attrs.clone().into_iter().map(|(k, v)| (VarName(k), v))); let custom_widget = element_to_gtk_thing(widget_definitions, eww_state, &local_env, &def.structure)?; custom_widget.get_style_context().add_class(widget.name.as_str()); custom_widget @@ -50,14 +52,14 @@ pub fn element_to_gtk_thing( pub fn build_gtk_widget( widget_definitions: &HashMap, eww_state: &mut EwwState, - local_env: &HashMap, + local_env: &HashMap, widget: &element::WidgetUse, ) -> Result> { let mut bargs = BuilderArgs { eww_state, local_env, widget, - unhandled_attrs: widget.attrs.keys().map(|x| x.as_str()).collect(), + unhandled_attrs: widget.attrs.keys().map(|x| x.as_ref()).collect(), }; let gtk_widget = match widget_to_gtk_widget(&mut bargs) { Ok(Some(gtk_widget)) => gtk_widget, @@ -150,10 +152,13 @@ macro_rules! resolve { // with default ($args:ident, $gtk_widget:ident, $func:ident => $attr:literal [$default:expr] => |$arg:ident| $body:expr) => { $args.unhandled_attrs.retain(|a| a != &$attr); - $args.eww_state.$func($args.local_env, $args.widget.attrs.get($attr).unwrap_or(&AttrValue::Concrete(PrimitiveValue::from($default))), { - let $gtk_widget = $gtk_widget.clone(); - move |$arg| { $body; } - }); + $args.eww_state.$func( + $args.local_env, $args.widget.attrs.get($attr).unwrap_or(&AttrValue::Concrete(PrimitiveValue::from($default))), + { + let $gtk_widget = $gtk_widget.clone(); + move |$arg| { $body; } + } + ); }; } diff --git a/src/widgets/widget_definitions.rs b/src/widgets/widget_definitions.rs index 40add27..3c9dff1 100644 --- a/src/widgets/widget_definitions.rs +++ b/src/widgets/widget_definitions.rs @@ -1,6 +1,6 @@ use super::{run_command, BuilderArgs}; use crate::resolve; -use crate::value::{AttrValue, PrimitiveValue}; +use crate::value::{AttrValue, PrimitiveValue, VarName}; use anyhow::*; use gtk::prelude::*; use gtk::ImageExt;