diff --git a/Cargo.lock b/Cargo.lock index 2611521..442984e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -143,7 +143,7 @@ checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.99", ] [[package]] @@ -321,7 +321,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.99", ] [[package]] @@ -346,6 +346,15 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "colored" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "compact_str" version = "0.8.1" @@ -457,7 +466,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.98", + "syn 2.0.99", ] [[package]] @@ -468,7 +477,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.98", + "syn 2.0.99", ] [[package]] @@ -500,7 +509,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.99", ] [[package]] @@ -577,7 +586,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.99", ] [[package]] @@ -613,6 +622,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enum_display_style_derive" +version = "0.1.0" +dependencies = [ + "darling", + "quote", + "syn 2.0.99", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -733,7 +751,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.99", ] [[package]] @@ -1122,7 +1140,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.99", ] [[package]] @@ -1191,7 +1209,7 @@ dependencies = [ "indoc", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.99", ] [[package]] @@ -1215,6 +1233,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.14" @@ -1340,7 +1367,7 @@ dependencies = [ "chrono", "clap", "clap_complete", - "colored", + "colored 3.0.0", "confy", "crossterm", "ctrlc", @@ -1348,10 +1375,11 @@ dependencies = [ "derive_setters", "deunicode", "dirs-next", + "enum_display_style_derive", "human-panic", "indicatif", "indoc", - "itertools", + "itertools 0.14.0", "log", "log4rs", "managarr-tree-widget", @@ -1442,7 +1470,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.99", ] [[package]] @@ -1453,7 +1481,7 @@ checksum = "652cd6d169a36eaf9d1e6bce1a221130439a966d7f27858af66a33a66e9c4ee2" dependencies = [ "assert-json-diff", "bytes", - "colored", + "colored 2.2.0", "futures-util", "http", "http-body", @@ -1566,7 +1594,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.99", ] [[package]] @@ -1745,18 +1773,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.93" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.38" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" dependencies = [ "proc-macro2", ] @@ -1803,7 +1831,7 @@ dependencies = [ "crossterm", "indoc", "instability", - "itertools", + "itertools 0.13.0", "lru", "paste", "strum", @@ -1928,21 +1956,21 @@ dependencies = [ [[package]] name = "rstest" -version = "0.23.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a2c585be59b6b5dd66a9d2084aa1d8bd52fbdb806eafdeffb52791147862035" +checksum = "6fc39292f8613e913f7df8fa892b8944ceb47c247b78e1b1ae2f09e019be789d" dependencies = [ - "futures", "futures-timer", + "futures-util", "rstest_macros", "rustc_version", ] [[package]] name = "rstest_macros" -version = "0.23.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "825ea780781b15345a146be27eaefb05085e337e869bff01b4306a4fd4a9ad5a" +checksum = "1f168d99749d307be9de54d23fd226628d99768225ef08f6ffb52e0182a27746" dependencies = [ "cfg-if", "glob", @@ -1952,7 +1980,7 @@ dependencies = [ "regex", "relative-path", "rustc_version", - "syn 2.0.98", + "syn 2.0.99", "unicode-ident", ] @@ -2121,7 +2149,7 @@ checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.99", ] [[package]] @@ -2192,7 +2220,7 @@ checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.99", ] [[package]] @@ -2299,7 +2327,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.98", + "syn 2.0.99", ] [[package]] @@ -2321,9 +2349,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.98" +version = "2.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" +checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2" dependencies = [ "proc-macro2", "quote", @@ -2347,7 +2375,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.99", ] [[package]] @@ -2418,7 +2446,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.99", ] [[package]] @@ -2488,7 +2516,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.99", ] [[package]] @@ -2637,7 +2665,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" dependencies = [ - "itertools", + "itertools 0.13.0", "unicode-segmentation", "unicode-width 0.1.14", ] @@ -2743,7 +2771,7 @@ checksum = "5b2d5567b6fbd34e8f0488d56b648e67c0d999535f4af2060d14f9074b43e833" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.99", ] [[package]] @@ -2801,7 +2829,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.99", "wasm-bindgen-shared", ] @@ -2836,7 +2864,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.99", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3141,7 +3169,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.99", "synstructure", ] @@ -3163,7 +3191,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.99", ] [[package]] @@ -3183,7 +3211,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.99", "synstructure", ] @@ -3212,5 +3240,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.98", + "syn 2.0.99", ] diff --git a/Cargo.toml b/Cargo.toml index 06a0153..acc18ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,9 @@ license = "MIT" rust-version = "1.82.0" exclude = [".github", "CONTRIBUTING.md", "*.log", "tags"] +[workspace] +members = ["proc_macros/enum_display_style_derive"] + [dependencies] anyhow = "1.0.68" backtrace = "0.3.74" @@ -41,11 +44,16 @@ ratatui = { version = "0.29.0", features = [ "unstable-widget-ref", ] } urlencoding = "2.1.2" -clap = { version = "4.5.20", features = ["derive", "cargo", "env", "wrap_help"] } +clap = { version = "4.5.20", features = [ + "derive", + "cargo", + "env", + "wrap_help", +] } clap_complete = "4.5.33" -itertools = "0.13.0" +itertools = "0.14.0" ctrlc = "3.4.5" -colored = "2.1.0" +colored = "3.0.0" async-trait = "0.1.83" dirs-next = "2.0.0" managarr-tree-widget = "0.24.0" @@ -55,13 +63,14 @@ deunicode = "1.6.0" paste = "1.0.15" openssl = { version = "0.10.70", features = ["vendored"] } veil = "0.2.0" +enum_display_style_derive = { path = "proc_macros/enum_display_style_derive" } [dev-dependencies] assert_cmd = "2.0.16" mockall = "0.13.0" mockito = "1.0.0" pretty_assertions = "1.3.0" -rstest = "0.23.0" +rstest = "0.25.0" serial_test = "3.2.0" [dev-dependencies.cargo-husky] diff --git a/Makefile b/Makefile index 5f224d4..31fce58 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ default: run .PHONY: test test-cov build run lint lint-fix fmt analyze sonar release delete-tag test: - @cargo test + @cargo test --all ## Run all tests with coverage - `cargo install cargo-tarpaulin` test-cov: diff --git a/proc_macros/enum_display_style_derive/Cargo.toml b/proc_macros/enum_display_style_derive/Cargo.toml new file mode 100644 index 0000000..5c4a7fe --- /dev/null +++ b/proc_macros/enum_display_style_derive/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "enum_display_style_derive" +version = "0.1.0" +edition = "2024" + +[lib] +proc-macro = true + +[dependencies] +quote = "1.0.39" +syn = "2.0.99" +darling = "0.20.10" diff --git a/proc_macros/enum_display_style_derive/src/lib.rs b/proc_macros/enum_display_style_derive/src/lib.rs new file mode 100644 index 0000000..1e02028 --- /dev/null +++ b/proc_macros/enum_display_style_derive/src/lib.rs @@ -0,0 +1,73 @@ +mod macro_models; + +use crate::macro_models::DisplayStyleArgs; +use darling::FromVariant; +use quote::quote; +use syn::{parse_macro_input, Data, DeriveInput}; +/// Derive macro for the EnumDisplayStyle trait. +/// +/// # Example +/// +/// Using default values for the display style: +/// +/// ``` +/// use enum_display_style_derive::EnumDisplayStyle; +/// +/// #[derive(EnumDisplayStyle)] +/// enum Weekend { +/// Saturday, +/// Sunday, +/// } +/// +/// assert_eq!(Weekend::Saturday.to_display_str(), "Saturday"); +/// assert_eq!(Weekend::Sunday.to_display_str(), "Sunday"); +/// +/// ``` +/// +/// Using custom values for the display style: +/// +/// ``` +/// use enum_display_style_derive::EnumDisplayStyle; +/// +/// #[derive(EnumDisplayStyle)] +/// enum MonitorStatus { +/// #[display_style(name = "Monitor Transactions")] +/// Active, +/// #[display_style(name = "Don't Monitor Transactions")] +/// None, +/// } +/// +/// assert_eq!(MonitorStatus::Active.to_display_str(), "Monitor Transactions"); +/// assert_eq!(MonitorStatus::None.to_display_str(), "Don't Monitor Transactions"); +/// ``` +#[proc_macro_derive(EnumDisplayStyle, attributes(display_style))] +pub fn enum_display_style_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let enum_name = &input.ident; + + let mut match_arms = Vec::new(); + + if let Data::Enum(data_enum) = &input.data { + let variants = &data_enum.variants; + + for variant in variants { + let variant_ident = &variant.ident; + let variant_display_name = DisplayStyleArgs::from_variant(variant).unwrap().name.unwrap_or_else(|| variant_ident.to_string()); + + match_arms.push(quote! { + #enum_name::#variant_ident => #variant_display_name, + }); + } + } + + quote! { + impl<'a> #enum_name { + pub fn to_display_str(self) -> &'a str { + match self { + #(#match_arms)* + } + } + } + } + .into() +} \ No newline at end of file diff --git a/proc_macros/enum_display_style_derive/src/macro_models.rs b/proc_macros/enum_display_style_derive/src/macro_models.rs new file mode 100644 index 0000000..469f030 --- /dev/null +++ b/proc_macros/enum_display_style_derive/src/macro_models.rs @@ -0,0 +1,7 @@ +use darling::FromVariant; + +#[derive(Debug, FromVariant)] +#[darling(attributes(display_style))] +pub struct DisplayStyleArgs { + pub name: Option +} \ No newline at end of file diff --git a/src/models/mod.rs b/src/models/mod.rs index 6635e5a..75cb072 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -42,10 +42,6 @@ pub enum Serdeable { Sonarr(SonarrSerdeable), } -pub trait EnumDisplayStyle<'a> { - fn to_display_str(self) -> &'a str; -} - pub trait Scrollable { fn scroll_down(&mut self); fn scroll_up(&mut self); diff --git a/src/models/radarr_models.rs b/src/models/radarr_models.rs index 8e8b235..d89af1b 100644 --- a/src/models/radarr_models.rs +++ b/src/models/radarr_models.rs @@ -1,19 +1,19 @@ use std::fmt::{Display, Formatter}; +use crate::{models::HorizontallyScrollableText, serde_enum_from}; use chrono::{DateTime, Utc}; use clap::ValueEnum; use derivative::Derivative; +use enum_display_style_derive::EnumDisplayStyle; use serde::{Deserialize, Serialize}; use serde_json::{Number, Value}; -use strum_macros::EnumIter; - -use crate::{models::HorizontallyScrollableText, serde_enum_from}; +use strum_macros::{Display, EnumIter}; use super::servarr_models::{ DiskSpace, HostConfig, Indexer, Language, LogResponse, QualityProfile, QualityWrapper, QueueEvent, RootFolder, SecurityConfig, Tag, Update, }; -use super::{EnumDisplayStyle, Serdeable}; +use super::Serdeable; #[cfg(test)] #[path = "radarr_models_tests.rs"] @@ -258,69 +258,44 @@ pub struct MediaInfo { } #[derive( - Serialize, Deserialize, Default, PartialEq, Eq, Clone, Copy, Debug, EnumIter, ValueEnum, + Serialize, + Deserialize, + Default, + PartialEq, + Eq, + Clone, + Copy, + Debug, + EnumIter, + ValueEnum, + Display, + EnumDisplayStyle, )] #[serde(rename_all = "camelCase")] +#[strum(serialize_all = "camelCase")] pub enum MinimumAvailability { #[default] Announced, + #[display_style(name = "In Cinemas")] InCinemas, Released, + #[display_style(name = "TBA")] Tba, } -impl Display for MinimumAvailability { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let minimum_availability = match self { - MinimumAvailability::Tba => "tba", - MinimumAvailability::Announced => "announced", - MinimumAvailability::InCinemas => "inCinemas", - MinimumAvailability::Released => "released", - }; - write!(f, "{minimum_availability}") - } -} - -impl<'a> EnumDisplayStyle<'a> for MinimumAvailability { - fn to_display_str(self) -> &'a str { - match self { - MinimumAvailability::Tba => "TBA", - MinimumAvailability::Announced => "Announced", - MinimumAvailability::InCinemas => "In Cinemas", - MinimumAvailability::Released => "Released", - } - } -} - -#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, EnumIter, ValueEnum)] +#[derive( + Default, PartialEq, Eq, Clone, Copy, Debug, EnumIter, ValueEnum, Display, EnumDisplayStyle, +)] +#[strum(serialize_all = "camelCase")] pub enum MovieMonitor { #[default] + #[display_style(name = "Movie only")] MovieOnly, + #[display_style(name = "Movie and Collection")] MovieAndCollection, None, } -impl Display for MovieMonitor { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let monitor = match self { - MovieMonitor::MovieOnly => "movieOnly", - MovieMonitor::MovieAndCollection => "movieAndCollection", - MovieMonitor::None => "none", - }; - write!(f, "{monitor}") - } -} - -impl<'a> EnumDisplayStyle<'a> for MovieMonitor { - fn to_display_str(self) -> &'a str { - match self { - MovieMonitor::MovieOnly => "Movie only", - MovieMonitor::MovieAndCollection => "Movie and Collection", - MovieMonitor::None => "None", - } - } -} - #[derive(Derivative, Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct Movie { diff --git a/src/models/radarr_models_tests.rs b/src/models/radarr_models_tests.rs index b260344..2a611e8 100644 --- a/src/models/radarr_models_tests.rs +++ b/src/models/radarr_models_tests.rs @@ -11,7 +11,7 @@ mod tests { RadarrSerdeable, RadarrTask, RadarrTaskName, SystemStatus, Tag, Update, }, servarr_models::{HostConfig, Log, LogResponse, QueueEvent, RootFolder, SecurityConfig}, - EnumDisplayStyle, Serdeable, + Serdeable, }; #[test] diff --git a/src/models/sonarr_models.rs b/src/models/sonarr_models.rs index c41b301..4e0dbc2 100644 --- a/src/models/sonarr_models.rs +++ b/src/models/sonarr_models.rs @@ -1,13 +1,14 @@ use std::fmt::{Display, Formatter}; +use crate::serde_enum_from; use chrono::{DateTime, Utc}; use clap::ValueEnum; use derivative::Derivative; +use enum_display_style_derive::EnumDisplayStyle; use serde::{Deserialize, Serialize}; use serde_json::{Number, Value}; use strum::EnumIter; - -use crate::serde_enum_from; +use strum_macros::Display; use super::{ radarr_models::IndexerTestResult, @@ -15,7 +16,7 @@ use super::{ DiskSpace, HostConfig, Indexer, Language, LogResponse, QualityProfile, QualityWrapper, QueueEvent, RootFolder, SecurityConfig, Tag, Update, }, - EnumDisplayStyle, HorizontallyScrollableText, Serdeable, + HorizontallyScrollableText, Serdeable, }; #[cfg(test)] @@ -125,8 +126,21 @@ pub struct DownloadRecord { impl Eq for DownloadRecord {} -#[derive(Serialize, Deserialize, Default, PartialEq, Eq, Clone, Copy, Debug, EnumIter)] +#[derive( + Serialize, + Deserialize, + Default, + PartialEq, + Eq, + Clone, + Copy, + Debug, + EnumIter, + Display, + EnumDisplayStyle, +)] #[serde(rename_all = "camelCase")] +#[strum(serialize_all = "camelCase")] pub enum DownloadStatus { #[default] Unknown, @@ -137,45 +151,11 @@ pub enum DownloadStatus { Failed, Warning, Delay, + #[display_style(name = "Download Client Unavailable")] DownloadClientUnavailable, Fallback, } -impl Display for DownloadStatus { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let download_status = match self { - DownloadStatus::Unknown => "unknown", - DownloadStatus::Queued => "queued", - DownloadStatus::Paused => "paused", - DownloadStatus::Downloading => "downloading", - DownloadStatus::Completed => "completed", - DownloadStatus::Failed => "failed", - DownloadStatus::Warning => "warning", - DownloadStatus::Delay => "delay", - DownloadStatus::DownloadClientUnavailable => "downloadClientUnavailable", - DownloadStatus::Fallback => "fallback", - }; - write!(f, "{download_status}") - } -} - -impl<'a> EnumDisplayStyle<'a> for DownloadStatus { - fn to_display_str(self) -> &'a str { - match self { - DownloadStatus::Unknown => "Unknown", - DownloadStatus::Queued => "Queued", - DownloadStatus::Paused => "Paused", - DownloadStatus::Downloading => "Downloading", - DownloadStatus::Completed => "Completed", - DownloadStatus::Failed => "Failed", - DownloadStatus::Warning => "Warning", - DownloadStatus::Delay => "Delay", - DownloadStatus::DownloadClientUnavailable => "Download Client Unavailable", - DownloadStatus::Fallback => "Fallback", - } - } -} - #[derive(Default, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct DownloadsResponse { @@ -363,74 +343,66 @@ pub struct Series { } #[derive( - Serialize, Deserialize, Default, PartialEq, Eq, Clone, Copy, Debug, EnumIter, ValueEnum, + Serialize, + Deserialize, + Default, + PartialEq, + Eq, + Clone, + Copy, + Debug, + EnumIter, + ValueEnum, + Display, + EnumDisplayStyle, )] #[serde(rename_all = "camelCase")] +#[strum(serialize_all = "camelCase")] pub enum SeriesMonitor { #[default] + #[display_style(name = "All Episodes")] All, Unknown, + #[display_style(name = "Future Episodes")] Future, + #[display_style(name = "Missing Episodes")] Missing, + #[display_style(name = "Existing Episodes")] Existing, + #[display_style(name = "Only First Season")] FirstSeason, + #[display_style(name = "Only Last Season")] LastSeason, + #[display_style(name = "Only Latest Season")] LatestSeason, + #[display_style(name = "Pilot Episode")] Pilot, + #[display_style(name = "Recent Episodes")] Recent, + #[display_style(name = "Only Specials")] MonitorSpecials, + #[display_style(name = "Not Specials")] UnmonitorSpecials, None, Skip, } -impl Display for SeriesMonitor { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let series_monitor = match self { - SeriesMonitor::Unknown => "unknown", - SeriesMonitor::All => "all", - SeriesMonitor::Future => "future", - SeriesMonitor::Missing => "missing", - SeriesMonitor::Existing => "existing", - SeriesMonitor::FirstSeason => "firstSeason", - SeriesMonitor::LastSeason => "lastSeason", - SeriesMonitor::LatestSeason => "latestSeason", - SeriesMonitor::Pilot => "pilot", - SeriesMonitor::Recent => "recent", - SeriesMonitor::MonitorSpecials => "monitorSpecials", - SeriesMonitor::UnmonitorSpecials => "unmonitorSpecials", - SeriesMonitor::None => "none", - SeriesMonitor::Skip => "skip", - }; - write!(f, "{series_monitor}") - } -} - -impl<'a> EnumDisplayStyle<'a> for SeriesMonitor { - fn to_display_str(self) -> &'a str { - match self { - SeriesMonitor::Unknown => "Unknown", - SeriesMonitor::All => "All Episodes", - SeriesMonitor::Future => "Future Episodes", - SeriesMonitor::Missing => "Missing Episodes", - SeriesMonitor::Existing => "Existing Episodes", - SeriesMonitor::FirstSeason => "Only First Season", - SeriesMonitor::LastSeason => "Only Last Season", - SeriesMonitor::LatestSeason => "Only Latest Season", - SeriesMonitor::Pilot => "Pilot Episode", - SeriesMonitor::Recent => "Recent Episodes", - SeriesMonitor::MonitorSpecials => "Only Specials", - SeriesMonitor::UnmonitorSpecials => "Not Specials", - SeriesMonitor::None => "None", - SeriesMonitor::Skip => "Skip", - } - } -} - #[derive( - Serialize, Deserialize, Default, PartialEq, Eq, Clone, Copy, Debug, EnumIter, ValueEnum, + Serialize, + Deserialize, + Default, + PartialEq, + Eq, + Clone, + Copy, + Debug, + EnumIter, + ValueEnum, + Display, + EnumDisplayStyle, )] #[serde(rename_all = "camelCase")] +#[strum(serialize_all = "camelCase")] pub enum SeriesType { #[default] Standard, @@ -438,27 +410,6 @@ pub enum SeriesType { Anime, } -impl Display for SeriesType { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let series_type = match self { - SeriesType::Standard => "standard", - SeriesType::Daily => "daily", - SeriesType::Anime => "anime", - }; - write!(f, "{series_type}") - } -} - -impl<'a> EnumDisplayStyle<'a> for SeriesType { - fn to_display_str(self) -> &'a str { - match self { - SeriesType::Standard => "Standard", - SeriesType::Daily => "Daily", - SeriesType::Anime => "Anime", - } - } -} - #[derive(Derivative, Serialize, Deserialize, Debug, Default, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct SeriesStatistics { @@ -478,8 +429,21 @@ pub struct SeriesStatistics { impl Eq for SeriesStatistics {} -#[derive(Serialize, Deserialize, Default, PartialEq, Eq, Clone, Copy, Debug, EnumIter)] +#[derive( + Serialize, + Deserialize, + Default, + PartialEq, + Eq, + Clone, + Copy, + Debug, + EnumIter, + Display, + EnumDisplayStyle, +)] #[serde(rename_all = "camelCase")] +#[strum(serialize_all = "camelCase")] pub enum SeriesStatus { #[default] Continuing, @@ -488,29 +452,6 @@ pub enum SeriesStatus { Deleted, } -impl Display for SeriesStatus { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let series_status = match self { - SeriesStatus::Continuing => "continuing", - SeriesStatus::Ended => "ended", - SeriesStatus::Upcoming => "upcoming", - SeriesStatus::Deleted => "deleted", - }; - write!(f, "{series_status}") - } -} - -impl<'a> EnumDisplayStyle<'a> for SeriesStatus { - fn to_display_str(self) -> &'a str { - match self { - SeriesStatus::Continuing => "Continuing", - SeriesStatus::Ended => "Ended", - SeriesStatus::Upcoming => "Upcoming", - SeriesStatus::Deleted => "Deleted", - } - } -} - #[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct SonarrHistoryWrapper { @@ -537,51 +478,29 @@ pub struct SonarrHistoryData { pub relative_path: Option, } -#[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq)] +#[derive( + Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq, Display, EnumDisplayStyle, +)] #[serde(rename_all = "camelCase")] +#[strum(serialize_all = "camelCase")] pub enum SonarrHistoryEventType { #[default] Unknown, Grabbed, + #[display_style(name = "Series Folder Imported")] SeriesFolderImported, + #[display_style(name = "Download Folder Imported")] DownloadFolderImported, + #[display_style(name = "Download Failed")] DownloadFailed, + #[display_style(name = "Episode File Deleted")] EpisodeFileDeleted, + #[display_style(name = "Episode File Renamed")] EpisodeFileRenamed, + #[display_style(name = "Download Ignored")] DownloadIgnored, } -impl Display for SonarrHistoryEventType { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let event_type = match self { - SonarrHistoryEventType::Unknown => "unknown", - SonarrHistoryEventType::Grabbed => "grabbed", - SonarrHistoryEventType::SeriesFolderImported => "seriesFolderImported", - SonarrHistoryEventType::DownloadFolderImported => "downloadFolderImported", - SonarrHistoryEventType::DownloadFailed => "downloadFailed", - SonarrHistoryEventType::EpisodeFileDeleted => "episodeFileDeleted", - SonarrHistoryEventType::EpisodeFileRenamed => "episodeFileRenamed", - SonarrHistoryEventType::DownloadIgnored => "downloadIgnored", - }; - write!(f, "{event_type}") - } -} - -impl<'a> EnumDisplayStyle<'a> for SonarrHistoryEventType { - fn to_display_str(self) -> &'a str { - match self { - SonarrHistoryEventType::Unknown => "Unknown", - SonarrHistoryEventType::Grabbed => "Grabbed", - SonarrHistoryEventType::SeriesFolderImported => "Series Folder Imported", - SonarrHistoryEventType::DownloadFolderImported => "Download Folder Imported", - SonarrHistoryEventType::DownloadFailed => "Download Failed", - SonarrHistoryEventType::EpisodeFileDeleted => "Episode File Deleted", - SonarrHistoryEventType::EpisodeFileRenamed => "Episode File Renamed", - SonarrHistoryEventType::DownloadIgnored => "Download Ignored", - } - } -} - #[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct SonarrHistoryItem { diff --git a/src/models/sonarr_models_tests.rs b/src/models/sonarr_models_tests.rs index 0c1ea46..be82201 100644 --- a/src/models/sonarr_models_tests.rs +++ b/src/models/sonarr_models_tests.rs @@ -15,7 +15,7 @@ mod tests { SeriesStatus, SeriesType, SonarrHistoryEventType, SonarrHistoryItem, SonarrRelease, SonarrSerdeable, SonarrTask, SonarrTaskName, SystemStatus, }, - EnumDisplayStyle, Serdeable, + Serdeable, }; #[test] diff --git a/src/ui/radarr_ui/collections/collection_details_ui.rs b/src/ui/radarr_ui/collections/collection_details_ui.rs index 5f5f3e1..cdd434f 100644 --- a/src/ui/radarr_ui/collections/collection_details_ui.rs +++ b/src/ui/radarr_ui/collections/collection_details_ui.rs @@ -11,7 +11,7 @@ use crate::models::radarr_models::CollectionMovie; use crate::models::servarr_data::radarr::radarr_data::{ ActiveRadarrBlock, COLLECTION_DETAILS_BLOCKS, }; -use crate::models::{EnumDisplayStyle, Route}; +use crate::models::Route; use crate::ui::styles::ManagarrStyle; use crate::ui::utils::{ borderless_block, get_width_from_percentage, layout_block_top_border_with_title, title_block, diff --git a/src/ui/radarr_ui/collections/edit_collection_ui.rs b/src/ui/radarr_ui/collections/edit_collection_ui.rs index 765bad3..54bab3a 100644 --- a/src/ui/radarr_ui/collections/edit_collection_ui.rs +++ b/src/ui/radarr_ui/collections/edit_collection_ui.rs @@ -10,7 +10,7 @@ use crate::models::servarr_data::radarr::modals::EditCollectionModal; use crate::models::servarr_data::radarr::radarr_data::{ ActiveRadarrBlock, COLLECTION_DETAILS_BLOCKS, EDIT_COLLECTION_BLOCKS, }; -use crate::models::{EnumDisplayStyle, Route}; +use crate::models::Route; use crate::render_selectable_input_box; use crate::ui::radarr_ui::collections::collection_details_ui::CollectionDetailsUi; use crate::ui::styles::ManagarrStyle; diff --git a/src/ui/radarr_ui/library/add_movie_ui.rs b/src/ui/radarr_ui/library/add_movie_ui.rs index c3670f9..a7e4608 100644 --- a/src/ui/radarr_ui/library/add_movie_ui.rs +++ b/src/ui/radarr_ui/library/add_movie_ui.rs @@ -12,7 +12,7 @@ use crate::app::radarr::radarr_context_clues::ADD_MOVIE_SEARCH_RESULTS_CONTEXT_C use crate::models::radarr_models::AddMovieSearchResult; use crate::models::servarr_data::radarr::modals::AddMovieModal; use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, ADD_MOVIE_BLOCKS}; -use crate::models::{EnumDisplayStyle, Route}; +use crate::models::Route; use crate::ui::radarr_ui::collections::CollectionsUi; use crate::ui::styles::ManagarrStyle; use crate::ui::utils::{ diff --git a/src/ui/radarr_ui/library/edit_movie_ui.rs b/src/ui/radarr_ui/library/edit_movie_ui.rs index 09ba302..18fc10c 100644 --- a/src/ui/radarr_ui/library/edit_movie_ui.rs +++ b/src/ui/radarr_ui/library/edit_movie_ui.rs @@ -12,7 +12,7 @@ use crate::models::servarr_data::radarr::modals::EditMovieModal; use crate::models::servarr_data::radarr::radarr_data::{ ActiveRadarrBlock, EDIT_MOVIE_BLOCKS, MOVIE_DETAILS_BLOCKS, }; -use crate::models::{EnumDisplayStyle, Route}; +use crate::models::Route; use crate::render_selectable_input_box; use crate::ui::radarr_ui::library::movie_details_ui::MovieDetailsUi; diff --git a/src/ui/sonarr_ui/library/add_series_ui.rs b/src/ui/sonarr_ui/library/add_series_ui.rs index 3d95fbd..34384d0 100644 --- a/src/ui/sonarr_ui/library/add_series_ui.rs +++ b/src/ui/sonarr_ui/library/add_series_ui.rs @@ -12,7 +12,7 @@ use crate::app::sonarr::sonarr_context_clues::ADD_SERIES_SEARCH_RESULTS_CONTEXT_ use crate::models::servarr_data::sonarr::modals::AddSeriesModal; use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, ADD_SERIES_BLOCKS}; use crate::models::sonarr_models::AddSeriesSearchResult; -use crate::models::{EnumDisplayStyle, Route}; +use crate::models::Route; use crate::ui::styles::ManagarrStyle; use crate::ui::utils::{ borderless_block, get_width_from_percentage, layout_block, layout_paragraph_borderless, diff --git a/src/ui/sonarr_ui/library/edit_series_ui.rs b/src/ui/sonarr_ui/library/edit_series_ui.rs index 74095da..0b6fee4 100644 --- a/src/ui/sonarr_ui/library/edit_series_ui.rs +++ b/src/ui/sonarr_ui/library/edit_series_ui.rs @@ -12,7 +12,7 @@ use crate::models::servarr_data::sonarr::modals::EditSeriesModal; use crate::models::servarr_data::sonarr::sonarr_data::{ ActiveSonarrBlock, EDIT_SERIES_BLOCKS, SERIES_DETAILS_BLOCKS, }; -use crate::models::{EnumDisplayStyle, Route}; +use crate::models::Route; use crate::render_selectable_input_box; use crate::ui::styles::ManagarrStyle; diff --git a/src/ui/sonarr_ui/library/mod.rs b/src/ui/sonarr_ui/library/mod.rs index a29ec77..a31482c 100644 --- a/src/ui/sonarr_ui/library/mod.rs +++ b/src/ui/sonarr_ui/library/mod.rs @@ -17,7 +17,7 @@ use crate::{ models::{ servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, LIBRARY_BLOCKS}, sonarr_models::{Series, SeriesStatus}, - EnumDisplayStyle, Route, + Route, }, ui::{ styles::ManagarrStyle, diff --git a/src/ui/sonarr_ui/library/series_details_ui.rs b/src/ui/sonarr_ui/library/series_details_ui.rs index ddeee4e..d4965a7 100644 --- a/src/ui/sonarr_ui/library/series_details_ui.rs +++ b/src/ui/sonarr_ui/library/series_details_ui.rs @@ -12,7 +12,7 @@ use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, SERIES use crate::models::sonarr_models::{ Season, SeasonStatistics, SonarrHistoryEventType, SonarrHistoryItem, }; -use crate::models::{EnumDisplayStyle, Route}; +use crate::models::Route; use crate::ui::sonarr_ui::library::episode_details_ui::EpisodeDetailsUi; use crate::ui::sonarr_ui::library::season_details_ui::SeasonDetailsUi; use crate::ui::sonarr_ui::sonarr_ui_utils::{ diff --git a/tests/integration_test.rs b/tests/integration_test.rs new file mode 100644 index 0000000..db427fa --- /dev/null +++ b/tests/integration_test.rs @@ -0,0 +1,15 @@ +use enum_display_style_derive::EnumDisplayStyle; +use pretty_assertions::assert_str_eq; + +#[test] +fn test_derive_enum_display_style() { + assert_str_eq!(TestEnum::Test.to_display_str(), "Testing 123"); + assert_str_eq!(TestEnum::Ignored.to_display_str(), "Ignored"); +} + +#[derive(EnumDisplayStyle)] +pub enum TestEnum { + #[display_style(name = "Testing 123")] + Test, + Ignored, +} \ No newline at end of file