Traits vs generics in i2c.rs
So I'm slowly digging my way through the stm32l0xx-hal crate. As written, the crate works with an older version of embedded-hal. My ultimate goal is to bring it up to the latest version or at least start the process.
My question surrounds the implementation of the I2c struct in i2c.rs.
Starting on line 57 is a struct that contains three elements of generic type.
/// I2C abstraction
pub struct I2c<I2C, SDA, SCL> {
i2c: I2C,
sda: SDA,
scl: SCL,
}
I want to specifically talk about the first element. The bounds on what the generic type can be start in the implementation where the first element must implement the type Instance.
impl<I, SDA, SCL> I2c<I, SDA, SCL>
where
I: Instance,
{
pub fn new(i2c: I, sda: SDA, scl: SCL, freq: Hertz, rcc: &mut Rcc) -> Self
where
I: Instance,
SDA: SDAPin<I>,
SCL: SCLPin<I>,
{...}
...
}
Going one step higher, I2c::new() is called inside a macro on line 522 inside an implementation of the I2cExt trait on I2C1, I2C2, etc.
impl I2cExt<$I2CX> for $I2CX {
fn i2c<SDA, SCL>(
self,
sda: SDA,
scl: SCL,
freq: Hertz,
rcc: &mut Rcc,
) -> I2c<$I2CX, SDA, SCL>
where
SDA: SDAPin<$I2CX>,
SCL: SCLPin<$I2CX>,
{
I2c::new(self, sda, scl, freq, rcc)
}
}
So the generic type in the I2cExt trait is the same as the type for which the trait is implemented in this macro. The <$I2CX> type is passed to the I2c return type which ultimately creates an instance of the I2c struct with the first element of type <$I2CX> and along the way, it's verified that it implements the Instance type.
So my question is: couldn't we ignore all of this generic nonsense if we just defined the I2c struct to expect a certain trait for its first value?
For example, couldn't the first line of the struct just be i2c: Instance or some other defined trait that encompasses all of the I2c drivers on the chip? If we're bounding the type to an Instance anyway, why bother with all the generics?
