mecomp_core/
errors.rs

1use mecomp_storage::errors::Error;
2use serde::{Deserialize, Serialize};
3use thiserror::Error;
4
5/// An error in the UDP stack.
6#[derive(Error, Debug)]
7#[cfg(feature = "rpc")]
8pub enum UdpError {
9    #[error("IO error: {0}")]
10    IO(#[from] std::io::Error),
11    #[error("Ciborium deserialization error: {0}")]
12    CiboriumDeserialization(#[from] ciborium::de::Error<std::io::Error>),
13    #[error("Ciborium serialization error: {0}")]
14    CiboriumSerialization(#[from] ciborium::ser::Error<std::io::Error>),
15}
16
17/// Errors that can occur with finding the config or data directories.
18#[derive(Error, Debug)]
19pub enum DirectoryError {
20    #[error("Unable to find the config directory for mecomp.")]
21    Config,
22    #[error("Unable to find the data directory for mecomp.")]
23    Data,
24}
25
26/// Errors that can occur with the library.
27#[derive(Error, Debug)]
28pub enum LibraryError {
29    #[error("Database error: {0}")]
30    Database(#[from] Error),
31    #[error("IO error: {0}")]
32    IO(#[from] std::io::Error),
33    #[error("Decoder error: {0}")]
34    #[cfg(feature = "audio")]
35    Decoder(#[from] rodio::decoder::DecoderError),
36    #[error("UdpError: {0}")]
37    #[cfg(feature = "rpc")]
38    Udp(#[from] UdpError),
39}
40
41#[derive(Error, Debug, Deserialize, Serialize, PartialEq, Eq)]
42pub enum SerializableLibraryError {
43    #[error("Database error: {0}")]
44    Database(String),
45    #[error("IO error: {0}")]
46    IO(String),
47    #[error("Decoder error: {0}")]
48    Decoder(String),
49    #[error("Library Rescan already in progress.")]
50    RescanInProgress,
51    #[error("Library Analysis already in progress.")]
52    AnalysisInProgress,
53    #[error("Collection Reclustering already in progress.")]
54    ReclusterInProgress,
55    #[error("UdpError: {0}")]
56    #[cfg(feature = "rpc")]
57    Udp(String),
58}
59
60impl From<Error> for SerializableLibraryError {
61    fn from(e: Error) -> Self {
62        Self::Database(e.to_string())
63    }
64}
65
66impl From<std::io::Error> for SerializableLibraryError {
67    fn from(e: std::io::Error) -> Self {
68        Self::IO(e.to_string())
69    }
70}
71
72#[cfg(feature = "audio")]
73impl From<rodio::decoder::DecoderError> for SerializableLibraryError {
74    fn from(e: rodio::decoder::DecoderError) -> Self {
75        Self::Decoder(e.to_string())
76    }
77}
78
79#[cfg(feature = "rpc")]
80impl From<UdpError> for SerializableLibraryError {
81    fn from(e: UdpError) -> Self {
82        Self::Udp(e.to_string())
83    }
84}
85
86impl From<LibraryError> for SerializableLibraryError {
87    fn from(e: LibraryError) -> Self {
88        match e {
89            LibraryError::Database(e) => Self::Database(e.to_string()),
90            LibraryError::IO(e) => Self::IO(e.to_string()),
91            #[cfg(feature = "audio")]
92            LibraryError::Decoder(e) => Self::Decoder(e.to_string()),
93            #[cfg(feature = "rpc")]
94            LibraryError::Udp(e) => Self::Udp(e.to_string()),
95        }
96    }
97}
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102    use pretty_assertions::assert_str_eq;
103    use rstest::rstest;
104
105    #[rstest]
106    #[case(
107        LibraryError::from(Error::NoId),
108        "Database error: Item is missing an Id."
109    )]
110    #[case(
111        LibraryError::from(std::io::Error::new(std::io::ErrorKind::Other, "test")),
112        "IO error: test"
113    )]
114    #[case(
115        LibraryError::from(rodio::decoder::DecoderError::DecodeError("test")),
116        "Decoder error: test"
117    )]
118    fn test_serializable_library_error(#[case] input: LibraryError, #[case] expected: String) {
119        let actual = SerializableLibraryError::from(input).to_string();
120        assert_str_eq!(actual, expected);
121    }
122
123    #[rstest]
124    #[case(Error::NoId, LibraryError::Database(Error::NoId).into())]
125    #[case(std::io::Error::new(std::io::ErrorKind::Other, "test"), LibraryError::IO(std::io::Error::new(std::io::ErrorKind::Other, "test")).into())]
126    #[case(rodio::decoder::DecoderError::DecodeError("test"), LibraryError::Decoder(rodio::decoder::DecoderError::DecodeError("test")).into())]
127    fn test_serializable_library_error_from<T: Into<SerializableLibraryError>>(
128        #[case] from: T,
129        #[case] to: SerializableLibraryError,
130    ) {
131        let actual = from.into();
132        assert_eq!(actual, to);
133    }
134}