<commit_before>use std::{mem, net};
use std::time::Duration;
use std::sync::{Arc, atomic::{AtomicUsize, Ordering}};

use futures::{Future, Stream, Sink};
use futures::sync::{mpsc, mpsc::unbounded};

use actix::{fut, signal, Actor, ActorFuture, Addr, Arbiter, AsyncContext,
            Context, Handler, Response, System, StreamHandler, WrapFuture};

use super::accept::{AcceptLoop, AcceptNotify, Command};
use super::worker::{StopWorker, Worker, WorkerClient, Conn};
use super::{PauseServer, ResumeServer, StopServer, Token};

pub trait Service: Send + 'static {
    /// Clone service
    fn clone(&self) -> Box<Service>;

    /// Create service handler for this service
    fn create(&self, conn: Connections) -> Box<ServiceHandler>;
}

impl Service for Box<Service> {
    fn clone(&self) -> Box<Service> {
        self.as_ref().clone()
    }

    fn create(&self, conn: Connections) -> Box<ServiceHandler> {
        self.as_ref().create(conn)
    }
}

pub trait ServiceHandler {
    /// Handle incoming stream
    fn handle(&mut self, token: Token, io: net::TcpStream, peer: Option<net::SocketAddr>);

    /// Shutdown open handlers
    fn shutdown(&self, _: bool) {}
}

pub(crate) enum ServerCommand {
    WorkerDied(usize),
}

pub struct Server {
    threads: usize,
    workers: Vec<(usize, Addr<Worker>)>,
    services: Vec<Box<Service>>,
    sockets: Vec<Vec<(Token, net::TcpListener)>>,
    accept: AcceptLoop,
    exit: bool,
    shutdown_timeout: u16,
    signals: Option<Addr<signal::ProcessSignals>>,
    no_signals: bool,
    maxconn: usize,
    maxconnrate: usize,
}

impl Default for Server {
    fn default() -> Self {
        Self::new()
    }
}

impl Server {
    /// Create new Server instance
    pub fn new() -> Server {
        Server {
            threads: num_cpus::get(),
            workers: Vec::new(),
            services: Vec::new(),
            sockets: Vec::new(),
            accept: AcceptLoop::new(),
            exit: false,
            shutdown_timeout: 30,
            signals: None,
            no_signals: false,
            maxconn: 102_400,
            maxconnrate: 256,
        }
    }

    /// Set number of workers to start.
    ///
    /// By default http server uses number of available logical cpu as threads
    /// count.
    pub fn workers(mut self, num: usize) -> Self {
        self.threads = num;
        self
    }

    /// Sets the maximum per-worker number of concurrent connections.
    ///
    /// All socket listeners will stop accepting connections when this limit is reached
    /// for each worker.
    ///
    /// By default max connections is set to a 100k.
    pub fn maxconn(mut self, num: usize) -> Self {
        self.maxconn = num;
        self
    }

    /// Sets the maximum per-worker concurrent connection establish process.
    ///
    /// All listeners will stop accepting connections when this limit is reached. It
    /// can be used to limit the global SSL CPU usage.
    ///
    /// By default max connections is set to a 256.
    pub fn maxconnrate(mut self, num: usize) -> Self {
        self.maxconnrate= num;
        self
    }

    /// Stop actix system.
    ///
    /// `SystemExit` message stops currently running system.
    pub fn system_exit(mut self) -> Self {
        self.exit = true;
        self
    }

    #[doc(hidden)]
    /// Set alternative address for `ProcessSignals` actor.
    pub fn signals(mut self, addr: Addr<signal::ProcessSignals>) -> Self {
        self.signals = Some(addr);
        self
    }

    /// Disable signal handling
    pub fn disable_signals(mut self) -> Self {
        self.no_signals = true;
        self
    }

    /// Timeout for graceful workers shutdown.
    ///
    /// After receiving a stop signal, workers have this much time to finish
    /// serving requests. Workers still alive after the timeout are force
    /// dropped.
    ///
    /// By default shutdown timeout sets to 30 seconds.
    pub fn shutdown_timeout(mut self, sec: u16) -> Self {
        self.shutdown_timeout = sec;
        self
    }

    /// Add new service to server
    pub fn service<T>(mut self, srv: T) -> Self
    where
        T: Into<(Box<Service>, Vec<(Token, net::TcpListener)>)>
    {
        let (srv, sockets) = srv.into();
        self.services.push(srv);
        self.sockets.push(sockets);
        self
    }

    /// Spawn new thread and start listening for incoming connections.
    ///
    /// This method spawns new thread and starts new actix system. Other than
    /// that it is similar to `start()` method. This method blocks.
    ///
    /// This methods panics if no socket addresses get bound.
    ///
    /// ```rust,ignore
    /// # extern crate futures;
    /// # extern crate actix_web;
    /// # use futures::Future;
    /// use actix_web::*;
    ///
    /// fn main() {
    ///     Server::new().
    ///         .service(
    ///            HttpServer::new(|| App::new().resource("/", |r| r.h(|_| HttpResponse::Ok())))
    ///                .bind("127.0.0.1:0")
    ///                .expect("Can not bind to 127.0.0.1:0"))
    ///         .run();
    /// }
    /// ```
    pub fn run(self) {
        let sys = System::new("http-server");
        self.start();
        sys.run();
    }

    /// Start
    pub fn start(mut self) -> Addr<Server> {
        if self.sockets.is_empty() {
            panic!("Service should have at least one bound socket");
        } else {
            info!("Starting {} http workers", self.threads);

            // start workers
            let mut workers = Vec::new();
            for idx in 0..self.threads {
                let (addr, worker) = self.start_worker(idx, self.accept.get_notify());
                workers.push(worker);
                self.workers.push((idx, addr));
            }

            // start accept thread
            for sock in &self.sockets {
                for s in sock.iter() {
                    info!("Starting server on http://{:?}", s.1.local_addr().ok());
                }
            }
            let rx = self.accept.start(
                mem::replace(&mut self.sockets, Vec::new()), workers);

            // start http server actor
            let signals = self.subscribe_to_signals();
            let addr = Actor::create(move |ctx| {
                ctx.add_stream(rx);
                self
            });
            if let Some(signals) = signals {
                signals.do_send(signal::Subscribe(addr.clone().recipient()))
            }
            addr
        }
    }

    // subscribe to os signals
    fn subscribe_to_signals(&self) -> Option<Addr<signal::ProcessSignals>> {
        if !self.no_signals {
            if let Some(ref signals) = self.signals {
                Some(signals.clone())
            } else {
                Some(System::current().registry().get::<signal::ProcessSignals>())
            }
        } else {
            None
        }
    }

    fn start_worker(&self, idx: usize, notify: AcceptNotify) -> (Addr<Worker>, WorkerClient) {
        let (tx, rx) = unbounded::<Conn<net::TcpStream>>();
        let conns = Connections::new(notify, self.maxconn, self.maxconnrate);
        let worker = WorkerClient::new(idx, tx, conns.clone());
        let services: Vec<_> = self.services.iter().map(|v| v.clone()).collect();

        let addr = Arbiter::start(move |ctx: &mut Context<_>| {
            ctx.add_message_stream(rx);
            let handlers: Vec<_> = services.into_iter().map(|s| s.create(conns.clone())).collect();
            Worker::new(conns, handlers)
        });

        (addr, worker)
    }
}

impl Actor for Server
{
    type Context = Context<Self>;
}

/// Signals support
/// Handle `SIGINT`, `SIGTERM`, `SIGQUIT` signals and stop actix system
/// message to `System` actor.
impl Handler<signal::Signal> for Server {
    type Result = ();

    fn handle(&mut self, msg: signal::Signal, ctx: &mut Context<Self>) {
        match msg.0 {
            signal::SignalType::Int => {
                info!("SIGINT received, exiting");
                self.exit = true;
                Handler::<StopServer>::handle(self, StopServer { graceful: false }, ctx);
            }
            signal::SignalType::Term => {
                info!("SIGTERM received, stopping");
                self.exit = true;
                Handler::<StopServer>::handle(self, StopServer { graceful: true }, ctx);
            }
            signal::SignalType::Quit => {
                info!("SIGQUIT received, exiting");
                self.exit = true;
                Handler::<StopServer>::handle(self, StopServer { graceful: false }, ctx);
            }
            _ => (),
        }
    }
}

impl Handler<PauseServer> for Server {
    type Result = ();

    fn handle(&mut self, _: PauseServer, _: &mut Context<Self>) {
        self.accept.send(Command::Pause);
    }
}

impl Handler<ResumeServer> for Server {
    type Result = ();

    fn handle(&mut self, _: ResumeServer, _: &mut Context<Self>) {
        self.accept.send(Command::Resume);
    }
}

impl Handler<StopServer> for Server {
    type Result = Response<(), ()>;

    fn handle(&mut self, msg: StopServer, ctx: &mut Context<Self>) -> Self::Result {
        // stop accept thread
        self.accept.send(Command::Stop);

        // stop workers
        let (tx, rx) = mpsc::channel(1);

        let dur = if msg.graceful {
            Some(Duration::new(u64::from(self.shutdown_timeout), 0))
        } else {
            None
        };
        for worker in &self.workers {
            let tx2 = tx.clone();
            ctx.spawn(
                worker
                    .1
                    .send(StopWorker { graceful: dur })
                    .into_actor(self)
                    .then(move |_, slf, ctx| {
                        slf.workers.pop();
                        if slf.workers.is_empty() {
                            let _ = tx2.send(());

                            // we need to stop system if server was spawned
                            if slf.exit {
                                ctx.run_later(Duration::from_millis(300), |_, _| {
                                    System::current().stop();
                                });
                            }
                        }

                        fut::ok(())
                    }),
            );
        }

        if !self.workers.is_empty() {
            Response::async(rx.into_future().map(|_| ()).map_err(|_| ()))
        } else {
            // we need to stop system if server was spawned
            if self.exit {
                ctx.run_later(Duration::from_millis(300), |_, _| {
                    System::current().stop();
                });
            }
            Response::reply(Ok(()))
        }
    }
}

/// Commands from accept threads
impl StreamHandler<ServerCommand, ()> for Server {
    fn finished(&mut self, _: &mut Context<Self>) {}

    fn handle(&mut self, msg: ServerCommand, _: &mut Context<Self>) {
        match msg {
            ServerCommand::WorkerDied(idx) => {
                let mut found = false;
                for i in 0..self.workers.len() {
                    if self.workers[i].0 == idx {
                        self.workers.swap_remove(i);
                        found = true;
                        break;
                    }
                }

                if found {
                    error!("Worker has died {:?}, restarting", idx);

                    let mut new_idx = self.workers.len();
                    'found: loop {
                        for i in 0..self.workers.len() {
                            if self.workers[i].0 == new_idx {
                                new_idx += 1;
                                continue 'found;
                            }
                        }
                        break;
                    }

                    let (addr, worker) = self.start_worker(new_idx, self.accept.get_notify());
                    self.workers.push((new_idx, addr));
                    self.accept.send(Command::Worker(worker));
                }
            }
        }
    }
}

