Skip to main content

loadsmith_registry/
error.rs

1use std::error::Error as StdError;
2
3use camino::Utf8PathBuf;
4
5/// Errors returned by registry operations.
6///
7/// Wraps I/O errors, Thunderstore client errors, zip errors, JSON errors, and
8/// several registry-specific error conditions such as missing packages,
9/// missing or invalid metadata, and file-not-found.
10///
11/// # Examples
12///
13/// ```rust
14/// use loadsmith_registry::Error;
15///
16/// let err = Error::PackageNotFound;
17/// assert_eq!(err.to_string(), "package not found");
18///
19/// let io_err = Error::Io(std::io::Error::new(std::io::ErrorKind::NotFound, "missing"));
20/// assert!(io_err.to_string().contains("I/O error"));
21/// ```
22#[derive(Debug, thiserror::Error)]
23pub enum Error {
24    /// An I/O error occurred while reading a file or directory.
25    #[error("I/O error")]
26    Io(#[from] std::io::Error),
27
28    /// An error from the Thunderstore API client.
29    #[error("thunderstore client error")]
30    Thunderstore(#[from] thunderstore::Error),
31
32    /// An error while reading a zip archive.
33    #[error("zip error")]
34    Zip(#[from] zip::result::ZipError),
35
36    /// An error while serialising or deserialising JSON metadata.
37    #[error("json error")]
38    Json(#[from] serde_json::Error),
39
40    /// A registry with the given identifier was not found in the set.
41    #[error("registry not found: {0}")]
42    RegistryNotFound(String),
43
44    /// An opaque, boxed error from an external source.
45    #[error(transparent)]
46    Other(Box<dyn StdError + Send + Sync>),
47
48    /// A registry operation required metadata but none was provided.
49    #[error("registry requires metadata, but none was provided")]
50    MissingMetadata,
51
52    /// The metadata provided to the registry was not valid for the expected schema.
53    #[error("registry got invalid metadata")]
54    InvalidMetadata(#[source] serde_json::Error),
55
56    /// A required file does not exist at the given path.
57    #[error("file not found: {0}")]
58    FileNotFound(Utf8PathBuf),
59
60    /// The file at the given path is not a recognised type.
61    #[error("invalid file type: {0}")]
62    InvalidFileType(Utf8PathBuf),
63
64    /// The requested package could not be found in the registry.
65    #[error("package not found")]
66    PackageNotFound,
67
68    /// The requested package version could not be found.
69    #[error("package version not found")]
70    VersionNotFound,
71
72    /// A local package source is missing its `manifest.json`.
73    #[error("local package has no manifest")]
74    LocalManifestMissing,
75
76    /// A local package's version could not be determined and no `source_version` was supplied.
77    #[error(
78        "version could not be determined from local package, please specify a source_version in metadata"
79    )]
80    LocalVersionMissing,
81}
82
83impl Error {
84    /// Wrap an arbitrary error into the [`Error::Other`] variant.
85    ///
86    /// # Examples
87    ///
88    /// ```rust
89    /// use loadsmith_registry::Error;
90    ///
91    /// let custom = "something went wrong".to_string();
92    /// let err = Error::other(std::io::Error::new(std::io::ErrorKind::Other, custom));
93    /// assert!(err.to_string().contains("something went wrong"));
94    /// ```
95    pub fn other<E: StdError + Send + Sync + 'static>(err: E) -> Self {
96        Self::Other(Box::new(err))
97    }
98}
99
100/// Convenience alias for [`std::result::Result`] whose error type is [`Error`].
101pub type Result<T> = std::result::Result<T, Error>;