Browse Source

Add encoder functions with unit tests

master
Alex Williams 9 months ago
parent
commit
2653343f32
Signed by: aw GPG Key ID: 19EE4AAA361A7E2C
5 changed files with 409 additions and 13 deletions
  1. +1
    -1
      Cargo.lock
  2. +1
    -3
      Cargo.toml
  3. +12
    -8
      src/decode.rs
  4. +350
    -0
      src/encode.rs
  5. +45
    -1
      src/lib.rs

+ 1
- 1
Cargo.lock View File

@ -1,5 +1,5 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "libboawp"
name = "boawp"
version = "0.1.0"

+ 1
- 3
Cargo.toml View File

@ -1,5 +1,5 @@
[package]
name = "libboawp"
name = "boawp"
version = "0.1.0"
authors = ["Alexander Williams, On-Prem <license@on-premises.com>"]
edition = "2018"
@ -9,5 +9,3 @@ homepage = "https://boawp.org"
repository = "https://git.boawp.org/boawp/rust-libboawp"
keywords = ["boawp", "encoder", "tool", "decoder"]
publish = false
[dependencies]

+ 12
- 8
src/decode.rs View File

@ -22,7 +22,7 @@ pub fn read_integer(buf: DataBuffer) -> ResultDataType {
let buffer: Vec<u8> = buf.drain(..tl.dlength as usize).collect();
let int = match tl.dlength {
0 => Integer::Zero(),
1 => Integer::One(u8::from_be_bytes(buffer[..1].try_into().unwrap())),
1 => Integer::One(i8::from_be_bytes(buffer[..1].try_into().unwrap())),
2 => Integer::Two(i16::from_be_bytes(buffer[..2].try_into().unwrap())),
4 => Integer::Four(i32::from_be_bytes(buffer[..4].try_into().unwrap())),
8 => Integer::Eight(i64::from_be_bytes(buffer[..8].try_into().unwrap())),
@ -62,7 +62,7 @@ pub fn read_map(buf: DataBuffer) -> ResultDataType {
Ok(DataType::Map(dmap))
}
pub fn read_u8(buf: DataBuffer) -> ResultInteger {
pub fn read_i8(buf: DataBuffer) -> ResultInteger {
let int = read_integer(buf)?;
match int {
DataType::Integer(Integer::One(x)) => Ok(Integer::One(x)),
@ -340,9 +340,9 @@ mod tests {
}
#[test]
fn _read_integer() {
let mut x = vec![105, 1, 255];
let mut x = vec![105, 1, 127];
let value = read_integer(&mut x).unwrap();
assert_eq!(value, DataType::Integer(Integer::One(255)));
assert_eq!(value, DataType::Integer(Integer::One(127)));
assert_eq!(x, []);
let mut x = vec![105, 2, 127, 255];
@ -570,13 +570,17 @@ mod tests {
);
}
#[test]
fn _read_integer_u8() {
fn _read_integer_i8() {
let mut x = vec![105, 1, 127];
let value = read_i8(&mut x).unwrap();
assert_eq!(value, Integer::One(127));
let mut x = vec![105, 1, 255];
let value = read_u8(&mut x).unwrap();
assert_eq!(value, Integer::One(255));
let value = read_i8(&mut x).unwrap();
assert_eq!(value, Integer::One(-1));
let mut x = vec![105, 2, 255, 255];
let value = read_u8(&mut x);
let value = read_i8(&mut x);
assert!(value.is_err());
assert_eq!(
value.unwrap_err().into_inner().unwrap().to_string(),


+ 350
- 0
src/encode.rs View File

@ -1 +1,351 @@
use std::{io::Error, io::ErrorKind};
use super::*;
pub fn write_null() -> ResultBuffer<'static> {
let res: Vec<u8> = vec!['n' as u8, 0];
Ok(res)
}
pub fn write_true() -> ResultBuffer<'static> {
let res: Vec<u8> = vec!['t' as u8, 0];
Ok(res)
}
pub fn write_false() -> ResultBuffer<'static> {
let res: Vec<u8> = vec!['f' as u8, 0];
Ok(res)
}
pub fn write_integer(z: &Integer) -> ResultBuffer {
let mut res: Vec<u8> = vec!['i' as u8];
let mut int = match z {
Integer::Zero() => vec![],
Integer::One(i) => i.to_be_bytes().to_vec(),
Integer::Two(i) => i.to_be_bytes().to_vec(),
Integer::Four(i) => i.to_be_bytes().to_vec(),
Integer::Eight(i) => i.to_be_bytes().to_vec(),
Integer::Sixteen(i) => i.to_be_bytes().to_vec(),
Integer::BigNum(i) => i.to_vec(),
};
if let true = int.len() > 255 { return Err(Error::new(ErrorKind::InvalidData, "Invalid integer value length, max 255")) }
res.push(int.len() as u8);
res.append(&mut int);
Ok(res)
}
pub fn write_sint(z: i128) -> ResultBuffer<'static> {
let int = match z {
i if i >= i8::MIN.into() && i <= i8::MAX.into() => write_i8(i as i8)?,
i if i >= i16::MIN.into() && i <= i16::MAX.into() => write_i16(z as i16)?,
i if i >= i32::MIN.into() && i <= i32::MAX.into() => write_i32(z as i32)?,
i if i >= i64::MIN.into() && i <= i64::MAX.into() => write_i64(z as i64)?,
i if i >= i128::MIN.into() && i <= i128::MAX.into() => write_i128(z)?,
_ => return Err(Error::new(ErrorKind::InvalidData, "Invalid signed integer value length"))
};
Ok(int)
}
pub fn write_string(z: &String) -> ResultBuffer {
if let true = z.len() > 255 { return Err(Error::new(ErrorKind::InvalidData, "Invalid string value length, max 255")) }
let mut res: Vec<u8> = vec!['s' as u8, z.len() as u8];
res.append(&mut z.as_bytes().to_vec());
Ok(res)
}
pub fn write_binary(z: &Vec<u8>) -> ResultBuffer {
if let true = z.len() > 255 { return Err(Error::new(ErrorKind::InvalidData, "Invalid binary value length, max 255")) }
let mut res: Vec<u8> = vec!['b' as u8, z.len() as u8];
res.append(&mut z.to_vec());
Ok(res)
}
pub fn write_map(z: &DataMap) -> ResultBuffer {
let mut res: Vec<_> = z.iter()
.map(|(x,y)| {
let dkey = write_value(x)?;
// 257 because +2 for type & length
if let true = dkey.len() > 257 { return Err(Error::new(ErrorKind::InvalidData, "Invalid map key length, max 255")) }
let mut dmap = dkey;
let mut dvalue = write_value(y)?;
if let true = dvalue.len() > 257 { return Err(Error::new(ErrorKind::InvalidData, "Invalid map value length, max 255")) }
dmap.append(&mut dvalue);
Ok(dmap)
})
.map(|x| {
x.unwrap()
}).into_iter().flatten().collect();
res.insert(0, res.len() as u8);
res.insert(0, b'm');
if let true = res.len() > 255 { return Err(Error::new(ErrorKind::InvalidData, "Invalid map length, max 255")) }
Ok(res)
}
pub fn write_zero() -> ResultBuffer<'static> {
let int = write_integer(&Integer::Zero())?;
Ok(int)
}
pub fn write_i8(z: i8) -> ResultBuffer<'static> {
let int = write_integer(&Integer::One(z))?;
Ok(int)
}
pub fn write_i16(z: i16) -> ResultBuffer<'static> {
let int = write_integer(&Integer::Two(z))?;
Ok(int)
}
pub fn write_i32(z: i32) -> ResultBuffer<'static> {
let int = write_integer(&Integer::Four(z))?;
Ok(int)
}
pub fn write_i64(z: i64) -> ResultBuffer<'static> {
let int = write_integer(&Integer::Eight(z))?;
Ok(int)
}
pub fn write_i128(z: i128) -> ResultBuffer<'static> {
let int = write_integer(&Integer::Sixteen(z))?;
Ok(int)
}
pub fn write_bignum(z: Vec<u8>) -> ResultBuffer<'static> {
let int = write_integer(&Integer::BigNum(z))?;
Ok(int)
}
pub fn write_value(z: &DataType) -> ResultBuffer {
let value = match z {
DataType::Null => write_null()?,
DataType::Boolean(true) => write_true()?,
DataType::Boolean(false) => write_false()?,
DataType::Integer(z) => write_integer(z)?,
DataType::String(z) => write_string(z)?,
DataType::Binary(z) => write_binary(z)?,
DataType::Map(z) => write_map(z)?,
};
Ok(value)
}
// TESTS
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn _write_null() {
let value = write_null().unwrap();
assert_eq!(value, vec![b'n', 0]);
}
#[test]
fn _write_true() {
let value = write_true().unwrap();
assert_eq!(value, vec![b't', 0]);
}
#[test]
fn _write_false() {
let value = write_false().unwrap();
assert_eq!(value, vec![b'f', 0]);
}
#[test]
fn _write_integer() {
let mut x = Integer::Zero();
let value = write_integer(&mut x).unwrap();
assert_eq!(value, vec![b'i', 0]);
let mut x = Integer::One(127);
let value = write_integer(&mut x).unwrap();
assert_eq!(value, vec![b'i', 1, 127]);
let mut x = Integer::One(-1);
let value = write_integer(&mut x).unwrap();
assert_eq!(value, vec![b'i', 1, 255]);
let mut x = Integer::Two(255);
let value = write_integer(&mut x).unwrap();
assert_eq!(value, vec![b'i', 2, 0, 255]);
let mut x = Integer::Two(32456);
let value = write_integer(&mut x).unwrap();
assert_eq!(value, vec![b'i', 2, 126, 200]);
let mut x = Integer::Four(-1234567);
let value = write_integer(&mut x).unwrap();
assert_eq!(value, vec![b'i', 4, 255, 237, 41, 121]);
let mut x = Integer::Eight(1234567);
let value = write_integer(&mut x).unwrap();
assert_eq!(value, vec![b'i', 8, 0, 0, 0, 0, 0, 18, 214, 135]);
let mut x = Integer::Sixteen(170141183460469231731687303715884105727);
let value = write_integer(&mut x).unwrap();
assert_eq!(value, vec![b'i', 16, 127, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]);
let mut x = Integer::BigNum(vec![1, 2, 3, 4, 5, 6]);
let value = write_integer(&mut x).unwrap();
assert_eq!(value, vec![b'i', 6, 1, 2, 3, 4, 5, 6]);
}
#[test]
fn _write_integer_error() {
let mut x = Integer::BigNum(vec![255; 256]);
let value = write_integer(&mut x);
assert!(value.is_err());
assert_eq!(
value.unwrap_err().into_inner().unwrap().to_string(),
"Invalid integer value length, max 255"
);
}
#[test]
fn _write_sint() {
let x = 127;
let value = write_sint(x).unwrap();
assert_eq!(value, vec![b'i', 1, 127]);
let x = -1;
let value = write_sint(x).unwrap();
assert_eq!(value, vec![b'i', 1, 255]);
let x = i16::MAX as i128;
let value = write_sint(x).unwrap();
assert_eq!(value, vec![b'i', 2, 127, 255]);
let x = i32::MAX as i128;
let value = write_sint(x).unwrap();
assert_eq!(value, vec![b'i', 4, 127, 255, 255, 255]);
let x = i64::MAX as i128;
let value = write_sint(x).unwrap();
assert_eq!(value, vec![b'i', 8, 127, 255, 255, 255, 255, 255, 255, 255]);
let x = i128::MAX;
let value = write_sint(x).unwrap();
assert_eq!(value, vec![b'i', 16, 127, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]);
}
#[test]
fn _write_string() {
let mut x = String::from("Hello");
let value = write_string(&mut x).unwrap();
assert_eq!(value, vec![b's', 5, 72, 101, 108, 108, 111]);
let mut x = String::from("");
let value = write_string(&mut x).unwrap();
assert_eq!(value, vec![b's', 0]);
}
#[test]
fn _write_string_error() {
let y = vec![65; 256];
let mut x = String::from_utf8(y).unwrap();
let value = write_string(&mut x);
assert!(value.is_err());
assert_eq!(
value.unwrap_err().into_inner().unwrap().to_string(),
"Invalid string value length, max 255"
);
}
#[test]
fn _write_binary() {
let mut x = vec![1, 2, 3, 4];
let value = write_binary(&mut x).unwrap();
assert_eq!(value, vec![b'b', 4, 1, 2, 3, 4]);
let mut x = vec![];
let value = write_binary(&mut x).unwrap();
assert_eq!(value, vec![b'b', 0]);
}
#[test]
fn _write_binary_error() {
let mut x = vec![0; 256];
let value = write_binary(&mut x);
assert!(value.is_err());
assert_eq!(
value.unwrap_err().into_inner().unwrap().to_string(),
"Invalid binary value length, max 255"
);
}
#[test]
fn _write_map() {
let mut x = vec![(DataType::String(String::from("A")), DataType::Boolean(true))];
let value = write_map(&mut x).unwrap();
assert_eq!(value, vec![109, 5, 115, 1, 65, 116, 0]);
let mut x = vec![];
let value = write_map(&mut x).unwrap();
assert_eq!(value, vec![b'm', 0]);
}
#[test]
fn _write_map_error() {
let mut x = vec![(DataType::Binary(vec![0; 255]), DataType::Binary(vec![0; 255]))];
let value = write_map(&mut x);
assert!(value.is_err());
assert_eq!(value.unwrap_err().into_inner().unwrap().to_string(), "Invalid map length, max 255");
}
#[test]
fn _write_integer_zero() {
let value = write_zero().unwrap();
assert_eq!(value, vec![b'i', 0]);
}
#[test]
fn _write_integer_i8() {
let value = write_i8(127).unwrap();
assert_eq!(value, vec![b'i', 1, 127]);
}
#[test]
fn _write_integer_i16() {
let value = write_i16(-32768).unwrap();
assert_eq!(value, vec![b'i', 2, 128, 0]);
}
#[test]
fn _write_integer_i32() {
let value = write_i32(-32768).unwrap();
assert_eq!(value, vec![b'i', 4, 255, 255, 128, 0]);
}
#[test]
fn _write_integer_i64() {
let value = write_i64(-32768).unwrap();
assert_eq!(value, vec![b'i', 8, 255, 255, 255, 255, 255, 255, 128, 0]);
}
#[test]
fn _write_integer_i128() {
let value = write_i128(-32768).unwrap();
assert_eq!(value, vec![b'i', 16, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 128, 0]);
}
#[test]
fn _write_integer_bignum() {
let value = write_bignum(vec![1, 2, 3, 4, 5]).unwrap();
assert_eq!(value, vec![b'i', 5, 1, 2, 3, 4, 5]);
}
#[test]
fn _write_value() {
let mut x = DataType::Null;
let value = write_value(&mut x).unwrap();
assert_eq!(value, vec![b'n', 0]);
let mut x = DataType::Boolean(true);
let value = write_value(&mut x).unwrap();
assert_eq!(value, vec![b't', 0]);
let mut x = DataType::Boolean(false);
let value = write_value(&mut x).unwrap();
assert_eq!(value, vec![b'f', 0]);
let mut x = DataType::Integer(Integer::One(42));
let value = write_value(&mut x).unwrap();
assert_eq!(value, vec![b'i', 1, 42]);
let mut x = DataType::String(String::from("A"));
let value = write_value(&mut x).unwrap();
assert_eq!(value, vec![b's', 1, b'A']);
let mut x = DataType::Binary(vec![1, 2, 3]);
let value = write_value(&mut x).unwrap();
assert_eq!(value, vec![b'b', 3, 1, 2, 3]);
let mut x = DataType::Map(vec![(DataType::Boolean(true), DataType::Boolean(false)), (DataType::String(String::from("Hello")), DataType::String(String::from("World")))]);
let value = write_value(&mut x).unwrap();
assert_eq!(value, vec![b'm', 18, b't', 0, b'f', 0, 115, 5, 72, 101, 108, 108, 111, 115, 5, 87, 111, 114, 108, 100]);
}
}