#[derive(Clone, Default)]
pub struct Connections (Arc<ConnectionsInner>);

impl Connections {
    fn new(notify: AcceptNotify, maxconn: usize, maxconnrate: usize) -> Self {
        let maxconn_low = if maxconn > 10 { maxconn - 10 } else { 0 };
        let maxconnrate_low = if maxconnrate > 10 {
            maxconnrate - 10
        } else {
            0
        };

        Connections (
            Arc::new(ConnectionsInner {
                notify,
                maxconn, maxconnrate,
                maxconn_low, maxconnrate_low,
                conn: AtomicUsize::new(0),
                connrate: AtomicUsize::new(0),
            }))
    }

    pub(crate) fn available(&self) -> bool {
        self.0.available()
    }

    pub(crate) fn num_connections(&self) -> usize {
        self.0.conn.load(Ordering::Relaxed)
    }

    /// Report opened connection
    pub fn connection(&self) -> ConnectionTag {
        ConnectionTag::new(self.0.clone())
    }

    /// Report rate connection, rate is usually ssl handshake
    pub fn connection_rate(&self) -> ConnectionRateTag {
        ConnectionRateTag::new(self.0.clone())
    }
}

#[derive(Default)]
struct ConnectionsInner {
    notify: AcceptNotify,
    conn: AtomicUsize,
    connrate: AtomicUsize,
    maxconn: usize,
    maxconnrate: usize,
    maxconn_low: usize,
    maxconnrate_low: usize,
}

impl ConnectionsInner {
    fn available(&self) -> bool {
        if self.maxconnrate <= self.connrate.load(Ordering::Relaxed) {
            false
        } else {
            self.maxconn > self.conn.load(Ordering::Relaxed)
        }
    }

    fn notify_maxconn(&self, maxconn: usize) {
        if maxconn > self.maxconn_low && maxconn <= self.maxconn {
            self.notify.notify();
        }
    }

    fn notify_maxconnrate(&self, connrate: usize) {
        if connrate > self.maxconnrate_low && connrate <= self.maxconnrate {
            self.notify.notify();
        }
    }

}

/// Type responsible for max connection stat.
///
/// Max connections stat get updated on drop.
pub struct ConnectionTag(Arc<ConnectionsInner>);

impl ConnectionTag {
    fn new(inner: Arc<ConnectionsInner>) -> Self {
        inner.conn.fetch_add(1, Ordering::Relaxed);
        ConnectionTag(inner)
    }
}

impl Drop for ConnectionTag {
    fn drop(&mut self) {
        let conn = self.0.conn.fetch_sub(1, Ordering::Relaxed);
        self.0.notify_maxconn(conn);
    }
}

/// Type responsible for max connection rate stat.
///
/// Max connections rate stat get updated on drop.
pub struct ConnectionRateTag (Arc<ConnectionsInner>);

impl ConnectionRateTag {
    fn new(inner: Arc<ConnectionsInner>) -> Self {
        inner.connrate.fetch_add(1, Ordering::Relaxed);
        ConnectionRateTag(inner)
    }
}

impl Drop for ConnectionRateTag {
    fn drop(&mut self) {
        let connrate = self.0.connrate.fetch_sub(1, Ordering::Relaxed);
        self.0.notify_maxconnrate(connrate);
    }
}
<commit_msg>explicit use<commit_after>use std::{mem, net};
use std::time::Duration;
use std::sync::{Arc, atomic::{AtomicUsize, Ordering}};

use num_cpus;
use futures::{Future, Stream, Sink};
use futures::sync::{mpsc, mpsc::unbounded};

use actix::{fut, signal, Actor, ActorFuture, Addr, Arbiter, AsyncContext,
            Context, Handler, Response, System, StreamHandler, WrapFuture};

use super::accept::{AcceptLoop, AcceptNotify, Command};
use super::worker::{StopWorker, Worker, WorkerClient, Conn};
use super::{PauseServer, ResumeServer, StopServer, Token};

pub trait Service: Send + 'static {
    /// Clone service
    fn clone(&self) -> Box<Service>;

    /// Create service handler for this service
    fn create(&self, conn: Connections) -> Box<ServiceHandler>;
}

impl Service for Box<Service> {
    fn clone(&self) -> Box<Service> {
        self.as_ref().clone()
    }

    fn create(&self, conn: Connections) -> Box<ServiceHandler> {
        self.as_ref().create(conn)
    }
}

pub trait ServiceHandler {
    /// Handle incoming stream
    fn handle(&mut self, token: Token, io: net::TcpStream, peer: Option<net::SocketAddr>);

    /// Shutdown open handlers
    fn shutdown(&self, _: bool) {}
}

pub(crate) enum ServerCommand {
    WorkerDied(usize),
}

pub struct Server {
    threads: usize,
    workers: Vec<(usize, Addr<Worker>)>,
    services: Vec<Box<Service>>,
    sockets: Vec<Vec<(Token, net::TcpListener)>>,
    accept: AcceptLoop,
    exit: bool,
    shutdown_timeout: u16,
    signals: Option<Addr<signal::ProcessSignals>>,
    no_signals: bool,
    maxconn: usize,
    maxconnrate: usize,
}

impl Default for Server {
    fn default() -> Self {
        Self::new()
    }
}

impl Server {
    /// Create new Server instance
    pub fn new() -> Server {
        Server {
            threads: num_cpus::get(),
            workers: Vec::new(),
            services: Vec::new(),
            sockets: Vec::new(),
            accept: AcceptLoop::new(),
            exit: false,
            shutdown_timeout: 30,
            signals: None,
            no_signals: false,
            maxconn: 102_400,
            maxconnrate: 256,
        }
    }

    /// Set number of workers to start.
    ///
    /// By default http server uses number of available logical cpu as threads
    /// count.
    pub fn workers(mut self, num: usize) -> Self {
        self.threads = num;
        self
    }

    /// Sets the maximum per-worker number of concurrent connections.
    ///
    /// All socket listeners will stop accepting connections when this limit is reached
    /// for each worker.
    ///
    /// By default max connections is set to a 100k.
    pub fn maxconn(mut self, num: usize) -> Self {
        self.maxconn = num;
        self
    }

    /// Sets the maximum per-worker concurrent connection establish process.
    ///
    /// All listeners will stop accepting connections when this limit is reached. It
    /// can be used to limit the global SSL CPU usage.
    ///
    /// By default max connections is set to a 256.
    pub fn maxconnrate(mut self, num: usize) -> Self {
        self.maxconnrate= num;
        self
    }

    /// Stop actix system.
    ///
    /// `SystemExit` message stops currently running system.
    pub fn system_exit(mut self) -> Self {
        self.exit = true;
        self
    }

    #[doc(hidden)]
    /// Set alternative address for `ProcessSignals` actor.
    pub fn signals(mut self, addr: Addr<signal::ProcessSignals>) -> Self {
        self.signals = Some(addr);
        self
    }

    /// Disable signal handling
    pub fn disable_signals(mut self) -> Self {
        self.no_signals = true;
        self
    }

    /// Timeout for graceful workers shutdown.
    ///
    /// After receiving a stop signal, workers have this much time to finish
    /// serving requests. Workers still alive after the timeout are force
    /// dropped.
    ///
    /// By default shutdown timeout sets to 30 seconds.
    pub fn shutdown_timeout(mut self, sec: u16) -> Self {
        self.shutdown_timeout = sec;
        self
    }

    /// Add new service to server
    pub fn service<T>(mut self, srv: T) -> Self
    where
        T: Into<(Box<Service>, Vec<(Token, net::TcpListener)>)>
    {
        let (srv, sockets) = srv.into();
        self.services.push(srv);
        self.sockets.push(sockets);
        self
    }

    /// Spawn new thread and start listening for incoming connections.
    ///
    /// This method spawns new thread and starts new actix system. Other than
    /// that it is similar to `start()` method. This method blocks.
    ///
    /// This methods panics if no socket addresses get bound.
    ///
    /// ```rust,ignore
    /// # extern crate futures;
    /// # extern crate actix_web;
    /// # use futures::Future;
    /// use actix_web::*;
    ///
    /// fn main() {
    ///     Server::new().
    ///         .service(
    ///            HttpServer::new(|| App::new().resource("/", |r| r.h(|_| HttpResponse::Ok())))
    ///                .bind("127.0.0.1:0")
    ///                .expect("Can not bind to 127.0.0.1:0"))
    ///         .run();
    /// }
    /// ```
    pub fn run(self) {
        let sys = System::new("http-server");
        self.start();
        sys.run();
    }

    /// Start
    pub fn start(mut self) -> Addr<Server> {
        if self.sockets.is_empty() {
            panic!("Service should have at least one bound socket");
        } else {
            info!("Starting {} http workers", self.threads);

            // start workers
            let mut workers = Vec::new();
            for idx in 0..self.threads {
                let (addr, worker) = self.start_worker(idx, self.accept.get_notify());
                workers.push(worker);
                self.workers.push((idx, addr));
            }

            // start accept thread
            for sock in &self.sockets {
                for s in sock.iter() {
                    info!("Starting server on http://{:?}", s.1.local_addr().ok());
                }
            }
            let rx = self.accept.start(
                mem::replace(&mut self.sockets, Vec::new()), workers);

            // start http server actor
            let signals = self.subscribe_to_signals();
            let addr = Actor::create(move |ctx| {
                ctx.add_stream(rx);
                self
            });
            if let Some(signals) = signals {
                signals.do_send(signal::Subscribe(addr.clone().recipient()))
            }
            addr
        }
    }

    // subscribe to os signals
    fn subscribe_to_signals(&self) -> Option<Addr<signal::ProcessSignals>> {
        if !self.no_signals {
            if let Some(ref signals) = self.signals {
                Some(signals.clone())
            } else {
                Some(System::current().registry().get::<signal::ProcessSignals>())
            }
        } else {
            None
        }
    }

    fn start_worker(&self, idx: usize, notify: AcceptNotify) -> (Addr<Worker>, WorkerClient) {
        let (tx, rx) = unbounded::<Conn<net::TcpStream>>();
        let conns = Connections::new(notify, self.maxconn, self.maxconnrate);
        let worker = WorkerClient::new(idx, tx, conns.clone());
        let services: Vec<_> = self.services.iter().map(|v| v.clone()).collect();

        let addr = Arbiter::start(move |ctx: &mut Context<_>| {
            ctx.add_message_stream(rx);
            let handlers: Vec<_> = services.into_iter().map(|s| s.create(conns.clone())).collect();
            Worker::new(conns, handlers)
        });

        (addr, worker)
    }
}

