//! Encoding data use std::fmt::{ self, Write, }; use smallmap::{ Primitive, Map, }; pub trait Encoder { fn encode_byte(&self, byte: u8, f: &mut W) -> fmt::Result; #[inline] fn encode_slice(&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(&self) -> T; } impl EncodeExt for S where S: AsRef<[u8]> { //TODO: A version for `bytes::Buf` fn encode_with(&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(&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(&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::())//array_chunks::()>() .try_for_each(|chunk| { // Work on multiples of the pointer size, if possible. if chunk.len() == mem::size_of::() { // SAFETY: The length is equal to the size of `usize`. let chunk: &[u8; mem::size_of::()] = unsafe { &*chunk.as_ptr().cast()//::<[u8; mem::size_of::()]>() }; 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)) } }) } }