How to `Extend` two collections from a single iterator?

Consider

struct A {
    validity: Vec<bool>,
    values: Vec<bool>
}

impl Extend<Option<bool>> for A {
    fn extend<T: IntoIterator<Item = Option<bool>>>(&mut self, iter: T) {
        let iter = iter.into_iter();

         // how to extend `self.validity` and  `self.values` in a single iteration?
        self.validity.extend(iter.map(|value| value.is_some()));
        self.values.extend(iter.map(|value| value.unwrap_or(false)));
    }
}

the current code does not compile because I need to clone iter, effectively costing two iterations.

Note that Vec is used here for illustration. In my use case, the container actually uses u8 and single bits to store the validity, as well as custom allocations, which requires unsafe. I was trying to keep all that unsafe code in a single method (trait method Extend), as it is optimized to use size_hint and avoid a couple of bound checks during the iteration.

I would write it like this:

impl Extend<Option<bool>> for A {
    fn extend<T: IntoIterator<Item = Option<bool>>>(&mut self, iter: T) {
        let iter = iter.into_iter();
        let n = iter.size_hint().0;
        
        self.validity.reserve(n);
        self.values.reserve(n);
        
        for value in iter {
            self.validity.push(value.is_some());
            self.values.push(value.unwrap_or(false));
        }
    }
}
4 Likes