impl Actor for Server
{
    type Context = Context<Self>;
}

/// Signals support
/// Handle `SIGINT`, `SIGTERM`, `SIGQUIT` signals and stop actix system
/// message to `System` actor.
impl Handler<signal::Signal> for Server {
    type Result = ();

    fn handle(&mut self, msg: signal::Signal, ctx: &mut Context<Self>) {
        match msg.0 {
            signal::SignalType::Int => {
                info!("SIGINT received, exiting");
                self.exit = true;
                Handler::<StopServer>::handle(self, StopServer { graceful: false }, ctx);
            }
            signal::SignalType::Term => {
                info!("SIGTERM received, stopping");
                self.exit = true;
                Handler::<StopServer>::handle(self, StopServer { graceful: true }, ctx);
            }
            signal::SignalType::Quit => {
                info!("SIGQUIT received, exiting");
                self.exit = true;
                Handler::<StopServer>::handle(self, StopServer { graceful: false }, ctx);
            }
            _ => (),
        }
    }
}

impl Handler<PauseServer> for Server {
    type Result = ();

    fn handle(&mut self, _: PauseServer, _: &mut Context<Self>) {
        self.accept.send(Command::Pause);
    }
}

impl Handler<ResumeServer> for Server {
    type Result = ();

    fn handle(&mut self, _: ResumeServer, _: &mut Context<Self>) {
        self.accept.send(Command::Resume);
    }
}

impl Handler<StopServer> for Server {
    type Result = Response<(), ()>;

    fn handle(&mut self, msg: StopServer, ctx: &mut Context<Self>) -> Self::Result {
        // stop accept thread
        self.accept.send(Command::Stop);

        // stop workers
        let (tx, rx) = mpsc::channel(1);

        let dur = if msg.graceful {
            Some(Duration::new(u64::from(self.shutdown_timeout), 0))
        } else {
            None
        };
        for worker in &self.workers {
            let tx2 = tx.clone();
            ctx.spawn(
                worker
                    .1
                    .send(StopWorker { graceful: dur })
                    .into_actor(self)
                    .then(move |_, slf, ctx| {
                        slf.workers.pop();
                        if slf.workers.is_empty() {
                            let _ = tx2.send(());

                            // we need to stop system if server was spawned
                            if slf.exit {
                                ctx.run_later(Duration::from_millis(300), |_, _| {
                                    System::current().stop();
                                });
                            }
                        }

                        fut::ok(())
                    }),
            );
        }

        if !self.workers.is_empty() {
            Response::async(rx.into_future().map(|_| ()).map_err(|_| ()))
        } else {
            // we need to stop system if server was spawned
            if self.exit {
                ctx.run_later(Duration::from_millis(300), |_, _| {
                    System::current().stop();
                });
            }
            Response::reply(Ok(()))
        }
    }
}

/// Commands from accept threads
impl StreamHandler<ServerCommand, ()> for Server {
    fn finished(&mut self, _: &mut Context<Self>) {}

    fn handle(&mut self, msg: ServerCommand, _: &mut Context<Self>) {
        match msg {
            ServerCommand::WorkerDied(idx) => {
                let mut found = false;
                for i in 0..self.workers.len() {
                    if self.workers[i].0 == idx {
                        self.workers.swap_remove(i);
                        found = true;
                        break;
                    }
                }

                if found {
                    error!("Worker has died {:?}, restarting", idx);

                    let mut new_idx = self.workers.len();
                    'found: loop {
                        for i in 0..self.workers.len() {
                            if self.workers[i].0 == new_idx {
                                new_idx += 1;
                                continue 'found;
                            }
                        }
                        break;
                    }

                    let (addr, worker) = self.start_worker(new_idx, self.accept.get_notify());
                    self.workers.push((new_idx, addr));
                    self.accept.send(Command::Worker(worker));
                }
            }
        }
    }
}

#[derive(Clone, Default)]
pub struct Connections (Arc<ConnectionsInner>);

impl Connections {
    fn new(notify: AcceptNotify, maxconn: usize, maxconnrate: usize) -> Self {
        let maxconn_low = if maxconn > 10 { maxconn - 10 } else { 0 };
        let maxconnrate_low = if maxconnrate > 10 {
            maxconnrate - 10
        } else {
            0
        };

        Connections (
            Arc::new(ConnectionsInner {
                notify,
                maxconn, maxconnrate,
                maxconn_low, maxconnrate_low,
                conn: AtomicUsize::new(0),
                connrate: AtomicUsize::new(0),
            }))
    }

    pub(crate) fn available(&self) -> bool {
        self.0.available()
    }

    pub(crate) fn num_connections(&self) -> usize {
        self.0.conn.load(Ordering::Relaxed)
    }

    /// Report opened connection
    pub fn connection(&self) -> ConnectionTag {
        ConnectionTag::new(self.0.clone())
    }

    /// Report rate connection, rate is usually ssl handshake
    pub fn connection_rate(&self) -> ConnectionRateTag {
        ConnectionRateTag::new(self.0.clone())
    }
}

#[derive(Default)]
struct ConnectionsInner {
    notify: AcceptNotify,
    conn: AtomicUsize,
    connrate: AtomicUsize,
    maxconn: usize,
    maxconnrate: usize,
    maxconn_low: usize,
    maxconnrate_low: usize,
}

impl ConnectionsInner {
    fn available(&self) -> bool {
        if self.maxconnrate <= self.connrate.load(Ordering::Relaxed) {
            false
        } else {
            self.maxconn > self.conn.load(Ordering::Relaxed)
        }
    }

    fn notify_maxconn(&self, maxconn: usize) {
        if maxconn > self.maxconn_low && maxconn <= self.maxconn {
            self.notify.notify();
        }
    }

    fn notify_maxconnrate(&self, connrate: usize) {
        if connrate > self.maxconnrate_low && connrate <= self.maxconnrate {
            self.notify.notify();
        }
    }

}

/// Type responsible for max connection stat.
///
/// Max connections stat get updated on drop.
pub struct ConnectionTag(Arc<ConnectionsInner>);

impl ConnectionTag {
    fn new(inner: Arc<ConnectionsInner>) -> Self {
        inner.conn.fetch_add(1, Ordering::Relaxed);
        ConnectionTag(inner)
    }
}

impl Drop for ConnectionTag {
    fn drop(&mut self) {
        let conn = self.0.conn.fetch_sub(1, Ordering::Relaxed);
        self.0.notify_maxconn(conn);
    }
}

/// Type responsible for max connection rate stat.
///
/// Max connections rate stat get updated on drop.
pub struct ConnectionRateTag (Arc<ConnectionsInner>);

impl ConnectionRateTag {
    fn new(inner: Arc<ConnectionsInner>) -> Self {
        inner.connrate.fetch_add(1, Ordering::Relaxed);
        ConnectionRateTag(inner)
    }
}

impl Drop for ConnectionRateTag {
    fn drop(&mut self) {
        let connrate = self.0.connrate.fetch_sub(1, Ordering::Relaxed);
        self.0.notify_maxconnrate(connrate);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2019 Fabian Schuiki

//! The central data structure of the compiler.
//!
//! The main piece of infrastructure provided by this module is the [`Context`]
//! trait. It exposes all queries supported by the compiler, together with many
//! other basic operations. Most compiler tasks interact only with [`Context`].
//! The complementary piece of the puzzle is the [`GlobalContext`] which caches
//! all intermediate results and implements the [`Context`] trait. The global
//! context also holds a reference to the [`GlobalArenas`] which own everything
//! that is allocated or interned during query execution.
//!
//! # Example
//!
//! ```
//! # extern crate moore_common as common;
//! # extern crate moore_svlog as svlog;
//! # use common::Session;
//! # use svlog::{GlobalContext, GlobalArenas};
//! let sess = Session::new();
//! let arena = GlobalArenas::default();
//! let gcx = GlobalContext::new(&sess, &arena);
//! ```

use crate::{
    ast,
    ast_map::{AstMap, AstNode},
    common::{arenas::Alloc, arenas::TypedArena, Session},
    crate_prelude::*,
    hir::{self, HirNode},
    ty::{Type, TypeKind},
};
use llhd;
use std::cell::RefCell;
use std::collections::HashMap;

/// The central data structure of the compiler. It stores references to various
/// arenas and tables that store the results of the various computations that
/// have been performed.
pub struct GlobalContext<'gcx> {
    /// The global compiler session.
    pub sess: &'gcx Session,
    /// The arena that owns all references.
    pub arena: &'gcx GlobalArenas<'gcx>,
    /// The underlying runtime for the query system.
    runtime: salsa::Runtime<GlobalContext<'gcx>>,
    /// The mapping of node IDs to abstract syntax tree nodes.
    ast_map: AstMap<'gcx>,
    /// The modules in the AST.
    modules: RefCell<HashMap<Name, NodeId>>,
    /// A mapping from node ids to spans for diagnostics.
    node_id_to_span: RefCell<HashMap<NodeId, Span>>,
}

impl<'gcx> GlobalContext<'gcx> {
    /// Create a new global context.
    pub fn new(sess: &'gcx Session, arena: &'gcx GlobalArenas<'gcx>) -> Self {
        GlobalContext {
            sess,
            arena,
            runtime: Default::default(),
            ast_map: Default::default(),
            modules: Default::default(),
            node_id_to_span: Default::default(),
        }
    }

    /// Add root AST nodes to the context for processing.
    ///
    /// Use the `find_global_item` function afterwards to look up the id of
    /// modules that were added.
    pub fn add_root_nodes(&self, ast: impl Iterator<Item = &'gcx ast::Root>) {
        for root in ast {
            for item in &root.items {
                match *item {
                    ast::Item::Module(ref m) => {
                        let id = self.map_ast(AstNode::Module(m));
                        self.modules.borrow_mut().insert(m.name, id);
                    }
                    _ => {
                        let _: Result<()> = self.unimp(item);
                    }
                }
            }
        }
    }

    /// Find a module in the AST.
    pub fn find_module(&self, name: Name) -> Option<NodeId> {
        self.modules.borrow().get(&name).cloned()
    }

    /// Get an iterator over all modules in the AST.
    pub fn modules(&self) -> impl Iterator<Item = (Name, NodeId)> {
        self.modules.borrow().clone().into_iter()
    }
}

impl DiagEmitter for GlobalContext<'_> {
    fn emit(&self, diag: DiagBuilder2) {
        self.sess.emit(diag)
    }
}

