#[repr(u8)]
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ParseErrorKind {
BlockSizeIsEmpty,
BlockSizeStartsWithZero,
BlockSizeIsInvalid,
BlockSizeIsTooLarge,
BlockHashIsTooLong,
UnexpectedCharacter,
UnexpectedEndOfString,
}
impl core::fmt::Display for ParseErrorKind {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(match self {
ParseErrorKind::BlockHashIsTooLong => "block hash is too long",
ParseErrorKind::BlockSizeIsEmpty => "block size field is empty",
ParseErrorKind::BlockSizeStartsWithZero => "block size starts with '0'",
ParseErrorKind::BlockSizeIsInvalid => "block size is not valid",
ParseErrorKind::BlockSizeIsTooLarge => "block size is too large",
ParseErrorKind::UnexpectedCharacter => "an unexpected character is encountered",
ParseErrorKind::UnexpectedEndOfString => "end-of-string is not expected",
})
}
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ParseErrorOrigin {
BlockSize,
BlockHash1,
BlockHash2,
}
impl core::fmt::Display for ParseErrorOrigin {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(match self {
ParseErrorOrigin::BlockSize => "block size",
ParseErrorOrigin::BlockHash1 => "block hash 1",
ParseErrorOrigin::BlockHash2 => "block hash 2",
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ParseError(
pub(crate) ParseErrorKind,
pub(crate) ParseErrorOrigin,
pub(crate) usize
);
pub trait ParseErrorInfo {
fn kind(&self) -> ParseErrorKind;
fn origin(&self) -> ParseErrorOrigin;
fn offset(&self) -> usize;
}
impl ParseErrorInfo for ParseError {
fn kind(&self) -> ParseErrorKind { self.0 }
fn origin(&self) -> ParseErrorOrigin { self.1 }
fn offset(&self) -> usize { self.2 }
}
impl core::fmt::Display for ParseError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "error occurred while parsing a fuzzy hash ({1}, at byte offset {2}): {0}",
self.kind(),
self.origin(),
self.offset()
)
}
}
#[cfg(feature = "std")]
impl std::error::Error for ParseError {}
#[cfg(all(not(feature = "std"), feature = "nightly"))]
impl core::error::Error for ParseError {}
#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum BlockHashParseState {
MetEndOfString,
MetComma,
MetColon,
OverflowError,
Base64Error,
}
#[cfg(test)]
pub(crate) mod tests {
use super::*;
use crate::test_utils::test_auto_clone;
use crate::test_utils::test_auto_debug_for_enum;
#[test]
fn parse_error_kind_impls() {
test_auto_clone::<ParseErrorKind>(&ParseErrorKind::BlockHashIsTooLong);
assert_eq!(format!("{}", ParseErrorKind::BlockHashIsTooLong), "block hash is too long");
assert_eq!(format!("{}", ParseErrorKind::BlockSizeIsEmpty), "block size field is empty");
assert_eq!(format!("{}", ParseErrorKind::BlockSizeStartsWithZero), "block size starts with '0'");
assert_eq!(format!("{}", ParseErrorKind::BlockSizeIsInvalid), "block size is not valid");
assert_eq!(format!("{}", ParseErrorKind::BlockSizeIsTooLarge), "block size is too large");
assert_eq!(format!("{}", ParseErrorKind::UnexpectedCharacter), "an unexpected character is encountered");
assert_eq!(format!("{}", ParseErrorKind::UnexpectedEndOfString), "end-of-string is not expected");
test_auto_debug_for_enum!(
ParseErrorKind,
[
BlockSizeIsEmpty,
BlockSizeStartsWithZero,
BlockSizeIsInvalid,
BlockSizeIsTooLarge,
BlockHashIsTooLong,
UnexpectedCharacter,
UnexpectedEndOfString,
]
);
}
#[test]
fn parse_error_origin_impls() {
test_auto_clone::<ParseErrorOrigin>(&ParseErrorOrigin::BlockSize);
#[cfg(feature = "alloc")]
{
assert_eq!(format!("{}", ParseErrorOrigin::BlockSize), "block size");
assert_eq!(format!("{}", ParseErrorOrigin::BlockHash1), "block hash 1");
assert_eq!(format!("{}", ParseErrorOrigin::BlockHash2), "block hash 2");
test_auto_debug_for_enum!(
ParseErrorOrigin,
[
BlockSize,
BlockHash1,
BlockHash2,
]
);
}
}
#[test]
fn block_hash_parse_state_impls() {
test_auto_clone::<BlockHashParseState>(&BlockHashParseState::MetEndOfString);
#[cfg(feature = "alloc")]
{
test_auto_debug_for_enum!(
BlockHashParseState,
[
MetEndOfString,
MetComma,
MetColon,
OverflowError,
Base64Error,
]
);
}
}
#[test]
fn parse_error_basic_and_impls() {
const KIND: ParseErrorKind = ParseErrorKind::UnexpectedEndOfString;
const ORIGIN: ParseErrorOrigin = ParseErrorOrigin::BlockHash1;
const OFFSET: usize = 2;
let err = ParseError(KIND, ORIGIN, OFFSET);
test_auto_clone::<ParseError>(&err);
assert_eq!(err.kind(), KIND);
assert_eq!(err.origin(), ORIGIN);
assert_eq!(err.offset(), OFFSET);
}
pub(crate) const PARSE_ERROR_CASES: [(ParseError, &str, &str); 3] = [
(ParseError(ParseErrorKind::UnexpectedEndOfString, ParseErrorOrigin::BlockSize, 0), "(block size, at byte offset 0): end-of-string is not expected", "ParseError(UnexpectedEndOfString, BlockSize, 0)"),
(ParseError(ParseErrorKind::UnexpectedEndOfString, ParseErrorOrigin::BlockHash1, 2), "(block hash 1, at byte offset 2): end-of-string is not expected", "ParseError(UnexpectedEndOfString, BlockHash1, 2)"),
(ParseError(ParseErrorKind::BlockSizeIsInvalid, ParseErrorOrigin::BlockSize, 0), "(block size, at byte offset 0): block size is not valid", "ParseError(BlockSizeIsInvalid, BlockSize, 0)"),
];
#[test]
fn parse_error_impls_display_and_debug() {
for (err, err_str_display, err_str_debug) in PARSE_ERROR_CASES {
assert_eq!(
format!("{}", err),
format!("error occurred while parsing a fuzzy hash {}", err_str_display)
);
assert_eq!(format!("{:?}", err), err_str_debug);
}
}
}