use std::io::Write;
use byteorder::{ByteOrder, LittleEndian};
use crate::{
error::Error,
sd::{Array, Object, Value},
Result
};
fn get_value_type_code(val: &Value) -> u8
{
match val {
Value::Null => 0x0,
Value::Bool(_) => 0x1,
Value::Uint8(_) => 0x2,
Value::Uint16(_) => 0x3,
Value::Uint32(_) => 0x4,
Value::Uint64(_) => 0x5,
Value::Int8(_) => 0x6,
Value::Int16(_) => 0x7,
Value::Int32(_) => 0x8,
Value::Int64(_) => 0x9,
Value::Float(_) => 0xA,
Value::Double(_) => 0xB,
Value::String(_) => 0xC,
Value::Array(_) => 0xD,
Value::Object(_) => 0xE
}
}
fn write_value(val: &Value) -> Result<Vec<u8>>
{
let mut buf = Vec::new();
match val {
Value::Null => (),
Value::Bool(b) => {
if *b {
buf.push(1);
} else {
buf.push(0);
}
},
Value::Uint8(v) => buf.push(*v),
Value::Uint16(v) => {
let mut b: [u8; 2] = [0; 2];
LittleEndian::write_u16(&mut b, *v);
buf.extend_from_slice(&b);
},
Value::Uint32(v) => {
let mut b: [u8; 4] = [0; 4];
LittleEndian::write_u32(&mut b, *v);
buf.extend_from_slice(&b);
},
Value::Uint64(v) => {
let mut b: [u8; 8] = [0; 8];
LittleEndian::write_u64(&mut b, *v);
buf.extend_from_slice(&b);
},
Value::Int8(v) => buf.push(*v as u8),
Value::Int16(v) => {
let mut b: [u8; 2] = [0; 2];
LittleEndian::write_i16(&mut b, *v);
buf.extend_from_slice(&b);
},
Value::Int32(v) => {
let mut b: [u8; 4] = [0; 4];
LittleEndian::write_i32(&mut b, *v);
buf.extend_from_slice(&b);
},
Value::Int64(v) => {
let mut b: [u8; 8] = [0; 8];
LittleEndian::write_i64(&mut b, *v);
buf.extend_from_slice(&b);
},
Value::Float(v) => {
let mut b: [u8; 4] = [0; 4];
LittleEndian::write_f32(&mut b, *v);
buf.extend_from_slice(&b);
},
Value::Double(v) => {
let mut b: [u8; 8] = [0; 8];
LittleEndian::write_f64(&mut b, *v);
buf.extend_from_slice(&b);
},
Value::String(s) => {
buf.extend_from_slice(s.as_bytes());
buf.push(0x0); },
Value::Array(arr) => buf.append(&mut write_array(arr)?),
Value::Object(obj) => buf.append(&mut write_object(obj)?)
}
return Ok(buf);
}
fn write_object(obj: &Object) -> Result<Vec<u8>>
{
let mut v: Vec<u8> = Vec::new();
let count = obj.prop_count();
if count > 255 {
return Err(Error::PropCountExceeded(count));
}
v.push(count as u8);
for hash in obj.get_keys() {
let val = &obj[*hash];
let mut head: [u8; 9] = [0; 9];
LittleEndian::write_u64(&mut head[0..8], *hash);
head[8] = get_value_type_code(val);
v.extend_from_slice(&head);
v.append(&mut write_value(val)?);
}
return Ok(v);
}
fn write_array(arr: &Array) -> Result<Vec<u8>>
{
let mut v: Vec<u8> = Vec::new();
let count = arr.len();
if count > 255 {
return Err(Error::PropCountExceeded(count));
}
v.push(count as u8);
for i in 0..count {
let val = &arr[i];
v.push(get_value_type_code(val));
v.append(&mut write_value(val)?);
}
return Ok(v);
}
pub fn write_structured_data<TWrite: Write>(dest: &mut TWrite, obj: &Object) -> Result<()>
{
let bytes = write_object(obj)?;
dest.write(&bytes)?;
return Ok(());
}