impl<'gcx> salsa::Database for GlobalContext<'gcx> {
    fn salsa_runtime(&self) -> &salsa::Runtime<Self> {
        &self.runtime
    }
}

impl<'gcx> BaseContext<'gcx> for GlobalContext<'gcx> {
    fn gcx(&self) -> &GlobalContext<'gcx> {
        self
    }
}

/// The arenas that allocate things in the global context.
///
/// Use this struct whenever you want to allocate or internalize
/// something during the compilation procedure.
pub struct GlobalArenas<'t> {
    ids: TypedArena<NodeId>,
    hir: hir::Arena<'t>,
}

impl Default for GlobalArenas<'_> {
    fn default() -> Self {
        GlobalArenas {
            ids: TypedArena::new(),
            hir: Default::default(),
        }
    }
}

impl<'t> GlobalArenas<'t> {
    /// Allocate a list of node IDs.
    pub fn alloc_ids(&'t self, ids: impl IntoIterator<Item = NodeId>) -> &'t [NodeId] {
        self.ids.alloc_extend(ids)
    }

    /// Allocate an HIR node into the global context.
    pub fn alloc_hir<T>(&'t self, hir: T) -> &'t T
    where
        hir::Arena<'t>: Alloc<'t, 't, T>,
        T: 't,
    {
        self.hir.alloc(hir)
    }
}

/// The fundamental compiler context.
///
/// This trait represents the context within which most compiler operations take
/// place. It is implemented by [`GlobalContext`] and also provides access to
/// the global context via the `gcx()` method.
pub trait BaseContext<'gcx>: salsa::Database + DiagEmitter {
    /// Get the global context.
    #[inline(always)]
    fn gcx(&self) -> &GlobalContext<'gcx>;

    /// Get the compiler session.
    #[inline(always)]
    fn sess(&self) -> &'gcx Session {
        self.gcx().sess
    }

    /// Access the arena into which values are to be allocated.
    #[inline(always)]
    fn arena(&self) -> &'gcx GlobalArenas<'gcx> {
        self.gcx().arena
    }

    /// Emit an internal compiler error that a node is not implemented.
    fn unimp<T: HasSpan + HasDesc, R>(&self, node: &T) -> Result<R> {
        self.emit(
            DiagBuilder2::bug(format!("{} not implemented", node.desc_full()))
                .span(node.human_span()),
        );
        Err(())
    }

    /// Emit an internal compiler error and message that a node is not
    /// implemented. Same as [`unimp`], but the caller can provide a message
    /// prefix.
    fn unimp_msg<T: HasSpan + HasDesc, R>(&self, msg: impl Into<String>, node: &T) -> Result<R> {
        self.emit(
            DiagBuilder2::bug(format!(
                "{} {} not implemented",
                msg.into(),
                node.desc_full()
            ))
            .span(node.human_span()),
        );
        Err(())
    }

    /// Allocate a new node id.
    ///
    /// The provided span is used primarily for diagnostic messages and is
    /// supposed to easily identify the node to the user in case of an error.
    fn alloc_id(&self, span: Span) -> NodeId {
        let id = NodeId::alloc();
        self.gcx().node_id_to_span.borrow_mut().insert(id, span);
        id
    }

    /// Return the diagnostic span associated with a ndoe id.
    fn span(&self, node_id: NodeId) -> Span {
        self.gcx()
            .node_id_to_span
            .borrow()
            .get(&node_id)
            .cloned()
            .unwrap_or(crate::common::source::INVALID_SPAN)
    }

    /// Associate an AST node with a node id.
    fn set_ast(&self, node_id: NodeId, ast: AstNode<'gcx>) {
        self.gcx().ast_map.set(node_id, ast)
    }

    /// Allocate a node id for an AST node and associate that id with the node.
    fn map_ast(&self, ast: AstNode<'gcx>) -> NodeId {
        let id = self.alloc_id(ast.human_span());
        self.set_ast(id, ast);
        id
    }

    /// Obtain the AST node associated with a node id.
    fn ast_of(&self, node_id: NodeId) -> Result<AstNode<'gcx>> {
        match self.gcx().ast_map.get(node_id) {
            Some(node) => Ok(node),
            None => {
                let span = self.gcx().node_id_to_span.borrow()[&node_id];
                self.emit(
                    DiagBuilder2::bug(format!("no ast node for `{}` in the map", span.extract()))
                        .span(span),
                );
                Err(())
            }
        }
    }

    /// Make a void type.
    fn mkty_void(&self) -> Type<'gcx> {
        static STATIC: TypeKind<'static> = TypeKind::Void;
        &STATIC
    }

    /// Make a bit type.
    fn mkty_bit(&self) -> Type<'gcx> {
        static STATIC: TypeKind<'static> = TypeKind::Bit;
        &STATIC
    }
}

salsa::query_group! {
    /// A collection of compiler queries.
    pub trait Context<'a>: BaseContext<'a> {
        /// Lower an AST node to HIR.
        fn hir_of(node_id: NodeId) -> Result<HirNode<'a>> {
            type HirOf;
            use fn hir::hir_of;
        }

        /// Determine the type of a node.
        fn type_of(node_id: NodeId) -> Result<Type<'a>> {
            type TypeOf;
            use fn typeck::type_of;
        }
    }
}

salsa::database_storage! {
    /// The query result storage embedded in the global context.
    pub struct GlobalStorage<'gcx> for GlobalContext<'gcx> {
        impl Context<'gcx> {
            fn hir_of() for HirOf<'gcx>;
            fn type_of() for TypeOf<'gcx>;
        }
    }
}
<commit_msg>svlog: move queries into private module<commit_after>// Copyright (c) 2016-2019 Fabian Schuiki

//! The central data structure of the compiler.
//!
//! The main piece of infrastructure provided by this module is the [`Context`]
//! trait. It exposes all queries supported by the compiler, together with many
//! other basic operations. Most compiler tasks interact only with [`Context`].
//! The complementary piece of the puzzle is the [`GlobalContext`] which caches
//! all intermediate results and implements the [`Context`] trait. The global
//! context also holds a reference to the [`GlobalArenas`] which own everything
//! that is allocated or interned during query execution.
//!
//! # Example
//!
//! ```
//! # extern crate moore_common as common;
//! # extern crate moore_svlog as svlog;
//! # use common::Session;
//! # use svlog::{GlobalContext, GlobalArenas};
//! let sess = Session::new();
//! let arena = GlobalArenas::default();
//! let gcx = GlobalContext::new(&sess, &arena);
//! ```

use crate::{
    ast,
    ast_map::{AstMap, AstNode},
    common::{arenas::Alloc, arenas::TypedArena, Session},
    crate_prelude::*,
    hir::{self, HirNode},
    ty::{Type, TypeKind},
};
use llhd;
use std::cell::RefCell;
use std::collections::HashMap;

/// The central data structure of the compiler. It stores references to various
/// arenas and tables that store the results of the various computations that
/// have been performed.
pub struct GlobalContext<'gcx> {
    /// The global compiler session.
    pub sess: &'gcx Session,
    /// The arena that owns all references.
    pub arena: &'gcx GlobalArenas<'gcx>,
    /// The underlying runtime for the query system.
    runtime: salsa::Runtime<GlobalContext<'gcx>>,
    /// The mapping of node IDs to abstract syntax tree nodes.
    ast_map: AstMap<'gcx>,
    /// The modules in the AST.
    modules: RefCell<HashMap<Name, NodeId>>,
    /// A mapping from node ids to spans for diagnostics.
    node_id_to_span: RefCell<HashMap<NodeId, Span>>,
}

impl<'gcx> GlobalContext<'gcx> {
    /// Create a new global context.
    pub fn new(sess: &'gcx Session, arena: &'gcx GlobalArenas<'gcx>) -> Self {
        GlobalContext {
            sess,
            arena,
            runtime: Default::default(),
            ast_map: Default::default(),
            modules: Default::default(),
            node_id_to_span: Default::default(),
        }
    }

    /// Add root AST nodes to the context for processing.
    ///
    /// Use the `find_global_item` function afterwards to look up the id of
    /// modules that were added.
    pub fn add_root_nodes(&self, ast: impl Iterator<Item = &'gcx ast::Root>) {
        for root in ast {
            for item in &root.items {
                match *item {
                    ast::Item::Module(ref m) => {
                        let id = self.map_ast(AstNode::Module(m));
                        self.modules.borrow_mut().insert(m.name, id);
                    }
                    _ => {
                        let _: Result<()> = self.unimp(item);
                    }
                }
            }
        }
    }

    /// Find a module in the AST.
    pub fn find_module(&self, name: Name) -> Option<NodeId> {
        self.modules.borrow().get(&name).cloned()
    }

    /// Get an iterator over all modules in the AST.
    pub fn modules(&self) -> impl Iterator<Item = (Name, NodeId)> {
        self.modules.borrow().clone().into_iter()
    }
}

impl DiagEmitter for GlobalContext<'_> {
    fn emit(&self, diag: DiagBuilder2) {
        self.sess.emit(diag)
    }
}

impl<'gcx> salsa::Database for GlobalContext<'gcx> {
    fn salsa_runtime(&self) -> &salsa::Runtime<Self> {
        &self.runtime
    }
}

impl<'gcx> BaseContext<'gcx> for GlobalContext<'gcx> {
    fn gcx(&self) -> &GlobalContext<'gcx> {
        self
    }
}

/// The arenas that allocate things in the global context.
///
/// Use this struct whenever you want to allocate or internalize
/// something during the compilation procedure.
pub struct GlobalArenas<'t> {
    ids: TypedArena<NodeId>,
    hir: hir::Arena<'t>,
}

impl Default for GlobalArenas<'_> {
    fn default() -> Self {
        GlobalArenas {
            ids: TypedArena::new(),
            hir: Default::default(),
        }
    }
}

impl<'t> GlobalArenas<'t> {
    /// Allocate a list of node IDs.
    pub fn alloc_ids(&'t self, ids: impl IntoIterator<Item = NodeId>) -> &'t [NodeId] {
        self.ids.alloc_extend(ids)
    }

    /// Allocate an HIR node into the global context.
    pub fn alloc_hir<T>(&'t self, hir: T) -> &'t T
    where
        hir::Arena<'t>: Alloc<'t, 't, T>,
        T: 't,
    {
        self.hir.alloc(hir)
    }
}

/// The fundamental compiler context.
///
/// This trait represents the context within which most compiler operations take
/// place. It is implemented by [`GlobalContext`] and also provides access to
/// the global context via the `gcx()` method.
pub trait BaseContext<'gcx>: salsa::Database + DiagEmitter {
    /// Get the global context.
    #[inline(always)]
    fn gcx(&self) -> &GlobalContext<'gcx>;

    /// Get the compiler session.
    #[inline(always)]
    fn sess(&self) -> &'gcx Session {
        self.gcx().sess
    }

