Open nyanpasu64 opened 1 year ago
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.
It may be worthwhile for every time. This would save allocations, but would probably be an insignificant micro-optimization (unless you were running in a no-alloc environment or similar).
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