use std::io::Write;
use byteorder::{LittleEndian, WriteBytesExt};
use tag::Tag;
use error::Error;
#[derive(Debug)]
pub struct RtMessage {
tags: Vec<Tag>,
values: Vec<Vec<u8>>,
}
impl RtMessage {
pub fn new(num_fields: u8) -> Self {
RtMessage {
tags: Vec::with_capacity(num_fields as usize),
values: Vec::with_capacity(num_fields as usize),
}
}
pub fn add_field(&mut self, tag: Tag, value: &[u8]) -> Result<(), Error> {
if let Some(last_tag) = self.tags.last() {
if tag <= *last_tag {
return Err(Error::TagNotStrictlyIncreasing(tag));
}
}
self.tags.push(tag);
self.values.push(value.to_vec());
Ok(())
}
pub fn num_fields(&self) -> u32 {
self.tags.len() as u32
}
pub fn encode(&self) -> Result<Vec<u8>, Error> {
let num_tags = self.tags.len();
let mut out = Vec::with_capacity(self.encoded_size());
out.write_u32::<LittleEndian>(num_tags as u32)?;
if num_tags > 1 {
let mut offset_sum = self.values[0].len();
for val in &self.values[1..] {
out.write_u32::<LittleEndian>(offset_sum as u32)?;
offset_sum += val.len();
}
}
for tag in &self.tags {
out.write_all(tag.wire_value())?;
}
for value in &self.values {
out.write_all(value)?;
}
assert_eq!(out.len(), self.encoded_size(), "unexpected length");
Ok(out)
}
pub fn encoded_size(&self) -> usize {
let num_tags = self.tags.len();
let tags_size = 4 * num_tags;
let offsets_size = if num_tags < 2 { 0 } else { 4 * (num_tags - 1) };
let values_size: usize = self.values.iter().map(|v| v.len()).sum();
4 + tags_size + offsets_size + values_size
}
}
#[cfg(test)]
mod test {
use std::io::{Cursor, Read};
use byteorder::{LittleEndian, ReadBytesExt};
use message::*;
use tag::Tag;
#[test]
fn empty_message_size() {
let msg = RtMessage::new(0);
assert_eq!(msg.num_fields(), 0);
assert_eq!(msg.encoded_size(), 4);
}
#[test]
fn single_field_message_size() {
let mut msg = RtMessage::new(1);
msg.add_field(Tag::NONC, "1234".as_bytes()).unwrap();
assert_eq!(msg.num_fields(), 1);
assert_eq!(msg.encoded_size(), 12);
}
#[test]
fn two_field_message_size() {
let mut msg = RtMessage::new(2);
msg.add_field(Tag::NONC, "1234".as_bytes()).unwrap();
msg.add_field(Tag::PAD, "abcd".as_bytes()).unwrap();
assert_eq!(msg.num_fields(), 2);
assert_eq!(msg.encoded_size(), 24);
}
#[test]
fn empty_message_encoding() {
let msg = RtMessage::new(0);
let mut encoded = Cursor::new(msg.encode().unwrap());
assert_eq!(encoded.read_u32::<LittleEndian>().unwrap(), 0);
}
#[test]
fn single_field_message_encoding() {
let value = vec![b'a'; 64];
let mut msg = RtMessage::new(1);
msg.add_field(Tag::CERT, &value).unwrap();
let mut encoded = Cursor::new(msg.encode().unwrap());
assert_eq!(encoded.read_u32::<LittleEndian>().unwrap(), 1);
let mut cert = [0u8; 4];
encoded.read_exact(&mut cert).unwrap();
assert_eq!(cert, Tag::CERT.wire_value());
let mut read_val = vec![0u8; 64];
encoded.read_exact(&mut read_val).unwrap();
assert_eq!(value, read_val);
assert_eq!(encoded.position(), 72);
}
#[test]
fn two_field_message_encoding() {
let dele_value = vec![b'a'; 24];
let maxt_value = vec![b'z'; 32];
let mut msg = RtMessage::new(2);
msg.add_field(Tag::DELE, &dele_value).unwrap();
msg.add_field(Tag::MAXT, &maxt_value).unwrap();
let mut encoded = Cursor::new(msg.encode().unwrap());
assert_eq!(encoded.read_u32::<LittleEndian>().unwrap(), 2);
assert_eq!(encoded.read_u32::<LittleEndian>().unwrap(),
dele_value.len() as u32);
let mut dele = [0u8; 4];
encoded.read_exact(&mut dele).unwrap();
assert_eq!(dele, Tag::DELE.wire_value());
let mut maxt = [0u8; 4];
encoded.read_exact(&mut maxt).unwrap();
assert_eq!(maxt, Tag::MAXT.wire_value());
let mut read_dele_val = vec![0u8; 24];
encoded.read_exact(&mut read_dele_val).unwrap();
assert_eq!(dele_value, read_dele_val);
let mut read_maxt_val = vec![0u8; 32];
encoded.read_exact(&mut read_maxt_val).unwrap();
assert_eq!(maxt_value, read_maxt_val);
assert_eq!(encoded.position() as usize, msg.encoded_size());
}
}