From ebc9fd2a62a7b15f9c2996a7b7b009db57ed6219 Mon Sep 17 00:00:00 2001 From: Fl1tzi Date: Wed, 1 Nov 2023 00:12:56 +0100 Subject: [PATCH] add image module, config parsing improvements --- src/config.rs | 33 +++++++++++++++++++++++++++------ src/modules.rs | 5 ++++- src/modules/image.rs | 44 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 7 deletions(-) create mode 100644 src/modules/image.rs diff --git a/src/config.rs b/src/config.rs index 96c2528..f33a3c1 100644 --- a/src/config.rs +++ b/src/config.rs @@ -77,6 +77,8 @@ fn new_hashmap() -> HashMap { pub enum ButtonConfigError { /// (Key, Expected) WrongType(String, &'static str), + /// a required value + Required(&'static str), /// A general error which gets directly outputed to the user General(String), } @@ -90,6 +92,9 @@ impl Display for ButtonConfigError { "Expected value of type {expected} in option \"{key}\"." ) } + ButtonConfigError::Required(key) => { + write!(formatter, "A value for the option \"{key}\" is required.") + } ButtonConfigError::General(message) => { write!(formatter, "{message}") } @@ -99,19 +104,35 @@ impl Display for ButtonConfigError { /// See [parse_button_config()] pub enum ParseButtonConfigResult { - Found(T), - NotFound(T), + /// (user-defined value, key) + Found(T, &'static str), + /// (alternative value, key) + NotFound(T, &'static str), ParseError(ButtonConfigError), } impl ParseButtonConfigResult { /// instead of the enum return Result. /// - /// [ParseButtonConfigResult::Found] || [ParseButtonConfigResult::NotFound] => Ok(value) + /// [ParseButtonConfigResult::Found] | [ParseButtonConfigResult::NotFound] => Ok(value) /// [ParseButtonConfigResult::ParseError] => Err(e) pub fn res(self) -> Result { match self { - ParseButtonConfigResult::Found(v) | ParseButtonConfigResult::NotFound(v) => Ok(v), + ParseButtonConfigResult::Found(v, _) | ParseButtonConfigResult::NotFound(v, _) => Ok(v), + ParseButtonConfigResult::ParseError(e) => Err(e), + } + } + + /// instead of the enum return Result + /// + /// This makes a user-defined value required. + /// + /// [ParseButtonConfigResult::Found] => Ok(value) + /// [ParseButtonConfigResult::NotFound] | [ParseButtonConfigResult::ParseError] => Err(e) + pub fn required(self) -> Result { + match self { + ParseButtonConfigResult::Found(v, _) => Ok(v), + ParseButtonConfigResult::NotFound(_, k) => Err(ButtonConfigError::Required(k)), ParseButtonConfigResult::ParseError(e) => Err(e), } } @@ -135,11 +156,11 @@ impl Button { // try to find value or return None let parse_result = match self.options.get(key) { Some(value) => value.parse::(), - _ => return ParseButtonConfigResult::NotFound(if_wrong_type), + _ => return ParseButtonConfigResult::NotFound(if_wrong_type, key), }; // check if value could be parsed if let Ok(out) = parse_result { - return ParseButtonConfigResult::Found(out); + return ParseButtonConfigResult::Found(out, key); } ParseButtonConfigResult::ParseError(ButtonConfigError::WrongType( key.to_string(), diff --git a/src/modules.rs b/src/modules.rs index 0195295..d807345 100644 --- a/src/modules.rs +++ b/src/modules.rs @@ -1,17 +1,19 @@ mod blank; mod counter; +mod image; mod space; // modules use self::counter::Counter; +use self::image::Image; use self::space::Space; // other things use crate::config::{Button, ButtonConfigError}; +use ::image::DynamicImage; use async_trait::async_trait; pub use deck_driver as streamdeck; use futures_util::Future; -use image::DynamicImage; use std::{error::Error, pin::Pin, sync::Arc}; use streamdeck::info::ImageFormat; use streamdeck::info::Kind; @@ -38,6 +40,7 @@ pub fn retrieve_module_from_name(name: &str) -> Option { match name { "space" => Some(Space::init as ModuleInitFunction), "counter" => Some(Counter::init as ModuleInitFunction), + "image" => Some(Image::init as ModuleInitFunction), _ => None, } } diff --git a/src/modules/image.rs b/src/modules/image.rs new file mode 100644 index 0000000..3f730e4 --- /dev/null +++ b/src/modules/image.rs @@ -0,0 +1,44 @@ +use super::Button; +use super::ButtonConfigError; +use super::ChannelReceiver; +use super::DeviceAccess; +use super::Module; +use super::ModuleObject; +use super::ReturnError; +use crate::image_rendering::{load_image, ImageBuilder}; +use async_trait::async_trait; +use image::DynamicImage; +use std::sync::Arc; +use tokio::task; + +pub struct Image { + image: DynamicImage, + scale: f32, +} + +#[async_trait] +impl Module for Image { + async fn init(config: Arc