Skip to main content

deps_swift/
error.rs

1//! Errors specific to Swift/SPM dependency handling.
2
3use thiserror::Error;
4
5/// Errors specific to Swift/SPM dependency handling.
6#[derive(Error, Debug)]
7pub enum SwiftError {
8    /// Failed to parse Package.swift
9    #[error("Failed to parse Package.swift: {message}")]
10    ParseError { message: String },
11
12    /// Invalid SPM version specifier
13    #[error("Invalid SPM version specifier '{specifier}': {message}")]
14    InvalidVersionSpecifier { specifier: String, message: String },
15
16    /// GitHub API request failed
17    #[error("GitHub API request failed for '{package}': {source}")]
18    RegistryError {
19        package: String,
20        #[source]
21        source: Box<dyn std::error::Error + Send + Sync>,
22    },
23
24    /// GitHub API returned an error status
25    #[error("GitHub API error: {status} {message}")]
26    GitHubApiError { status: u16, message: String },
27
28    /// I/O error
29    #[error("I/O error: {0}")]
30    Io(#[from] std::io::Error),
31}
32
33/// Result type alias for Swift operations.
34pub type Result<T> = std::result::Result<T, SwiftError>;
35
36impl SwiftError {
37    pub fn registry_error(
38        package: impl Into<String>,
39        error: impl std::error::Error + Send + Sync + 'static,
40    ) -> Self {
41        Self::RegistryError {
42            package: package.into(),
43            source: Box::new(error),
44        }
45    }
46
47    pub fn parse_error(message: impl Into<String>) -> Self {
48        Self::ParseError {
49            message: message.into(),
50        }
51    }
52
53    pub fn github_api_error(message: impl Into<String>) -> Self {
54        Self::GitHubApiError {
55            status: 0,
56            message: message.into(),
57        }
58    }
59}
60
61impl From<deps_core::DepsError> for SwiftError {
62    fn from(err: deps_core::DepsError) -> Self {
63        match err {
64            deps_core::DepsError::CacheError(msg) => Self::ParseError { message: msg },
65            deps_core::DepsError::InvalidVersionReq(msg) => Self::InvalidVersionSpecifier {
66                specifier: String::new(),
67                message: msg,
68            },
69            deps_core::DepsError::Io(e) => Self::Io(e),
70            other => Self::ParseError {
71                message: other.to_string(),
72            },
73        }
74    }
75}
76
77impl From<SwiftError> for deps_core::DepsError {
78    fn from(err: SwiftError) -> Self {
79        match err {
80            SwiftError::ParseError { message } => Self::CacheError(message),
81            SwiftError::InvalidVersionSpecifier { message, .. } => Self::InvalidVersionReq(message),
82            SwiftError::RegistryError { package, source } => Self::ParseError {
83                file_type: format!("GitHub API for {package}"),
84                source,
85            },
86            SwiftError::GitHubApiError { status, message } => {
87                Self::CacheError(format!("GitHub API {status}: {message}"))
88            }
89            SwiftError::Io(e) => Self::Io(e),
90        }
91    }
92}
93
94#[cfg(test)]
95mod tests {
96    use super::*;
97
98    #[test]
99    fn test_error_display() {
100        let err = SwiftError::ParseError {
101            message: "unexpected token".into(),
102        };
103        assert_eq!(
104            err.to_string(),
105            "Failed to parse Package.swift: unexpected token"
106        );
107
108        let err = SwiftError::GitHubApiError {
109            status: 403,
110            message: "rate limited".into(),
111        };
112        assert_eq!(err.to_string(), "GitHub API error: 403 rate limited");
113    }
114
115    #[test]
116    fn test_conversion_to_deps_error() {
117        let err = SwiftError::ParseError {
118            message: "test".into(),
119        };
120        let deps_err: deps_core::DepsError = err.into();
121        assert!(deps_err.to_string().contains("test"));
122    }
123}