Skip to content

Commit

Permalink
core: Relax lifetime constraint on msgs in I2CTransfer::transfer()
Browse files Browse the repository at this point in the history
This change enables users of `i2cdev` to create generic functions on `T:
I2CTransfer` that have output buffers constructed separately from the
`I2CMessage` array, like the following:

```rust
fn smbus_read_post_box<T>(i2c: &mut T, offset: u16, out: &mut [u8])
	where for<'a> T: I2CTransfer<'a>,
{
	let addr = offset.to_be_bytes();
	let mut messages = [
		T::Message::write(addr),
		T::Message::read(out),
	];
	i2c.transfer(&mut messages).expect("uh oh");
}
```

Before this, `messages` would not satisfy the constraints of `.transfer()`,
because `messages` does not live as long as one of the output buffers `out`:

```
error[E0597]: `messages` does not live long enough
  --> src/smbpbisensor.rs:69:19
   |
63 |     let mut messages = [
   |         ------------ binding `messages` declared here
...
69 |         .transfer(&mut messages)
   |                   ^^^^^^^^^^^^^ borrowed value does not live long enough
...
78 | }
   | -
   | |
   | `messages` dropped here while still borrowed
   | borrow might be used here, when `messages` is dropped and runs the destructor for type `[<T as I2CTransfer<'_>>::Message; 2]`
```

The error message is a little confusing, but basically `&'a mut [Self::Message]`
is forcing the array of `I2CMessage`s to match the lifetime of the buffers in
the messages, which is not strictly necessary: the array of messages can have a
different lifetime than the buffers. After this change, the above example
compiles successfully.
  • Loading branch information
peterdelevoryas committed Dec 7, 2024
1 parent 499e902 commit 3595e51
Show file tree
Hide file tree
Showing 4 changed files with 6 additions and 4 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

- Relax lifetime constraint on `I2CTransfer::transfer` `msgs` reference

## [v0.6.1] - 2024-05-09

- Properly ellide the start bit when sending a series of I2C messages as a
Expand Down
2 changes: 1 addition & 1 deletion src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ pub trait I2CTransfer<'a> {
/// Performs multiple serially chained I2C read/write transactions. On
/// success the return code is the number of successfully executed
/// transactions
fn transfer(&mut self, msgs: &'a mut [Self::Message]) -> Result<u32, Self::Error>;
fn transfer(&mut self, msgs: &mut [Self::Message]) -> Result<u32, Self::Error>;
}

/// Read/Write I2C message
Expand Down
4 changes: 2 additions & 2 deletions src/linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ impl<'a> I2CTransfer<'a> for LinuxI2CDevice {
type Message = LinuxI2CMessage<'a>;

/// Issue the provided sequence of I2C transactions
fn transfer(&mut self, messages: &'a mut [Self::Message]) -> Result<u32, LinuxI2CError> {
fn transfer(&mut self, messages: &mut [Self::Message]) -> Result<u32, LinuxI2CError> {
let msg_type = |flag: u16| flag & I2CMessageFlags::READ.bits();
let mut prev_msg_type = None;
for msg in messages.iter_mut() {
Expand Down Expand Up @@ -335,7 +335,7 @@ impl<'a> I2CTransfer<'a> for LinuxI2CBus {
type Message = LinuxI2CMessage<'a>;

/// Issue the provided sequence of I2C transactions
fn transfer(&mut self, msgs: &'a mut [Self::Message]) -> Result<u32, LinuxI2CError> {
fn transfer(&mut self, msgs: &mut [Self::Message]) -> Result<u32, LinuxI2CError> {
ffi::i2c_rdwr(self.as_raw_fd(), msgs).map_err(From::from)
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ where
type Message = MockI2CMessage<'a>;

/// Issue the provided sequence of I2C transactions
fn transfer(&mut self, messages: &'a mut [Self::Message]) -> Result<u32, Self::Error> {
fn transfer(&mut self, messages: &mut [Self::Message]) -> Result<u32, Self::Error> {
for msg in messages.iter_mut() {
match &mut msg.msg_type {
MessageType::Read(data) => self.read(data)?,
Expand Down

0 comments on commit 3595e51

Please sign in to comment.