Skip to content

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