mod read;
mod write;
use crate::*;
pub const PACKET_SIG: [u8; 8] = [236u8, 37u8, 94u8, 136u8, 236u8, 37u8, 94u8, 136u8];
#[derive(Debug)]
pub struct PacketHeader {
pub size: u64,
pub blocks_len: u64,
pub payload: bool,
pub crc: u32,
}
impl PacketHeader {
pub const SIZE: u64 = (
PACKET_SIG.len()
+ std::mem::size_of::<u64>()
+ std::mem::size_of::<u64>()
+ 1
+ std::mem::size_of::<u32>()
) as u64;
pub(crate) fn from_lengths(blocks_len: u64, payload_len: u64, has_payload: bool) -> Self {
let size = blocks_len + payload_len;
let mut hasher = crc32fast::Hasher::new();
hasher.update(&size.to_le_bytes());
hasher.update(&blocks_len.to_le_bytes());
hasher.update(if has_payload { &[1] } else { &[0] });
let crc = hasher.finalize();
Self {
size,
blocks_len,
payload: has_payload,
crc,
}
}
pub fn new<B: BlockDef, Inner: PayloadInnerDef>(
blocks: &[B],
payload: Option<&Inner>,
ctx: &mut <Inner as PayloadSchema>::Context<'_>,
) -> std::io::Result<Self> {
let blocks_len: u64 = blocks.iter().map(|blk| blk.size()).sum();
let payload_len: u64 = payload
.as_ref()
.map(|payload| Self::payload_size(*payload, ctx))
.unwrap_or(Ok(0))?;
Ok(Self::from_lengths(
blocks_len,
payload_len,
payload.is_some(),
))
}
pub fn payload_size<Inner: PayloadInnerDef>(
payload: &Inner,
ctx: &mut <Inner as PayloadSchema>::Context<'_>,
) -> std::io::Result<u64> {
let payload_header_len: u64 = PayloadHeader::ssize::<Inner>(payload).map(|s| s as u64)?;
let payload_body_len: u64 = payload.size(ctx)?;
Ok(payload_body_len + payload_header_len)
}
pub fn get_pos(buffer: &[u8]) -> Option<usize> {
let mut offset = 0;
while buffer.len() > offset + PACKET_SIG.len() {
if buffer[offset..].starts_with(&PACKET_SIG) {
return Some(offset);
} else {
offset += 1;
continue;
}
}
None
}
pub fn is_not_enought(buffer: &[u8]) -> Option<usize> {
if buffer.len() >= Self::SIZE as usize {
None
} else {
Some(Self::SIZE as usize - buffer.len())
}
}
}
impl StaticSize for PacketHeader {
fn ssize() -> u64 {
PacketHeader::SIZE
}
}
impl CrcU32 for PacketHeader {
fn crc(&self) -> [u8; 4] {
let mut hasher = crc32fast::Hasher::new();
hasher.update(&self.size.to_le_bytes());
hasher.update(&self.blocks_len.to_le_bytes());
hasher.update(if self.payload { &[1] } else { &[0] });
hasher.finalize().to_le_bytes()
}
}