use crate::common::Size;
use core::fmt;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Error {
SizeMismatch {
expected: Size,
actual: Size,
},
LengthMismatch {
expected: usize,
actual: usize,
},
ChannelCountMismatch {
expected: usize,
actual: usize,
},
TemplateTooLarge {
image_size: Size,
template_size: Size,
},
InvalidBinningStrategy(String),
AccumulatorOverflow {
required_capacity: u128,
accumulator_capacity: u128,
},
LabelOverflow {
label_capacity: u64,
},
}
impl std::error::Error for Error {}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::SizeMismatch { expected, actual } => {
write!(
f,
"size mismatch: expected {}x{}, got {}x{}",
expected.width, expected.height, actual.width, actual.height
)
}
Error::LengthMismatch { expected, actual } => {
write!(
f,
"length mismatch: expected {} elements, got {}",
expected, actual
)
}
Error::ChannelCountMismatch { expected, actual } => {
write!(
f,
"channel count mismatch: expected {} channels, got {}",
expected, actual
)
}
Error::TemplateTooLarge {
image_size,
template_size,
} => {
write!(
f,
"template {}x{} is larger than image {}x{}",
template_size.width, template_size.height, image_size.width, image_size.height
)
}
Error::InvalidBinningStrategy(reason) => {
write!(f, "invalid binning strategy: {}", reason)
}
Error::AccumulatorOverflow {
required_capacity,
accumulator_capacity,
} => {
write!(
f,
"accumulator overflow: image requires capacity for {}, \
but accumulator can hold at most {}",
required_capacity, accumulator_capacity
)
}
Error::LabelOverflow { label_capacity } => {
write!(
f,
"label overflow: image contains more components than the \
chosen label type can represent (capacity = {})",
label_capacity
)
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn display_size_mismatch() {
let err = Error::SizeMismatch {
expected: Size::new(640, 480),
actual: Size::new(320, 240),
};
assert_eq!(
err.to_string(),
"size mismatch: expected 640x480, got 320x240"
);
}
#[test]
fn display_length_mismatch() {
let err = Error::LengthMismatch {
expected: 100,
actual: 50,
};
assert_eq!(
err.to_string(),
"length mismatch: expected 100 elements, got 50"
);
}
#[test]
fn display_channel_count_mismatch() {
let err = Error::ChannelCountMismatch {
expected: 3,
actual: 2,
};
assert_eq!(
err.to_string(),
"channel count mismatch: expected 3 channels, got 2"
);
}
#[test]
fn error_is_clone() {
let err = Error::LengthMismatch {
expected: 10,
actual: 5,
};
let cloned = err.clone();
assert_eq!(err, cloned);
}
#[test]
fn error_is_debug() {
let err = Error::SizeMismatch {
expected: Size::new(10, 10),
actual: Size::new(5, 5),
};
let debug = format!("{:?}", err);
assert!(debug.contains("SizeMismatch"));
}
#[test]
fn error_equality() {
let a = Error::LengthMismatch {
expected: 100,
actual: 50,
};
let b = Error::LengthMismatch {
expected: 100,
actual: 50,
};
let c = Error::LengthMismatch {
expected: 100,
actual: 99,
};
assert_eq!(a, b);
assert_ne!(a, c);
}
#[test]
fn display_template_too_large() {
let err = Error::TemplateTooLarge {
image_size: Size::new(10, 10),
template_size: Size::new(20, 15),
};
assert_eq!(err.to_string(), "template 20x15 is larger than image 10x10");
}
#[test]
fn different_variants_not_equal() {
let size_err = Error::SizeMismatch {
expected: Size::new(10, 10),
actual: Size::new(5, 5),
};
let length_err = Error::LengthMismatch {
expected: 100,
actual: 25,
};
assert_ne!(size_err, length_err);
}
#[test]
fn display_invalid_binning_strategy() {
let err = Error::InvalidBinningStrategy("min >= max".to_string());
assert_eq!(err.to_string(), "invalid binning strategy: min >= max");
}
#[test]
fn display_accumulator_overflow() {
let err = Error::AccumulatorOverflow {
required_capacity: 4_278_190_080,
accumulator_capacity: 4_294_967_295,
};
assert_eq!(
err.to_string(),
"accumulator overflow: image requires capacity for 4278190080, \
but accumulator can hold at most 4294967295"
);
}
#[test]
fn accumulator_overflow_equality_and_clone() {
let a = Error::AccumulatorOverflow {
required_capacity: 100,
accumulator_capacity: 50,
};
let b = a.clone();
let c = Error::AccumulatorOverflow {
required_capacity: 100,
accumulator_capacity: 51,
};
assert_eq!(a, b);
assert_ne!(a, c);
}
#[test]
fn display_label_overflow() {
let err = Error::LabelOverflow {
label_capacity: u32::MAX as u64,
};
assert_eq!(
err.to_string(),
"label overflow: image contains more components than the chosen label type \
can represent (capacity = 4294967295)"
);
}
#[test]
fn label_overflow_equality_and_clone() {
let a = Error::LabelOverflow {
label_capacity: 255,
};
let b = a.clone();
let c = Error::LabelOverflow {
label_capacity: 65_535,
};
assert_eq!(a, b);
assert_ne!(a, c);
}
#[test]
fn invalid_binning_strategy_equality_and_clone() {
let a = Error::InvalidBinningStrategy("bin_count == 0".to_string());
let b = a.clone();
let c = Error::InvalidBinningStrategy("non-finite edge".to_string());
assert_eq!(a, b);
assert_ne!(a, c);
}
#[test]
fn error_implements_std_error_trait() {
fn assert_error<E: std::error::Error>() {}
assert_error::<Error>();
let err: Box<dyn std::error::Error> = Box::new(Error::LengthMismatch {
expected: 10,
actual: 5,
});
assert!(err.to_string().contains("length mismatch"));
assert!(err.source().is_none());
}
}