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.
94 lines
2.3 KiB
94 lines
2.3 KiB
//! Encoding data
|
|
use std::fmt::{
|
|
self,
|
|
Write,
|
|
};
|
|
use smallmap::{
|
|
Primitive,
|
|
Map,
|
|
};
|
|
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))
|
|
}
|
|
})
|
|
}
|
|
}
|