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

async/i2c: fix lifetimes on transaction() #363

Merged
merged 1 commit into from
Feb 15, 2022

Conversation

Dirbaio
Copy link
Member

@Dirbaio Dirbaio commented Feb 14, 2022

Trying to implement i2c for a shared i2c bus behind an async mutex yielded lots of cursed lifetime errors, because &'a mut [Operation<'b>] is invariant on 'b, not covariant as one would expect...

To fix this, the GAT future needs two lifetimes. Also counterintuitively, the future must be + 'a, but NOT + 'b. Then AddressMode: 'static is needed because Rust wants annoying where A: 'a bounds otherwise.

The async SPI PR has the same issue, will fix later. #347

With these fixes, implementing i2c on a mutex works nicely now:

struct SharedI2c<T>(tokio::sync::Mutex<T>);

impl<T: ErrorType> ErrorType for SharedI2c<T> {
    type Error = T::Error;
}

impl<A: AddressMode, T: I2c<A>> I2c<A> for SharedI2c<T> {
    type ReadFuture<'a>
    where
        Self: 'a,
    = impl Future<Output = Result<(), Self::Error>> + 'a;

    fn read<'a>(&'a mut self, address: A, read: &'a mut [u8]) -> Self::ReadFuture<'a> {
        async move { self.0.lock().await.read(address, read).await }
    }

    type WriteFuture<'a>
    where
        Self: 'a,
    = impl Future<Output = Result<(), Self::Error>> + 'a;

    fn write<'a>(&'a mut self, address: A, write: &'a [u8]) -> Self::WriteFuture<'a> {
        async move { self.0.lock().await.write(address, write).await }
    }

    type WriteReadFuture<'a>
    where
        Self: 'a,
    = impl Future<Output = Result<(), Self::Error>> + 'a;

    fn write_read<'a>(
        &'a mut self,
        address: A,
        write: &'a [u8],
        read: &'a mut [u8],
    ) -> Self::WriteReadFuture<'a> {
        async move { self.0.lock().await.write_read(address, write, read).await }
    }

    type TransactionFuture<'a, 'b>
    where
        Self: 'a,
        'b: 'a,
    = impl Future<Output = Result<(), Self::Error>> + 'a;

    fn transaction<'a, 'b>(
        &'a mut self,
        address: A,
        operations: &'a mut [Operation<'b>],
    ) -> Self::TransactionFuture<'a, 'b> {
        async move { self.0.lock().await.transaction(address, operations).await }
    }
}

cc @matoushybl

@Dirbaio Dirbaio requested a review from a team as a code owner February 14, 2022 23:21
@rust-highfive
Copy link

r? @eldruin

(rust-highfive has picked a reviewer for you, use r? to override)

Copy link
Contributor

@ryankurte ryankurte left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems reasonable to me!

bors r+

@bors bors bot merged commit ddf4375 into rust-embedded:master Feb 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Review is incomplete T-hal
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants