ciruela 0.6.12

A peer-to-peer synchronization software for servers in datacenters.
Documentation
use abstract_ns::{HostResolve, Address, IpList, Name, Error};
use abstract_ns::addr::union;
use std::collections::VecDeque;

use futures::{Future, Async};
use void::{Void, unreachable};

pub(in cluster) enum AddrCell {
    Ready(Address),
    Fetching(Box<FutureAddr<Item=Address, Error=Void>>),
}

pub(in cluster) trait FutureAddr: Future + AsRef<Address> {
}

pub(in cluster) struct AddrFuture<F> {
    port: u16,
    futures: VecDeque<(Name, F)>,
    current: Address,
}

impl<F: Future<Item=IpList, Error=Error>> Future for AddrFuture<F> {
    type Item = Address;
    type Error = Void;
    fn poll(&mut self) -> Result<Async<Address>, Void> {
        for _ in 0..self.futures.len() {
            let (n, mut fut) = self.futures.pop_front().unwrap();
            match fut.poll() {
                Ok(Async::Ready(new)) => {
                    self.current = union(&[
                        self.current.clone(), new.with_port(self.port)
                    ]);
                }
                Ok(Async::NotReady) => {
                    self.futures.push_back((n, fut));
                }
                Err(e) => {
                    error!("Error resolving name {:?}: {}", n, e);
                }
            }
        }
        if self.futures.len() > 0 {
            return Ok(Async::NotReady);
        } else {
            return Ok(Async::Ready(self.current.clone()))
        }
    }
}

impl<F> AsRef<Address> for AddrFuture<F> {
    fn as_ref(&self) -> &Address {
        &self.current
    }
}

impl<F: Future<Item=IpList, Error=Error>> FutureAddr for AddrFuture<F> {}

impl AddrCell {
    pub fn new<R: HostResolve>(initial_address: Vec<Name>,
        port: u16, resolver: &R)
        -> AddrCell
        where R::HostFuture: 'static,
    {
        AddrCell::Fetching(Box::new(AddrFuture {
            port: port,
            futures: initial_address.iter()
                .map(|n| (n.clone(), resolver.resolve_host(n)))
                .collect(),
            current: [][..].into(),
        }))
    }
    pub fn poll(&mut self) {
        use self::AddrCell::*;
        let res = match *self {
            Ready(..) => return,
            Fetching(ref mut b) => match b.poll() {
                Ok(Async::Ready(a)) => a,
                Ok(Async::NotReady) => return,
                Err(e) => unreachable(e),
            },
        };
        *self = Ready(res);
    }
    pub fn get(&self) -> &Address {
        use self::AddrCell::*;
        match *self {
            Ready(ref a) => a,
            Fetching(ref b) => b.as_ref().as_ref(),
        }
    }
    pub fn is_done(&self) -> bool {
        matches!(self, &AddrCell::Ready(..))
    }
}