+ 45
- 1
src/lib.rs View File

@ -1,3 +1,44 @@
/*!
This crate is a decoder and encoder library for the [BOAWP serialization type system](https://boawp.org)
(Binary Oriented Application Wire Protocol).
This implementation **does not** handle specific `BOAWP frames` based on the `BOAWP
wire protocol`; instead it is used as the underlying library for decoding `BOAWP`
values which would appear in `BOAWP frame headers`.
This implementation is 100% spec compliant and contains 100% unit test coverage.
It should never exit with a panic or segfault. If it does, please [file an issue](https://git.boawp.org/boawp/rust-libboawp/issues/new)
to help resolve that.
**Note** this library can be considered stable and ready for production use.
## Usage
Add this to your `Cargo.toml`:
```toml
[dependencies.boawp]
boawp = "1.0"
```
Next, try this code:
```rust
extern crate boawp;
use boawp::DataType;
use boawp::Integer;
let mut encoded = boawp::encode::write_i32(65535).unwrap();
assert_eq!(encoded, vec![b'i', 4, 0, 0, 255, 255]);
let decoded = boawp::decode::read_integer(&mut encoded).unwrap();
assert_eq!(encoded, vec![]);
assert_eq!(decoded, DataType::Integer(Integer::Four(65535)));
```
*/
use std::io::Error;
pub mod decode;
@ -5,6 +46,7 @@ pub mod encode;
type DataBuffer<'a> = &'a mut Vec<u8>;
type DataMap = Vec<(DataType, DataType)>;
type ResultBuffer<'a> = Result<Vec<u8>, Error>;
type ResultInteger<'a> = Result<Integer, Error>;
type ResultDataType<'a> = Result<DataType, Error>;
@ -14,10 +56,11 @@ struct DataTypeLength {
dlength: u8,
}
/// Integer types: 0,8,16,32,64,128-bits,BigNum.
#[derive(Debug, PartialEq)]
pub enum Integer {
Zero(),
One(u8),
One(i8),
Two(i16),
Four(i32),
Eight(i64),
@ -25,6 +68,7 @@ pub enum Integer {
BigNum(Vec<u8>),
}
/// Data types such as null, bool, string, etc.
#[derive(Debug, PartialEq)]
pub enum DataType {
Null,


Loading…
Cancel
Save