1use std::io;
2use std::path::PathBuf;
3
4use reqwest::StatusCode;
5
6#[derive(Debug, thiserror::Error)]
13pub enum Error {
14 #[error("{algorithm} mismatch for {url}: expected {expected}, got {actual}")]
15 ChecksumMismatch {
16 algorithm: &'static str,
17 url: String,
18 expected: String,
19 actual: String,
20 },
21 #[error("download path is not a single safe file name: {}", .path.display())]
22 InvalidDownloadPath { path: PathBuf },
23 #[error("invalid range response for {url}: {details}")]
24 InvalidRangeResponse { url: String, details: String },
25 #[error("I/O failed: {0}")]
26 Io(#[from] io::Error),
27 #[error("resource not found: {0}")]
28 NotFound(String),
29 #[error("HTTP request failed: {0}")]
30 Request(#[from] reqwest::Error),
31 #[cfg(feature = "s3")]
32 #[error("S3 operation failed: {0}")]
33 S3(Box<dyn std::error::Error + Send + Sync>),
34 #[error("downloaded {actual} bytes from {url}; expected {expected}")]
35 SizeMismatch {
36 url: String,
37 expected: u64,
38 actual: u64,
39 },
40 #[error("source resolution failed: {0}")]
41 Source(Box<dyn std::error::Error + Send + Sync>),
42 #[error("unexpected status: {0}")]
43 Status(StatusCode),
44 #[error("invalid URL: {0}")]
45 Url(#[from] url::ParseError),
46}
47
48impl Error {
49 pub fn from_source(err: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> Self {
54 Error::Source(err.into())
55 }
56}