blaze-rs 1.0.3

A Rustified OpenCL Experience
Documentation
use core::ffi::c_char;
use std::{backtrace::Backtrace, sync::Arc, ffi::CString, fmt::Debug};
use ffmpeg_sys_next::*;

pub type Result<T> = ::core::result::Result<T, Error>;

#[derive(Clone)]
pub struct Error {
    pub kind: ErrorKind,
    pub desc: CString,
    #[cfg(debug_assertions)]
    pub backtrace: Arc<Backtrace>
}

impl Error {
    #[inline]
    pub fn new (kind: ErrorKind, desc: impl ToString) -> Error {
        Self::with_desc(kind, CString::new(desc.to_string()).unwrap())
    }

    #[inline]
    pub fn with_desc (kind: ErrorKind, desc: CString) -> Error {
        Self {
            kind,
            desc,
            #[cfg(debug_assertions)]
            backtrace: Arc::new(Backtrace::capture())
        }
    }

    #[inline(always)]
    pub fn from_kind (kind: ErrorKind) -> Error {
        Self::with_desc(kind, error_desc(kind as i32))
    }
}

impl Debug for Error {
    #[inline]
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        #[cfg(not(debug_assertions))]
        return write!(f, "{:?}: {:?}", &self.kind, self.desc);
        #[cfg(debug_assertions)]
        return write!(f, "{:?}: {:?}\n{}", &self.kind, &self.desc, &self.backtrace);
    }
}

impl From<i32> for Error {
    #[inline]
    fn from(x: i32) -> Self {
        let kind = match x {
            AVERROR_BSF_NOT_FOUND => ErrorKind::BsfNotFound,
            AVERROR_BUG => ErrorKind::Bug,
            AVERROR_BUFFER_TOO_SMALL => ErrorKind::BufferTooSmall,
            AVERROR_DECODER_NOT_FOUND => ErrorKind::DecoderNotFound,
            AVERROR_DEMUXER_NOT_FOUND => ErrorKind::DemuxerNotFound,
            AVERROR_ENCODER_NOT_FOUND => ErrorKind::EncoderNotFound,
            AVERROR_EOF => ErrorKind::Eof,
            AVERROR_EXIT => ErrorKind::Exit,
            AVERROR_EXTERNAL => ErrorKind::External,
            AVERROR_FILTER_NOT_FOUND => ErrorKind::FilterNotFound,
            AVERROR_INVALIDDATA => ErrorKind::InvalidData,
            AVERROR_MUXER_NOT_FOUND => ErrorKind::MuxerNotFound,
            AVERROR_OPTION_NOT_FOUND => ErrorKind::OptionNotFound,
            AVERROR_PATCHWELCOME => ErrorKind::Patchwelcome,
            AVERROR_PROTOCOL_NOT_FOUND => ErrorKind::ProtocolNotFound,
            AVERROR_STREAM_NOT_FOUND => ErrorKind::StreamNotFound,
            AVERROR_BUG2 => ErrorKind::Bug2,
            AVERROR_UNKNOWN => ErrorKind::Unknown,
            AVERROR_HTTP_BAD_REQUEST => ErrorKind::HttpBadRequest,
            AVERROR_HTTP_UNAUTHORIZED => ErrorKind::HttpUnauthorized,
            AVERROR_HTTP_FORBIDDEN => ErrorKind::HttpForbidden,
            AVERROR_HTTP_NOT_FOUND => ErrorKind::HttpNotFound,
            AVERROR_HTTP_OTHER_4XX => ErrorKind::HttpOther4xx,
            AVERROR_HTTP_SERVER_ERROR => ErrorKind::HttpServerError,
            other => {
                let desc = error_desc(other);
                return Self::with_desc(ErrorKind::Unknown, desc)
            }
        };

        Self::from_kind(kind)
    }
}

impl From<ErrorKind> for Error {
    #[inline(always)]
    fn from(kind: ErrorKind) -> Self {
        Self::from_kind(kind)
    }
}

