diff --git a/src/library/beets.rs b/src/library/beets.rs index e9c1f2e..b042e6f 100644 --- a/src/library/beets.rs +++ b/src/library/beets.rs @@ -16,6 +16,33 @@ use crate::{Album, AlbumId, Artist, ArtistId, Track, TrackFormat}; use super::{Error, Library, Query, QueryOption}; +macro_rules! list_format_separator { + () => { + " -*^- " + }; +} + +const CMD_LIST: &str = "ls"; +const LIST_FORMAT_SEPARATOR: &str = list_format_separator!(); +const LIST_FORMAT_ARG: &str = concat!( + "--format=", + "$albumartist", + list_format_separator!(), + "$year", + list_format_separator!(), + "$album", + list_format_separator!(), + "$track", + list_format_separator!(), + "$title", + list_format_separator!(), + "$artist", + list_format_separator!(), + "$format" +); +const TRACK_FORMAT_FLAC: &str = "FLAC"; +const TRACK_FORMAT_MP3: &str = "MP3"; + trait QueryOptionArgBeets { fn to_arg(&self, option_name: &str) -> Option; } @@ -94,29 +121,23 @@ pub trait BeetsLibraryExecutor { } /// Beets library. -pub struct BeetsLibrary { - executor: Box, +pub struct BeetsLibrary { + executor: BLE, } trait LibraryPrivate { - const CMD_LIST: &'static str; - const LIST_FORMAT_SEPARATOR: &'static str; - const LIST_FORMAT_ARG: &'static str; - const TRACK_FORMAT_FLAC: &'static str; - const TRACK_FORMAT_MP3: &'static str; - fn list_cmd_and_args(query: &Query) -> Vec; fn list_to_artists(list_output: Vec) -> Result, Error>; } -impl BeetsLibrary { +impl BeetsLibrary { /// Create a new beets library with the provided executor, e.g. [`BeetsLibraryCommandExecutor`]. - pub fn new(executor: Box) -> BeetsLibrary { + pub fn new(executor: BLE) -> Self { BeetsLibrary { executor } } } -impl Library for BeetsLibrary { +impl Library for BeetsLibrary { fn list(&mut self, query: &Query) -> Result, Error> { let cmd = Self::list_cmd_and_args(query); let output = self.executor.exec(&cmd)?; @@ -124,37 +145,10 @@ impl Library for BeetsLibrary { } } -macro_rules! list_format_separator { - () => { - " -*^- " - }; -} - -impl LibraryPrivate for BeetsLibrary { - const CMD_LIST: &'static str = "ls"; - const LIST_FORMAT_SEPARATOR: &'static str = list_format_separator!(); - const LIST_FORMAT_ARG: &'static str = concat!( - "--format=", - "$albumartist", - list_format_separator!(), - "$year", - list_format_separator!(), - "$album", - list_format_separator!(), - "$track", - list_format_separator!(), - "$title", - list_format_separator!(), - "$artist", - list_format_separator!(), - "$format" - ); - const TRACK_FORMAT_FLAC: &'static str = "FLAC"; - const TRACK_FORMAT_MP3: &'static str = "MP3"; - +impl LibraryPrivate for BeetsLibrary { fn list_cmd_and_args(query: &Query) -> Vec { - let mut cmd: Vec = vec![String::from(Self::CMD_LIST)]; - cmd.push(Self::LIST_FORMAT_ARG.to_string()); + let mut cmd: Vec = vec![String::from(CMD_LIST)]; + cmd.push(LIST_FORMAT_ARG.to_string()); cmd.append(&mut query.to_args()); cmd } @@ -168,7 +162,7 @@ impl LibraryPrivate for BeetsLibrary { continue; } - let split: Vec<&str> = line.split(Self::LIST_FORMAT_SEPARATOR).collect(); + let split: Vec<&str> = line.split(LIST_FORMAT_SEPARATOR).collect(); if split.len() != 7 { return Err(Error::InvalidData(line.to_string())); } @@ -193,8 +187,8 @@ impl LibraryPrivate for BeetsLibrary { title: track_title, artist: track_artist.split("; ").map(|s| s.to_owned()).collect(), format: match track_format.as_ref() { - Self::TRACK_FORMAT_FLAC => TrackFormat::Flac, - Self::TRACK_FORMAT_MP3 => TrackFormat::Mp3, + TRACK_FORMAT_FLAC => TrackFormat::Flac, + TRACK_FORMAT_MP3 => TrackFormat::Mp3, _ => return Err(Error::InvalidData(track_format)), }, }; @@ -309,14 +303,14 @@ mod tests { let track_title = &track.title; let track_artist = &track.artist.join("; "); let track_format = match track.format { - TrackFormat::Flac => BeetsLibrary::TRACK_FORMAT_FLAC, - TrackFormat::Mp3 => BeetsLibrary::TRACK_FORMAT_MP3, + TrackFormat::Flac => TRACK_FORMAT_FLAC, + TrackFormat::Mp3 => TRACK_FORMAT_MP3, }; strings.push(format!( "{album_artist}{0}{album_year}{0}{album_title}{0}\ {track_number}{0}{track_title}{0}{track_artist}{0}{track_format}", - BeetsLibrary::LIST_FORMAT_SEPARATOR, + LIST_FORMAT_SEPARATOR, )); } } @@ -356,7 +350,7 @@ mod tests { #[test] fn test_list_empty() { - let arguments = vec!["ls".to_string(), BeetsLibrary::LIST_FORMAT_ARG.to_string()]; + let arguments = vec!["ls".to_string(), LIST_FORMAT_ARG.to_string()]; let result = Ok(vec![]); let mut executor = MockBeetsLibraryExecutor::new(); @@ -366,7 +360,7 @@ mod tests { .times(1) .return_once(|_| result); - let mut beets = BeetsLibrary::new(Box::new(executor)); + let mut beets = BeetsLibrary::new(executor); let output = beets.list(&Query::default()).unwrap(); let expected: Vec = vec![]; @@ -375,7 +369,7 @@ mod tests { #[test] fn test_list_ordered() { - let arguments = vec!["ls".to_string(), BeetsLibrary::LIST_FORMAT_ARG.to_string()]; + let arguments = vec!["ls".to_string(), LIST_FORMAT_ARG.to_string()]; let expected = COLLECTION.to_owned(); let result = Ok(artists_to_beets_string(&expected)); @@ -386,7 +380,7 @@ mod tests { .times(1) .return_once(|_| result); - let mut beets = BeetsLibrary::new(Box::new(executor)); + let mut beets = BeetsLibrary::new(executor); let output = beets.list(&Query::default()).unwrap(); assert_eq!(output, expected); @@ -394,7 +388,7 @@ mod tests { #[test] fn test_list_unordered() { - let arguments = vec!["ls".to_string(), BeetsLibrary::LIST_FORMAT_ARG.to_string()]; + let arguments = vec!["ls".to_string(), LIST_FORMAT_ARG.to_string()]; let mut expected = COLLECTION.to_owned(); let mut output = artists_to_beets_string(&expected); let last = output.len() - 1; @@ -421,7 +415,7 @@ mod tests { .times(1) .return_once(|_| result); - let mut beets = BeetsLibrary::new(Box::new(executor)); + let mut beets = BeetsLibrary::new(executor); let output = beets.list(&Query::default()).unwrap(); assert_eq!(output, expected); @@ -429,7 +423,7 @@ mod tests { #[test] fn test_list_album_title_year_clash() { - let arguments = vec!["ls".to_string(), BeetsLibrary::LIST_FORMAT_ARG.to_string()]; + let arguments = vec!["ls".to_string(), LIST_FORMAT_ARG.to_string()]; let mut expected = COLLECTION.to_owned(); expected[0].albums[0].id.year = expected[1].albums[0].id.year; expected[0].albums[0].id.title = expected[1].albums[0].id.title.clone(); @@ -443,7 +437,7 @@ mod tests { .times(1) .return_once(|_| result); - let mut beets = BeetsLibrary::new(Box::new(executor)); + let mut beets = BeetsLibrary::new(executor); let output = beets.list(&Query::default()).unwrap(); assert_eq!(output, expected); @@ -458,7 +452,7 @@ mod tests { let arguments = vec![ "ls".to_string(), - BeetsLibrary::LIST_FORMAT_ARG.to_string(), + LIST_FORMAT_ARG.to_string(), String::from("^album:some.album"), String::from("track:5"), String::from("artist:some.artist"), @@ -472,7 +466,7 @@ mod tests { .times(1) .return_once(|_| result); - let mut beets = BeetsLibrary::new(Box::new(executor)); + let mut beets = BeetsLibrary::new(executor); let output = beets.list(&query).unwrap(); let expected: Vec = vec![]; diff --git a/src/main.rs b/src/main.rs index 04ab395..81a8fab 100644 --- a/src/main.rs +++ b/src/main.rs @@ -41,9 +41,9 @@ fn main() { // Create the application. let opt = Opt::from_args(); - let beets = BeetsLibrary::new(Box::new( + let beets = BeetsLibrary::new( BeetsLibraryCommandExecutor::default().config(opt.beets_config_file_path.as_deref()), - )); + ); let database = JsonDatabase::new(Box::new(JsonDatabaseFileBackend::new( &opt.database_file_path, diff --git a/tests/library/beets.rs b/tests/library/beets.rs index efdecbf..bea16d0 100644 --- a/tests/library/beets.rs +++ b/tests/library/beets.rs @@ -15,19 +15,21 @@ use musichoard::{ use crate::COLLECTION; -static BEETS_EMPTY_CONFIG: Lazy>> = Lazy::new(|| { - Arc::new(Mutex::new(BeetsLibrary::new(Box::new( - BeetsLibraryCommandExecutor::default(), - )))) -}); +static BEETS_EMPTY_CONFIG: Lazy>>> = + Lazy::new(|| { + Arc::new(Mutex::new(BeetsLibrary::new( + BeetsLibraryCommandExecutor::default(), + ))) + }); -static BEETS_TEST_CONFIG: Lazy>> = Lazy::new(|| { - Arc::new(Mutex::new(BeetsLibrary::new(Box::new( - BeetsLibraryCommandExecutor::default().config(Some( - &fs::canonicalize("./tests/files/library/config.yml").unwrap(), - )), - )))) -}); +static BEETS_TEST_CONFIG: Lazy>>> = + Lazy::new(|| { + Arc::new(Mutex::new(BeetsLibrary::new( + BeetsLibraryCommandExecutor::default().config(Some( + &fs::canonicalize("./tests/files/library/config.yml").unwrap(), + )), + ))) + }); #[test] fn test_no_config_list() {