use alloc::{string::String, vec::Vec};
use snafu::prelude::*;
use crate::hex::{from_hex, to_hex, Hex, HexError};
#[derive(Debug, Snafu, PartialEq, Eq)]
pub enum ByteArrayError {
#[snafu(display("Could not create a ByteArray when converting from a different format: `{reason}'"))]
ConversionError {
reason: String,
},
#[snafu(display("The input data was the incorrect length to perform the desired conversion"))]
IncorrectLength {},
}
#[allow(clippy::ptr_arg)]
pub trait ByteArray: Sized {
fn to_vec(&self) -> Vec<u8> {
self.as_bytes().to_vec()
}
fn from_vec(v: &Vec<u8>) -> Result<Self, ByteArrayError> {
Self::from_bytes(v.as_slice())
}
fn from_bytes(bytes: &[u8]) -> Result<Self, ByteArrayError>;
fn as_bytes(&self) -> &[u8];
}
impl ByteArray for Vec<u8> {
fn to_vec(&self) -> Vec<u8> {
self.clone()
}
fn from_vec(v: &Vec<u8>) -> Result<Self, ByteArrayError> {
Ok(v.clone())
}
fn from_bytes(bytes: &[u8]) -> Result<Self, ByteArrayError> {
Ok(bytes.to_vec())
}
fn as_bytes(&self) -> &[u8] {
Vec::as_slice(self)
}
}
impl<const I: usize> ByteArray for [u8; I] {
fn from_bytes(bytes: &[u8]) -> Result<Self, ByteArrayError> {
if bytes.len() != I {
return Err(ByteArrayError::IncorrectLength {});
}
let mut a = [0u8; I];
a.copy_from_slice(bytes);
Ok(a)
}
fn as_bytes(&self) -> &[u8] {
self
}
}
impl<T: ByteArray> Hex for T {
fn from_hex(hex: &str) -> Result<Self, HexError> {
let v = from_hex(hex)?;
Self::from_bytes(&v).map_err(|_| HexError::HexConversionError {})
}
fn to_hex(&self) -> String {
to_hex(self.as_bytes())
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn from_to_vec() {
let v = vec![0u8, 1, 128, 255];
let ba = <Vec<u8>>::from_vec(&v).unwrap();
assert_eq!(ba.to_vec(), v);
}
#[test]
fn from_to_array() {
let v = vec![
0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
29, 30, 31,
];
let ba = <[u8; 32]>::from_vec(&v).unwrap();
assert_eq!(ba.to_vec(), v);
}
#[test]
fn from_to_different_sizes() {
let v4 = vec![0u8, 1, 2, 3];
let a4 = <[u8; 4]>::from_vec(&v4).unwrap();
assert_eq!(a4.to_vec(), v4);
let v10 = vec![0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let a10 = <[u8; 10]>::from_vec(&v10).unwrap();
assert_eq!(a10.to_vec(), v10);
fn check(_: impl ByteArray) {}
check([0; 32]);
check([0; 64]);
check([0; 1000]);
}
#[test]
fn from_to_hex() {
let v = <Vec<u8>>::from_hex("deadbeef").unwrap();
assert_eq!(v.to_hex(), "deadbeef");
}
#[test]
fn test_error_handling() {
let err = <[u8; 32]>::from_bytes(&[1, 2, 3, 4]).unwrap_err();
assert_eq!(err, ByteArrayError::IncorrectLength {});
let err = <[u8; 32]>::from_hex("abcd").unwrap_err();
assert!(matches!(err, HexError::HexConversionError {}));
}
}