Something I've run into a few times is trying to make an owned iterator of a few given values. The issue is that [T; N]
does not implement IntoIterator
, so the resulting iterator is a borrow. To combat this I came up with this macro:
macro_rules! iter {
[$item:expr; $count:expr] => {
std::iter::repeat($item).take($count)
};
[$($item:expr),*] => {{
const LEN: usize = [$(zero!($item)),*].len();
struct Iter<T> {
index: usize,
values: std::mem::ManuallyDrop<[T; LEN]>,
}
impl<T> Iterator for Iter<T> {
type Item = T;
fn next(&mut self) -> Option<T> {
if self.index < LEN {
let val = unsafe { std::ptr::read(&self.values[self.index]) };
self.index += 1;
Some(val)
} else {
None
}
}
}
impl<T> Drop for Iter<T> {
fn drop(&mut self) {
for ptr in &mut self.values[self.index..] {
unsafe { std::ptr::drop_in_place(ptr); }
}
}
}
Iter {
index: 0,
values: std::mem::ManuallyDrop::new([$($item),*]),
}
}};
[$($item:expr,)*] => { iter!($($item),*) };
}
What do you think? I looked around and found some old implementations of this, e.g. here and literator, but they're more hacky and limited in length.
Also I usually look up how to count here, but it seems it is much easier now that slice::len
is const.