use crate::error::InvalidWidth;
use embedded_io::{Error, Write};
pub fn write_u8(w: &mut impl Write, v: u8) -> Result<usize, embedded_io::ErrorKind> {
w.write_all(&[v]).map_err(|e| e.kind())?;
Ok(1)
}
pub fn write_u16_be(w: &mut impl Write, v: u16) -> Result<usize, embedded_io::ErrorKind> {
w.write_all(&v.to_be_bytes()).map_err(|e| e.kind())?;
Ok(2)
}
pub fn write_u32_be(w: &mut impl Write, v: u32) -> Result<usize, embedded_io::ErrorKind> {
w.write_all(&v.to_be_bytes()).map_err(|e| e.kind())?;
Ok(4)
}
pub fn write_u64_be(w: &mut impl Write, v: u64) -> Result<usize, embedded_io::ErrorKind> {
w.write_all(&v.to_be_bytes()).map_err(|e| e.kind())?;
Ok(8)
}
pub fn write_u128_be(w: &mut impl Write, v: u128) -> Result<usize, embedded_io::ErrorKind> {
w.write_all(&v.to_be_bytes()).map_err(|e| e.kind())?;
Ok(16)
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum WriteUintError {
Io(embedded_io::ErrorKind),
InvalidWidth(InvalidWidth),
}
impl From<embedded_io::ErrorKind> for WriteUintError {
fn from(e: embedded_io::ErrorKind) -> Self {
WriteUintError::Io(e)
}
}
impl From<InvalidWidth> for WriteUintError {
fn from(e: InvalidWidth) -> Self {
WriteUintError::InvalidWidth(e)
}
}
impl core::fmt::Display for WriteUintError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
WriteUintError::Io(kind) => write!(f, "write failed: {kind:?}"),
WriteUintError::InvalidWidth(e) => e.fmt(f),
}
}
}
impl core::error::Error for WriteUintError {}
#[must_use]
#[allow(clippy::cast_possible_truncation)] pub const fn minimal_be_len(value: u128) -> usize {
(u128::BITS - value.leading_zeros()).div_ceil(8) as usize
}
pub fn write_be_uint(w: &mut impl Write, value: u128, n: usize) -> Result<usize, WriteUintError> {
if n > 16 {
return Err(InvalidWidth { max: 16, got: n }.into());
}
let bytes = value.to_be_bytes(); w.write_all(&bytes[16 - n..])
.map_err(|e| WriteUintError::from(e.kind()))?;
Ok(n)
}
pub fn write_all(w: &mut impl Write, bytes: &[u8]) -> Result<usize, embedded_io::ErrorKind> {
w.write_all(bytes).map_err(|e| e.kind())?;
Ok(bytes.len())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error::InvalidWidth;
#[test]
fn write_u16_be_writes_big_endian_and_counts() {
let mut buf = [0u8; 4];
let mut w: &mut [u8] = &mut buf;
let n = write_u16_be(&mut w, 0x1234).unwrap();
assert_eq!(n, 2);
assert_eq!(&buf[..2], &[0x12, 0x34]);
}
#[test]
fn write_be_uint_writes_only_low_n_bytes() {
let mut buf = [0u8; 3];
let mut w: &mut [u8] = &mut buf;
let n = write_be_uint(&mut w, 0xAABB_CCDD_u128, 3).unwrap();
assert_eq!(n, 3);
assert_eq!(buf, [0xBB, 0xCC, 0xDD]);
}
#[test]
fn write_all_writes_verbatim() {
let mut buf = [0u8; 4];
let mut w: &mut [u8] = &mut buf;
let n = write_all(&mut w, &[9, 8, 7]).unwrap();
assert_eq!(n, 3);
assert_eq!(&buf[..3], &[9, 8, 7]);
}
#[test]
fn write_into_too_small_slice_errors_not_panics() {
let mut buf = [0u8; 1];
let mut w: &mut [u8] = &mut buf;
assert!(write_u16_be(&mut w, 0x1234).is_err());
}
#[test]
fn write_be_uint_hostile_width_is_data_error_not_panic() {
let mut buf = [0u8; 300];
let mut w: &mut [u8] = &mut buf;
assert_eq!(
write_be_uint(&mut w, 0xABCD, 255),
Err(WriteUintError::InvalidWidth(InvalidWidth {
max: 16,
got: 255
}))
);
}
#[test]
fn write_be_uint_zero_width_writes_nothing() {
let mut buf = [0xFFu8; 2];
let mut w: &mut [u8] = &mut buf;
assert_eq!(write_be_uint(&mut w, 0xABCD, 0).unwrap(), 0);
assert_eq!(buf, [0xFF, 0xFF]);
}
#[test]
fn write_u128_be_writes_big_endian_and_counts() {
let v = 0x0102_0304_0506_0708_090A_0B0C_0D0E_0F10_u128;
let mut buf = [0u8; 16];
let mut w: &mut [u8] = &mut buf;
assert_eq!(write_u128_be(&mut w, v).unwrap(), 16);
assert_eq!(buf, v.to_be_bytes());
}
#[test]
fn minimal_be_len_boundaries() {
assert_eq!(minimal_be_len(0), 0);
assert_eq!(minimal_be_len(1), 1);
assert_eq!(minimal_be_len(0xFF), 1);
assert_eq!(minimal_be_len(0x100), 2);
assert_eq!(minimal_be_len(0xFFFF), 2);
assert_eq!(minimal_be_len(0x1_0000), 3);
assert_eq!(minimal_be_len(u128::from(u64::MAX)), 8);
assert_eq!(minimal_be_len(u128::MAX), 16);
}
#[test]
fn write_be_uint_truncates_value_wider_than_n() {
let mut buf = [0xEEu8; 4];
let mut w: &mut [u8] = &mut buf;
assert_eq!(write_be_uint(&mut w, 0x1_0000, 2).unwrap(), 2);
assert_eq!(&buf[..2], &[0x00, 0x00]); }
#[test]
fn minimal_be_len_pairs_with_write_be_uint() {
let v = 0x00AB_CDEF_u128;
let n = minimal_be_len(v);
assert_eq!(n, 3);
let mut buf = [0u8; 16];
let mut w: &mut [u8] = &mut buf;
assert_eq!(write_be_uint(&mut w, v, minimal_be_len(v)).unwrap(), n);
assert_eq!(&buf[..n], &[0xAB, 0xCD, 0xEF]);
}
}