<commit_before>use futures::{Poll, Future, Async};
use tokio_service::Service;
use store::Store;
use {LogPos, Error};
use std::net::SocketAddr;
use std::mem;
use replica::{ReplicaRequest, ReplicaResponse, LogEntry, HostConfig};

pub trait DownstreamService {
    type Future: Future<Item = ReplicaResponse, Error = Error>;
    fn call(&self, req: ReplicaRequest) -> Self::Future;
}

pub trait NewDownstreamService {
    type Item: DownstreamService;
    fn new_downstream(&self, addr: SocketAddr) -> Self::Item;
}

impl<D, F> DownstreamService for D
    where D: Service<Request = ReplicaRequest,
                     Response = ReplicaResponse,
                     Error = Error,
                     Future = F>,
          F: Future<Item = ReplicaResponse, Error = Error> + Send
{
    type Future = D::Future;

    fn call(&self, req: ReplicaRequest) -> Self::Future {
        Service::call(self, req)
    }
}

impl<F, D> NewDownstreamService for F
    where F: Fn(SocketAddr) -> D,
          D: DownstreamService
{
    type Item = D;
    fn new_downstream(&self, addr: SocketAddr) -> D {
        debug!("new downstream: {:?}", addr);
        self(addr)
    }
}

enum ReplicatorState<S: Store, N>
    where N: NewDownstreamService
{
    Idle,
    Fetching(S::FetchFut),
    Forwarding(<N::Item as DownstreamService>::Future),
}

pub struct Replicator<S: Store, N: NewDownstreamService> {
    store: S,
    new_downstream: N,
    downstream: Option<N::Item>,
    last_seen_seq: LogPos,
    state: ReplicatorState<S, N>,
}

impl<S: Store, N: NewDownstreamService> Replicator<S, N> {
    pub fn new(store: S, new_downstream: N) -> Self {
        Replicator {
            store: store,
            new_downstream: new_downstream,
            downstream: None,
            last_seen_seq: LogPos::zero(),
            state: ReplicatorState::Idle,
        }
    }

    fn process_config_message(&mut self, conf: &HostConfig<SocketAddr>) {
        debug!("logged Config message: {:?}", conf);
        // FIXME: Well, this is blatantly wrong.
        debug!("connecting downstream to: {:?}", conf.head);
        self.downstream = Some(self.new_downstream
            .new_downstream(conf.head));
    }

    fn try_take_next(&mut self) -> Poll<(), Error> {
        if let ReplicatorState::Idle = self.state {
            debug!("Idle, fetching after: {:?}", self.last_seen_seq);
            let fetch_f = self.store.fetch_next(self.last_seen_seq);
            self.state = ReplicatorState::Fetching(fetch_f);
        }
        Ok(Async::Ready(()))
    }

    fn try_process_message(&mut self) -> Poll<(), Error> {
        match mem::replace(&mut self.state, ReplicatorState::Idle) {
            ReplicatorState::Fetching(mut fetch_f) => {
                debug!("Fetching");
                match try!(fetch_f.poll()) {
                    Async::NotReady => {
                        self.state = ReplicatorState::Fetching(fetch_f);
                        Ok(Async::NotReady)
                    }
                    Async::Ready((off, val)) => {
                        debug!("Fetched: {:?}", (&off, &val));
                        if let &LogEntry::Config(ref conf) = &val {
                            self.process_config_message(conf);
                        };

                        if let Some(ref downstream) = self.downstream {
                            debug!("Forward {:?}", off);
                            let req = ReplicaRequest::AppendLogEntry {
                                assumed_offset: self.last_seen_seq,
                                // FIXME: NO. WRONG.
                                entry_offset: off,
                                datum: val,
                            };
                            let _: &DownstreamService<Future = _> = downstream;
                            let f = downstream.call(req);
                            self.state = ReplicatorState::Forwarding(f);
                        } else {
                            debug!("No downstream at {:?}", off);
                        }
                        self.last_seen_seq = off;
                        Ok(Async::Ready(()))
                    }
                }
            }
            other => {
                self.state = other;
                Ok(Async::Ready(()))
            }
        }
    }

    fn try_process_forward(&mut self) -> Poll<(), Error> {
        match mem::replace(&mut self.state, ReplicatorState::Idle) {
            ReplicatorState::Forwarding(mut f) => {
                match try!(f.poll()) {
                    Async::NotReady => {
                        self.state = ReplicatorState::Forwarding(f);
                        Ok(Async::NotReady)
                    }
                    Async::Ready(ReplicaResponse::Done(pos)) => {
                        debug!("woo! {:?}", pos);
                        Ok(Async::Ready(()))
                    }
                    Async::Ready(ReplicaResponse::BadSequence(pos)) => {
                        debug!("Bad sequence: resetting to {:?}", pos);
                        self.last_seen_seq = pos;
                        Ok(Async::Ready(()))
                    }
                }
            }
            other => {
                self.state = other;
                Ok(Async::Ready(()))
            }
        }
    }
}

impl<S: Store, N: NewDownstreamService> Drop for Replicator<S, N> {
    fn drop(&mut self) {
        debug!("Drop Replicator");
    }
}

impl<S: Store, N: NewDownstreamService> Future for Replicator<S, N> {
    type Item = ();
    type Error = Error;
    fn poll(&mut self) -> Poll<(), Error> {
        debug!("Replicator#poll");
        loop {
            try_ready!(self.try_take_next());
            try_ready!(self.try_process_message());
            try_ready!(self.try_process_forward());
        }
    }
}

#[cfg(test)]
mod test {
    use futures::{self, Future, BoxFuture, Async};
    use futures::stream::Stream;
    use service::Service;
    use tokio::channel;
    use replica::LogPos;
    use store::{RamStore, Store};
    use replica::{ReplicaRequest, ReplicaResponse, LogEntry, HostConfig};
    use errors::Error;
    use std::net::SocketAddr;
    use super::*;
    use tokio::reactor::Core;
    use std::time::Duration;
    use std::io;
    use tokio_timer;
    use env_logger;

    type MessageType = ((SocketAddr, ReplicaRequest), futures::Complete<ReplicaResponse>);
    struct MyMagicalDownstream {
        addr: SocketAddr,
        send: channel::Sender<MessageType>,
    }

    struct MyDownstreamBuilder {
        send: channel::Sender<MessageType>,
    }

    impl Service for MyMagicalDownstream {
        type Request = ReplicaRequest;
        type Response = ReplicaResponse;
        type Error = Error;
        type Future = BoxFuture<ReplicaResponse, Error>;
        fn poll_ready(&self) -> Async<()> {
            Async::Ready(())
        }
        fn call(&self, req: Self::Request) -> Self::Future {
            let (c, p) = futures::oneshot();
            match self.send.send(((self.addr.clone(), req), c)) {
                Ok(()) => (),
                Err(e) => return futures::failed(e.into()).boxed(),
            };
            p.map_err(|_| io::Error::new(io::ErrorKind::BrokenPipe, "broken pipe").into())
                .boxed()
        }
    }

    impl NewDownstreamService for MyDownstreamBuilder {
        type Item = MyMagicalDownstream;
        fn new_downstream(&self, addr: SocketAddr) -> Self::Item {
            MyMagicalDownstream {
                addr: addr,
                send: self.send.clone(),
            }
        }
    }

    #[test]
    fn should_start_replicating_to_downstream_on_committed_config_message() {
        env_logger::init().unwrap_or(());
        let store = RamStore::new();
        let timer = tokio_timer::wheel().tick_duration(Duration::from_millis(1)).build();

        let mut core = Core::new().expect("core::new");
        let (tx, rx) = channel::channel(&core.handle()).expect("channel");

        let downstream = MyDownstreamBuilder { send: tx };

        let replica = Replicator::new(store.clone(), downstream);

        core.handle().spawn(replica.map_err(|e| panic!("Replicator failed!: {:?}", e)));
        debug!("Spawned replica task");

        let head_addr = "1.2.3.4:5".parse().expect("parse");

        let config: HostConfig<::std::net::SocketAddr> = HostConfig {
            head: head_addr,
            tail: "1.2.3.6:7".parse().expect("parse"),
        };
        let off = LogPos::zero();
        let _ = append_entry(&store, &mut core, off, LogEntry::Config(config.clone()));

        let (_rx, _response, _assumed0, _off0, entry0) =
            take_next_entry(rx, &head_addr, &mut core, &timer);

        assert_eq!(entry0, LogEntry::Config(config));
    }

    #[test]
    fn should_send_next_log_entry_on_okay_from_downstream() {
        env_logger::init().unwrap_or(());
        let store = RamStore::new();
        let timer = tokio_timer::wheel().tick_duration(Duration::from_millis(1)).build();

        let mut core = Core::new().expect("core::new");
        let (tx, rx) = channel::channel(&core.handle()).expect("channel");

        let downstream = MyDownstreamBuilder { send: tx };

        let replica = Replicator::new(store.clone(), downstream);

        core.handle().spawn(replica.map_err(|e| panic!("Replicator failed!: {:?}", e)));
        debug!("Spawned replica task");

        let head_addr = "1.2.3.4:5".parse().expect("parse");

        let config: HostConfig<::std::net::SocketAddr> = HostConfig {
            head: head_addr,
            tail: "1.2.3.6:7".parse().expect("parse"),
        };

        let off0 = append_entry(&store,
                                &mut core,
                                LogPos::zero(),
                                LogEntry::Config(config.clone()));
        let _off1 = append_entry(&store,
                                 &mut core,
                                 off0,
                                 LogEntry::Data(b"Hello world!".to_vec().into()));

        let (rx, response, _assumed0, off0, _entry0) =
            take_next_entry(rx, &head_addr, &mut core, &timer);

        response.complete(ReplicaResponse::Done(off0));

        let (_rx, _response, assumed1, off1, entry1) =
            take_next_entry(rx, &head_addr, &mut core, &timer);

        assert_eq!((assumed1, entry1),
                   (off0, LogEntry::Data(b"Hello world!".to_vec().into())));
        assert!(off1 > assumed1);
    }

    #[test]
    fn should_restart_replication_on_badsequence_from_downstream() {
        env_logger::init().unwrap_or(());
        let store = RamStore::new();
        let timer = tokio_timer::wheel().tick_duration(Duration::from_millis(1)).build();

        let mut core = Core::new().expect("core::new");
        let (tx, rx) = channel::channel(&core.handle()).expect("channel");

        let downstream = MyDownstreamBuilder { send: tx };

        let replica = Replicator::new(store.clone(), downstream);

        core.handle().spawn(replica.map_err(|e| panic!("Replicator failed!: {:?}", e)));
        debug!("Spawned replica task");

        let head_addr = "1.2.3.4:5".parse().expect("parse");

        let config: HostConfig<::std::net::SocketAddr> = HostConfig {
            head: head_addr,
            tail: "1.2.3.6:7".parse().expect("parse"),
        };

        let log_off = LogPos::zero();
        let log_off0 = append_entry(&store, &mut core, log_off, LogEntry::Config(config.clone()));
        let log_off1 = append_entry(&store,
                                    &mut core,
                                    log_off0,
                                    LogEntry::Data(b"Hello".to_vec().into()));
        let log_off2 = append_entry(&store,
                                    &mut core,
                                    log_off1,
                                    LogEntry::Data(b"world!".to_vec().into()));

        let (rx, response, _assumed0, _off0, _entry0) =
            take_next_entry(rx, &head_addr, &mut core, &timer);

        // So we expect the delivery of "world!"
        let resp = ReplicaResponse::BadSequence(log_off1);
        println!("Respond with: {:?}", resp);
        response.complete(resp);
        let (_rx, _response, assumed1, off1, entry1) =
            take_next_entry(rx, &head_addr, &mut core, &timer);

        assert_eq!((assumed1, off1, entry1),
                   (log_off1, log_off2, LogEntry::Data(b"world!".to_vec().into())));
    }

    fn append_entry<S: Store>(store: &S, core: &mut Core, off: LogPos, entry: LogEntry) -> LogPos {
        let next = off.next();
        debug!("append config message {:?} -> {:?}", off, next);
        core.run(store.append_entry(off, next, entry))
            .expect("append");
        next
    }

