Async trait in struct

Hi,
I'm new in Rust and trying to build a small embedded application with the Embassy framework.

Now I want to design the HAL architecture and create communication devices:
So, I've created a trait to define the CommPort:

pub trait CommPort {
    fn init(&self);
    async fn read(&self) -> &[u8];
    async fn write(&self, data: &[u8]);
}

And I have I2C and UART that implement this trait and should manage the communication with the HW:

impl CommPort for I2C {
    fn init(&self) {
        // Init I2C device
    }

    async fn read(&self) -> &[u8] {
        // WaitForData().await;
        &self.buffer
    }

    async fn write(&self, data: &[u8]) {
        // WriteData().await;
    }
}

(Same for UART, SPI, etc)

To make it generic, I want that each device will define its own port. something like that:

pub struct DeviceX {
    port: CommPort,
}

impl DeviceX {
    pub fn new() -> Self {
        DeviceX { 
            port:  I2C::new()
        }
    }

    pub async fn send_message(&mut self, message: &[u8]) {
        self.port.write(message).await;
    }

But I learned that I cannot use dynamic dispatch in the struct and I have to use box<syn> that don't exist in no_std.
Do you have any idea what should I do to make the communication ports generic for the devices?
I would love to hear how to do it right in Rust.

Thanks!!

You can use a generic type parameter.

pub struct DeviceX<T>
where
    T: CommPort
 {
    port: T,
}

You cannot use a trait object, since CommPort is not object safe.

5 Likes