#![warn(missing_docs)]
mod error;
mod macros;
pub mod ctx;
pub mod derive;
pub mod util;
pub use self::error::Error;
#[doc(hidden)]
pub use std as export;
#[cfg(feature = "derive")]
pub use declio_derive::Decode;
#[cfg(feature = "derive")]
pub use declio_derive::Encode;
use self::ctx::{Endian, Len};
use std::borrow::Cow;
use std::{io, mem};
pub fn to_bytes<T>(value: T) -> Result<Vec<u8>, Error>
where
T: Encode,
{
to_bytes_with_context(value, ())
}
pub fn to_bytes_with_context<T, Ctx>(value: T, ctx: Ctx) -> Result<Vec<u8>, Error>
where
T: Encode<Ctx>,
{
let mut bytes = Vec::new();
value.encode(ctx, &mut bytes)?;
Ok(bytes)
}
pub fn from_bytes<T>(bytes: &[u8]) -> Result<T, Error>
where
T: Decode,
{
from_bytes_with_context(bytes, ())
}
pub fn from_bytes_with_context<T, Ctx>(mut bytes: &[u8], ctx: Ctx) -> Result<T, Error>
where
T: Decode<Ctx>,
{
let value = T::decode(ctx, &mut bytes)?;
if bytes.is_empty() {
Ok(value)
} else {
Err(Error::new("byte slice was not fully consumed"))
}
}
pub trait Encode<Ctx = ()> {
fn encode<W>(&self, ctx: Ctx, writer: &mut W) -> Result<(), Error>
where
W: io::Write;
}
pub trait Decode<Ctx = ()>: Sized {
fn decode<R>(ctx: Ctx, reader: &mut R) -> Result<Self, Error>
where
R: io::Read;
}
impl<T, Ctx> Encode<Ctx> for &T
where
T: Encode<Ctx>,
{
fn encode<W>(&self, ctx: Ctx, writer: &mut W) -> Result<(), Error>
where
W: io::Write,
{
(*self).encode(ctx, writer)
}
}
impl<T, Ctx> Encode<(Len, Ctx)> for [T]
where
T: Encode<Ctx>,
Ctx: Clone,
{
fn encode<W>(&self, (Len(len), inner_ctx): (Len, Ctx), writer: &mut W) -> Result<(), Error>
where
W: io::Write,
{
if self.len() != len {
Err(Error::new(
"provided length context does not match the slice length",
))
} else {
self.encode((inner_ctx,), writer)
}
}
}
impl<T> Encode<Len> for [T]
where
T: Encode,
{
fn encode<W>(&self, len: Len, writer: &mut W) -> Result<(), Error>
where
W: io::Write,
{
self.encode((len, ()), writer)
}
}
impl<T, Ctx> Encode<(Ctx,)> for [T]
where
T: Encode<Ctx>,
Ctx: Clone,
{
fn encode<W>(&self, (inner_ctx,): (Ctx,), writer: &mut W) -> Result<(), Error>
where
W: io::Write,
{
for elem in self {
elem.encode(inner_ctx.clone(), writer)?;
}
Ok(())
}
}
impl<T, Ctx, const N: usize> Encode<Ctx> for [T; N]
where
T: Encode<Ctx>,
Ctx: Clone,
{
fn encode<W>(&self, inner_ctx: Ctx, writer: &mut W) -> Result<(), Error>
where
W: io::Write,
{
for elem in self {
elem.encode(inner_ctx.clone(), writer)?;
}
Ok(())
}
}
impl<T, Ctx, const N: usize> Decode<Ctx> for [T; N]
where
T: Decode<Ctx> + Copy + Default,
Ctx: Clone,
{
fn decode<R>(inner_ctx: Ctx, reader: &mut R) -> Result<Self, Error>
where
R: io::Read,
{
let mut arr = [Default::default(); N];
for slot in &mut arr {
*slot = Decode::decode(inner_ctx.clone(), reader)?;
}
Ok(arr)
}
}
impl<T, Ctx> Encode<(Len, Ctx)> for Vec<T>
where
T: Encode<Ctx>,
Ctx: Clone,
{
fn encode<W>(&self, ctx: (Len, Ctx), writer: &mut W) -> Result<(), Error>
where
W: io::Write,
{
self.as_slice().encode(ctx, writer)
}
}
impl<T> Encode<Len> for Vec<T>
where
T: Encode,
{
fn encode<W>(&self, ctx: Len, writer: &mut W) -> Result<(), Error>
where
W: io::Write,
{
self.as_slice().encode(ctx, writer)
}
}
impl<T, Ctx> Encode<(Ctx,)> for Vec<T>
where
T: Encode<Ctx>,
Ctx: Clone,
{
fn encode<W>(&self, ctx: (Ctx,), writer: &mut W) -> Result<(), Error>
where
W: io::Write,
{
self.as_slice().encode(ctx, writer)
}
}
impl<T, Ctx> Decode<(Len, Ctx)> for Vec<T>
where
T: Decode<Ctx>,
Ctx: Clone,
{
fn decode<R>((Len(len), inner_ctx): (Len, Ctx), reader: &mut R) -> Result<Self, Error>
where
R: io::Read,
{
let mut acc = Self::with_capacity(len);
for _ in 0..len {
acc.push(T::decode(inner_ctx.clone(), reader)?);
}
Ok(acc)
}
}
impl<T> Decode<Len> for Vec<T>
where
T: Decode,
{
fn decode<R>(len: Len, reader: &mut R) -> Result<Self, Error>
where
R: io::Read,
{
Self::decode((len, ()), reader)
}
}
impl<T, Ctx> Encode<Ctx> for Option<T>
where
T: Encode<Ctx>,
{
fn encode<W>(&self, inner_ctx: Ctx, writer: &mut W) -> Result<(), Error>
where
W: io::Write,
{
if let Some(inner) = self {
inner.encode(inner_ctx, writer)
} else {
Ok(())
}
}
}
impl<T, Ctx> Decode<Ctx> for Option<T>
where
T: Decode<Ctx>,
{
fn decode<R>(inner_ctx: Ctx, reader: &mut R) -> Result<Self, Error>
where
R: io::Read,
{
T::decode(inner_ctx, reader).map(Some)
}
}
impl<'a, T, Ctx> Encode<Ctx> for Cow<'a, T>
where
T: Encode<Ctx> + ToOwned + ?Sized,
{
fn encode<W>(&self, inner_ctx: Ctx, writer: &mut W) -> Result<(), Error>
where
W: io::Write,
{
T::encode(&*self, inner_ctx, writer)
}
}
impl<'a, T, Ctx> Decode<Ctx> for Cow<'a, T>
where
T: ToOwned + ?Sized,
T::Owned: Decode<Ctx>,
{
fn decode<R>(inner_ctx: Ctx, reader: &mut R) -> Result<Self, Error>
where
R: io::Read,
{
T::Owned::decode(inner_ctx, reader).map(Self::Owned)
}
}
impl<T, Ctx> Encode<Ctx> for Box<T>
where
T: Encode<Ctx>,
{
fn encode<W>(&self, inner_ctx: Ctx, writer: &mut W) -> Result<(), Error>
where
W: io::Write,
{
T::encode(&*self, inner_ctx, writer)
}
}
impl<T, Ctx> Decode<Ctx> for Box<T>
where
T: Decode<Ctx>,
{
fn decode<R>(inner_ctx: Ctx, reader: &mut R) -> Result<Self, Error>
where
R: io::Read,
{
T::decode(inner_ctx, reader).map(Self::new)
}
}
impl Encode for () {
fn encode<W>(&self, _: (), _: &mut W) -> Result<(), Error>
where
W: io::Write,
{
Ok(())
}
}
impl Decode for () {
fn decode<R>(_: (), _: &mut R) -> Result<Self, Error>
where
R: io::Read,
{
Ok(())
}
}
macro_rules! impl_primitive {
($($t:ty)*) => {$(
impl Encode<Endian> for $t {
fn encode<W>(&self, endian: Endian, writer: &mut W) -> Result<(), Error>
where
W: io::Write,
{
let bytes = match endian {
Endian::Big => self.to_be_bytes(),
Endian::Little => self.to_le_bytes(),
};
writer.write_all(&bytes)?;
Ok(())
}
}
impl Decode<Endian> for $t {
fn decode<R>(endian: Endian, reader: &mut R) -> Result<Self, Error>
where
R: io::Read,
{
let mut bytes = [0u8; mem::size_of::<$t>()];
reader.read_exact(&mut bytes)?;
match endian {
Endian::Big => Ok(Self::from_be_bytes(bytes)),
Endian::Little => Ok(Self::from_le_bytes(bytes)),
}
}
}
)*}
}
impl_primitive! {
u8 u16 u32 u64 u128 i8 i16 i32 i64 i128 f32 f64
}
impl Encode for u8 {
fn encode<W>(&self, _ctx: (), writer: &mut W) -> Result<(), Error>
where
W: io::Write,
{
self.encode(Endian::Big, writer)
}
}
impl Decode for u8 {
fn decode<R>(_ctx: (), reader: &mut R) -> Result<Self, Error>
where
R: io::Read,
{
Self::decode(Endian::Big, reader)
}
}
impl Encode for i8 {
fn encode<W>(&self, _ctx: (), writer: &mut W) -> Result<(), Error>
where
W: io::Write,
{
self.encode(Endian::Big, writer)
}
}
impl Decode for i8 {
fn decode<R>(_ctx: (), reader: &mut R) -> Result<Self, Error>
where
R: io::Read,
{
Self::decode(Endian::Big, reader)
}
}