first commit
This commit is contained in:
commit
deb12ed037
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/target
|
16
Cargo.lock
generated
Normal file
16
Cargo.lock
generated
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "plabble-serializer"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
]
|
7
Cargo.toml
Normal file
7
Cargo.toml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[package]
|
||||||
|
name = "plabble-serializer"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
log = "0.4.25"
|
1
src/lib.rs
Normal file
1
src/lib.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
mod schema;
|
242
src/schema/deserializer.rs
Normal file
242
src/schema/deserializer.rs
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
dyn_int, LengthDetermination, OptionalCondition, ParseError, ParseResult, SchemaDataType, ValueDataType
|
||||||
|
};
|
||||||
|
|
||||||
|
impl SchemaDataType {
|
||||||
|
pub fn parse(
|
||||||
|
&self,
|
||||||
|
data: &[u8],
|
||||||
|
bit_start: usize,
|
||||||
|
context: Option<&BTreeMap<usize, ValueDataType>>,
|
||||||
|
) -> Result<ParseResult, ParseError> {
|
||||||
|
// if bit start > 0, make sure the datatype supports that
|
||||||
|
if bit_start > 0 {
|
||||||
|
match self {
|
||||||
|
SchemaDataType::U4 => (),
|
||||||
|
SchemaDataType::I4 => (),
|
||||||
|
SchemaDataType::BitFlag => (),
|
||||||
|
SchemaDataType::Object(_) => (),
|
||||||
|
SchemaDataType::Array(..) => (),
|
||||||
|
_ => return Err(ParseError::InvalidBitStart),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
match self {
|
||||||
|
SchemaDataType::Array(schema_data_type, length_determination) => {
|
||||||
|
let length = match length_determination {
|
||||||
|
LengthDetermination::AvailableDataLength => data.len(),
|
||||||
|
LengthDetermination::NumberWithKey(nr) => context_get_length(context, *nr)?,
|
||||||
|
LengthDetermination::Fixed(len) => *len,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut context = BTreeMap::new();
|
||||||
|
let mut offset = 0;
|
||||||
|
let mut bit_start = bit_start;
|
||||||
|
for key in 0..length {
|
||||||
|
let parsed =
|
||||||
|
schema_data_type.parse(&data[offset..], bit_start, Some(&context))?;
|
||||||
|
offset += parsed.0;
|
||||||
|
context.insert(key, parsed.1);
|
||||||
|
bit_start = parsed.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
let items = context.into_values().collect();
|
||||||
|
Ok(ParseResult(offset, ValueDataType::Array(items), bit_start))
|
||||||
|
}
|
||||||
|
SchemaDataType::U4 => {
|
||||||
|
let start = next_bitstart_and_byte_read(bit_start, 4)?;
|
||||||
|
if bit_start > 4 { // TODO not sure if this check is reduntant
|
||||||
|
Err(ParseError::InvalidBitStart)
|
||||||
|
} else {
|
||||||
|
let val = u8::from_be_bytes([data[0]]);
|
||||||
|
let mask = 0xF << bit_start;
|
||||||
|
let result = (val & mask) >> bit_start;
|
||||||
|
let bytes_read = if start.1 { 1 } else { 0 };
|
||||||
|
Ok(ParseResult(bytes_read, ValueDataType::U4(result), start.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SchemaDataType::I4 => {
|
||||||
|
let start = next_bitstart_and_byte_read(bit_start, 4)?;
|
||||||
|
if bit_start > 4 { // TODO not sure if this check is reduntant
|
||||||
|
Err(ParseError::InvalidBitStart)
|
||||||
|
} else {
|
||||||
|
let val = i8::from_be_bytes([data[0]]);
|
||||||
|
let mask = 0xF << bit_start;
|
||||||
|
let result = (val & mask) >> bit_start;
|
||||||
|
let bytes_read = if start.1 { 1 } else { 0 };
|
||||||
|
Ok(ParseResult(
|
||||||
|
bytes_read,
|
||||||
|
ValueDataType::I4(result as i8),
|
||||||
|
start.0,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SchemaDataType::U8 => Ok(ParseResult(1, ValueDataType::U8(data[0]), bit_start)),
|
||||||
|
SchemaDataType::I8 => Ok(ParseResult(1, ValueDataType::I8(data[0] as i8), bit_start)),
|
||||||
|
SchemaDataType::U16 => data
|
||||||
|
.get(0..2)
|
||||||
|
.and_then(|b| b.try_into().ok())
|
||||||
|
.map(|bytes| {
|
||||||
|
ParseResult(2, ValueDataType::U16(u16::from_be_bytes(bytes)), bit_start)
|
||||||
|
})
|
||||||
|
.ok_or_else(|| ParseError::NotEnoughBytes(2, data.len())),
|
||||||
|
|
||||||
|
SchemaDataType::I16 => data
|
||||||
|
.get(0..2)
|
||||||
|
.and_then(|b| b.try_into().ok())
|
||||||
|
.map(|bytes| {
|
||||||
|
ParseResult(2, ValueDataType::I16(i16::from_be_bytes(bytes)), bit_start)
|
||||||
|
})
|
||||||
|
.ok_or_else(|| ParseError::NotEnoughBytes(2, data.len())),
|
||||||
|
|
||||||
|
SchemaDataType::U32 => data
|
||||||
|
.get(0..4)
|
||||||
|
.and_then(|b| b.try_into().ok())
|
||||||
|
.map(|bytes| {
|
||||||
|
ParseResult(4, ValueDataType::U32(u32::from_be_bytes(bytes)), bit_start)
|
||||||
|
})
|
||||||
|
.ok_or_else(|| ParseError::NotEnoughBytes(4, data.len())),
|
||||||
|
|
||||||
|
SchemaDataType::I32 => data
|
||||||
|
.get(0..4)
|
||||||
|
.and_then(|b| b.try_into().ok())
|
||||||
|
.map(|bytes| {
|
||||||
|
ParseResult(4, ValueDataType::I32(i32::from_be_bytes(bytes)), bit_start)
|
||||||
|
})
|
||||||
|
.ok_or_else(|| ParseError::NotEnoughBytes(4, data.len())),
|
||||||
|
|
||||||
|
SchemaDataType::UDynamic => {
|
||||||
|
let (val, bytes_read): (u128, usize) = dyn_int::read_from_slice(data)?;
|
||||||
|
Ok(ParseResult(
|
||||||
|
bytes_read,
|
||||||
|
ValueDataType::UDynamic(val),
|
||||||
|
bit_start,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
SchemaDataType::IDynamic => {
|
||||||
|
let (val, bytes_read): (u128, usize) = dyn_int::read_from_slice(data)?;
|
||||||
|
Ok(ParseResult(
|
||||||
|
bytes_read,
|
||||||
|
ValueDataType::IDynamic(val as i128),
|
||||||
|
bit_start,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
SchemaDataType::BitFlag => {
|
||||||
|
let start = next_bitstart_and_byte_read(bit_start, 1)?;
|
||||||
|
let bit = data[0] & (1 << bit_start) != 0;
|
||||||
|
let bytes_read = if start.1 { 1 } else { 0 };
|
||||||
|
Ok(ParseResult(
|
||||||
|
bytes_read,
|
||||||
|
ValueDataType::BitFlag(bit),
|
||||||
|
start.0,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
SchemaDataType::String(length_determination) => {
|
||||||
|
let length = match length_determination {
|
||||||
|
LengthDetermination::AvailableDataLength => data.len(),
|
||||||
|
LengthDetermination::NumberWithKey(nr) => context_get_length(context, *nr)?,
|
||||||
|
LengthDetermination::Fixed(len) => *len,
|
||||||
|
};
|
||||||
|
|
||||||
|
let utf8 = data
|
||||||
|
.get(..length)
|
||||||
|
.ok_or_else(|| ParseError::NotEnoughBytes(length, data.len()))?
|
||||||
|
.to_vec();
|
||||||
|
|
||||||
|
let str: String = String::from_utf8(utf8).map_err(|_| ParseError::ParsingFailed)?;
|
||||||
|
|
||||||
|
Ok(ParseResult(length, ValueDataType::String(str), bit_start))
|
||||||
|
}
|
||||||
|
SchemaDataType::Optional(schema_data_type, optional_condition) => {
|
||||||
|
let available = match optional_condition {
|
||||||
|
OptionalCondition::IfDataAvailable => data.len() > 0,
|
||||||
|
OptionalCondition::ByBitFlag(nr) => context_is_flag_set(context, *nr)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
if available {
|
||||||
|
schema_data_type.parse(data, bit_start, context)
|
||||||
|
} else {
|
||||||
|
Ok(ParseResult(0, ValueDataType::Optional(None), bit_start))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SchemaDataType::Object(map) => {
|
||||||
|
let mut context = BTreeMap::new();
|
||||||
|
let mut offset = 0;
|
||||||
|
let mut bit_start = bit_start;
|
||||||
|
|
||||||
|
for (key, schema) in map {
|
||||||
|
let parsed = schema.parse(&data[offset..], bit_start, Some(&context))?;
|
||||||
|
offset += parsed.0;
|
||||||
|
context.insert(*key, parsed.1);
|
||||||
|
bit_start = parsed.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ParseResult(
|
||||||
|
offset,
|
||||||
|
ValueDataType::Object(context),
|
||||||
|
bit_start,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_bitstart_and_byte_read(
|
||||||
|
bit_start: usize,
|
||||||
|
bits_read: usize,
|
||||||
|
) -> Result<(usize, bool), ParseError> {
|
||||||
|
let new = bit_start + bits_read;
|
||||||
|
if new > 8 {
|
||||||
|
Err(ParseError::InvalidBitStart)
|
||||||
|
} else if new < 8 {
|
||||||
|
Ok((new, false))
|
||||||
|
} else {
|
||||||
|
Ok((0, true))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn context_is_flag_set(
|
||||||
|
context: Option<&BTreeMap<usize, ValueDataType>>,
|
||||||
|
slot: usize,
|
||||||
|
) -> Result<bool, ParseError> {
|
||||||
|
match context {
|
||||||
|
Some(context) => match context.get(&slot) {
|
||||||
|
Some(context) => {
|
||||||
|
if let ValueDataType::BitFlag(value) = context {
|
||||||
|
Ok(*value)
|
||||||
|
} else {
|
||||||
|
Err(ParseError::InvalidContext(slot))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => Err(ParseError::MissingContext(slot)),
|
||||||
|
},
|
||||||
|
None => Err(ParseError::NoContextAvailable),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn context_get_length(
|
||||||
|
context: Option<&BTreeMap<usize, ValueDataType>>,
|
||||||
|
slot: usize,
|
||||||
|
) -> Result<usize, ParseError> {
|
||||||
|
match context {
|
||||||
|
Some(context) => match context.get(&slot) {
|
||||||
|
Some(context) => match context {
|
||||||
|
ValueDataType::U4(len) => Ok(*len as usize),
|
||||||
|
ValueDataType::I4(len) => Ok(*len as usize),
|
||||||
|
ValueDataType::U8(len) => Ok(*len as usize),
|
||||||
|
ValueDataType::I8(len) => Ok(*len as usize),
|
||||||
|
ValueDataType::U16(len) => Ok(*len as usize),
|
||||||
|
ValueDataType::I16(len) => Ok(*len as usize),
|
||||||
|
ValueDataType::U32(len) => Ok(*len as usize),
|
||||||
|
ValueDataType::I32(len) => Ok(*len as usize),
|
||||||
|
ValueDataType::UDynamic(len) => Ok(*len as usize),
|
||||||
|
ValueDataType::IDynamic(len) => Ok(*len as usize),
|
||||||
|
_ => Err(ParseError::InvalidContext(slot)),
|
||||||
|
},
|
||||||
|
None => Err(ParseError::MissingContext(slot)),
|
||||||
|
},
|
||||||
|
None => Err(ParseError::NoContextAvailable),
|
||||||
|
}
|
||||||
|
}
|
136
src/schema/dyn_int.rs
Normal file
136
src/schema/dyn_int.rs
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
use crate::schema::ParseError;
|
||||||
|
|
||||||
|
/// Gives encoded size in bytes
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `nr` - number to encode
|
||||||
|
pub fn encoded_size(nr: u128) -> usize {
|
||||||
|
let mut res = 0;
|
||||||
|
let mut nr = nr;
|
||||||
|
while nr > 0 {
|
||||||
|
nr /= 128;
|
||||||
|
res += 1;
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encodes a number into a vector of bytes.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `nr` - number to encode
|
||||||
|
pub fn encode(nr: u128) -> Vec<u8> {
|
||||||
|
let mut res = Vec::new();
|
||||||
|
let mut nr = nr;
|
||||||
|
while nr > 0 {
|
||||||
|
let mut encoded = nr % 128;
|
||||||
|
nr /= 128;
|
||||||
|
if nr > 0 {
|
||||||
|
encoded |= 128;
|
||||||
|
}
|
||||||
|
res.push(encoded as u8);
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decodes a number from a slice of bytes.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `data` - slice of bytes to decode
|
||||||
|
pub fn decode(data: &[u8]) -> u128 {
|
||||||
|
let mut num = 0;
|
||||||
|
let mut multiplier = 1;
|
||||||
|
for byte in data {
|
||||||
|
num += (*byte as u128 & 127) * multiplier;
|
||||||
|
multiplier *= 128;
|
||||||
|
}
|
||||||
|
num
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decodes a number from a slice of bytes when size of encoded number is unknown, returning the number and the number of bytes read.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `data` - slice of bytes to decode number from
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// * (number, bytes read)
|
||||||
|
pub fn read_from_slice(data: &[u8]) -> Result<(u128, usize), ParseError> {
|
||||||
|
let mut idx = 0;
|
||||||
|
loop {
|
||||||
|
if idx > data.len() - 1 {
|
||||||
|
break Err(ParseError::NotEnoughBytes(idx + 1, data.len()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[idx] & 1 << 7) == 0 {
|
||||||
|
break Ok((decode(&data[..=idx]), idx + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_encode_decode_number() {
|
||||||
|
let number = 1234567890;
|
||||||
|
let encoded = encode(number);
|
||||||
|
let decoded = decode(&encoded);
|
||||||
|
assert_eq!(number, decoded);
|
||||||
|
assert_eq!(5, encoded.len()); // 1234567890 ~ 2^31, 7 bits per byte = 7 * 5 = 35
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_decode_number() {
|
||||||
|
let nr = &[216u8, 4];
|
||||||
|
let res = decode(nr);
|
||||||
|
assert_eq!(600, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_decode_number_from_larger_slice() {
|
||||||
|
let nr = &[216u8, 4, 234, 19, 74];
|
||||||
|
let res = read_from_slice(nr).unwrap();
|
||||||
|
assert_eq!((600, 2), res);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_decode_number_in_4_bytes() {
|
||||||
|
let max_nr = 268435455; // max number in 4 bytes
|
||||||
|
let encoded = encode(max_nr);
|
||||||
|
assert_eq!(4, encoded.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cant_decode_bignr_in_4_bytes() {
|
||||||
|
let max_nr = 268435456;
|
||||||
|
let encoded = encode(max_nr);
|
||||||
|
assert_ne!(4, encoded.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cant_decode_slice_that_lies() {
|
||||||
|
let slice = &[0b10111110]; // slice notes there is a second byte (7th bit, right-to-left), but there's not
|
||||||
|
let decoded = read_from_slice(slice);
|
||||||
|
assert!(decoded.is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_encode_nr_lt_128_in_1_byte() {
|
||||||
|
let encoded = encode(127);
|
||||||
|
assert_eq!(1, encoded.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_guess_encoded_size() {
|
||||||
|
let one_byte = 127;
|
||||||
|
assert_eq!(1, encoded_size(one_byte));
|
||||||
|
|
||||||
|
let two_bytes = 128;
|
||||||
|
assert_eq!(2, encoded_size(two_bytes));
|
||||||
|
|
||||||
|
let four_bytes = 268435455;
|
||||||
|
assert_eq!(4, encoded_size(four_bytes));
|
||||||
|
}
|
||||||
|
}
|
136
src/schema/mod.rs
Normal file
136
src/schema/mod.rs
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
use core::str;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
mod deserializer;
|
||||||
|
mod serializer;
|
||||||
|
pub mod dyn_int;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum SchemaDataType {
|
||||||
|
Array(Box<SchemaDataType>, LengthDetermination),
|
||||||
|
U4,
|
||||||
|
I4,
|
||||||
|
U8,
|
||||||
|
I8,
|
||||||
|
U16,
|
||||||
|
I16,
|
||||||
|
U32,
|
||||||
|
I32,
|
||||||
|
UDynamic,
|
||||||
|
IDynamic,
|
||||||
|
BitFlag,
|
||||||
|
String(LengthDetermination),
|
||||||
|
Optional(Box<SchemaDataType>, OptionalCondition),
|
||||||
|
Object(BTreeMap<usize, SchemaDataType>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ValueDataType {
|
||||||
|
Array(Vec<ValueDataType>),
|
||||||
|
U4(u8),
|
||||||
|
I4(i8),
|
||||||
|
U8(u8),
|
||||||
|
I8(i8),
|
||||||
|
U16(u16),
|
||||||
|
I16(i16),
|
||||||
|
U32(u32),
|
||||||
|
I32(i32),
|
||||||
|
UDynamic(u128),
|
||||||
|
IDynamic(i128),
|
||||||
|
BitFlag(bool),
|
||||||
|
String(String),
|
||||||
|
Optional(Option<Box<ValueDataType>>),
|
||||||
|
Object(BTreeMap<usize, ValueDataType>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum OptionalCondition {
|
||||||
|
IfDataAvailable,
|
||||||
|
ByBitFlag(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum LengthDetermination {
|
||||||
|
AvailableDataLength,
|
||||||
|
NumberWithKey(usize),
|
||||||
|
Fixed(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
// bytes read, value, new bit start
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ParseResult(usize, ValueDataType, usize);
|
||||||
|
|
||||||
|
// bytes written, bit start
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SerializeResult(usize, usize);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ParseError {
|
||||||
|
// required, actual
|
||||||
|
NotEnoughBytes(usize, usize),
|
||||||
|
InvalidBitStart,
|
||||||
|
NoContextAvailable,
|
||||||
|
MissingContext(usize),
|
||||||
|
InvalidContext(usize),
|
||||||
|
ParsingFailed,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum SerializerError {
|
||||||
|
InvalidBitStart,
|
||||||
|
InvalidValue
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test() {
|
||||||
|
let data = ValueDataType::Array(vec![
|
||||||
|
ValueDataType::U4(0),
|
||||||
|
ValueDataType::I4(-8),
|
||||||
|
ValueDataType::U4(15),
|
||||||
|
ValueDataType::I4(7),
|
||||||
|
ValueDataType::U8(255),
|
||||||
|
ValueDataType::I8(-127)
|
||||||
|
]);
|
||||||
|
|
||||||
|
let mut buff = Vec::new();
|
||||||
|
let res = data.serialize(&mut buff, 0);
|
||||||
|
|
||||||
|
println!("{:?}", res);
|
||||||
|
println!("{:?}", buff);
|
||||||
|
println!("-----");
|
||||||
|
println!("{:0>8b}", buff[0]);
|
||||||
|
|
||||||
|
println!("{:0>8b}", -1i8);
|
||||||
|
println!("{:0>8b}", 128 as u8);
|
||||||
|
|
||||||
|
|
||||||
|
let schema = SchemaDataType::Object(BTreeMap::from([
|
||||||
|
(1, SchemaDataType::U4),
|
||||||
|
(2, SchemaDataType::I4),
|
||||||
|
(3, SchemaDataType::U4),
|
||||||
|
(4, SchemaDataType::I4),
|
||||||
|
(5, SchemaDataType::U8),
|
||||||
|
(6, SchemaDataType::I8)
|
||||||
|
]));
|
||||||
|
println!("{:?}", schema);
|
||||||
|
|
||||||
|
let res = schema.parse(&buff, 0, None);
|
||||||
|
println!("{:?}", res);
|
||||||
|
todo!();
|
||||||
|
|
||||||
|
// let schema = SchemaDataType::Object(BTreeMap::from([
|
||||||
|
// (1, SchemaDataType::U4), // 4
|
||||||
|
// (2, SchemaDataType::BitFlag), //5
|
||||||
|
// (3, SchemaDataType::BitFlag), //6
|
||||||
|
// (4, SchemaDataType::BitFlag), //7
|
||||||
|
// (5, SchemaDataType::U4), //5
|
||||||
|
|
||||||
|
// ]));
|
||||||
|
|
||||||
|
// let data = [0b00000000, 1, 0];
|
||||||
|
// let res = schema.parse(&data, 0, None);
|
||||||
|
// println!("{:?}", res);
|
||||||
|
|
||||||
|
// todo!()
|
||||||
|
// given bytes and schema should produce filled schema
|
||||||
|
}
|
107
src/schema/serializer.rs
Normal file
107
src/schema/serializer.rs
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
use super::{dyn_int, SerializeResult, SerializerError, ValueDataType};
|
||||||
|
|
||||||
|
impl ValueDataType {
|
||||||
|
pub fn serialize(&self, buffer: &mut Vec<u8>, bit_start: usize) -> Result<SerializeResult, SerializerError> {
|
||||||
|
let mut len: usize = buffer.len();
|
||||||
|
match self {
|
||||||
|
ValueDataType::Array(arr) => {
|
||||||
|
let mut bit_start = bit_start;
|
||||||
|
let mut bytes_written = 0;
|
||||||
|
for item in arr {
|
||||||
|
let res = item.serialize(buffer, bit_start)?;
|
||||||
|
bytes_written += res.0;
|
||||||
|
bit_start = res.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(SerializeResult(bytes_written, bit_start))
|
||||||
|
},
|
||||||
|
ValueDataType::U4(v) => {
|
||||||
|
let (next_bit_start, bytes_written) = next_bitstart_and_byte_written(bit_start, 4)?;
|
||||||
|
if *v > 0xF {
|
||||||
|
return Err(SerializerError::InvalidValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if bit_start == 0 {
|
||||||
|
buffer.push(0); // Add an empty byte to write to
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mask = 0xF << bit_start;
|
||||||
|
buffer[len - 1] &= !mask; // Clear the bits where we are writing
|
||||||
|
buffer[len - 1] |= (*v << bit_start) & mask;
|
||||||
|
|
||||||
|
Ok(SerializeResult(bytes_written, next_bit_start))
|
||||||
|
},
|
||||||
|
ValueDataType::I4(v) => {
|
||||||
|
let (next_bit_start, bytes_written) = next_bitstart_and_byte_written(bit_start, 4)?;
|
||||||
|
if *v < -8 || *v > 7 {
|
||||||
|
return Err(SerializerError::InvalidValue); // Only values -8 to 7 are valid for 4 bits
|
||||||
|
}
|
||||||
|
|
||||||
|
if bit_start == 0 {
|
||||||
|
buffer.push(0); // Add an empty byte to write to
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the value to the correct position
|
||||||
|
let mask = 0xF << bit_start;
|
||||||
|
buffer[len - 1] &= !mask; // Clear the bits where we are writing
|
||||||
|
buffer[len - 1] |= ((*v as u8) << bit_start) & mask;
|
||||||
|
|
||||||
|
Ok(SerializeResult(bytes_written, next_bit_start))
|
||||||
|
},
|
||||||
|
ValueDataType::U8(v) => {
|
||||||
|
buffer.push(*v);
|
||||||
|
Ok(SerializeResult(1, bit_start))
|
||||||
|
},
|
||||||
|
ValueDataType::I8(v) => {
|
||||||
|
buffer.push(*v as u8);
|
||||||
|
Ok(SerializeResult(1, bit_start))
|
||||||
|
},
|
||||||
|
ValueDataType::U16(v) => {
|
||||||
|
buffer.append(&mut v.to_be_bytes().to_vec());
|
||||||
|
Ok(SerializeResult(2, bit_start))
|
||||||
|
},
|
||||||
|
ValueDataType::I16(v) => {
|
||||||
|
buffer.append(&mut v.to_be_bytes().to_vec());
|
||||||
|
Ok(SerializeResult(2, bit_start))
|
||||||
|
},
|
||||||
|
ValueDataType::U32(v) => {
|
||||||
|
buffer.append(&mut v.to_be_bytes().to_vec());
|
||||||
|
Ok(SerializeResult(4, bit_start))
|
||||||
|
},
|
||||||
|
ValueDataType::I32(v) => {
|
||||||
|
buffer.append(&mut v.to_be_bytes().to_vec());
|
||||||
|
Ok(SerializeResult(4, bit_start))
|
||||||
|
},
|
||||||
|
ValueDataType::UDynamic(v) => {
|
||||||
|
let mut encoded = dyn_int::encode(*v);
|
||||||
|
buffer.append(&mut encoded);
|
||||||
|
Ok(SerializeResult(encoded.len(), bit_start))
|
||||||
|
},
|
||||||
|
ValueDataType::IDynamic(v) => {
|
||||||
|
let mut encoded = dyn_int::encode(*v as u128);
|
||||||
|
buffer.append(&mut encoded);
|
||||||
|
Ok(SerializeResult(encoded.len(), bit_start))
|
||||||
|
},
|
||||||
|
ValueDataType::BitFlag(_) => todo!(),
|
||||||
|
ValueDataType::String(_) => todo!(),
|
||||||
|
ValueDataType::Optional(value_data_type) => todo!(),
|
||||||
|
ValueDataType::Object(btree_map) => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_bitstart_and_byte_written(
|
||||||
|
bit_start: usize,
|
||||||
|
bits_written: usize,
|
||||||
|
) -> Result<(usize, usize), SerializerError> {
|
||||||
|
let new = bit_start + bits_written;
|
||||||
|
if new > 8 {
|
||||||
|
Err(SerializerError::InvalidBitStart)
|
||||||
|
} else if new < 8 {
|
||||||
|
Ok((new, 0))
|
||||||
|
} else {
|
||||||
|
Ok((0, 1))
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user