use serde::{Deserialize, Serialize}; use crate::{RenameContext, RenameRule}; #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)] pub enum SwapOccurrence { #[default] First, Last, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SwapRule { pub delimiter: String, pub occurrence: SwapOccurrence, #[serde(default)] pub new_delimiter: Option, pub enabled: bool, } impl SwapRule { pub fn new() -> Self { Self { delimiter: ", ".into(), occurrence: SwapOccurrence::First, new_delimiter: None, enabled: true, } } } impl RenameRule for SwapRule { fn apply(&self, filename: &str, _context: &RenameContext) -> String { if self.delimiter.is_empty() { return filename.to_string(); } let pos = match self.occurrence { SwapOccurrence::First => filename.find(&self.delimiter), SwapOccurrence::Last => filename.rfind(&self.delimiter), }; let pos = match pos { Some(p) => p, None => return filename.to_string(), }; let left = &filename[..pos]; let right = &filename[pos + self.delimiter.len()..]; let joiner = self.new_delimiter.as_deref().unwrap_or(&self.delimiter); format!("{}{}{}", right, joiner, left) } fn display_name(&self) -> &str { "Swap" } fn rule_type(&self) -> &str { "swap" } fn is_enabled(&self) -> bool { self.enabled } } #[cfg(test)] mod tests { use super::*; fn ctx() -> RenameContext { RenameContext::dummy(0) } #[test] fn swap_comma_space() { let rule = SwapRule::new(); assert_eq!(rule.apply("LastName, FirstName", &ctx()), "FirstName, LastName"); } #[test] fn swap_with_new_delimiter() { let rule = SwapRule { new_delimiter: Some(" ".into()), ..SwapRule::new() }; assert_eq!(rule.apply("LastName, FirstName", &ctx()), "FirstName LastName"); } #[test] fn swap_first_occurrence() { let rule = SwapRule { delimiter: "-".into(), occurrence: SwapOccurrence::First, ..SwapRule::new() }; assert_eq!(rule.apply("a-b-c", &ctx()), "b-c-a"); } #[test] fn swap_last_occurrence() { let rule = SwapRule { delimiter: "-".into(), occurrence: SwapOccurrence::Last, ..SwapRule::new() }; assert_eq!(rule.apply("a-b-c", &ctx()), "c-a-b"); } #[test] fn no_delimiter_found() { let rule = SwapRule::new(); assert_eq!(rule.apply("nodelimiter", &ctx()), "nodelimiter"); } }