Use parking_lot for mutexes
Diff
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(-)
@@ -137,6 +137,15 @@
]
[[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 @@
name = "shalom"
version = "0.1.0"
dependencies = [
"atomic",
"bytemuck",
"iced",
"image",
"internment",
@@ -2904,6 +2915,7 @@
"lru 0.12.0",
"once_cell",
"palette",
"parking_lot 0.12.1",
"reqwest",
"serde",
"serde_json",
@@ -6,9 +6,12 @@
[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"
@@ -372,7 +372,7 @@
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 @@
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 {
@@ -1,14 +1,17 @@
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 @@
pub struct Oracle {
client: crate::hass_client::Client,
rooms: BTreeMap<&'static str, Room>,
weather: Mutex<Weather>,
weather: Atomic<Weather>,
media_players: Mutex<BTreeMap<&'static str, MediaPlayer>>,
lights: Mutex<BTreeMap<&'static str, Light>>,
entity_updates: broadcast::Sender<Arc<str>>,
@@ -102,7 +105,7 @@
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 @@
}
pub fn current_weather(&self) -> Weather {
*self.weather.lock().unwrap()
self.weather.load(Ordering::Acquire)
}
pub fn subscribe_weather(&self) -> impl Stream<Item = ()> {
@@ -140,7 +143,7 @@
}
pub fn fetch_light(&self, entity_id: &'static str) -> Option<Light> {
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 @@
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 @@
}
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 @@
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::<str>::from(state_changed.entity_id.as_ref()).as_ref(),
Light::from((attrs.clone(), state_changed.new_state.state.as_ref())),
);
@@ -309,7 +311,6 @@
.oracle
.media_players
.lock()
.unwrap()
.get_mut(self.speaker_id)
.unwrap()
{
@@ -327,7 +328,6 @@
.oracle
.media_players
.lock()
.unwrap()
.get_mut(self.speaker_id)
.unwrap()
{
@@ -345,7 +345,6 @@
.oracle
.media_players
.lock()
.unwrap()
.get_mut(self.speaker_id)
.unwrap()
{
@@ -367,7 +366,6 @@
.oracle
.media_players
.lock()
.unwrap()
.get_mut(self.speaker_id)
.unwrap()
{
@@ -385,7 +383,6 @@
.oracle
.media_players
.lock()
.unwrap()
.get_mut(self.speaker_id)
.unwrap()
{
@@ -403,7 +400,6 @@
.oracle
.media_players
.lock()
.unwrap()
.get_mut(self.speaker_id)
.unwrap()
{
@@ -418,7 +414,6 @@
.oracle
.media_players
.lock()
.unwrap()
.get_mut(self.speaker_id)
.unwrap()
{
@@ -649,7 +644,6 @@
oracle
.media_players
.lock()
.unwrap()
.get(v.as_ref())
.cloned()
.zip(Some(v))
@@ -660,7 +654,7 @@
}
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 @@
}
}
#[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 @@
Self {
temperature: attributes.temperature.round() as i16,
condition,
condition: condition as u16,
high,
low,
}
@@ -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<I: Hash + 'static, M: 'static>(
@@ -16,7 +17,7 @@
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 @@
.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)
}),
@@ -39,7 +39,9 @@
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 @@
});
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);
}