use crate::ArrayOfHex;
use crate::Error;
#[cfg(feature = "serde")]
use serde::{
ser::{Serialize, Serializer},
Deserialize,
};
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct ArrayOfBase<const N: usize, const B: u8> {
value: [u8; N],
}
impl<const N: usize, const B: u8> ArrayOfBase<N, B> {
pub fn try_new(v: [u8; N]) -> Result<Self, Error> {
if v.iter().copied().all(Self::valid_number) {
Ok(Self { value: v })
} else {
Err(Error::InvalidValue)
}
}
pub fn try_from_vec_exact(v: &[u8]) -> Result<Self, Error> {
use std::cmp::Ordering::{Equal, Greater, Less};
match v.len().cmp(&N) {
Greater => Err(Error::Oversized),
Less if v.is_empty() => Err(Error::Empty),
Less => Err(Error::Undersized),
Equal => Self::try_new(v.try_into().expect(
"1666898415 - Unreachable: Correct length already verified",
)),
}
}
pub fn try_from_vec_pad(v: &[u8]) -> Result<Self, Error> {
use std::cmp::Ordering::{Greater, Less};
match v.len().cmp(&N) {
Greater => Err(Error::Oversized),
Less if v.is_empty() => Err(Error::Empty),
_ => Self::try_new(Self::pad_array(v)),
}
}
#[must_use]
pub fn unwrap(self) -> [u8; N] {
self.value
}
#[must_use]
pub fn borrow_u8_array(&self) -> &[u8; N] {
&self.value
}
fn valid_number(u8: u8) -> bool {
u8 < B
}
#[must_use]
pub fn pad_array(v: &[u8]) -> [u8; N] {
assert!(v.len() <= N);
let mut vec = v.to_vec();
while vec.len() < N {
vec.insert(0, 0);
}
vec.try_into().expect("1666979421 - Unreachable")
}
#[must_use]
pub fn trim<const L: usize>(&self) -> ArrayOfBase<L, B> {
assert!(L <= N);
ArrayOfBase {
value: array_from_iter_unchecked(self.value.into_iter().take(L)),
}
}
}
impl<const N: usize, const B: u8> Default for ArrayOfBase<N, B> {
fn default() -> Self {
Self { value: [0u8; N] }
}
}
impl<const N: usize> std::fmt::Display for ArrayOfBase<N, 16> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for v in self.borrow_u8_array().iter() {
match v {
10 => write!(f, "a")?,
11 => write!(f, "b")?,
12 => write!(f, "c")?,
13 => write!(f, "d")?,
14 => write!(f, "e")?,
15 => write!(f, "f")?,
v => write!(f, "{v}")?,
}
}
Ok(())
}
}
#[cfg(feature = "serde")]
impl<const N: usize> Serialize for ArrayOfBase<N, 16> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
impl<const N: usize> std::str::FromStr for ArrayOfBase<N, 16> {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.len() != N {
return Err(format!(
"1669744337 - String does not match expected length of {N}"
));
}
let mut array = [0; N];
for (i, v) in s.chars().enumerate() {
array[i] = match v {
'0' => 0,
'1' => 1,
'2' => 2,
'3' => 3,
'4' => 4,
'5' => 5,
'6' => 6,
'7' => 7,
'8' => 8,
'9' => 9,
'a' | 'A' => 10,
'b' | 'B' => 11,
'c' | 'C' => 12,
'd' | 'D' => 13,
'e' | 'E' => 14,
'f' | 'F' => 15,
v => {
return Err(format!(
"1669744576 - Unrecognized char `{v}` at position {i}"
));
}
};
}
ArrayOfHex::try_new(array).map_err(|_| {
unreachable!("1669744870 - Input values already validated")
})
}
}
#[cfg(feature = "serde")]
impl<'de, const N: usize> Deserialize<'de> for ArrayOfBase<N, 16> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
std::str::FromStr::from_str(&s).map_err(serde::de::Error::custom)
}
}
fn array_from_iter_unchecked<const N: usize, I: Iterator<Item = u8>>(
mut i: I,
) -> [u8; N] {
std::array::from_fn(|_| i.next().unwrap_or_default())
}
#[must_use]
fn u8_to_u4_as_u8(v: u8) -> [u8; 2] {
[(v & 0xf0) >> 4, v & 0x0f]
}
impl<const N: usize> ArrayOfBase<N, 16> {
pub fn from_u8_array<const I: usize>(array: [u8; I]) -> ArrayOfHex<N> {
assert!(N == I * 2);
ArrayOfBase {
value: array_from_iter_unchecked(
array.into_iter().flat_map(u8_to_u4_as_u8),
),
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test1669773971_u8_to_u4_as_u8() {
let x = 0xab;
let actual = u8_to_u4_as_u8(x);
assert_eq!(actual, [0xa, 0xb]);
}
}