impl Into<ErrorKind> for Error {
    #[inline(always)]
    fn into(self) -> ErrorKind {
        self.kind
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(i32)]
#[non_exhaustive]
pub enum ErrorKind {
    BsfNotFound = AVERROR_BSF_NOT_FOUND,
    Bug = AVERROR_BUG,
    BufferTooSmall = AVERROR_BUFFER_TOO_SMALL,
    DecoderNotFound = AVERROR_DECODER_NOT_FOUND,
    DemuxerNotFound = AVERROR_DEMUXER_NOT_FOUND,
    EncoderNotFound = AVERROR_ENCODER_NOT_FOUND,
    Eof = AVERROR_EOF,
    Exit = AVERROR_EXIT,
    External = AVERROR_EXTERNAL,
    FilterNotFound = AVERROR_FILTER_NOT_FOUND,
    InvalidData = AVERROR_INVALIDDATA,
    MuxerNotFound = AVERROR_MUXER_NOT_FOUND,
    OptionNotFound = AVERROR_OPTION_NOT_FOUND,
    Patchwelcome = AVERROR_PATCHWELCOME,
    ProtocolNotFound = AVERROR_PROTOCOL_NOT_FOUND,
    StreamNotFound = AVERROR_STREAM_NOT_FOUND,
    Bug2 = AVERROR_BUG2,
    Unknown = AVERROR_UNKNOWN,
    HttpBadRequest = AVERROR_HTTP_BAD_REQUEST,
    HttpUnauthorized = AVERROR_HTTP_UNAUTHORIZED,
    HttpForbidden = AVERROR_HTTP_FORBIDDEN,
    HttpNotFound = AVERROR_HTTP_NOT_FOUND,
    HttpOther4xx = AVERROR_HTTP_OTHER_4XX,
    HttpServerError = AVERROR_HTTP_SERVER_ERROR
}

impl From<i32> for ErrorKind {
    #[inline]
    fn from(x: i32) -> Self {
        match x {
            AVERROR_BSF_NOT_FOUND => Self::BsfNotFound,
            AVERROR_BUG => Self::Bug,
            AVERROR_BUFFER_TOO_SMALL => Self::BufferTooSmall,
            AVERROR_DECODER_NOT_FOUND => Self::DecoderNotFound,
            AVERROR_DEMUXER_NOT_FOUND => Self::DemuxerNotFound,
            AVERROR_ENCODER_NOT_FOUND => Self::EncoderNotFound,
            AVERROR_EOF => Self::Eof,
            AVERROR_EXIT => Self::Exit,
            AVERROR_EXTERNAL => Self::External,
            AVERROR_FILTER_NOT_FOUND => Self::FilterNotFound,
            AVERROR_INVALIDDATA => Self::InvalidData,
            AVERROR_MUXER_NOT_FOUND => Self::MuxerNotFound,
            AVERROR_OPTION_NOT_FOUND => Self::OptionNotFound,
            AVERROR_PATCHWELCOME => Self::Patchwelcome,
            AVERROR_PROTOCOL_NOT_FOUND => Self::ProtocolNotFound,
            AVERROR_STREAM_NOT_FOUND => Self::StreamNotFound,
            AVERROR_BUG2 => Self::Bug2,
            AVERROR_UNKNOWN => Self::Unknown,
            AVERROR_HTTP_BAD_REQUEST => Self::HttpBadRequest,
            AVERROR_HTTP_UNAUTHORIZED => Self::HttpUnauthorized,
            AVERROR_HTTP_FORBIDDEN => Self::HttpForbidden,
            AVERROR_HTTP_NOT_FOUND => Self::HttpNotFound,
            AVERROR_HTTP_OTHER_4XX => Self::HttpOther4xx,
            AVERROR_HTTP_SERVER_ERROR => Self::HttpServerError,
            _ => Self::Unknown
        }
    }
}

fn error_desc (err: i32) -> CString {
    extern "C" {
        fn strlen (p: *const c_char) -> usize;
    }

    let mut str = Vec::<c_char>::with_capacity(AV_ERROR_MAX_STRING_SIZE);
    let desc = unsafe {
        av_strerror(err, str.as_mut_ptr(), AV_ERROR_MAX_STRING_SIZE)
    };

    match desc {
        x if x < 0 => unsafe {
            let len = strlen(str.as_ptr()) + 1;
            str.set_len(len);
            str.shrink_to_fit();

            let cstr = CString::from_raw(str.as_mut_ptr());
            core::mem::forget(str);
            cstr
        },

        _ => CString::new(Vec::new()).unwrap()
    }
}