use std::error::Error as StdError;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(thiserror::Error, Debug)]
#[error(transparent)]
pub enum Error {
#[error("Error processing header: {0}")]
HeaderError(#[from] HeaderError),
#[error("Error writing file: {0}")]
WriteError(#[from] WriteError),
#[error("Error reading file: {0}")]
ReadError(#[from] ReadError),
#[error("Error building file: {0}")]
BuilderError(#[from] BuilderError),
#[error("Error processing Index: {0}")]
IndexError(#[from] IndexError),
#[error("Error with IO: {0}")]
IoError(#[from] std::io::Error),
#[error("Error with UTF8: {0}")]
Utf8Error(#[from] std::str::Utf8Error),
ExtensionError(#[from] ExtensionError),
#[error("Bitnuc error: {0}")]
BitnucError(#[from] bitnuc::Error),
#[error("Generic error: {0}")]
AnyhowError(#[from] anyhow::Error),
#[error("Generic error: {0}")]
GenericError(#[from] Box<dyn StdError + Send + Sync>),
}
impl Error {
#[must_use]
pub fn is_index_mismatch(&self) -> bool {
match self {
Self::IndexError(err) => err.is_mismatch(),
_ => false,
}
}
}
#[derive(thiserror::Error, Debug)]
pub enum HeaderError {
#[error("Invalid magic number: {0}")]
InvalidMagicNumber(u32),
#[error("Invalid format version: {0}")]
InvalidFormatVersion(u8),
#[error("Invalid reserved bytes")]
InvalidReservedBytes,
#[error("Invalid bit size found in header: {0} - expecting [2,4]")]
InvalidBitSize(u8),
#[error("Invalid number of bytes provided: {0}. Expected: {1}")]
InvalidSize(usize, usize),
}
#[derive(thiserror::Error, Debug)]
pub enum ReadError {
#[error("File is not regular")]
IncompatibleFile,
#[error(
"Number of bytes in file does not match expectation - possibly truncated at byte pos {0}"
)]
FileTruncation(usize),
#[error("Requested record index ({0}) is out of record range ({1})")]
OutOfRange(usize, usize),
#[error("End of stream reached")]
EndOfStream,
#[error("Partial record at end of stream ({0} bytes)")]
PartialRecord(usize),
#[error("Unexpected Block Magic Number found: {0} at position {1}")]
InvalidBlockMagicNumber(u64, usize),
#[error("Unable to find an expected full block at position {0}")]
UnexpectedEndOfFile(usize),
#[error("Unexpected file metadata")]
InvalidFileType,
#[error("Missing index end magic number")]
MissingIndexEndMagic,
}
#[derive(thiserror::Error, Debug)]
pub enum BuilderError {
#[error("Missing sequence length")]
MissingSlen,
}
#[derive(thiserror::Error, Debug)]
pub enum WriteError {
#[error("Sequence length ({got}) does not match the header ({expected})")]
UnexpectedSequenceLength { expected: u32, got: usize },
#[error("Invalid nucleotides found in sequence: {0}")]
InvalidNucleotideSequence(String),
#[error("Missing header in writer builder")]
MissingHeader,
#[error("Quality flag is set in header but trying to write without quality scores.")]
QualityFlagSet,
#[error("Paired flag is set in header but trying to write without record pair.")]
PairedFlagSet,
#[error("Quality flag not set in header but trying to write quality scores.")]
QualityFlagNotSet,
#[error("Paired flag not set in header but trying to write with record pair.")]
PairedFlagNotSet,
#[error("Header flag is set in header but trying to write without headers.")]
HeaderFlagSet,
#[error("Encountered a record with embedded size {0} but the maximum block size is {1}. Rerun with increased block size.")]
RecordSizeExceedsMaximumBlockSize(usize, usize),
#[error(
"Incompatible block sizes encountered in BlockWriter Ingest. Found ({1}) Expected ({0})"
)]
IncompatibleBlockSizes(usize, usize),
#[error("Incompatible headers found in VBinseqWriter::ingest. Found ({1:?}) Expected ({0:?})")]
IncompatibleHeaders(crate::vbq::VBinseqHeader, crate::vbq::VBinseqHeader),
}
#[derive(thiserror::Error, Debug)]
pub enum IndexError {
#[error("Invalid magic number: {0}")]
InvalidMagicNumber(u64),
#[error("Index missing upstream file path: {0}")]
MissingUpstreamFile(String),
#[error("Mismatch in size between upstream size: {0} and expected index size {1}")]
ByteSizeMismatch(u64, u64),
#[error("Invalid reserved bytes in index header")]
InvalidReservedBytes,
}
impl IndexError {
#[must_use]
pub fn is_mismatch(&self) -> bool {
matches!(self, Self::ByteSizeMismatch(_, _) | _) }
}
#[derive(thiserror::Error, Debug)]
pub enum ExtensionError {
#[error("Unsupported extension in path: {0}")]
UnsupportedExtension(String),
}
pub trait IntoBinseqError {
fn into_binseq_error(self) -> Error;
}
impl<E> IntoBinseqError for E
where
E: StdError + Send + Sync + 'static,
{
fn into_binseq_error(self) -> Error {
Error::GenericError(Box::new(self))
}
}
mod testing {
#[allow(unused)]
use super::*;
use thiserror::Error;
#[allow(unused)]
#[derive(Error, Debug)]
pub enum MyError {
#[error("Custom error: {0}")]
CustomError(String),
}
#[test]
fn test_into_binseq_error() {
let my_error = MyError::CustomError(String::from("some error"));
let binseq_error = my_error.into_binseq_error();
assert!(matches!(binseq_error, Error::GenericError(_)));
}
}