use std::fmt;
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum UnsupportedFeature {
ProgressiveJpeg,
ExtendedSequentialJpeg,
ArithmeticCodedJpeg,
LosslessJpeg,
HierarchicalJpeg,
JpegPrecision {
bits: u8,
},
JpegComponentCount {
components: u8,
},
PngNotEnabled,
JpegChromaSubsampling,
}
impl fmt::Display for UnsupportedFeature {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::ProgressiveJpeg => write!(f, "progressive JPEG (SOF2)"),
Self::ExtendedSequentialJpeg => {
write!(f, "extended sequential JPEG (SOF1)")
}
Self::ArithmeticCodedJpeg => write!(
f,
"arithmetic-coded JPEG (SOF9/SOF10/SOF11/SOF13/SOF14/SOF15)"
),
Self::LosslessJpeg => write!(f, "lossless JPEG (SOF3)"),
Self::HierarchicalJpeg => write!(f, "hierarchical JPEG (SOF5/SOF6/SOF7)"),
Self::JpegPrecision { bits } => {
write!(f, "JPEG sample precision {bits} (only 8-bit is supported)")
}
Self::JpegComponentCount { components } => {
write!(
f,
"JPEG component count {components} (only 1 or 3 are supported)"
)
}
Self::PngNotEnabled => write!(
f,
"PNG decoding is not enabled in this build (enable the `png` feature)"
),
Self::JpegChromaSubsampling => {
write!(f, "JPEG chroma subsampling that exceeds luma sampling rate")
}
}
}
}
#[derive(Debug)]
pub enum CodecError {
InsufficientCapacity {
image: (usize, usize),
tensor: (usize, usize),
},
UnsupportedDtype(edgefirst_tensor::DType),
UnsupportedFormat(edgefirst_tensor::PixelFormat),
Unsupported(UnsupportedFeature),
InvalidData(String),
Io(std::io::Error),
Tensor(edgefirst_tensor::Error),
NoDevice(String),
InvalidConfig(String),
InvalidInput(String),
Device {
op: String,
source: std::io::Error,
},
Timeout(String),
PoolExhausted {
held: usize,
pool: usize,
},
}
impl fmt::Display for CodecError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InsufficientCapacity { image, tensor } => write!(
f,
"image dimensions {}×{} exceed tensor capacity {}×{}",
image.0, image.1, tensor.0, tensor.1,
),
Self::UnsupportedDtype(dt) => {
write!(f, "unsupported tensor dtype {dt:?} for image decode")
}
Self::UnsupportedFormat(pf) => {
write!(f, "unsupported pixel format {pf:?} for image decode")
}
Self::Unsupported(feat) => write!(f, "unsupported image feature: {feat}"),
Self::InvalidData(msg) => write!(f, "invalid image data: {msg}"),
Self::Io(e) => write!(f, "I/O error: {e}"),
Self::Tensor(e) => write!(f, "tensor error: {e}"),
Self::NoDevice(what) => write!(f, "no device: {what}"),
Self::InvalidConfig(what) => write!(f, "invalid configuration: {what}"),
Self::InvalidInput(what) => write!(f, "invalid input: {what}"),
Self::Device { op, source } => write!(f, "{op} failed: {source}"),
Self::Timeout(what) => write!(f, "timed out: {what}"),
Self::PoolExhausted { held, pool } => write!(
f,
"{held} of {pool} decoder output buffers are held by frames not yet dropped"
),
}
}
}
impl std::error::Error for CodecError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Io(e) => Some(e),
Self::Tensor(e) => Some(e),
Self::Device { source, .. } => Some(source),
_ => None,
}
}
}
impl CodecError {
pub fn cpu_access_denied(&self) -> Option<&edgefirst_tensor::Error> {
match self {
Self::Tensor(e) => e.cpu_access_denied(),
_ => None,
}
}
}
impl From<std::io::Error> for CodecError {
fn from(e: std::io::Error) -> Self {
Self::Io(e)
}
}
impl From<edgefirst_tensor::Error> for CodecError {
fn from(e: edgefirst_tensor::Error) -> Self {
Self::Tensor(e)
}
}
#[cfg(feature = "png")]
impl From<zune_png::error::PngDecodeErrors> for CodecError {
fn from(e: zune_png::error::PngDecodeErrors) -> Self {
Self::InvalidData(format!("PNG: {e}"))
}
}