use std::io::{Cursor, Write};
use anyhow::{bail, Context, Result};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use super::Value;
const NULL_ID: u8 = 0x01;
const BOOL_FALSE_ID: u8 = 0x02;
const BOOL_TRUE_ID: u8 = 0x03;
const INT64_ID: u8 = 0x04;
const STR_ID: u8 = 0x05;
pub fn d_encode_row(values: &[Value]) -> Vec<u8> {
let mut bytes = Vec::new();
for value in values {
match value {
Value::Null => bytes.write_u8(NULL_ID).unwrap(),
Value::Bool(b) => bytes
.write_u8(if *b { BOOL_TRUE_ID } else { BOOL_FALSE_ID })
.unwrap(),
Value::Int(i) => {
bytes.write_u8(INT64_ID).unwrap();
bytes.write_i64::<BigEndian>(*i).unwrap();
}
Value::String(s) => {
bytes.write_u8(STR_ID).unwrap();
bytes.write(&s.as_bytes()).unwrap();
bytes.write_u8(0).unwrap();
}
}
}
bytes
}
pub fn d_decode_row(bytes: &[u8]) -> Result<Vec<Value>> {
let mut c = Cursor::new(bytes);
let mut values = Vec::new();
while let Ok(b) = c.read_u8() {
values.push(match b {
NULL_ID => Value::Null,
BOOL_FALSE_ID => Value::Bool(false),
BOOL_TRUE_ID => Value::Bool(true),
INT64_ID => Value::Int(c.read_i64::<BigEndian>().context("failed to decode INT")?),
STR_ID => {
let mut v = Vec::new();
loop {
let b = c.read_u8().context("improperly terminated TEXT")?;
if b != 0 {
v.push(b);
} else {
break;
}
}
Value::String(String::from_utf8(v).context("failed to decode TEXT as utf8")?)
}
_ => bail!("invalid value type byte {b:x?}"),
})
}
Ok(values)
}