mirror of https://git.sr.ht/~stygianentity/bincode
201 lines
6.5 KiB
Rust
201 lines
6.5 KiB
Rust
#![deny(missing_docs)]
|
|
|
|
//! `bincode` is a crate for encoding and decoding using a tiny binary
|
|
//! serialization strategy.
|
|
//!
|
|
//! There are simple functions for encoding to `Vec<u8>` and decoding from
|
|
//! `&[u8]`, but the meat of the library is the `serialize_into` and `deserialize_from`
|
|
//! functions which respectively allow encoding into any `std::io::Write`
|
|
//! or decode from any `std::io::Read`.
|
|
//!
|
|
//! ## Modules
|
|
//! Until "default type parameters" lands, we have an extra module called `endian_choice`
|
|
//! that duplicates all of the core bincode functionality but with the option to choose
|
|
//! which endianness the integers are encoded using.
|
|
//!
|
|
//! The default endianness is little.
|
|
//!
|
|
//! ### Using Basic Functions
|
|
//!
|
|
//! ```rust
|
|
//! extern crate bincode;
|
|
//! use bincode::{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);
|
|
//! }
|
|
//! ```
|
|
|
|
#![crate_name = "bincode"]
|
|
#![crate_type = "rlib"]
|
|
#![crate_type = "dylib"]
|
|
|
|
extern crate byteorder;
|
|
extern crate serde as serde_crate;
|
|
|
|
mod ser;
|
|
mod de;
|
|
pub mod internal;
|
|
|
|
pub mod read_types {
|
|
//! The types that the deserializer uses for optimizations
|
|
pub use de::read::{SliceReader, BincodeRead, IoReader};
|
|
}
|
|
|
|
use std::io::{Read, Write};
|
|
|
|
pub use internal::{ErrorKind, Error, Result, serialized_size, serialized_size_bounded};
|
|
|
|
/// A Deserializer that uses LittleEndian byteorder
|
|
pub type Deserializer<W, S> = internal::Deserializer<W, S, byteorder::LittleEndian>;
|
|
/// A Serializer that uses LittleEndian byteorder
|
|
pub type Serializer<W> = internal::Serializer<W, byteorder::LittleEndian>;
|
|
|
|
/// 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]) -> internal::Result<T>
|
|
where
|
|
T: serde_crate::de::Deserialize<'a>,
|
|
{
|
|
internal::deserialize::<_, byteorder::LittleEndian>(bytes)
|
|
}
|
|
|
|
/// 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: ?Sized, T, S>(reader: &mut R, size_limit: S) -> internal::Result<T>
|
|
where
|
|
R: Read,
|
|
T: serde_crate::de::DeserializeOwned,
|
|
S: SizeLimit,
|
|
{
|
|
internal::deserialize_from::<_, _, _, byteorder::LittleEndian>(reader, size_limit)
|
|
}
|
|
|
|
/// 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: ?Sized, T: ?Sized, S>(
|
|
writer: &mut W,
|
|
value: &T,
|
|
size_limit: S,
|
|
) -> internal::Result<()>
|
|
where
|
|
W: Write,
|
|
T: serde_crate::Serialize,
|
|
S: SizeLimit,
|
|
{
|
|
internal::serialize_into::<_, _, _, byteorder::LittleEndian>(writer, value, size_limit)
|
|
}
|
|
|
|
/// 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) -> internal::Result<Vec<u8>>
|
|
where
|
|
T: serde_crate::Serialize,
|
|
S: SizeLimit,
|
|
{
|
|
internal::serialize::<_, _, byteorder::LittleEndian>(value, size_limit)
|
|
}
|
|
|
|
/// A limit on the amount of bytes 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 bytes that a single encoded message can be; otherwise, if you
|
|
/// are decoding bytes 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-bytes 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 bytes 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 bytes 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 byte length.
|
|
#[derive(Copy, Clone)]
|
|
pub struct Bounded(pub u64);
|
|
|
|
/// 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(Box::new(ErrorKind::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<'a> Sealed for super::de::read::SliceReader<'a> {}
|
|
impl<R> Sealed for super::de::read::IoReader<R> {}
|
|
impl Sealed for super::Infinite {}
|
|
impl Sealed for super::Bounded {}
|
|
impl Sealed for super::CountSize {}
|
|
}
|