    fn take_next_entry(rx: channel::Receiver<MessageType>,
                       target: &SocketAddr,
                       core: &mut Core,
                       timer: &tokio_timer::Timer)
                       -> (channel::Receiver<MessageType>,
                           futures::Complete<ReplicaResponse>,
                           LogPos,
                           LogPos,
                           LogEntry) {
        let f = timer.timeout(rx.into_future().map_err(|(e, _)| e),
                              Duration::from_millis(1000));
        debug!("wait for stub message");
        let (data, rx) = core.run(f).expect("receive downstream");
        let ((addr, msg), response) = data.expect("Some message");
        assert_eq!(&addr, target);
        println!("Some: {:?}", (&addr, &msg));
        // Expect that the target at `head_addr` receives a set of replication messages.
        match msg {
            ReplicaRequest::AppendLogEntry { assumed_offset, entry_offset, datum } => {
                (rx, response, assumed_offset, entry_offset, datum)
            }
        }
    }
}
<commit_msg>See if we can avoid using mem::replace.<commit_after>use futures::{Poll, Future, Async};
use tokio_service::Service;
use store::Store;
use {LogPos, Error};
use std::net::SocketAddr;
use replica::{ReplicaRequest, ReplicaResponse, LogEntry, HostConfig};

pub trait DownstreamService {
    type Future: Future<Item = ReplicaResponse, Error = Error>;
    fn call(&self, req: ReplicaRequest) -> Self::Future;
}

pub trait NewDownstreamService {
    type Item: DownstreamService;
    fn new_downstream(&self, addr: SocketAddr) -> Self::Item;
}

impl<D, F> DownstreamService for D
    where D: Service<Request = ReplicaRequest,
                     Response = ReplicaResponse,
                     Error = Error,
                     Future = F>,
          F: Future<Item = ReplicaResponse, Error = Error> + Send
{
    type Future = D::Future;

    fn call(&self, req: ReplicaRequest) -> Self::Future {
        Service::call(self, req)
    }
}

impl<F, D> NewDownstreamService for F
    where F: Fn(SocketAddr) -> D,
          D: DownstreamService
{
    type Item = D;
    fn new_downstream(&self, addr: SocketAddr) -> D {
        debug!("new downstream: {:?}", addr);
        self(addr)
    }
}

enum ReplicatorState<S: Store, N>
    where N: NewDownstreamService
{
    Idle,
    Fetching(S::FetchFut),
    Forwarding(<N::Item as DownstreamService>::Future),
}

pub struct Replicator<S: Store, N: NewDownstreamService> {
    store: S,
    new_downstream: N,
    downstream: Option<N::Item>,
    last_seen_seq: LogPos,
    state: ReplicatorState<S, N>,
}

impl<S: Store, N: NewDownstreamService> Replicator<S, N> {
    pub fn new(store: S, new_downstream: N) -> Self {
        Replicator {
            store: store,
            new_downstream: new_downstream,
            downstream: None,
            last_seen_seq: LogPos::zero(),
            state: ReplicatorState::Idle,
        }
    }

    fn process_config_message(&mut self, conf: &HostConfig<SocketAddr>) {
        debug!("logged Config message: {:?}", conf);
        // FIXME: Well, this is blatantly wrong.
        debug!("connecting downstream to: {:?}", conf.head);
        self.downstream = Some(self.new_downstream
            .new_downstream(conf.head));
    }

    fn try_take_next(&mut self) -> Poll<(), Error> {
        if let ReplicatorState::Idle = self.state {
            debug!("Idle, fetching after: {:?}", self.last_seen_seq);
            let fetch_f = self.store.fetch_next(self.last_seen_seq);
            self.state = ReplicatorState::Fetching(fetch_f);
        }
        Ok(Async::Ready(()))
    }

    fn try_process_message(&mut self) -> Poll<(), Error> {
        let (off, val) = if let &mut ReplicatorState::Fetching(ref mut fetch_f) = &mut self.state {
            debug!("Fetching");
            try_ready!(fetch_f.poll())
        } else {
            return Ok(Async::Ready(()));
        };

        debug!("Fetched: {:?}", (&off, &val));
        if let &LogEntry::Config(ref conf) = &val {
            self.process_config_message(conf);
        };

        self.state = if let Some(ref downstream) = self.downstream {
            debug!("Forward {:?} -> {:?}", self.last_seen_seq, off);
            let req = ReplicaRequest::AppendLogEntry {
                assumed_offset: self.last_seen_seq,
                // FIXME: NO. WRONG.
                entry_offset: off,
                datum: val,
            };
            ReplicatorState::Forwarding(downstream.call(req))
        } else {
            debug!("No downstream at {:?}", off);
            ReplicatorState::Idle
        };

        self.last_seen_seq = off;
        Ok(Async::Ready(()))
    }

    fn try_process_forward(&mut self) -> Poll<(), Error> {
        let next = if let &mut ReplicatorState::Forwarding(ref mut f) = &mut self.state {
            match try_ready!(f.poll()) {
                ReplicaResponse::Done(pos) => {
                    debug!("woo! {:?}", pos);
                    Some(ReplicatorState::Idle)
                }
                ReplicaResponse::BadSequence(pos) => {
                    debug!("Bad sequence: resetting to {:?}", pos);
                    self.last_seen_seq = pos;
                    Some(ReplicatorState::Idle)
                }
            }
        } else {
            None
        };
        if let Some(next) = next {
            self.state = next;
        }
        Ok(Async::Ready(()))
    }
}

impl<S: Store, N: NewDownstreamService> Drop for Replicator<S, N> {
    fn drop(&mut self) {
        debug!("Drop Replicator");
    }
}

impl<S: Store, N: NewDownstreamService> Future for Replicator<S, N> {
    type Item = ();
    type Error = Error;
    fn poll(&mut self) -> Poll<(), Error> {
        debug!("Replicator#poll");
        loop {
            try_ready!(self.try_take_next());
            try_ready!(self.try_process_message());
            try_ready!(self.try_process_forward());
        }
    }
}

#[cfg(test)]
mod test {
    use futures::{self, Future, BoxFuture, Async};
    use futures::stream::Stream;
    use service::Service;
    use tokio::channel;
    use replica::LogPos;
    use store::{RamStore, Store};
    use replica::{ReplicaRequest, ReplicaResponse, LogEntry, HostConfig};
    use errors::Error;
    use std::net::SocketAddr;
    use super::*;
    use tokio::reactor::Core;
    use std::time::Duration;
    use std::io;
    use tokio_timer;
    use env_logger;

    type MessageType = ((SocketAddr, ReplicaRequest), futures::Complete<ReplicaResponse>);
    struct MyMagicalDownstream {
        addr: SocketAddr,
        send: channel::Sender<MessageType>,
    }

    struct MyDownstreamBuilder {
        send: channel::Sender<MessageType>,
    }

    impl Service for MyMagicalDownstream {
        type Request = ReplicaRequest;
        type Response = ReplicaResponse;
        type Error = Error;
        type Future = BoxFuture<ReplicaResponse, Error>;
        fn poll_ready(&self) -> Async<()> {
            Async::Ready(())
        }
        fn call(&self, req: Self::Request) -> Self::Future {
            let (c, p) = futures::oneshot();
            match self.send.send(((self.addr.clone(), req), c)) {
                Ok(()) => (),
                Err(e) => return futures::failed(e.into()).boxed(),
            };
            p.map_err(|_| io::Error::new(io::ErrorKind::BrokenPipe, "broken pipe").into())
                .boxed()
        }
    }

    impl NewDownstreamService for MyDownstreamBuilder {
        type Item = MyMagicalDownstream;
        fn new_downstream(&self, addr: SocketAddr) -> Self::Item {
            MyMagicalDownstream {
                addr: addr,
                send: self.send.clone(),
            }
        }
    }

    #[test]
    fn should_start_replicating_to_downstream_on_committed_config_message() {
        env_logger::init().unwrap_or(());
        let store = RamStore::new();
        let timer = tokio_timer::wheel().tick_duration(Duration::from_millis(1)).build();

        let mut core = Core::new().expect("core::new");
        let (tx, rx) = channel::channel(&core.handle()).expect("channel");

        let downstream = MyDownstreamBuilder { send: tx };

        let replica = Replicator::new(store.clone(), downstream);

        core.handle().spawn(replica.map_err(|e| panic!("Replicator failed!: {:?}", e)));
        debug!("Spawned replica task");

        let head_addr = "1.2.3.4:5".parse().expect("parse");

        let config: HostConfig<::std::net::SocketAddr> = HostConfig {
            head: head_addr,
            tail: "1.2.3.6:7".parse().expect("parse"),
        };
        let off = LogPos::zero();
        let _ = append_entry(&store, &mut core, off, LogEntry::Config(config.clone()));

        let (_rx, _response, _assumed0, _off0, entry0) =
            take_next_entry(rx, &head_addr, &mut core, &timer);

        assert_eq!(entry0, LogEntry::Config(config));
    }

    #[test]
    fn should_send_next_log_entry_on_okay_from_downstream() {
        env_logger::init().unwrap_or(());
        let store = RamStore::new();
        let timer = tokio_timer::wheel().tick_duration(Duration::from_millis(1)).build();

        let mut core = Core::new().expect("core::new");
        let (tx, rx) = channel::channel(&core.handle()).expect("channel");

        let downstream = MyDownstreamBuilder { send: tx };

        let replica = Replicator::new(store.clone(), downstream);

        core.handle().spawn(replica.map_err(|e| panic!("Replicator failed!: {:?}", e)));
        debug!("Spawned replica task");

        let head_addr = "1.2.3.4:5".parse().expect("parse");

        let config: HostConfig<::std::net::SocketAddr> = HostConfig {
            head: head_addr,
            tail: "1.2.3.6:7".parse().expect("parse"),
        };

        let off0 = append_entry(&store,
                                &mut core,
                                LogPos::zero(),
                                LogEntry::Config(config.clone()));
        let _off1 = append_entry(&store,
                                 &mut core,
                                 off0,
                                 LogEntry::Data(b"Hello world!".to_vec().into()));

        let (rx, response, _assumed0, off0, _entry0) =
            take_next_entry(rx, &head_addr, &mut core, &timer);

        response.complete(ReplicaResponse::Done(off0));

        let (_rx, _response, assumed1, off1, entry1) =
            take_next_entry(rx, &head_addr, &mut core, &timer);

        assert_eq!((assumed1, entry1),
                   (off0, LogEntry::Data(b"Hello world!".to_vec().into())));
        assert!(off1 > assumed1);
    }

    #[test]
    fn should_restart_replication_on_badsequence_from_downstream() {
        env_logger::init().unwrap_or(());
        let store = RamStore::new();
        let timer = tokio_timer::wheel().tick_duration(Duration::from_millis(1)).build();

        let mut core = Core::new().expect("core::new");
        let (tx, rx) = channel::channel(&core.handle()).expect("channel");

        let downstream = MyDownstreamBuilder { send: tx };

        let replica = Replicator::new(store.clone(), downstream);

        core.handle().spawn(replica.map_err(|e| panic!("Replicator failed!: {:?}", e)));
        debug!("Spawned replica task");

        let head_addr = "1.2.3.4:5".parse().expect("parse");

        let config: HostConfig<::std::net::SocketAddr> = HostConfig {
            head: head_addr,
            tail: "1.2.3.6:7".parse().expect("parse"),
        };

        let log_off = LogPos::zero();
        let log_off0 = append_entry(&store, &mut core, log_off, LogEntry::Config(config.clone()));
        let log_off1 = append_entry(&store,
                                    &mut core,
                                    log_off0,
                                    LogEntry::Data(b"Hello".to_vec().into()));
        let log_off2 = append_entry(&store,
                                    &mut core,
                                    log_off1,
                                    LogEntry::Data(b"world!".to_vec().into()));

        let (rx, response, _assumed0, _off0, _entry0) =
            take_next_entry(rx, &head_addr, &mut core, &timer);

        // So we expect the delivery of "world!"
        let resp = ReplicaResponse::BadSequence(log_off1);
        println!("Respond with: {:?}", resp);
        response.complete(resp);
        let (_rx, _response, assumed1, off1, entry1) =
            take_next_entry(rx, &head_addr, &mut core, &timer);

        assert_eq!((assumed1, off1, entry1),
                   (log_off1, log_off2, LogEntry::Data(b"world!".to_vec().into())));
    }

