From d9478009a2677b101b9134b5011b4e5d2c529adc Mon Sep 17 00:00:00 2001 From: Jordan Doyle Date: Sat, 4 Nov 2023 00:53:25 +0000 Subject: [PATCH] Use parking_lot for mutexes --- Cargo.lock | 12 ++++++++++++ shalom/Cargo.toml | 3 +++ shalom/src/hass_client.rs | 5 +++-- shalom/src/oracle.rs | 53 ++++++++++++++++++++++++++--------------------------- shalom/src/subscriptions.rs | 7 ++++--- shalom/src/widgets/cards/weather.rs | 6 ++++-- 6 files changed, 52 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fe776a8..5361944 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -137,6 +137,15 @@ dependencies = [ ] [[package]] +name = "atomic" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994" +dependencies = [ + "bytemuck", +] + +[[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2896,6 +2905,8 @@ dependencies = [ name = "shalom" version = "0.1.0" dependencies = [ + "atomic", + "bytemuck", "iced", "image", "internment", @@ -2904,6 +2915,7 @@ dependencies = [ "lru 0.12.0", "once_cell", "palette", + "parking_lot 0.12.1", "reqwest", "serde", "serde_json", diff --git a/shalom/Cargo.toml b/shalom/Cargo.toml index 83eace2..694d855 100644 --- a/shalom/Cargo.toml +++ b/shalom/Cargo.toml @@ -6,9 +6,12 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +atomic = "0.6" +bytemuck = "1.14" iced = { version = "0.10", features = ["tokio", "svg", "lazy", "advanced", "image", "canvas"] } image = "0.24" once_cell = "1.18" +parking_lot = "0.12" internment = "0.7.4" itertools = "0.11" keyframe = "1.1" diff --git a/shalom/src/hass_client.rs b/shalom/src/hass_client.rs index ea9997d..1d837f5 100644 --- a/shalom/src/hass_client.rs +++ b/shalom/src/hass_client.rs @@ -372,7 +372,7 @@ pub mod responses { Deserialize, Deserializer, }; use serde_json::value::RawValue; - use strum::EnumString; + use strum::{EnumString, FromRepr}; use yoke::Yokeable; use crate::theme::Icon; @@ -639,7 +639,8 @@ pub mod responses { entity_picture: Cow<'a, str>, } - #[derive(Default, Deserialize, Debug, EnumString, Copy, Clone)] + #[derive(Default, Deserialize, Debug, EnumString, Copy, Clone, FromRepr)] + #[repr(u16)] #[serde(rename_all = "kebab-case")] #[strum(serialize_all = "kebab-case")] pub enum WeatherCondition { diff --git a/shalom/src/oracle.rs b/shalom/src/oracle.rs index 9013b0e..a847601 100644 --- a/shalom/src/oracle.rs +++ b/shalom/src/oracle.rs @@ -2,13 +2,16 @@ use std::{ borrow::Cow, collections::{BTreeMap, BTreeSet, HashMap, HashSet}, str::FromStr, - sync::{Arc, Mutex}, + sync::{atomic::Ordering, Arc}, time::Duration, }; +use atomic::Atomic; +use bytemuck::NoUninit; use iced::futures::{future, Stream, StreamExt}; use internment::Intern; use itertools::Itertools; +use parking_lot::Mutex; use time::OffsetDateTime; use tokio::{ sync::{broadcast, broadcast::error::RecvError}, @@ -39,7 +42,7 @@ use crate::{ pub struct Oracle { client: crate::hass_client::Client, rooms: BTreeMap<&'static str, Room>, - weather: Mutex, + weather: Atomic, media_players: Mutex>, lights: Mutex>, entity_updates: broadcast::Sender>, @@ -102,7 +105,7 @@ impl Oracle { let this = Arc::new(Self { client: hass_client, rooms, - weather: Mutex::new(Weather::parse_from_states(states)), + weather: Atomic::new(Weather::parse_from_states(states)), media_players: Mutex::new(media_players), lights: Mutex::new(lights), entity_updates: entity_updates.clone(), @@ -122,7 +125,7 @@ impl Oracle { } pub fn current_weather(&self) -> Weather { - *self.weather.lock().unwrap() + self.weather.load(Ordering::Acquire) } pub fn subscribe_weather(&self) -> impl Stream { @@ -140,7 +143,7 @@ impl Oracle { } pub fn fetch_light(&self, entity_id: &'static str) -> Option { - self.lights.lock().unwrap().get(entity_id).cloned() + self.lights.lock().get(entity_id).cloned() } pub fn speaker(&self, speaker_id: &'static str) -> EloquentSpeaker<'_> { @@ -197,7 +200,6 @@ impl Oracle { let mut active_media_players = self .media_players .lock() - .unwrap() .iter() .filter(|(_k, v)| v.is_playing()) .map(|(k, _v)| *k) @@ -219,7 +221,7 @@ impl Oracle { } fn update_media_player_positions(&self, active_media_players: &HashSet<&'static str>) { - let mut media_players = self.media_players.lock().unwrap(); + let mut media_players = self.media_players.lock(); for entity_id in active_media_players { let Some(MediaPlayer::Speaker(speaker)) = media_players.get_mut(entity_id) else { @@ -258,19 +260,19 @@ impl Oracle { active_media_players.remove(entity_id); } - self.media_players - .lock() - .unwrap() - .insert(entity_id, new_state); + self.media_players.lock().insert(entity_id, new_state); } StateAttributes::Weather(attrs) => { - *self.weather.lock().unwrap() = Weather::parse_from_state_and_attributes( - state_changed.new_state.state.as_ref(), - attrs, + self.weather.store( + Weather::parse_from_state_and_attributes( + state_changed.new_state.state.as_ref(), + attrs, + ), + Ordering::Release, ); } StateAttributes::Light(attrs) => { - self.lights.lock().unwrap().insert( + self.lights.lock().insert( Intern::::from(state_changed.entity_id.as_ref()).as_ref(), Light::from((attrs.clone(), state_changed.new_state.state.as_ref())), ); @@ -309,7 +311,6 @@ impl EloquentSpeaker<'_> { .oracle .media_players .lock() - .unwrap() .get_mut(self.speaker_id) .unwrap() { @@ -327,7 +328,6 @@ impl EloquentSpeaker<'_> { .oracle .media_players .lock() - .unwrap() .get_mut(self.speaker_id) .unwrap() { @@ -345,7 +345,6 @@ impl EloquentSpeaker<'_> { .oracle .media_players .lock() - .unwrap() .get_mut(self.speaker_id) .unwrap() { @@ -367,7 +366,6 @@ impl EloquentSpeaker<'_> { .oracle .media_players .lock() - .unwrap() .get_mut(self.speaker_id) .unwrap() { @@ -385,7 +383,6 @@ impl EloquentSpeaker<'_> { .oracle .media_players .lock() - .unwrap() .get_mut(self.speaker_id) .unwrap() { @@ -403,7 +400,6 @@ impl EloquentSpeaker<'_> { .oracle .media_players .lock() - .unwrap() .get_mut(self.speaker_id) .unwrap() { @@ -418,7 +414,6 @@ impl EloquentSpeaker<'_> { .oracle .media_players .lock() - .unwrap() .get_mut(self.speaker_id) .unwrap() { @@ -649,7 +644,6 @@ impl Room { oracle .media_players .lock() - .unwrap() .get(v.as_ref()) .cloned() .zip(Some(v)) @@ -660,7 +654,7 @@ impl Room { } pub fn lights(&self, oracle: &Oracle) -> BTreeMap<&'static str, Light> { - let lights = oracle.lights.lock().unwrap(); + let lights = oracle.lights.lock(); self.lights .iter() @@ -669,15 +663,20 @@ impl Room { } } -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, NoUninit)] +#[repr(C)] pub struct Weather { pub temperature: i16, pub high: i16, pub low: i16, - pub condition: WeatherCondition, + pub condition: u16, } impl Weather { + pub fn weather_condition(self) -> WeatherCondition { + WeatherCondition::from_repr(self.condition).unwrap_or_default() + } + #[allow(clippy::cast_possible_truncation)] fn parse_from_state_and_attributes(state: &str, attributes: &StateWeatherAttributes) -> Self { let condition = WeatherCondition::from_str(state).unwrap_or_default(); @@ -694,7 +693,7 @@ impl Weather { Self { temperature: attributes.temperature.round() as i16, - condition, + condition: condition as u16, high, low, } diff --git a/shalom/src/subscriptions.rs b/shalom/src/subscriptions.rs index 79ba7aa..c6867de 100644 --- a/shalom/src/subscriptions.rs +++ b/shalom/src/subscriptions.rs @@ -1,8 +1,9 @@ -use std::{hash::Hash, num::NonZeroUsize, sync::Mutex}; +use std::{hash::Hash, num::NonZeroUsize}; use iced::{futures::stream, subscription, widget::image, Subscription}; use lru::LruCache; use once_cell::sync::Lazy; +use parking_lot::Mutex; use url::Url; pub fn download_image( @@ -16,7 +17,7 @@ pub fn download_image( subscription::run_with_id( id, stream::once(async move { - if let Some(handle) = CACHE.lock().unwrap().get(&url) { + if let Some(handle) = CACHE.lock().get(&url) { return (resp)(url, handle.clone()); } @@ -28,7 +29,7 @@ pub fn download_image( .unwrap(); let handle = image::Handle::from_memory(bytes); - CACHE.lock().unwrap().push(url.clone(), handle.clone()); + CACHE.lock().push(url.clone(), handle.clone()); (resp)(url, handle) }), diff --git a/shalom/src/widgets/cards/weather.rs b/shalom/src/widgets/cards/weather.rs index 5d8302b..ee359aa 100644 --- a/shalom/src/widgets/cards/weather.rs +++ b/shalom/src/widgets/cards/weather.rs @@ -39,7 +39,9 @@ impl WeatherCard { fn build_conditions(&self) -> String { format!( "{}\nH:{}° L:{}°", - self.current_weather.condition, self.current_weather.high, self.current_weather.low, + self.current_weather.weather_condition(), + self.current_weather.high, + self.current_weather.low, ) } } @@ -151,7 +153,7 @@ impl Widget for WeatherCard { }); let icon_bounds = children.next().unwrap().bounds(); - if let Some(icon) = self.current_weather.condition.icon(day_time) { + if let Some(icon) = self.current_weather.weather_condition().icon(day_time) { renderer.draw(icon.handle(), None, icon_bounds); } -- libgit2 1.7.2