use arbitrary::Arbitrary;
use embedded_hal::i2c::{
self, ErrorKind, I2c, NoAcknowledgeSource, Operation, SevenBitAddress, TenBitAddress,
};
use std::marker::PhantomData;
#[derive(Debug)]
pub struct Error {
kind: ErrorKind,
}
impl Default for Error {
fn default() -> Self {
Error {
kind: ErrorKind::Other,
}
}
}
impl i2c::Error for Error {
fn kind(&self) -> ErrorKind {
self.kind
}
}
impl<'a> Arbitrary<'a> for Error {
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
use ErrorKind::*;
use NoAcknowledgeSource::*;
Ok(Error {
kind: *u.choose(&[
Bus,
ArbitrationLoss,
NoAcknowledge(Address),
NoAcknowledge(Data),
NoAcknowledge(Unknown),
Overrun,
Other,
])?,
})
}
}
#[derive(Debug, Arbitrary)]
pub struct ArbitraryI2c<T> {
read_data: Vec<u8>,
maybe_error: Vec<Result<(), Error>>,
_p: PhantomData<T>,
}
impl<T> ArbitraryI2c<T> {
fn transaction_impl(&mut self, operations: &mut [Operation<'_>]) -> Result<(), Error> {
self.maybe_error.pop().ok_or(Error::default())??;
let operation_result: Result<Vec<_>, _> = operations
.iter_mut()
.map(|x| match x {
Operation::Read(read) => {
let result: Result<Vec<_>, Error> = read
.iter_mut()
.map(|x| {
*x = self.read_data.pop().ok_or(Error::default())?;
Ok(())
})
.collect();
result
}
Operation::Write(_) => Ok(Vec::new()),
})
.collect();
operation_result.map(|_| ())
}
}
impl<T> i2c::ErrorType for ArbitraryI2c<T> {
type Error = Error;
}
impl I2c<SevenBitAddress> for ArbitraryI2c<SevenBitAddress> {
fn transaction(
&mut self,
_address: u8,
operations: &mut [Operation<'_>],
) -> Result<(), Self::Error> {
self.transaction_impl(operations)
}
}
impl I2c<TenBitAddress> for ArbitraryI2c<TenBitAddress> {
fn transaction(
&mut self,
_address: u16,
operations: &mut [Operation<'_>],
) -> Result<(), Self::Error> {
self.transaction_impl(operations)
}
}