    fn append_entry<S: Store>(store: &S, core: &mut Core, off: LogPos, entry: LogEntry) -> LogPos {
        let next = off.next();
        debug!("append config message {:?} -> {:?}", off, next);
        core.run(store.append_entry(off, next, entry))
            .expect("append");
        next
    }

    fn take_next_entry(rx: channel::Receiver<MessageType>,
                       target: &SocketAddr,
                       core: &mut Core,
                       timer: &tokio_timer::Timer)
                       -> (channel::Receiver<MessageType>,
                           futures::Complete<ReplicaResponse>,
                           LogPos,
                           LogPos,
                           LogEntry) {
        let f = timer.timeout(rx.into_future().map_err(|(e, _)| e),
                              Duration::from_millis(1000));
        debug!("wait for stub message");
        let (data, rx) = core.run(f).expect("receive downstream");
        let ((addr, msg), response) = data.expect("Some message");
        assert_eq!(&addr, target);
        println!("Some: {:?}", (&addr, &msg));
        // Expect that the target at `head_addr` receives a set of replication messages.
        match msg {
            ReplicaRequest::AppendLogEntry { assumed_offset, entry_offset, datum } => {
                (rx, response, assumed_offset, entry_offset, datum)
            }
        }
    }
}
<|endoftext|>


<commit_before>// "Tifflin" Kernel
// - By John Hodge (thePowersGang)
//
// Core/pci.rs
// - PCI Bus Handling
use _common::*;

struct PCIDev
{
	addr: u16,	// Bus,Slot,Fcn
	vendor: u16,
	device: u16,
	class: u32,

	// TODO: Include bound status, and BAR mappings
	config: [u32,..16]
}

module_define!(PCI, [DeviceManager], init)

fn init()
{
	// 1. Enumerate PCI bus(es)
	let devs = scan_bus(0);
	log_debug!("devs = {}", devs);
	// - All drivers that have PCI bindings should be waiting on this to load
}

fn scan_bus(bus_id: u8) -> Vec<PCIDev>
{
	log_trace!("PCI scan_bus({})", bus_id);
	let mut ret = Vec::new();
	for devidx in range(0, 32)
	{
		match get_device(bus_id, devidx, 0)
		{
		Some(devinfo) => {
			let is_multifunc = (devinfo.config[3] & 0x0080_0000) != 0;
			// Increase device count
			ret.push(devinfo);
			// Handle multi-function devices
			if is_multifunc
			{
				for fcnidx in range(1, 8)
				{
					if let Some(devinfo) = get_device(bus_id, devidx, fcnidx)
					{
						ret.push(devinfo);
					}
				}
			}
			},
		None => {
			// Move along, nothing to see here
			},
		}
	}
	ret
}

fn get_device(bus_id: u8, devidx: u8, function: u8) -> Option<PCIDev>
{
	let addr = get_pci_addr(bus_id, devidx, function);
	let idword = read_word(addr, 0);

	if idword & 0xFFFF == 0xFFFF {
		None
	}
	else {
		log_debug!("Device {:#x} = Dev/Ven {:08x}", addr, idword);
		Some(PCIDev {
			addr: addr,
			vendor: (idword & 0xFFFF) as u16,
			device: (idword >> 16) as u16,
			class: read_word(addr, 2),
			config: [
				idword            , read_word(addr, 1),
				read_word(addr, 2), read_word(addr, 3),
				read_word(addr, 4), read_word(addr, 5),
				read_word(addr, 6), read_word(addr, 7),
				read_word(addr, 8), read_word(addr, 9),
				read_word(addr,10), read_word(addr,11),
				read_word(addr,12), read_word(addr,13),
				read_word(addr,14), read_word(addr,15),
				],
			})
	}
}

fn get_pci_addr(bus_id: u8, dev: u8, fcn: u8) -> u16
{
	(bus_id as u16 << 8) | (dev as u16 << 3) | fcn as u16
}

fn read_word(bus_addr: u16, wordidx: u8) -> u32
{
	let addr = (bus_addr as u32 << 8) | (wordidx as u32 << 2);
	//log_trace!("read_word(bus_addr={:x},idx={}) addr={:#x}", bus_addr, wordidx, addr);
	::arch::pci::read(addr)
}

impl ::core::fmt::Show for PCIDev
{
	fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::result::Result<(),::core::fmt::FormatError>
	{
		write!(f, "{:#04x} V{:04x} D{:04x} {:06x}", self.addr, self.vendor, self.device, self.class)
	}
}

// vim: ft=rust
<commit_msg>Kernel/PCI - Code cleanup<commit_after>// "Tifflin" Kernel
// - By John Hodge (thePowersGang)
//
// Core/pci.rs
// - PCI Bus Handling
use _common::*;

const MAX_FUNC: u8 = 8;	// Address restriction
const MAX_DEV: u8 = 32;	// Address restriction
const CONFIG_WORD_IDENT: u8 = 0;
const CONFIG_WORD_CLASS: u8 = 2;

struct PCIDev
{
	addr: u16,	// Bus,Slot,Fcn
	vendor: u16,
	device: u16,
	class: u32,

	// TODO: Include bound status, and BAR mappings
	config: [u32,..16]
}

module_define!(PCI, [DeviceManager], init)

fn init()
{
	// 1. Enumerate PCI bus(es)
	let devs = scan_bus(0);
	log_debug!("devs = {}", devs);
	// - All drivers that have PCI bindings should be waiting on this to load
}

fn scan_bus(bus_id: u8) -> Vec<PCIDev>
{
	log_trace!("PCI scan_bus({})", bus_id);
	let mut ret = Vec::new();
	for devidx in range(0, MAX_DEV)
	{
		match get_device(bus_id, devidx, 0)
		{
		Some(devinfo) => {
			let is_multifunc = (devinfo.config[3] & 0x0080_0000) != 0;
			// Increase device count
			ret.push(devinfo);
			// Handle multi-function devices (iterate from 1 onwards)
			if is_multifunc
			{
				for fcnidx in range(1, MAX_FUNC)
				{
					if let Some(devinfo) = get_device(bus_id, devidx, fcnidx)
					{
						ret.push(devinfo);
					}
				}
			}
			},
		None => {
			// Move along, nothing to see here
			},
		}
	}
	ret
}

fn get_device(bus_id: u8, devidx: u8, function: u8) -> Option<PCIDev>
{
	let addr = get_pci_addr(bus_id, devidx, function);
	let idword = read_word(addr, CONFIG_WORD_IDENT);

	if idword & 0xFFFF == 0xFFFF {
		None
	}
	else {
		log_debug!("Device {:#x} = Dev/Ven {:08x}", addr, idword);
		Some(PCIDev {
			addr: addr,
			vendor: (idword & 0xFFFF) as u16,
			device: (idword >> 16) as u16,
			class: read_word(addr, CONFIG_WORD_CLASS),
			config: [
				idword            , read_word(addr, 1),
				read_word(addr, 2), read_word(addr, 3),
				read_word(addr, 4), read_word(addr, 5),
				read_word(addr, 6), read_word(addr, 7),
				read_word(addr, 8), read_word(addr, 9),
				read_word(addr,10), read_word(addr,11),
				read_word(addr,12), read_word(addr,13),
				read_word(addr,14), read_word(addr,15),
				],
			})
	}
}

fn get_pci_addr(bus_id: u8, dev: u8, fcn: u8) -> u16
{
	assert!(dev < MAX_DEV);
	assert!(fcn < MAX_FUNC);
	(bus_id as u16 << 8) | (dev as u16 << 3) | fcn as u16
}

fn read_word(bus_addr: u16, wordidx: u8) -> u32
{
	let addr = (bus_addr as u32 << 8) | (wordidx as u32 << 2);
	//log_trace!("read_word(bus_addr={:x},idx={}) addr={:#x}", bus_addr, wordidx, addr);
	::arch::pci::read(addr)
}

impl ::core::fmt::Show for PCIDev
{
	fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::result::Result<(),::core::fmt::FormatError>
	{
		write!(f, "{:#04x} V{:04x} D{:04x} {:06x}", self.addr, self.vendor, self.device, self.class)
	}
}

// vim: ft=rust
<|endoftext|>


<commit_before>use error::Error;
use client::Client;
use params::{List, Metadata, Timestamp};
use resources::{Currency, Discount, Plan};
use serde_qs as query;

/// The set of parameters that can be used when creating or updating an invoice.
///
/// For more details see https://stripe.com/docs/api#create_invoice, https://stripe.com/docs/api#update_invoice.
#[derive(Default, Serialize)]
pub struct InvoiceParams<'a> {
    #[serde(skip_serializing_if = "Option::is_none")] pub application_fee: Option<u64>,
    #[serde(skip_serializing_if = "Option::is_none")] pub customer: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")] pub description: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")] pub statement_descriptor: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")] pub subscription: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")] pub tax_percent: Option<f64>,

    #[serde(skip_serializing_if = "Option::is_none")] pub closed: Option<bool>,
    #[serde(skip_serializing_if = "Option::is_none")] pub forgiven: Option<bool>,
}

#[derive(Default, Serialize)]
pub struct InvoiceItemParams<'a> {
    #[serde(skip_serializing_if = "Option::is_none")] pub amount: Option<i64>,
    #[serde(skip_serializing_if = "Option::is_none")] pub currency: Option<Currency>,
    #[serde(skip_serializing_if = "Option::is_none")] pub customer: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")] pub description: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")] pub discountable: Option<bool>,
    #[serde(skip_serializing_if = "Option::is_none")] pub invoice: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")] pub metadata: Option<bool>,
    #[serde(skip_serializing_if = "Option::is_none")] pub subscription: Option<bool>,
}

/*
#[derive(Serialize)]
pub struct InvoiceListLinesParams {
    #[serde(skip_serializing_if = "Option::is_none")] pub limit: Option<u64>,
    #[serde(skip_serializing_if = "Option::is_none")] pub ending_before: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")] pub starting_after: Option<String>,

    ..
}
*/

/// Period is a structure representing a start and end dates.
#[derive(Debug, Deserialize)]
pub struct Period {
    pub start: Timestamp,
    pub end: Timestamp,
}

/// The resource representing a Stripe invoice line item.
///
/// For more details see https://stripe.com/docs/api#invoice_line_item_object.
#[derive(Debug, Deserialize)]
pub struct InvoiceItem {
    pub id: String,
    pub amount: i64,
    pub currency: Currency,
    pub description: Option<String>,
    pub discountable: bool,
    pub livemode: bool,
    pub metadata: Metadata,
    pub period: Period,
    pub plan: Option<Plan>,
    pub proration: bool,
    pub quantity: Option<u64>,
    pub subscription: Option<String>,
    pub subscription_item: Option<String>,
    #[serde(rename = "type")] pub item_type: String, // (invoiceitem, subscription)
}

/// The resource representing a Stripe invoice.
///
/// For more details see https://stripe.com/docs/api#invoice_object.
#[derive(Debug, Deserialize)]
pub struct Invoice {
    pub id: String,
    pub amount_due: u64,
    pub application_fee: Option<u64>,
    pub attempt_count: u64,
    pub attempted: bool,
    pub charge: Option<String>,
    pub closed: bool,
    pub currency: Currency,
    pub customer: String,
    pub date: Timestamp,
    pub description: Option<String>,
    pub discount: Option<Discount>,
    pub ending_balance: Option<i64>,
    pub forgiven: bool,
    pub lines: List<InvoiceItem>,
    pub livemode: bool,
    pub metadata: Metadata,
    pub next_payment_attempt: Option<Timestamp>,
    pub paid: bool,
    pub period_end: Timestamp,
    pub period_start: Timestamp,
    pub receipt_number: Option<String>,
    pub starting_balance: i64,
    pub statment_descriptor: Option<String>,
    pub subscription: Option<String>,
    pub subscription_proration_date: Option<Timestamp>,
    pub subtotal: i64,
    pub tax: Option<i64>,
    pub tax_percent: Option<f64>,
    pub total: i64,
    pub webhooks_delivered_at: Option<Timestamp>,
}

#[derive(Default, Serialize)]
pub struct InvoiceListParams<'a> {
    #[serde(skip_serializing_if = "Option::is_none")] pub limit: Option<u64>,
    #[serde(skip_serializing_if = "Option::is_none")] pub customer: Option<&'a str>,
}

impl Invoice {
    /// Creates a new invoice.
    ///
    /// For more details see https://stripe.com/docs/api#create_invoice.
    pub fn create(client: &Client, params: InvoiceParams) -> Result<Invoice, Error> {
        client.post("/invoices", params)
    }

    /// Retrieves the details of an invoice.
    ///
    /// For more details see https://stripe.com/docs/api#retrieve_invoice.
    pub fn retrieve(client: &Client, invoice_id: &str) -> Result<Invoice, Error> {
        client.get(&format!("/invoices/{}", invoice_id))
    }

    // TODO: Implement InvoiceListLinesParams
    // pub fn get_lines(client: &Client, invoice_id: &str, params: InvoiceListLinesParams) -> Result<List<InvoiceItem>, Error> {
    //     client.get(&format!("/invoices/{}/lines", invoice_id))
    // }

    // TODO: Implement InvoiceUpcomingParams
    // pub fn get_upcoming(client: &Client, params: InvoiceUpcomingParams) -> Result<Invoice, Error> {
    //     client.get(&format!("/invoices/upcoming?customer={}", invoice_id))
    // }

    /// Pays an invoice.
    ///
    /// For more details see https://stripe.com/docs/api#pay_invoice.
    pub fn pay(client: &Client, invoice_id: &str) -> Result<Invoice, Error> {
        client.post_empty(&format!("/invoices/{}/pay", invoice_id))
    }

    /// Updates an invoice.
    ///
    /// For more details see https://stripe.com/docs/api#update_invoice.
    pub fn update(client: &Client, invoice_id: &str, params: InvoiceParams) -> Result<Invoice, Error> {
        client.post(&format!("/invoices/{}", invoice_id), &params)
    }

    /// Lists all invoices with optional customer_id and limit params
    ///
    /// For more details see https://stripe.com/docs/api#list_invoices.
    pub fn list(client: &Client, params: InvoiceListParams) -> Result<List<Invoice>, Error> {
        client.get(&format!("/invoices?{}", query::to_string(&params)?))
    }
}

impl InvoiceItem {
    /// Creates an invoice line item.
    ///
    /// For more details see https://stripe.com/docs/api/node#invoice_line_item_object
    pub fn create(client: &Client, params: InvoiceItemParams) -> Result<InvoiceItem, Error> {
        client.post(&format!("/invoiceitems"), &params)
    }

}
<commit_msg>Invoice item type is not returned after create<commit_after>use error::Error;
use client::Client;
use params::{List, Metadata, Timestamp};
use resources::{Currency, Discount, Plan};
use serde_qs as query;

/// The set of parameters that can be used when creating or updating an invoice.
///
/// For more details see https://stripe.com/docs/api#create_invoice, https://stripe.com/docs/api#update_invoice.
#[derive(Default, Serialize)]
pub struct InvoiceParams<'a> {
    #[serde(skip_serializing_if = "Option::is_none")] pub application_fee: Option<u64>,
    #[serde(skip_serializing_if = "Option::is_none")] pub customer: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")] pub description: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")] pub statement_descriptor: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")] pub subscription: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")] pub tax_percent: Option<f64>,

    #[serde(skip_serializing_if = "Option::is_none")] pub closed: Option<bool>,
    #[serde(skip_serializing_if = "Option::is_none")] pub forgiven: Option<bool>,
}

#[derive(Default, Serialize)]
pub struct InvoiceItemParams<'a> {
    #[serde(skip_serializing_if = "Option::is_none")] pub amount: Option<i64>,
    #[serde(skip_serializing_if = "Option::is_none")] pub currency: Option<Currency>,
    #[serde(skip_serializing_if = "Option::is_none")] pub customer: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")] pub description: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")] pub discountable: Option<bool>,
    #[serde(skip_serializing_if = "Option::is_none")] pub invoice: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")] pub metadata: Option<bool>,
    #[serde(skip_serializing_if = "Option::is_none")] pub subscription: Option<bool>,
}

/*
#[derive(Serialize)]
pub struct InvoiceListLinesParams {
    #[serde(skip_serializing_if = "Option::is_none")] pub limit: Option<u64>,
    #[serde(skip_serializing_if = "Option::is_none")] pub ending_before: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")] pub starting_after: Option<String>,

    ..
}
*/

/// Period is a structure representing a start and end dates.
#[derive(Debug, Deserialize)]
pub struct Period {
    pub start: Timestamp,
    pub end: Timestamp,
}

/// The resource representing a Stripe invoice line item.
///
/// For more details see https://stripe.com/docs/api#invoice_line_item_object.
#[derive(Debug, Deserialize)]
pub struct InvoiceItem {
    pub id: String,
    pub amount: i64,
    pub currency: Currency,
    pub description: Option<String>,
    pub discountable: bool,
    pub livemode: bool,
    pub metadata: Metadata,
    pub period: Period,
    pub plan: Option<Plan>,
    pub proration: bool,
    pub quantity: Option<u64>,
    pub subscription: Option<String>,
    pub subscription_item: Option<String>,
    #[serde(default)] // NOTE: Missing in response to InvoiceItem create
    #[serde(rename = "type")]
    pub item_type: String, // (invoiceitem, subscription)
}

/// The resource representing a Stripe invoice.
///
/// For more details see https://stripe.com/docs/api#invoice_object.
#[derive(Debug, Deserialize)]
pub struct Invoice {
    pub id: String,
    pub amount_due: u64,
    pub application_fee: Option<u64>,
    pub attempt_count: u64,
    pub attempted: bool,
    pub charge: Option<String>,
    pub closed: bool,
    pub currency: Currency,
    pub customer: String,
    pub date: Timestamp,
    pub description: Option<String>,
    pub discount: Option<Discount>,
    pub ending_balance: Option<i64>,
    pub forgiven: bool,
    pub lines: List<InvoiceItem>,
    pub livemode: bool,
    pub metadata: Metadata,
    pub next_payment_attempt: Option<Timestamp>,
    pub paid: bool,
    pub period_end: Timestamp,
    pub period_start: Timestamp,
    pub receipt_number: Option<String>,
    pub starting_balance: i64,
    pub statment_descriptor: Option<String>,
    pub subscription: Option<String>,
    pub subscription_proration_date: Option<Timestamp>,
    pub subtotal: i64,
    pub tax: Option<i64>,
    pub tax_percent: Option<f64>,
    pub total: i64,
    pub webhooks_delivered_at: Option<Timestamp>,
}

#[derive(Default, Serialize)]
pub struct InvoiceListParams<'a> {
    #[serde(skip_serializing_if = "Option::is_none")] pub limit: Option<u64>,
    #[serde(skip_serializing_if = "Option::is_none")] pub customer: Option<&'a str>,
}

impl Invoice {
    /// Creates a new invoice.
    ///
    /// For more details see https://stripe.com/docs/api#create_invoice.
    pub fn create(client: &Client, params: InvoiceParams) -> Result<Invoice, Error> {
        client.post("/invoices", params)
    }

    /// Retrieves the details of an invoice.
    ///
    /// For more details see https://stripe.com/docs/api#retrieve_invoice.
    pub fn retrieve(client: &Client, invoice_id: &str) -> Result<Invoice, Error> {
        client.get(&format!("/invoices/{}", invoice_id))
    }

    // TODO: Implement InvoiceListLinesParams
    // pub fn get_lines(client: &Client, invoice_id: &str, params: InvoiceListLinesParams) -> Result<List<InvoiceItem>, Error> {
    //     client.get(&format!("/invoices/{}/lines", invoice_id))
    // }

    // TODO: Implement InvoiceUpcomingParams
    // pub fn get_upcoming(client: &Client, params: InvoiceUpcomingParams) -> Result<Invoice, Error> {
    //     client.get(&format!("/invoices/upcoming?customer={}", invoice_id))
    // }

    /// Pays an invoice.
    ///
    /// For more details see https://stripe.com/docs/api#pay_invoice.
    pub fn pay(client: &Client, invoice_id: &str) -> Result<Invoice, Error> {
        client.post_empty(&format!("/invoices/{}/pay", invoice_id))
    }

    /// Updates an invoice.
    ///
    /// For more details see https://stripe.com/docs/api#update_invoice.
    pub fn update(client: &Client, invoice_id: &str, params: InvoiceParams) -> Result<Invoice, Error> {
        client.post(&format!("/invoices/{}", invoice_id), &params)
    }

    /// Lists all invoices with optional customer_id and limit params
    ///
    /// For more details see https://stripe.com/docs/api#list_invoices.
    pub fn list(client: &Client, params: InvoiceListParams) -> Result<List<Invoice>, Error> {
        client.get(&format!("/invoices?{}", query::to_string(&params)?))
    }
}

impl InvoiceItem {
    /// Creates an invoice line item.
    ///
    /// For more details see https://stripe.com/docs/api/node#invoice_line_item_object
    pub fn create(client: &Client, params: InvoiceItemParams) -> Result<InvoiceItem, Error> {
        client.post(&format!("/invoiceitems"), &params)
    }

}
<|endoftext|>


<commit_before>use if_chain::if_chain;
use rustc_hir::{Local, PatKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_session::{declare_lint_pass, declare_tool_lint};

use crate::utils::{implements_trait, is_must_use_func_call, is_must_use_ty, match_type, paths, span_lint_and_help};

declare_clippy_lint! {
    /// **What it does:** Checks for `let _ = <expr>`
    /// where expr is #[must_use]
    ///
    /// **Why is this bad?** It's better to explicitly
    /// handle the value of a #[must_use] expr
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// fn f() -> Result<u32, u32> {
    ///     Ok(0)
    /// }
    ///
    /// let _ = f();
    /// // is_ok() is marked #[must_use]
    /// let _ = f().is_ok();
    /// ```
    pub LET_UNDERSCORE_MUST_USE,
    restriction,
    "non-binding let on a `#[must_use]` expression"
}

declare_clippy_lint! {
    /// **What it does:** Checks for `let _ = sync_lock`
    ///
    /// **Why is this bad?** This statement immediately drops the lock instead of
    /// extending its lifetime to the end of the scope, which is often not intended.
    /// To extend lock lifetime to the end of the scope, use an underscore-prefixed
    /// name instead (i.e. _lock). If you want to explicitly drop the lock,
    /// `std::mem::drop` conveys your intention better and is less error-prone.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// Bad:
    /// ```rust,ignore
    /// let _ = mutex.lock();
    /// ```
    ///
    /// Good:
    /// ```rust,ignore
    /// let _lock = mutex.lock();
    /// ```
    pub LET_UNDERSCORE_LOCK,
    correctness,
    "non-binding let on a synchronization lock"
}

declare_clippy_lint! {
    /// **What it does:** Checks for `let _ = <expr>`
    /// where expr has a type that implements `Drop`
    ///
    /// **Why is this bad?** This statement immediately drops the initializer
    /// expression instead of extending its lifetime to the end of the scope, which
    /// is often not intended. To extend the expression's lifetime to the end of the
    /// scope, use an underscore-prefixed name instead (i.e. _var). If you want to
    /// explicitly drop the expression, `std::mem::drop` conveys your intention
    /// better and is less error-prone.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// Bad:
    /// ```rust,ignore
    /// struct Droppable;
    /// impl Drop for Droppable {
    ///     fn drop(&mut self) {}
    /// }
    /// let _ = Droppable;
    /// ```
    ///
    /// Good:
    /// ```rust,ignore
    /// let _droppable = Droppable;
    /// ```
    pub LET_UNDERSCORE_DROP,
    correctness,
    "non-binding let on a type that implements `Drop`"
}

declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_DROP]);

const SYNC_GUARD_PATHS: [&[&str]; 3] = [
    &paths::MUTEX_GUARD,
    &paths::RWLOCK_READ_GUARD,
    &paths::RWLOCK_WRITE_GUARD,
];

impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
    fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
        if in_external_macro(cx.tcx.sess, local.span) {
            return;
        }

        if_chain! {
            if let PatKind::Wild = local.pat.kind;
            if let Some(ref init) = local.init;
            then {
                let init_ty = cx.typeck_results().expr_ty(init);
                let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() {
                    GenericArgKind::Type(inner_ty) => {
                        SYNC_GUARD_PATHS.iter().any(|path| match_type(cx, inner_ty, path))
                    },

                    GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
                });
                let implements_drop = cx.tcx.lang_items().drop_trait().map_or(false, |drop_trait|
                    init_ty.walk().any(|inner| match inner.unpack() {
                        GenericArgKind::Type(inner_ty) => {
                            implements_trait(cx, inner_ty, drop_trait, &[])
                        },

                        GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
                    })
                );
                if contains_sync_guard {
                    span_lint_and_help(
                        cx,
                        LET_UNDERSCORE_LOCK,
                        local.span,
                        "non-binding let on a synchronization lock",
                        None,
                        "consider using an underscore-prefixed named \
                            binding or dropping explicitly with `std::mem::drop`"
                    )
                } else if implements_drop {
                    span_lint_and_help(
                        cx,
                        LET_UNDERSCORE_DROP,
                        local.span,
                        "non-binding `let` on a type that implements `Drop`",
                        None,
                        "consider using an underscore-prefixed named \
                            binding or dropping explicitly with `std::mem::drop`"
                    )
                } else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) {
                    span_lint_and_help(
                        cx,
                        LET_UNDERSCORE_MUST_USE,
                        local.span,
                        "non-binding let on an expression with `#[must_use]` type",
                        None,
                        "consider explicitly using expression value"
                    )
                } else if is_must_use_func_call(cx, init) {
                    span_lint_and_help(
                        cx,
                        LET_UNDERSCORE_MUST_USE,
                        local.span,
                        "non-binding let on a result of a `#[must_use]` function",
                        None,
                        "consider explicitly using function result"
                    )
                }
            }
        }
    }
}
<commit_msg>Update clippy_lints/src/let_underscore.rs<commit_after>use if_chain::if_chain;
use rustc_hir::{Local, PatKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_session::{declare_lint_pass, declare_tool_lint};

use crate::utils::{implements_trait, is_must_use_func_call, is_must_use_ty, match_type, paths, span_lint_and_help};

declare_clippy_lint! {
    /// **What it does:** Checks for `let _ = <expr>`
    /// where expr is #[must_use]
    ///
    /// **Why is this bad?** It's better to explicitly
    /// handle the value of a #[must_use] expr
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// fn f() -> Result<u32, u32> {
    ///     Ok(0)
    /// }
    ///
    /// let _ = f();
    /// // is_ok() is marked #[must_use]
    /// let _ = f().is_ok();
    /// ```
    pub LET_UNDERSCORE_MUST_USE,
    restriction,
    "non-binding let on a `#[must_use]` expression"
}

declare_clippy_lint! {
    /// **What it does:** Checks for `let _ = sync_lock`
    ///
    /// **Why is this bad?** This statement immediately drops the lock instead of
    /// extending its lifetime to the end of the scope, which is often not intended.
    /// To extend lock lifetime to the end of the scope, use an underscore-prefixed
    /// name instead (i.e. _lock). If you want to explicitly drop the lock,
    /// `std::mem::drop` conveys your intention better and is less error-prone.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// Bad:
    /// ```rust,ignore
    /// let _ = mutex.lock();
    /// ```
    ///
    /// Good:
    /// ```rust,ignore
    /// let _lock = mutex.lock();
    /// ```
    pub LET_UNDERSCORE_LOCK,
    correctness,
    "non-binding let on a synchronization lock"
}

declare_clippy_lint! {
    /// **What it does:** Checks for `let _ = <expr>`
    /// where expr has a type that implements `Drop`
    ///
    /// **Why is this bad?** This statement immediately drops the initializer
    /// expression instead of extending its lifetime to the end of the scope, which
    /// is often not intended. To extend the expression's lifetime to the end of the
    /// scope, use an underscore-prefixed name instead (i.e. _var). If you want to
    /// explicitly drop the expression, `std::mem::drop` conveys your intention
    /// better and is less error-prone.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// Bad:
    /// ```rust,ignore
    /// struct Droppable;
    /// impl Drop for Droppable {
    ///     fn drop(&mut self) {}
    /// }
    /// {
    ///     let _ = Droppable;
    ///     //               ^ dropped here
    ///     /* more code */
    /// }
    /// ```
    ///
    /// Good:
    /// ```rust,ignore
    /// {
    ///     let _droppable = Droppable;
    ///     /* more code */
    ///     // dropped at end of scope
    /// }
    /// ```
    pub LET_UNDERSCORE_DROP,
    correctness,
    "non-binding let on a type that implements `Drop`"
}

declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_DROP]);

const SYNC_GUARD_PATHS: [&[&str]; 3] = [
    &paths::MUTEX_GUARD,
    &paths::RWLOCK_READ_GUARD,
    &paths::RWLOCK_WRITE_GUARD,
];

impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
    fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
        if in_external_macro(cx.tcx.sess, local.span) {
            return;
        }

        if_chain! {
            if let PatKind::Wild = local.pat.kind;
            if let Some(ref init) = local.init;
            then {
                let init_ty = cx.typeck_results().expr_ty(init);
                let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() {
                    GenericArgKind::Type(inner_ty) => {
                        SYNC_GUARD_PATHS.iter().any(|path| match_type(cx, inner_ty, path))
                    },

                    GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
                });
                let implements_drop = cx.tcx.lang_items().drop_trait().map_or(false, |drop_trait|
                    init_ty.walk().any(|inner| match inner.unpack() {
                        GenericArgKind::Type(inner_ty) => {
                            implements_trait(cx, inner_ty, drop_trait, &[])
                        },

                        GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
                    })
                );
                if contains_sync_guard {
                    span_lint_and_help(
                        cx,
                        LET_UNDERSCORE_LOCK,
                        local.span,
                        "non-binding let on a synchronization lock",
                        None,
                        "consider using an underscore-prefixed named \
                            binding or dropping explicitly with `std::mem::drop`"
                    )
                } else if implements_drop {
                    span_lint_and_help(
                        cx,
                        LET_UNDERSCORE_DROP,
                        local.span,
                        "non-binding `let` on a type that implements `Drop`",
                        None,
                        "consider using an underscore-prefixed named \
                            binding or dropping explicitly with `std::mem::drop`"
                    )
                } else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) {
                    span_lint_and_help(
                        cx,
                        LET_UNDERSCORE_MUST_USE,
                        local.span,
                        "non-binding let on an expression with `#[must_use]` type",
                        None,
                        "consider explicitly using expression value"
                    )
                } else if is_must_use_func_call(cx, init) {
                    span_lint_and_help(
                        cx,
                        LET_UNDERSCORE_MUST_USE,
                        local.span,
                        "non-binding let on a result of a `#[must_use]` function",
                        None,
                        "consider explicitly using function result"
                    )
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>#![allow(non_snake_case)]

extern crate jsontests;
extern crate serde_json;
#[macro_use]
extern crate lazy_static;

use serde_json::Value;
use jsontests::test_transaction;

lazy_static! {
    static ref TESTS: Value =
        serde_json::from_str(include_str!("files/vmSystemOperationsTest.json")).unwrap();
}

#[test] fn aBAcalls0() { assert_eq!(test_transaction("ABAcalls0", &TESTS["ABAcalls0"], true), true); }
#[test] fn aBAcalls1() { assert_eq!(test_transaction("ABAcalls1", &TESTS["ABAcalls1"], true), true); }
#[test] fn aBAcalls2() { assert_eq!(test_transaction("ABAcalls2", &TESTS["ABAcalls2"], true), true); }
#[test] fn aBAcalls3() { assert_eq!(test_transaction("ABAcalls3", &TESTS["ABAcalls3"], true), true); }
#[test] fn aBAcallsSuicide0() { assert_eq!(test_transaction("ABAcallsSuicide0", &TESTS["ABAcallsSuicide0"], true), true); }
#[test] fn aBAcallsSuicide1() { assert_eq!(test_transaction("ABAcallsSuicide1", &TESTS["ABAcallsSuicide1"], true), true); }
#[test] fn callRecursiveBomb0() { assert_eq!(test_transaction("CallRecursiveBomb0", &TESTS["CallRecursiveBomb0"], true), true); }
#[test] fn callRecursiveBomb1() { assert_eq!(test_transaction("CallRecursiveBomb1", &TESTS["CallRecursiveBomb1"], true), true); }
#[test] fn callRecursiveBomb2() { assert_eq!(test_transaction("CallRecursiveBomb2", &TESTS["CallRecursiveBomb2"], true), true); }
#[test] fn callRecursiveBomb3() { assert_eq!(test_transaction("CallRecursiveBomb3", &TESTS["CallRecursiveBomb3"], true), true); }
#[test] fn callToNameRegistrator0() { assert_eq!(test_transaction("CallToNameRegistrator0", &TESTS["CallToNameRegistrator0"], true), true); }
#[test] fn callToNameRegistratorNotMuchMemory0() { assert_eq!(test_transaction("CallToNameRegistratorNotMuchMemory0", &TESTS["CallToNameRegistratorNotMuchMemory0"], true), true); }
#[test] fn callToNameRegistratorNotMuchMemory1() { assert_eq!(test_transaction("CallToNameRegistratorNotMuchMemory1", &TESTS["CallToNameRegistratorNotMuchMemory1"], true), true); }
#[test] fn callToNameRegistratorOutOfGas() { assert_eq!(test_transaction("CallToNameRegistratorOutOfGas", &TESTS["CallToNameRegistratorOutOfGas"], true), true); }
#[test] fn callToNameRegistratorTooMuchMemory0() { assert_eq!(test_transaction("CallToNameRegistratorTooMuchMemory0", &TESTS["CallToNameRegistratorTooMuchMemory0"], true), true); }
#[test] fn callToNameRegistratorTooMuchMemory1() { assert_eq!(test_transaction("CallToNameRegistratorTooMuchMemory1", &TESTS["CallToNameRegistratorTooMuchMemory1"], true), true); }
#[test] fn callToNameRegistratorTooMuchMemory2() { assert_eq!(test_transaction("CallToNameRegistratorTooMuchMemory2", &TESTS["CallToNameRegistratorTooMuchMemory2"], true), true); }
#[test] fn callToReturn1() { assert_eq!(test_transaction("CallToReturn1", &TESTS["CallToReturn1"], true), true); }
#[test] fn postToNameRegistrator0() { assert_eq!(test_transaction("PostToNameRegistrator0", &TESTS["PostToNameRegistrator0"], true), true); }
#[test] fn postToReturn1() { assert_eq!(test_transaction("PostToReturn1", &TESTS["PostToReturn1"], true), true); }
#[test] fn testNameRegistrator() { assert_eq!(test_transaction("TestNameRegistrator", &TESTS["TestNameRegistrator"], true), true); }
#[test] fn callcodeToNameRegistrator0() { assert_eq!(test_transaction("callcodeToNameRegistrator0", &TESTS["callcodeToNameRegistrator0"], true), true); }
#[test] fn callcodeToReturn1() { assert_eq!(test_transaction("callcodeToReturn1", &TESTS["callcodeToReturn1"], true), true); }
#[test] fn callstatelessToNameRegistrator0() { assert_eq!(test_transaction("callstatelessToNameRegistrator0", &TESTS["callstatelessToNameRegistrator0"], true), true); }
#[test] fn callstatelessToReturn1() { assert_eq!(test_transaction("callstatelessToReturn1", &TESTS["callstatelessToReturn1"], true), true); }
#[test] fn createNameRegistrator() { assert_eq!(test_transaction("createNameRegistrator", &TESTS["createNameRegistrator"], true), true); }
#[test] fn createNameRegistratorOutOfMemoryBonds0() { assert_eq!(test_transaction("createNameRegistratorOutOfMemoryBonds0", &TESTS["createNameRegistratorOutOfMemoryBonds0"], true), true); }
#[test] fn createNameRegistratorOutOfMemoryBonds1() { assert_eq!(test_transaction("createNameRegistratorOutOfMemoryBonds1", &TESTS["createNameRegistratorOutOfMemoryBonds1"], true), true); }
#[test] fn createNameRegistratorValueTooHigh() { assert_eq!(test_transaction("createNameRegistratorValueTooHigh", &TESTS["createNameRegistratorValueTooHigh"], true), true); }
#[test] fn return0() { assert_eq!(test_transaction("return0", &TESTS["return0"], true), true); }
#[test] fn return1() { assert_eq!(test_transaction("return1", &TESTS["return1"], true), true); }
#[test] fn return2() { assert_eq!(test_transaction("return2", &TESTS["return2"], true), true); }
#[test] fn suicide0() { assert_eq!(test_transaction("suicide0", &TESTS["suicide0"], true), true); }
#[test] fn suicideNotExistingAccount() { assert_eq!(test_transaction("suicideNotExistingAccount", &TESTS["suicideNotExistingAccount"], true), true); }
#[test] fn suicideSendEtherToMe() { assert_eq!(test_transaction("suicideSendEtherToMe", &TESTS["suicideSendEtherToMe"], true), true); }
<commit_msg>Remove several vmtests<commit_after>#![allow(non_snake_case)]

extern crate jsontests;
extern crate serde_json;
#[macro_use]
extern crate lazy_static;

use serde_json::Value;
use jsontests::test_transaction;

lazy_static! {
    static ref TESTS: Value =
        serde_json::from_str(include_str!("files/vmSystemOperationsTest.json")).unwrap();
}

#[test] fn aBAcalls1() { assert_eq!(test_transaction("ABAcalls1", &TESTS["ABAcalls1"], true), true); }
#[test] fn aBAcalls2() { assert_eq!(test_transaction("ABAcalls2", &TESTS["ABAcalls2"], true), true); }
#[test] fn aBAcalls3() { assert_eq!(test_transaction("ABAcalls3", &TESTS["ABAcalls3"], true), true); }
#[test] fn callRecursiveBomb0() { assert_eq!(test_transaction("CallRecursiveBomb0", &TESTS["CallRecursiveBomb0"], true), true); }
#[test] fn callToNameRegistratorNotMuchMemory0() { assert_eq!(test_transaction("CallToNameRegistratorNotMuchMemory0", &TESTS["CallToNameRegistratorNotMuchMemory0"], true), true); }
#[test] fn callToNameRegistratorNotMuchMemory1() { assert_eq!(test_transaction("CallToNameRegistratorNotMuchMemory1", &TESTS["CallToNameRegistratorNotMuchMemory1"], true), true); }
#[test] fn callToNameRegistratorOutOfGas() { assert_eq!(test_transaction("CallToNameRegistratorOutOfGas", &TESTS["CallToNameRegistratorOutOfGas"], true), true); }
#[test] fn callToNameRegistratorTooMuchMemory0() { assert_eq!(test_transaction("CallToNameRegistratorTooMuchMemory0", &TESTS["CallToNameRegistratorTooMuchMemory0"], true), true); }
#[test] fn callToNameRegistratorTooMuchMemory1() { assert_eq!(test_transaction("CallToNameRegistratorTooMuchMemory1", &TESTS["CallToNameRegistratorTooMuchMemory1"], true), true); }
#[test] fn callToNameRegistratorTooMuchMemory2() { assert_eq!(test_transaction("CallToNameRegistratorTooMuchMemory2", &TESTS["CallToNameRegistratorTooMuchMemory2"], true), true); }
#[test] fn postToNameRegistrator0() { assert_eq!(test_transaction("PostToNameRegistrator0", &TESTS["PostToNameRegistrator0"], true), true); }
#[test] fn postToReturn1() { assert_eq!(test_transaction("PostToReturn1", &TESTS["PostToReturn1"], true), true); }
#[test] fn testNameRegistrator() { assert_eq!(test_transaction("TestNameRegistrator", &TESTS["TestNameRegistrator"], true), true); }
#[test] fn callstatelessToNameRegistrator0() { assert_eq!(test_transaction("callstatelessToNameRegistrator0", &TESTS["callstatelessToNameRegistrator0"], true), true); }
#[test] fn callstatelessToReturn1() { assert_eq!(test_transaction("callstatelessToReturn1", &TESTS["callstatelessToReturn1"], true), true); }
#[test] fn createNameRegistrator() { assert_eq!(test_transaction("createNameRegistrator", &TESTS["createNameRegistrator"], true), true); }
#[test] fn createNameRegistratorOutOfMemoryBonds0() { assert_eq!(test_transaction("createNameRegistratorOutOfMemoryBonds0", &TESTS["createNameRegistratorOutOfMemoryBonds0"], true), true); }
#[test] fn createNameRegistratorOutOfMemoryBonds1() { assert_eq!(test_transaction("createNameRegistratorOutOfMemoryBonds1", &TESTS["createNameRegistratorOutOfMemoryBonds1"], true), true); }
#[test] fn createNameRegistratorValueTooHigh() { assert_eq!(test_transaction("createNameRegistratorValueTooHigh", &TESTS["createNameRegistratorValueTooHigh"], true), true); }
#[test] fn return0() { assert_eq!(test_transaction("return0", &TESTS["return0"], true), true); }
#[test] fn return1() { assert_eq!(test_transaction("return1", &TESTS["return1"], true), true); }
#[test] fn return2() { assert_eq!(test_transaction("return2", &TESTS["return2"], true), true); }
#[test] fn suicide0() { assert_eq!(test_transaction("suicide0", &TESTS["suicide0"], true), true); }
#[test] fn suicideNotExistingAccount() { assert_eq!(test_transaction("suicideNotExistingAccount", &TESTS["suicideNotExistingAccount"], true), true); }
#[test] fn suicideSendEtherToMe() { assert_eq!(test_transaction("suicideSendEtherToMe", &TESTS["suicideSendEtherToMe"], true), true); }
<|endoftext|>


<commit_before><commit_msg>Record frame images by default when debug=true on compare()<commit_after><|endoftext|>


<commit_before>//! MySQL specific types

#[cfg(feature = "chrono")]
mod date_and_time;
mod numeric;

use byteorder::WriteBytesExt;
use mysql::{Mysql, MysqlType};
#[cfg(not(feature = "postgres"))]
use query_builder::QueryId;
use std::error::Error as StdError;
use std::io::Write;
use types::{FromSql, HasSqlType, IsNull, Tinyint, ToSql, ToSqlOutput};

primitive_impls!(Tinyint -> (i8, mysql: (Tiny)));

impl ToSql<::types::Tinyint, Mysql> for i8 {
    fn to_sql<W: Write>(
        &self,
        out: &mut ToSqlOutput<W, Mysql>,
    ) -> Result<IsNull, Box<StdError + Send + Sync>> {
        out.write_i8(*self)
            .map(|_| IsNull::No)
            .map_err(|e| Box::new(e) as Box<StdError + Send + Sync>)
    }
}

impl FromSql<::types::Tinyint, Mysql> for i8 {
    fn from_sql(bytes: Option<&[u8]>) -> Result<Self, Box<StdError + Send + Sync>> {
        let bytes = not_none!(bytes);
        Ok(bytes[0] as i8)
    }
}

impl ToSql<::types::Bool, Mysql> for bool {
    fn to_sql<W: Write>(
        &self,
        out: &mut ToSqlOutput<W, Mysql>,
    ) -> Result<IsNull, Box<StdError + Send + Sync>> {
        let int_value = if *self { 1 } else { 0 };
        <i32 as ToSql<::types::Integer, Mysql>>::to_sql(&int_value, out)
    }
}

impl FromSql<::types::Bool, Mysql> for bool {
    fn from_sql(bytes: Option<&[u8]>) -> Result<Self, Box<StdError + Send + Sync>> {
        Ok(not_none!(bytes).iter().any(|x| *x != 0))
    }
}

impl HasSqlType<::types::Date> for Mysql {
    fn metadata(_: &()) -> MysqlType {
        MysqlType::Date
    }
}

impl HasSqlType<::types::Time> for Mysql {
    fn metadata(_: &()) -> MysqlType {
        MysqlType::Time
    }
}

impl HasSqlType<::types::Timestamp> for Mysql {
    fn metadata(_: &()) -> MysqlType {
        MysqlType::Timestamp
    }
}

impl HasSqlType<Datetime> for Mysql {
    fn metadata(_: &()) -> MysqlType {
        MysqlType::DateTime
    }
}

impl HasSqlType<::types::Numeric> for Mysql {
    fn metadata(_: &()) -> MysqlType {
        MysqlType::String
    }
}

/// Represents the MySQL datetime type.
///
/// ### [`ToSql`] impls
///
/// - [`chrono::NaiveDateTime`] with `feature = "chrono"`
///
/// ### [`FromSql`] impls
///
/// - [`chrono::NaiveDateTime`] with `feature = "chrono"`
///
/// [`ToSql`]: ../../types/trait.ToSql.html
/// [`FromSql`]: ../../types/trait.FromSql.html
/// [`chrono::NaiveDateTime`]: ../../../chrono/naive/struct.NaiveDateTime.html
#[derive(Debug, Clone, Copy, Default, QueryId)]
pub struct Datetime;

primitive_impls!(Datetime);
<commit_msg>Fix failing build<commit_after>//! MySQL specific types

#[cfg(feature = "chrono")]
mod date_and_time;
mod numeric;

use byteorder::WriteBytesExt;
use mysql::{Mysql, MysqlType};
use std::error::Error as StdError;
use std::io::Write;
use types::{FromSql, HasSqlType, IsNull, Tinyint, ToSql, ToSqlOutput};

primitive_impls!(Tinyint -> (i8, mysql: (Tiny)));

impl ToSql<::types::Tinyint, Mysql> for i8 {
    fn to_sql<W: Write>(
        &self,
        out: &mut ToSqlOutput<W, Mysql>,
    ) -> Result<IsNull, Box<StdError + Send + Sync>> {
        out.write_i8(*self)
            .map(|_| IsNull::No)
            .map_err(|e| Box::new(e) as Box<StdError + Send + Sync>)
    }
}

impl FromSql<::types::Tinyint, Mysql> for i8 {
    fn from_sql(bytes: Option<&[u8]>) -> Result<Self, Box<StdError + Send + Sync>> {
        let bytes = not_none!(bytes);
        Ok(bytes[0] as i8)
    }
}

impl ToSql<::types::Bool, Mysql> for bool {
    fn to_sql<W: Write>(
        &self,
        out: &mut ToSqlOutput<W, Mysql>,
    ) -> Result<IsNull, Box<StdError + Send + Sync>> {
        let int_value = if *self { 1 } else { 0 };
        <i32 as ToSql<::types::Integer, Mysql>>::to_sql(&int_value, out)
    }
}

impl FromSql<::types::Bool, Mysql> for bool {
    fn from_sql(bytes: Option<&[u8]>) -> Result<Self, Box<StdError + Send + Sync>> {
        Ok(not_none!(bytes).iter().any(|x| *x != 0))
    }
}

impl HasSqlType<::types::Date> for Mysql {
    fn metadata(_: &()) -> MysqlType {
        MysqlType::Date
    }
}

impl HasSqlType<::types::Time> for Mysql {
    fn metadata(_: &()) -> MysqlType {
        MysqlType::Time
    }
}

impl HasSqlType<::types::Timestamp> for Mysql {
    fn metadata(_: &()) -> MysqlType {
        MysqlType::Timestamp
    }
}

impl HasSqlType<Datetime> for Mysql {
    fn metadata(_: &()) -> MysqlType {
        MysqlType::DateTime
    }
}

impl HasSqlType<::types::Numeric> for Mysql {
    fn metadata(_: &()) -> MysqlType {
        MysqlType::String
    }
}

/// Represents the MySQL datetime type.
///
/// ### [`ToSql`] impls
///
/// - [`chrono::NaiveDateTime`] with `feature = "chrono"`
///
/// ### [`FromSql`] impls
///
/// - [`chrono::NaiveDateTime`] with `feature = "chrono"`
///
/// [`ToSql`]: ../../types/trait.ToSql.html
/// [`FromSql`]: ../../types/trait.FromSql.html
/// [`chrono::NaiveDateTime`]: ../../../chrono/naive/struct.NaiveDateTime.html
#[derive(Debug, Clone, Copy, Default, QueryId)]
pub struct Datetime;

primitive_impls!(Datetime);
<|endoftext|>


<commit_before>use na::{DVector, Real, Point2};

use crate::bounding_volume::AABB;
use crate::query::{ContactPreprocessor, Contact, ContactKinematic};
use crate::shape::Segment;
use crate::math::Vector;

#[derive(Clone, Debug)]
pub struct HeightField<N: Real> {
    heights: DVector<N>,
    scale: Vector<N>,
    aabb: AABB<N>,
    num_segments: usize
}

impl<N: Real> HeightField<N> {
    pub fn new(heights: DVector<N>, scale: Vector<N>) -> Self {
        assert!(heights.len() > 1, "A heightfield heights must have at least 2 elements.");

        let max = heights.max();
        let min = heights.min();
        let hscale = scale * na::convert::<_, N>(0.5);
        let aabb = AABB::new(
            Point2::new(-hscale.x, min * scale.y),
            Point2::new(hscale.x, max * scale.y)
        );
        let num_segments = heights.len() - 1;

        HeightField {
            heights, scale, aabb, num_segments
        }
    }

    pub fn heights(&self) -> &DVector<N> {
        &self.heights
    }

    pub fn scale(&self) -> &Vector<N> {
        &self.scale
    }

    pub fn aabb(&self) -> &AABB<N> {
        &self.aabb
    }

    pub fn map_elements_in_local_aabb(&self, aabb: &AABB<N>, f: &mut impl FnMut(usize, &Segment<N>, &ContactPreprocessor<N>)) {
        let _0_5: N = na::convert(0.5);
        let ref_mins = aabb.mins().coords.component_div(&self.scale);
        let ref_maxs = aabb.maxs().coords.component_div(&self.scale);
        let seg_length  = N::one() / na::convert(self.heights.len() as f64 - 1.0);

        if ref_maxs.x <= -_0_5 || ref_mins.x >= _0_5 {
            // Outside of the heightfield bounds.
            return;
        }

        let min_x = unsafe { na::convert_unchecked::<N, f64>((na::clamp(ref_mins.x + _0_5, N::zero(), N::one()) / seg_length).floor()) } as usize;
        let max_x = unsafe { na::convert_unchecked::<N, f64>((na::clamp(ref_maxs.x + _0_5, N::zero(), N::one()) / seg_length).ceil()) } as usize;

        // FIXME: find a way to avoid recomputing the same vertices
        // multiple times.
        for i in min_x..max_x {
            let x0 = -_0_5 +  seg_length * na::convert(i as f64);
            let x1 = x0 + seg_length;

            let y0 = self.heights[i + 0];
            let y1 = self.heights[i + 1];

            if (y0 > ref_maxs.y && y1 > ref_maxs.y) || (y0 < ref_mins.y && y1 < ref_mins.y) {
                continue;
            }

            let mut p0 = Point2::new(x0, y0);
            let mut p1 = Point2::new(x1, y1);

            // Apply scales:
            p0.coords.component_mul_mut(&self.scale);
            p1.coords.component_mul_mut(&self.scale);

            // Build the two triangles.
            let seg = Segment::new(p0, p1);

            // Build the contact preprocessors.
            let seg_id = i;
            let proc = HeightFieldTriangleContactPreprocessor::new(self, seg_id);

            // Call the callback.
            f(seg_id, &seg, &proc);
        }
    }
}

pub struct HeightFieldTriangleContactPreprocessor<'a, N: Real> {
    heightfield: &'a HeightField<N>,
    triangle: usize
}

