use ::{Payload, Encoded, FRAME_END_SYMBOL};
#[cfg(feature = "use_std")]
use ::{BoxPayload, BoxEncoded};
use ::checksum::MAX_CHECKSUM_LEN;
use ::error::{Error, Result};
use ::typed;
use cobs;
use serde::Serialize;
use serde::de::DeserializeOwned;
#[cfg(feature = "use_std")]
use ref_slice::ref_slice_mut;
#[cfg(feature = "use_std")]
use std::io::{self, Read, Write};
pub use ::checksum::Checksum;
pub struct Codec {
config: Config
}
#[derive(Clone, Debug, Default)]
pub struct Config {
checksum: Checksum,
}
impl Config {
pub fn to_codec(&mut self) -> Codec {
Codec {
config: self.clone(),
}
}
#[cfg(feature = "use_std")]
pub fn to_receiver<R: Read>(&mut self, r: R) -> Receiver<R> {
Receiver::<R> {
codec: self.to_codec(),
r: r,
}
}
#[cfg(feature = "use_std")]
pub fn to_sender<W: Write>(&mut self, w: W) -> Sender<W> {
Sender::<W> {
codec: self.to_codec(),
w: w,
}
}
pub fn typed<T: DeserializeOwned + Serialize>(&mut self) -> typed::Config<T> {
typed::Config::<T>::new(self)
}
pub fn checksum(&self) -> &Checksum {
&self.checksum
}
pub fn set_checksum(&mut self, checksum: Checksum) -> &mut Self {
self.checksum = checksum;
self
}
}
const MAX_FRAMING_LEN: usize = MAX_CHECKSUM_LEN + 1;
impl Codec {
fn checksum(&self) -> &Checksum {
&self.config.checksum
}
fn min_frame_len(&self) -> usize {
0
+ self.checksum().len()
+ 1
}
pub fn encode_to_slice(&mut self, p: &Payload, dest: &mut Encoded)
-> Result<usize> {
assert!(max_encoded_len(p.len()) <= dest.len());
#[cfg(feature = "trace")] {
println!("framed::encode: Payload = {:?}", p);
}
let checksum_type = self.checksum();
let checksum_value = checksum_type.calculate(p);
let cobs_len = {
let mut cobs_enc = cobs::CobsEncoder::new(dest);
cobs_enc.push(p)
.map_err(|_| Error::CobsEncodeFailed)?;
if checksum_value.len() > 0 {
cobs_enc.push(&*checksum_value)
.map_err(|_| Error::CobsEncodeFailed)?;
}
let cobs_len = cobs_enc.finalize()
.map_err(|_| Error::CobsEncodeFailed)?;
cobs_len
};
dest[cobs_len] = FRAME_END_SYMBOL;
let len = cobs_len + 1;
#[cfg(feature = "trace")] {
println!("framed::encode: Frame = {:?}", &dest[0..len]);
}
Ok(len)
}
#[cfg(feature = "use_std")]
pub fn encode_to_box(&mut self, p: &Payload) -> Result<BoxEncoded> {
let mut buf = vec![0; max_encoded_len(p.len())];
let len = self.encode_to_slice(p, &mut *buf)?;
buf.truncate(len);
Ok(BoxEncoded::from(buf))
}
#[cfg(feature = "use_std")]
pub fn encode_to_writer<W: Write>(&mut self, p: &Payload, w: &mut W)
-> Result<usize> {
let b = self.encode_to_box(p)?;
w.write_all(&*b.0)?;
Ok(b.len())
}
pub fn decode_to_slice(&mut self, e: &Encoded, dest: &mut [u8])
-> Result<usize> {
#[cfg(feature = "trace")] {
println!("framed::decode: Encoded = {:?}", e);
}
if e.len() == 0 {
return Err(Error::EofBeforeFrame);
}
if e.len() < self.min_frame_len() {
return Err(Error::EofDuringFrame);
}
if e[e.len()-1] != FRAME_END_SYMBOL {
return Err(Error::EofDuringFrame)
}
assert!(dest.len() >= max_decoded_len(e.len()));
assert_eq!(e[e.len() - 1], FRAME_END_SYMBOL);
let cobs_payload = &e[0..e.len() - 1];
let cobs_decoded_len =
if cobs_payload.len() == 0 {
0
} else {
cobs::decode(cobs_payload, dest)
.map_err(|_| Error::CobsDecodeFailed)?
};
let cobs_decoded = &dest[0..cobs_decoded_len];
if cobs_decoded_len < self.checksum().len() {
return Err(Error::EofDuringFrame);
}
let payload = &cobs_decoded[0..cobs_decoded_len - self.checksum().len()];
#[cfg(feature = "trace")] {
println!("framed::decode: cobs_decoded = {:?}",
cobs_decoded);
println!("framed::decode: payload = {:?}",
payload);
}
let checksum = self.checksum();
let calc_checksum = checksum.calculate(payload);
let recv_checksum = &cobs_decoded[payload.len() .. payload.len() + checksum.len()];
#[cfg(feature = "trace")] {
println!("framed::decode: calc_checksum = {:?}\n\
framed::decode: recv_checksum = {:?}",
calc_checksum, recv_checksum);
}
if &*calc_checksum != recv_checksum {
return Err(Error::ChecksumError);
}
Ok(payload.len())
}
#[cfg(feature = "use_std")]
pub fn decode_to_box(&mut self, e: &Encoded) -> Result<BoxPayload> {
if e.len() == 0 {
return Err(Error::EofBeforeFrame);
}
let mut buf = vec![0; max_decoded_len(e.len())];
let len = self.decode_to_slice(e, &mut buf)?;
buf.truncate(len);
Ok(BoxPayload::from(buf))
}
#[cfg(feature = "use_std")]
pub fn decode_from_reader<R: Read>(&mut self, r: &mut Read)
-> Result<BoxPayload> {
let mut next_frame = Vec::new();
let mut b = 0u8;
loop {
let res = r.read(ref_slice_mut(&mut b));
#[cfg(feature = "trace")] {
println!("framed: Read result = {:?}", res);
}
match res {
Err(ref e) if e.kind() == io::ErrorKind::UnexpectedEof =>
return self.decode_to_box(&*next_frame),
Ok(0) =>
return self.decode_to_box(&*next_frame),
Err(e) => return Err(Error::from(e)),
Ok(1) => (),
Ok(_) => unreachable!(),
};
#[cfg(feature = "trace")] {
println!("framed: Read byte = {}", b);
}
next_frame.push(b);
if b == FRAME_END_SYMBOL {
break;
}
}
assert_eq!(next_frame[next_frame.len()-1], FRAME_END_SYMBOL);
self.decode_to_box(&*next_frame)
}
}
const_fn! {
pub fn max_decoded_len(code_len: usize) -> usize {
code_len
}
}
const_fn! {
pub fn max_encoded_len(payload_len: usize) -> usize {
MAX_FRAMING_LEN
+ cobs_max_encoded_len(payload_len)
}
}
const_fn! {
fn cobs_max_encoded_len(payload_len: usize) -> usize {
payload_len
+ (payload_len / 254)
+ 1
}
}
#[cfg(feature = "use_std")]
pub struct Sender<W: Write> {
codec: Codec,
w: W,
}
#[cfg(feature = "use_std")]
impl<W: Write> Sender<W> {
pub fn into_inner(self) -> W {
self.w
}
pub fn flush(&mut self) -> Result<()> {
Ok(self.w.flush()?)
}
pub fn queue(&mut self, p: &Payload) -> Result<usize> {
self.codec.encode_to_writer(p, &mut self.w)
}
pub fn send(&mut self, p: &Payload) -> Result<usize> {
let len = self.queue(p)?;
self.flush()?;
Ok(len)
}
}
#[cfg(feature = "use_std")]
pub struct Receiver<R: Read> {
codec: Codec,
r: R,
}
#[cfg(feature = "use_std")]
impl<R: Read> Receiver<R> {
pub fn into_inner(self) -> R {
self.r
}
pub fn recv(&mut self) -> Result<BoxPayload> {
self.codec.decode_from_reader::<R>(&mut self.r)
}
}
#[cfg(test)]
mod tests {
#[cfg(feature = "use_std")]
use std::io::Cursor;
use super::*;
#[test]
fn max_encoded_len_ok() {
assert_eq!(max_encoded_len(0) , 4);
assert_eq!(max_encoded_len(1) , 5);
assert_eq!(max_encoded_len(2) , 6);
assert_eq!(max_encoded_len(254), 259);
assert_eq!(max_encoded_len(255), 260);
}
#[test]
fn max_decoded_len_ok() {
assert_eq!(max_decoded_len(0) , 0);
assert_eq!(max_decoded_len(1) , 1);
assert_eq!(max_decoded_len(2) , 2);
assert_eq!(max_decoded_len(3) , 3);
assert_eq!(max_decoded_len(255), 255);
}
fn codec() -> Codec {
Config::default().to_codec()
}
const PAYLOAD: [u8; PAYLOAD_LEN] = [0, 1, 2, 3];
const PAYLOAD_LEN: usize = 4;
const ENCODED_LEN: usize = 9;
fn encoded_payload(buf: &mut [u8; ENCODED_LEN]) -> &[u8] {
let len = codec().encode_to_slice(&PAYLOAD, buf).unwrap();
&buf[0..len]
}
fn assert_payload_eq(encoded: &Encoded, payload: &Payload) {
#[cfg(feature = "use_std")] {
println!("assert_payload_eq \n\
- encoded = {:?}\n\
- payload = {:?}",
encoded, payload);
}
let mut decoded_buf = [0; 100];
let len = codec().decode_to_slice(encoded, &mut decoded_buf).unwrap();
let decoded = &decoded_buf[0..len];
assert_eq!(decoded, payload);
}
#[test]
#[should_panic]
fn encode_to_slice_dest_too_small() {
let mut encoded_buf = [0u8; PAYLOAD_LEN];;
let _ = codec().encode_to_slice(&PAYLOAD, &mut encoded_buf);
}
#[test]
#[cfg(feature = "use_std")]
fn encode_to_slice_ok_dynamic_dest() {
let mut encoded_buf = vec![0u8; max_encoded_len(PAYLOAD.len())];
let len = codec().encode_to_slice(&PAYLOAD, &mut *encoded_buf).unwrap();
let encoded = &encoded_buf[0..len];
assert_payload_eq(encoded, &PAYLOAD);
}
#[test]
#[cfg(feature = "use_nightly")]
fn encode_to_slice_ok_static_dest() {
let mut encoded_buf = [0u8; max_encoded_len(PAYLOAD_LEN)];
let len = codec().encode_to_slice(&PAYLOAD, &mut encoded_buf).unwrap();
let encoded = &encoded_buf[0..len];
assert_payload_eq(encoded, &PAYLOAD);
}
#[test]
#[cfg(feature = "use_std")]
fn encode_to_writer_ok() {
let mut encoded = vec![];
codec().encode_to_writer(&PAYLOAD, &mut encoded).unwrap();
assert_payload_eq(&*encoded, &PAYLOAD);
}
#[test]
#[should_panic]
fn decode_to_slice_dest_too_small() {
let mut buf = [0; ENCODED_LEN];
let encoded = encoded_payload(&mut buf);
let mut decoded_buf = [0u8; PAYLOAD_LEN - 1];
let _ = codec().decode_to_slice(&*encoded, &mut decoded_buf);
}
#[test]
#[cfg(feature = "use_std")]
fn decode_to_slice_ok_dynamic_dest() {
let encoded = codec().encode_to_box(&PAYLOAD).unwrap();
let mut decoded_buf = vec![0u8; max_decoded_len(encoded.len())];
let len = codec().decode_to_slice(&*encoded, &mut decoded_buf).unwrap();
let decoded = &decoded_buf[0..len];
assert_eq!(&PAYLOAD, decoded);
}
#[test]
#[cfg(feature = "use_std")]
fn decode_to_slice_no_end_symbol() {
let encoded = vec![FRAME_END_SYMBOL + 1; max_encoded_len(0)];
let mut decoded_buf = [];
let res = codec().decode_to_slice(&*encoded, &mut decoded_buf);
match res {
Err(Error::EofDuringFrame) => (),
_ => panic!("Bad output: {:?}", res),
}
}
#[test]
#[cfg(feature = "use_std")]
fn decode_to_slice_encoded_too_short() {
let mut c = codec();
let encoded = vec![FRAME_END_SYMBOL; c.min_frame_len() - 1];
let mut decoded_buf = [];
let res = c.decode_to_slice(&*encoded, &mut decoded_buf);
match res {
Err(Error::EofDuringFrame) => (),
_ => panic!("Bad output: {:?}", res),
}
}
#[test]
#[cfg(feature = "use_std")]
fn decode_to_slice_encoded_empty() {
let encoded = vec![];
let mut decoded_buf = [];
let res = codec().decode_to_slice(&*encoded, &mut decoded_buf);
match res {
Err(Error::EofBeforeFrame) => (),
_ => panic!("Bad output: {:?}", res),
}
}
#[test]
#[cfg(feature = "use_std")]
fn decode_to_slice_bad_checksum() {
let mut c = codec();
let encoded = c.encode_to_box(&PAYLOAD).unwrap();
let mut encoded = Vec::from(&*encoded);
let checksum_offset = encoded.len() - c.checksum().len() - 1;
{
let checksum =
&mut encoded[checksum_offset..
(checksum_offset + c.config.checksum.len())];
checksum[0] = checksum[0].wrapping_add(1);
checksum[1] = checksum[1].wrapping_add(2);
}
let mut decoded_buf = vec![0u8; max_decoded_len(encoded.len())];
let res = codec().decode_to_slice(&*encoded, &mut decoded_buf);
match res {
Err(Error::ChecksumError) => (),
_ => panic!("Bad output: {:?}", res),
}
}
#[test]
#[cfg(feature = "use_std")]
fn decode_to_slice_missing_bytes() {
let encoded = codec().encode_to_box(&PAYLOAD).unwrap();
let encoded = &encoded[1..encoded.len()];
let mut decoded_buf = vec![0u8; max_decoded_len(encoded.len())];
let res = codec().decode_to_slice(&*encoded, &mut decoded_buf);
match res {
Err(Error::ChecksumError) => (),
_ => panic!("Bad output: {:?}", res),
}
}
#[test]
#[cfg(feature = "use_std")]
fn decode_to_box_ok() {
let encoded = codec().encode_to_box(&PAYLOAD).unwrap();
let decoded = codec().decode_to_box(&*encoded).unwrap();
assert_eq!(&PAYLOAD, &*decoded);
}
#[test]
#[cfg(feature = "use_std")]
fn decode_from_reader_ok() {
let mut c = codec();
let encoded = c.encode_to_box(&PAYLOAD).unwrap();
let mut reader = Cursor::new(&*encoded);
let decoded = c.decode_from_reader::<Cursor<&[u8]>>(&mut reader).unwrap();
assert_eq!(&*decoded, &PAYLOAD);
}
#[test]
#[cfg(feature = "use_std")]
fn roundtrip_default_config() {
roundtrip_case(&mut Config::default()
.to_codec(),
&PAYLOAD)
}
#[test]
#[cfg(feature = "use_std")]
fn roundtrip_no_checksum() {
roundtrip_case(&mut Config::default()
.set_checksum(Checksum::None)
.to_codec(),
&PAYLOAD)
}
#[test]
#[cfg(feature = "use_std")]
fn roundtrip_empty_payload() {
roundtrip_case(&mut Config::default()
.to_codec(),
&[])
}
#[cfg(feature = "use_std")]
fn roundtrip_case(c: &mut Codec, payload: &Payload) {
let encoded = c.encode_to_box(payload);
println!("encoded: {:?}", encoded);
let encoded = encoded.unwrap();
let decoded = c.decode_to_box(&*encoded);
println!("decoded: {:?}", decoded);
let decoded = decoded.unwrap();
assert_eq!(&*decoded, payload);
}
}
#[cfg(all(test, feature = "use_std"))]
mod rw_tests {
use channel::Channel;
use error::Error;
use std::io::{Read, Write};
use super::*;
#[test]
fn one_frame() {
let (mut tx, mut rx) = pair();
let p = [0x00, 0x01, 0x02];
tx.send(&p).unwrap();
let recvd = rx.recv().unwrap();
assert_eq!(*recvd, p);
}
#[test]
fn two_frames_sequentially() {
let (mut tx, mut rx) = pair();
{
let sent = [0x00, 0x01, 0x02];
tx.send(&sent).unwrap();
let recvd = rx.recv().unwrap();
assert_eq!(*recvd, sent);
}
{
let sent = [0x10, 0x11, 0x12];
tx.send(&sent).unwrap();
let recvd = rx.recv().unwrap();
assert_eq!(*recvd, sent);
}
}
#[test]
fn two_frames_at_once() {
let (mut tx, mut rx) = pair();
let s1 = [0x00, 0x01, 0x02];
let s2 = [0x10, 0x11, 0x12];
tx.send(&s1).unwrap();
tx.send(&s2).unwrap();
let r1 = rx.recv().unwrap();
let r2 = rx.recv().unwrap();
println!("r1: {:?}\n\
r2: {:?}", r1, r2);
assert_eq!(*r1, s1);
assert_eq!(*r2, s2);
}
#[test]
fn empty_input() {
let (mut _tx, mut rx) = pair();
match rx.recv() {
Err(Error::EofBeforeFrame) => (),
e @ _ => panic!("Bad value: {:?}", e)
}
}
#[test]
fn partial_input() {
let chan = Channel::new();
let mut rx = config().to_receiver(chan.reader());
let mut tx_raw = chan.writer();
tx_raw.write(&[0x01]).unwrap();
match rx.recv() {
Err(Error::EofDuringFrame) => (),
e @ _ => panic!("Bad value: {:?}", e)
}
}
fn config() -> Config {
Config::default()
}
fn pair() -> (Sender<Box<Write>>, Receiver<Box<Read>>) {
let chan = Channel::new();
let c = config();
let tx = c.clone().to_sender(Box::new(chan.writer()) as Box<Write>);
let rx = c.clone().to_receiver(Box::new(chan.reader()) as Box<Read>);
(tx, rx)
}
}