From e6fbc13137ea1a16bfb14afa02e8403268af24a5 Mon Sep 17 00:00:00 2001 From: Peter Delevoryas Date: Wed, 4 Dec 2024 14:12:25 -0800 Subject: [PATCH] core: Relax lifetime constraint on `msgs` in `I2CTransfer::transfer()` 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(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 `[>::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. --- CHANGELOG.md | 2 ++ src/core.rs | 2 +- src/linux.rs | 4 ++-- src/mock.rs | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b09ec494..956fe90b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/src/core.rs b/src/core.rs index 10a3abbb..b9456e44 100644 --- a/src/core.rs +++ b/src/core.rs @@ -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; + fn transfer(&mut self, msgs: &mut [Self::Message]) -> Result; } /// Read/Write I2C message diff --git a/src/linux.rs b/src/linux.rs index 1c68be37..1917eacd 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -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 { + fn transfer(&mut self, messages: &mut [Self::Message]) -> Result { let msg_type = |flag: u16| flag & I2CMessageFlags::READ.bits(); let mut prev_msg_type = None; for msg in messages.iter_mut() { @@ -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 { + fn transfer(&mut self, msgs: &mut [Self::Message]) -> Result { ffi::i2c_rdwr(self.as_raw_fd(), msgs).map_err(From::from) } } diff --git a/src/mock.rs b/src/mock.rs index ff52e803..45d3fb29 100644 --- a/src/mock.rs +++ b/src/mock.rs @@ -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 { + fn transfer(&mut self, messages: &mut [Self::Message]) -> Result { for msg in messages.iter_mut() { match &mut msg.msg_type { MessageType::Read(data) => self.read(data)?,