Recently, I needed to sort iterators by their first value and/or use them in BinaryHeap. There are things I don't like about this implementation:
- Using
RefCell. - Mutating an underlying object while calling eq/cmp/etc methods.
- Using unsafe in
Deref.
It seems to be doing exactly what I want but I feel there must be a better way of achieving the same result.
use std::cell::RefCell;
use std::cmp::{Ordering, Reverse};
use std::collections::BinaryHeap;
use std::iter::Peekable;
use std::ops::{Deref, DerefMut};
struct IterHeapWrapper<I, T>
where
I: Iterator<Item = T>,
T: Ord,
{
iter: RefCell<Peekable<I>>,
}
impl<I, T> Eq for IterHeapWrapper<I, T>
where
I: Iterator<Item = T>,
T: Ord,
{
}
impl<I, T> PartialEq<Self> for IterHeapWrapper<I, T>
where
I: Iterator<Item = T>,
T: Ord,
{
fn eq(&self, other: &Self) -> bool {
self.iter.borrow_mut().peek().eq(&other.iter.borrow_mut().peek())
}
}
impl<I, T> PartialOrd<Self> for IterHeapWrapper<I, T>
where
I: Iterator<Item = T>,
T: Ord,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.iter.borrow_mut().peek().partial_cmp(&other.iter.borrow_mut().peek())
}
}
impl<I, T> Ord for IterHeapWrapper<I, T>
where
I: Iterator<Item = T>,
T: Ord,
{
fn cmp(&self, other: &Self) -> Ordering {
self.iter.borrow_mut().peek().cmp(&other.iter.borrow_mut().peek())
}
}
impl<I, T> From<I> for IterHeapWrapper<I, T>
where
I: Iterator<Item = T>,
T: Ord,
{
fn from(iter: I) -> Self {
Self { iter: RefCell::new(iter.peekable()) }
}
}
impl<I, T> Deref for IterHeapWrapper<I, T>
where
I: Iterator<Item = T>,
T: Ord,
{
type Target = Peekable<I>;
fn deref(&self) -> &Self::Target {
let ptr = self.iter.as_ptr();
unsafe { &*ptr }
}
}
impl<I, T> DerefMut for IterHeapWrapper<I, T>
where
I: Iterator<Item = T>,
T: Ord,
{
fn deref_mut(&mut self) -> &mut Self::Target {
let ptr = self.iter.as_ptr();
unsafe { &mut *ptr }
}
}
Usage example:
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test() {
let a = [1, 2, 3];
let b = [3, 2, 1];
let mut heap = BinaryHeap::new();
heap.push(IterHeapWrapper::from(a.iter()));
heap.push(IterHeapWrapper::from(b.iter()));
assert_eq!(heap.pop().unwrap().next().unwrap(), &3);
}
}