impl<'a, N: Real> HeightFieldTriangleContactPreprocessor<'a, N> {
    pub fn new(heightfield: &'a HeightField<N>, triangle: usize) -> Self {
        HeightFieldTriangleContactPreprocessor {
            heightfield,
            triangle
        }
    }
}

impl<'a, N: Real> ContactPreprocessor<N> for HeightFieldTriangleContactPreprocessor<'a, N> {
    fn process_contact(
        &self,
        c: &mut Contact<N>,
        kinematic: &mut ContactKinematic<N>,
        is_first: bool)
        -> bool {
        /*
        // Fix the feature ID.
        let feature = if is_first {
            kinematic.feature1()
        } else {
            kinematic.feature2()
        };

        let face = &self.mesh.faces()[self.face_id];
        let actual_feature = match feature {
            FeatureId::Vertex(i) => FeatureId::Vertex(face.indices[i]),
            FeatureId::Edge(i) => FeatureId::Edge(face.edges[i]),
            FeatureId::Face(i) => {
                if i == 0 {
                    FeatureId::Face(self.face_id)
                } else {
                    FeatureId::Face(self.face_id + self.mesh.faces().len())
                }
            }
            FeatureId::Unknown => FeatureId::Unknown,
        };

        if is_first {
            kinematic.set_feature1(actual_feature);
        } else {
            kinematic.set_feature2(actual_feature);
        }

        // Test the validity of the LMD.
        if c.depth > N::zero() {
            true
        } else {
            // FIXME
        }
        */

        true
    }
}<commit_msg>Add the ability to remove some segments from a 2D heightfield.<commit_after>use std::iter;
use na::{DVector, Real, Point2};

use crate::bounding_volume::AABB;
use crate::query::{ContactPreprocessor, Contact, ContactKinematic};
use crate::shape::Segment;
use crate::math::Vector;

#[derive(Clone, Debug)]
pub struct HeightField<N: Real> {
    heights: DVector<N>,
    scale: Vector<N>,
    removed: Vec<bool>,
    aabb: AABB<N>,
    num_segments: usize
}

impl<N: Real> HeightField<N> {
    pub fn new(heights: DVector<N>, scale: Vector<N>) -> Self {
        assert!(heights.len() > 1, "A heightfield heights must have at least 2 elements.");

        let max = heights.max();
        let min = heights.min();
        let hscale = scale * na::convert::<_, N>(0.5);
        let aabb = AABB::new(
            Point2::new(-hscale.x, min * scale.y),
            Point2::new(hscale.x, max * scale.y)
        );
        let num_segments = heights.len() - 1;

        HeightField {
            heights, scale, aabb, num_segments, removed: Vec::new()
        }
    }

    pub fn num_segments(&self) -> usize {
        self.num_segments
    }

    pub fn heights(&self) -> &DVector<N> {
        &self.heights
    }

    pub fn scale(&self) -> &Vector<N> {
        &self.scale
    }

    pub fn aabb(&self) -> &AABB<N> {
        &self.aabb
    }

    pub fn segment_at(&self, i: usize) -> Option<Segment<N>> {
        if self.is_segment_removed(i) {
            return None;
        }

        let _0_5: N = na::convert(0.5);
        let seg_length  = N::one() / na::convert(self.heights.len() as f64 - 1.0);

        let x0 = -_0_5 +  seg_length * na::convert(i as f64);
        let x1 = x0 + seg_length;

        let y0 = self.heights[i + 0];
        let y1 = self.heights[i + 1];

        let mut p0 = Point2::new(x0, y0);
        let mut p1 = Point2::new(x1, y1);

        // Apply scales:
        p0.coords.component_mul_mut(&self.scale);
        p1.coords.component_mul_mut(&self.scale);

        Some(Segment::new(p0, p1))
    }

    pub fn set_segment_removed(&mut self, i: usize, removed: bool) {
        if self.removed.len() == 0 {
            self.removed = iter::repeat(false).take(self.num_segments).collect()
        }

        self.removed[i] = removed
    }

    pub fn is_segment_removed(&self, i: usize) -> bool {
        self.removed.len() != 0 && self.removed[i]
    }

    pub fn map_elements_in_local_aabb(&self, aabb: &AABB<N>, f: &mut impl FnMut(usize, &Segment<N>, &ContactPreprocessor<N>)) {
        let _0_5: N = na::convert(0.5);
        let ref_mins = aabb.mins().coords.component_div(&self.scale);
        let ref_maxs = aabb.maxs().coords.component_div(&self.scale);
        let seg_length  = N::one() / na::convert(self.heights.len() as f64 - 1.0);

        if ref_maxs.x <= -_0_5 || ref_mins.x >= _0_5 {
            // Outside of the heightfield bounds.
            return;
        }

        let min_x = unsafe { na::convert_unchecked::<N, f64>((na::clamp(ref_mins.x + _0_5, N::zero(), N::one()) / seg_length).floor()) } as usize;
        let max_x = unsafe { na::convert_unchecked::<N, f64>((na::clamp(ref_maxs.x + _0_5, N::zero(), N::one()) / seg_length).ceil()) } as usize;

        // FIXME: find a way to avoid recomputing the same vertices
        // multiple times.
        for i in min_x..max_x {
            if self.is_segment_removed(i) {
                continue;
            }

            let x0 = -_0_5 +  seg_length * na::convert(i as f64);
            let x1 = x0 + seg_length;

            let y0 = self.heights[i + 0];
            let y1 = self.heights[i + 1];

            if (y0 > ref_maxs.y && y1 > ref_maxs.y) || (y0 < ref_mins.y && y1 < ref_mins.y) {
                continue;
            }

            let mut p0 = Point2::new(x0, y0);
            let mut p1 = Point2::new(x1, y1);

            // Apply scales:
            p0.coords.component_mul_mut(&self.scale);
            p1.coords.component_mul_mut(&self.scale);

            // Build the segment.
            let seg = Segment::new(p0, p1);

            // Build the contact preprocessor.
            let seg_id = i;
            let proc = HeightFieldTriangleContactPreprocessor::new(self, seg_id);

            // Call the callback.
            f(seg_id, &seg, &proc);
        }
    }
}

pub struct HeightFieldTriangleContactPreprocessor<'a, N: Real> {
    heightfield: &'a HeightField<N>,
    triangle: usize
}

impl<'a, N: Real> HeightFieldTriangleContactPreprocessor<'a, N> {
    pub fn new(heightfield: &'a HeightField<N>, triangle: usize) -> Self {
        HeightFieldTriangleContactPreprocessor {
            heightfield,
            triangle
        }
    }
}

impl<'a, N: Real> ContactPreprocessor<N> for HeightFieldTriangleContactPreprocessor<'a, N> {
    fn process_contact(
        &self,
        c: &mut Contact<N>,
        kinematic: &mut ContactKinematic<N>,
        is_first: bool)
        -> bool {
        /*
        // Fix the feature ID.
        let feature = if is_first {
            kinematic.feature1()
        } else {
            kinematic.feature2()
        };

        let face = &self.mesh.faces()[self.face_id];
        let actual_feature = match feature {
            FeatureId::Vertex(i) => FeatureId::Vertex(face.indices[i]),
            FeatureId::Edge(i) => FeatureId::Edge(face.edges[i]),
            FeatureId::Face(i) => {
                if i == 0 {
                    FeatureId::Face(self.face_id)
                } else {
                    FeatureId::Face(self.face_id + self.mesh.faces().len())
                }
            }
            FeatureId::Unknown => FeatureId::Unknown,
        };

        if is_first {
            kinematic.set_feature1(actual_feature);
        } else {
            kinematic.set_feature2(actual_feature);
        }

        // Test the validity of the LMD.
        if c.depth > N::zero() {
            true
        } else {
            // FIXME
        }
        */

        true
    }
}<|endoftext|>


<commit_before>use std::rc::Rc;
use std::cell::RefCell;
use std::net::SocketAddr;
use std::collections::HashMap;
use rand::random;
use mio::net::TcpStream;

use sozu_command::messages;

use network::{AppId,Backend,ConnectionError};

#[derive(Debug)]
pub struct BackendMap {
  pub backends:     HashMap<AppId, BackendList>,
  pub max_failures: usize,
}

impl BackendMap {
  pub fn new() -> BackendMap {
    BackendMap {
      backends:     HashMap::new(),
      max_failures: 3,
    }
  }

  pub fn import_configuration_state(&mut self, backends: &HashMap<AppId, Vec<messages::Backend>>) {
    self.backends.extend(backends.iter().map(|(ref app_id, ref backend_vec)| {
      (app_id.to_string(), BackendList::import_configuration_state(backend_vec))
    }));
  }

  pub fn add_backend(&mut self, app_id: &str, backend_id: &str, backend_address: &SocketAddr) {
    self.backends.entry(app_id.to_string()).or_insert(BackendList::new()).add_backend(backend_id, backend_address);
  }

  pub fn remove_backend(&mut self, app_id: &str, backend_address: &SocketAddr) {
    if let Some(backends) = self.backends.get_mut(app_id) {
      backends.remove_backend(backend_address);
    } else {
      error!("Backend was already removed: app id {}, address {:?}", app_id, backend_address);
    }
  }

  pub fn close_backend_connection(&mut self, app_id: &str, addr: &SocketAddr) {
    if let Some(app_backends) = self.backends.get_mut(app_id) {
      if let Some(ref mut backend) = app_backends.find_backend(addr) {
        (*backend.borrow_mut()).dec_connections();
      }
    }
  }

  pub fn has_backend(&self, app_id: &str, backend: &Backend) -> bool {
    self.backends.get(app_id).map(|backends| {
      backends.has_backend(&backend.address)
    }).unwrap_or(false)
  }

