1
votes

I'm developing an application for STM32 cortex-m microcontrollers in Rust, using a hardware abstraction layer compliant with embedded_hal interfaces - specifically, stm32f4xx-hal.

I'd like to implement a verbose read function that prints what has been received on a generic serial port, with extra messages in case of an error.

My first draft looks like this:

fn read<T: embedded_hal::serial::Read<u8>>(port: &mut T) {
    match nb::block!(port.read()) {
        Ok(byte) => hprintln!("received {}", byte),
        Err(hal::serial::Error::Overrun) => hprintln!("Overrun Error"),
        Err(_) => hprintln!("Unknown error"),
    }.ok();
}

Unfortunately the compiler complains that it cannot conciliate the serial Error enum with the Error type associated with the Read trait:

error[E0308]: mismatched types
  --> src/peripherals/cctalk.rs:95:13
   |
93 |     match nb::block!(port.read()) {
   |           ----------------------- this expression has type `core::result::Result<u8, <T as embedded_hal::serial::Read<u8>>::Error>`
94 |         Ok(byte) => hprintln!("received {}", byte),
95 |         Err(hal::serial::Error::Overrun) => hprintln!("Overrun Error"),
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found enum `stm32f4xx_hal::serial::Error`
   |
   = note: expected associated type `<T as embedded_hal::serial::Read<u8>>::Error`
                         found enum `stm32f4xx_hal::serial::Error`
help: consider constraining the associated type `<T as embedded_hal::serial::Read<u8>>::Error` to `stm32f4xx_hal::serial::Error`
   |
92 | fn read<T: embedded_hal::serial::Read<u8, Error = stm32f4xx_hal::serial::Error>>(port: T) {
   | 

At this point I thought it would be appropriate to specify an additional constraint for the trait:

fn read<T: embedded_hal::serial::Read<u8>>(port: &mut T) {
// Read::Error must be equal to hal::serial::Error
where <T as embedded_hal::serial::Read<u8>>::Error = hal::serial::Error,
{
    match nb::block!(port.read()) {
        Ok(byte) => hprintln!("received {}", byte),
        Err(hal::serial::Error::Overrun) => hprintln!("Overrun Error"),
        Err(_) => hprintln!("Unknown error"),
    }.ok();
}

At which point an error pointed out that equality constraints are not supported in where clauses (yet)

error: equality constraints are not yet supported in `where` clauses
  --> src/peripherals/cctalk.rs:94:1
   |
94 | <T as embedded_hal::serial::Read<u8>>::Error = hal::serial::Error,
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not supported
   |
   = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
help: if `Error` is an associated type you're trying to set, use the associated type binding syntax
   |
94 | T: embedded_hal::serial::Read<u8, Error = hal::serial::Error>,
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Here my limited experience with Rust falls short. I get that I should somehow make clearer that embedded_hal::serial::Read<u8>::Error is the same as hal::serial::Error, but I am not sure how (if possible). How should I proceed?

1
T: embedded_hal::serial::Read<u8, Error = stm32f4xx_hal::serial::Error>Stargateur
Analogous question applied to iterators: stackoverflow.com/q/27893501E_net4 the voter

1 Answers

1
votes

Despite the trait Read not having a parameter for its Error, it's possible to constrain the associated Error type with the following syntax:

                                      /*Associated types can be referred
                                        to between angular braces like this,
                                        similarly to struct fields.*/
fn read<T: embedded_hal::serial::Read<u8, Error = hal::serial::Error>>(port: &mut T)
// ...

There is (at the time of writing, rustc 1.45.0) no way to handle this requirement in the corresponding where clause.