diff --git a/src/core/musichoard/musichoard.rs b/src/core/musichoard/musichoard.rs index 66a7d6b..3eb55bf 100644 --- a/src/core/musichoard/musichoard.rs +++ b/src/core/musichoard/musichoard.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, mem}; +use std::collections::HashMap; use paste::paste; @@ -20,6 +20,9 @@ pub struct MusicHoard { collection: Collection, library: LIB, database: DB, + // There is no database cache since the database contains the entirety of the `collection` + // itself. Therefore, [`collection`] also represents the last state of the database. + library_cache: HashMap, } /// Phantom type for when a library implementation is not needed. @@ -117,6 +120,7 @@ impl MusicHoard { collection: vec![], library, database, + library_cache: HashMap::new(), } } @@ -189,34 +193,17 @@ impl MusicHoard { } } - fn merge_with_primary(&mut self, primary: HashMap) { - let collection = mem::take(&mut self.collection); - self.collection = Self::merge_collections(primary, collection); - } - - fn merge_with_secondary>(&mut self, secondary: SEC) { - let primary_map: HashMap = self - .collection - .drain(..) - .map(|a| (a.id.clone(), a)) - .collect(); - self.collection = Self::merge_collections(primary_map, secondary); - } - - fn merge_collections>( - mut primary: HashMap, - secondary: SEC, - ) -> Collection { - for secondary_artist in secondary.into_iter() { + fn merge_collections(&mut self) { + let mut primary = self.library_cache.clone(); + for secondary_artist in self.collection.drain(..) { if let Some(ref mut primary_artist) = primary.get_mut(&secondary_artist.id) { primary_artist.merge_in_place(secondary_artist); } else { primary.insert(secondary_artist.id.clone(), secondary_artist); } } - let mut collection: Collection = primary.into_values().collect(); - Self::sort_artists(&mut collection); - collection + self.collection.extend(primary.into_values()); + Self::sort_artists(&mut self.collection); } fn items_to_artists(items: Vec) -> Result, Error> { @@ -307,10 +294,10 @@ impl MusicHoard { /// Rescan the library and merge with the in-memory collection. pub fn rescan_library(&mut self) -> Result<(), Error> { let items = self.library.list(&Query::new())?; - let mut library_collection = Self::items_to_artists(items)?; - Self::sort_albums_and_tracks(library_collection.values_mut()); + self.library_cache = Self::items_to_artists(items)?; + Self::sort_albums_and_tracks(self.library_cache.values_mut()); - self.merge_with_primary(library_collection); + self.merge_collections(); Ok(()) } } @@ -318,10 +305,10 @@ impl MusicHoard { impl MusicHoard { /// Load the database and merge with the in-memory collection. pub fn load_from_database(&mut self) -> Result<(), Error> { - let mut database_collection = self.database.load()?; - Self::sort_albums_and_tracks(database_collection.iter_mut()); + self.collection = self.database.load()?; + Self::sort_albums_and_tracks(self.collection.iter_mut()); - self.merge_with_secondary(database_collection); + self.merge_collections(); Ok(()) } @@ -729,25 +716,28 @@ mod tests { let mut expected = FULL_COLLECTION.to_owned(); expected.sort_unstable(); - let merged = MusicHoard::::merge_collections( - left.clone() - .into_iter() - .map(|a| (a.id.clone(), a)) - .collect(), - right.clone(), - ); - assert_eq!(expected, merged); + let mut mh = MusicHoard::default(); + mh.library_cache = left + .clone() + .into_iter() + .map(|a| (a.id.clone(), a)) + .collect(); + mh.collection = right.clone(); + + mh.merge_collections(); + assert_eq!(expected, mh.collection); // The merge is completely non-overlapping so it should be commutative. - let merged = MusicHoard::::merge_collections( - right - .clone() - .into_iter() - .map(|a| (a.id.clone(), a)) - .collect(), - left.clone(), - ); - assert_eq!(expected, merged); + let mut mh = MusicHoard::default(); + mh.library_cache = right + .clone() + .into_iter() + .map(|a| (a.id.clone(), a)) + .collect(); + mh.collection = left.clone(); + + mh.merge_collections(); + assert_eq!(expected, mh.collection); } #[test] @@ -760,25 +750,28 @@ mod tests { let mut expected = FULL_COLLECTION.to_owned(); expected.sort_unstable(); - let merged = MusicHoard::::merge_collections( - left.clone() - .into_iter() - .map(|a| (a.id.clone(), a)) - .collect(), - right.clone(), - ); - assert_eq!(expected, merged); + let mut mh = MusicHoard::default(); + mh.library_cache = left + .clone() + .into_iter() + .map(|a| (a.id.clone(), a)) + .collect(); + mh.collection = right.clone(); + + mh.merge_collections(); + assert_eq!(expected, mh.collection); // The merge does not overwrite any data so it should be commutative. - let merged = MusicHoard::::merge_collections( - right - .clone() - .into_iter() - .map(|a| (a.id.clone(), a)) - .collect(), - left.clone(), - ); - assert_eq!(expected, merged); + let mut mh = MusicHoard::default(); + mh.library_cache = right + .clone() + .into_iter() + .map(|a| (a.id.clone(), a)) + .collect(); + mh.collection = left.clone(); + + mh.merge_collections(); + assert_eq!(expected, mh.collection); } #[test] @@ -804,27 +797,28 @@ mod tests { expected.last_mut().as_mut().unwrap().sort = artist_sort.clone(); expected.rotate_right(1); - let merged = MusicHoard::::merge_collections( - left.clone() - .into_iter() - .map(|a| (a.id.clone(), a)) - .collect(), - right.clone(), - ); - assert_eq!(expected.len(), merged.len()); - assert_eq!(expected, merged); + let mut mh = MusicHoard::default(); + mh.library_cache = left + .clone() + .into_iter() + .map(|a| (a.id.clone(), a)) + .collect(); + mh.collection = right.clone(); + + mh.merge_collections(); + assert_eq!(expected, mh.collection); // The merge overwrites the sort data, but no data is erased so it should be commutative. - let merged = MusicHoard::::merge_collections( - right - .clone() - .into_iter() - .map(|a| (a.id.clone(), a)) - .collect(), - left.clone(), - ); - assert_eq!(expected.len(), merged.len()); - assert_eq!(expected, merged); + let mut mh = MusicHoard::default(); + mh.library_cache = right + .clone() + .into_iter() + .map(|a| (a.id.clone(), a)) + .collect(); + mh.collection = left.clone(); + + mh.merge_collections(); + assert_eq!(expected, mh.collection); } #[test]