use std::cmp::Ordering;
pub struct LeftJoin<L, R, K, U, V>
where L: Iterator<Item = (K, U)>,
R: Iterator<Item = (K, V)>,
K: Ord
{
left: L,
right: R,
buf: Option<R::Item>,
}
impl<L, R, K, U, V> LeftJoin<L, R, K, U, V>
where L: Iterator<Item = (K, U)>,
R: Iterator<Item = (K, V)>,
K: Ord
{
pub fn new(left: L, right: R) -> Self {
Self {left: left, right: right, buf: None}
}
fn next_right(&mut self, key: &K) -> Option<V> {
let mut buf = self.buf.take().or_else(|| self.right.next());
loop {
return match buf.as_ref().map(|item| item.0.cmp(key)) {
Some(Ordering::Less) => { buf = self.right.next(); continue },
Some(Ordering::Equal) => buf.map(|item| item.1),
_ => { self.buf = buf; None },
};
}
}
}
impl<L, R, K, U, V> Iterator for LeftJoin<L, R, K, U, V>
where L: Iterator<Item = (K, U)>,
R: Iterator<Item = (K, V)>,
K: Ord
{
type Item = (U, Option<V>);
fn next(&mut self) -> Option<Self::Item> {
let item = self.left.next();
item.map(|item| {
let value = self.next_right(&item.0);
(item.1, value)
})
}
}
pub trait LeftJoinable<L, R, K, U, V>
where L: Iterator<Item = (K, U)>,
R: Iterator<Item = (K, V)>,
K: Ord
{
fn join_left(self, right: R) -> LeftJoin<L, R, K, U, V>;
}
impl<L, R, K, U, V> LeftJoinable<L, R, K, U, V> for L
where L: Iterator<Item = (K, U)>,
R: Iterator<Item = (K, V)>,
K: Ord
{
fn join_left(self, right: R) -> LeftJoin<L, R, K, U, V> {
LeftJoin::new(self, right)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn smoke() {
let left = vec![
(1, "a"),
(3, "b"),
(4, "c"),
(7, "d"),
(8, "e")
];
let right = vec![
(2, "x"),
(3, "u"),
(4, "v"),
(5, "x"),
(6, "x"),
(7, "w")
];
let mut res = LeftJoin::new(left.into_iter(), right.into_iter());
assert_eq!(res.next(), Some(("a", None)));
assert_eq!(res.next(), Some(("b", Some("u"))));
assert_eq!(res.next(), Some(("c", Some("v"))));
assert_eq!(res.next(), Some(("d", Some("w"))));
assert_eq!(res.next(), Some(("e", None)));
assert_eq!(res.next(), None)
}
}