use alloc::collections::TryReserveError;
use alloc::string::String;
use core::fmt;
use enough::StopReason;
use whereat::{At, at};
pub type Result<T> = core::result::Result<T, At<HeicError>>;
#[derive(Debug)]
#[non_exhaustive]
pub enum HeicError {
InvalidContainer(&'static str),
InvalidData(&'static str),
Unsupported(&'static str),
NoPrimaryImage,
HevcDecode(HevcError),
BufferTooSmall {
required: usize,
actual: usize,
},
LimitExceeded(&'static str),
OutOfMemory,
Cancelled(StopReason),
Sink(alloc::boxed::Box<dyn core::error::Error + Send + Sync>),
UnsupportedCodec(&'static str),
}
impl fmt::Display for HeicError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidContainer(msg) => write!(f, "invalid HEIF container: {msg}"),
Self::InvalidData(msg) => write!(f, "invalid data: {msg}"),
Self::Unsupported(msg) => write!(f, "unsupported: {msg}"),
Self::NoPrimaryImage => write!(f, "no primary image in container"),
Self::HevcDecode(e) => write!(f, "HEVC decode error: {e}"),
Self::BufferTooSmall { required, actual } => {
write!(f, "buffer too small: need {required}, got {actual}")
}
Self::LimitExceeded(msg) => write!(f, "limit exceeded: {msg}"),
Self::OutOfMemory => write!(f, "out of memory"),
Self::Cancelled(reason) => write!(f, "{reason}"),
Self::Sink(e) => write!(f, "decode sink error: {e}"),
Self::UnsupportedCodec(msg) => write!(f, "unsupported codec: {msg}"),
}
}
}
impl core::error::Error for HeicError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
Self::HevcDecode(e) => Some(e),
Self::Sink(e) => Some(e.as_ref()),
_ => None,
}
}
}
impl From<HevcError> for HeicError {
fn from(e: HevcError) -> Self {
Self::HevcDecode(e)
}
}
impl From<StopReason> for HeicError {
fn from(r: StopReason) -> Self {
Self::Cancelled(r)
}
}
impl From<TryReserveError> for HeicError {
fn from(_: TryReserveError) -> Self {
Self::OutOfMemory
}
}
impl From<HevcError> for At<HeicError> {
#[track_caller]
fn from(e: HevcError) -> Self {
at!(HeicError::from(e))
}
}
#[track_caller]
pub(crate) fn check_stop(stop: &dyn enough::Stop) -> Result<()> {
stop.check().map_err(|r| at!(HeicError::Cancelled(r)))
}
#[derive(Debug)]
#[non_exhaustive]
pub enum HevcError {
InvalidNalUnit(&'static str),
InvalidBitstream(&'static str),
MissingParameterSet(&'static str),
InvalidParameterSet {
kind: &'static str,
msg: String,
},
CabacError(&'static str),
UnsupportedProfile {
profile: u8,
level: u8,
},
Unsupported(&'static str),
DecodingError(&'static str),
AllocationFailed,
DimensionOverflow,
}
impl fmt::Display for HevcError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidNalUnit(msg) => write!(f, "invalid NAL unit: {msg}"),
Self::InvalidBitstream(msg) => write!(f, "invalid bitstream: {msg}"),
Self::MissingParameterSet(kind) => write!(f, "missing {kind}"),
Self::InvalidParameterSet { kind, msg } => {
write!(f, "invalid {kind}: {msg}")
}
Self::CabacError(msg) => write!(f, "CABAC error: {msg}"),
Self::UnsupportedProfile { profile, level } => {
write!(f, "unsupported profile {profile} level {level}")
}
Self::Unsupported(msg) => write!(f, "unsupported: {msg}"),
Self::DecodingError(msg) => write!(f, "decoding error: {msg}"),
Self::AllocationFailed => write!(f, "memory allocation failed"),
Self::DimensionOverflow => write!(f, "frame dimensions overflow"),
}
}
}
impl core::error::Error for HevcError {}
impl From<TryReserveError> for HevcError {
fn from(_: TryReserveError) -> Self {
Self::AllocationFailed
}
}
#[derive(Debug)]
#[non_exhaustive]
pub enum ProbeError {
NeedMoreData,
InvalidFormat,
Corrupt(At<HeicError>),
}
impl fmt::Display for ProbeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::NeedMoreData => write!(f, "not enough data to parse header"),
Self::InvalidFormat => write!(f, "not a valid HEIC/HEIF file"),
Self::Corrupt(e) => write!(f, "corrupt header: {e}"),
}
}
}
impl core::error::Error for ProbeError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
Self::Corrupt(e) => Some(e),
_ => None,
}
}
}