From 59594923488b923dbe0f0e2d0bf08d8688fc7d9e Mon Sep 17 00:00:00 2001 From: Jack Wills <32690432+mrjackwills@users.noreply.github.com> Date: Sat, 19 Oct 2024 18:55:23 +0000 Subject: [PATCH] feat: S! & C! macros --- src/app_env.rs | 57 +++++++++++++++++++++--------------------- src/camera.rs | 9 ++++--- src/main.rs | 19 ++++++++++++++ src/sysinfo.rs | 26 +++++++++---------- src/word_art/mod.rs | 61 ++++++++++++++++++++++++--------------------- src/ws/mod.rs | 6 ++--- src/ws/ws_sender.rs | 3 ++- 7 files changed, 103 insertions(+), 78 deletions(-) diff --git a/src/app_env.rs b/src/app_env.rs index 49d3a23..3c92e0a 100644 --- a/src/app_env.rs +++ b/src/app_env.rs @@ -2,7 +2,7 @@ use std::{collections::HashMap, env, fmt, time::SystemTime}; use time::UtcOffset; use time_tz::{timezones, Offset, TimeZone}; -use crate::app_error::AppError; +use crate::{app_error::AppError, S}; type EnvHashMap = HashMap; @@ -15,7 +15,7 @@ impl EnvTimeZone { if timezones::get_by_name(&x).is_some() { Self(x) } else { - Self("Etc/UTC".into()) + Self(S!("Etc/UTC")) } } @@ -165,12 +165,14 @@ impl AppEnv { #[cfg(test)] #[expect(clippy::unwrap_used)] mod tests { + use crate::S; + use super::*; #[test] fn env_missing_env() { let mut map = HashMap::new(); - map.insert("not_fish".to_owned(), "not_fish".to_owned()); + map.insert(S!("not_fish"), S!("not_fish")); // ACTION let result = AppEnv::parse_string("fish", &map); @@ -183,7 +185,7 @@ mod tests { fn env_parse_string_valid() { // FIXTURES let mut map = HashMap::new(); - map.insert("LOCATION_SQLITE".to_owned(), "/alarms.db".to_owned()); + map.insert(S!("LOCATION_SQLITE"), S!("/alarms.db")); // ACTION let result = AppEnv::parse_string("LOCATION_SQLITE", &map).unwrap(); @@ -196,9 +198,9 @@ mod tests { fn env_parse_boolean_ok() { // FIXTURES let mut map = HashMap::new(); - map.insert("valid_true".to_owned(), "true".to_owned()); - map.insert("valid_false".to_owned(), "false".to_owned()); - map.insert("invalid_but_false".to_owned(), "as".to_owned()); + map.insert(S!("valid_true"), S!("true")); + map.insert(S!("valid_false"), S!("false")); + map.insert(S!("invalid_but_false"), S!("as")); // ACTION let result01 = AppEnv::parse_boolean("valid_true", &map); @@ -217,7 +219,7 @@ mod tests { fn env_parse_rotation_ok() { // FIXTURES let mut map = HashMap::new(); - map.insert("ROTATION".to_owned(), "90".to_owned()); + map.insert(S!("ROTATION"), S!("90")); // ACTION let result = AppEnv::parse_rotation(&map); @@ -227,7 +229,7 @@ mod tests { // FIXTURES let mut map = HashMap::new(); - map.insert("ROTATION".to_owned(), "180".to_owned()); + map.insert(S!("ROTATION"), S!("180")); // ACTION let result = AppEnv::parse_rotation(&map); @@ -237,7 +239,7 @@ mod tests { // FIXTURES let mut map = HashMap::new(); - map.insert("ROTATION".to_owned(), "270".to_owned()); + map.insert(S!("ROTATION"), S!("270")); // ACTION let result = AppEnv::parse_rotation(&map); @@ -247,7 +249,7 @@ mod tests { // FIXTURES let mut map = HashMap::new(); - map.insert("ROTATION".to_owned(), "0".to_owned()); + map.insert(S!("ROTATION"), S!("0")); // ACTION let result = AppEnv::parse_rotation(&map); @@ -257,7 +259,7 @@ mod tests { // FIXTURES let mut map = HashMap::new(); - map.insert("ROTATION".to_owned(), "181".to_owned()); + map.insert(S!("ROTATION"), S!("181")); // ACTION let result = AppEnv::parse_rotation(&map); @@ -266,7 +268,7 @@ mod tests { assert_eq!(result, Rotation::Zero); let mut map = HashMap::new(); - map.insert("ROTATION".to_owned(), String::new()); + map.insert(S!("ROTATION"), S!()); // ACTION let result = AppEnv::parse_rotation(&map); @@ -288,7 +290,7 @@ mod tests { fn env_parse_timezone_ok() { // FIXTURES let mut map = HashMap::new(); - map.insert("TIMEZONE".to_owned(), "America/New_York".to_owned()); + map.insert(S!("TIMEZONE"), S!("America/New_York")); // ACTION let result = AppEnv::parse_timezone(&map); @@ -297,7 +299,7 @@ mod tests { assert_eq!(result.0, "America/New_York"); let mut map = HashMap::new(); - map.insert("TIMEZONE".to_owned(), "Europe/Berlin".to_owned()); + map.insert(S!("TIMEZONE"), S!("Europe/Berlin")); // ACTION let result = AppEnv::parse_timezone(&map); @@ -319,7 +321,7 @@ mod tests { fn env_parse_timezone_err() { // FIXTURES let mut map = HashMap::new(); - map.insert("TIMEZONE".to_owned(), "america/New_York".to_owned()); + map.insert(S!("TIMEZONE"), S!("america/New_York")); // ACTION let result = AppEnv::parse_timezone(&map); @@ -338,7 +340,7 @@ mod tests { #[test] fn env_parse_log_valid() { // FIXTURES - let map = HashMap::from([("RANDOM_STRING".to_owned(), "123".to_owned())]); + let map = HashMap::from([(S!("RANDOM_STRING"), S!("123"))]); // ACTION let result = AppEnv::parse_log(&map); @@ -347,7 +349,7 @@ mod tests { assert_eq!(result, tracing::Level::INFO); // FIXTURES - let map = HashMap::from([("LOG_DEBUG".to_owned(), "false".to_owned())]); + let map = HashMap::from([(S!("LOG_DEBUG"), S!("false"))]); // ACTION let result = AppEnv::parse_log(&map); @@ -356,7 +358,7 @@ mod tests { assert_eq!(result, tracing::Level::INFO); // FIXTURES - let map = HashMap::from([("LOG_TRACE".to_owned(), "false".to_owned())]); + let map = HashMap::from([(S!("LOG_TRACE"), S!("false"))]); // ACTION let result = AppEnv::parse_log(&map); @@ -366,8 +368,8 @@ mod tests { // FIXTURES let map = HashMap::from([ - ("LOG_DEBUG".to_owned(), "false".to_owned()), - ("LOG_TRACE".to_owned(), "false".to_owned()), + (S!("LOG_DEBUG"), S!("false")), + (S!("LOG_TRACE"), S!("false")), ]); // ACTION @@ -378,8 +380,8 @@ mod tests { // FIXTURES let map = HashMap::from([ - ("LOG_DEBUG".to_owned(), "true".to_owned()), - ("LOG_TRACE".to_owned(), "false".to_owned()), + (S!("LOG_DEBUG"), S!("true")), + (S!("LOG_TRACE"), S!("false")), ]); // ACTION @@ -389,10 +391,7 @@ mod tests { assert_eq!(result, tracing::Level::DEBUG); // FIXTURES - let map = HashMap::from([ - ("LOG_DEBUG".to_owned(), "true".to_owned()), - ("LOG_TRACE".to_owned(), "true".to_owned()), - ]); + let map = HashMap::from([(S!("LOG_DEBUG"), S!("true")), (S!("LOG_TRACE"), S!("true"))]); // ACTION let result = AppEnv::parse_log(&map); @@ -402,8 +401,8 @@ mod tests { // FIXTURES let map = HashMap::from([ - ("LOG_DEBUG".to_owned(), "false".to_owned()), - ("LOG_TRACE".to_owned(), "true".to_owned()), + (S!("LOG_DEBUG"), S!("false")), + (S!("LOG_TRACE"), S!("true")), ]); // ACTION diff --git a/src/camera.rs b/src/camera.rs index 2db40b1..a68e824 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -1,4 +1,7 @@ -use crate::app_env::{AppEnv, EnvTimeZone}; +use crate::{ + app_env::{AppEnv, EnvTimeZone}, + C, +}; use image::imageops::FilterType; use std::{ io::Cursor, @@ -66,8 +69,8 @@ impl Camera { image_timestamp: SystemTime::now(), file_size: FileSize::default(), rotation: app_envs.rotation.to_string(), - timezone: app_envs.timezone.clone(), - location_images: app_envs.location_images.clone(), + timezone: C!(app_envs.timezone), + location_images: C!(app_envs.location_images), }; let photo_buffer = camera.photograph().await; camera.convert_to_webp(&photo_buffer).await; diff --git a/src/main.rs b/src/main.rs index acb77db..51e215f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,6 +22,25 @@ use ws::open_connection; const LOGS_NAME: &str = "leafcast.log"; +/// Simple macro to create a new String, or convert from a &str to a String - basically just gets rid of String::from() / .to_owned() etc +#[macro_export] +macro_rules! S { + () => { + String::new() + }; + ($s:expr) => { + String::from($s) + }; +} + +/// Simple macro to call `.clone()` on whatever is passed in +#[macro_export] +macro_rules! C { + ($i:expr) => { + $i.clone() + }; +} + fn setup_tracing(app_env: &AppEnv) -> Result<(), AppError> { let logfile = tracing_appender::rolling::never(&app_env.location_log, LOGS_NAME); diff --git a/src/sysinfo.rs b/src/sysinfo.rs index c40a4d0..81ea7cb 100644 --- a/src/sysinfo.rs +++ b/src/sysinfo.rs @@ -3,7 +3,7 @@ use std::time::Instant; use serde::{Deserialize, Serialize}; use tokio::fs::read_to_string; -use crate::{app_env::AppEnv, app_error::AppError}; +use crate::{app_env::AppEnv, app_error::AppError, C, S}; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct SysInfo { @@ -38,10 +38,10 @@ impl SysInfo { } async fn get_ip(app_envs: &AppEnv) -> String { - let na = String::from("N/A"); + let na = S!("N/A"); let ip = read_to_string(&app_envs.location_ip_address) .await - .unwrap_or_else(|_| na.clone()); + .unwrap_or_else(|_| C!(na)); let output = if ip.len() > 1 { ip.trim().to_owned() } else { @@ -85,18 +85,18 @@ mod tests { use super::*; fn gen_app_env(location_ip_address: String) -> AppEnv { - let na = String::from("na"); + let na = S!("na"); AppEnv { - location_images: String::from("photos"), + location_images: S!("photos"), location_ip_address, - location_log: na.clone(), + location_log: C!(na), log_level: tracing::Level::INFO, rotation: Rotation::Zero, start_time: SystemTime::now(), timezone: EnvTimeZone::new("America/New_York"), - ws_address: na.clone(), - ws_apikey: na.clone(), - ws_password: na.clone(), + ws_address: C!(na), + ws_apikey: C!(na), + ws_password: C!(na), ws_token_address: na, } } @@ -104,7 +104,7 @@ mod tests { #[tokio::test] async fn sysinfo_getuptime_ok() { // FIXTURES - gen_app_env(String::from("ip.addr")); + gen_app_env(S!("ip.addr")); // ACTIONS let result = SysInfo::get_uptime().await; @@ -117,7 +117,7 @@ mod tests { #[tokio::test] async fn sysinfo_get_ip_na() { // FIXTURES - let app_envs = gen_app_env(String::from("na")); + let app_envs = gen_app_env(S!("na")); // ACTIONS let result = SysInfo::get_ip(&app_envs).await; @@ -129,7 +129,7 @@ mod tests { #[tokio::test] async fn sysinfo_get_ip_ok() { // FIXTURES - let app_envs = gen_app_env(String::from("ip.addr")); + let app_envs = gen_app_env(S!("ip.addr")); // ACTIONS let result = SysInfo::get_ip(&app_envs).await; @@ -140,7 +140,7 @@ mod tests { #[tokio::test] async fn sysinfo_get_sysinfo_ok() { // FIXTURES - let app_envs = gen_app_env(String::from("ip.addr")); + let app_envs = gen_app_env(S!("ip.addr")); tokio::time::sleep(std::time::Duration::from_secs(1)).await; let now = Instant::now(); diff --git a/src/word_art/mod.rs b/src/word_art/mod.rs index fc88415..f66a889 100644 --- a/src/word_art/mod.rs +++ b/src/word_art/mod.rs @@ -1,4 +1,4 @@ -use crate::app_env::AppEnv; +use crate::{app_env::AppEnv, S}; use std::fmt::Write; mod font; @@ -10,16 +10,16 @@ const RESET: &str = "\x1b[0m"; /// Convert input string to ASCII art fn create_art(input: &str, fontname: FontName) -> String { - FIGfont::from_content(FontName::get(fontname)).map_or(String::new(), |font| { + FIGfont::from_content(FontName::get(fontname)).map_or(S!(), |font| { let figure = font.convert(input); - figure.map_or(String::new(), |text| text.to_string()) + figure.map_or(S!(), |text| text.to_string()) }) } /// Add color to a given string fn paint_text(text: &str, color: Color) -> String { let tint = Color::get(color); - let painted = text.lines().fold(String::new(), |mut output, i| { + let painted = text.lines().fold(S!(), |mut output, i| { writeln!(output, "{tint}{i}").ok(); output }); @@ -77,25 +77,28 @@ impl Intro { /// cargo watch -q -c -w src/ -x 'test word_art -- --nocapture' #[cfg(test)] mod tests { - use crate::app_env::{EnvTimeZone, Rotation}; + use crate::{ + app_env::{EnvTimeZone, Rotation}, + C, + }; use super::*; use std::time::SystemTime; #[test] fn word_art_display_intro_trace() { - let na = String::from("na"); + let na = S!("na"); let args = AppEnv { - location_images: na.clone(), - location_ip_address: na.clone(), - location_log: na.clone(), + location_images: C!(na), + location_ip_address: C!(na), + location_log: C!(na), log_level: tracing::Level::TRACE, rotation: Rotation::Zero, start_time: SystemTime::now(), - timezone: EnvTimeZone::new(String::new()), - ws_address: na.clone(), - ws_apikey: na.clone(), - ws_password: na.clone(), + timezone: EnvTimeZone::new(S!()), + ws_address: C!(na), + ws_apikey: C!(na), + ws_password: C!(na), ws_token_address: na, }; @@ -106,18 +109,18 @@ mod tests { #[test] fn word_art_display_intro_debug() { - let na = String::from("na"); + let na = S!("na"); let args = AppEnv { - location_images: na.clone(), - location_ip_address: na.clone(), - location_log: na.clone(), + location_images: C!(na), + location_ip_address: C!(na), + location_log: C!(na), log_level: tracing::Level::DEBUG, rotation: Rotation::Zero, start_time: SystemTime::now(), - timezone: EnvTimeZone::new(String::new()), - ws_address: na.clone(), - ws_apikey: na.clone(), - ws_password: na.clone(), + timezone: EnvTimeZone::new(S!()), + ws_address: C!(na), + ws_apikey: C!(na), + ws_password: C!(na), ws_token_address: na, }; @@ -128,18 +131,18 @@ mod tests { #[test] fn word_art_display_intro() { - let na = String::from("na"); + let na = S!("na"); let args = AppEnv { - location_images: na.clone(), - location_ip_address: na.clone(), - location_log: na.clone(), + location_images: C!(na), + location_ip_address: C!(na), + location_log: C!(na), log_level: tracing::Level::INFO, rotation: Rotation::Zero, start_time: SystemTime::now(), - timezone: EnvTimeZone::new(String::new()), - ws_address: na.clone(), - ws_apikey: na.clone(), - ws_password: na.clone(), + timezone: EnvTimeZone::new(S!()), + ws_address: C!(na), + ws_apikey: C!(na), + ws_password: C!(na), ws_token_address: na, }; diff --git a/src/ws/mod.rs b/src/ws/mod.rs index dbc7558..31e95ff 100644 --- a/src/ws/mod.rs +++ b/src/ws/mod.rs @@ -14,7 +14,7 @@ use tokio::{net::TcpStream, sync::Mutex as TokioMutex, task::JoinHandle}; use tokio_tungstenite::{self, tungstenite::Message, MaybeTlsStream, WebSocketStream}; use tracing::{error, info}; -use crate::{app_env::AppEnv, camera::Camera}; +use crate::{app_env::AppEnv, camera::Camera, C}; use ws_sender::WSSender; @@ -32,7 +32,7 @@ impl AutoClose { if let Some(handle) = self.0.as_ref() { handle.abort(); }; - let ws_sender = ws_sender.clone(); + let ws_sender = C!(ws_sender); self.0 = Some(tokio::spawn(async move { tokio::time::sleep(std::time::Duration::from_secs(40)).await; ws_sender.close().await; @@ -47,7 +47,7 @@ async fn incoming_ws_message(mut reader: WSReader, ws_sender: WSSender) { while let Ok(Some(message)) = reader.try_next().await { match message { Message::Text(message) => { - let ws_sender = ws_sender.clone(); + let ws_sender = C!(ws_sender); tokio::spawn(async move { ws_sender.on_text(message).await; }); diff --git a/src/ws/ws_sender.rs b/src/ws/ws_sender.rs index 09eb21e..6e62522 100644 --- a/src/ws/ws_sender.rs +++ b/src/ws/ws_sender.rs @@ -11,6 +11,7 @@ use tokio::sync::Mutex as TokioMutex; use crate::camera::Camera; use crate::sysinfo::SysInfo; +use crate::C; use crate::{ app_env::AppEnv, ws_messages::{to_struct, MessageValues, ParsedMessage, Photo, Response, StructuredResponse}, @@ -34,7 +35,7 @@ impl WSSender { writer: Arc>, ) -> Self { Self { - app_envs: app_envs.clone(), + app_envs: C!(app_envs), camera, connected_instant, writer,