    /// Access the arena into which values are to be allocated.
    #[inline(always)]
    fn arena(&self) -> &'gcx GlobalArenas<'gcx> {
        self.gcx().arena
    }

    /// Emit an internal compiler error that a node is not implemented.
    fn unimp<T: HasSpan + HasDesc, R>(&self, node: &T) -> Result<R> {
        self.emit(
            DiagBuilder2::bug(format!("{} not implemented", node.desc_full()))
                .span(node.human_span()),
        );
        Err(())
    }

    /// Emit an internal compiler error and message that a node is not
    /// implemented. Same as [`unimp`], but the caller can provide a message
    /// prefix.
    fn unimp_msg<T: HasSpan + HasDesc, R>(&self, msg: impl Into<String>, node: &T) -> Result<R> {
        self.emit(
            DiagBuilder2::bug(format!(
                "{} {} not implemented",
                msg.into(),
                node.desc_full()
            ))
            .span(node.human_span()),
        );
        Err(())
    }

    /// Allocate a new node id.
    ///
    /// The provided span is used primarily for diagnostic messages and is
    /// supposed to easily identify the node to the user in case of an error.
    fn alloc_id(&self, span: Span) -> NodeId {
        let id = NodeId::alloc();
        self.gcx().node_id_to_span.borrow_mut().insert(id, span);
        id
    }

    /// Return the diagnostic span associated with a ndoe id.
    fn span(&self, node_id: NodeId) -> Span {
        self.gcx()
            .node_id_to_span
            .borrow()
            .get(&node_id)
            .cloned()
            .unwrap_or(crate::common::source::INVALID_SPAN)
    }

    /// Associate an AST node with a node id.
    fn set_ast(&self, node_id: NodeId, ast: AstNode<'gcx>) {
        self.gcx().ast_map.set(node_id, ast)
    }

    /// Allocate a node id for an AST node and associate that id with the node.
    fn map_ast(&self, ast: AstNode<'gcx>) -> NodeId {
        let id = self.alloc_id(ast.human_span());
        self.set_ast(id, ast);
        id
    }

    /// Obtain the AST node associated with a node id.
    fn ast_of(&self, node_id: NodeId) -> Result<AstNode<'gcx>> {
        match self.gcx().ast_map.get(node_id) {
            Some(node) => Ok(node),
            None => {
                let span = self.gcx().node_id_to_span.borrow()[&node_id];
                self.emit(
                    DiagBuilder2::bug(format!("no ast node for `{}` in the map", span.extract()))
                        .span(span),
                );
                Err(())
            }
        }
    }

    /// Make a void type.
    fn mkty_void(&self) -> Type<'gcx> {
        static STATIC: TypeKind<'static> = TypeKind::Void;
        &STATIC
    }

    /// Make a bit type.
    fn mkty_bit(&self) -> Type<'gcx> {
        static STATIC: TypeKind<'static> = TypeKind::Bit;
        &STATIC
    }
}

/// The queries implemented by the compiler.
pub(super) mod queries {
    use super::*;

    salsa::query_group! {
        /// A collection of compiler queries.
        pub trait Context<'a>: BaseContext<'a> {
            /// Lower an AST node to HIR.
            fn hir_of(node_id: NodeId) -> Result<HirNode<'a>> {
                type HirOf;
                use fn hir::hir_of;
            }

            /// Determine the type of a node.
            fn type_of(node_id: NodeId) -> Result<Type<'a>> {
                type TypeOf;
                use fn typeck::type_of;
            }
        }
    }

    salsa::database_storage! {
        /// The query result storage embedded in the global context.
        pub struct GlobalStorage<'gcx> for GlobalContext<'gcx> {
            impl Context<'gcx> {
                fn hir_of() for HirOf<'gcx>;
                fn type_of() for TypeOf<'gcx>;
            }
        }
    }
}

pub use self::queries::Context;
<|endoftext|>


<commit_before>use std::sync::Arc;
use std::path::Path;

use img;

use ::Point2i;
use interaction::SurfaceInteraction;
use mipmap::{MIPMap, WrapMode};
use spectrum::Spectrum;
use texture::{Texture, TextureMapping2D, UVMapping2D};

pub struct ImageTexture {
    mapping: Box<TextureMapping2D + Send + Sync>,
    mipmap: Arc<MIPMap<Spectrum>>,
}

impl ImageTexture {
    pub fn new(path: &Path) -> ImageTexture {
        info!("Loading texture {}", path.display());
        // TODO log warning and use constant texture if cannot open texture file
        let buf = img::open(path).unwrap();
        let rgb = buf.to_rgb();
        let res = Point2i::new(rgb.width(), rgb.height());
        let pixels: Vec<Spectrum> = rgb.pixels()
            .map(|p| Spectrum::from_srgb(&p.data))
            .collect();

        ImageTexture {
            mapping: Box::new(UVMapping2D::new(2.0, 2.0, 0.0, 0.0)),
            mipmap: Arc::new(MIPMap::new(&res, &pixels[..], false, 0.0, WrapMode::Repeat)),
        }
    }
}

impl Texture<Spectrum> for ImageTexture {
    fn evaluate(&self, si: &SurfaceInteraction) -> Spectrum {
        let st = self.mapping.map(si);
        // TODO Call correct lookup method once we have ray differentials
        self.mipmap.lookup(&st, 0.1)
    }
}

#[test]
fn load_texture() {
    ImageTexture::new(&Path::new("lines.png"));
    assert!(true);
}
<commit_msg>Use 0 width in image texture for looking up mipmap<commit_after>use std::sync::Arc;
use std::path::Path;

use img;

use ::Point2i;
use interaction::SurfaceInteraction;
use mipmap::{MIPMap, WrapMode};
use spectrum::Spectrum;
use texture::{Texture, TextureMapping2D, UVMapping2D};

pub struct ImageTexture {
    mapping: Box<TextureMapping2D + Send + Sync>,
    mipmap: Arc<MIPMap<Spectrum>>,
}

impl ImageTexture {
    pub fn new(path: &Path) -> ImageTexture {
        info!("Loading texture {}", path.display());
        // TODO log warning and use constant texture if cannot open texture file
        let buf = img::open(path).unwrap();
        let rgb = buf.to_rgb();
        let res = Point2i::new(rgb.width(), rgb.height());
        let pixels: Vec<Spectrum> = rgb.pixels()
            .map(|p| Spectrum::from_srgb(&p.data))
            .collect();

        ImageTexture {
            mapping: Box::new(UVMapping2D::new(2.0, 2.0, 0.0, 0.0)),
            mipmap: Arc::new(MIPMap::new(&res, &pixels[..], false, 0.0, WrapMode::Repeat)),
        }
    }
}

impl Texture<Spectrum> for ImageTexture {
    fn evaluate(&self, si: &SurfaceInteraction) -> Spectrum {
        let st = self.mapping.map(si);
        // TODO Call correct lookup method once we have ray differentials
        self.mipmap.lookup(&st, 0.0)
    }
}

#[test]
fn load_texture() {
    ImageTexture::new(&Path::new("lines.png"));
    assert!(true);
}
<|endoftext|>


<commit_before>
extern crate rand;
use std::net::{Ipv4Addr, SocketAddrV4, UdpSocket};
use file_stream_iter::FileStream;
use std::io::Error;
use tftp_specific::PacketType;
use std::str::FromStr;
use std::net::AddrParseError;
use std::error;

pub struct EndPoint{
    local_connection : SocketAddrV4,
    remote_connection : SocketAddrV4
}

impl EndPoint{

    pub fn new(remote : &str) -> Result<EndPoint, AddrParseError>{

        let ipv4 = try!(get_ip_from(remote));
        Ok(EndPoint{
            local_connection : SocketAddrV4::new(Ipv4Addr::new(127,0,0,1), 6900),
            remote_connection : SocketAddrV4::new(ipv4, 9990)
        })
    }

    fn start_listen(){

    }

    pub fn recv(&mut self) -> Result<(), Error> {
        // Define the local connection information
        //let ip = Ipv4Addr::new(127, 0, 0, 1);
        //TODO we want to use port 69 here
        //let connection = SocketAddrV4::new(ip, 6900);

        // Bind the socket
        let socket = try!(UdpSocket::bind(self.local_connection));

        // Read from the socket
        let mut buf = [0u8; 516]; //UDP packet is 516 bytes
        let (amt, src) = try!(socket.recv_from(&mut buf));
        match buf[1]{
            3 =>{
                let block_num : u16 = 0u16 | (buf[2] as u16) << 8 |  buf[3] as u16;
                let block_size = amt - 4;
                println!("{:?}", block_size);
                if block_size < 512{
                    println!("recvr recvd: {:?}", &buf[0 .. amt]);
                    println!("Last block of the file received");
                }
                //send ACK

                let low = block_num & 0x00FF;
                let high = (block_num & 0xFF00) >> 8;

                socket.send_to(&[0,PacketType::ACK as u8, high as u8, low as u8], src);
            },
            _ => {}
        }

        Ok(())
    }

    pub fn send(&mut self) -> Result<(), Error> {
        // Define the local connection (to send the data from)
        //let ip = Ipv4Addr::new(127, 0, 0, 1);
        //TODO generate port # using rand
        //let connection = SocketAddrV4::new(ip, 9992);

        // Bind the socket
        let socket = try!(UdpSocket::bind(self.local_connection));

        // Define the remote connection (to send the data to)
        //let connection2 = SocketAddrV4::new(ip, 6900);

        // Send data via the socket
        let mut fs = FileStream::new("/home/abhi/code/rust/fei/target/debug/foo.txt".to_string()).unwrap();
        let (buf, num_bytes_read) = fs.next().unwrap();
        let mut v = Vec::with_capacity(num_bytes_read + 4);
        v.push(0);
        v.push(3);
        v.push(0xFF);
        let mut cnt = 0xFF;
        v.push(cnt);
        v.extend_from_slice(&buf[0..num_bytes_read]);
        try!(socket.send_to(v.as_slice(), self.remote_connection));

        let mut buf  = [0; 10];
        socket.recv_from(&mut buf);

        println!("sender recvd {:?}", buf);
        Ok(())
    }

    fn create_rrq_wrq_packet(p_type: PacketType, file_name: String, mode : &'static str)->Vec<u8>{
        let mut v = Vec::with_capacity(2+file_name.len()+1+mode.len()+1);
        v.push(0);
        v.push(p_type as u8);
        v.extend(file_name.as_bytes());
        v.push(0);//zero terminator
        v.extend(mode.as_bytes());
        v.push(0);//zero terminator
        v
    }
}

