rust-i2cdev
rust-i2cdev copied to clipboard
Make smbus_read_i2c_block_data() write into &mut Vec/[u8] rather than returning new Vec?
It may be worthwhile for smbus_read_i2c_block_data() and similar functions to write data into a preallocated buffer (of fixed size &mut [u8], or allowing the function to resize a &mut [u8]), rather than returning a new Vec
I took a look on how to implement this for the i2c_smbus_read_i2c_block_data function in src/ffi.rs and I came up with this:
pub fn i2c_smbus_read_i2c_block_data_inplace(
fd: RawFd,
register: u8,
block: &mut [u8],
) -> Result<usize, I2CError> {
let mut data = i2c_smbus_data::empty();
unsafe {
i2c_smbus_access(
fd,
I2CSMBusReadWrite::I2C_SMBUS_READ,
register,
I2CSMBusSize::I2C_SMBUS_BLOCK_DATA,
&mut data,
)?;
}
let bytes_available = data.block[0] as usize;
let bytes_written = if bytes_available >= block.len() {
// since this is a &mut [u8], we cannot resize it
// and we just override the entire container
block.len()
} else {
// otherwise, we write the amount of bytes fetched from the line
bytes_available
};
// zip allows us to be bounded by the shortest iterator,
// therefore we will never overrun the buffer
data.block[0..bytes_available]
.iter()
.zip(block.into_iter())
.for_each(|(source, destination)| {
*destination = *source;
});
// similar to the `std::io::Write::read` method
Ok(bytes_written)
}
If the caller provides a &mut [u8], then it should be assumed that the starting position of writing is at the beginning and no resizing can be done.
This would still allow for a no-alloc environment, as both the i2c_smbus_data and block would have a known size at compile time.