From 13d53fec92fddae9c312d323db81bbcb97adbe21 Mon Sep 17 00:00:00 2001 From: Stuart Stock Date: Sat, 17 Jun 2017 15:17:37 -0500 Subject: restructuring as a proper crate --- src/error.rs | 15 ++++ src/lib.rs | 5 ++ src/main.rs | 268 --------------------------------------------------------- src/message.rs | 202 +++++++++++++++++++++++++++++++++++++++++++ src/tag.rs | 41 +++++++++ 5 files changed, 263 insertions(+), 268 deletions(-) create mode 100644 src/error.rs create mode 100644 src/lib.rs delete mode 100644 src/main.rs create mode 100644 src/message.rs create mode 100644 src/tag.rs diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..094171d --- /dev/null +++ b/src/error.rs @@ -0,0 +1,15 @@ +use std; + +use tag::Tag; + +#[derive(Debug)] +pub enum Error { + TagNotStrictlyIncreasing(Tag), + EncodingFailure(std::io::Error), +} + +impl From for Error { + fn from(err: std::io::Error) -> Self { + Error::EncodingFailure(err) + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..7f339c1 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,5 @@ +extern crate byteorder; + +pub mod error; +pub mod tag; +pub mod message; diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 32a65b7..0000000 --- a/src/main.rs +++ /dev/null @@ -1,268 +0,0 @@ -extern crate byteorder; - -use std::io::Write; -use byteorder::{LittleEndian, WriteBytesExt}; - -#[derive(Debug)] -pub enum RtError { - TagNotStrictlyIncreasing(RtTag), - EncodingFailure(std::io::Error), -} - -impl From for RtError { - fn from(err: std::io::Error) -> Self { - RtError::EncodingFailure(err) - } -} - -#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)] -pub enum RtTag { - CERT, - DELE, - INDX, - MAXT, - MIDP, - MINT, - NONC, - PAD, - PATH, - PUBK, - RADI, - ROOT, - SIG, - SREP, -} - -static PAD_VALUE: [u8; 4] = [b'P', b'A', b'D', 0x00]; -static SIG_VALUE: [u8; 4] = [b'S', b'I', b'G', 0xff]; - -impl RtTag { - pub fn wire_value(&self) -> &'static [u8] { - match *self { - RtTag::CERT => "CERT".as_bytes(), - RtTag::DELE => "DELE".as_bytes(), - RtTag::INDX => "INDX".as_bytes(), - RtTag::MAXT => "MAXT".as_bytes(), - RtTag::MIDP => "MIDP".as_bytes(), - RtTag::MINT => "MINT".as_bytes(), - RtTag::NONC => "NONC".as_bytes(), - RtTag::PAD => PAD_VALUE.as_ref(), - RtTag::PATH => "PATH".as_bytes(), - RtTag::PUBK => "PUBK".as_bytes(), - RtTag::RADI => "RADI".as_bytes(), - RtTag::ROOT => "ROOT".as_bytes(), - RtTag::SIG => SIG_VALUE.as_ref(), - RtTag::SREP => "SREP".as_bytes(), - } - } -} - -#[derive(Debug)] -pub struct RtMessage<'a> { - tags: Vec, - values: Vec<&'a [u8]>, -} - -impl<'a> RtMessage<'a> { - 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: RtTag, value: &'a [u8]) -> Result<(), RtError> { - if let Some(last_tag) = self.tags.last() { - if tag <= *last_tag { - return Err(RtError::TagNotStrictlyIncreasing(tag)); - } - } - - self.tags.push(tag); - self.values.push(value); - - Ok(()) - } - - pub fn num_fields(&self) -> u32 { - self.tags.len() as u32 - } - - pub fn encode(&self) -> Result, RtError> { - let num_tags = self.tags.len(); - let mut out = Vec::with_capacity(self.encoded_size()); - - // number of tags - out.write_u32::(num_tags as u32)?; - - // offset(s) to values, IFF there are two or more tags - if num_tags > 1 { - let mut offset_sum = self.values[0].len(); - - for val in &self.values[1..] { - out.write_u32::(offset_sum as u32)?; - offset_sum += val.len(); - } - } - - // write tags - for tag in &self.tags { - out.write_all(tag.wire_value())?; - } - - // write values - for value in &self.values { - out.write_all(value)?; - } - - // check we wrote exactly what we expected - assert!(out.len() == self.encoded_size(), "unexpected length"); - - Ok(out) - } - - 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(not(test))] -fn main() { - let mut msg = RtMessage::new(3); - - msg.add_field(RtTag::CERT, "abcd".as_bytes()).unwrap(); - msg.add_field(RtTag::NONC, "1234".as_bytes()).unwrap(); - - println!("msg {:?}", msg.encode()); -} - -#[cfg(test)] -mod test { - use std::io::{Cursor, Read}; - use byteorder::{LittleEndian, ReadBytesExt}; - use super::*; - - #[test] - fn empty_message_size() { - let msg = RtMessage::new(0); - - assert_eq!(msg.num_fields(), 0); - // Empty message is 4 bytes, a single num_tags value - assert_eq!(msg.encoded_size(), 4); - } - - #[test] - fn single_field_message_size() { - let mut msg = RtMessage::new(1); - msg.add_field(RtTag::NONC, "1234".as_bytes()).unwrap(); - - assert_eq!(msg.num_fields(), 1); - // Single tag message is 4 (num_tags) + 4 (NONC) + 4 (value) - assert_eq!(msg.encoded_size(), 12); - } - - #[test] - fn two_field_message_size() { - let mut msg = RtMessage::new(2); - msg.add_field(RtTag::NONC, "1234".as_bytes()).unwrap(); - msg.add_field(RtTag::PAD, "abcd".as_bytes()).unwrap(); - - assert_eq!(msg.num_fields(), 2); - // Two tag message - // 4 num_tags - // 8 (NONC, PAD) tags - // 4 PAD offset - // 8 values - 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::().unwrap(), 0); - } - - #[test] - fn single_field_message_encoding() { - let value = vec![b'a'; 64]; - let mut msg = RtMessage::new(1); - - msg.add_field(RtTag::CERT, &value).unwrap(); - - let mut encoded = Cursor::new(msg.encode().unwrap()); - - // num tags - assert_eq!(encoded.read_u32::().unwrap(), 1); - - // CERT tag - let mut cert = [0u8; 4]; - encoded.read_exact(&mut cert).unwrap(); - assert_eq!(cert, RtTag::CERT.wire_value()); - - // CERT value - let mut read_val = vec![0u8; 64]; - encoded.read_exact(&mut read_val).unwrap(); - assert_eq!(value, read_val); - - // Entire message was read - 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(RtTag::DELE, &dele_value).unwrap(); - msg.add_field(RtTag::MAXT, &maxt_value).unwrap(); - - let foo = msg.encode().unwrap(); - - let mut encoded = Cursor::new(msg.encode().unwrap()); - // Wire encoding - // 4 num_tags - // 8 (DELE, MAXT) tags - // 4 MAXT offset - // 24 DELE value - // 32 MAXT value - - // num tags - assert_eq!(encoded.read_u32::().unwrap(), 2); - - // Offset past DELE value to start of MAXT value - assert_eq!(encoded.read_u32::().unwrap(), dele_value.len() as u32); - - // DELE tag - let mut dele = [0u8; 4]; - encoded.read_exact(&mut dele).unwrap(); - assert_eq!(dele, RtTag::DELE.wire_value()); - - // MAXT tag - let mut maxt = [0u8; 4]; - encoded.read_exact(&mut maxt).unwrap(); - assert_eq!(maxt, RtTag::MAXT.wire_value()); - - // DELE value - let mut read_dele_val = vec![0u8; 24]; - encoded.read_exact(&mut read_dele_val).unwrap(); - assert_eq!(dele_value, read_dele_val); - - // MAXT value - let mut read_maxt_val = vec![0u8; 32]; - encoded.read_exact(&mut read_maxt_val).unwrap(); - assert_eq!(maxt_value, read_maxt_val); - - // Everything was read - assert_eq!(encoded.position() as usize, msg.encoded_size()); - } -} - - diff --git a/src/message.rs b/src/message.rs new file mode 100644 index 0000000..4e7e84b --- /dev/null +++ b/src/message.rs @@ -0,0 +1,202 @@ +use std::io::Write; +use byteorder::{LittleEndian, WriteBytesExt}; + +use tag::Tag; +use error::Error; + +#[derive(Debug)] +pub struct RtMessage<'a> { + tags: Vec, + values: Vec<&'a [u8]>, +} + +impl<'a> RtMessage<'a> { + 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: &'a [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); + + Ok(()) + } + + pub fn num_fields(&self) -> u32 { + self.tags.len() as u32 + } + + pub fn encode(&self) -> Result, Error> { + let num_tags = self.tags.len(); + let mut out = Vec::with_capacity(self.encoded_size()); + + // number of tags + out.write_u32::(num_tags as u32)?; + + // offset(s) to values, IFF there are two or more tags + if num_tags > 1 { + let mut offset_sum = self.values[0].len(); + + for val in &self.values[1..] { + out.write_u32::(offset_sum as u32)?; + offset_sum += val.len(); + } + } + + // write tags + for tag in &self.tags { + out.write_all(tag.wire_value())?; + } + + // write values + for value in &self.values { + out.write_all(value)?; + } + + // check we wrote exactly what we expected + assert!(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); + // Empty message is 4 bytes, a single num_tags value + 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); + // Single tag message is 4 (num_tags) + 4 (NONC) + 4 (value) + 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); + // Two tag message + // 4 num_tags + // 8 (NONC, PAD) tags + // 4 PAD offset + // 8 values + 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::().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()); + + // num tags + assert_eq!(encoded.read_u32::().unwrap(), 1); + + // CERT tag + let mut cert = [0u8; 4]; + encoded.read_exact(&mut cert).unwrap(); + assert_eq!(cert, Tag::CERT.wire_value()); + + // CERT value + let mut read_val = vec![0u8; 64]; + encoded.read_exact(&mut read_val).unwrap(); + assert_eq!(value, read_val); + + // Entire message was read + 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()); + // Wire encoding + // 4 num_tags + // 8 (DELE, MAXT) tags + // 4 MAXT offset + // 24 DELE value + // 32 MAXT value + + // num tags + assert_eq!(encoded.read_u32::().unwrap(), 2); + + // Offset past DELE value to start of MAXT value + assert_eq!(encoded.read_u32::().unwrap(), dele_value.len() as u32); + + // DELE tag + let mut dele = [0u8; 4]; + encoded.read_exact(&mut dele).unwrap(); + assert_eq!(dele, Tag::DELE.wire_value()); + + // MAXT tag + let mut maxt = [0u8; 4]; + encoded.read_exact(&mut maxt).unwrap(); + assert_eq!(maxt, Tag::MAXT.wire_value()); + + // DELE value + let mut read_dele_val = vec![0u8; 24]; + encoded.read_exact(&mut read_dele_val).unwrap(); + assert_eq!(dele_value, read_dele_val); + + // MAXT value + let mut read_maxt_val = vec![0u8; 32]; + encoded.read_exact(&mut read_maxt_val).unwrap(); + assert_eq!(maxt_value, read_maxt_val); + + // Everything was read + assert_eq!(encoded.position() as usize, msg.encoded_size()); + } +} diff --git a/src/tag.rs b/src/tag.rs new file mode 100644 index 0000000..168d81a --- /dev/null +++ b/src/tag.rs @@ -0,0 +1,41 @@ +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)] +pub enum Tag { + CERT, + DELE, + INDX, + MAXT, + MIDP, + MINT, + NONC, + PAD, + PATH, + PUBK, + RADI, + ROOT, + SIG, + SREP, +} + +static PAD_VALUE: [u8; 4] = [b'P', b'A', b'D', 0x00]; +static SIG_VALUE: [u8; 4] = [b'S', b'I', b'G', 0xff]; + +impl Tag { + pub fn wire_value(&self) -> &'static [u8] { + match *self { + Tag::CERT => "CERT".as_bytes(), + Tag::DELE => "DELE".as_bytes(), + Tag::INDX => "INDX".as_bytes(), + Tag::MAXT => "MAXT".as_bytes(), + Tag::MIDP => "MIDP".as_bytes(), + Tag::MINT => "MINT".as_bytes(), + Tag::NONC => "NONC".as_bytes(), + Tag::PAD => PAD_VALUE.as_ref(), + Tag::PATH => "PATH".as_bytes(), + Tag::PUBK => "PUBK".as_bytes(), + Tag::RADI => "RADI".as_bytes(), + Tag::ROOT => "ROOT".as_bytes(), + Tag::SIG => SIG_VALUE.as_ref(), + Tag::SREP => "SREP".as_bytes(), + } + } +} -- cgit v1.2.3