zlo 0.1.0

A binary serialization/deserialization strategy that uses Serde for transforming structs into very compact bit representations
Documentation
#![deny(missing_docs)]

//! `zlo` is a crate for encoding and decoding using a bit-compact
//! serialization strategy.
//!
//! ### Using Basic Functions
//!
//! ```rust
//! extern crate zlo;
//! use zlo::{serialize, deserialize, Bounded};
//! fn main() {
//!     // The object that we will serialize.
//!     let target = Some("hello world".to_string());
//!     // The maximum size of the encoded message.
//!     let limit = Bounded(20);
//!
//!     let encoded: Vec<u8>        = serialize(&target, limit).unwrap();
//!     let decoded: Option<String> = deserialize(&encoded[..]).unwrap();
//!     assert_eq!(target, decoded);
//! }
//! ```

extern crate serde;

pub use de::Deserializer;
pub use ser::Serializer;
use ser::SizeChecker;

use std::io::Read;
use std::io::Write;
use std::{error, fmt, io, result};

mod ser;
mod de;

/// The result of a serialization or deserialization operation.
pub type Result<T> = result::Result<T, Error>;

/// The kind of error that can be produced during a serialization or
/// deserialization.
#[derive(Debug)]
pub enum Error {
    /// If the error stems from the reader/writer that is being used during
    /// (de)serialization, that error will be stored and returned here.
    Io(io::Error),
    /// If the bytes in the reader are not decodable because of an invalid
    /// encoding, this error will be returned.  This error is only possible if a
    /// stream is corrupted.  A stream produced from `encode` or `encode_into`
    /// should **never** produce an InvalidEncoding error.
    InvalidEncoding {
        #[allow(missing_docs)]
        desc: &'static str,
        #[allow(missing_docs)]
        detail: Option<String>,
    },
    /// If (de)serializing a message takes more than the provided size limit,
    /// this error is returned.
    SizeLimit,
    /// zlo can not encode sequences of unknown length (like iterators).
    SequenceMustHaveLength,
    /// A custom error message from Serde.
    Custom(String),
    #[doc(hidden)]
    __Nonexhaustive,
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Io(ref err) => error::Error::description(err),
            Error::InvalidEncoding { desc, .. } => desc,
            Error::SequenceMustHaveLength => "zlo can't encode infinite sequences",
            Error::SizeLimit => "the size limit for decoding has been reached",
            Error::Custom(ref msg) => msg,
            Error::__Nonexhaustive => unreachable!(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Io(ref err) => Some(err),
            Error::InvalidEncoding { .. } => None,
            Error::SequenceMustHaveLength => None,
            Error::SizeLimit => None,
            Error::Custom(_) => None,
            Error::__Nonexhaustive => unreachable!(),
        }
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err).into()
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Io(ref ioerr) => write!(fmt, "Io: {}", ioerr),
            Error::InvalidEncoding { desc, detail: None } =>
                write!(fmt, "InvalidEncoding: {}", desc),
            Error::InvalidEncoding {
                desc, detail: Some(ref detail),
            } => write!(fmt, "InvalidEncoding: {} ({})", desc, detail),
            Error::SequenceMustHaveLength =>
                write!(fmt, "zlo can only encode sequences and maps that have \
                             a knowable size ahead of time."),
            Error::SizeLimit => write!(fmt, "SizeLimit"),
            Error::Custom(ref s) => s.fmt(fmt),
            Error::__Nonexhaustive => unreachable!(),
        }
    }
}

impl serde::de::Error for Error {
    fn custom<T: fmt::Display>(desc: T) -> Error {
        Error::Custom(desc.to_string()).into()
    }
}

impl serde::ser::Error for Error {
    fn custom<T: fmt::Display>(msg: T) -> Self {
        Error::Custom(msg.to_string()).into()
    }
}

/// Serializes an object directly into a `Writer`.
///
/// If the serialization would take more bytes than allowed by `size_limit`, an
/// error is returned and *no bytes* will be written into the `Writer`.
///
/// If this returns an `Error` (other than SizeLimit), assume that the writer is
/// in an invalid state, as writing could bail out in the middle of serializing.
pub fn serialize_into<W, T: ?Sized, S>(
    writer: W,
    value: &T,
    size_limit: S,
) -> Result<()>
where
    W: Write,
    T: serde::Serialize,
    S: SizeLimit,
{
    if let Some(limit) = size_limit.limit() {
        serialized_size_bounded(value, limit)
            .ok_or(Error::SizeLimit)?;
    }

    let mut serializer = Serializer::<_>::new(writer);
    serde::Serialize::serialize(value, &mut serializer)?;
    serializer.finish().map_err(|(_, e)| e)?;
    Ok(())
}

/// Serializes a serializable object into a `Vec` of bytes.
///
/// If the serialization would take more bytes than allowed by `size_limit`,
/// an error is returned.
pub fn serialize<T: ?Sized, S>(value: &T, size_limit: S) -> Result<Vec<u8>>
where
    T: serde::Serialize,
    S: SizeLimit,
{
    let mut writer = match size_limit.limit() {
        Some(size_limit) => {
            let actual_size = serialized_size_bounded(value, size_limit)
                .ok_or(Error::SizeLimit)?;
            Vec::with_capacity(actual_size as usize)
        }
        None => Vec::with_capacity(serialized_size(value) as usize)
    };
    serialize_into(&mut writer, value, Infinite)?;
    Ok(writer)
}

