use crate::*;
impl ReadFrom for Slot {
fn read<T: std::io::Read, S: ProtocolSchema>(buf: &mut T) -> Result<Self, Error> {
let header = SlotHeader::read::<_, S>(buf)?;
let mut lenghts = Vec::with_capacity(header.capacity as usize);
for _ in 0..header.capacity {
let mut packet_len = [0u8; 8usize];
buf.read_exact(&mut packet_len)?;
lenghts.push(u64::from_le_bytes(packet_len));
}
let mut crc = [0u8; 4usize];
buf.read_exact(&mut crc)?;
let slot = Slot::new(lenghts, header.capacity, crc);
if slot.crc == slot.crc() {
Ok(slot)
} else {
Err(Error::CrcDismatch)
}
}
}
impl TryReadFrom for Slot {
fn try_read<T: std::io::Read + std::io::Seek, S: ProtocolSchema>(
buf: &mut T,
) -> Result<ReadStatus<Self>, Error> {
let start_pos = buf.stream_position()?;
let len = buf.seek(std::io::SeekFrom::End(0))? - start_pos;
buf.seek(std::io::SeekFrom::Start(start_pos))?;
let header = match SlotHeader::try_read::<_, S>(buf)? {
ReadStatus::Success(header) => header,
ReadStatus::NotEnoughData(needed) => return Ok(ReadStatus::NotEnoughData(needed)),
};
let needed = SlotHeader::ssize()
+ header.capacity * std::mem::size_of::<u64>() as u64
+ std::mem::size_of::<u32>() as u64;
if len < needed {
buf.seek(std::io::SeekFrom::Start(start_pos))?;
return Ok(ReadStatus::NotEnoughData(PacketHeader::ssize() - needed));
}
let mut lenghts = Vec::with_capacity(header.capacity as usize);
for _ in 0..header.capacity {
let mut packet_len = [0u8; 8usize];
buf.read_exact(&mut packet_len)?;
lenghts.push(u64::from_le_bytes(packet_len));
}
let mut crc = [0u8; 4usize];
buf.read_exact(&mut crc)?;
let slot = Slot::new(lenghts, header.capacity, crc);
if slot.crc == slot.crc() {
Ok(ReadStatus::Success(slot))
} else {
Err(Error::CrcDismatch)
}
}
}
#[cfg(test)]
mod tests {
use crate::{CrcU32, Error, ReadFrom, ReadStatus, Slot, TryReadFrom, WriteTo};
use std::io::{Cursor, Seek};
fn sample_slot() -> Slot {
let mut slot = Slot::new(vec![12, 34, 0], 3, [0; 4]);
slot.overwrite_crc();
slot
}
fn encoded_slot() -> Vec<u8> {
let slot = sample_slot();
let mut out = Vec::new();
slot.write_all(&mut out).expect("slot serialization");
out
}
#[test]
fn slot_read_and_try_read_roundtrip() {
let bytes = encoded_slot();
let mut cursor = Cursor::new(bytes.clone());
let read = Slot::read::<_, ()>(&mut cursor).expect("slot read");
assert_eq!(read.capacity, 3);
assert_eq!(read.lenghts, vec![12, 34, 0]);
assert_eq!(read.crc, read.crc());
let mut cursor = Cursor::new(bytes);
match Slot::try_read::<_, ()>(&mut cursor).expect("slot try_read") {
ReadStatus::Success(read) => {
assert_eq!(read.capacity, 3);
assert_eq!(read.lenghts, vec![12, 34, 0]);
}
ReadStatus::NotEnoughData(_) => panic!("expected Success"),
}
}
#[test]
fn slot_read_and_try_read_detect_crc_error() {
let mut bytes = encoded_slot();
let last = bytes.len() - 1;
bytes[last] ^= 0xFF;
let mut cursor = Cursor::new(bytes.clone());
assert!(matches!(
Slot::read::<_, ()>(&mut cursor),
Err(Error::CrcDismatch)
));
let mut cursor = Cursor::new(bytes);
assert!(matches!(
Slot::try_read::<_, ()>(&mut cursor),
Err(Error::CrcDismatch)
));
}
#[test]
fn slot_try_read_not_enough_keeps_position() {
let bytes = encoded_slot();
let short = bytes[..8].to_vec();
let mut cursor = Cursor::new(short);
match Slot::try_read::<_, ()>(&mut cursor).expect("not enough data should not fail") {
ReadStatus::NotEnoughData(_) => {}
ReadStatus::Success(_) => panic!("expected NotEnoughData"),
}
assert_eq!(cursor.stream_position().expect("pos"), 0);
}
}