use std::{fmt, io};
use std::error::Error;
use crate::color::ExtendedColorType;
use crate::image::ImageFormat;
use crate::utils::NonExhaustiveMarker;
#[derive(Debug)]
pub enum ImageError {
Decoding(DecodingError),
Encoding(EncodingError),
Parameter(ParameterError),
Limits(LimitError),
Unsupported(UnsupportedError),
IoError(io::Error),
}
#[derive(Debug)]
pub struct UnsupportedError {
format: ImageFormatHint,
kind: UnsupportedErrorKind,
}
#[derive(Clone, Debug, Hash, PartialEq)]
pub enum UnsupportedErrorKind {
Color(ExtendedColorType),
Format(ImageFormatHint),
GenericFeature(String),
#[doc(hidden)]
__NonExhaustive(NonExhaustiveMarker),
}
#[derive(Debug)]
pub struct EncodingError {
format: ImageFormatHint,
underlying: Option<Box<dyn Error + Send + Sync>>,
}
#[derive(Debug)]
pub struct ParameterError {
kind: ParameterErrorKind,
underlying: Option<Box<dyn Error + Send + Sync>>,
}
#[derive(Clone, Debug, Hash, PartialEq)]
pub enum ParameterErrorKind {
FailedAlready,
DimensionMismatch,
Generic(String),
#[doc(hidden)]
__NonExhaustive(NonExhaustiveMarker),
}
#[derive(Debug)]
pub struct DecodingError {
format: ImageFormatHint,
message: Option<Box<str>>,
underlying: Option<Box<dyn Error + Send + Sync>>,
}
#[derive(Debug)]
pub struct LimitError {
kind: LimitErrorKind,
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
#[allow(missing_copy_implementations)]
pub enum LimitErrorKind {
DimensionError,
InsufficientMemory,
#[doc(hidden)]
__NonExhaustive(NonExhaustiveMarker),
}
#[derive(Clone, Debug, Hash, PartialEq)]
pub enum ImageFormatHint {
Exact(ImageFormat),
Name(String),
PathExtension(std::path::PathBuf),
Unknown,
#[doc(hidden)]
__NonExhaustive(NonExhaustiveMarker),
}
#[allow(non_upper_case_globals)]
#[allow(non_snake_case)]
impl ImageError {
pub(crate) const InsufficientMemory: Self =
ImageError::Limits(LimitError {
kind: LimitErrorKind::InsufficientMemory,
});
pub(crate) const DimensionError: Self =
ImageError::Parameter(ParameterError {
kind: ParameterErrorKind::DimensionMismatch,
underlying: None,
});
pub(crate) const ImageEnd: Self =
ImageError::Parameter(ParameterError {
kind: ParameterErrorKind::FailedAlready,
underlying: None,
});
pub(crate) fn UnsupportedError(message: String) -> Self {
ImageError::Unsupported(UnsupportedError::legacy_from_string(message))
}
pub(crate) fn UnsupportedColor(color: ExtendedColorType) -> Self {
ImageError::Unsupported(UnsupportedError::from_format_and_kind(
ImageFormatHint::Unknown,
UnsupportedErrorKind::Color(color),
))
}
pub(crate) fn FormatError(message: String) -> Self {
ImageError::Decoding(DecodingError::legacy_from_string(message))
}
}
impl UnsupportedError {
pub fn from_format_and_kind(format: ImageFormatHint, kind: UnsupportedErrorKind) -> Self {
UnsupportedError {
format,
kind,
}
}
pub(crate) fn legacy_from_string(message: String) -> Self {
UnsupportedError {
format: ImageFormatHint::Unknown,
kind: UnsupportedErrorKind::GenericFeature(message),
}
}
pub fn kind(&self) -> UnsupportedErrorKind {
self.kind.clone()
}
pub fn format_hint(&self) -> ImageFormatHint {
self.format.clone()
}
}
impl DecodingError {
pub fn new(
format: ImageFormatHint,
err: impl Into<Box<dyn Error + Send + Sync>>,
) -> Self {
DecodingError {
format,
message: None,
underlying: Some(err.into()),
}
}
pub fn from_format_hint(format: ImageFormatHint) -> Self {
DecodingError {
format,
message: None,
underlying: None,
}
}
pub fn format_hint(&self) -> ImageFormatHint {
self.format.clone()
}
pub(crate) fn legacy_from_string(message: String) -> Self {
DecodingError {
format: ImageFormatHint::Unknown,
message: Some(message.into_boxed_str()),
underlying: None,
}
}
pub(crate) fn with_message(
format: ImageFormatHint,
message: String,
) -> Self {
DecodingError {
format,
message: Some(message.into_boxed_str()),
underlying: None,
}
}
fn get_message_or_default(&self) -> &str {
match &self.message {
Some(st) => st,
None => "",
}
}
}
impl EncodingError {
pub fn new(
format: ImageFormatHint,
err: impl Into<Box<dyn Error + Send + Sync>>,
) -> Self {
EncodingError {
format,
underlying: Some(err.into()),
}
}
pub fn from_format_hint(format: ImageFormatHint) -> Self {
EncodingError {
format,
underlying: None,
}
}
pub fn format_hint(&self) -> ImageFormatHint {
self.format.clone()
}
}
impl ParameterError {
pub fn from_kind(kind: ParameterErrorKind) -> Self {
ParameterError {
kind,
underlying: None,
}
}
pub fn kind(&self) -> ParameterErrorKind {
self.kind.clone()
}
}
impl LimitError {
pub fn from_kind(kind: LimitErrorKind) -> Self {
LimitError {
kind,
}
}
pub fn kind(&self) -> LimitErrorKind {
self.kind.clone()
}
}
impl From<io::Error> for ImageError {
fn from(err: io::Error) -> ImageError {
ImageError::IoError(err)
}
}
impl From<ImageFormat> for ImageFormatHint {
fn from(format: ImageFormat) -> Self {
ImageFormatHint::Exact(format)
}
}
impl From<&'_ std::path::Path> for ImageFormatHint {
fn from(path: &'_ std::path::Path) -> Self {
match path.extension() {
Some(ext) => ImageFormatHint::PathExtension(ext.into()),
None => ImageFormatHint::Unknown,
}
}
}
impl From<ImageFormatHint> for UnsupportedError {
fn from(hint: ImageFormatHint) -> Self {
UnsupportedError {
format: hint.clone(),
kind: UnsupportedErrorKind::Format(hint),
}
}
}
pub type ImageResult<T> = Result<T, ImageError>;
impl fmt::Display for ImageError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match self {
ImageError::IoError(err) => err.fmt(fmt),
ImageError::Decoding(err) => err.fmt(fmt),
ImageError::Encoding(err) => err.fmt(fmt),
ImageError::Parameter(err) => err.fmt(fmt),
ImageError::Limits(err) => err.fmt(fmt),
ImageError::Unsupported(err) => err.fmt(fmt),
}
}
}
impl Error for ImageError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
ImageError::IoError(err) => err.source(),
ImageError::Decoding(err) => err.source(),
ImageError::Encoding(err) => err.source(),
ImageError::Parameter(err) => err.source(),
ImageError::Limits(err) => err.source(),
ImageError::Unsupported(err) => err.source(),
}
}
}
impl fmt::Display for UnsupportedError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match &self.kind {
UnsupportedErrorKind::Format(ImageFormatHint::Unknown) => write!(
fmt,
"The image format could not be determined",
),
UnsupportedErrorKind::Format(format @ ImageFormatHint::PathExtension(_)) => write!(
fmt,
"The file extension {} was not recognized as an image format",
format,
),
UnsupportedErrorKind::Format(format) => write!(
fmt,
"The image format {} is not supported",
format,
),
UnsupportedErrorKind::Color(color) => write!(
fmt,
"The decoder for {} does not support the color type `{:?}`",
self.format,
color,
),
UnsupportedErrorKind::GenericFeature(message) => {
match &self.format {
ImageFormatHint::Unknown => write!(
fmt,
"The decoder does not support the format feature {}",
message,
),
other => write!(
fmt,
"The decoder for {} does not support the format features {}",
other,
message,
),
}
},
UnsupportedErrorKind::__NonExhaustive(marker) => match marker._private {},
}
}
}
impl Error for UnsupportedError { }
impl fmt::Display for ParameterError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match &self.kind {
ParameterErrorKind::DimensionMismatch => write!(
fmt,
"The Image's dimensions are either too \
small or too large"
),
ParameterErrorKind::FailedAlready => write!(
fmt,
"The end the image stream has been reached due to a previous error"
),
ParameterErrorKind::Generic(message) => write!(
fmt,
"The parameter is malformed: {}",
message,
),
ParameterErrorKind::__NonExhaustive(marker) => match marker._private {},
}?;
if let Some(underlying) = &self.underlying {
write!(fmt, "\n{}", underlying)?;
}
Ok(())
}
}
impl Error for ParameterError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match &self.underlying {
None => None,
Some(source) => Some(&**source),
}
}
}
impl fmt::Display for EncodingError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match &self.underlying {
Some(underlying) => write!(
fmt,
"Format error encoding {}:\n{}",
self.format,
underlying,
),
None => write!(
fmt,
"Format error encoding {}",
self.format,
),
}
}
}
impl Error for EncodingError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match &self.underlying {
None => None,
Some(source) => Some(&**source),
}
}
}
impl fmt::Display for DecodingError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match &self.underlying {
None => match self.format {
ImageFormatHint::Unknown => write!(
fmt,
"Format error: {}",
self.get_message_or_default(),
),
_ => write!(
fmt,
"Format error decoding {}: {}",
self.format,
self.get_message_or_default(),
),
},
Some(underlying) => write!(
fmt,
"Format error decoding {}: {}\n{}",
self.format,
self.get_message_or_default(),
underlying,
),
}
}
}
impl Error for DecodingError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match &self.underlying {
None => None,
Some(source) => Some(&**source),
}
}
}
impl fmt::Display for LimitError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match self.kind {
LimitErrorKind::InsufficientMemory => write!(fmt, "Insufficient memory"),
LimitErrorKind::DimensionError => write!(fmt, "Image is too large"),
LimitErrorKind::__NonExhaustive(marker) => match marker._private {},
}
}
}
impl Error for LimitError { }
impl fmt::Display for ImageFormatHint {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match self {
ImageFormatHint::Exact(format) => write!(fmt, "{:?}", format),
ImageFormatHint::Name(name) => write!(fmt, "`{}`", name),
ImageFormatHint::PathExtension(ext) => write!(fmt, "`.{:?}`", ext),
ImageFormatHint::Unknown => write!(fmt, "`Unknown`"),
ImageFormatHint::__NonExhaustive(marker) => match marker._private {},
}
}
}
#[cfg(test)]
mod tests {
use std::mem;
use super::*;
#[allow(dead_code)]
const ASSERT_SMALLISH: usize = [0][(mem::size_of::<ImageError>() >= 200) as usize];
#[test]
fn test_send_sync_stability() {
fn assert_send_sync<T: Send + Sync>() { }
assert_send_sync::<ImageError>();
}
}