impl SizeLimit for CountSize {
    fn add(&mut self, c: u64) -> Result<()> {
        self.total += c;
        if let Some(limit) = self.limit {
            if self.total > limit {
                return Err(Error::SizeLimit);
            }
        }
        Ok(())
    }

    fn limit(&self) -> Option<u64> {
        unreachable!()
    }
}

/// Returns the size that an object would be if serialized using zlo.
///
/// It can be useful for preallocating buffers if thats your style.
pub fn serialized_size<T: ?Sized>(value: &T) -> u64
where
    T: serde::Serialize,
{
    let mut size_counter = SizeChecker {
        size_limit: CountSize {
            total: 0,
            limit: None,
        },
    };

    value.serialize(&mut size_counter).ok();
    size_counter.size_limit.total
}

/// Given a maximum size limit, check how large an object would be if it were to
/// be serialized.
///
/// If it can be serialized in `max` or fewer bytes, that number will be
/// returned inside `Some`.  If it goes over bounds, then None is returned.
pub fn serialized_size_bounded<T: ?Sized>(value: &T, max: u64) -> Option<u64>
where
    T: serde::Serialize,
{
    let mut size_counter = SizeChecker {
        size_limit: CountSize {
            total: 0,
            limit: Some(max),
        },
    };

    match value.serialize(&mut size_counter) {
        Ok(_) => Some(size_counter.size_limit.total),
        Err(_) => None,
    }
}

/// Deserializes an object directly from a `Buffer`ed Reader.
///
/// If the provided `SizeLimit` is reached, the deserialization will bail
/// immediately.  A SizeLimit can help prevent an attacker from flooding your
/// server with a neverending stream of values that runs your server out of
/// memory.
///
/// If this returns an `Error`, assume that the buffer that you passed in is in
/// an invalid state, as the error could be returned during any point in the
/// reading.
pub fn deserialize_from<R, T, S>(reader: R, size_limit: S) -> Result<T>
where
    R: Read,
    T: serde::de::DeserializeOwned,
    S: SizeLimit,
{
    let mut deserializer = Deserializer::<_, S>::new(reader, size_limit);
    serde::Deserialize::deserialize(&mut deserializer)
}

/// Deserializes a slice of bytes into an object.
///
/// This method does not have a size-limit because if you already have the bytes
/// in memory, then you don't gain anything by having a limiter.
pub fn deserialize<'a, T>(bytes: &'a [u8]) -> Result<T>
where
    T: serde::de::Deserialize<'a>,
{
    use std::io::Cursor;
    let reader = Cursor::new(&bytes);
    let mut deserializer = Deserializer::new(reader, Infinite);
    serde::Deserialize::deserialize(&mut deserializer)
}

/// A limit on the amount of bits that can be read or written.
///
/// Size limits are an incredibly important part of both encoding and decoding.
///
/// In order to prevent DOS attacks on a decoder, it is important to limit the
/// amount of bits that a single encoded message can be; otherwise, if you are
/// decoding bits right off of a TCP stream for example, it would be possible
/// for an attacker to flood your server with a 3TB vec, causing the decoder to
/// run out of memory and crash your application!  Because of this, you can
/// provide a maximum-number-of-bits that can be read during decoding, and the
/// decoder will explicitly fail if it has to read any more than that.
///
/// On the other side, you want to make sure that you aren't encoding a message
/// that is larger than your decoder expects.  By supplying a size limit to an
/// encoding function, the encoder will verify that the structure can be encoded
/// within that limit.  This verification occurs before any bits are written to
/// the Writer, so recovering from an error is easy.
pub trait SizeLimit: private::Sealed {
    /// Tells the SizeLimit that a certain number of bits has been read or
    /// written.  Returns Err if the limit has been exceeded.
    fn add(&mut self, n: u64) -> Result<()>;
    /// Returns the hard limit (if one exists)
    fn limit(&self) -> Option<u64>;
}

/// A SizeLimit that restricts serialized or deserialized messages from
/// exceeding a certain bit length.
#[derive(Copy, Clone)]
pub struct Bounded(u64);

impl Bounded {
    /// Create new bit limit.
    pub fn new_bits(lim: u64) -> Self {
        Self { 0: lim }
    }

    /// Create new byte limit.
    pub fn new_bytes(lim: u64) -> Self {
        assert!(lim <= ::std::u64::MAX / 8, "lim must be representable \
                                             as bit count in 64 bits");
        Self { 0: lim * 8 }
    }
}

/// A SizeLimit without a limit!
/// Use this if you don't care about the size of encoded or decoded messages.
#[derive(Copy, Clone)]
pub struct Infinite;

struct CountSize {
    total: u64,
    limit: Option<u64>,
}

impl SizeLimit for Bounded {
    #[inline(always)]
    fn add(&mut self, n: u64) -> Result<()> {
        if self.0 >= n {
            self.0 -= n;
            Ok(())
        } else {
            Err(Error::SizeLimit)
        }
    }

    #[inline(always)]
    fn limit(&self) -> Option<u64> {
        Some(self.0)
    }
}

impl SizeLimit for Infinite {
    #[inline(always)]
    fn add(&mut self, _: u64) -> Result<()> {
        Ok(())
    }

    #[inline(always)]
    fn limit(&self) -> Option<u64> {
        None
    }
}

mod private {
    pub trait Sealed {}

    impl Sealed for super::Infinite {}
    impl Sealed for super::Bounded {}
    impl Sealed for super::CountSize {}
}