#[cfg(feature = "alloc")]
use alloc::vec::Vec;
pub mod encoders;
pub trait Encodable {
type Encoder<'e>: Encoder
where
Self: 'e;
fn encoder(&self) -> Self::Encoder<'_>;
}
pub trait Encoder {
fn current_chunk(&self) -> &[u8];
fn advance(&mut self) -> bool;
}
#[macro_export]
macro_rules! encoder_newtype{
(
$(#[$($struct_attr:tt)*])*
pub struct $name:ident<$lt:lifetime>($encoder:ty);
) => {
$(#[$($struct_attr)*])*
pub struct $name<$lt>($encoder, core::marker::PhantomData<&$lt $encoder>);
impl<$lt> $name<$lt> {
pub fn new(encoder: $encoder) -> $name<$lt> {
$name(encoder, core::marker::PhantomData)
}
}
impl<$lt> $crate::Encoder for $name<$lt> {
#[inline]
fn current_chunk(&self) -> &[u8] { self.0.current_chunk() }
#[inline]
fn advance(&mut self) -> bool { self.0.advance() }
}
}
}
#[macro_export]
macro_rules! encoder_newtype_exact{
(
$(#[$($struct_attr:tt)*])*
pub struct $name:ident<$lt:lifetime>($encoder:ty);
) => {
$crate::encoder_newtype! {
$(#[$($struct_attr)*])*
pub struct $name<$lt>($encoder);
}
impl<$lt> $crate::ExactSizeEncoder for $name<$lt> {
#[inline]
fn len(&self) -> usize { self.0.len() }
}
}
}
pub struct EncodableByteIter<'e, T: Encodable + 'e> {
enc: T::Encoder<'e>,
position: usize,
}
impl<'e, T: Encodable + 'e> EncodableByteIter<'e, T> {
pub fn new(encodable: &'e T) -> Self { Self { enc: encodable.encoder(), position: 0 } }
}
impl<'e, T: Encodable + 'e> Iterator for EncodableByteIter<'e, T> {
type Item = u8;
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(b) = self.enc.current_chunk().get(self.position) {
self.position += 1;
return Some(*b);
} else if !self.enc.advance() {
return None;
}
self.position = 0;
}
}
}
impl<'e, T> ExactSizeIterator for EncodableByteIter<'e, T>
where
T: Encodable + 'e,
T::Encoder<'e>: ExactSizeEncoder,
{
fn len(&self) -> usize { self.enc.len() - self.position }
}
pub trait ExactSizeEncoder: Encoder {
fn len(&self) -> usize;
fn is_empty(&self) -> bool { self.len() == 0 }
}
#[cfg(feature = "alloc")]
pub fn encode_to_vec<T>(object: &T) -> Vec<u8>
where
T: Encodable + ?Sized,
{
let mut encoder = object.encoder();
flush_to_vec(&mut encoder)
}
#[cfg(feature = "alloc")]
pub fn flush_to_vec<T>(encoder: &mut T) -> Vec<u8>
where
T: Encoder + ?Sized,
{
let mut vec = Vec::new();
loop {
vec.extend_from_slice(encoder.current_chunk());
if !encoder.advance() {
break;
}
}
vec
}
#[cfg(feature = "std")]
pub fn encode_to_writer<T, W>(object: &T, writer: W) -> Result<(), std::io::Error>
where
T: Encodable + ?Sized,
W: std::io::Write,
{
let mut encoder = object.encoder();
flush_to_writer(&mut encoder, writer)
}
#[cfg(feature = "std")]
pub fn flush_to_writer<T, W>(encoder: &mut T, mut writer: W) -> Result<(), std::io::Error>
where
T: Encoder + ?Sized,
W: std::io::Write,
{
loop {
writer.write_all(encoder.current_chunk())?;
if !encoder.advance() {
break;
}
}
Ok(())
}
impl<T: Encoder> Encoder for Option<T> {
fn current_chunk(&self) -> &[u8] {
match self {
Some(encoder) => encoder.current_chunk(),
None => &[],
}
}
fn advance(&mut self) -> bool {
match self {
Some(encoder) => encoder.advance(),
None => false,
}
}
}