You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

91 lines
2.2 KiB

//! Encoding data
use std::fmt::{
self,
Write,
};
pub trait Encoder
{
fn encode_byte<W: Write + ?Sized>(&self, byte: u8, f: &mut W) -> fmt::Result;
#[inline]
fn encode_slice<W: Write + ?Sized>(&self, slice: &[u8], f: &mut W) -> fmt::Result
{
slice.iter().try_for_each(|&byte| self.encode_byte(byte, f))
}
}
pub trait EncodeExt
{
fn encode_with<E: Encoder + Default, T: Write + Default>(&self) -> T;
}
impl<S: ?Sized> EncodeExt for S
where S: AsRef<[u8]>
{
//TODO: A version for `bytes::Buf`
fn encode_with<E: Encoder + Default, T: Write + Default>(&self) -> T
{
let mut w = T::default();
let e = E::default();
e.encode_slice(self.as_ref(), &mut w).expect("Failed to encode");
w
}
}
#[derive(Debug, Default)]
pub struct HexEncoder;
const fn gen_hexmap() -> [[u8; 2]; 256]
{
const MAP: &[u8; 16] = b"0123456789abcdef";
let mut output = [[0u8; 2]; 256];
let mut i=0u8;
loop {
output[i as usize] = [
// top
MAP[(i >> 4) as usize],
// bottom
MAP[(i & 0xf) as usize]
];
if i == 255 {
break;
} else {
i += 1;
}
}
output
}
impl HexEncoder
{
pub const HEXMAP: [[u8; 2]; 256] = gen_hexmap();
}
impl Encoder for HexEncoder
{
#[inline(always)]
fn encode_byte<W: Write + ?Sized>(&self, byte: u8, f: &mut W) -> fmt::Result {
f.write_str(unsafe { std::str::from_utf8_unchecked(&Self::HEXMAP[byte as usize][..]) })
}
#[inline]
fn encode_slice<W: Write + ?Sized>(&self, slice: &[u8], f: &mut W) -> fmt::Result {
use std::mem;
type ChunkTo = u128; //XXX: TODO: Benchmark if `usize` works better than `u128`.
slice.chunks(mem::size_of::<ChunkTo>())//array_chunks::<mem::size_of::<usize>()>()
.try_for_each(|chunk| {
// Work on multiples of the pointer size, if possible.
if chunk.len() == mem::size_of::<ChunkTo>() {
// SAFETY: The length is equal to the size of `usize`.
let chunk: &[u8; mem::size_of::<ChunkTo>()] = unsafe {
&*chunk.as_ptr().cast()//::<[u8; mem::size_of::<usize>()]>()
};
write!(f, "{:x}", ChunkTo::from_ne_bytes(*chunk)) //TODO: Test this; we might need BE or LE, idk. I think we'll need BE.
} else {
chunk.iter().try_for_each(|&byte| self.encode_byte(byte, f))
}
})
}
}