From 6888fbbb6235e646456af28df4d268bdc12b3d29 Mon Sep 17 00:00:00 2001 From: Barafu Albino Cheetah Date: Thu, 22 Aug 2024 13:31:39 +0300 Subject: [PATCH] refactor Dream trait to avoid building Dreams needlessly. --- src/app_settings.rs | 12 +++++------- src/dreamconfig.rs | 30 +++++++++++++++------------- src/dreams.rs | 41 ++++++++++++++++++++++----------------- src/dreams/dendraclock.rs | 17 +++++++++++----- src/dreams/monet.rs | 11 +++++++---- src/dreams/solid_color.rs | 17 +++++++++++----- src/dreamspinner.rs | 8 ++++---- 7 files changed, 79 insertions(+), 57 deletions(-) diff --git a/src/app_settings.rs b/src/app_settings.rs index 42506f5..6d17061 100644 --- a/src/app_settings.rs +++ b/src/app_settings.rs @@ -2,7 +2,7 @@ use anyhow::{anyhow, Result}; use directories::ProjectDirs; use log; use std::{ - collections::{HashMap, HashSet}, + collections::{BTreeMap, BTreeSet}, fmt::Display, fs::File, path::{Path, PathBuf}, @@ -13,14 +13,12 @@ pub static SETTINGS: LazyLock> = LazyLock::new(|| { RwLock::new(SettingsRaw::read_from_file_default().unwrap()) }); -use crate::dreams::DreamId; - #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] #[serde(default)] /// Contains all persistant settings of the application pub struct SettingsRaw { /// Contains unique settings of particular dreams - pub dream_settings: HashMap, + pub dream_settings: BTreeMap, /// Try to detect and cover additional monitors. pub attempt_multiscreen: bool, @@ -28,7 +26,7 @@ pub struct SettingsRaw { /// Show FPS statistics on primary screen. pub show_fps: bool, - pub selected_dreams: HashSet, + pub selected_dreams: BTreeSet, pub viewport_mode: ViewportMode, } @@ -36,10 +34,10 @@ pub struct SettingsRaw { impl Default for SettingsRaw { fn default() -> Self { Self { - dream_settings: HashMap::new(), + dream_settings: BTreeMap::new(), attempt_multiscreen: false, show_fps: false, - selected_dreams: HashSet::from(["fractal_clock".to_string()]), + selected_dreams: BTreeSet::from(["fractal_clock".to_string()]), viewport_mode: ViewportMode::Immediate, } } diff --git a/src/dreamconfig.rs b/src/dreamconfig.rs index 5c9a642..60e01be 100644 --- a/src/dreamconfig.rs +++ b/src/dreamconfig.rs @@ -1,3 +1,5 @@ +use std::collections::BTreeMap; + use crate::app_settings::{ViewportMode, SETTINGS}; use crate::dreams::*; use anyhow::Result; @@ -13,7 +15,7 @@ enum ActivePanel { pub struct DreamConfigApp { active_panel: ActivePanel, - zoo: Zoo, + zoo: BTreeMap, } impl eframe::App for DreamConfigApp { @@ -53,7 +55,7 @@ impl eframe::App for DreamConfigApp { ); //ui.separator(); // TODO: Can't enable separator: breaks UI for some reason - for dream in self.zoo.iter() { + for dream in self.zoo.values() { ui.selectable_value( &mut self.active_panel, ActivePanel::Dream(dream.read().unwrap().id()), @@ -67,8 +69,7 @@ impl eframe::App for DreamConfigApp { ActivePanel::Select => self.draw_dream_select(ui), ActivePanel::About => self.draw_about(ui), ActivePanel::Dream(id) => { - let dream = select_dream_by_id(&self.zoo, id).unwrap(); - dream.write().unwrap().config_egui(ui); + self.zoo[*id].write().unwrap().config_egui(ui); } }); }); @@ -80,15 +81,16 @@ impl DreamConfigApp { pub fn new(_cc: &eframe::CreationContext<'_>) -> Result { // Load settings from file - let zoo = build_zoo(); - for dream in zoo.iter() { - dream.write().unwrap().prepare(); - } + let dream_ids = build_dreams_id_list(); + let zoo: BTreeMap = dream_ids + .keys() + .map(|id| (id.to_string(), build_dream_by_id(id))) + .collect(); Ok(Self { active_panel: ActivePanel::Generic, zoo }) } fn save(&mut self) { - for dream in self.zoo.iter() { + for dream in self.zoo.values() { dream.read().unwrap().store(); } SETTINGS.write().unwrap().write_to_file_default().unwrap(); @@ -137,7 +139,7 @@ impl DreamConfigApp { let mut ids = Vec::with_capacity(self.zoo.len()); let mut names = Vec::with_capacity(self.zoo.len()); - for arcd in self.zoo.iter() { + for arcd in self.zoo.values() { let d = arcd.read().unwrap(); ids.push(d.id()); names.push(d.name()); @@ -149,13 +151,13 @@ impl DreamConfigApp { ui.label("Select dream:"); let st = &mut settings.selected_dreams; for n in 0..ids.len() { - let mut active = st.contains(&ids[n]); - ui.checkbox(&mut active, &names[n]); + let mut active = st.contains(ids[n]); + ui.checkbox(&mut active, names[n]); if active { - st.insert(ids[n].clone()); + st.insert(ids[n].to_string()); } else { if st.len() > 1 { - st.remove(&ids[n]); + st.remove(ids[n]); } } } diff --git a/src/dreams.rs b/src/dreams.rs index f045a05..06ced83 100644 --- a/src/dreams.rs +++ b/src/dreams.rs @@ -1,13 +1,15 @@ use crate::app_settings::SETTINGS; -use std::sync::{Arc, RwLock}; +use std::{ + collections::BTreeMap, + sync::{Arc, RwLock}, +}; mod dendraclock; mod monet; mod solid_color; -/// For giggles, I call the collection of all dream types "zoo" -pub type Zoo = Vec>>; -pub type DreamId = String; +pub type DreamId = &'static str; +pub type ADream = Arc>; #[derive(PartialEq, Debug)] pub enum DreamType { @@ -26,7 +28,7 @@ pub trait Dream: Sync + Send { /// Gives the name to display in UI. The name also serves as ID, including /// in settings, so it must be unique - fn name(&self) -> String; + fn name(&self) -> &'static str; /// Prepare dream for rendering (load resources, initialize RNG etc.) fn prepare(&mut self) {} @@ -53,21 +55,24 @@ pub trait Dream: Sync + Send { fn store(&self) {} } -pub fn build_zoo() -> Zoo { - let mut zoo: Zoo = Zoo::new(); - let d = RwLock::new(solid_color::SolidColorDream::new()); - zoo.push(Arc::new(d)); - let d = RwLock::new(dendraclock::DendraClockDream::new()); - zoo.push(Arc::new(d)); - let d = RwLock::new(monet::MonetDream::new()); - zoo.push(Arc::new(d)); +pub fn build_dreams_id_list() -> BTreeMap<&'static str, &'static str> { + let mut zoo = BTreeMap::new(); + zoo.insert(dendraclock::DREAM_ID, dendraclock::DREAM_NAME); + zoo.insert(monet::DREAM_ID, monet::DREAM_NAME); + zoo.insert(solid_color::DREAM_ID, solid_color::DREAM_NAME); zoo } // Pick a dream from zoo by its id. -pub fn select_dream_by_id( - zoo: &Zoo, - id: &DreamId, -) -> Option>> { - zoo.iter().find(|d| d.read().unwrap().id() == *id).map(|d| d.clone()) +pub fn build_dream_by_id(id: &str) -> ADream { + match id { + dendraclock::DREAM_ID => { + Arc::new(RwLock::new(dendraclock::DendraClockDream::new())) + } + monet::DREAM_ID => Arc::new(RwLock::new(monet::MonetDream::new())), + solid_color::DREAM_ID => { + Arc::new(RwLock::new(solid_color::SolidColorDream::new())) + } + _ => panic!("Unknown dream id: {}", id), + } } diff --git a/src/dreams/dendraclock.rs b/src/dreams/dendraclock.rs index f0cb512..8d6b8be 100644 --- a/src/dreams/dendraclock.rs +++ b/src/dreams/dendraclock.rs @@ -3,6 +3,9 @@ use chrono::{Local, Timelike}; use egui::{widgets::*, *}; use std::f32::consts::TAU; +pub const DREAM_ID: DreamId = "fractal_clock"; +pub const DREAM_NAME: &'static str = "Fractal Clock"; + pub struct DendraClockDream { dream_settings: DendraClockSettings, } @@ -41,7 +44,7 @@ impl Dream for DendraClockDream { .read() .unwrap() .dream_settings - .get(&d.id()) + .get(DREAM_ID) .cloned() .unwrap_or_default(); d.dream_settings = toml::from_str(&txt).unwrap_or_default(); @@ -49,11 +52,11 @@ impl Dream for DendraClockDream { } fn id(&self) -> DreamId { - "fractal_clock".to_string() + DREAM_ID } - fn name(&self) -> String { - "Fractal Clock".to_string() + fn name(&self) -> &'static str { + DREAM_NAME } fn get_type(&self) -> DreamType { @@ -76,7 +79,11 @@ impl Dream for DendraClockDream { fn store(&self) { let txt = toml::to_string(&self.dream_settings).unwrap(); - SETTINGS.write().unwrap().dream_settings.insert(self.id(), txt); + SETTINGS + .write() + .unwrap() + .dream_settings + .insert(DREAM_ID.to_string(), txt); } } diff --git a/src/dreams/monet.rs b/src/dreams/monet.rs index 21436f1..898cbec 100644 --- a/src/dreams/monet.rs +++ b/src/dreams/monet.rs @@ -1,5 +1,8 @@ use crate::dreams::*; +pub const DREAM_ID: DreamId = "monet"; +pub const DREAM_NAME: &'static str = "Monet"; + pub struct MonetDream { dream_settings: MonetSettings, } @@ -18,7 +21,7 @@ impl Dream for MonetDream { .read() .unwrap() .dream_settings - .get(&d.id()) + .get(DREAM_ID) .cloned() .unwrap_or_default(); d.dream_settings = toml::from_str(&txt).unwrap_or_default(); @@ -26,11 +29,11 @@ impl Dream for MonetDream { } fn id(&self) -> super::DreamId { - "monet".to_string() + DREAM_ID } - fn name(&self) -> String { - "Monet".to_string() + fn name(&self) -> &'static str { + DREAM_NAME } fn get_type(&self) -> super::DreamType { diff --git a/src/dreams/solid_color.rs b/src/dreams/solid_color.rs index 22bc092..a631f3e 100644 --- a/src/dreams/solid_color.rs +++ b/src/dreams/solid_color.rs @@ -1,5 +1,8 @@ use crate::dreams::*; +pub const DREAM_ID: DreamId = "solid_color"; +pub const DREAM_NAME: &'static str = "Solid Color"; + /// This dream is intended to be as primitive as possible to serve as example /// of how to implement Dream trait. /// @@ -27,18 +30,18 @@ impl Dream for SolidColorDream { .read() .unwrap() .dream_settings - .get(&d.id()) + .get(DREAM_ID) .cloned() .unwrap_or_default(); d.dream_settings = toml::from_str(&txt).unwrap_or_default(); d } fn id(&self) -> DreamId { - "solid_color".to_string() + DREAM_ID } - fn name(&self) -> String { - "Solid Color".to_string() + fn name(&self) -> &'static str { + DREAM_NAME } fn get_type(&self) -> DreamType { @@ -66,6 +69,10 @@ impl Dream for SolidColorDream { fn store(&self) { let txt = toml::to_string(&self.dream_settings).unwrap(); - SETTINGS.write().unwrap().dream_settings.insert(self.id(), txt); + SETTINGS + .write() + .unwrap() + .dream_settings + .insert(DREAM_ID.to_string(), txt); } } diff --git a/src/dreamspinner.rs b/src/dreamspinner.rs index ab32559..81fa1b1 100644 --- a/src/dreamspinner.rs +++ b/src/dreamspinner.rs @@ -96,12 +96,12 @@ impl DreamSpinner { /// /// Chooses randomly one of the dreams in selected list. Runs prepare on it. fn select_active_dream() -> Arc> { - let zoo = build_zoo(); - let selected_dreams = &SETTINGS.read().unwrap().selected_dreams; + let selected_dreams = SETTINGS.read().unwrap().selected_dreams.clone(); let mut rng = rand::thread_rng(); let random_index = rng.gen_range(0..selected_dreams.len()); - let random_id = selected_dreams.iter().nth(random_index).unwrap(); - let dream = select_dream_by_id(&zoo, random_id).unwrap(); + let random_id = + selected_dreams.iter().nth(random_index).unwrap().to_string(); + let dream = build_dream_by_id(&random_id); dream.write().unwrap().prepare(); dream }