use error::HammersbaldError;
use pref::PRef;
use byteorder::{WriteBytesExt, ByteOrder, BigEndian};
use std::io::Write;
pub struct Envelope {
buffer: Vec<u8>
}
impl Envelope {
pub fn new (payload: &[u8], previous: PRef) -> Envelope {
let mut buffer = vec!();
buffer.write_u48::<BigEndian>(previous.as_u64()).unwrap();
buffer.write(payload).unwrap();
Envelope{buffer}
}
pub fn previous(&self) -> PRef {
PRef::from(BigEndian::read_u48(&self.buffer.as_slice()[0 .. 6]))
}
pub fn payload (&self) -> &[u8] {
&self.buffer.as_slice()[6..]
}
pub fn serialize (&self, result: &mut Write) {
result.write_u24::<BigEndian>(self.buffer.len() as u32).unwrap();
result.write(self.buffer.as_slice()).unwrap();
}
pub fn deseralize(buffer: Vec<u8>) -> Envelope {
Envelope{buffer}
}
}
pub enum Payload<'e> {
Indexed(IndexedData<'e>),
Referred(Data<'e>),
Link(Link<'e>)
}
impl<'e> Payload<'e> {
pub fn serialize (&self, result: &mut Write) {
match self {
Payload::Indexed(indexed) => {
result.write_u8(0).unwrap();
indexed.serialize(result);
},
Payload::Referred(referred) => {
result.write_u8(1).unwrap();
referred.serialize(result);
},
Payload::Link(link) => {
result.write_u8(2).unwrap();
link.serialize(result);
}
}
}
pub fn deserialize(slice: &'e [u8]) -> Result<Payload, HammersbaldError> {
match slice [0] {
0 => Ok(Payload::Indexed(IndexedData::deserialize(&slice[1..]))),
1 => Ok(Payload::Referred(Data::deserialize(&slice[1..]))),
2 => Ok(Payload::Link(Link::deserialize(&slice[1..]))),
_ => Err(HammersbaldError::Corrupted("unknown payload type".to_string()))
}
}
}
pub struct Data<'e> {
pub data: &'e [u8],
referred: &'e [u8]
}
impl<'e> Data<'e> {
pub fn from_referred(referred: &[PRef]) -> Vec<u8> {
let mut rv = vec!(0u8;referred.len()*6);
for (i, r) in referred.iter().enumerate() {
BigEndian::write_u48(&mut rv[i*6 .. i*6+6], r.as_u64());
}
rv
}
pub fn new(data: &'e [u8], referred: &'e [u8]) -> Data<'e> {
Data{data, referred}
}
pub fn referred(&self) -> Vec<PRef> {
let mut referred = vec!();
for i in 0 .. self.referred.len()/6 {
let r = PRef::from(BigEndian::read_u48(&self.referred[i*6 .. i*6+6]));
referred.push(r);
}
referred
}
pub fn serialize (&self, result: &mut Write) {
result.write_u24::<BigEndian>(self.data.len() as u32).unwrap();
result.write(self.data).unwrap();
result.write(self.referred).unwrap();
}
pub fn deserialize(slice: &'e [u8]) -> Data {
let data_len = BigEndian::read_u24(&slice[0 .. 3]) as usize;
let data = &slice[3 .. 3+data_len];
let referred = &slice[3+data_len .. ];
Data {data, referred }
}
}
pub struct IndexedData<'e> {
pub key: &'e [u8],
pub data: Data<'e>
}
impl<'e> IndexedData<'e> {
pub fn new (key: &'e [u8], data: Data<'e>) -> IndexedData<'e> {
IndexedData {key, data}
}
pub fn serialize (&self, result: &mut Write) {
result.write_u8(self.key.len() as u8).unwrap();
result.write(self.key).unwrap();
self.data.serialize(result);
}
pub fn deserialize(slice: &'e [u8]) -> IndexedData<'e> {
let key_len = slice[0] as usize;
let key = &slice[1 .. key_len+1];
let data = Data::deserialize(&slice[key_len+1 ..]);
IndexedData{key, data }
}
}
pub struct Link<'e> {
links: &'e [u8]
}
impl<'e> Link<'e> {
pub fn from_slots(slots: &[(u32, PRef)]) -> Vec<u8> {
let mut links = vec!(0u8;10*slots.len());
for (i, slot) in slots.iter().enumerate() {
BigEndian::write_u32(&mut links[i*10 .. i*10+4], slot.0);
BigEndian::write_u48(&mut links[i*10+4 .. i*10+10], slot.1.as_u64());
}
links
}
pub fn slots(&self) -> Vec<(u32, PRef)> {
let mut slots = vec!();
for i in 0 .. self.links.len()/10 {
let hash = BigEndian::read_u32(&self.links[i*10..i*10+4]);
let pref = PRef::from(BigEndian::read_u48(&self.links[i*10+4..i*10+10]));
slots.push((hash, pref));
}
slots
}
pub fn serialize (&self, write: &mut Write) {
write.write(&self.links).unwrap();
}
pub fn deserialize(slice: &'e [u8]) -> Link<'e> {
Link{links: slice}
}
}