use core::{mem::MaybeUninit, slice, str};
use std::{cmp::Ordering, fmt, io, iter::FusedIterator};
use bytes::{BufMut, Bytes};
use super::fixed_arr::serialize;
pub use super::{Array, ArrayStr, DecodeError, Result};
#[derive(Debug, Clone)]
pub struct Decoder<'a> {
rem: Option<u8>,
src: &'a [[u8; 2]],
}
impl<'a> Decoder<'a> {
pub const fn new(src: &'a [u8]) -> Self {
let (rem, src) = src.as_rchunks();
Self { rem: rem.first().copied(), src }
}
pub const fn skip_0x(self) -> Self {
match (self.rem, self.src) {
(Some(b'0'), [[b'x' | b'X', x], rest @ ..]) => Self { rem: Some(*x), src: rest },
(None, [[b'0', b'x' | b'X'], rest @ ..]) => Self { rem: None, src: rest },
_ => self,
}
}
pub const fn skip_leading_zeros(mut self) -> Self {
if let Some(v) = self.rem {
if v == b'0' {
self.rem = None;
} else {
return self;
}
}
loop {
match self.src {
[[b'0', b'0'], rest @ ..] => {
self.src = rest;
continue;
},
[[b'0', x], rest @ ..] => {
self.rem = Some(*x);
self.src = rest;
},
_ => {},
}
break self;
}
}
pub fn into_vec(self) -> Result<Vec<u8>> {
let len = self.len();
let mut buf = Vec::<u8>::with_capacity(len);
let base = buf.spare_capacity_mut();
let mut di = 0;
if let Some(rem) = self.rem {
let n = parse_nibble(rem).ok_or(DecodeError::InvalidCharacter(rem))?;
unsafe { base.get_unchecked_mut(di) }.write(n);
di += 1;
}
let mut si = 0;
while si + 8 <= self.src.len() {
for _ in 0..8 {
let b = parse_byte(self.src[si])?;
unsafe { base.get_unchecked_mut(di) }.write(b);
di += 1;
si += 1;
}
}
for &[h, l] in &self.src[si..] {
let b = parse_byte([h, l])?;
unsafe { base.get_unchecked_mut(di) }.write(b);
di += 1;
}
debug_assert_eq!(di, len);
unsafe { buf.set_len(len) };
Ok(buf)
}
pub fn into_bytes(self) -> Result<Bytes> {
self.into_vec().map(Bytes::from)
}
pub fn into_slice(mut self, mut buf: &mut [u8]) -> Result<usize> {
let mut n = if let Some(rem) = self.rem {
let Some(d) = buf.split_off_first_mut() else {
return Ok(0);
};
*d = parse_nibble(rem).ok_or(DecodeError::InvalidCharacter(rem))?;
1
} else {
0
};
while let Some(d) = buf.split_off_first_mut()
&& let Some(&hl) = self.src.split_off_first()
{
*d = parse_byte(hl)?;
n += 1;
}
Ok(n)
}
pub fn into_array<const K: usize>(self) -> Result<[u8; K]> {
let mut buf = [0u8; K];
let n = self.into_slice(&mut buf)?;
if n != K {
return Err(DecodeError::InputTooShort);
}
Ok(buf)
}
#[inline]
pub fn into_buf<B: BufMut>(mut self, mut buf: B) -> Result<B> {
loop {
let mut n = 0;
let chunk = unsafe { buf.chunk_mut().as_uninit_slice_mut() };
for (b, dst) in self.by_ref().zip(&mut *chunk) {
dst.write(b?);
n += 1;
}
let exhausted = n < chunk.len();
unsafe { buf.advance_mut(n) };
if exhausted {
break Ok(buf);
}
}
}
pub fn extend_into<E: Extend<u8> + ?Sized>(self, buf: &mut E) -> Result<usize> {
buf.extend_reserve(self.len());
let mut n = 0;
for byte in self {
let byte = byte?;
buf.extend_one(byte);
n += 1;
}
Ok(n)
}
pub fn write_into<W: io::Write + ?Sized>(mut self, writer: &mut W) -> io::Result<usize> {
let mut buf = [MaybeUninit::<u8>::uninit(); 512];
let mut n = 0;
let mut done = false;
while !done {
let mut i = 0;
for dst in &mut buf {
if let Some(b) = self.next() {
dst.write(b.map_err(io::Error::other)?);
i += 1;
} else {
done = true;
break;
}
}
n += i;
if i != 0 {
unsafe { writer.write_all(slice::from_raw_parts(buf.as_ptr().cast(), i))? };
}
}
Ok(n)
}
}
impl Iterator for Decoder<'_> {
type Item = Result<u8>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if let Some(s0) = self.rem.take() {
return Some(parse_nibble(s0).ok_or(DecodeError::InvalidCharacter(s0)));
}
match parse_byte(*self.src.split_off_first()?) {
Ok(b) => Some(Ok(b)),
Err(e) => Some(Err(e)),
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let n = self.len();
(n, Some(n))
}
}
impl DoubleEndedIterator for Decoder<'_> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
if let Some(x) = self.src.split_off_last() {
return match parse_byte(*x) {
Ok(b) => Some(Ok(b)),
Err(e) => Some(Err(e)),
};
}
if let Some(s0) = self.rem.take() {
return Some(parse_nibble(s0).ok_or(DecodeError::InvalidCharacter(s0)));
}
None
}
}
impl ExactSizeIterator for Decoder<'_> {
#[inline]
fn len(&self) -> usize {
self.src.len() + usize::from(self.rem.is_some())
}
}
impl FusedIterator for Decoder<'_> {}
impl<const N: usize> TryFrom<Decoder<'_>> for [u8; N] {
type Error = DecodeError;
fn try_from(decoder: Decoder<'_>) -> Result<Self> {
decoder.into_array()
}
}
impl fmt::Display for Decoder<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for byte in self.clone() {
if let Ok(byte) = byte {
write!(f, "{byte:02x}")?;
} else {
write!(f, "??")?;
}
}
Ok(())
}
}
impl PartialEq<[u8]> for Decoder<'_> {
fn eq(&self, other: &[u8]) -> bool {
self.clone().eq(other.iter().map(|&b| Ok(b)))
}
}
impl PartialOrd<[u8]> for Decoder<'_> {
fn partial_cmp(&self, other: &[u8]) -> Option<Ordering> {
Some(self.clone().cmp(other.iter().map(|&b| Ok(b))))
}
}
pub const fn decode_mut(src: &[u8], dst: &mut [u8]) -> Result<usize> {
let mut i = 0;
let mut si = src;
if let [s0, sn @ ..] = si
&& sn.len() & 1 == 0
&& dst.len() > i
{
let Some(s0) = parse_nibble(*s0) else {
return Err(DecodeError::InvalidCharacter(*s0));
};
dst[i] = s0;
si = sn;
i += 1;
}
while let [c0, c1, sn @ ..] = si
&& dst.len() > i
{
let c0v = *c0;
let c1v = *c1;
dst[i] = match parse_byte([c0v, c1v]) {
Ok(b) => b,
Err(e) => return Err(e),
};
si = sn;
i += 1;
}
Ok(i)
}
#[inline]
pub fn decode<T: AsRef<[u8]> + ?Sized>(src: &T) -> Decoder<'_> {
Decoder::new(src.as_ref())
}
#[inline]
pub const fn skip_0x(src: &[u8]) -> &[u8] {
match src {
[b'0', b'x' | b'X', rest @ ..] => rest,
_ => src,
}
}
#[inline]
pub const fn skip_leading_zeros(mut src: &[u8]) -> &[u8] {
while let [b'0', rest @ ..] = src {
src = rest;
}
src
}
const DEC_TABLE: [u8; 0x100] = {
let mut table = [0x80; 0x100];
let mut i = 0;
while i <= 0xf {
let c = char::from_digit(i as u32, 0x10).unwrap();
table[c.to_ascii_lowercase() as usize] = i;
table[c.to_ascii_uppercase() as usize] = i;
i += 1;
}
table
};
#[inline]
pub const fn parse_nibble(b: u8) -> Option<u8> {
let v = DEC_TABLE[b as usize];
if v.cast_signed() >= 0 {
Some(v)
} else {
std::hint::cold_path();
None
}
}
#[inline]
pub const fn parse_byte([h, l]: [u8; 2]) -> Result<u8> {
let hv = DEC_TABLE[h as usize];
let lv = DEC_TABLE[l as usize];
if (hv | lv).cast_signed() >= 0 {
Ok((hv << 4) | lv)
} else {
std::hint::cold_path();
let inv = if hv.cast_signed() >= 0 { l } else { h };
Err(DecodeError::InvalidCharacter(inv))
}
}
const ALPHABET: [u8; 32] = *b"0123456789abcdef0123456789ABCDEF";
const LUT: [[u16; 256]; 2] = {
let mut t = [[0u16; 256]; 2];
{
let t = t[0].as_mut_slice();
let mut i = 0u16;
while i < 256 {
let b = (i & 0xff) as u8;
let h = LOWER.encode_nibble(b >> 4);
let l = LOWER.encode_nibble(b & 0x0f);
t[i as usize] = u16::from_ne_bytes([h, l]);
i += 1;
}
}
{
let t = t[1].as_mut_slice();
let mut i = 0u16;
while i < 256 {
let b = (i & 0xff) as u8;
let h = UPPER.encode_nibble(b >> 4);
let l = UPPER.encode_nibble(b & 0x0f);
t[i as usize] = u16::from_ne_bytes([h, l]);
i += 1;
}
}
t
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(u8)]
pub enum Encoding {
Lowercase = 0,
Uppercase = 1,
}
pub const STD: Encoding = Encoding::Lowercase;
pub const LOWER: Encoding = Encoding::Lowercase;
pub const UPPER: Encoding = Encoding::Uppercase;
impl Encoding {
#[inline]
pub const fn encode_nibble(self, nibble: u8) -> u8 {
let idx = (((self as usize) << 4) + (nibble as usize)) & 31;
ALPHABET[idx]
}
#[inline]
pub const fn encode_mut(self, src: &[u8], dst: &mut [u8]) -> usize {
let lut = self.lut();
let mut n = dst.len() >> 1;
if n > src.len() {
n = src.len();
}
let src = src.as_ptr();
let dst = dst.as_mut_ptr();
let mut i = 0;
while i < n {
unsafe {
dst.add(i << 1)
.cast::<u16>()
.write_unaligned(lut[src.add(i).read() as usize]);
}
i += 1;
}
n << 1
}
#[inline]
pub const fn encode_byte(self, byte: u8) -> [u8; 2] {
LUT[self as usize][byte as usize].to_ne_bytes()
}
#[inline]
pub const fn encode_n<const N: usize>(self, src: &[u8; N]) -> ArrayStr<N> {
let mut out = [[0u8; 2]; N];
self.encode_mut(src.as_slice(), out.as_flattened_mut());
ArrayStr::new(out, N * 2)
}
#[inline]
pub const fn lut(self) -> &'static [u16; 256] {
&LUT[self as usize]
}
}
#[derive(Debug, Clone)]
pub struct Encoder<'a> {
src: &'a [u8],
charset: Encoding,
low: Option<u8>,
high: Option<u8>,
}
impl<'a> From<&'a [u8]> for Encoder<'a> {
fn from(src: &'a [u8]) -> Self {
Self { src, charset: LOWER, low: None, high: None }
}
}
impl<'a> Encoder<'a> {
pub fn new(src: &'a [u8]) -> Self {
src.into()
}
pub const fn lower(mut self) -> Self {
self.charset = LOWER;
self
}
pub const fn upper(mut self) -> Self {
self.charset = UPPER;
self
}
pub const fn with_charset(mut self, charset: Encoding) -> Self {
self.charset = charset;
self
}
#[define_opaque(CharEncoder)]
pub fn into_chars(self) -> CharEncoder<'a> {
self.map(|x| x as char)
}
pub fn into_vec(self) -> Vec<u8> {
let lut = self.charset.lut();
let out_len = self.len();
let mut buf = Vec::<u8>::with_capacity(out_len);
if let Some(low) = self.low {
buf.push(self.charset.encode_nibble(low));
}
let pairs_end = buf.len() + 2 * self.src.len();
let base = buf.spare_capacity_mut();
for (i, &byte) in self.src.iter().enumerate() {
unsafe {
base
.as_mut_ptr()
.cast::<u16>()
.add(i)
.write_unaligned(lut[byte as usize]);
};
}
unsafe { buf.set_len(pairs_end) };
if let Some(high) = self.high {
buf.push(self.charset.encode_nibble(high));
}
debug_assert_eq!(buf.len(), out_len);
buf
}
pub fn into_bytes(self) -> Bytes {
Bytes::from(self.into_vec())
}
pub fn into_string(self) -> String {
super::ascii_to_str_owned(self.into_vec())
}
pub fn extend_into<E: Extend<u8> + ?Sized>(self, buf: &mut E) {
buf.extend(self);
}
pub fn into_buf<B: BufMut>(mut self, mut buf: B) -> B {
loop {
let mut n = 0;
let chunk = unsafe { buf.chunk_mut().as_uninit_slice_mut() };
for (b, d) in self.by_ref().zip(&mut *chunk) {
d.write(b);
n += 1;
}
let exhausted = n < chunk.len();
unsafe { buf.advance_mut(n) };
if exhausted {
break buf;
}
}
}
pub fn write_into<W: io::Write + ?Sized>(self, writer: &mut W) -> io::Result<usize> {
let Self { src: mut it, charset, low, mut high } = self;
let mut n = 0;
let mut buf = MaybeUninit::<[[u8; 2]; 64]>::uninit().transpose();
if let Some(low) = low {
buf[0].write([0, charset.encode_nibble(low)]);
n += 1;
for d in &mut buf[1..] {
let Some(&b) = it.split_off_first() else {
break;
};
d.write(charset.encode_byte(b));
n += 2;
}
let data = unsafe { slice::from_raw_parts(buf.as_ptr().cast::<u8>().add(1), n) };
writer.write_all(data)?;
}
while !it.is_empty() {
let mut local = 0;
for d in &mut buf {
let Some(&b) = it.split_off_first() else {
if let Some(hi) = high.take() {
d.write([charset.encode_nibble(hi), 0]);
local += 1;
}
break;
};
d.write(charset.encode_byte(b));
local += 2;
}
let data = unsafe { slice::from_raw_parts(buf.as_ptr().cast::<u8>(), local) };
writer.write_all(data)?;
n += local;
}
if let Some(high) = high {
writer.write_all(&[charset.encode_nibble(high)])?;
n += 1;
}
Ok(n)
}
pub fn format_into<W: fmt::Write + ?Sized>(self, writer: &mut W) -> fmt::Result {
for bytes in self {
writer.write_str(super::ascii_to_str(&[bytes]))?;
}
Ok(())
}
}
impl From<Encoder<'_>> for String {
fn from(encoder: Encoder<'_>) -> Self {
encoder.into_string()
}
}
impl From<Encoder<'_>> for Bytes {
fn from(encoder: Encoder<'_>) -> Self {
encoder.into_bytes()
}
}
impl From<Encoder<'_>> for Vec<u8> {
fn from(encoder: Encoder<'_>) -> Self {
encoder.into_vec()
}
}
impl Iterator for Encoder<'_> {
type Item = u8;
fn next(&mut self) -> Option<Self::Item> {
if let Some(low) = self.low.take() {
return Some(self.charset.encode_nibble(low));
}
if let Some(byte) = self.src.split_off_first() {
let byte = *byte;
let high = byte >> 4;
let low = byte & 0x0f;
self.low = Some(low);
return Some(self.charset.encode_nibble(high));
}
if let Some(high) = self.high.take() {
return Some(self.charset.encode_nibble(high));
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
let n = self.len();
(n, Some(n))
}
}
impl DoubleEndedIterator for Encoder<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
if let Some(high) = self.high.take() {
return Some(self.charset.encode_nibble(high));
}
if let Some(byte) = self.src.split_off_last() {
let byte = *byte;
let high = byte >> 4;
let low = byte & 0x0f;
self.high = Some(high);
return Some(self.charset.encode_nibble(low));
}
if let Some(low) = self.low.take() {
return Some(self.charset.encode_nibble(low));
}
None
}
}
impl ExactSizeIterator for Encoder<'_> {
fn len(&self) -> usize {
let rem = self.low.is_some() as usize + self.high.is_some() as usize;
(self.src.len() << 1) + rem
}
}
impl FusedIterator for Encoder<'_> {}
impl fmt::Display for Encoder<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
super::format_with_precision(self.clone(), f)
}
}
impl fmt::LowerHex for Encoder<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.clone().lower(), f)
}
}
impl fmt::UpperHex for Encoder<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.clone().upper(), f)
}
}
impl<'b> PartialEq<Encoder<'b>> for Encoder<'_> {
fn eq(&self, other: &Encoder<'b>) -> bool {
self.clone().eq(other.clone())
}
}
impl Ord for Encoder<'_> {
fn cmp(&self, other: &Self) -> Ordering {
self.clone().cmp(other.clone())
}
}
impl<'b> PartialOrd<Encoder<'b>> for Encoder<'_> {
fn partial_cmp(&self, other: &Encoder<'b>) -> Option<Ordering> {
self.clone().partial_cmp(other.clone())
}
}
impl Eq for Encoder<'_> {}
impl PartialEq<[u8]> for Encoder<'_> {
fn eq(&self, other: &[u8]) -> bool {
self.clone().eq(other.iter().copied())
}
}
impl PartialEq<str> for Encoder<'_> {
fn eq(&self, other: &str) -> bool {
self.clone().eq(other.as_bytes().iter().copied())
}
}
impl PartialOrd<[u8]> for Encoder<'_> {
fn partial_cmp(&self, other: &[u8]) -> Option<Ordering> {
Some(self.clone().cmp(other.iter().copied()))
}
}
impl PartialOrd<str> for Encoder<'_> {
fn partial_cmp(&self, other: &str) -> Option<Ordering> {
Some(self.clone().cmp(other.as_bytes().iter().copied()))
}
}
impl serde::Serialize for Encoder<'_> {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let len = encode_len(self.src.len());
serialize(serializer, len, |buffer| self.charset.encode_mut(self.src, buffer))
}
}
pub type CharEncoder<'a> =
impl ExactSizeIterator<Item = char> + DoubleEndedIterator + FusedIterator + 'a;
pub fn encode<I: AsRef<[u8]> + ?Sized>(src: &I) -> Encoder<'_> {
Encoder::new(src.as_ref())
}
#[inline]
pub const fn encode_mut(src: &[u8], dst: &mut [u8]) -> usize {
LOWER.encode_mut(src, dst)
}
pub const fn decode_n<const N: usize>(src: &[u8; N]) -> Option<Array<N>> {
let mut out = [0; _];
let Ok(written) = decode_mut(src.as_slice(), out.as_mut_slice()) else {
return None;
};
Some(Array::new(out, written))
}
#[inline]
pub const fn encode_n<const N: usize>(src: &[u8; N]) -> ArrayStr<N> {
LOWER.encode_n(src)
}
#[inline]
pub const fn encode_len(src_len: usize) -> usize {
src_len << 1
}
#[inline]
pub const fn decode_len(src_len: usize) -> usize {
src_len.div_ceil(2)
}