Skip to main content

exiftool_rs_wrapper/
error.rs

1//! ExifTool 错误类型定义
2
3use std::io;
4use thiserror::Error;
5
6/// 所有 ExifTool 操作的错误类型
7#[derive(Error, Debug)]
8pub enum Error {
9    /// IO 错误
10    #[error("IO error: {0}")]
11    Io(#[from] io::Error),
12
13    /// 进程错误
14    #[error("ExifTool process error: {message}")]
15    Process {
16        message: String,
17        exit_code: Option<i32>,
18    },
19
20    /// 解析错误
21    #[error("Parse error: {0}")]
22    Parse(String),
23
24    /// 标签未找到
25    #[error("Tag not found: {0}")]
26    TagNotFound(String),
27
28    /// 无效参数
29    #[error("Invalid argument: {0}")]
30    InvalidArgument(String),
31
32    /// ExifTool 未找到
33    #[error("ExifTool not found in PATH. Please install ExifTool: https://exiftool.org/")]
34    ExifToolNotFound,
35
36    /// 互斥锁被污染
37    #[error("Internal mutex poisoned")]
38    MutexPoisoned,
39
40    /// 序列化错误
41    #[error("Serialization error: {0}")]
42    Serialization(#[from] serde_json::Error),
43
44    /// 超时
45    #[error("Operation timed out")]
46    Timeout,
47}
48
49/// Result 类型别名
50pub type Result<T> = std::result::Result<T, Error>;
51
52impl Error {
53    /// 创建进程错误
54    pub fn process(message: impl Into<String>) -> Self {
55        Self::Process {
56            message: message.into(),
57            exit_code: None,
58        }
59    }
60
61    /// 创建带退出码的进程错误
62    pub fn process_with_code(message: impl Into<String>, code: i32) -> Self {
63        Self::Process {
64            message: message.into(),
65            exit_code: Some(code),
66        }
67    }
68
69    /// 创建解析错误
70    pub fn parse(message: impl Into<String>) -> Self {
71        Self::Parse(message.into())
72    }
73
74    /// 创建无效参数错误
75    pub fn invalid_arg(message: impl Into<String>) -> Self {
76        Self::InvalidArgument(message.into())
77    }
78}
79
80impl From<std::sync::PoisonError<std::sync::MutexGuard<'_, crate::process::ExifToolInner>>>
81    for Error
82{
83    fn from(
84        _: std::sync::PoisonError<std::sync::MutexGuard<'_, crate::process::ExifToolInner>>,
85    ) -> Self {
86        Error::MutexPoisoned
87    }
88}
89
90#[cfg(test)]
91mod tests {
92    use super::*;
93
94    #[test]
95    fn test_error_creation() {
96        let err = Error::process("test error");
97        assert!(matches!(err, Error::Process { .. }));
98        assert!(err.to_string().contains("test error"));
99    }
100
101    #[test]
102    fn test_error_from_io() {
103        let io_err = io::Error::new(io::ErrorKind::NotFound, "file not found");
104        let err: Error = io_err.into();
105        assert!(matches!(err, Error::Io(_)));
106    }
107}