diff --git a/src/library.rs b/src/library.rs new file mode 100644 index 0000000..d4db4ab --- /dev/null +++ b/src/library.rs @@ -0,0 +1,128 @@ +use nanoserde::DeJson; +use std::{ + collections::{HashMap, HashSet}, + hash::Hash, +}; + +#[derive(Debug, Clone)] +pub struct Library { + artists: HashSet, +} + +impl Library { + pub fn new(json: HashMap>) -> Self { + let artists = json + .into_iter() + .map(|(name, catalog)| Artist { + name, + catalog: catalog.into_iter().collect(), + }) + .collect(); + Library { artists } + } + + pub fn find_covers(&self) -> HashSet<&Song> { + let names = self + .artists + .iter() + .map(|artist| artist.name.clone()) + .collect::>(); + self.artists + .iter() + .fold(HashSet::new(), |mut covers, artist| { + covers.extend(artist.covered_songs()); + covers + }) + .into_iter() + .filter(|song| names.contains(&song.composer)) + .collect() + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +struct Artist { + name: String, + catalog: HashSet, +} + +impl Hash for Artist { + fn hash(&self, state: &mut H) { + self.name.hash(state); + } +} + +impl Artist { + fn covered_songs(&self) -> HashSet<&Song> { + self.catalog + .iter() + .filter(|song| song.composer != self.name) + .collect() + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash, DeJson)] +pub struct Song { + pub title: String, + pub performer: String, + pub composer: String, +} + +#[cfg(test)] +mod tests { + use super::*; + + fn bmbmbm() -> Song { + Song { + title: "bmbmbm".to_string(), + performer: "black midi".to_string(), + composer: "black midi".to_string(), + } + } + + fn love_story(performer: &str) -> Song { + Song { + title: "Love Story".to_string(), + performer: performer.to_string(), + composer: "Taylor Swift".to_string(), + } + } + + fn schizoid_man() -> Song { + Song { + title: "21st Century Schizoid Man".to_string(), + performer: "black midi".to_string(), + composer: "Greg Lake, Ian McDonald, Michael Giles, Peter Sinfield & Robert Fripp" + .to_string(), + } + } + + fn bm() -> Artist { + Artist { + name: "black midi".to_string(), + catalog: HashSet::from([bmbmbm(), love_story("black midi"), schizoid_man()]), + } + } + + fn ts() -> Artist { + Artist { + name: "Taylor Swift".to_string(), + catalog: HashSet::from([love_story("Taylor Swift")]), + } + } + + fn library() -> Library { + Library { + artists: HashSet::from([bm(), ts()]), + } + } + + #[test] + fn test_covered_songs() { + assert!(bm().covered_songs() == HashSet::from([&love_story("black midi"), &schizoid_man()])) + } + + #[test] + fn test_find_covers() { + assert!(library().find_covers() == HashSet::from([&love_story("black midi")])) + } +} diff --git a/src/main.rs b/src/main.rs index 12eb334..dcfa765 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,8 @@ use nanoserde::DeJson; -use std::{ - collections::{HashMap, HashSet}, - env, fs, - hash::Hash, -}; +use std::{collections::HashMap, env, fs}; + +mod library; +use crate::library::{Library, Song}; fn main() { let file_path = env::args() @@ -21,128 +20,3 @@ fn main() { ) } } - -#[derive(Debug, Clone)] -struct Library { - artists: HashSet, -} - -impl Library { - fn new(json: HashMap>) -> Self { - let artists = json - .into_iter() - .map(|(name, catalog)| Artist { - name, - catalog: catalog.into_iter().collect(), - }) - .collect(); - Library { artists } - } -} - -impl Library { - fn find_covers(&self) -> HashSet<&Song> { - let names = self - .artists - .iter() - .map(|artist| artist.name.clone()) - .collect::>(); - self.artists - .iter() - .fold(HashSet::new(), |mut covers, artist| { - covers.extend(artist.covered_songs()); - covers - }) - .into_iter() - .filter(|song| names.contains(&song.composer)) - .collect() - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -struct Artist { - name: String, - catalog: HashSet, -} - -impl Hash for Artist { - fn hash(&self, state: &mut H) { - self.name.hash(state); - } -} - -impl Artist { - fn covered_songs(&self) -> HashSet<&Song> { - self.catalog - .iter() - .filter(|song| song.composer != self.name) - .collect() - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash, DeJson)] -struct Song { - title: String, - performer: String, - composer: String, -} - -#[cfg(test)] -mod tests { - use super::*; - - fn bmbmbm() -> Song { - Song { - title: "bmbmbm".to_string(), - performer: "black midi".to_string(), - composer: "black midi".to_string(), - } - } - - fn love_story(performer: &str) -> Song { - Song { - title: "Love Story".to_string(), - performer: performer.to_string(), - composer: "Taylor Swift".to_string(), - } - } - - fn schizoid_man() -> Song { - Song { - title: "21st Century Schizoid Man".to_string(), - performer: "black midi".to_string(), - composer: "Greg Lake, Ian McDonald, Michael Giles, Peter Sinfield & Robert Fripp" - .to_string(), - } - } - - fn bm() -> Artist { - Artist { - name: "black midi".to_string(), - catalog: HashSet::from([bmbmbm(), love_story("black midi"), schizoid_man()]), - } - } - - fn ts() -> Artist { - Artist { - name: "Taylor Swift".to_string(), - catalog: HashSet::from([love_story("Taylor Swift")]), - } - } - - fn library() -> Library { - Library { - artists: HashSet::from([bm(), ts()]), - } - } - - #[test] - fn test_covered_songs() { - assert!(bm().covered_songs() == HashSet::from([&love_story("black midi"), &schizoid_man()])) - } - - #[test] - fn test_find_covers() { - assert!(library().find_covers() == HashSet::from([&love_story("black midi")])) - } -}