use core::{
fmt,
ops::{Index, RangeFrom, RangeTo},
str,
};
#[cfg(feature = "serde")]
use {
core::{marker::PhantomData, str::FromStr},
serde::de,
};
pub enum ByteSliceFormatter<'a> {
Array(&'a [u8; 32]),
Dynamic(&'a [u8]),
}
impl ByteSliceFormatter<'_> {
fn len(&self) -> usize {
match self {
ByteSliceFormatter::Array(arr) => arr.len(),
ByteSliceFormatter::Dynamic(slice) => slice.len(),
}
}
}
impl Index<RangeTo<usize>> for ByteSliceFormatter<'_> {
type Output = <[u8] as Index<RangeTo<usize>>>::Output;
fn index(&self, index: RangeTo<usize>) -> &Self::Output {
match self {
ByteSliceFormatter::Array(arr) => &arr[index],
ByteSliceFormatter::Dynamic(slice) => &slice[index],
}
}
}
impl Index<RangeFrom<usize>> for ByteSliceFormatter<'_> {
type Output = <[u8] as Index<RangeFrom<usize>>>::Output;
fn index(&self, index: RangeFrom<usize>) -> &Self::Output {
match self {
ByteSliceFormatter::Array(arr) => &arr[index],
ByteSliceFormatter::Dynamic(slice) => &slice[index],
}
}
}
impl fmt::Display for ByteSliceFormatter<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
const STACK_LEN: usize = 32;
let len = self.len();
let median = len.div_ceil(2);
let mut e1 = median;
let mut s2 = median;
if let Some(precision) = f.precision()
&& precision < median
{
e1 = precision;
s2 = len - precision;
}
let out1_len = e1 * 2;
let out2_len = (len - s2) * 2;
let mut out1_vec;
let mut out2_vec;
let (out1, out2) = match self {
ByteSliceFormatter::Array(_arr) => (
&mut [0u8; STACK_LEN] as &mut [u8],
&mut [0u8; STACK_LEN] as &mut [u8],
),
ByteSliceFormatter::Dynamic(slice) if slice.len() <= STACK_LEN => (
&mut [0u8; STACK_LEN] as &mut [u8],
&mut [0u8; STACK_LEN] as &mut [u8],
),
ByteSliceFormatter::Dynamic(_slice) => {
out1_vec = alloc::vec![0u8; out1_len];
out2_vec = alloc::vec![0u8; out2_len];
(&mut out1_vec[..], &mut out2_vec[..])
}
};
let _ = hex::encode_to_slice(&self[..e1], &mut out1[..out1_len]);
let _ = hex::encode_to_slice(&self[s2..], &mut out2[..out2_len]);
let p1 = unsafe { str::from_utf8_unchecked(&out1[..out1_len]) };
let p2 = unsafe { str::from_utf8_unchecked(&out2[..out2_len]) };
let sep = if e1.ne(&s2) { ".." } else { Default::default() };
write!(f, "0x{p1}{sep}{p2}")
}
}
#[cfg(feature = "serde")]
pub(crate) struct HexStrVisitor<T: FromStr>(PhantomData<T>);
#[cfg(feature = "serde")]
impl<T: FromStr> HexStrVisitor<T> {
pub fn new() -> Self {
Self(PhantomData)
}
}
#[cfg(feature = "serde")]
impl<T: FromStr> de::Visitor<'_> for HexStrVisitor<T> {
type Value = T;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a string in hex format starting with 0x")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
value
.parse()
.map_err(|_| de::Error::invalid_value(de::Unexpected::Str(value), &self))
}
}