//! Test transport with owned pending bytes, never retained caller pointers. use kaptan_spi::{CompletionError, SpiCompletion, SpiDevice}; #[derive(Debug, Eq, PartialEq)] pub(crate) enum FakeError { Start, Busy, InvalidLength, Quarantined, } pub(crate) struct FakeBus { pub response: [u8; 32], pub fail_start: bool, pub fail_completion: Option, pub busy: bool, pub starts: usize, pub cancellations: usize, pub transmitted: [u8; 32], pending: Option<([u8; 32], usize)>, quarantined: bool, } impl FakeBus { pub fn ready() -> Self { Self { response: [0; 32], fail_start: false, fail_completion: None, busy: false, starts: 0, cancellations: 0, transmitted: [0; 32], pending: None, quarantined: false, } } } impl SpiDevice for FakeBus { type StartError = FakeError; fn is_busy(error: &Self::StartError) -> bool { *error == FakeError::Busy } fn start_transfer(&mut self, transmit: &[u8]) -> Result<(), Self::StartError> { if self.quarantined { return Err(FakeError::Quarantined); } if self.pending.is_some() || self.busy { return Err(FakeError::Busy); } if self.fail_start { return Err(FakeError::Start); } if transmit.is_empty() || transmit.len() > self.response.len() { return Err(FakeError::InvalidLength); } // Simulated hardware computes its response at submission, but only the // accepted completion is allowed to copy those owned bytes to a caller. self.pending = Some((self.response, transmit.len())); self.transmitted[..transmit.len()].copy_from_slice(transmit); self.starts += 1; Ok(()) } fn complete_transfer( &mut self, completion: SpiCompletion, receive: &mut [u8], ) -> Result<(), CompletionError> { if completion == SpiCompletion::NotPending { return Err(CompletionError::NotPending); } if self.quarantined { return Err(CompletionError::Quarantined); } if completion == SpiCompletion::TransferFault { self.cancellations += 1; } let (pending, length) = self.pending.take().ok_or(CompletionError::NotActive)?; if let Some(error) = self.fail_completion.take() { self.quarantined = error == CompletionError::Quarantined; return Err(error); } if completion == SpiCompletion::TransferFault { return Err(CompletionError::TransferFault); } if receive.len() != length { return Err(CompletionError::InvalidLength); } receive.copy_from_slice(&pending[..length]); Ok(()) } }