#![cfg(feature = "easy-functions")]
use core::str::FromStr;
use crate::hash::LongFuzzyHash;
use crate::hash::parser_state::{
ParseError, ParseErrorKind, ParseErrorOrigin, ParseErrorInfo
};
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ParseErrorSide {
Left,
Right,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ParseErrorEither(ParseErrorSide, ParseError);
impl ParseErrorEither {
pub fn side(&self) -> ParseErrorSide { self.0 }
}
impl ParseErrorInfo for ParseErrorEither {
fn kind(&self) -> ParseErrorKind { self.1.kind() }
fn origin(&self) -> ParseErrorOrigin { self.1.origin() }
fn offset(&self) -> usize { self.1.offset() }
}
impl core::fmt::Display for ParseErrorEither {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "Error occurred while parsing fuzzy hash {3} ({1}, at byte offset {2}): {0}",
self.kind(),
self.origin(),
self.offset(),
match self.side() {
ParseErrorSide::Left => 1,
ParseErrorSide::Right => 2,
}
)
}
}
#[cfg(feature = "std")]
impl std::error::Error for ParseErrorEither {}
pub fn compare(lhs: &str, rhs: &str) -> Result<u32, ParseErrorEither> {
let lhs = match LongFuzzyHash::from_str(lhs) {
Ok(value) => { value }
Err(err) => { return Err(ParseErrorEither(ParseErrorSide::Left, err)); }
};
let rhs = match LongFuzzyHash::from_str(rhs) {
Ok(value) => { value }
Err(err) => { return Err(ParseErrorEither(ParseErrorSide::Right, err)); }
};
Ok(lhs.compare(rhs.as_ref()))
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "alloc")]
use alloc::format;
use crate::hash::parser_state::{ParseError, ParseErrorKind, ParseErrorOrigin};
use crate::test_utils::test_auto_clone;
#[test]
fn test_parse_error_side_basic() {
test_auto_clone::<ParseErrorSide>(&ParseErrorSide::Left);
#[cfg(feature = "alloc")]
{
crate::test_utils::test_auto_debug_for_enum!(
ParseErrorSide,
[
Left,
Right,
]
);
}
}
#[test]
fn test_parse_error_either_basic() {
let err = ParseErrorEither(
ParseErrorSide::Left,
ParseError(ParseErrorKind::UnexpectedEndOfString, ParseErrorOrigin::BlockHash1, 2)
);
test_auto_clone::<ParseErrorEither>(&err);
assert_eq!(err.side(), ParseErrorSide::Left);
assert_eq!(err.kind(), ParseErrorKind::UnexpectedEndOfString);
assert_eq!(err.origin(), ParseErrorOrigin::BlockHash1);
assert_eq!(err.offset(), 2);
#[cfg(feature = "alloc")]
{
assert_eq!(
format!("{:?}", err),
"ParseErrorEither(Left, ParseError(UnexpectedEndOfString, BlockHash1, 2))"
);
}
}
#[test]
fn test_compare_ok() {
assert_eq!(
compare(
"6:3ll7QzDkmJmMHkQoO/llSZEnEuLszmbMAWn:VqDk5QtLbW",
"6:3ll7QzDkmQjmMoDHglHOxPWT0lT0lT0lB:VqDk+n"
).unwrap(),
46
);
}
#[test]
fn test_compare_err() {
assert_eq!(compare("3,::", "3::"), Err(ParseErrorEither(
ParseErrorSide::Left,
ParseError(ParseErrorKind::UnexpectedCharacter, ParseErrorOrigin::BlockSize, 1))
));
assert_eq!(compare("3::", "4::"), Err(ParseErrorEither(
ParseErrorSide::Right,
ParseError(ParseErrorKind::BlockSizeIsInvalid, ParseErrorOrigin::BlockSize, 0))
));
assert!(compare("3,::", "4::").is_err());
}
#[test]
fn test_compare_error_side() {
let hstr_valid = "3::";
let hstr_err_empty = "";
let hstr_err_eos_bh1 = "3:";
let hstr_err_bs_invalid = "4::";
let err_empty = ParseError(ParseErrorKind::UnexpectedEndOfString, ParseErrorOrigin::BlockSize, 0);
let err_eos_bh1 = ParseError(ParseErrorKind::UnexpectedEndOfString, ParseErrorOrigin::BlockHash1, 2);
let err_bs_invalid = ParseError(ParseErrorKind::BlockSizeIsInvalid, ParseErrorOrigin::BlockSize, 0);
assert_eq!(compare(hstr_err_empty, hstr_valid), Err(ParseErrorEither(ParseErrorSide::Left, err_empty)));
assert_eq!(compare(hstr_err_eos_bh1, hstr_valid), Err(ParseErrorEither(ParseErrorSide::Left, err_eos_bh1)));
assert_eq!(compare(hstr_err_bs_invalid, hstr_valid), Err(ParseErrorEither(ParseErrorSide::Left, err_bs_invalid)));
assert_eq!(compare(hstr_valid, hstr_err_empty), Err(ParseErrorEither(ParseErrorSide::Right, err_empty)));
assert_eq!(compare(hstr_valid, hstr_err_eos_bh1), Err(ParseErrorEither(ParseErrorSide::Right, err_eos_bh1)));
assert_eq!(compare(hstr_valid, hstr_err_bs_invalid), Err(ParseErrorEither(ParseErrorSide::Right, err_bs_invalid)));
}
#[cfg(feature = "alloc")]
#[test]
fn test_compare_error_str() {
let err_empty = ParseError(ParseErrorKind::UnexpectedEndOfString, ParseErrorOrigin::BlockSize, 0);
let err_eos_bh1 = ParseError(ParseErrorKind::UnexpectedEndOfString, ParseErrorOrigin::BlockHash1, 2);
let err_bs_invalid = ParseError(ParseErrorKind::BlockSizeIsInvalid, ParseErrorOrigin::BlockSize, 0);
assert_eq!(format!("{}", ParseErrorEither(ParseErrorSide::Left, err_empty)),
"Error occurred while parsing fuzzy hash 1 (block size, at byte offset 0): end-of-string is not expected.");
assert_eq!(format!("{}", ParseErrorEither(ParseErrorSide::Right, err_empty)),
"Error occurred while parsing fuzzy hash 2 (block size, at byte offset 0): end-of-string is not expected.");
assert_eq!(format!("{}", ParseErrorEither(ParseErrorSide::Left, err_eos_bh1)),
"Error occurred while parsing fuzzy hash 1 (block hash 1, at byte offset 2): end-of-string is not expected.");
assert_eq!(format!("{}", ParseErrorEither(ParseErrorSide::Right, err_eos_bh1)),
"Error occurred while parsing fuzzy hash 2 (block hash 1, at byte offset 2): end-of-string is not expected.");
assert_eq!(format!("{}", ParseErrorEither(ParseErrorSide::Left, err_bs_invalid)),
"Error occurred while parsing fuzzy hash 1 (block size, at byte offset 0): block size is not valid.");
assert_eq!(format!("{}", ParseErrorEither(ParseErrorSide::Right, err_bs_invalid)),
"Error occurred while parsing fuzzy hash 2 (block size, at byte offset 0): block size is not valid.");
}
}