  pub fn backend_from_app_id(&mut self, app_id: &str) -> Result<(Rc<RefCell<Backend>>,TcpStream),ConnectionError> {
    if let Some(ref mut app_backends) = self.backends.get_mut(app_id) {
      if app_backends.backends.len() == 0 {
        return Err(ConnectionError::NoBackendAvailable);
      }

      for _ in 0..self.max_failures {
        if let Some(ref mut b) = app_backends.next_available_backend() {
          let ref mut backend = *b.borrow_mut();

          debug!("Connecting {} -> {:?}", app_id, (backend.address, backend.active_connections, backend.failures));
          let conn = backend.try_connect();
          if backend.failures >= MAX_FAILURES_PER_BACKEND {
            error!("backend {:?} connections failed {} times, disabling it", (backend.address, backend.active_connections), backend.failures);
          }

          return conn.map(|c| (b.clone(), c)).map_err(|e| {
            error!("could not connect {} to {:?} ({} failures)", app_id, backend.address, backend.failures);
            e
          });
        } else {
          error!("no more available backends for app {}", app_id);
          return Err(ConnectionError::NoBackendAvailable);
        }
      }
      Err(ConnectionError::NoBackendAvailable)
    } else {
      Err(ConnectionError::NoBackendAvailable)
    }
  }

  pub fn backend_from_sticky_session(&mut self, app_id: &str, sticky_session: u32) -> Result<(Rc<RefCell<Backend>>,TcpStream),ConnectionError> {
    let sticky_conn: Option<Result<(Rc<RefCell<Backend>>,TcpStream),ConnectionError>> = self.backends
      .get_mut(app_id)
      .and_then(|app_backends| app_backends.find_sticky(sticky_session))
      .map(|b| {
        let ref mut backend = *b.borrow_mut();
        let conn = backend.try_connect();
        if backend.failures >= MAX_FAILURES_PER_BACKEND {
          error!("backend {:?} connections failed {} times, disabling it", (backend.address, backend.active_connections), backend.failures);
        }

        conn.map(|c| (b.clone(), c)).map_err(|e| {
          error!("could not connect {} to {:?} using session {} ({} failures)",
            app_id, backend.address, sticky_session, backend.failures);
          e
        })
      });

    if let Some(res) = sticky_conn {
      return res;
    } else {
      debug!("Couldn't find a backend corresponding to sticky_session {} for app {}", sticky_session, app_id);
      return self.backend_from_app_id(app_id);
    }
  }
}

const MAX_FAILURES_PER_BACKEND: usize = 10;

#[derive(Debug)]
pub struct BackendList {
  pub backends:  Vec<Rc<RefCell<Backend>>>,
  pub next_id:   u32,
}

impl BackendList {
  pub fn new() -> BackendList {
    BackendList {
      backends:  Vec::new(),
      next_id:   0,
    }
  }

  pub fn import_configuration_state(backend_vec: &Vec<messages::Backend>) -> BackendList {
    let mut list = BackendList::new();
    for ref backend in backend_vec {
      let addr_string = backend.ip_address.to_string() + ":" + &backend.port.to_string();
      let parsed:Option<SocketAddr> = addr_string.parse().ok();
      if let Some(addr) = parsed {
        list.add_backend(&backend.backend_id, &addr);
      }
    }

    list
  }

  pub fn add_backend(&mut self, backend_id: &str, backend_address: &SocketAddr) {
    if self.backends.iter().find(|b| &(*b.borrow()).address == backend_address).is_none() {
      let backend = Rc::new(RefCell::new(Backend::new(backend_id, *backend_address, self.next_id)));
      self.backends.push(backend);
      self.next_id += 1;
    }
  }

  pub fn remove_backend(&mut self, backend_address: &SocketAddr) {
    self.backends.retain(|backend| &(*backend.borrow()).address != backend_address);
  }

  pub fn has_backend(&self, backend_address: &SocketAddr) -> bool {
    self.backends.iter().any(|backend| &(*backend.borrow()).address == backend_address)
  }

  pub fn find_backend(&mut self, backend_address: &SocketAddr) -> Option<&mut Rc<RefCell<Backend>>> {
    self.backends.iter_mut().find(|backend| &(*backend.borrow()).address == backend_address)
  }

  pub fn find_sticky(&mut self, sticky_session: u32) -> Option<&mut Rc<RefCell<Backend>>> {
    self.backends.iter_mut()
      .find(|b| b.borrow().id == sticky_session )
      .and_then(|b| {
        if b.borrow().can_open() {
          Some(b)
        } else {
          None
        }
      })
  }

  pub fn available_backends(&mut self) -> Vec<&mut Rc<RefCell<Backend>>> {
    self.backends.iter_mut()
      .filter(|backend| (*backend.borrow()).can_open())
      .collect()
  }

  pub fn next_available_backend(&mut self) -> Option<&mut Rc<RefCell<Backend>>> {
    let mut backends:Vec<&mut Rc<RefCell<Backend>>> = self.available_backends();
    if backends.is_empty() {
      return None;
    }

    let rnd = random::<usize>();
    let idx = rnd % backends.len();

    Some(backends.remove(idx))
  }
}
<commit_msg>show unavailable backends error log only once<commit_after>use std::rc::Rc;
use std::cell::RefCell;
use std::net::SocketAddr;
use std::collections::HashMap;
use rand::random;
use mio::net::TcpStream;

use sozu_command::messages;

use network::{AppId,Backend,ConnectionError};

#[derive(Debug)]
pub struct BackendMap {
  pub backends:     HashMap<AppId, BackendList>,
  pub max_failures: usize,
  pub available:    bool,
}

impl BackendMap {
  pub fn new() -> BackendMap {
    BackendMap {
      backends:     HashMap::new(),
      max_failures: 3,
      available:    true,
    }
  }

  pub fn import_configuration_state(&mut self, backends: &HashMap<AppId, Vec<messages::Backend>>) {
    self.backends.extend(backends.iter().map(|(ref app_id, ref backend_vec)| {
      (app_id.to_string(), BackendList::import_configuration_state(backend_vec))
    }));
  }

  pub fn add_backend(&mut self, app_id: &str, backend_id: &str, backend_address: &SocketAddr) {
    self.backends.entry(app_id.to_string()).or_insert(BackendList::new()).add_backend(backend_id, backend_address);
  }

  pub fn remove_backend(&mut self, app_id: &str, backend_address: &SocketAddr) {
    if let Some(backends) = self.backends.get_mut(app_id) {
      backends.remove_backend(backend_address);
    } else {
      error!("Backend was already removed: app id {}, address {:?}", app_id, backend_address);
    }
  }

  pub fn close_backend_connection(&mut self, app_id: &str, addr: &SocketAddr) {
    if let Some(app_backends) = self.backends.get_mut(app_id) {
      if let Some(ref mut backend) = app_backends.find_backend(addr) {
        (*backend.borrow_mut()).dec_connections();
      }
    }
  }

  pub fn has_backend(&self, app_id: &str, backend: &Backend) -> bool {
    self.backends.get(app_id).map(|backends| {
      backends.has_backend(&backend.address)
    }).unwrap_or(false)
  }

  pub fn backend_from_app_id(&mut self, app_id: &str) -> Result<(Rc<RefCell<Backend>>,TcpStream),ConnectionError> {
    if let Some(ref mut app_backends) = self.backends.get_mut(app_id) {
      if app_backends.backends.len() == 0 {
        self.available = false;
        return Err(ConnectionError::NoBackendAvailable);
      }

      for _ in 0..self.max_failures {
        if let Some(ref mut b) = app_backends.next_available_backend() {
          let ref mut backend = *b.borrow_mut();

          debug!("Connecting {} -> {:?}", app_id, (backend.address, backend.active_connections, backend.failures));
          let conn = backend.try_connect();
          if backend.failures >= MAX_FAILURES_PER_BACKEND {
            error!("backend {:?} connections failed {} times, disabling it", (backend.address, backend.active_connections), backend.failures);
          }

          let res = conn.map(|c| {
            (b.clone(), c)
          }).map_err(|e| {
            error!("could not connect {} to {:?} ({} failures)", app_id, backend.address, backend.failures);
            e
          });

          if res.is_ok() {
            self.available = true;
          }

          return res;
        } else {
          if self.available {
            error!("no more available backends for app {}", app_id);
            self.available = false;
          }
          return Err(ConnectionError::NoBackendAvailable);
        }
      }
      Err(ConnectionError::NoBackendAvailable)
    } else {
      Err(ConnectionError::NoBackendAvailable)
    }
  }

  pub fn backend_from_sticky_session(&mut self, app_id: &str, sticky_session: u32) -> Result<(Rc<RefCell<Backend>>,TcpStream),ConnectionError> {
    let sticky_conn: Option<Result<(Rc<RefCell<Backend>>,TcpStream),ConnectionError>> = self.backends
      .get_mut(app_id)
      .and_then(|app_backends| app_backends.find_sticky(sticky_session))
      .map(|b| {
        let ref mut backend = *b.borrow_mut();
        let conn = backend.try_connect();
        if backend.failures >= MAX_FAILURES_PER_BACKEND {
          error!("backend {:?} connections failed {} times, disabling it", (backend.address, backend.active_connections), backend.failures);
        }

        conn.map(|c| (b.clone(), c)).map_err(|e| {
          error!("could not connect {} to {:?} using session {} ({} failures)",
            app_id, backend.address, sticky_session, backend.failures);
          e
        })
      });

    if let Some(res) = sticky_conn {
      return res;
    } else {
      debug!("Couldn't find a backend corresponding to sticky_session {} for app {}", sticky_session, app_id);
      return self.backend_from_app_id(app_id);
    }
  }
}

const MAX_FAILURES_PER_BACKEND: usize = 10;

#[derive(Debug)]
pub struct BackendList {
  pub backends:  Vec<Rc<RefCell<Backend>>>,
  pub next_id:   u32,
}

impl BackendList {
  pub fn new() -> BackendList {
    BackendList {
      backends:  Vec::new(),
      next_id:   0,
    }
  }

  pub fn import_configuration_state(backend_vec: &Vec<messages::Backend>) -> BackendList {
    let mut list = BackendList::new();
    for ref backend in backend_vec {
      let addr_string = backend.ip_address.to_string() + ":" + &backend.port.to_string();
      let parsed:Option<SocketAddr> = addr_string.parse().ok();
      if let Some(addr) = parsed {
        list.add_backend(&backend.backend_id, &addr);
      }
    }

    list
  }

  pub fn add_backend(&mut self, backend_id: &str, backend_address: &SocketAddr) {
    if self.backends.iter().find(|b| &(*b.borrow()).address == backend_address).is_none() {
      let backend = Rc::new(RefCell::new(Backend::new(backend_id, *backend_address, self.next_id)));
      self.backends.push(backend);
      self.next_id += 1;
    }
  }

  pub fn remove_backend(&mut self, backend_address: &SocketAddr) {
    self.backends.retain(|backend| &(*backend.borrow()).address != backend_address);
  }

  pub fn has_backend(&self, backend_address: &SocketAddr) -> bool {
    self.backends.iter().any(|backend| &(*backend.borrow()).address == backend_address)
  }

  pub fn find_backend(&mut self, backend_address: &SocketAddr) -> Option<&mut Rc<RefCell<Backend>>> {
    self.backends.iter_mut().find(|backend| &(*backend.borrow()).address == backend_address)
  }

  pub fn find_sticky(&mut self, sticky_session: u32) -> Option<&mut Rc<RefCell<Backend>>> {
    self.backends.iter_mut()
      .find(|b| b.borrow().id == sticky_session )
      .and_then(|b| {
        if b.borrow().can_open() {
          Some(b)
        } else {
          None
        }
      })
  }

  pub fn available_backends(&mut self) -> Vec<&mut Rc<RefCell<Backend>>> {
    self.backends.iter_mut()
      .filter(|backend| (*backend.borrow()).can_open())
      .collect()
  }

  pub fn next_available_backend(&mut self) -> Option<&mut Rc<RefCell<Backend>>> {
    let mut backends:Vec<&mut Rc<RefCell<Backend>>> = self.available_backends();
    if backends.is_empty() {
      return None;
    }

    let rnd = random::<usize>();
    let idx = rnd % backends.len();

    Some(backends.remove(idx))
  }
}
<|endoftext|>