cover/src/main.rs

89 lines
2.1 KiB
Rust

use nanoserde::DeJson;
use std::{
collections::{HashMap, HashSet},
env, fs,
hash::Hash,
};
fn main() {
let file_path = env::args()
.nth(1)
.expect("Usage: cover path/to/library.json");
let data = fs::read_to_string(file_path).expect("Failed to open library file");
let json: HashMap<String, Vec<Song>> =
DeJson::deserialize_json(&data).expect("Failed to deserialize library");
let library = Library::new(json);
for cover in library.find_covers() {
println!("Found cover!");
println!(
"{}, by {}, covered by {}",
cover.title, cover.composer, cover.performer
)
}
}
#[derive(Debug, Clone)]
struct Library {
artists: HashSet<Artist>,
}
impl Library {
fn new(json: HashMap<String, Vec<Song>>) -> 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::<HashSet<_>>();
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<Song>,
}
impl Hash for Artist {
fn hash<H: std::hash::Hasher>(&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,
}