use core::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ByteSliceErrorKind {
Empty,
Overflow,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ByteSliceError {
pub kind: ByteSliceErrorKind,
}
impl fmt::Display for ByteSliceError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let description = match self.kind {
ByteSliceErrorKind::Empty => "cannot parse integer from empty byte slice",
ByteSliceErrorKind::Overflow => "byte slice too long for target type",
};
description.fmt(f)
}
}
c0nst::c0nst! {
pub c0nst trait FromByteSlice: Sized {
fn from_be_slice(bytes: &[u8]) -> Result<Self, ByteSliceError>;
fn from_le_slice(bytes: &[u8]) -> Result<Self, ByteSliceError>;
}
}
macro_rules! from_byte_slice_impl {
($($t:ty)*) => {$(
c0nst::c0nst! {
c0nst impl FromByteSlice for $t {
fn from_be_slice(bytes: &[u8]) -> Result<Self, ByteSliceError> {
if bytes.len() == 0 {
return Err(ByteSliceError { kind: ByteSliceErrorKind::Empty });
}
let width = core::mem::size_of::<$t>();
if bytes.len() > width {
return Err(ByteSliceError { kind: ByteSliceErrorKind::Overflow });
}
let mut buf = [0u8; core::mem::size_of::<$t>()];
let off = width - bytes.len();
let mut i = 0;
while i < bytes.len() {
buf[off + i] = bytes[i];
i += 1;
}
Ok(<$t>::from_be_bytes(buf))
}
fn from_le_slice(bytes: &[u8]) -> Result<Self, ByteSliceError> {
if bytes.len() == 0 {
return Err(ByteSliceError { kind: ByteSliceErrorKind::Empty });
}
let width = core::mem::size_of::<$t>();
if bytes.len() > width {
return Err(ByteSliceError { kind: ByteSliceErrorKind::Overflow });
}
let mut buf = [0u8; core::mem::size_of::<$t>()];
let mut i = 0;
while i < bytes.len() {
buf[i] = bytes[i];
i += 1;
}
Ok(<$t>::from_le_bytes(buf))
}
}
}
)*};
}
from_byte_slice_impl!(usize u8 u16 u32 u64 u128);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn exact_width() {
assert_eq!(
<u32 as FromByteSlice>::from_be_slice(&[1, 2, 3, 4]),
Ok(0x0102_0304)
);
assert_eq!(
<u32 as FromByteSlice>::from_le_slice(&[1, 2, 3, 4]),
Ok(0x0403_0201)
);
assert_eq!(<u8 as FromByteSlice>::from_be_slice(&[0xff]), Ok(0xff));
assert_eq!(<u8 as FromByteSlice>::from_le_slice(&[0xff]), Ok(0xff));
}
#[test]
fn zero_extends_short_input() {
assert_eq!(
<u32 as FromByteSlice>::from_be_slice(&[0x12, 0x34]),
Ok(0x0000_1234)
);
assert_eq!(
<u32 as FromByteSlice>::from_le_slice(&[0x34, 0x12]),
Ok(0x0000_1234)
);
assert_eq!(<u128 as FromByteSlice>::from_be_slice(&[1]), Ok(1));
}
#[test]
fn round_trips_be_le() {
let v = 0x0102_0304u32;
assert_eq!(
<u32 as FromByteSlice>::from_be_slice(&v.to_be_bytes()),
Ok(v)
);
assert_eq!(
<u32 as FromByteSlice>::from_le_slice(&v.to_le_bytes()),
Ok(v)
);
}
#[test]
fn empty_is_error_not_zero() {
use ByteSliceErrorKind::*;
assert_eq!(
<u32 as FromByteSlice>::from_be_slice(&[]).unwrap_err().kind,
Empty
);
assert_eq!(
<u32 as FromByteSlice>::from_le_slice(&[]).unwrap_err().kind,
Empty
);
}
#[test]
fn too_wide_is_overflow() {
use ByteSliceErrorKind::*;
assert_eq!(
<u16 as FromByteSlice>::from_be_slice(&[1, 2, 3])
.unwrap_err()
.kind,
Overflow
);
assert_eq!(
<u16 as FromByteSlice>::from_be_slice(&[0, 1, 2])
.unwrap_err()
.kind,
Overflow
);
assert_eq!(
<u8 as FromByteSlice>::from_le_slice(&[1, 2])
.unwrap_err()
.kind,
Overflow
);
}
}