use thiserror::Error;
use crate::{media::Media, status::ErrorFlags};
#[derive(Error, Debug)]
pub enum PrintJobCreationError {
#[error("Image dimensions ({actual_width}x{actual_height} px) don't match media requirements (width: {expected_width} px{})",
expected_height.map(|h| format!(", height: {h} px")).unwrap_or_default()
)]
DimensionMismatch {
expected_width: u32,
actual_width: u32,
expected_height: Option<u32>,
actual_height: u32,
},
#[error("Image error: {0}")]
ImageError(#[from] image::ImageError),
}
pub trait ConnectionError {}
#[cfg(feature = "usb")]
#[derive(Error, Debug)]
pub enum UsbError {
#[error("USB device not found (vendor: {vendor_id:#06x}, product: {product_id:#06x})")]
DeviceNotFound {
vendor_id: u16,
product_id: u16,
},
#[error("Incomplete USB write occurred! Please report this issue!")]
IncompleteWrite,
#[error(transparent)]
Rusb(#[from] rusb::Error),
}
#[cfg(feature = "usb")]
impl ConnectionError for UsbError {}
#[derive(Error, Debug)]
pub enum KernelError {
#[error("Kernel IO error: {0}")]
KernelIOError(#[from] std::io::Error),
#[error("Incomplete write occurred! Please report this issue!")]
IncompleteWrite,
#[error("Kernel IO operation timed out")]
KernelIOTimeout,
}
impl ConnectionError for KernelError {}
#[derive(Error, Debug, Clone)]
#[error("Failed to parse status information: {reason}")]
pub struct StatusParsingError {
pub reason: String,
}
#[derive(Error, Debug)]
pub enum StatusError<E: ConnectionError> {
#[error(transparent)]
Connection(#[from] E),
#[error("Printer did not respond with a status information reply after being queried")]
NoResponse,
#[error(transparent)]
Parsing(StatusParsingError),
}
#[derive(Error, Debug, Clone)]
pub enum ProtocolError {
#[error("Printer reported errors: {0:?}")]
PrinterError(ErrorFlags),
#[error(
"Unexpected printer status: expected {expected_type:?}/{expected_phase:?}, got {actual_type:?}/{actual_phase:?}"
)]
UnexpectedStatus {
expected_type: crate::status::StatusType,
expected_phase: crate::status::Phase,
actual_type: crate::status::StatusType,
actual_phase: crate::status::Phase,
},
#[error("Print job requires {expected_media:?} tape but printer reported {reported_media:?}")]
MediaMismatch {
expected_media: Media,
reported_media: Option<Media>,
},
}
#[derive(Error, Debug)]
#[error("Print error on page {page_no}: {source}")]
pub struct PrintError<E: ConnectionError> {
pub page_no: u32,
#[source]
pub source: PrintErrorSource<E>,
}
impl<E: ConnectionError> PrintError<E> {
pub(crate) fn with_page<T: Into<PrintErrorSource<E>>>(err: T, page_no: u32) -> Self {
PrintError {
page_no,
source: err.into(),
}
}
pub(crate) fn err_source_mapper<S>(page_no: u32) -> impl Fn(S) -> Self
where
S: Into<PrintErrorSource<E>>,
{
move |e: S| Self {
page_no,
source: e.into(),
}
}
}
#[derive(Error, Debug)]
#[error(transparent)]
pub enum PrintErrorSource<E: ConnectionError> {
#[error(transparent)]
Connection(#[from] E),
#[error(transparent)]
Status(#[from] StatusError<E>),
#[error(transparent)]
Protocol(#[from] ProtocolError),
}
#[cfg(feature = "test-labels")]
#[derive(Error, Debug)]
#[error("Couldn't create test-label using typst: {reason}")]
pub struct TypstError {
pub reason: String,
}