plumtree 0.0.4

A Rust implementation of Plumtree algorithm
Documentation
use std::cmp::Ordering;
use std::collections::{BinaryHeap, HashMap};
use std::fmt;

use message::IhaveMessage;
use time::LogicalTime;
use System;

pub struct MissingMessages<T: System> {
    ihave_queue: BinaryHeap<WithExpiryTime<T>>,
    missings: HashMap<T::MessageId, Entry<T::NodeId>>,
}
impl<T: System> fmt::Debug for MissingMessages<T>
where
    T::NodeId: fmt::Debug,
    T::MessageId: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "MissingMessages {{ ihave_queue: {:?}, missings: {:?} }}",
            self.ihave_queue, self.missings
        )
    }
}
impl<T: System> MissingMessages<T> {
    pub fn new() -> Self {
        MissingMessages {
            ihave_queue: BinaryHeap::new(),
            missings: HashMap::new(),
        }
    }

    pub fn enqueue(&mut self, ihave: IhaveMessage<T>, mut expiry_time: LogicalTime) {
        if !self.missings.contains_key(&ihave.message_id) {
            let e = Entry {
                latest_expiry_time: expiry_time,
                min_round: ihave.round,
                min_round_owner: ihave.sender.clone(),
                owner_count: 1,
            };
            self.missings.insert(ihave.message_id.clone(), e);
        } else {
            let entry = self.missings
                .get_mut(&ihave.message_id)
                .expect("Never fails");
            if expiry_time <= entry.latest_expiry_time {
                expiry_time.0 = entry.latest_expiry_time.0 + 1;
            }
            entry.latest_expiry_time = expiry_time;
            if entry.min_round > ihave.round {
                entry.min_round = ihave.round;
                entry.min_round_owner = ihave.sender.clone();
            }
            entry.owner_count += 1;
        }
        self.ihave_queue.push(WithExpiryTime { expiry_time, ihave });
    }

    pub fn dequeue_expired(&mut self, now: LogicalTime) -> Option<IhaveMessage<T>> {
        while self.ihave_queue
            .peek()
            .map_or(false, |x| x.expiry_time <= now)
        {
            let ihave = self.ihave_queue.pop().expect("Never fails").ihave;
            let empty = if let Some(e) = self.missings.get_mut(&ihave.message_id) {
                e.owner_count -= 1;
                e.owner_count == 0
            } else {
                continue;
            };
            if empty {
                self.missings.remove(&ihave.message_id);
            }
            return Some(ihave);
        }
        None
    }

    pub fn remove(&mut self, message_id: &T::MessageId) {
        self.missings.remove(message_id);
    }

    pub fn get_min_round_owner(&self, message_id: &T::MessageId) -> Option<(u16, &T::NodeId)> {
        self.missings
            .get(message_id)
            .map(|e| (e.min_round, &e.min_round_owner))
    }
}

#[derive(Debug)]
struct Entry<N> {
    latest_expiry_time: LogicalTime,
    min_round: u16,
    min_round_owner: N,
    owner_count: usize,
}

struct WithExpiryTime<T: System> {
    expiry_time: LogicalTime,
    ihave: IhaveMessage<T>,
}
impl<T: System> PartialEq for WithExpiryTime<T> {
    fn eq(&self, other: &Self) -> bool {
        self.expiry_time == other.expiry_time
    }
}
impl<T: System> Eq for WithExpiryTime<T> {}
impl<T: System> PartialOrd for WithExpiryTime<T> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        other.expiry_time.partial_cmp(&self.expiry_time)
    }
}
impl<T: System> Ord for WithExpiryTime<T> {
    fn cmp(&self, other: &Self) -> Ordering {
        other.expiry_time.cmp(&self.expiry_time)
    }
}
impl<T: System> fmt::Debug for WithExpiryTime<T>
where
    T::NodeId: fmt::Debug,
    T::MessageId: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "WithExpiryTime {{ expiry_time: {:?}, ihave: {:?} }}",
            self.expiry_time, self.ihave
        )
    }
}