use std::io;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct SlotInfo {
pub num: u8,
pub module_ready: bool,
}
pub trait CaDevice {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize>;
fn write(&mut self, buf: &[u8]) -> io::Result<()>;
fn reset(&mut self) -> io::Result<()>;
fn slot_info(&mut self) -> io::Result<SlotInfo>;
fn poll(&mut self, timeout: std::time::Duration) -> io::Result<bool>;
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DeviceOp {
Write(Vec<u8>),
Reset,
SlotInfo,
}
#[derive(Debug, Default)]
pub struct MockCaDevice {
pub inbound: std::collections::VecDeque<Vec<u8>>,
pub ops: Vec<DeviceOp>,
pub slot: SlotInfo,
}
impl MockCaDevice {
#[must_use]
pub fn new(inbound: impl IntoIterator<Item = Vec<u8>>) -> Self {
Self {
inbound: inbound.into_iter().collect(),
ops: Vec::new(),
slot: SlotInfo {
num: 0,
module_ready: true,
},
}
}
#[must_use]
pub fn written(&self) -> Vec<u8> {
self.ops
.iter()
.filter_map(|o| match o {
DeviceOp::Write(b) => Some(b.clone()),
_ => None,
})
.flatten()
.collect()
}
}
impl CaDevice for MockCaDevice {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self.inbound.pop_front() {
Some(frame) => {
let n = frame.len().min(buf.len());
buf[..n].copy_from_slice(&frame[..n]);
Ok(n)
}
None => Ok(0),
}
}
fn write(&mut self, buf: &[u8]) -> io::Result<()> {
self.ops.push(DeviceOp::Write(buf.to_vec()));
Ok(())
}
fn reset(&mut self) -> io::Result<()> {
self.ops.push(DeviceOp::Reset);
Ok(())
}
fn slot_info(&mut self) -> io::Result<SlotInfo> {
self.ops.push(DeviceOp::SlotInfo);
Ok(self.slot)
}
fn poll(&mut self, _timeout: std::time::Duration) -> io::Result<bool> {
Ok(!self.inbound.is_empty())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mock_records_writes_and_replays_inbound() {
let mut dev = MockCaDevice::new([vec![0x01, 0x02], vec![0x03]]);
dev.write(&[0xAA, 0xBB]).unwrap();
dev.reset().unwrap();
let mut buf = [0u8; 16];
assert_eq!(dev.read(&mut buf).unwrap(), 2);
assert_eq!(&buf[..2], &[0x01, 0x02]);
assert_eq!(dev.read(&mut buf).unwrap(), 1);
assert_eq!(dev.read(&mut buf).unwrap(), 0); assert_eq!(dev.written(), vec![0xAA, 0xBB]);
assert_eq!(dev.ops[1], DeviceOp::Reset);
}
}