Just finished chapter 10 of the Rust book and I thought I’d try digging into some real code. I’m a rust noob, but I’ve got 15 years with embedded C.
I’m working my way through the source code of the stm32l0xx-hal crate. Inside adc.rs on line 96, an implementation for the Adc struct is created for the type Adc<Ready> where Ready is defined on line 324.
/// Analog to Digital converter interface
pub struct Adc<State> {
rb: ADC,
sample_time: SampleTime,
align: Align,
precision: Precision,
_state: State,
}
impl Adc<Ready> {
pub fn new(adc: ADC, rcc: &mut Rcc) -> Self {
// Enable ADC clocks
ADC::enable(rcc);
adc.cr.modify(|_, w| w.advregen().set_bit());
Self {
rb: adc,
sample_time: SampleTime::T_1_5,
align: Align::Right,
precision: Precision::B_12,
_state: Ready,
}
}
...
}
...
/// Indicates that the ADC peripheral is ready
pub struct Ready;
I’m a little confused about how the associated function new() works. I understand that it generates a new Adc<Ready>, but I don’t fully understand why it’s inside the impl Adc<Ready> block.
It’s not a method that would be called on an Adc<Ready> type, and it doesn’t take any arguments of type Ready. Couldn’t it just as easily have been inside a impl<T> Adc<T> block?
Or is it that impl types go both ways. Like you can’t return an Adc<Ready> unless you’re inside an impl Adc<Ready>?
Sidenote: Since the Ready struct has no fields, does “Ready” actually create a new instance of a Ready type? (like you don’t need Ready{}?)


That makes sense! Thank you!
It’s funny how much of Rust appears to be writing footnotes for the compiler.
When you think about it, that’s all programming really is, it’s just that Rust pays a bit more attention than other languages and does a better job at spotting problems at compile time instead of letting them turn into runtime problems.