Skip to main content

crabcamera/
errors.rs

1use std::fmt;
2
3/// The top-level error type for camera operations.
4#[derive(Debug)]
5pub enum CameraError {
6    /// Failed to initialize the camera backend or device.
7    InitializationError(String),
8    /// Permission denied by OS or user.
9    PermissionDenied(String),
10    /// Failed to capture a frame.
11    CaptureError(String),
12    /// Failed to set a camera control.
13    ControlError(String),
14    /// Error in the video stream pipeline.
15    StreamError(String),
16    /// Operation not supported by the current hardware or platform.
17    UnsupportedOperation(String),
18    #[cfg(feature = "recording")]
19    /// Video encoding initialization or processing error.
20    EncodingError(String),
21    #[cfg(feature = "recording")]
22    /// Container muxing error.
23    MuxingError(String),
24    #[cfg(feature = "recording")]
25    /// File system I/O error during recording.
26    IoError(String),
27    #[cfg(feature = "audio")]
28    /// Audio device or capture error.
29    AudioError(String),
30    /// System resource or access error.
31    AccessError(String),
32    /// Connection implementation error.
33    ConnectionError(String),
34    /// Internal system error.
35    SystemError(String),
36    /// Invalid configuration.
37    ConfigError(String),
38}
39
40impl fmt::Display for CameraError {
41    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
42        match self {
43            CameraError::InitializationError(msg) => {
44                write!(f, "Camera initialization error: {msg}")
45            }
46            CameraError::PermissionDenied(msg) => write!(f, "Permission denied error: {msg}"),
47            CameraError::CaptureError(msg) => write!(f, "Capture error: {msg}"),
48            CameraError::ControlError(msg) => write!(f, "Camera control error: {msg}"),
49            CameraError::StreamError(msg) => write!(f, "Stream error: {msg}"),
50            CameraError::UnsupportedOperation(msg) => write!(f, "Unsupported operation: {msg}"),
51            #[cfg(feature = "recording")]
52            CameraError::EncodingError(msg) => write!(f, "Encoding error: {msg}"),
53            #[cfg(feature = "recording")]
54            CameraError::MuxingError(msg) => write!(f, "Muxing error: {msg}"),
55            #[cfg(feature = "recording")]
56            CameraError::IoError(msg) => write!(f, "IO error: {msg}"),
57            #[cfg(feature = "audio")]
58            CameraError::AudioError(msg) => write!(f, "Audio error: {msg}"),
59            CameraError::AccessError(msg) => write!(f, "Access error: {msg}"),
60            CameraError::ConnectionError(msg) => write!(f, "Connection error: {msg}"),
61            CameraError::SystemError(msg) => write!(f, "System error: {msg}"),
62            CameraError::ConfigError(msg) => write!(f, "Configuration error: {msg}"),
63        }
64    }
65}
66
67impl From<CameraError> for String {
68    fn from(err: CameraError) -> Self {
69        err.to_string()
70    }
71}
72
73impl std::error::Error for CameraError {}
74
75#[cfg(test)]
76mod tests {
77    use super::CameraError;
78
79    #[test]
80    fn test_display_messages_for_all_core_variants() {
81        let cases = vec![
82            (
83                CameraError::InitializationError("init".to_string()),
84                "Camera initialization error: init",
85            ),
86            (
87                CameraError::PermissionDenied("perm".to_string()),
88                "Permission denied error: perm",
89            ),
90            (
91                CameraError::CaptureError("capture".to_string()),
92                "Capture error: capture",
93            ),
94            (
95                CameraError::ControlError("control".to_string()),
96                "Camera control error: control",
97            ),
98            (
99                CameraError::StreamError("stream".to_string()),
100                "Stream error: stream",
101            ),
102            (
103                CameraError::UnsupportedOperation("unsupported".to_string()),
104                "Unsupported operation: unsupported",
105            ),
106            (
107                CameraError::AccessError("access".to_string()),
108                "Access error: access",
109            ),
110            (
111                CameraError::ConnectionError("connection".to_string()),
112                "Connection error: connection",
113            ),
114            (
115                CameraError::SystemError("system".to_string()),
116                "System error: system",
117            ),
118            (
119                CameraError::ConfigError("config".to_string()),
120                "Configuration error: config",
121            ),
122        ];
123
124        for (error, expected) in cases {
125            assert_eq!(error.to_string(), expected);
126        }
127    }
128
129    #[cfg(feature = "recording")]
130    #[test]
131    fn test_display_messages_for_recording_variants() {
132        let cases = vec![
133            (
134                CameraError::EncodingError("enc".to_string()),
135                "Encoding error: enc",
136            ),
137            (
138                CameraError::MuxingError("mux".to_string()),
139                "Muxing error: mux",
140            ),
141            (CameraError::IoError("io".to_string()), "IO error: io"),
142        ];
143
144        for (error, expected) in cases {
145            assert_eq!(error.to_string(), expected);
146        }
147    }
148
149    #[cfg(feature = "audio")]
150    #[test]
151    fn test_display_message_for_audio_variant() {
152        let error = CameraError::AudioError("audio".to_string());
153        assert_eq!(error.to_string(), "Audio error: audio");
154    }
155
156    #[test]
157    fn test_into_string_and_error_trait() {
158        let error = CameraError::CaptureError("boom".to_string());
159        let as_string: String = error.into();
160        assert_eq!(as_string, "Capture error: boom");
161
162        let err_obj: &dyn std::error::Error = &CameraError::SystemError("x".to_string());
163        assert!(err_obj.source().is_none());
164    }
165}