use crate::encoding::{Encoding, Fixed};
use crate::read::Read;
use crate::write::Write;
use crate::Result;
pub(crate) fn encode_internal<'a>(
writer: &'a mut (impl Write + Default),
t: &(impl Encode + ?Sized),
) -> Result<&'a [u8]> {
writer.start_write();
t.encode(Fixed, writer)?;
Ok(writer.finish_write())
}
pub(crate) fn decode_internal<T: Decode>(
reader: &mut (impl Read + Default),
bytes: &[u8],
) -> Result<T> {
reader.start_read(bytes);
let decode_result = T::decode(Fixed, reader);
reader.finish_read_with_result(decode_result)
}
pub trait Encode {
#[doc(hidden)]
const ENCODE_MIN: usize;
#[doc(hidden)]
const ENCODE_MAX: usize;
#[doc(hidden)]
fn encode(&self, encoding: impl Encoding, writer: &mut impl Write) -> Result<()>;
}
pub trait Decode: Sized {
#[doc(hidden)]
const DECODE_MIN: usize;
#[doc(hidden)]
const DECODE_MAX: usize;
#[doc(hidden)]
fn decode(encoding: impl Encoding, reader: &mut impl Read) -> Result<Self>;
}
#[doc(hidden)]
#[macro_export]
macro_rules! optimized_enc {
($encoding:ident, $writer:ident) => {
let mut buf = $crate::__private::RegisterBuffer::default();
#[allow(unused_mut)]
let mut i: usize = 0;
#[allow(unused)]
let no_encoding_upstream = $encoding.is_fixed();
#[allow(unused)]
macro_rules! enc {
($t:expr, $T:ty) => {
if <$T>::ENCODE_MAX.saturating_add(i) <= 64 && no_encoding_upstream {
<$T>::encode(&$t, $encoding, &mut buf)?;
} else {
if i != 0 {
buf.flush($writer);
}
if <$T>::ENCODE_MAX < 64 && no_encoding_upstream {
<$T>::encode(&$t, $encoding, &mut buf)?;
} else {
<$T>::encode(&$t, $encoding, $writer)?;
}
}
i = if <$T>::ENCODE_MAX.saturating_add(i) <= 64 && no_encoding_upstream {
<$T>::ENCODE_MAX + i
} else {
if <$T>::ENCODE_MAX < 64 && no_encoding_upstream {
<$T>::ENCODE_MAX
} else {
0
}
};
};
}
macro_rules! flush {
() => {
if i != 0 {
buf.flush($writer);
}
};
}
macro_rules! end_enc {
() => {
flush!();
};
}
};
}
pub use optimized_enc;
#[cfg(test)]
mod optimized_enc_tests {
use test::{black_box, Bencher};
type A = u8;
type B = u8;
#[derive(Clone, Debug, PartialEq, crate::Encode, crate::Decode)]
struct Foo {
a: A,
b: B,
}
#[bench]
fn bench_foo(b: &mut Bencher) {
let mut buffer = crate::Buffer::new();
let foo = Foo { a: 1, b: 2 };
let foo = vec![foo; 4000];
let bytes = buffer.encode(&foo).unwrap().to_vec();
let decoded: Vec<Foo> = buffer.decode(&bytes).unwrap();
assert_eq!(foo, decoded);
b.iter(|| {
let foo = black_box(foo.as_slice());
let bytes = buffer.encode(foo).unwrap();
black_box(bytes);
})
}
#[bench]
fn bench_tuple(b: &mut Bencher) {
let mut buffer = crate::Buffer::new();
let foo = vec![(0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8); 1000];
b.iter(|| {
let foo = black_box(foo.as_slice());
let bytes = buffer.encode(foo).unwrap();
black_box(bytes);
})
}
#[bench]
fn bench_array(b: &mut Bencher) {
let mut buffer = crate::Buffer::new();
let foo = vec![[0u8; 8]; 1000];
b.iter(|| {
let foo = black_box(foo.as_slice());
let bytes = buffer.encode(foo).unwrap();
black_box(bytes);
})
}
#[bench]
fn bench_byte_slice(b: &mut Bencher) {
let mut buffer = crate::Buffer::new();
let foo = vec![0u8; 8 * 1000];
b.iter(|| {
let foo = black_box(foo.as_slice());
let bytes = buffer.encode(foo).unwrap();
black_box(bytes);
})
}
#[bench]
fn bench_bool_slice(b: &mut Bencher) {
let mut buffer = crate::Buffer::new();
let foo = vec![false; 8 * 1000];
b.iter(|| {
let foo = black_box(foo.as_slice());
let bytes = buffer.encode(foo).unwrap();
black_box(bytes);
})
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! optimized_dec {
($encoding:ident, $reader:ident) => {
let mut buf = $crate::__private::RegisterBuffer::default();
#[allow(unused_mut)]
let mut i: usize = 0;
#[allow(unused)]
let no_encoding_upstream = $encoding.is_fixed();
#[allow(unused)]
macro_rules! dec {
($t:ident, $T:ty) => {
let $t = if i >= <$T>::DECODE_MAX && no_encoding_upstream {
<$T>::decode($encoding, &mut buf)?
} else {
if <$T>::DECODE_MAX < 64 && no_encoding_upstream {
buf.refill($reader)?;
<$T>::decode($encoding, &mut buf)?
} else {
buf.advance_reader($reader)?;
<$T>::decode($encoding, $reader)?
}
};
i = if i >= <$T>::DECODE_MAX && no_encoding_upstream {
i - <$T>::DECODE_MAX
} else {
if <$T>::DECODE_MAX < 64 && no_encoding_upstream {
64usize.saturating_sub(<$T>::DECODE_MAX)
} else {
0
}
};
};
}
macro_rules! flush {
() => {
buf.advance_reader($reader)?;
};
}
macro_rules! end_dec {
() => {
let _ = i;
flush!();
};
}
};
}
pub use optimized_dec;
#[cfg(test)]
mod optimized_dec_tests {
use test::{black_box, Bencher};
type A = u8;
type B = u8;
#[derive(Clone, Debug, PartialEq, crate::Encode, crate::Decode)]
#[repr(C, align(8))]
struct Foo {
a: A,
b: B,
c: A,
d: B,
e: A,
f: B,
g: A,
h: B,
}
#[bench]
fn bench_foo(b: &mut Bencher) {
let mut buffer = crate::Buffer::new();
let foo = Foo {
a: 1,
b: 2,
c: 3,
d: 4,
e: 5,
f: 6,
g: 7,
h: 8,
};
let foo = vec![foo; 1000];
type T = Vec<Foo>;
let bytes = buffer.encode(&foo).unwrap().to_vec();
let decoded: T = buffer.decode(&bytes).unwrap();
assert_eq!(foo, decoded);
b.iter(|| {
let bytes = black_box(bytes.as_slice());
black_box(buffer.decode::<T>(bytes).unwrap())
})
}
#[bench]
fn bench_tuple(b: &mut Bencher) {
let mut buffer = crate::Buffer::new();
let foo = vec![(0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8); 1000];
type T = Vec<(u8, u8, u8, u8, u8, u8, u8, u8)>;
let bytes = buffer.encode(&foo).unwrap().to_vec();
let decoded: T = buffer.decode(&bytes).unwrap();
assert_eq!(foo, decoded);
b.iter(|| {
let bytes = black_box(bytes.as_slice());
black_box(buffer.decode::<T>(bytes).unwrap())
})
}
#[bench]
fn bench_array(b: &mut Bencher) {
let mut buffer = crate::Buffer::new();
let foo = vec![[0u8; 8]; 1000];
type T = Vec<[u8; 8]>;
let bytes = buffer.encode(&foo).unwrap().to_vec();
let decoded: T = buffer.decode(&bytes).unwrap();
assert_eq!(foo, decoded);
b.iter(|| {
let bytes = black_box(bytes.as_slice());
black_box(buffer.decode::<T>(bytes).unwrap())
})
}
#[bench]
fn bench_vec(b: &mut Bencher) {
let mut buffer = crate::Buffer::new();
let foo = vec![0u8; 8000];
type T = Vec<u8>;
let bytes = buffer.encode(&foo).unwrap().to_vec();
let decoded: T = buffer.decode(&bytes).unwrap();
assert_eq!(foo, decoded);
b.iter(|| {
let bytes = black_box(bytes.as_slice());
black_box(buffer.decode::<T>(bytes).unwrap())
})
}
}