Implement framed::typed::decode_from_slice() and a round trip test.
This commit is contained in:
parent
b5cdc7b86f
commit
26ed183b29
1 changed files with 43 additions and 29 deletions
|
@ -8,6 +8,8 @@
|
||||||
//! length types (arrays, maps). Its lack of stability fits with the
|
//! length types (arrays, maps). Its lack of stability fits with the
|
||||||
//! frame encoding in this crate: unsuitable for long-term storage or
|
//! frame encoding in this crate: unsuitable for long-term storage or
|
||||||
//! transmission between different versions of an application.
|
//! transmission between different versions of an application.
|
||||||
|
//!
|
||||||
|
//! TODO: Usage examples.
|
||||||
|
|
||||||
use ::{Encoded, TempBuffer};
|
use ::{Encoded, TempBuffer};
|
||||||
use error::{Result};
|
use error::{Result};
|
||||||
|
@ -22,7 +24,16 @@ use core::mem::size_of;
|
||||||
/// Serializes and encodes the supplied value `v` into destination
|
/// Serializes and encodes the supplied value `v` into destination
|
||||||
/// buffer `dest`, using `ser_buf` as a temporary serialization buffer.
|
/// buffer `dest`, using `ser_buf` as a temporary serialization buffer.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// 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>()`. See the example.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// extern crate framed;
|
/// extern crate framed;
|
||||||
|
@ -31,7 +42,7 @@ use core::mem::size_of;
|
||||||
/// #[macro_use]
|
/// #[macro_use]
|
||||||
/// extern crate serde_derive;
|
/// extern crate serde_derive;
|
||||||
///
|
///
|
||||||
/// #[derive(Serialize)]
|
/// #[derive(Deserialize, Serialize)]
|
||||||
/// struct Test {
|
/// struct Test {
|
||||||
/// a: u8,
|
/// a: u8,
|
||||||
/// b: u16,
|
/// b: u16,
|
||||||
|
@ -39,16 +50,19 @@ use core::mem::size_of;
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let mut ser_buf = [0u8; max_serialize_buf_len::<Test>()];
|
/// let mut ser_buf = [0u8; max_serialize_buf_len::<Test>()];
|
||||||
/// let mut encoded = [0u8; max_encoded_len::<Test>()];
|
/// let mut encoded_buf = [0u8; max_encoded_len::<Test>()];
|
||||||
/// encode_to_slice::<Test>(
|
/// let encoded_len = encode_to_slice::<Test>(
|
||||||
/// &Test { a: 1, b: 2 },
|
/// &Test { a: 1, b: 2 },
|
||||||
/// &mut ser_buf,
|
/// &mut ser_buf,
|
||||||
/// &mut encoded
|
/// &mut encoded_buf
|
||||||
/// ).expect("encode ok");
|
/// ).expect("encode ok");
|
||||||
|
///
|
||||||
|
/// let encoded = &encoded_buf[0..encoded_len];
|
||||||
|
/// // `encoded` now contains the complete encoded frame.
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
pub fn encode_to_slice<T: Serialize>(
|
pub fn encode_to_slice<T: DeserializeOwned + Serialize>(
|
||||||
v: &T,
|
v: &T,
|
||||||
ser_buf: &mut TempBuffer,
|
ser_buf: &mut TempBuffer,
|
||||||
dest: &mut Encoded,
|
dest: &mut Encoded,
|
||||||
|
@ -58,21 +72,34 @@ pub fn encode_to_slice<T: Serialize>(
|
||||||
|
|
||||||
let ser_len = ssmarshal::serialize(ser_buf, v)?;
|
let ser_len = ssmarshal::serialize(ser_buf, v)?;
|
||||||
let ser = &ser_buf[0..ser_len];
|
let ser = &ser_buf[0..ser_len];
|
||||||
super::encode_to_slice(ser, dest)
|
::encode_to_slice(ser, dest)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// TODO.
|
||||||
|
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 = ::decode_to_slice(e, de_buf)?;
|
||||||
|
let payload = &de_buf[0..de_len];
|
||||||
|
let (v, _len) = ssmarshal::deserialize(payload)?;
|
||||||
|
Ok(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an upper bound for the encoded length of a frame with a
|
/// Returns an upper bound for the encoded length of a frame with a
|
||||||
/// serialized `T` value as its payload.
|
/// serialized `T` value as its payload.
|
||||||
///
|
///
|
||||||
/// Useful for calculating an appropriate buffer length.
|
/// Useful for calculating an appropriate buffer length.
|
||||||
pub const fn max_encoded_len<T: Serialize>() -> usize {
|
pub const fn max_encoded_len<T: DeserializeOwned + Serialize>() -> usize {
|
||||||
super::max_encoded_len(max_serialize_buf_len::<T>())
|
super::max_encoded_len(max_serialize_buf_len::<T>())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an upper bound for the temporary serialization buffer
|
/// Returns an upper bound for the temporary serialization buffer
|
||||||
/// length needed by `encode_to_slice` when serializing a
|
/// length needed by `encode_to_slice` and `decode_from_slice` when
|
||||||
/// value of type `T`.
|
/// serializing or deserializing a value of type `T`.
|
||||||
pub const fn max_serialize_buf_len<T: Serialize>() -> usize {
|
pub const fn max_serialize_buf_len<T: DeserializeOwned + Serialize>() -> usize {
|
||||||
size_of::<T>()
|
size_of::<T>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,8 +141,6 @@ impl<W: Write, T: Serialize> Sender<W, T> {
|
||||||
///
|
///
|
||||||
/// See also: [`send`](#method.send)
|
/// See also: [`send`](#method.send)
|
||||||
pub fn queue(&mut self, v: &T) -> Result<usize> {
|
pub fn queue(&mut self, v: &T) -> Result<usize> {
|
||||||
// TODO: Re-use encode_to_slice
|
|
||||||
|
|
||||||
// This uses a dynamically allocated buffer.
|
// This uses a dynamically allocated buffer.
|
||||||
//
|
//
|
||||||
// I couldn't get a no_std version to compile with a stack-allocated
|
// I couldn't get a no_std version to compile with a stack-allocated
|
||||||
|
@ -130,22 +155,10 @@ impl<W: Write, T: Serialize> Sender<W, T> {
|
||||||
// I think this may require const generics
|
// I think this may require const generics
|
||||||
// (rust-lang tracking issue:
|
// (rust-lang tracking issue:
|
||||||
// https://github.com/rust-lang/rust/issues/44580).
|
// https://github.com/rust-lang/rust/issues/44580).
|
||||||
//
|
|
||||||
// When I need to write a no_std version I see a few easy options:
|
|
||||||
// 1. Caller supplies a reference to a buffer, we can assert! that
|
|
||||||
// it's long enough. Annoying to use.
|
|
||||||
// 2. Choose a reasonable length buffer and assert it's long enough.
|
|
||||||
// Won't work for large enough structs, may consume an inappropriate
|
|
||||||
// amount of memory for embedded use.
|
|
||||||
// 3. Provide overloads for 1 and 2. For most cases the fixed size
|
|
||||||
// buffer will be fine, and if not you can provide your own.
|
|
||||||
let mut ser_buf = vec![0u8; size_of::<T>()];
|
let mut ser_buf = vec![0u8; size_of::<T>()];
|
||||||
|
|
||||||
let ser_len = ssmarshal::serialize(&mut ser_buf, v)?;
|
let ser_len = ssmarshal::serialize(&mut ser_buf, v)?;
|
||||||
let ser = &ser_buf[0..ser_len];
|
let ser = &ser_buf[0..ser_len];
|
||||||
#[cfg(feature = "trace")] {
|
|
||||||
println!("framed: Serialized = {:?}", ser);
|
|
||||||
}
|
|
||||||
::encode_to_writer(&ser, &mut self.w)
|
::encode_to_writer(&ser, &mut self.w)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,16 +255,17 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn first() {
|
fn roundtrip() {
|
||||||
|
let input = test_val();
|
||||||
let mut ser_buf = [0u8; 100];
|
let mut ser_buf = [0u8; 100];
|
||||||
let mut enc_buf = [0u8; 100];
|
let mut enc_buf = [0u8; 100];
|
||||||
let len = super::encode_to_slice(
|
let len = super::encode_to_slice(
|
||||||
&test_val(), &mut ser_buf, &mut enc
|
&input, &mut ser_buf, &mut enc_buf
|
||||||
).unwrap();
|
).unwrap();
|
||||||
let enc = &enc_buf[0..len];
|
let enc = &enc_buf[0..len];
|
||||||
|
|
||||||
super::decode_from_slice(&enc
|
let output = super::decode_from_slice(&enc, &mut ser_buf).unwrap();
|
||||||
// TODO: Deserialize the test value.
|
assert_eq!(input, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Reference in a new issue