121 lines
3.7 KiB
Rust
121 lines
3.7 KiB
Rust
macro_rules! bounded_array {
|
|
{$(
|
|
$(#[$struct_docs:meta])*
|
|
$vis:vis struct $struct_name:ident($max_len:ident)
|
|
),*} => {
|
|
$(
|
|
$(#[$struct_docs])*
|
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
|
$vis struct $struct_name {
|
|
buf: [u8; Self::MAX_LEN],
|
|
len: u8,
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
impl $struct_name {
|
|
/// Maximum value allowed.
|
|
$vis const MAX_LEN: usize = $max_len;
|
|
|
|
/// Creates a new instance, taking ownership of the buffer.
|
|
#[inline]
|
|
$vis fn new(buf: [u8; Self::MAX_LEN], len: usize) -> Self {
|
|
Self { buf, len: len as _ }
|
|
}
|
|
|
|
/// Creates a new instance with an empty buffer of the given size.
|
|
#[inline]
|
|
$vis fn with_len(len: usize) -> Self {
|
|
Self::new([0u8; Self::MAX_LEN], len)
|
|
}
|
|
|
|
/// Creates a new instance, copying the buffer.
|
|
#[inline]
|
|
$vis fn from(input: &[u8]) -> Self {
|
|
assert!(input.len() <= Self::MAX_LEN);
|
|
let mut buf = [0u8; Self::MAX_LEN];
|
|
let len = input.len();
|
|
buf[..len].copy_from_slice(input);
|
|
|
|
Self::new(buf, len)
|
|
}
|
|
|
|
/// Creates a new instance with random contents.
|
|
#[inline]
|
|
$vis fn random() -> Self {
|
|
let mut buf = [0u8; Self::MAX_LEN];
|
|
rand::RngCore::fill_bytes(&mut rand::rng(), &mut buf);
|
|
Self::new(buf, Self::MAX_LEN)
|
|
}
|
|
|
|
/// Creates a new instance from the parsed hex string.
|
|
#[inline]
|
|
$vis fn parse_hex_string(
|
|
input: &str,
|
|
) -> crate::error::Result<Self> {
|
|
if input.len() % 2 != 0 {
|
|
return Err(crate::error::Error::invalid_input(
|
|
"hex string with odd length".to_string(),
|
|
));
|
|
}
|
|
|
|
let out_len = input.len() / 2;
|
|
if out_len > Self::MAX_LEN {
|
|
return Err(crate::error::Error::invalid_input(
|
|
"hex string value exceeds buffer size".to_string(),
|
|
));
|
|
}
|
|
|
|
let mut out = [0u8; Self::MAX_LEN];
|
|
|
|
let mut out_ix = 0;
|
|
let mut in_ix = 0;
|
|
while in_ix < input.len() {
|
|
let next_two_chars = &input[in_ix..in_ix + 2];
|
|
out[out_ix] = u8::from_str_radix(next_two_chars, 16).unwrap();
|
|
|
|
in_ix += 2;
|
|
out_ix += 1;
|
|
}
|
|
|
|
Ok($struct_name {
|
|
buf: out,
|
|
len: out_len as _,
|
|
})
|
|
}
|
|
|
|
/// Returns the length of the buffer.
|
|
#[inline]
|
|
$vis fn len(&self) -> usize {
|
|
self.len as _
|
|
}
|
|
|
|
/// Returns a slice of the buffer for its length.
|
|
#[inline]
|
|
$vis fn slice(&self) -> &[u8] {
|
|
&self.buf[..self.len as _]
|
|
}
|
|
|
|
/// Returns a mutable slice of the buffer for its length.
|
|
#[inline]
|
|
$vis fn slice_mut(&mut self) -> &mut [u8] {
|
|
&mut self.buf[..self.len as _]
|
|
}
|
|
|
|
/// Returns a raw pointer to the buffer.
|
|
#[inline]
|
|
$vis fn as_ptr(&self) -> *const u8 {
|
|
self.buf.as_ptr()
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Debug for $struct_name {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
write!(f, "{:02x?}", self.slice())
|
|
}
|
|
}
|
|
)*
|
|
}
|
|
}
|
|
|
|
pub(crate) use bounded_array;
|