Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core: Relax lifetime constraint on msgs in I2CTransfer::transfer() #89

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

peterdelevoryas
Copy link

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:

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 I2CMessages 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.

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.
@peterdelevoryas peterdelevoryas requested a review from a team as a code owner December 4, 2024 22:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant