Skip to main content

ff_sys/
error.rs

1//! Typed representation of an FFmpeg return code.
2//!
3//! The safe wrapper layer currently returns bare `c_int` error codes; migrating
4//! those signatures to [`AvError`] and updating the downstream consumers is
5//! tracked in #1488 (ADR-0003). This module introduces the type: it wraps the
6//! negative `c_int` FFmpeg returns, renders it through `av_strerror`, and exposes
7//! the `EAGAIN` / `EOF` drain states as predicates so the send/receive loop can
8//! read them without comparing raw codes.
9
10use std::fmt;
11use std::os::raw::c_int;
12
13/// A typed FFmpeg return code.
14///
15/// Wraps the raw negative `c_int` error code returned by FFmpeg. [`Display`](fmt::Display)
16/// renders it through `av_strerror`, and [`is_eagain`](Self::is_eagain) /
17/// [`is_eof`](Self::is_eof) expose the drain states the send/receive loop cares
18/// about.
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub struct AvError(c_int);
21
22impl AvError {
23    /// Wraps a raw FFmpeg error code.
24    #[must_use]
25    pub const fn new(code: c_int) -> Self {
26        Self(code)
27    }
28
29    /// Returns the raw FFmpeg error code.
30    #[must_use]
31    pub const fn code(self) -> c_int {
32        self.0
33    }
34
35    /// Returns `true` when the code is `EAGAIN`: the decoder or encoder needs
36    /// more input before it can produce output.
37    #[must_use]
38    pub const fn is_eagain(self) -> bool {
39        self.0 == crate::error_codes::EAGAIN
40    }
41
42    /// Returns `true` when the code is `AVERROR_EOF`: the stream is fully
43    /// drained and no more output will be produced.
44    #[must_use]
45    pub const fn is_eof(self) -> bool {
46        self.0 == crate::error_codes::EOF
47    }
48}
49
50impl fmt::Display for AvError {
51    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52        write!(f, "{} (code={})", crate::av_error_string(self.0), self.0)
53    }
54}
55
56impl std::error::Error for AvError {}
57
58impl From<c_int> for AvError {
59    fn from(code: c_int) -> Self {
60        Self(code)
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67
68    #[test]
69    fn av_error_should_preserve_the_raw_code() {
70        assert_eq!(AvError::new(-22).code(), -22);
71    }
72
73    #[test]
74    fn av_error_should_detect_eagain() {
75        assert!(AvError::new(crate::error_codes::EAGAIN).is_eagain());
76        assert!(!AvError::new(crate::error_codes::EOF).is_eagain());
77    }
78
79    #[test]
80    fn av_error_should_detect_eof() {
81        assert!(AvError::new(crate::error_codes::EOF).is_eof());
82        assert!(!AvError::new(crate::error_codes::EAGAIN).is_eof());
83    }
84
85    #[test]
86    fn av_error_display_should_include_the_message_and_code() {
87        let rendered = AvError::new(crate::error_codes::EOF).to_string();
88        assert!(
89            rendered.contains("code="),
90            "display should include the raw code: {rendered}"
91        );
92        assert!(!rendered.is_empty());
93    }
94
95    #[test]
96    fn av_error_should_convert_from_a_raw_code() {
97        let err = AvError::from(-22);
98        assert_eq!(err.code(), -22);
99    }
100}