1
Fork 0
framed-rs/framed/src/typed.rs
2017-12-29 02:00:34 +00:00

436 lines
13 KiB
Rust

//! Sending and receiving serde-serialized structs.
//!
//! Currently structs are serialized with [`ssmarshal`][ssmarshal],
//! but this is an implementation detail that may change without
//! warning. `ssmarshal` uses a straightforward, compact serialization
//! format that doesn't support compatibility between versions or
//! dynamic length types (arrays, maps). Its lack of versioning fits
//! with the design goals for the frame encoding in this crate:
//! unsuitable for long-term storage or transmission between different
//! versions of an application, but space-efficient.
//!
//! [ssmarshal]: https://crates.io/crates/ssmarshal
//!
//! ## Example usage from a `std` crate
//!
//! The `Sender` struct writes serialized and encoded values to an
//! inner `std::io::Write` instance, and the `Receiver` struct reads
//! and decodes values from an inner `std::io::Read` instance.
//!
//! ```rust
//! # extern crate framed;
//! # use framed::typed::*;
//! # extern crate serde;
//! # #[macro_use]
//! # extern crate serde_derive;
//! #
//! # use std::io::Cursor;
//! #
//! # fn main() {
//! #[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
//! struct Test {
//! a: u8,
//! b: u16,
//! }
//!
//! let payload = Test { a: 1, b: 2 };
//!
//! let mut encoded = vec![];
//! {
//! let mut sender = Sender::<_, Test>::new(&mut encoded);
//! sender.send(&payload).expect("send ok");
//! }
//!
//! // `encoded` now contains the encoded value.
//!
//! let mut receiver = Receiver::<_, Test>::new(Cursor::new(encoded));
//! let decoded = receiver.recv().expect("recv ok");
//!
//! assert_eq!(payload, decoded);
//! # }
//! ```
//!
//! ## Example usage from a `no_std` crate
//!
//! The `encode_to_slice` and `decode_from_slice` functions offer an
//! API for `no_std` crates that do not have a heap allocator and
//! cannot use `std::io::Read` or `std::io::Write`.
//!
//! ```rust
//! # extern crate framed;
//! # use framed::typed::*;
//! # extern crate serde;
//! # #[macro_use]
//! # extern crate serde_derive;
//! #
//! # fn main() {
//! # #[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
//! # struct Test {
//! # a: u8,
//! # b: u16,
//! # }
//! #
//! # let payload = Test { a: 1, b: 2 };
//! #
//! let mut ser_buf = [0u8; max_serialize_buf_len::<Test>()];
//! let mut encoded_buf = [0u8; max_encoded_len::<Test>()];
//! let encoded_len = encode_to_slice::<Test>(
//! &payload,
//! &mut ser_buf,
//! &mut encoded_buf
//! ).expect("encode ok");
//! let encoded = &encoded_buf[0..encoded_len];
//!
//! // `encoded` now contains the complete encoded frame.
//!
//! let mut de_buf = [0u8; max_serialize_buf_len::<Test>()];
//! let decoded = decode_from_slice(encoded, &mut de_buf)
//! .expect("decode ok");
//!
//! assert_eq!(payload, decoded);
//! # }
//! ```
use ::{Encoded, TempBuffer};
use ::bytes;
use ::error::{Result};
#[cfg(feature = "use_std")]
use core::marker::PhantomData;
use core::mem::size_of;
use serde::Serialize;
use serde::de::DeserializeOwned;
use ssmarshal;
#[cfg(feature = "use_std")]
use std::io::{Read, Write};
/// Serializes and encodes the supplied value `v` into destination
/// buffer `dest`, using `ser_buf` as a temporary serialization buffer.
/// Available from `no_std` crates.
///
/// Returns the number of bytes written to the beginning of `dest`.
///
/// ## Panics
///
/// This will panic if the supplied buffers are too small to serialize
/// a value of `T`. Callers must ensure that:
///
/// * `ser_buf.len() >= max_serialize_buf_len::<T>()` and
/// * `dest.len() >= max_encoded_len::<T>()`.
///
/// ## Examples
///
/// See the [no_std usage example][ex] in the `typed` module documentation.
/// [ex]: index.html#example-usage-from-a-no_std-crate
pub fn encode_to_slice<T: DeserializeOwned + Serialize>(
v: &T,
ser_buf: &mut TempBuffer,
dest: &mut Encoded,
) -> Result<usize> {
assert!(ser_buf.len() >= max_serialize_buf_len::<T>());
assert!(dest.len() >= max_encoded_len::<T>());
let ser_len = ssmarshal::serialize(ser_buf, v)?;
let ser = &ser_buf[0..ser_len];
bytes::encode_to_slice(ser, dest)
}
/// Decodes the supplied encoded frame `e`, then deserializes its
/// payload as a value of type `T`, using `de_buf` as a temporary
/// deserialization buffer. Available from `no_std` crates.
///
/// Returns the deserialized value.
///
/// ## Panics
///
/// This will panic if the supplied buffer is too small to deserialize
/// a value of `T`. Callers must ensure that:
///
/// * `de_buf.len() >= max_serialize_buf_len::<T>()`.
///
/// ## Examples
///
/// See the [no_std usage example][ex] in the `typed` module documentation.
/// [ex]: index.html#example-usage-from-a-no_std-crate
pub fn decode_from_slice<T: DeserializeOwned + Serialize>(
e: &Encoded,
de_buf: &mut TempBuffer
) -> Result<T> {
assert!(de_buf.len() >= max_serialize_buf_len::<T>());
let de_len = bytes::decode_to_slice(e, de_buf)?;
let payload = &de_buf[0..de_len];
let (v, _len) = ssmarshal::deserialize(payload)?;
Ok(v)
}
const_fn! {
/// Returns an upper bound for the encoded length of a frame with a
/// serialized `T` value as its payload.
///
/// Useful for calculating an appropriate buffer length.
pub fn max_encoded_len<T: Serialize>() -> usize {
bytes::max_encoded_len(max_serialize_buf_len::<T>())
}
}
const_fn! {
/// Returns an upper bound for the temporary serialization buffer
/// length needed by `encode_to_slice` and `decode_from_slice` when
/// serializing or deserializing a value of type `T`.
pub fn max_serialize_buf_len<T: Serialize>() -> usize {
bytes::max_encoded_len(size_of::<T>())
}
}
/// Sends encoded structs of type `T` over an inner `std::io::Write` instance.
///
/// ## Examples
///
/// See the [std usage example][ex] in the `typed` module documentation.
/// [ex]: index.html#example-usage-from-a-std-crate
#[cfg(feature = "use_std")]
pub struct Sender<W: Write, T: Serialize> {
w: W,
_t: PhantomData<T>,
}
#[cfg(feature = "use_std")]
impl<W: Write, T: Serialize> Sender<W, T> {
/// Construct a `Sender` that sends encoded structs over the supplied
/// `io::Write`.
pub fn new(w: W) -> Sender<W, T> {
Sender::<W, T> {
w: w,
_t: PhantomData::default(),
}
}
/// Consume this `Sender` and return the inner `std::io::Write`.
pub fn into_inner(self) -> W {
self.w
}
/// Flush all buffered data. Includes calling `flush` on the inner
/// writer.
pub fn flush(&mut self) -> Result<()> {
Ok(self.w.flush()?)
}
/// Queue the supplied payload for transmission.
///
/// This `Sender` may buffer the data indefinitely, as may the
/// inner writer. To ensure all buffered data has been
/// transmitted call [`flush`](#method.flush).
///
/// See also: [`send`](#method.send)
pub fn queue(&mut self, v: &T) -> Result<usize> {
// This uses a dynamically allocated buffer.
//
// I couldn't get a no_std version to compile with a stack-allocated
// buffer as [0u8; size_of::<T>()] due to compiler errors like:
// ```
// error[E0401]: can't use type parameters from outer function; try using a local type parameter instead
// --> src/typed.rs:46:39
// |
// 46 | const _sbl: usize = size_of::<T>();
// | ^ use of type variable from outer function
// ```
// I think this may require const generics
// (rust-lang tracking issue:
// https://github.com/rust-lang/rust/issues/44580).
let mut ser_buf = vec![0u8; size_of::<T>()];
let ser_len = ssmarshal::serialize(&mut ser_buf, v)?;
let ser = &ser_buf[0..ser_len];
bytes::encode_to_writer(&ser, &mut self.w)
}
/// Encode the supplied payload as a frame, write it to the
/// inner writer, then flush.
///
/// Ensures the data has been transmitted before returning to the
/// caller.
///
/// See also: [`queue`](#method.queue)
pub fn send(&mut self, v: &T) -> Result<usize> {
let len = self.queue(v)?;
self.flush()?;
Ok(len)
}
}
/// Receives encoded structs of type `T` from an inner `std::io::Read` instance.
///
/// ## Examples
///
/// See the [std usage example][ex] in the `typed` module documentation.
/// [ex]: index.html#example-usage-from-a-std-crate
#[cfg(feature = "use_std")]
pub struct Receiver<R: Read, T: DeserializeOwned> {
r: R,
_t: PhantomData<T>,
}
#[cfg(feature = "use_std")]
impl<R: Read, T: DeserializeOwned> Receiver<R, T> {
/// Construct a `Receiver` that receives encoded structs from the supplied
/// `io::Read`.
pub fn new(r: R) -> Receiver<R, T> {
Receiver::<R, T> {
r: r,
_t: PhantomData::default(),
}
}
/// Consume this `Receiver` and return the inner `std::io::Read`.
pub fn into_inner(self) -> R {
self.r
}
/// Receive an encoded frame from the inner `std::io::Read`, decode it
/// and return the payload.
pub fn recv(&mut self) -> Result<T> {
let payload = bytes::decode_from_reader::<R>(&mut self.r)?;
let (v, _len) = ssmarshal::deserialize(&*payload)?;
Ok(v)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
struct Test {
i8: i8,
i16: i16,
i32: i32,
i64: i64,
u8: u8,
u16: u16,
u32: u32,
u64: u64,
some: Option<u8>,
none: Option<u8>,
a: [u8; 3],
}
fn test_val() -> Test {
let v = Test {
i8: 1,
i16: 2,
i32: 3,
i64: 4,
u8: 10,
u16: 11,
u32: 12,
u64: 13,
some: Some(17),
none: None,
a: [1, 2, 3],
};
#[cfg(feature = "use_std")] {
println!("Test value: {:#?}", v);
}
v
}
mod slice_tests {
use super::*;
#[test]
#[cfg(feature = "use_nightly")]
fn roundtrip() {
let input = test_val();
let mut ser_buf = [0u8; max_serialize_buf_len::<Test>()];
let mut enc_buf = [0u8; max_encoded_len::<Test>()];
let len = super::encode_to_slice(
&input, &mut ser_buf, &mut enc_buf
).unwrap();
let enc = &enc_buf[0..len];
let output = super::decode_from_slice(&enc, &mut ser_buf).unwrap();
assert_eq!(input, output);
}
#[test]
#[should_panic]
fn bad_ser_buf_len() {
let mut ser_buf = [0u8; 1];
let mut enc = [0u8; 100];
super::encode_to_slice(
&test_val(), &mut ser_buf, &mut enc
).unwrap();
}
#[test]
#[should_panic]
fn bad_dest_len() {
let mut ser_buf = [0u8; 100];
let mut enc = [0u8; 1];
super::encode_to_slice(
&test_val(), &mut ser_buf, &mut enc
).unwrap();
}
}
mod len_tests {
use super::*;
#[test]
fn serialize_buf_len() {
assert_eq!(max_serialize_buf_len::<Test>(), 42);
assert_eq!(max_serialize_buf_len::<u8>(), 3);
assert_eq!(max_serialize_buf_len::<u16>(), 4);
assert_eq!(max_serialize_buf_len::<u32>(), 6);
assert_eq!(max_serialize_buf_len::<u64>(), 10);
}
#[test]
fn encoded_len() {
assert_eq!(max_encoded_len::<Test>(), 44);
assert_eq!(max_encoded_len::<u8>(), 5);
}
}
#[cfg(feature = "use_std")]
mod rw_tests {
use channel::Channel;
use error::Error;
use std::io::{Read, Write};
use super::*;
#[test]
fn one() {
let (mut tx, mut rx) = pair();
let v = test_val();
tx.send(&v).unwrap();
let r = rx.recv().unwrap();
println!("r: {:#?}", r);
assert_eq!(v, r);
}
#[test]
fn empty_input() {
let (mut _tx, mut rx) = pair();
match rx.recv() {
Err(Error::EofBeforeFrame) => (),
e @ _ => panic!("Bad value: {:?}", e)
}
}
fn pair() -> (Sender<Box<Write>, Test>, Receiver<Box<Read>, Test>) {
let c = Channel::new();
let tx = Sender::new(Box::new(c.writer()) as Box<Write>);
let rx = Receiver::new(Box::new(c.reader()) as Box<Read>);
(tx, rx)
}
}
}