use super::device::Device;
use alloc::boxed::Box;
#[derive(Default)]
pub struct Socket<const ADDR_BITS: u8> {
connected_device: Option<Box<dyn Device>>,
}
impl<const ADDR_BITS: u8> Device for Socket<ADDR_BITS> {
fn with_data(_: &[u8]) -> Self {
panic!("attempting to init an empty socket with data")
}
fn init_data(&mut self, data: &[u8]) {
self.connected_device
.as_mut()
.expect("calling init device with an empty socket")
.init_data(data);
}
fn cache_current_read_data(&self, destination: &mut [u8]) {
self.connected_device
.as_ref()
.expect("calling cache_current_read_data with an empty socket")
.cache_current_read_data(destination);
}
fn read(&self, addr: u16) -> u8 {
self.connected_device
.as_ref()
.expect("calling read with an empty socket")
.read(addr)
}
fn write(&mut self, data: u8, addr: u16) {
if let Some(connected_device) = self.connected_device.as_mut() {
connected_device.write(data, addr);
}
}
fn addr_space_size() -> u32 {
2u32.pow(ADDR_BITS as u32)
}
fn addr_bits_count() -> u8 {
ADDR_BITS
}
fn addr_space_size_dyn(&self) -> u32 {
2u32.pow(ADDR_BITS as u32)
}
fn addr_bits_count_dyn(&self) -> u8 {
ADDR_BITS
}
fn is_connected(&self) -> bool {
self.connected_device.is_some()
}
}
impl<const ADDR_BITS: u8> Socket<ADDR_BITS> {
pub fn new() -> Self {
Self::default()
}
pub fn is_device_compatible(&self, device: &dyn Device) -> bool {
device.addr_bits_count_dyn() == ADDR_BITS
}
pub fn disconnect_device(&mut self) -> Option<Box<dyn Device>> {
self.connected_device.take()
}
pub fn connect_device(&mut self, device_to_connect: Box<dyn Device>) {
let _ = self.disconnect_device();
assert!(
self.is_device_compatible(device_to_connect.as_ref()),
"Trying to connect a memory mapped device to an incompatible socket"
);
self.connected_device = Some(device_to_connect);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::size_const::*;
use crate::Ram;
#[test]
#[should_panic(expected = "Trying to connect a memory mapped device to an incompatible socket")]
fn connectdevicetoincompatiblesocket_panics() {
let ram = Box::new(Ram::<{ SIZE_64K }>::new());
let mut socket = Socket::<4>::new();
socket.connect_device(ram);
}
#[test]
fn connectdevicetocompatiblesocket_doesntpanic() {
let ram = Box::new(Ram::<16>::new());
let mut socket = Socket::<4>::new();
socket.connect_device(ram);
let ram = Box::new(Ram::<{ SIZE_64K }>::new());
let mut socket = Socket::<16>::new();
socket.connect_device(ram);
}
#[test]
fn connectram_fillwithdata_datacorrect() {
let ram = Box::new(Ram::<{ SIZE_64K }>::new());
let mut socket = Socket::<16>::new();
socket.connect_device(ram);
for i in 0..u16::MAX {
socket.write(i as u8, i);
}
for i in 0..u16::MAX {
assert_eq!(socket.read(i), i as u8, "\nerroneous data at {}", i);
}
}
}