Skip to content

Commit 331b726

Browse files
Merge pull request rubberduck203#41 from rubberduck203/leds-iter
Implements Iterator for Leds
2 parents 3d5ab3a + a7af010 commit 331b726

File tree

4 files changed

+209
-69
lines changed

4 files changed

+209
-69
lines changed

examples/leds_array_iterator.rs renamed to examples/leds.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ fn main() -> ! {
2424

2525
// initialize user leds
2626
let mut gpioe = device_periphs.GPIOE.split(&mut reset_and_clock_control.ahb);
27-
let leds = Leds::new(
27+
let mut leds = Leds::new(
2828
gpioe.pe8,
2929
gpioe.pe9,
3030
gpioe.pe10,
@@ -37,13 +37,10 @@ fn main() -> ! {
3737
&mut gpioe.otyper,
3838
);
3939

40-
let mut compass = leds.into_array();
41-
4240
loop {
4341
let ms_delay = 50u16;
44-
// Alternative way to iterate through lights
45-
// do it backwards because it's fun and easy
46-
for led in compass.iter_mut().rev() {
42+
43+
for led in &mut leds {
4744
led.on().ok();
4845
delay.delay_ms(ms_delay);
4946
led.off().ok();

examples/leds_array_indexing.rs

Lines changed: 0 additions & 54 deletions
This file was deleted.

examples/leds_iterator_test.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
extern crate panic_itm;
5+
6+
use cortex_m_rt::entry;
7+
8+
use stm32f3_discovery::stm32f3xx_hal::delay::Delay;
9+
use stm32f3_discovery::stm32f3xx_hal::prelude::*;
10+
use stm32f3_discovery::stm32f3xx_hal::pac;
11+
12+
use stm32f3_discovery::leds::Leds;
13+
use stm32f3_discovery::switch_hal::OutputSwitch;
14+
15+
#[entry]
16+
fn main() -> ! {
17+
let device_periphs = pac::Peripherals::take().unwrap();
18+
let mut reset_and_clock_control = device_periphs.RCC.constrain();
19+
20+
let core_periphs = cortex_m::Peripherals::take().unwrap();
21+
let mut flash = device_periphs.FLASH.constrain();
22+
let clocks = reset_and_clock_control.cfgr.freeze(&mut flash.acr);
23+
let mut delay = Delay::new(core_periphs.SYST, clocks);
24+
25+
// initialize user leds
26+
let mut gpioe = device_periphs.GPIOE.split(&mut reset_and_clock_control.ahb);
27+
let mut leds = Leds::new(
28+
gpioe.pe8,
29+
gpioe.pe9,
30+
gpioe.pe10,
31+
gpioe.pe11,
32+
gpioe.pe12,
33+
gpioe.pe13,
34+
gpioe.pe14,
35+
gpioe.pe15,
36+
&mut gpioe.moder,
37+
&mut gpioe.otyper,
38+
);
39+
40+
loop {
41+
let ms_delay = 50u16;
42+
43+
// iterate through the leds in reverse
44+
for led in leds.iter_mut().rev() {
45+
led.on().ok();
46+
delay.delay_ms(ms_delay);
47+
led.off().ok();
48+
delay.delay_ms(ms_delay);
49+
}
50+
51+
delay.delay_ms(ms_delay);
52+
53+
// verify we stop when meeting in the middle
54+
let mut iter = leds.iter_mut();
55+
iter.next().map(|led| led.on().ok());
56+
delay.delay_ms(ms_delay);
57+
iter.next_back().map(|led| led.on().ok());
58+
delay.delay_ms(ms_delay);
59+
iter.next().map(|led| led.on().ok());
60+
delay.delay_ms(ms_delay);
61+
iter.next_back().map(|led| led.on().ok());
62+
delay.delay_ms(ms_delay);
63+
iter.next().map(|led| led.on().ok());
64+
delay.delay_ms(ms_delay);
65+
iter.next_back().map(|led| led.on().ok());
66+
delay.delay_ms(ms_delay);
67+
iter.next().map(|led| led.on().ok());
68+
delay.delay_ms(ms_delay);
69+
iter.next_back().map(|led| led.on().ok());
70+
delay.delay_ms(ms_delay);
71+
// we're in the middle, so panic if either of the next two calls returns a led
72+
iter.next().map(|_| panic!("Got a Some!"));
73+
iter.next_back().map(|_| panic!("Got a Some!"));
74+
75+
// turn everything back off
76+
for led in &mut leds {
77+
led.off().ok();
78+
delay.delay_ms(ms_delay);
79+
}
80+
}
81+
}

src/leds.rs

Lines changed: 125 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use stm32f3xx_hal::gpio::{Output, PushPull};
55
use switch_hal::{ActiveHigh, IntoSwitch, OutputSwitch, Switch};
66

77
use core::slice::Iter;
8+
use core::iter::FusedIterator;
89

910
/// LED compass direction as noted on the board
1011
#[derive(Clone, Copy, Eq, PartialEq)]
@@ -21,6 +22,9 @@ pub enum Direction
2122
}
2223

2324
impl Direction {
25+
/// Provides an iterator starting with North
26+
/// and moving clockwise around the compass
27+
/// e.g. N -> NE -> E, etc.
2428
pub fn iter() -> Iter<'static, Direction> {
2529
static DIRECTIONS: [Direction; 8] = [
2630
Direction::North,
@@ -106,15 +110,9 @@ impl Leds {
106110
.into_active_high_switch(),
107111
};
108112

109-
//TODO: expose an iterator
110-
leds.ld3.off().ok();
111-
leds.ld4.off().ok();
112-
leds.ld5.off().ok();
113-
leds.ld6.off().ok();
114-
leds.ld7.off().ok();
115-
leds.ld8.off().ok();
116-
leds.ld9.off().ok();
117-
leds.ld10.off().ok();
113+
for led in &mut leds {
114+
led.off().ok();
115+
}
118116

119117
leds
120118
}
@@ -133,9 +131,17 @@ impl Leds {
133131
}
134132
}
135133

134+
/// Provides a mutable iterator for iterating over the on board leds.
135+
/// Starts at ld3 (N) and moves clockwise.
136+
/// Stops once it has iterated through all 8 leds.
137+
pub fn iter_mut(&mut self) -> LedsMutIterator {
138+
LedsMutIterator::new(self)
139+
}
140+
136141
/// Consumes the `Leds` struct and returns an array
137142
/// where index 0 is N and each incrementing index
138143
/// rotates clockwise around the compass
144+
#[deprecated(since = "0.7.1", note = "Use `iter_mut()` intsead. This will be removed in 0.8.0")]
139145
pub fn into_array(self) -> [Led; 8] {
140146
[
141147
self.ld3, //N
@@ -149,3 +155,113 @@ impl Leds {
149155
]
150156
}
151157
}
158+
159+
impl<'a> IntoIterator for &'a mut Leds {
160+
type Item = &'a mut Led;
161+
type IntoIter = LedsMutIterator<'a>;
162+
163+
fn into_iter(self) -> Self::IntoIter {
164+
self.iter_mut()
165+
}
166+
}
167+
168+
const ITERATOR_SIZE: usize = 8;
169+
170+
pub struct LedsMutIterator<'a> {
171+
index: usize,
172+
index_back: usize,
173+
leds: &'a mut Leds
174+
}
175+
176+
impl<'a> LedsMutIterator<'a> {
177+
fn new(leds: &'a mut Leds) -> Self {
178+
LedsMutIterator { index: 0, index_back: ITERATOR_SIZE, leds }
179+
}
180+
181+
fn len(&self) -> usize {
182+
self.index_back - self.index
183+
}
184+
185+
fn size_hint(&self) -> (usize, Option<usize>) {
186+
let length = self.len();
187+
(length, Some(length))
188+
}
189+
}
190+
191+
impl<'a> Iterator for LedsMutIterator<'a> {
192+
type Item = &'a mut Led;
193+
fn next(&mut self) -> Option<Self::Item> {
194+
if self.len() == 0 {
195+
None
196+
} else {
197+
let current = unsafe {
198+
//Safety: Each branch is only executed once,
199+
// and only if there are elements left to be returned,
200+
// so we can not possibly alias a mutable reference.
201+
// This depends on DoubleEndedIterator and ExactSizedIterator being implemented correctly.
202+
// If len() does not return the correct number of remaining elements,
203+
// this becomes unsound.
204+
match self.index {
205+
0 => Some(&mut *(&mut self.leds.ld3 as *mut _)), //N
206+
1 => Some(&mut *(&mut self.leds.ld5 as *mut _)), //NE
207+
2 => Some(&mut *(&mut self.leds.ld7 as *mut _)), //E
208+
3 => Some(&mut *(&mut self.leds.ld9 as *mut _)), //SE
209+
4 => Some(&mut *(&mut self.leds.ld10 as *mut _)), //S
210+
5 => Some(&mut *(&mut self.leds.ld8 as *mut _)), //SW
211+
6 => Some(&mut *(&mut self.leds.ld6 as *mut _)), //W
212+
7 => Some(&mut *(&mut self.leds.ld4 as *mut _)), //NW
213+
_ => None
214+
}
215+
};
216+
self.index += 1;
217+
current
218+
}
219+
}
220+
221+
// Because we implement ExactSizedIterator, we need to ensure size_hint returns the right length
222+
fn size_hint(&self) -> (usize, Option<usize>) {
223+
self.size_hint()
224+
}
225+
}
226+
227+
impl<'a> DoubleEndedIterator for LedsMutIterator<'a> {
228+
fn next_back(&mut self) -> Option<Self::Item> {
229+
if self.len() == 0 {
230+
None
231+
} else {
232+
let current = unsafe {
233+
//Safety: Each branch is only executed once,
234+
// and only if there are elements left to be returned,
235+
// so we can not possibly alias a mutable reference.
236+
// This depends on Iterator and ExactSizedIterator being implemented correctly.
237+
// If len() does not return the correct number of remaining elements,
238+
// this becomes unsound.
239+
match self.index_back {
240+
// Because we're going backwards and index_back is a usize,
241+
// We use a one based index so we don't go negative
242+
0 => None, //done
243+
1 => Some(&mut *(&mut self.leds.ld3 as *mut _)), //N
244+
2 => Some(&mut *(&mut self.leds.ld5 as *mut _)), //NE
245+
3 => Some(&mut *(&mut self.leds.ld7 as *mut _)), //E
246+
4 => Some(&mut *(&mut self.leds.ld9 as *mut _)), //SE
247+
5 => Some(&mut *(&mut self.leds.ld10 as *mut _)), //S
248+
6 => Some(&mut *(&mut self.leds.ld8 as *mut _)), //SW
249+
7 => Some(&mut *(&mut self.leds.ld6 as *mut _)), //W
250+
8 => Some(&mut *(&mut self.leds.ld4 as *mut _)), //NW
251+
_ => None //can't happen
252+
}
253+
};
254+
self.index_back -= 1;
255+
current
256+
}
257+
}
258+
}
259+
260+
impl<'a> ExactSizeIterator for LedsMutIterator<'a> {
261+
fn len(&self) -> usize {
262+
self.len()
263+
}
264+
}
265+
266+
///Marker trait that indicates LedsMutIterator never starts returning Some after returning None
267+
impl<'a> FusedIterator for LedsMutIterator<'a> {}

0 commit comments

Comments
 (0)