fn get_ip_from(ip : &str) -> Result<Ipv4Addr, AddrParseError>{
    Ipv4Addr::from_str(ip)
}

<commit_msg>Add an empty send_file function<commit_after>
extern crate rand;
use std::net::{Ipv4Addr, SocketAddrV4, UdpSocket};
use file_stream_iter::FileStream;
use std::io::Error;
use tftp_specific::PacketType;
use std::str::FromStr;
use std::net::AddrParseError;
use std::error;

pub struct EndPoint{
    local_connection : SocketAddrV4,
    remote_connection : SocketAddrV4
}

impl EndPoint{

    pub fn new(remote : &str) -> Result<EndPoint, AddrParseError>{

        let ipv4 = try!(get_ip_from(remote));
        Ok(EndPoint{
            local_connection : SocketAddrV4::new(Ipv4Addr::new(127,0,0,1), 6900),
            remote_connection : SocketAddrV4::new(ipv4, 9990)
        })
    }

    fn start_listen(){

    }

    pub fn recv(&mut self) -> Result<(), Error> {
        // Define the local connection information
        //let ip = Ipv4Addr::new(127, 0, 0, 1);
        //TODO we want to use port 69 here
        //let connection = SocketAddrV4::new(ip, 6900);

        // Bind the socket
        let socket = try!(UdpSocket::bind(self.local_connection));

        // Read from the socket
        let mut buf = [0u8; 516]; //UDP packet is 516 bytes
        let (amt, src) = try!(socket.recv_from(&mut buf));
        match buf[1]{
            3 =>{
                let block_num : u16 = 0u16 | (buf[2] as u16) << 8 |  buf[3] as u16;
                let block_size = amt - 4;
                println!("{:?}", block_size);
                if block_size < 512{
                    println!("recvr recvd: {:?}", &buf[0 .. amt]);
                    println!("Last block of the file received");
                }
                //send ACK

                let low = block_num & 0x00FF;
                let high = (block_num & 0xFF00) >> 8;

                socket.send_to(&[0,PacketType::ACK as u8, high as u8, low as u8], src);
            },
            _ => {}
        }

        Ok(())
    }

    pub fn send(&mut self) -> Result<(), Error> {
        // Define the local connection (to send the data from)
        //let ip = Ipv4Addr::new(127, 0, 0, 1);
        //TODO generate port # using rand
        //let connection = SocketAddrV4::new(ip, 9992);

        // Bind the socket
        let socket = try!(UdpSocket::bind(self.local_connection));

        // Define the remote connection (to send the data to)
        //let connection2 = SocketAddrV4::new(ip, 6900);

        // Send data via the socket
        let mut fs = FileStream::new("/home/abhi/code/rust/fei/target/debug/foo.txt".to_string()).unwrap();
        let (buf, num_bytes_read) = fs.next().unwrap();
        let mut v = Vec::with_capacity(num_bytes_read + 4);
        v.push(0);
        v.push(3);
        v.push(0xFF);
        let mut cnt = 0xFF;
        v.push(cnt);
        v.extend_from_slice(&buf[0..num_bytes_read]);
        try!(socket.send_to(v.as_slice(), self.remote_connection));

        let mut buf  = [0; 10];
        socket.recv_from(&mut buf);

        println!("sender recvd {:?}", buf);
        Ok(())
    }

    fn send_file(&mut self, filename : &str) {

    }

    fn create_rrq_wrq_packet(p_type: PacketType, file_name: String, mode : &'static str)->Vec<u8>{
        let mut v = Vec::with_capacity(2+file_name.len()+1+mode.len()+1);
        v.push(0);
        v.push(p_type as u8);
        v.extend(file_name.as_bytes());
        v.push(0);//zero terminator
        v.extend(mode.as_bytes());
        v.push(0);//zero terminator
        v
    }
}

fn get_ip_from(ip : &str) -> Result<Ipv4Addr, AddrParseError>{
    Ipv4Addr::from_str(ip)
}

<|endoftext|>


<commit_before>use super::super::{Coord, Grid, X, Y};
use super::*;
use grid_loop::{Edge, GridLoop, GridLoopField};
use std::cmp;

#[derive(Clone)]
pub struct Field {
    grid_loop: GridLoop,
    clue: Grid<Clue>,
    cell: Grid<Cell>,
}

const FOUR_NEIGHBORS: [(i32, i32); 4] = [(-1, 0), (0, -1), (1, 0), (0, 1)];

impl Field {
    pub fn new(clue: Grid<Clue>) -> Field {
        let height = clue.height();
        let width = clue.width();

        let mut cell = Grid::new(height, width, Cell::Undecided);
        let mut grid_loop = GridLoop::new(height - 1, width - 1);

        {
            let mut handle = GridLoop::get_handle(&mut grid_loop);
            for y in 0..height {
                for x in 0..width {
                    let c = clue[(Y(y), X(x))];
                    if c != Clue::NoClue {
                        cell[(Y(y), X(x))] = Cell::Clue;
                        GridLoop::decide_edge(&mut *handle, (Y(y * 2 - 1), X(x * 2)), Edge::Blank);
                        GridLoop::decide_edge(&mut *handle, (Y(y * 2 + 1), X(x * 2)), Edge::Blank);
                        GridLoop::decide_edge(&mut *handle, (Y(y * 2), X(x * 2 - 1)), Edge::Blank);
                        GridLoop::decide_edge(&mut *handle, (Y(y * 2), X(x * 2 + 1)), Edge::Blank);
                    }
                }
            }
        }
        Field {
            grid_loop,
            clue,
            cell,
        }
    }
    pub fn height(&self) -> i32 {
        self.clue.height()
    }
    pub fn width(&self) -> i32 {
        self.clue.width()
    }
    pub fn inconsistent(&self) -> bool {
        self.grid_loop.inconsistent()
    }
    pub fn set_inconsistent(&mut self) {
        self.grid_loop.set_inconsistent()
    }
    pub fn fully_solved(&self) -> bool {
        self.grid_loop.fully_solved()
    }
    pub fn get_cell(&self, cd: Coord) -> Cell {
        self.cell[cd]
    }
    pub fn get_cell_safe(&self, cd: Coord) -> Cell {
        if self.cell.is_valid_coord(cd) {
            self.cell[cd]
        } else {
            // The outside of the field can be identified with a (meaningless) clue
            Cell::Clue
        }
    }
    pub fn get_edge(&self, cd: Coord) -> Edge {
        self.grid_loop.get_edge(cd)
    }
    pub fn get_edge_safe(&self, cd: Coord) -> Edge {
        self.grid_loop.get_edge_safe(cd)
    }

    pub fn set_cell(&mut self, cd: Coord, v: Cell) {
        let mut handle = GridLoop::get_handle(self);
        handle.set_cell_internal(cd, v);
    }
    pub fn check_all_cell(&mut self) {
        let height = self.height();
        let width = self.width();
        let mut handle = GridLoop::get_handle(self);
        for y in 0..height {
            for x in 0..width {
                GridLoop::check(&mut *handle, (Y(y * 2), X(x * 2)));
            }
        }
    }

    fn set_cell_internal(&mut self, cd: Coord, v: Cell) {
        let current = self.cell[cd];
        if current != Cell::Undecided {
            if current != v {
                self.set_inconsistent();
            }
            return;
        }

        self.cell[cd] = v;
        let (Y(y), X(x)) = cd;
        match v {
            Cell::Undecided => (),
            Cell::Clue => (), // don't do this!
            Cell::Line => GridLoop::check(self, (Y(y * 2), X(x * 2))),
            Cell::Blocked => for &(dy, dx) in &FOUR_NEIGHBORS {
                if self.get_cell_safe((Y(y + dy), X(x + dx))) != Cell::Clue {
                    self.set_cell_internal((Y(y + dy), X(x + dx)), Cell::Line);
                }
                GridLoop::decide_edge(self, (Y(y * 2 + dy), X(x * 2 + dx)), Edge::Blank);
            },
        }
    }
    fn inspect_clue(&mut self, cell_cd: Coord) {
        let (Y(y), X(x)) = cell_cd;
        let clue = self.clue[cell_cd];
        let (dy, dx, mut n) = match clue {
            Clue::NoClue | Clue::Empty => return,
            Clue::Up(n) => (-1, 0, n),
            Clue::Left(n) => (0, -1, n),
            Clue::Right(n) => (0, 1, n),
            Clue::Down(n) => (1, 0, n),
        };
        let mut involving_cells = 0;
        {
            let mut y = y + dy;
            let mut x = x + dx;
            while self.clue.is_valid_coord((Y(y), X(x))) {
                let c = self.clue[(Y(y), X(x))];
                if c.same_shape(clue) {
                    n -= c.clue_number();
                    break;
                }
                y += dy;
                x += dx;
                involving_cells += 1;
            }
        }
        let mut dp_left = vec![(0, 0); (involving_cells + 1) as usize];
        let mut dp_right = vec![(0, 0); (involving_cells + 1) as usize];

        for i in 0..involving_cells {
            let c = self.get_cell((Y(y + dy * (i + 1)), X(x + dx * (i + 1))));
            dp_left[(i + 1) as usize] = match c {
                Cell::Undecided => {
                    let (lo, hi) = dp_left[cmp::max(0, i - 1) as usize];
                    (lo, hi + 1)
                }
                Cell::Clue | Cell::Line => dp_left[i as usize],
                Cell::Blocked => {
                    let (lo, hi) = dp_left[cmp::max(0, i - 1) as usize];
                    (lo + 1, hi + 1)
                }
            };
        }
        for i in 0..involving_cells {
            let i = involving_cells - 1 - i;
            let c = self.get_cell((Y(y + dy * (i + 1)), X(x + dx * (i + 1))));
            dp_right[i as usize] = match c {
                Cell::Undecided => {
                    let (lo, hi) = dp_right[cmp::min(involving_cells, i + 2) as usize];
                    (lo, hi + 1)
                }
                Cell::Clue | Cell::Line => dp_right[(i + 1) as usize],
                Cell::Blocked => {
                    let (lo, hi) = dp_right[cmp::min(involving_cells, i + 2) as usize];
                    (lo + 1, hi + 1)
                }
            };
        }
        for i in 0..involving_cells {
            let (left_lo, left_hi) = dp_left[i as usize];
            let (right_lo, right_hi) = dp_right[(i + 1) as usize];

            if left_hi + right_hi < n - 1 {
                self.set_inconsistent();
                return;
            } else if left_hi + right_hi == n - 1 {
                self.set_cell_internal((Y(y + dy * (i + 1)), X(x + dx * (i + 1))), Cell::Blocked);
            }

            if left_lo + right_lo > n {
                self.set_inconsistent();
                return;
            } else if left_lo + right_lo == n {
                self.set_cell_internal((Y(y + dy * (i + 1)), X(x + dx * (i + 1))), Cell::Line);
            }
        }
    }
}

