diff --git a/src/collection/mod.rs b/src/collection/mod.rs new file mode 100644 index 0000000..87d7098 --- /dev/null +++ b/src/collection/mod.rs @@ -0,0 +1,54 @@ +use crate::{database::{Database, self}, library::{Library, Query, self}, Artist}; + +/// The collection type. +pub type Collection = Vec; + +/// Error type for collection manager. +#[derive(Debug)] +pub enum Error { + /// The [`CollectionManager`] failed to read/write from/to the library. + LibraryError(String), + /// The [`CollectionManager`] failed to read/write from/to the database. + DatabaseError(String), +} + +impl From for Error { + fn from(err: library::Error) -> Error { + Error::LibraryError(err.to_string()) + } +} + +impl From for Error { + fn from(err: database::Error) -> Error { + Error::DatabaseError(err.to_string()) + } +} + +pub struct CollectionManager { + library: Box, + database: Box, + collection: Collection, +} + +impl CollectionManager { + pub fn new( + library: Box, + database: Box, + ) -> Self { + CollectionManager { + library, + database, + collection: vec![], + } + } + + pub fn rescan_library(&mut self) -> Result<(), Error> { + self.collection = self.library.list(&Query::default())?; + Ok(()) + } + + pub fn save_to_database(&mut self) -> Result<(), Error> { + self.database.write(&self.collection)?; + Ok(()) + } +} diff --git a/src/database/json.rs b/src/database/json.rs index 30496f4..c4bf378 100644 --- a/src/database/json.rs +++ b/src/database/json.rs @@ -3,10 +3,15 @@ use std::fs; use std::path::{Path, PathBuf}; -use serde::de::DeserializeOwned; -use serde::Serialize; +use crate::collection::Collection; -use super::{Database, DatabaseRead, DatabaseWrite}; +use super::{Database, DatabaseRead, DatabaseWrite, Error}; + +impl From for Error { + fn from(err: serde_json::Error) -> Error { + Error::SerDeError(err.to_string()) + } +} /// Trait for the JSON database backend. pub trait JsonDatabaseBackend { @@ -19,21 +24,18 @@ pub trait JsonDatabaseBackend { /// JSON database. pub struct JsonDatabase { - backend: Box, + backend: Box, } impl JsonDatabase { /// Create a new JSON database with the provided backend, e.g. [JsonDatabaseFileBackend]. - pub fn new(backend: Box) -> Self { + pub fn new(backend: Box) -> Self { JsonDatabase { backend } } } impl DatabaseRead for JsonDatabase { - fn read(&self, collection: &mut D) -> Result<(), std::io::Error> - where - D: DeserializeOwned, - { + fn read(&self, collection: &mut Collection) -> Result<(), Error> { let serialized = self.backend.read()?; *collection = serde_json::from_str(&serialized)?; Ok(()) @@ -41,10 +43,7 @@ impl DatabaseRead for JsonDatabase { } impl DatabaseWrite for JsonDatabase { - fn write(&mut self, collection: &S) -> Result<(), std::io::Error> - where - S: Serialize, - { + fn write(&mut self, collection: &Collection) -> Result<(), Error> { let serialized = serde_json::to_string(&collection)?; self.backend.write(&serialized)?; Ok(()) diff --git a/src/database/mod.rs b/src/database/mod.rs index dea333d..bdfdd51 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -1,24 +1,47 @@ //! Module for storing MusicHoard data in a database. -use serde::de::DeserializeOwned; -use serde::Serialize; +use std::fmt; + +use crate::collection::Collection; pub mod json; +/// Error type for database calls. +#[derive(Debug)] +pub enum Error { + /// The database experienced an I/O error. + IoError(String), + /// The database experienced a (de)serialisation error. + SerDeError(String), +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Self::IoError(ref s) => write!(f, "the database experienced an I/O error: {s}"), + Self::SerDeError(ref s) => { + write!(f, "the database experienced a (de)serialisation error: {s}") + } + } + } +} + +impl From for Error { + fn from(err: std::io::Error) -> Error { + Error::IoError(err.to_string()) + } +} + /// Trait for database reads. pub trait DatabaseRead { /// Read collection from the database. - fn read(&self, collection: &mut D) -> Result<(), std::io::Error> - where - D: DeserializeOwned; + fn read(&self, collection: &mut Collection) -> Result<(), Error>; } /// Trait for database writes. pub trait DatabaseWrite { /// Write collection to the database. - fn write(&mut self, collection: &S) -> Result<(), std::io::Error> - where - S: Serialize; + fn write(&mut self, collection: &Collection) -> Result<(), Error>; } /// Trait for database reads and writes. diff --git a/src/lib.rs b/src/lib.rs index d387c1c..405b783 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize}; use uuid::Uuid; +pub mod collection; pub mod database; pub mod library; diff --git a/src/library/beets.rs b/src/library/beets.rs index 77e71fe..b407962 100644 --- a/src/library/beets.rs +++ b/src/library/beets.rs @@ -91,7 +91,7 @@ pub trait BeetsLibraryExecutor { /// Beets library. pub struct BeetsLibrary { - executor: Box, + executor: Box, } trait LibraryPrivate { @@ -107,7 +107,7 @@ trait LibraryPrivate { impl BeetsLibrary { /// Create a new beets library with the provided executor, e.g. [BeetsLibraryCommandExecutor]. - pub fn new(executor: Box) -> BeetsLibrary { + pub fn new(executor: Box) -> BeetsLibrary { BeetsLibrary { executor } } } diff --git a/src/library/mod.rs b/src/library/mod.rs index 3c1584b..3a441e8 100644 --- a/src/library/mod.rs +++ b/src/library/mod.rs @@ -1,6 +1,6 @@ //! Module for interacting with the music library. -use std::{num::ParseIntError, str::Utf8Error}; +use std::{num::ParseIntError, str::Utf8Error, fmt}; use crate::Artist; @@ -111,6 +111,18 @@ pub enum Error { Utf8Error(String), } +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Self::CmdExecError(ref s) => write!(f, "the library failed to execute a command: {s}"), + Self::InvalidData(ref s) => write!(f, "the library returned invalid data: {s}"), + Self::IoError(ref s) => write!(f, "the library experienced an I/O error: {s}"), + Self::ParseIntError(ref s) => write!(f, "the library returned an invalid integer: {s}"), + Self::Utf8Error(ref s) => write!(f, "the library returned invalid UTF-8: {s}"), + } + } +} + impl From for Error { fn from(err: std::io::Error) -> Error { Error::IoError(err.to_string())