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    #[inline]
62    fn from(e: Error) -> Self {
63        Self::Database(e.to_string())
64    }
65}
66
67impl From<std::io::Error> for SerializableLibraryError {
68    #[inline]
69    fn from(e: std::io::Error) -> Self {
70        Self::IO(e.to_string())
71    }
72}
73
74#[cfg(feature = "audio")]
75impl From<rodio::decoder::DecoderError> for SerializableLibraryError {
76    #[inline]
77    fn from(e: rodio::decoder::DecoderError) -> Self {
78        Self::Decoder(e.to_string())
79    }
80}
81
82#[cfg(feature = "rpc")]
83impl From<UdpError> for SerializableLibraryError {
84    #[inline]
85    fn from(e: UdpError) -> Self {
86        Self::Udp(e.to_string())
87    }
88}
89
90impl From<LibraryError> for SerializableLibraryError {
91    #[inline]
92    fn from(e: LibraryError) -> Self {
93        match e {
94            LibraryError::Database(e) => Self::Database(e.to_string()),
95            LibraryError::IO(e) => Self::IO(e.to_string()),
96            #[cfg(feature = "audio")]
97            LibraryError::Decoder(e) => Self::Decoder(e.to_string()),
98            #[cfg(feature = "rpc")]
99            LibraryError::Udp(e) => Self::Udp(e.to_string()),
100        }
101    }
102}
103
104#[cfg(test)]
105mod tests {
106    use super::*;
107    use pretty_assertions::assert_str_eq;
108    use rstest::rstest;
109
110    #[rstest]
111    #[case(
112        LibraryError::from(Error::NoId),
113        "Database error: Item is missing an Id."
114    )]
115    #[case(
116        LibraryError::from(std::io::Error::new(std::io::ErrorKind::Other, "test")),
117        "IO error: test"
118    )]
119    #[case(
120        LibraryError::from(rodio::decoder::DecoderError::DecodeError("test")),
121        "Decoder error: test"
122    )]
123    fn test_serializable_library_error(#[case] input: LibraryError, #[case] expected: String) {
124        let actual = SerializableLibraryError::from(input).to_string();
125        assert_str_eq!(actual, expected);
126    }
127
128    #[rstest]
129    #[case(Error::NoId, LibraryError::Database(Error::NoId).into())]
130    #[case(std::io::Error::new(std::io::ErrorKind::Other, "test"), LibraryError::IO(std::io::Error::new(std::io::ErrorKind::Other, "test")).into())]
131    #[case(rodio::decoder::DecoderError::DecodeError("test"), LibraryError::Decoder(rodio::decoder::DecoderError::DecodeError("test")).into())]
132    fn test_serializable_library_error_from<T: Into<SerializableLibraryError>>(
133        #[case] from: T,
134        #[case] to: SerializableLibraryError,
135    ) {
136        let actual = from.into();
137        assert_eq!(actual, to);
138    }
139}