impl GridLoopField for Field {
    fn grid_loop(&mut self) -> &mut GridLoop {
        &mut self.grid_loop
    }
    fn check_neighborhood(&mut self, (Y(y), X(x)): Coord) {
        if y % 2 == 0 {
            GridLoop::check(self, (Y(y), X(x - 1)));
            GridLoop::check(self, (Y(y), X(x + 1)));
        } else {
            GridLoop::check(self, (Y(y - 1), X(x)));
            GridLoop::check(self, (Y(y + 1), X(x)));
        }
    }
    fn inspect(&mut self, cd: Coord) {
        let (Y(y), X(x)) = cd;
        if !(y % 2 == 0 && x % 2 == 0) {
            return;
        }
        let cell = self.get_cell((Y(y / 2), X(x / 2)));
        if cell == Cell::Line || cell == Cell::Undecided {
            let (n_line, n_undecided) = self.grid_loop.neighbor_summary(cd);

            if cell == Cell::Line {
                if n_line + n_undecided <= 1 {
                    self.set_inconsistent();
                    return;
                } else if n_line + n_undecided <= 2 {
                    for &(dy, dx) in &FOUR_NEIGHBORS {
                        if self.get_edge_safe((Y(y + dy), X(x + dx))) != Edge::Blank {
                            GridLoop::decide_edge(self, (Y(y + dy), X(x + dx)), Edge::Line);
                        }
                    }
                }
            } else {
                if n_line == 0 && n_undecided == 2 {
                    for &(dy, dx) in &FOUR_NEIGHBORS {
                        if self.get_edge_safe((Y(y + dy), X(x + dx))) == Edge::Undecided {
                            self.set_cell_internal((Y(y / 2 + dy), X(x / 2 + dx)), Cell::Line);
                        }
                    }
                }
            }
        } else if cell == Cell::Clue {
            self.inspect_clue((Y(y / 2), X(x / 2)));
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_yajilin_clue() {
        {
            // Loop must not pass through clue cells
            let mut problem = Grid::new(5, 5, Clue::NoClue);
            problem[(Y(0), X(0))] = Clue::Right(1);

            let mut field = Field::new(problem);
            field.check_all_cell();

            assert_eq!(field.inconsistent(), false);
            assert_eq!(field.get_edge((Y(0), X(1))), Edge::Blank);
            assert_eq!(field.get_edge((Y(1), X(0))), Edge::Blank);
        }
        {
            // 0 block cells
            let mut problem = Grid::new(5, 7, Clue::NoClue);
            problem[(Y(0), X(3))] = Clue::Right(0);

            let mut field = Field::new(problem);
            field.check_all_cell();

            assert_eq!(field.inconsistent(), false);
            assert_eq!(field.get_cell((Y(0), X(4))), Cell::Line);
            assert_eq!(field.get_cell((Y(0), X(5))), Cell::Line);
            assert_eq!(field.get_cell((Y(0), X(6))), Cell::Line);
            assert_eq!(field.get_edge((Y(1), X(8))), Edge::Line);
        }
        {
            // 2 block cells in 3 consecutive cells
            let mut problem = Grid::new(5, 5, Clue::NoClue);
            problem[(Y(2), X(1))] = Clue::Right(2);

            let mut field = Field::new(problem);
            field.check_all_cell();

            assert_eq!(field.inconsistent(), false);
            assert_eq!(field.fully_solved(), true);
            assert_eq!(field.get_cell((Y(2), X(2))), Cell::Blocked);
            assert_eq!(field.get_cell((Y(2), X(4))), Cell::Blocked);
            assert_eq!(field.get_edge((Y(3), X(6))), Edge::Line);
            assert_eq!(field.get_edge((Y(5), X(6))), Edge::Line);
            assert_eq!(field.get_edge((Y(2), X(3))), Edge::Line);
            assert_eq!(field.get_edge((Y(3), X(0))), Edge::Line);
        }
    }
}
<commit_msg>Yajilin: reflect GridLoop status in cell status<commit_after>use super::super::{Coord, Grid, X, Y};
use super::*;
use grid_loop::{Edge, GridLoop, GridLoopField};
use std::cmp;

#[derive(Clone)]
pub struct Field {
    grid_loop: GridLoop,
    clue: Grid<Clue>,
    cell: Grid<Cell>,
}

const FOUR_NEIGHBORS: [(i32, i32); 4] = [(-1, 0), (0, -1), (1, 0), (0, 1)];

impl Field {
    pub fn new(clue: &Grid<Clue>) -> Field {
        let height = clue.height();
        let width = clue.width();

        let mut cell = Grid::new(height, width, Cell::Undecided);
        let mut grid_loop = GridLoop::new(height - 1, width - 1);

        {
            let mut handle = GridLoop::get_handle(&mut grid_loop);
            for y in 0..height {
                for x in 0..width {
                    let c = clue[(Y(y), X(x))];
                    if c != Clue::NoClue {
                        cell[(Y(y), X(x))] = Cell::Clue;
                        GridLoop::decide_edge(&mut *handle, (Y(y * 2 - 1), X(x * 2)), Edge::Blank);
                        GridLoop::decide_edge(&mut *handle, (Y(y * 2 + 1), X(x * 2)), Edge::Blank);
                        GridLoop::decide_edge(&mut *handle, (Y(y * 2), X(x * 2 - 1)), Edge::Blank);
                        GridLoop::decide_edge(&mut *handle, (Y(y * 2), X(x * 2 + 1)), Edge::Blank);
                    }
                }
            }
        }
        Field {
            grid_loop,
            clue: clue.clone(),
            cell,
        }
    }
    pub fn height(&self) -> i32 {
        self.clue.height()
    }
    pub fn width(&self) -> i32 {
        self.clue.width()
    }
    pub fn inconsistent(&self) -> bool {
        self.grid_loop.inconsistent()
    }
    pub fn set_inconsistent(&mut self) {
        self.grid_loop.set_inconsistent()
    }
    pub fn fully_solved(&self) -> bool {
        self.grid_loop.fully_solved()
    }
    pub fn get_cell(&self, cd: Coord) -> Cell {
        self.cell[cd]
    }
    pub fn get_cell_safe(&self, cd: Coord) -> Cell {
        if self.cell.is_valid_coord(cd) {
            self.cell[cd]
        } else {
            // The outside of the field can be identified with a (meaningless) clue
            Cell::Clue
        }
    }
    pub fn get_edge(&self, cd: Coord) -> Edge {
        self.grid_loop.get_edge(cd)
    }
    pub fn get_edge_safe(&self, cd: Coord) -> Edge {
        self.grid_loop.get_edge_safe(cd)
    }

    pub fn set_cell(&mut self, cd: Coord, v: Cell) {
        let mut handle = GridLoop::get_handle(self);
        handle.set_cell_internal(cd, v);
    }
    pub fn check_all_cell(&mut self) {
        let height = self.height();
        let width = self.width();
        let mut handle = GridLoop::get_handle(self);
        for y in 0..height {
            for x in 0..width {
                GridLoop::check(&mut *handle, (Y(y * 2), X(x * 2)));
            }
        }
    }

    fn set_cell_internal(&mut self, cd: Coord, v: Cell) {
        let current = self.cell[cd];
        if current != Cell::Undecided {
            if current != v {
                self.set_inconsistent();
            }
            return;
        }

        self.cell[cd] = v;
        let (Y(y), X(x)) = cd;
        match v {
            Cell::Undecided => (),
            Cell::Clue => (), // don't do this!
            Cell::Line => GridLoop::check(self, (Y(y * 2), X(x * 2))),
            Cell::Blocked => for &(dy, dx) in &FOUR_NEIGHBORS {
                if self.get_cell_safe((Y(y + dy), X(x + dx))) != Cell::Clue {
                    self.set_cell_internal((Y(y + dy), X(x + dx)), Cell::Line);
                }
                GridLoop::decide_edge(self, (Y(y * 2 + dy), X(x * 2 + dx)), Edge::Blank);
            },
        }
    }
    fn inspect_clue(&mut self, cell_cd: Coord) {
        let (Y(y), X(x)) = cell_cd;
        let clue = self.clue[cell_cd];
        let (dy, dx, mut n) = match clue {
            Clue::NoClue | Clue::Empty => return,
            Clue::Up(n) => (-1, 0, n),
            Clue::Left(n) => (0, -1, n),
            Clue::Right(n) => (0, 1, n),
            Clue::Down(n) => (1, 0, n),
        };
        let mut involving_cells = 0;
        {
            let mut y = y + dy;
            let mut x = x + dx;
            while self.clue.is_valid_coord((Y(y), X(x))) {
                let c = self.clue[(Y(y), X(x))];
                if c.same_shape(clue) {
                    n -= c.clue_number();
                    break;
                }
                y += dy;
                x += dx;
                involving_cells += 1;
            }
        }
        let mut dp_left = vec![(0, 0); (involving_cells + 1) as usize];
        let mut dp_right = vec![(0, 0); (involving_cells + 1) as usize];

        for i in 0..involving_cells {
            let c = self.get_cell((Y(y + dy * (i + 1)), X(x + dx * (i + 1))));
            dp_left[(i + 1) as usize] = match c {
                Cell::Undecided => {
                    let (lo, hi) = dp_left[cmp::max(0, i - 1) as usize];
                    (lo, hi + 1)
                }
                Cell::Clue | Cell::Line => dp_left[i as usize],
                Cell::Blocked => {
                    let (lo, hi) = dp_left[cmp::max(0, i - 1) as usize];
                    (lo + 1, hi + 1)
                }
            };
        }
        for i in 0..involving_cells {
            let i = involving_cells - 1 - i;
            let c = self.get_cell((Y(y + dy * (i + 1)), X(x + dx * (i + 1))));
            dp_right[i as usize] = match c {
                Cell::Undecided => {
                    let (lo, hi) = dp_right[cmp::min(involving_cells, i + 2) as usize];
                    (lo, hi + 1)
                }
                Cell::Clue | Cell::Line => dp_right[(i + 1) as usize],
                Cell::Blocked => {
                    let (lo, hi) = dp_right[cmp::min(involving_cells, i + 2) as usize];
                    (lo + 1, hi + 1)
                }
            };
        }
        for i in 0..involving_cells {
            let (left_lo, left_hi) = dp_left[i as usize];
            let (right_lo, right_hi) = dp_right[(i + 1) as usize];

            if left_hi + right_hi < n - 1 {
                self.set_inconsistent();
                return;
            } else if left_hi + right_hi == n - 1 {
                self.set_cell_internal((Y(y + dy * (i + 1)), X(x + dx * (i + 1))), Cell::Blocked);
            }

            if left_lo + right_lo > n {
                self.set_inconsistent();
                return;
            } else if left_lo + right_lo == n {
                self.set_cell_internal((Y(y + dy * (i + 1)), X(x + dx * (i + 1))), Cell::Line);
            }
        }
    }
}

impl GridLoopField for Field {
    fn grid_loop(&mut self) -> &mut GridLoop {
        &mut self.grid_loop
    }
    fn check_neighborhood(&mut self, (Y(y), X(x)): Coord) {
        if y % 2 == 0 {
            GridLoop::check(self, (Y(y), X(x - 1)));
            GridLoop::check(self, (Y(y), X(x + 1)));
        } else {
            GridLoop::check(self, (Y(y - 1), X(x)));
            GridLoop::check(self, (Y(y + 1), X(x)));
        }
    }
    fn inspect(&mut self, cd: Coord) {
        let (Y(y), X(x)) = cd;
        if !(y % 2 == 0 && x % 2 == 0) {
            return;
        }
        let cell = self.get_cell((Y(y / 2), X(x / 2)));
        if cell == Cell::Line || cell == Cell::Undecided {
            let (n_line, n_undecided) = self.grid_loop.neighbor_summary(cd);

            if cell == Cell::Line {
                if n_line + n_undecided <= 1 {
                    self.set_inconsistent();
                    return;
                } else if n_line + n_undecided <= 2 {
                    for &(dy, dx) in &FOUR_NEIGHBORS {
                        if self.get_edge_safe((Y(y + dy), X(x + dx))) != Edge::Blank {
                            GridLoop::decide_edge(self, (Y(y + dy), X(x + dx)), Edge::Line);
                        }
                    }
                }
            } else {
                if n_line == 0 && n_undecided == 2 {
                    for &(dy, dx) in &FOUR_NEIGHBORS {
                        if self.get_edge_safe((Y(y + dy), X(x + dx))) == Edge::Undecided {
                            self.set_cell_internal((Y(y / 2 + dy), X(x / 2 + dx)), Cell::Line);
                        }
                    }
                }
            }

            if cell == Cell::Undecided {
                if n_line >= 1 {
                    self.set_cell_internal((Y(y / 2), X(x / 2)), Cell::Line);
                }
                if n_line == 0 && n_undecided <= 1 {
                    self.set_cell_internal((Y(y / 2), X(x / 2)), Cell::Blocked);
                }
            }
        } else if cell == Cell::Clue {
            self.inspect_clue((Y(y / 2), X(x / 2)));
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_yajilin_clue() {
        {
            // Loop must not pass through clue cells
            let mut problem = Grid::new(5, 5, Clue::NoClue);
            problem[(Y(0), X(0))] = Clue::Right(1);

            let mut field = Field::new(&problem);
            field.check_all_cell();

            assert_eq!(field.inconsistent(), false);
            assert_eq!(field.get_edge((Y(0), X(1))), Edge::Blank);
            assert_eq!(field.get_edge((Y(1), X(0))), Edge::Blank);
        }
        {
            // 0 block cells
            let mut problem = Grid::new(5, 7, Clue::NoClue);
            problem[(Y(0), X(3))] = Clue::Right(0);

            let mut field = Field::new(&problem);
            field.check_all_cell();

            assert_eq!(field.inconsistent(), false);
            assert_eq!(field.get_cell((Y(0), X(4))), Cell::Line);
            assert_eq!(field.get_cell((Y(0), X(5))), Cell::Line);
            assert_eq!(field.get_cell((Y(0), X(6))), Cell::Line);
            assert_eq!(field.get_edge((Y(1), X(8))), Edge::Line);
        }
        {
            // 2 block cells in 3 consecutive cells
            let mut problem = Grid::new(5, 5, Clue::NoClue);
            problem[(Y(2), X(1))] = Clue::Right(2);

            let mut field = Field::new(&problem);
            field.check_all_cell();

            assert_eq!(field.inconsistent(), false);
            assert_eq!(field.fully_solved(), true);
            assert_eq!(field.get_cell((Y(2), X(2))), Cell::Blocked);
            assert_eq!(field.get_cell((Y(2), X(4))), Cell::Blocked);
            assert_eq!(field.get_cell((Y(2), X(0))), Cell::Line);
            assert_eq!(field.get_edge((Y(3), X(6))), Edge::Line);
            assert_eq!(field.get_edge((Y(5), X(6))), Edge::Line);
            assert_eq!(field.get_edge((Y(2), X(3))), Edge::Line);
            assert_eq!(field.get_edge((Y(3), X(0))), Edge::Line);
        }
        {
            // Cells which the loop does not pass through must be blocked (or have a clue)
            let mut problem = Grid::new(6, 6, Clue::NoClue);
            problem[(Y(2), X(4))] = Clue::Up(1);
            problem[(Y(4), X(4))] = Clue::Left(1);

            let mut field = Field::new(&problem);
            field.check_all_cell();

            assert_eq!(field.inconsistent(), false);
            assert_eq!(field.get_cell((Y(1), X(4))), Cell::Blocked);
            assert_eq!(field.get_cell((Y(3), X(4))), Cell::Blocked);
        }
        {
            // Clues to the same direction
            let mut problem = Grid::new(6, 6, Clue::NoClue);
            problem[(Y(2), X(0))] = Clue::Right(2);
            problem[(Y(2), X(2))] = Clue::Right(1);

            let mut field = Field::new(&problem);
            field.check_all_cell();

            assert_eq!(field.inconsistent(), false);
            assert_eq!(field.get_cell((Y(2), X(1))), Cell::Blocked);
        }
    }
}
<|endoftext|>


<commit_before>extern crate find_folder;

use screen::*;
use piston_window;
use conrod::{self, Widget, Frameable, Positionable};
use conrod::color::Colorable;

pub struct MainMenuScreen {
    ui: conrod::Ui<piston_window::Glyphs>,
}

impl MainMenuScreen {
    pub fn new(window: &piston_window::PistonWindow) -> MainMenuScreen {
        MainMenuScreen { ui: create_ui(&window) }
    }
}

impl Screen for MainMenuScreen {
    fn on_input(&mut self, input: &piston_window::Input, window: &piston_window::PistonWindow) -> InputResults {
        use piston_window::{Input, Button, MouseButton};

        let mut result = Vec::new();

        match input {
            &Input::Press(Button::Mouse(MouseButton::Left)) => {
                result.push(InputResult::PopScreen);
                result.push(InputResult::PushScreen(Box::new(BattleScreen::new(&window))));
            }
            _ => {}
        }

        result
    }

    fn on_draw(&mut self, args: &piston_window::RenderArgs, window: &piston_window::PistonWindow) {
        self.ui.handle_event(window);
        window.draw_2d(|context, graphics| self.ui.draw(context, graphics));
    }

    fn on_update(&mut self, args: &piston_window::UpdateArgs) {
        self.ui.set_widgets(|ui| {
            conrod::Canvas::new()
                .frame(200.)
                .pad(30.0)
                .color(conrod::color::rgb(0.2, 0.35, 0.45))
                .scroll_kids()
                .set(CANVAS, ui);

            conrod::Text::new("Widget Demonstration")
                .top_left_with_margins_on(CANVAS, 0.0, 350.0)
                .font_size(32)
                .color(conrod::color::rgb(0.2, 0.35, 0.45).plain_contrast())
                .set(TITLE, ui);
        });
    }
}

widget_ids! {
    CANVAS,
    TITLE,
}

fn create_ui(window: &piston_window::PistonWindow) -> conrod::Ui<piston_window::Glyphs> {
    let assets = find_folder::Search::KidsThenParents(3, 5).for_folder("assets").unwrap();
    let font_path = assets.join("NotoSans-Regular.ttf");
    let theme = conrod::Theme::default();
    let glyph_cache = piston_window::Glyphs::new(&font_path, window.factory.borrow().clone());
    conrod::Ui::new(glyph_cache.unwrap(), theme)
}
<commit_msg>draw_if_changed instead of simple draw<commit_after>extern crate find_folder;

use screen::*;
use piston_window;
use conrod::{self, Widget, Frameable, Positionable};
use conrod::color::Colorable;

pub struct MainMenuScreen {
    ui: conrod::Ui<piston_window::Glyphs>,
}

impl MainMenuScreen {
    pub fn new(window: &piston_window::PistonWindow) -> MainMenuScreen {
        MainMenuScreen { ui: create_ui(&window) }
    }
}

impl Screen for MainMenuScreen {
    fn on_input(&mut self, input: &piston_window::Input, window: &piston_window::PistonWindow) -> InputResults {
        use piston_window::{Input, Button, MouseButton};

        let mut result = Vec::new();

        match input {
            &Input::Press(Button::Mouse(MouseButton::Left)) => {
                result.push(InputResult::PopScreen);
                result.push(InputResult::PushScreen(Box::new(BattleScreen::new(&window))));
            }
            _ => {}
        }

        result
    }

    fn on_draw(&mut self, args: &piston_window::RenderArgs, window: &piston_window::PistonWindow) {
        self.ui.handle_event(window);
        window.draw_2d(|context, graphics| self.ui.draw_if_changed(context, graphics));
    }

    fn on_update(&mut self, args: &piston_window::UpdateArgs) {
        self.ui.set_widgets(|ui| {
            conrod::Canvas::new()
                .frame(200.)
                .pad(30.0)
                .color(conrod::color::rgb(0.2, 0.35, 0.45))
                .scroll_kids()
                .set(CANVAS, ui);

            conrod::Text::new("Widget Demonstration")
                .top_left_with_margins_on(CANVAS, 0.0, 350.0)
                .font_size(32)
                .color(conrod::color::rgb(0.2, 0.35, 0.45).plain_contrast())
                .set(TITLE, ui);
        });
    }
}

widget_ids! {
    CANVAS,
    TITLE,
}

fn create_ui(window: &piston_window::PistonWindow) -> conrod::Ui<piston_window::Glyphs> {
    let assets = find_folder::Search::KidsThenParents(3, 5).for_folder("assets").unwrap();
    let font_path = assets.join("NotoSans-Regular.ttf");
    let theme = conrod::Theme::default();
    let glyph_cache = piston_window::Glyphs::new(&font_path, window.factory.borrow().clone());
    conrod::Ui::new(glyph_cache.unwrap(), theme)
}
<|endoftext|>