diff --git a/src/error.rs b/src/error.rs index ff9e8c8..b3c1a57 100644 --- a/src/error.rs +++ b/src/error.rs @@ -3,10 +3,22 @@ use thiserror::Error; /// Errors that can occur in the chorus crate #[derive(Error, Debug)] pub enum Error { + // Bad hex input + #[error("Bad hex input")] + BadHexInput, + + // Output buffer too small + #[error("Output buffer too small")] + BufferTooSmall, + // Config #[error("Config: {0}")] Config(#[from] ron::error::SpannedError), + // End of Input + #[error("End of input")] + EndOfInput, + // I/O Error #[error("I/O: {0}")] Io(#[from] std::io::Error), diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 0000000..7f2873b --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,57 @@ +static HEX_CHARS: &[u8; 16] = b"0123456789abcdef"; +#[allow(clippy::zero_prefixed_literal)] +static HEX_INVERSE: [u8; 128] = { + const __: u8 = 255; + [ + // 1 2 3 4 5 6 7 8 9 A B C D E F + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 0 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 1 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 2 + 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, __, __, __, __, __, __, // 3 + __, 10, 11, 12, 13, 14, 15, __, __, __, __, __, __, __, __, __, // 4 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 5 + __, 10, 11, 12, 13, 14, 15, __, __, __, __, __, __, __, __, __, // 6 + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 7 + ] +}; + +macro_rules! write_hex { + ($input:expr, $output:expr, $bytelen:expr) => {{ + assert_eq!($input.len(), $bytelen); + if $output.len() != $bytelen * 2 { + Err(Error::BufferTooSmall) + } else { + for (i, byte) in $input.iter().enumerate() { + $output[i * 2] = crate::HEX_CHARS[((byte & 0xF0) >> 4) as usize]; + $output[i * 2 + 1] = crate::HEX_CHARS[(byte & 0x0F) as usize]; + } + Ok(()) + } + }}; +} + +macro_rules! read_hex { + ($input:expr, $output:expr, $bytelen:expr) => {{ + assert_eq!($output.len(), $bytelen); + if $input.len() != $bytelen * 2 { + Err(Error::EndOfInput) + } else { + let mut i = 0; + loop { + let high = crate::HEX_INVERSE[$input[i * 2] as usize]; + if high == 255 { + break Err(Error::BadHexInput); + } + let low = crate::HEX_INVERSE[$input[i * 2 + 1] as usize]; + if low == 255 { + break Err(Error::BadHexInput); + } + $output[i] = high * 16 + low; + i += 1; + if i == $bytelen { + break Ok(()); + } + } + } + }}; +} diff --git a/src/main.rs b/src/main.rs index 2c2ca0c..1e69016 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +include!("macros.rs"); pub mod config; pub mod error;