use byteorder::{ByteOrder, NetworkEndian};
use crate::base::header::{offsets, Header};
use crate::types::{Flags, ImmutableData, Kind, MutableData};
pub struct WireHeader<T: ImmutableData> {
pub(crate) buff: T,
}
impl<T: ImmutableData> From<&WireHeader<T>> for Header {
fn from(wh: &WireHeader<T>) -> Header {
Header::new(wh.application_id(), wh.kind(), wh.index(), wh.flags())
}
}
impl<T: ImmutableData> WireHeader<T> {
pub fn new(buff: T) -> Self {
Self { buff }
}
pub fn protocol_version(&self) -> u16 {
NetworkEndian::read_u16(&self.buff.as_ref()[offsets::PROTO_VERSION..])
}
pub fn application_id(&self) -> u16 {
NetworkEndian::read_u16(&self.buff.as_ref()[offsets::APPLICATION_ID..])
}
pub fn kind(&self) -> Kind {
let raw = NetworkEndian::read_u16(&self.buff.as_ref()[offsets::OBJECT_KIND..]);
Kind::from(raw)
}
pub fn flags(&self) -> Flags {
let raw = NetworkEndian::read_u16(&self.buff.as_ref()[offsets::FLAGS..]);
unsafe { Flags::from_bits_unchecked(raw) }
}
pub fn index(&self) -> u16 {
NetworkEndian::read_u16(&self.buff.as_ref()[offsets::INDEX..])
}
pub fn data_len(&self) -> usize {
NetworkEndian::read_u16(&self.buff.as_ref()[offsets::DATA_LEN..]) as usize
}
pub fn private_options_len(&self) -> usize {
NetworkEndian::read_u16(&self.buff.as_ref()[offsets::PRIVATE_OPTIONS_LEN..]) as usize
}
pub fn public_options_len(&self) -> usize {
NetworkEndian::read_u16(&self.buff.as_ref()[offsets::PUBLIC_OPTIONS_LEN..]) as usize
}
}
impl<T: MutableData> WireHeader<T> {
pub fn encode(&mut self, h: &Header) {
self.set_protocol_version(h.protocol_version());
self.set_application_id(h.application_id());
self.set_kind(h.kind());
self.set_flags(h.flags());
self.set_index(h.index());
}
pub fn set_protocol_version(&mut self, version: u16) {
NetworkEndian::write_u16(&mut self.buff.as_mut()[offsets::PROTO_VERSION..], version)
}
pub fn set_application_id(&mut self, application_id: u16) {
NetworkEndian::write_u16(
&mut self.buff.as_mut()[offsets::APPLICATION_ID..],
application_id,
)
}
pub fn set_flags(&mut self, flags: Flags) {
NetworkEndian::write_u16(&mut self.buff.as_mut()[offsets::FLAGS..], flags.bits())
}
pub fn set_kind(&mut self, kind: Kind) {
NetworkEndian::write_u16(&mut self.buff.as_mut()[offsets::OBJECT_KIND..], kind.into())
}
pub fn set_index(&mut self, index: u16) {
NetworkEndian::write_u16(&mut self.buff.as_mut()[offsets::INDEX..], index)
}
pub fn set_data_len(&mut self, data_len: usize) {
NetworkEndian::write_u16(
&mut self.buff.as_mut()[offsets::DATA_LEN..],
data_len as u16,
)
}
pub fn set_private_options_len(&mut self, private_options_len: usize) {
NetworkEndian::write_u16(
&mut self.buff.as_mut()[offsets::PRIVATE_OPTIONS_LEN..],
private_options_len as u16,
)
}
pub fn set_public_options_len(&mut self, public_options_len: usize) {
NetworkEndian::write_u16(
&mut self.buff.as_mut()[offsets::PUBLIC_OPTIONS_LEN..],
public_options_len as u16,
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::base::header::{Header, HEADER_LEN};
use crate::types::PageKind;
#[test]
fn test_encode_wire_header() {
let h = Header::new(0, PageKind::Generic.into(), 1, Flags::SECONDARY);
let mut h1 = WireHeader::new([0u8; HEADER_LEN]);
h1.encode(&h);
let h2 = Header::from(&h1);
assert_eq!(h, h2);
}
}