From 3c0df12b506be75acbb35a6d9887f2717cacaa09 Mon Sep 17 00:00:00 2001 From: mat ess Date: Mon, 17 Apr 2023 18:22:35 -0400 Subject: [PATCH] Initial version --- .envrc | 1 + .gitignore | 11 +++ Cargo.lock | 25 ++++++ Cargo.toml | 9 ++ flake.lock | 237 +++++++++++++++++++++++++++++++++++++++++++++++++++ flake.nix | 70 +++++++++++++++ library.json | 21 +++++ src/main.rs | 88 +++++++++++++++++++ 8 files changed, 462 insertions(+) create mode 100644 .envrc create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 library.json create mode 100644 src/main.rs diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9bc91cd --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +/.direnv +/result +/target +/.pre-commit-config.yaml + + +# Added by cargo +# +# already existing elements were commented out + +#/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..16aba8c --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,25 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cover" +version = "0.1.0" +dependencies = [ + "nanoserde", +] + +[[package]] +name = "nanoserde" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "755e7965536bc54d7c9fba2df5ada5bf835b0443fd613f0a53fa199a301839d3" +dependencies = [ + "nanoserde-derive", +] + +[[package]] +name = "nanoserde-derive" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed7a94da6c6181c35d043fc61c43ac96d3a5d739e7b8027f77650ba41504d6ab" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..665409b --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "cover" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +nanoserde = "0.1.32" diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..0653ec0 --- /dev/null +++ b/flake.lock @@ -0,0 +1,237 @@ +{ + "nodes": { + "crane": { + "inputs": { + "flake-compat": "flake-compat", + "flake-utils": "flake-utils", + "nixpkgs": [ + "nixpkgs" + ], + "rust-overlay": "rust-overlay" + }, + "locked": { + "lastModified": 1681680516, + "narHash": "sha256-EB8Adaeg4zgcYDJn9sR6UMjN/OHdIiMMK19+3LmmXQY=", + "owner": "ipetkov", + "repo": "crane", + "rev": "54b63c8eae4c50172cb50b612946ff1d2bc1c75c", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_2": { + "flake": false, + "locked": { + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1680392223, + "narHash": "sha256-n3g7QFr85lDODKt250rkZj2IFS3i4/8HBU2yKHO3tqw=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "dcc36e45d054d7bb554c9cdab69093debd91a0b5", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-utils": { + "locked": { + "lastModified": 1678901627, + "narHash": "sha256-U02riOqrKKzwjsxc/400XnElV+UtPUQWpANPlyazjH0=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "93a2b84fc4b70d9e089d029deacc3583435c2ed6", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "locked": { + "lastModified": 1667395993, + "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "pre-commit", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1660459072, + "narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "a20de23b925fd8264fd7fad6454652e142fd7f73", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1681648924, + "narHash": "sha256-pzi3HISK8+7mpEtv08Yr80wswyHKsz+RP1CROG1Qf6s=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "f294325aed382b66c7a188482101b0f336d1d7db", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "dir": "lib", + "lastModified": 1680213900, + "narHash": "sha256-cIDr5WZIj3EkKyCgj/6j3HBH4Jj1W296z7HTcWj1aMA=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e3652e0735fbec227f342712f180f4f21f0594f2", + "type": "github" + }, + "original": { + "dir": "lib", + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-stable": { + "locked": { + "lastModified": 1678872516, + "narHash": "sha256-/E1YwtMtFAu2KUQKV/1+KFuReYPANM2Rzehk84VxVoc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "9b8e5abb18324c7fe9f07cb100c3cd4a29cda8b8", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-22.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "pre-commit": { + "inputs": { + "flake-compat": "flake-compat_2", + "flake-utils": "flake-utils_2", + "gitignore": "gitignore", + "nixpkgs": [ + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable" + }, + "locked": { + "lastModified": 1681413034, + "narHash": "sha256-/t7OjNQcNkeWeSq/CFLYVBfm+IEnkjoSm9iKvArnUUI=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "d3de8f69ca88fb6f8b09e5b598be5ac98d28ede5", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, + "root": { + "inputs": { + "crane": "crane", + "flake-parts": "flake-parts", + "nixpkgs": "nixpkgs", + "pre-commit": "pre-commit" + } + }, + "rust-overlay": { + "inputs": { + "flake-utils": [ + "crane", + "flake-utils" + ], + "nixpkgs": [ + "crane", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1680488274, + "narHash": "sha256-0vYMrZDdokVmPQQXtFpnqA2wEgCCUXf5a3dDuDVshn0=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "7ec2ff598a172c6e8584457167575b3a1a5d80d8", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..e9648c0 --- /dev/null +++ b/flake.nix @@ -0,0 +1,70 @@ +{ + description = "FILL-ME-IN"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-parts.url = "github:hercules-ci/flake-parts"; + crane.url = "github:ipetkov/crane"; + crane.inputs.nixpkgs.follows = "nixpkgs"; + pre-commit.url = "github:cachix/pre-commit-hooks.nix"; + pre-commit.inputs.nixpkgs.follows = "nixpkgs"; + }; + + outputs = inputs@{ self, flake-parts, crane, pre-commit, ... }: + flake-parts.lib.mkFlake { inherit inputs; } { + imports = [ pre-commit.flakeModule ]; + systems = [ + "aarch64-darwin" + "aarch64-linux" + "x86_64-darwin" + "x86_64-linux" + ]; + perSystem = { config, pkgs, system, ... }: + let + crane-lib = crane.lib.${system}; + package = crane-lib.buildPackage { + src = crane-lib.cleanCargoSource ./.; + nativeBuildInputs = pkgs.lib.optionals pkgs.stdenv.isDarwin [ pkgs.libiconv ]; + }; + in + { + pre-commit.settings.hooks = { + rustfmt.enable = true; + clippy.enable = true; + cargo-check.enable = true; + }; + checks = { inherit package; }; + packages.default = package; + devShells.default = pkgs.mkShell { + shellHook = '' + ${config.pre-commit.installationScript} + echo "welcome to your rust project ミ(・・)ミ" 1>&2 + ''; + inputsFrom = builtins.attrValues self.checks; + + RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}"; + nativeBuildInputs = builtins.attrValues ({ + inherit (pkgs) + cargo + rustc + ; + } // pkgs.lib.optionalAttrs pkgs.stdenv.isDarwin { + inherit (pkgs) libiconv; + inherit (pkgs.darwin.apple_sdk.frameworks) Security; + }); + buildInputs = builtins.attrValues { + inherit (pkgs) + rust-analyzer + # rustfmt + clippy + ; + rustfmt = pkgs.rustfmt.overrideAttrs (old: { + preFixup = pkgs.lib.optionalString pkgs.stdenv.isDarwin '' + install_name_tool -add_rpath "${pkgs.rustc}/lib" "$out/bin/rustfmt" + ''; + }); + }; + }; + }; + }; +} diff --git a/library.json b/library.json new file mode 100644 index 0000000..a4a1841 --- /dev/null +++ b/library.json @@ -0,0 +1,21 @@ +{ + "Taylor Swift": [ + { + "title": "Love Story", + "composer": "Taylor Swift", + "performer": "Taylor Swift" + } + ], + "black midi": [ + { + "title": "Love Story", + "composer": "Taylor Swift", + "performer": "black midi" + }, + { + "title": "Love Story", + "composer": "black midi", + "performer": "black midi" + } + ] +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..9648012 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,88 @@ +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> = + 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, +} + +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, +}