use std::convert::TryInto;
const SIZE_BYTES: usize = 4;
pub trait FrameBuilderLike {
fn add_data(&mut self, tag: u16, value: &[u8]);
fn add_frame(&mut self, tag: u16) -> PacketFrameBuilder<'_>;
fn add_bool(&mut self, tag: u16, value: bool) {
self.add_u8(tag, if value { 0xFF } else { 0x00 })
}
fn add_u8(&mut self, tag: u16, value: u8) {
self.add_data(tag, &value.to_be_bytes())
}
fn add_u16(&mut self, tag: u16, value: u16) {
self.add_data(tag, &value.to_be_bytes())
}
fn add_u32(&mut self, tag: u16, value: u32) {
self.add_data(tag, &value.to_be_bytes())
}
fn add_u64(&mut self, tag: u16, value: u64) {
self.add_data(tag, &value.to_be_bytes())
}
fn add_str<S>(&mut self, tag: u16, value: S)
where
S: AsRef<str>,
{
self.add_data(tag, value.as_ref().as_bytes())
}
#[cfg(feature = "uuid")]
fn add_uuid(&mut self, tag: u16, value: &uuid::Uuid) {
self.add_data(tag, value.as_bytes())
}
}
pub struct FrameBuilder<'a> {
field_count: u32,
field_start: usize,
data: &'a mut Vec<u8>,
}
impl<'a> Drop for FrameBuilder<'a> {
fn drop(&mut self) {
let field_count_pos = self.field_start + 1;
self.data[field_count_pos..field_count_pos + SIZE_BYTES]
.copy_from_slice(&self.field_count.to_be_bytes())
}
}
impl<'a> FrameBuilder<'a> {
pub fn new(data: &mut Vec<u8>) -> FrameBuilder<'_> {
let field_start = data.len();
data.extend_from_slice(&[1, 0, 0, 0, 0]);
FrameBuilder {
field_count: 0,
field_start,
data,
}
}
}
impl<'a> FrameBuilderLike for FrameBuilder<'a> {
fn add_data(&mut self, tag: u16, value: &[u8]) {
self.field_count += 1;
self.data.reserve(6 + value.len());
self.data.extend_from_slice(&tag.to_be_bytes());
self.data
.extend_from_slice(&(value.len() as u32).to_be_bytes());
self.data.extend_from_slice(value);
}
fn add_frame(&mut self, tag: u16) -> PacketFrameBuilder<'_> {
self.field_count += 1;
self.data.reserve(6);
self.data.extend_from_slice(&tag.to_be_bytes());
PacketFrameBuilder::new(self.data)
}
}
pub struct PacketFrameBuilder<'a> {
field_count: u32,
packet_start: usize,
data: &'a mut Vec<u8>,
}
impl<'a> Drop for PacketFrameBuilder<'a> {
fn drop(&mut self) {
let packet_length = (self.data.len() - self.packet_start - SIZE_BYTES) as u32;
self.data[self.packet_start..self.packet_start + SIZE_BYTES]
.copy_from_slice(&packet_length.to_be_bytes());
let field_count_pos = self.packet_start + 5;
self.data[field_count_pos..field_count_pos + SIZE_BYTES]
.copy_from_slice(&self.field_count.to_be_bytes())
}
}
impl<'a> PacketFrameBuilder<'a> {
pub fn new(data: &mut Vec<u8>) -> PacketFrameBuilder<'_> {
let packet_start = data.len();
data.extend_from_slice(&[0, 0, 0, 0, 1, 0, 0, 0, 0]);
PacketFrameBuilder {
field_count: 0,
packet_start,
data,
}
}
}
impl<'a> FrameBuilderLike for PacketFrameBuilder<'a> {
fn add_data(&mut self, tag: u16, value: &[u8]) {
self.field_count += 1;
self.data.reserve(6 + value.len());
self.data.extend_from_slice(&tag.to_be_bytes());
self.data
.extend_from_slice(&(value.len() as u32).to_be_bytes());
self.data.extend_from_slice(value);
}
fn add_frame(&mut self, tag: u16) -> PacketFrameBuilder<'_> {
self.field_count += 1;
self.data.reserve(6);
self.data.extend_from_slice(&tag.to_be_bytes());
PacketFrameBuilder::new(self.data)
}
}
#[derive(Debug, Eq, PartialEq)]
pub enum Error {
IncompleteFrameFormat,
InvalidFrameFormat(u32),
IncompleteFrameFieldCount,
IncompleteFieldTagOrLength,
IncompleteFieldValue(usize, usize),
IncompatibleFieldLength(usize),
IncompatibleFieldValue,
UnexpectedData,
MissingRequiredField(u16),
}
pub type Result<T> = std::result::Result<T, Error>;
struct FrameParserField<'a> {
tag: u16,
value: &'a [u8],
}
pub struct FrameParser<'a> {
fields: Vec<FrameParserField<'a>>,
}
enum FrameFormat {
Format1,
}
fn read_frame_format(data: &[u8]) -> Result<(FrameFormat, &[u8])> {
if !data.is_empty() {
let (field_count_bytes, tail) = data.split_at(1);
let raw_format = field_count_bytes[0];
let format = match raw_format {
0x01 => Ok(FrameFormat::Format1),
_ => Err(Error::InvalidFrameFormat(raw_format as u32)),
}?;
Ok((format, tail))
} else {
Err(Error::IncompleteFrameFormat)
}
}
fn read_frame_field_count(data: &[u8]) -> Result<(u32, &[u8])> {
if data.len() >= 4 {
let (field_count_bytes, tail) = data.split_at(4);
let field_count = u32::from_be_bytes(field_count_bytes.try_into().unwrap());
Ok((field_count, tail))
} else {
Err(Error::IncompleteFrameFieldCount)
}
}
fn read_field_tag_and_length(data: &[u8]) -> Result<(u16, usize, &[u8])> {
if data.len() >= 6 {
let (tag_bytes, tail) = data.split_at(2);
let tag = u16::from_be_bytes(tag_bytes.try_into().unwrap());
let (length_bytes, tail) = tail.split_at(4);
let length = u32::from_be_bytes(length_bytes.try_into().unwrap()) as usize;
Ok((tag, length, tail))
} else {
Err(Error::IncompleteFieldTagOrLength)
}
}
fn read_field_value(data: &[u8], field_length: usize) -> Result<(&[u8], &[u8])> {
if data.len() >= field_length {
Ok(data.split_at(field_length))
} else {
Err(Error::IncompleteFieldValue(field_length, data.len()))
}
}
impl<'a> FrameParser<'a> {
pub fn new(frame_data: &[u8]) -> Result<FrameParser<'_>> {
let (_, body) = read_frame_format(frame_data)?;
let (field_count, mut body) = read_frame_field_count(body)?;
let max_possible_fields = body.len() / 6;
let mut fields = Vec::with_capacity((field_count as usize).min(max_possible_fields));
for _ in 0..field_count {
let (tag, length, tail) = read_field_tag_and_length(body)?;
let (value, tail) = read_field_value(tail, length)?;
fields.push(FrameParserField { tag, value });
body = tail
}
if body.is_empty() {
Ok(FrameParser { fields })
} else {
Err(Error::UnexpectedData)
}
}
pub fn get_optional_data(&self, search_tag: u16) -> Option<&'a [u8]> {
for field in &self.fields {
if field.tag == search_tag {
return Some(field.value);
}
}
None
}
pub fn get_data(&self, search_tag: u16) -> Result<&'a [u8]> {
self.get_optional_data(search_tag)
.ok_or(Error::MissingRequiredField(search_tag))
}
pub fn get_datas<'b>(&'b self, search_tag: u16) -> impl Iterator<Item = &'a [u8]>
where
'b: 'a,
{
self.fields
.iter()
.filter(move |f| f.tag == search_tag)
.map(|f| f.value)
}
pub fn get_optional_u8(&self, search_tag: u16) -> Result<Option<u8>> {
self.decode_value(search_tag, decode_u8)
}
pub fn get_u8(&self, search_tag: u16) -> Result<u8> {
self.get_optional_u8(search_tag)?
.ok_or(Error::MissingRequiredField(search_tag))
}
pub fn get_u8s<'b>(&'b self, search_tag: u16) -> impl Iterator<Item = Result<u8>> + 'b
where
'b: 'a,
{
self.get_datas(search_tag).map(decode_u8)
}
pub fn get_optional_u16(&self, search_tag: u16) -> Result<Option<u16>> {
self.decode_value(search_tag, decode_u16)
}
pub fn get_u16(&self, search_tag: u16) -> Result<u16> {
self.get_optional_u16(search_tag)?
.ok_or(Error::MissingRequiredField(search_tag))
}
pub fn get_u16s<'b>(&'b self, search_tag: u16) -> impl Iterator<Item = Result<u16>> + 'b
where
'b: 'a,
{
self.get_datas(search_tag).map(decode_u16)
}
pub fn get_optional_u32(&self, search_tag: u16) -> Result<Option<u32>> {
self.decode_value(search_tag, decode_u32)
}
pub fn get_u32(&self, search_tag: u16) -> Result<u32> {
self.get_optional_u32(search_tag)?
.ok_or(Error::MissingRequiredField(search_tag))
}
pub fn get_u32s<'b>(&'b self, search_tag: u16) -> impl Iterator<Item = Result<u32>> + 'b
where
'b: 'a,
{
self.get_datas(search_tag).map(decode_u32)
}
pub fn get_optional_u64(&self, search_tag: u16) -> Result<Option<u64>> {
self.decode_value(search_tag, decode_u64)
}
pub fn get_u64(&self, search_tag: u16) -> Result<u64> {
self.get_optional_u64(search_tag)?
.ok_or(Error::MissingRequiredField(search_tag))
}
pub fn get_u64s<'b>(&'b self, search_tag: u16) -> impl Iterator<Item = Result<u64>> + 'b
where
'b: 'a,
{
self.get_datas(search_tag).map(decode_u64)
}
pub fn get_optional_bool(&self, search_tag: u16) -> Result<Option<bool>> {
self.decode_value(search_tag, decode_bool)
}
pub fn get_bool(&self, search_tag: u16) -> Result<bool> {
self.get_optional_bool(search_tag)?
.ok_or(Error::MissingRequiredField(search_tag))
}
pub fn get_bools<'b>(&'b self, search_tag: u16) -> impl Iterator<Item = Result<bool>> + 'b
where
'b: 'a,
{
self.get_datas(search_tag).map(decode_bool)
}
pub fn get_optional_str(&self, search_tag: u16) -> Result<Option<&str>> {
self.decode_ref(search_tag, decode_str)
}
pub fn get_str(&self, search_tag: u16) -> Result<&str> {
self.get_optional_str(search_tag)?
.ok_or(Error::MissingRequiredField(search_tag))
}
pub fn get_strs<'b>(&'b self, search_tag: u16) -> impl Iterator<Item = Result<&'a str>> + 'b
where
'b: 'a,
{
self.get_datas(search_tag).map(decode_str)
}
#[cfg(feature = "uuid")]
pub fn get_optional_uuid(&self, search_tag: u16) -> Result<Option<uuid::Uuid>> {
self.decode_value(search_tag, decode_uuid)
}
#[cfg(feature = "uuid")]
pub fn get_uuid(&self, search_tag: u16) -> Result<uuid::Uuid> {
self.get_optional_uuid(search_tag)?
.ok_or(Error::MissingRequiredField(search_tag))
}
#[cfg(feature = "uuid")]
pub fn get_uuids<'b>(&'b self, search_tag: u16) -> impl Iterator<Item = Result<uuid::Uuid>> + 'b
where
'b: 'a,
{
self.get_datas(search_tag).map(decode_uuid)
}
pub fn get_optional_frame(&self, search_tag: u16) -> Result<Option<FrameParser<'_>>> {
self.get_optional_data(search_tag)
.map(FrameParser::new)
.transpose()
}
pub fn get_frame(&self, search_tag: u16) -> Result<FrameParser<'_>> {
self.get_optional_frame(search_tag)?
.ok_or(Error::MissingRequiredField(search_tag))
}
pub fn get_frames<'b>(
&'b self,
search_tag: u16,
) -> impl Iterator<Item = Result<FrameParser<'a>>> + 'b
where
'b: 'a,
{
self.get_datas(search_tag).map(FrameParser::new)
}
fn decode_value<T, F>(&self, search_tag: u16, decoder: F) -> Result<Option<T>>
where
F: FnOnce(&[u8]) -> Result<T>,
{
self.get_optional_data(search_tag).map(decoder).transpose()
}
fn decode_ref<T, F>(&self, search_tag: u16, decoder: F) -> Result<Option<&T>>
where
F: FnOnce(&[u8]) -> Result<&T>,
T: ?Sized,
{
self.get_optional_data(search_tag).map(decoder).transpose()
}
}
fn decode_u8(value: &[u8]) -> Result<u8> {
match value.len() {
1 => Ok(value[0]),
_ => Err(Error::IncompatibleFieldLength(value.len())),
}
}
fn decode_u16(value: &[u8]) -> Result<u16> {
match value.len() {
1 => Ok(value[0] as u16),
2 => Ok(u16::from_be_bytes(value.try_into().unwrap())),
_ => Err(Error::IncompatibleFieldLength(value.len())),
}
}
fn decode_u32(value: &[u8]) -> Result<u32> {
match value.len() {
1 => Ok(value[0] as u32),
2 => Ok(u16::from_be_bytes(value.try_into().unwrap()) as u32),
4 => Ok(u32::from_be_bytes(value.try_into().unwrap())),
_ => Err(Error::IncompatibleFieldLength(value.len())),
}
}
fn decode_u64(value: &[u8]) -> Result<u64> {
match value.len() {
1 => Ok(value[0] as u64),
2 => Ok(u16::from_be_bytes(value.try_into().unwrap()) as u64),
4 => Ok(u32::from_be_bytes(value.try_into().unwrap()) as u64),
8 => Ok(u64::from_be_bytes(value.try_into().unwrap())),
_ => Err(Error::IncompatibleFieldLength(value.len())),
}
}
fn decode_bool(value: &[u8]) -> Result<bool> {
if value.len() != 1 {
return Err(Error::IncompatibleFieldLength(value.len()));
}
match value[0] {
0x00 => Ok(false),
0xFF => Ok(true),
_ => Err(Error::IncompatibleFieldValue),
}
}
fn decode_str(value: &[u8]) -> Result<&str> {
std::str::from_utf8(value).map_err(|_| Error::IncompatibleFieldValue)
}
#[cfg(feature = "uuid")]
fn decode_uuid(value: &[u8]) -> Result<uuid::Uuid> {
uuid::Uuid::from_slice(value).map_err(|_| Error::IncompatibleFieldLength(value.len()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn can_make_an_empty_frame() {
let mut data = Vec::with_capacity(100);
{
FrameBuilder::new(&mut data);
}
assert_eq!(&[1, 0, 0, 0, 0], &data[..]);
}
#[test]
fn can_make_an_empty_packet_frame() {
let mut data = Vec::with_capacity(100);
{
PacketFrameBuilder::new(&mut data);
}
assert_eq!(&[0, 0, 0, 5, 1, 0, 0, 0, 0], &data[..]);
}
#[test]
fn can_add_data_to_frame() {
let mut data = Vec::with_capacity(100);
{
let mut bld = FrameBuilder::new(&mut data);
bld.add_data(1022, &[9, 255]);
}
assert_eq!(
&[
1, 0, 0, 0, 1, 3, 254, 0, 0, 0, 2, 9, 255, ],
&data[..]
);
}
#[test]
fn can_add_data_to_packet_frame() {
let mut data = Vec::with_capacity(100);
{
let mut bld = PacketFrameBuilder::new(&mut data);
bld.add_data(1022, &[9, 255]);
}
assert_eq!(
&[
0, 0, 0, 13, 1, 0, 0, 0, 1, 3, 254, 0, 0, 0, 2, 9, 255, ],
&data[..]
);
}
#[test]
fn can_add_child_to_frame() {
let mut data = Vec::with_capacity(100);
{
let mut bld = FrameBuilder::new(&mut data);
let mut child_bld = bld.add_frame(1022);
child_bld.add_data(60, &[9, 255])
}
assert_eq!(
&[
1, 0, 0, 0, 1, 3, 254, 0, 0, 0, 13, 1, 0, 0, 0, 1, 0, 60, 0, 0, 0, 2, 9, 255 ],
&data[..]
);
}
#[test]
fn can_add_child_to_packet_frame() {
let mut data = Vec::with_capacity(100);
{
let mut bld = PacketFrameBuilder::new(&mut data);
let mut child_bld = bld.add_frame(1022);
child_bld.add_data(60, &[9, 255])
}
assert_eq!(
&[
0, 0, 0, 24, 1, 0, 0, 0, 1, 3, 254, 0, 0, 0, 13, 1, 0, 0, 0, 1, 0, 60, 0, 0, 0, 2, 9, 255 ],
&data[..]
);
}
#[test]
fn can_add_bool_to_frame() {
let mut data = Vec::with_capacity(100);
{
let mut bld = FrameBuilder::new(&mut data);
bld.add_bool(1022, true);
bld.add_bool(1021, false);
}
assert_eq!(
&[
1, 0, 0, 0, 2, 3, 254, 0, 0, 0, 1, 255, 3, 253, 0, 0, 0, 1, 0 ],
&data[..]
);
}
#[test]
fn can_add_u8_to_frame() {
let mut data = Vec::with_capacity(100);
{
let mut bld = FrameBuilder::new(&mut data);
bld.add_u8(1022, 89);
}
assert_eq!(
&[
1, 0, 0, 0, 1, 3, 254, 0, 0, 0, 1, 89 ],
&data[..]
);
}
#[test]
fn can_add_u16_to_frame() {
let mut data = Vec::with_capacity(100);
{
let mut bld = FrameBuilder::new(&mut data);
bld.add_u16(1022, 1009);
}
assert_eq!(
&[
1, 0, 0, 0, 1, 3, 254, 0, 0, 0, 2, 3, 241 ],
&data[..]
);
}
#[test]
fn can_add_u32_to_frame() {
let mut data = Vec::with_capacity(100);
{
let mut bld = FrameBuilder::new(&mut data);
bld.add_u32(1022, 156090);
}
assert_eq!(
&[
1, 0, 0, 0, 1, 3, 254, 0, 0, 0, 4, 0, 2, 97, 186 ],
&data[..]
);
}
#[test]
fn can_add_u64_to_frame() {
let mut data = Vec::with_capacity(100);
{
let mut bld = FrameBuilder::new(&mut data);
bld.add_u64(1022, 156234234090);
}
assert_eq!(
&[
1, 0, 0, 0, 1, 3, 254, 0, 0, 0, 8, 0, 0, 0, 36, 96, 73, 56, 234 ],
&data[..]
);
}
#[test]
fn can_add_utf8_to_frame() {
let mut data = Vec::with_capacity(100);
{
let mut bld = FrameBuilder::new(&mut data);
bld.add_str(1022, "hello");
}
assert_eq!(
&[
1, 0, 0, 0, 1, 3, 254, 0, 0, 0, 5, 104, 101, 108, 108, 111 ],
&data[..]
);
}
#[test]
fn can_not_parse_a_frame_if_there_is_not_enough_data_for_frame_format() {
let data = &[]; assert_eq!(
Some(Error::IncompleteFrameFormat),
FrameParser::new(data).err()
);
}
#[test]
fn can_not_parse_a_frame_if_frame_format_is_not_recognized() {
let data = &[8]; assert_eq!(
Some(Error::InvalidFrameFormat(8)),
FrameParser::new(data).err()
);
}
#[test]
fn can_not_parse_a_frame_if_there_is_not_enough_data_for_field_count() {
let data = &[1, 0, 0, 0]; assert_eq!(
Some(Error::IncompleteFrameFieldCount),
FrameParser::new(data).err()
);
}
#[test]
fn can_not_parse_a_frame_if_there_is_not_enough_data_for_field_tag_and_length() {
let data = &[
1, 0, 0, 0, 1, 0, 1, 0, 0, 0, ];
assert_eq!(
Some(Error::IncompleteFieldTagOrLength),
FrameParser::new(data).err()
);
}
#[test]
fn can_not_parse_a_frame_if_there_is_not_enough_data_for_a_field_value() {
let data = &[
1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 4, 1, 2, 3, ];
assert_eq!(
Some(Error::IncompleteFieldValue(4, 3)),
FrameParser::new(data).err()
);
}
#[test]
fn can_not_parse_a_frame_if_there_is_excess_data() {
let data = &[
1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 4, 1, 2, 3, 4, 5, ];
assert_eq!(Some(Error::UnexpectedData), FrameParser::new(data).err());
}
#[test]
fn can_not_parse_a_frame_with_a_maliciously_large_field_count() {
let data = &[
1, 0xFF, 0xFF, 0xFF, 0xFF, ];
assert_eq!(
Some(Error::IncompleteFieldTagOrLength),
FrameParser::new(data).err()
);
}
#[test]
fn can_read_data_from_frame() {
let data = &[
1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 4, 1, 2, 3, 4, ];
let frame = FrameParser::new(data).unwrap();
assert_eq!(&[1, 2, 3, 4], frame.get_data(1).unwrap());
}
#[test]
fn get_data_returns_error_when_field_is_missing() {
let data = &[
1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 4, 1, 2, 3, 4,
];
let frame = FrameParser::new(data).unwrap();
assert_eq!(Some(Error::MissingRequiredField(3)), frame.get_data(3).err());
}
#[test]
fn can_read_datas_from_a_frame() {
let data = &[
1, 0, 0, 0, 3, 0, 1, 0, 0, 0, 2, 10, 11, 0, 2, 0, 0, 0, 2, 20, 22, 0, 1, 0, 0, 0, 2, 30, 33, ];
let frame = FrameParser::new(data).unwrap();
let expected = vec![&[10, 11], &[30, 33]];
let actual: Vec<&[u8]> = frame.get_datas(1).collect();
assert_eq!(expected, actual);
}
#[test]
fn get_optional_data_returns_none_when_field_is_missing() {
let data = &[
1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 4, 1, 2, 3, 4, ];
let frame = FrameParser::new(data).unwrap();
assert_eq!(None, frame.get_optional_data(3));
}
#[test]
fn can_not_decode_u8_with_zero_bytes() {
assert_eq!(
Some(Error::IncompatibleFieldLength(0)),
decode_u8(&[]).err()
);
}
#[test]
fn can_decode_compatible_values_into_u8() {
assert_eq!(Ok(8), decode_u8(&[8]));
}
#[test]
fn can_not_decode_incompatible_values_into_u8() {
assert_eq!(
Some(Error::IncompatibleFieldLength(2)),
decode_u8(&[0, 8]).err()
);
assert_eq!(
Some(Error::IncompatibleFieldLength(4)),
decode_u8(&[0, 0, 0, 8]).err()
);
assert_eq!(
Some(Error::IncompatibleFieldLength(8)),
decode_u8(&[0, 0, 0, 0, 0, 0, 0, 8]).err()
);
assert_eq!(
Some(Error::IncompatibleFieldLength(2)),
decode_u8(&[1, 8]).err()
);
assert_eq!(
Some(Error::IncompatibleFieldLength(4)),
decode_u8(&[0, 0, 1, 8]).err()
);
assert_eq!(
Some(Error::IncompatibleFieldLength(8)),
decode_u8(&[0, 0, 0, 0, 0, 0, 1, 8]).err()
);
}
#[test]
fn can_read_u8_from_a_frame() {
let mut data = Vec::new();
{
let mut bld = FrameBuilder::new(&mut data);
bld.add_u8(100, 250);
}
let frame = FrameParser::new(&data).unwrap();
assert_eq!(250, frame.get_u8(100).unwrap());
assert_eq!(Some(250), frame.get_optional_u8(100).unwrap());
assert_eq!(
Some(Error::MissingRequiredField(99)),
frame.get_u8(99).err()
);
}
#[test]
fn can_read_u8s_from_a_frame() {
let data = &[
1, 0, 0, 0, 3, 0, 1, 0, 0, 0, 1, 10, 0, 2, 0, 0, 0, 1, 20, 0, 1, 0, 0, 0, 1, 30, ];
let frame = FrameParser::new(data).unwrap();
let expected: Vec<Result<u8>> = vec![Ok(10), Ok(30)];
let actual: Vec<Result<u8>> = frame.get_u8s(1).collect();
assert_eq!(expected, actual);
}
#[test]
fn can_not_decode_u16_with_zero_bytes() {
assert_eq!(
Some(Error::IncompatibleFieldLength(0)),
decode_u16(&[]).err()
);
}
#[test]
fn can_decode_compatible_values_into_u16() {
assert_eq!(Ok(8), decode_u16(&[8]));
assert_eq!(Ok(3080), decode_u16(&[12, 8]));
}
#[test]
fn can_not_decode_incompatible_values_into_u16() {
assert_eq!(
Some(Error::IncompatibleFieldLength(4)),
decode_u16(&[0, 0, 12, 8]).err()
);
assert_eq!(
Some(Error::IncompatibleFieldLength(4)),
decode_u16(&[0, 1, 255, 255]).err()
);
assert_eq!(
Some(Error::IncompatibleFieldLength(8)),
decode_u16(&[0, 0, 0, 0, 0, 0, 0, 1]).err()
);
}
#[test]
fn can_read_u16_from_a_frame() {
let mut data = Vec::new();
{
let mut bld = FrameBuilder::new(&mut data);
bld.add_u8(100, 90);
bld.add_u16(200, 1025);
}
let frame = FrameParser::new(&data).unwrap();
assert_eq!(90, frame.get_u16(100).unwrap());
assert_eq!(1025, frame.get_u16(200).unwrap());
assert_eq!(Some(90), frame.get_optional_u16(100).unwrap());
assert_eq!(None, frame.get_optional_u16(99).unwrap());
assert_eq!(
Some(Error::MissingRequiredField(99)),
frame.get_u16(99).err()
);
}
#[test]
fn can_read_u16s_from_a_frame() {
let data = &[
1, 0, 0, 0, 3, 0, 1, 0, 0, 0, 1, 10, 0, 2, 0, 0, 0, 1, 20, 0, 1, 0, 0, 0, 1, 30, ];
let frame = FrameParser::new(data).unwrap();
let expected: Vec<Result<u16>> = vec![Ok(10), Ok(30)];
let actual: Vec<Result<u16>> = frame.get_u16s(1).collect();
assert_eq!(expected, actual);
}
#[test]
fn can_not_decode_u32_with_zero_bytes() {
assert_eq!(
Some(Error::IncompatibleFieldLength(0)),
decode_u32(&[]).err()
);
}
#[test]
fn can_decode_compatible_values_into_u32() {
assert_eq!(Ok(8), decode_u32(&[8]));
assert_eq!(Ok(3080), decode_u32(&[12, 8]));
assert_eq!(Ok(1744964616), decode_u32(&[104, 2, 12, 8]));
}
#[test]
fn can_not_decode_incompatible_values_into_u32() {
assert_eq!(
Some(Error::IncompatibleFieldLength(8)),
decode_u32(&[0, 0, 0, 0, 104, 2, 12, 8]).err()
);
assert_eq!(
Some(Error::IncompatibleFieldLength(8)),
decode_u32(&[0, 0, 0, 1, 255, 255, 255, 255]).err()
);
}
#[test]
fn can_read_u32_from_a_frame() {
let mut data = Vec::new();
{
let mut bld = FrameBuilder::new(&mut data);
bld.add_u8(100, 90);
bld.add_u16(200, 1025);
bld.add_u32(300, 1744964616);
}
let frame = FrameParser::new(&data).unwrap();
assert_eq!(90, frame.get_u32(100).unwrap());
assert_eq!(1025, frame.get_u32(200).unwrap());
assert_eq!(1744964616, frame.get_u32(300).unwrap());
assert_eq!(Some(1744964616), frame.get_optional_u32(300).unwrap());
assert_eq!(None, frame.get_optional_u32(99).unwrap());
assert_eq!(
Some(Error::MissingRequiredField(99)),
frame.get_u32(99).err()
);
}
#[test]
fn can_read_u32s_from_a_frame() {
let data = &[
1, 0, 0, 0, 3, 0, 1, 0, 0, 0, 1, 10, 0, 2, 0, 0, 0, 1, 20, 0, 1, 0, 0, 0, 1, 30, ];
let frame = FrameParser::new(data).unwrap();
let expected: Vec<Result<u32>> = vec![Ok(10), Ok(30)];
let actual: Vec<Result<u32>> = frame.get_u32s(1).collect();
assert_eq!(expected, actual);
}
#[test]
fn can_not_decode_u64_with_zero_bytes() {
assert_eq!(
Some(Error::IncompatibleFieldLength(0)),
decode_u64(&[]).err()
);
}
#[test]
fn can_decode_compatible_values_into_u64() {
assert_eq!(Ok(8), decode_u64(&[8]));
assert_eq!(Ok(3080), decode_u64(&[12, 8]));
assert_eq!(Ok(1744964616), decode_u64(&[104, 2, 12, 8]));
assert_eq!(
Ok(150626523450313736),
decode_u64(&[2, 23, 34, 6, 104, 2, 12, 8])
);
}
#[test]
fn can_read_u64_from_a_frame() {
let mut data = Vec::new();
{
let mut bld = FrameBuilder::new(&mut data);
bld.add_u8(100, 90);
bld.add_u16(200, 1025);
bld.add_u32(300, 1744964616);
bld.add_u64(400, 150626523450313736);
}
let frame = FrameParser::new(&data).unwrap();
assert_eq!(90, frame.get_u64(100).unwrap());
assert_eq!(1025, frame.get_u64(200).unwrap());
assert_eq!(1744964616, frame.get_u64(300).unwrap());
assert_eq!(150626523450313736, frame.get_u64(400).unwrap());
assert_eq!(Some(150626523450313736), frame.get_optional_u64(400).unwrap());
assert_eq!(None, frame.get_optional_u64(99).unwrap());
assert_eq!(
Some(Error::MissingRequiredField(99)),
frame.get_u64(99).err()
);
}
#[test]
fn can_read_u64s_from_a_frame() {
let data = &[
1, 0, 0, 0, 3, 0, 1, 0, 0, 0, 1, 10, 0, 2, 0, 0, 0, 1, 20, 0, 1, 0, 0, 0, 1, 30, ];
let frame = FrameParser::new(data).unwrap();
let expected: Vec<Result<u64>> = vec![Ok(10), Ok(30)];
let actual: Vec<Result<u64>> = frame.get_u64s(1).collect();
assert_eq!(expected, actual);
}
#[test]
fn can_not_decode_bool_with_zero_bytes() {
assert_eq!(
Some(Error::IncompatibleFieldLength(0)),
decode_bool(&[]).err()
);
}
#[test]
fn can_decode_compatible_values_into_bool() {
assert_eq!(Ok(false), decode_bool(&[0x00]));
assert_eq!(Ok(true), decode_bool(&[0xFF]));
}
#[test]
fn can_not_decode_incompatible_values_into_bool() {
assert_eq!(
Some(Error::IncompatibleFieldValue),
decode_bool(&[0x01]).err()
);
}
#[test]
fn can_read_bool_from_a_frame() {
let mut data = Vec::new();
{
let mut bld = FrameBuilder::new(&mut data);
bld.add_bool(100, true);
bld.add_bool(200, false);
}
let frame = FrameParser::new(&data).unwrap();
assert_eq!(true, frame.get_bool(100).unwrap());
assert_eq!(false, frame.get_bool(200).unwrap());
assert_eq!(Some(true), frame.get_optional_bool(100).unwrap());
assert_eq!(None, frame.get_optional_bool(99).unwrap());
assert_eq!(
Some(Error::MissingRequiredField(99)),
frame.get_bool(99).err()
);
}
#[test]
fn can_read_bools_from_a_frame() {
let mut data = Vec::new();
{
let mut bld = FrameBuilder::new(&mut data);
bld.add_bool(1, false);
bld.add_bool(2, false); bld.add_bool(1, true);
}
let frame = FrameParser::new(&data).unwrap();
let expected: Vec<Result<bool>> = vec![Ok(false), Ok(true)];
let actual: Vec<Result<bool>> = frame.get_bools(1).collect();
assert_eq!(expected, actual);
}
#[test]
fn can_read_str_from_a_frame() {
let test_str = "short test string";
let mut data = Vec::new();
{
let mut bld = FrameBuilder::new(&mut data);
bld.add_str(100, test_str);
}
let frame = FrameParser::new(&data).unwrap();
assert_eq!(test_str, frame.get_str(100).unwrap());
assert_eq!(Some(test_str), frame.get_optional_str(100).unwrap());
assert_eq!(None, frame.get_optional_str(99).unwrap());
assert_eq!(
Some(Error::MissingRequiredField(99)),
frame.get_str(99).err()
);
}
#[test]
fn can_read_strs_from_a_frame() {
let mut data = Vec::new();
{
let mut bld = FrameBuilder::new(&mut data);
bld.add_str(1, "hello");
bld.add_str(2, "welcome"); bld.add_str(1, "goodbye");
}
let frame = FrameParser::new(&data).unwrap();
let expected: Vec<Result<&str>> = vec![Ok("hello"), Ok("goodbye")];
let actual: Vec<Result<&str>> = frame.get_strs(1).collect();
assert_eq!(expected, actual);
}
#[test]
#[cfg(feature = "uuid")]
fn can_read_uuid_from_a_frame() {
let test_uuid = uuid::Uuid::parse_str("40b4e52c-1501-48d3-98eb-e2c66cb76cbf").unwrap();
let mut data = Vec::new();
{
let mut bld = FrameBuilder::new(&mut data);
bld.add_uuid(100, &test_uuid);
}
let frame = FrameParser::new(&data).unwrap();
assert_eq!(test_uuid, frame.get_uuid(100).unwrap());
assert_eq!(Some(test_uuid), frame.get_optional_uuid(100).unwrap());
assert_eq!(None, frame.get_optional_uuid(99).unwrap());
assert_eq!(
Some(Error::MissingRequiredField(99)),
frame.get_uuid(99).err()
);
}
#[test]
#[cfg(feature = "uuid")]
fn can_read_uuids_from_a_frame() {
let test_uuid1 = uuid::Uuid::parse_str("40b4e52c-1501-48d3-98eb-e2c66cb76cbf").unwrap();
let test_uuid2 = uuid::Uuid::parse_str("e6bb35e5-547b-4930-b72c-5d50aa60ff49").unwrap();
let test_uuid3 = uuid::Uuid::parse_str("451f82e5-c17a-4843-a9c7-5ff3f7ae20fd").unwrap();
let mut data = Vec::new();
{
let mut bld = FrameBuilder::new(&mut data);
bld.add_uuid(1, &test_uuid1);
bld.add_uuid(2, &test_uuid2); bld.add_uuid(1, &test_uuid3);
}
let frame = FrameParser::new(&data).unwrap();
let expected: Vec<Result<uuid::Uuid>> = vec![Ok(test_uuid1), Ok(test_uuid3)];
let actual: Vec<Result<uuid::Uuid>> = frame.get_uuids(1).collect();
assert_eq!(expected, actual);
}
#[test]
fn can_read_child_frame() {
let mut data = Vec::new();
{
let mut bld = FrameBuilder::new(&mut data);
bld.add_u8(100, 1);
let mut bld2 = bld.add_frame(200);
bld2.add_u8(300, 3);
}
let frame = FrameParser::new(&data).unwrap();
let child_frame = frame.get_frame(200).unwrap();
assert_eq!(3, child_frame.get_u8(300).unwrap());
assert!(frame.get_optional_frame(999).unwrap().is_none());
assert_eq!(
Some(Error::MissingRequiredField(999)),
frame.get_frame(999).err()
);
}
#[test]
fn can_read_child_frames() {
let mut data = Vec::new();
{
let mut bld = FrameBuilder::new(&mut data);
bld.add_u8(100, 1);
for i in 0..2 {
let mut bld2 = bld.add_frame(200);
bld2.add_u8(300, i);
}
}
let frame = FrameParser::new(&data).unwrap();
let child_frame: Vec<FrameParser> = frame.get_frames(200).map(|v| v.unwrap()).collect();
assert_eq!(0, child_frame[0].get_u8(300).unwrap());
assert_eq!(1, child_frame[1].get_u8(300).unwrap());
}
}