use std::error::Error;
#[derive(Debug, Clone, Copy)]
pub enum FormatError {
Unimplemented(Format),
}
impl std::fmt::Display for FormatError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::Unimplemented(format) => {
write!(f, "format {:?} is not implemented", format)
}
}
}
}
impl Error for FormatError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
None
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Format {
Octal,
LowerHex,
UpperHex,
Pointer,
Binary,
LowerExp,
UpperExp,
Unknown,
}
impl Format {
pub fn format(&self, data: u8, prefix: bool) -> Result<String, FormatError> {
let formatted = if prefix {
match self {
Self::Octal => format!("{:#06o}", data),
Self::LowerHex => format!("{:#04x}", data),
Self::UpperHex => format!("{:#04X}", data),
Self::Binary => format!("{:#010b}", data),
_ => return Err(FormatError::Unimplemented(*self)),
}
} else {
match self {
Self::Octal => format!("{:04o}", data),
Self::LowerHex => format!("{:02x}", data),
Self::UpperHex => format!("{:02X}", data),
Self::Binary => format!("{:08b}", data),
_ => return Err(FormatError::Unimplemented(*self)),
}
};
Ok(formatted)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::error::Error;
#[test]
fn test_hex_octal() {
let b: u8 = 0x6;
assert_eq!(Format::Octal.format(b, true).unwrap(), "0o0006");
assert_eq!(
Format::Octal.format(b, true).unwrap(),
format!("{:#06o}", b)
);
assert_eq!(Format::Octal.format(b, false).unwrap(), "0006");
assert_eq!(
Format::Octal.format(b, false).unwrap(),
format!("{:04o}", b)
);
}
#[test]
fn test_hex_lower_hex() {
let b: u8 = u8::MAX;
assert_eq!(Format::LowerHex.format(b, true).unwrap(), "0xff");
assert_eq!(
Format::LowerHex.format(b, true).unwrap(),
format!("{:#04x}", b)
);
assert_eq!(Format::LowerHex.format(b, false).unwrap(), "ff");
assert_eq!(
Format::LowerHex.format(b, false).unwrap(),
format!("{:02x}", b)
);
}
#[test]
fn test_hex_upper_hex() {
let b: u8 = u8::MAX;
assert_eq!(Format::UpperHex.format(b, true).unwrap(), "0xFF");
assert_eq!(
Format::UpperHex.format(b, true).unwrap(),
format!("{:#04X}", b)
);
assert_eq!(Format::UpperHex.format(b, false).unwrap(), "FF");
assert_eq!(
Format::UpperHex.format(b, false).unwrap(),
format!("{:02X}", b)
);
}
#[test]
fn test_hex_binary() {
let b: u8 = u8::MAX;
assert_eq!(Format::Binary.format(b, true).unwrap(), "0b11111111");
assert_eq!(
Format::Binary.format(b, true).unwrap(),
format!("{:#010b}", b)
);
assert_eq!(Format::Binary.format(b, false).unwrap(), "11111111");
assert_eq!(
Format::Binary.format(b, false).unwrap(),
format!("{:08b}", b)
);
}
#[test]
fn test_format_error_display() {
let error = FormatError::Unimplemented(Format::Pointer);
let error_string = format!("{}", error);
assert!(error_string.contains("not implemented"));
assert!(error_string.contains("Pointer"));
}
#[test]
fn test_format_error_is_error() {
let error = FormatError::Unimplemented(Format::Unknown);
let _boxed: Box<dyn Error> = Box::new(error);
}
#[test]
fn test_format_error_pointer_with_prefix() {
let result = Format::Pointer.format(0x42, true);
assert!(result.is_err());
match result {
Err(FormatError::Unimplemented(Format::Pointer)) => {
}
_ => panic!("Expected FormatError::Unimplemented(Format::Pointer)"),
}
}
#[test]
fn test_format_error_pointer_without_prefix() {
let result = Format::Pointer.format(0x42, false);
assert!(result.is_err());
match result {
Err(FormatError::Unimplemented(Format::Pointer)) => {
}
_ => panic!("Expected FormatError::Unimplemented(Format::Pointer)"),
}
}
#[test]
fn test_format_error_lower_exp() {
let result = Format::LowerExp.format(0xFF, true);
assert!(result.is_err());
assert!(matches!(
result,
Err(FormatError::Unimplemented(Format::LowerExp))
));
}
#[test]
fn test_format_error_upper_exp() {
let result = Format::UpperExp.format(0xFF, false);
assert!(result.is_err());
assert!(matches!(
result,
Err(FormatError::Unimplemented(Format::UpperExp))
));
}
#[test]
fn test_format_error_unknown() {
let result = Format::Unknown.format(0x00, true);
assert!(result.is_err());
assert!(matches!(
result,
Err(FormatError::Unimplemented(Format::Unknown))
));
}
#[test]
fn test_all_unimplemented_formats() {
let unimplemented = vec![
Format::Pointer,
Format::LowerExp,
Format::UpperExp,
Format::Unknown,
];
for format in unimplemented {
let result_with_prefix = format.format(0x42, true);
let result_without_prefix = format.format(0x42, false);
assert!(
result_with_prefix.is_err(),
"Format {:?} should return error with prefix",
format
);
assert!(
result_without_prefix.is_err(),
"Format {:?} should return error without prefix",
format
);
}
}
#[test]
fn test_all_implemented_formats() {
let implemented = vec![
Format::Octal,
Format::LowerHex,
Format::UpperHex,
Format::Binary,
];
for format in implemented {
let result_with_prefix = format.format(0x42, true);
let result_without_prefix = format.format(0x42, false);
assert!(
result_with_prefix.is_ok(),
"Format {:?} should return Ok with prefix",
format
);
assert!(
result_without_prefix.is_ok(),
"Format {:?} should return Ok without prefix",
format
);
}
}
#[test]
fn test_format_edge_cases() {
assert_eq!(Format::LowerHex.format(0, true).unwrap(), "0x00");
assert_eq!(Format::LowerHex.format(0, false).unwrap(), "00");
assert_eq!(Format::Octal.format(0, true).unwrap(), "0o0000");
assert_eq!(Format::Octal.format(0, false).unwrap(), "0000");
assert_eq!(Format::Binary.format(0, true).unwrap(), "0b00000000");
assert_eq!(Format::Binary.format(0, false).unwrap(), "00000000");
assert_eq!(Format::LowerHex.format(u8::MAX, true).unwrap(), "0xff");
assert_eq!(Format::LowerHex.format(u8::MAX, false).unwrap(), "ff");
assert_eq!(Format::UpperHex.format(u8::MAX, true).unwrap(), "0xFF");
assert_eq!(Format::UpperHex.format(u8::MAX, false).unwrap(), "FF");
}
}