It's possible without unsafe
, if you need it to work for arbitrary iterators¹ :
use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;
pub fn split_mut_iter<'it, A: 'it, B: 'it, I>(
iter: I,
) -> (
impl Iterator<Item = &'it mut A>,
impl Iterator<Item = &'it mut B>,
)
where
I: Iterator<Item = &'it mut (A, B)>,
{
split_iter(iter.map(|&mut (ref mut a, ref mut b)| (a, b)))
}
pub fn split_iter<A, B, I>(iter: I) -> (impl Iterator<Item = A>, impl Iterator<Item = B>)
where
I: Iterator<Item = (A, B)>,
{
let state = Rc::new(RefCell::new(IterState::new(iter)));
(AIterator(Rc::clone(&state)), BIterator(state))
}
struct IterState<A, B, I: ?Sized> {
pending_a: VecDeque<A>,
pending_b: VecDeque<B>,
source: I,
}
impl<A, B, I> IterState<A, B, I>
where
I: ?Sized + Iterator<Item = (A, B)>,
{
pub fn new(iter: I) -> Self
where
I: Sized,
{
IterState {
pending_a: VecDeque::default(),
pending_b: VecDeque::default(),
source: iter,
}
}
fn pump_source(&mut self) -> Option<()> {
let (a, b) = self.source.next()?;
self.pending_a.push_back(a);
self.pending_b.push_back(b);
Some(())
}
pub fn next_a(&mut self) -> Option<A> {
if self.pending_a.len() == 0 {
self.pump_source();
}
self.pending_a.pop_front()
}
pub fn next_b(&mut self) -> Option<B> {
if self.pending_b.len() == 0 {
self.pump_source();
}
self.pending_b.pop_front()
}
}
struct AIterator<I: ?Sized>(Rc<RefCell<I>>);
struct BIterator<I: ?Sized>(Rc<RefCell<I>>);
impl<A, B, I: ?Sized> Iterator for AIterator<IterState<A, B, I>>
where
I: Iterator<Item = (A, B)>,
{
type Item = A;
fn next(&mut self) -> Option<A> {
self.0.borrow_mut().next_a()
}
}
impl<A, B, I: ?Sized> Iterator for BIterator<IterState<A, B, I>>
where
I: Iterator<Item = (A, B)>,
{
type Item = B;
fn next(&mut self) -> Option<B> {
self.0.borrow_mut().next_b()
}
}
¹ If you're always iterating over Vec
s, then an unsafe
implementation will be able to avoid the heap allocations of this version.