<commit_before>// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.

// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.

//! jsonrpc server over unix sockets
//!
//! ```no_run
//! extern crate jsonrpc_core;
//! extern crate json_ipc_server;
//! extern crate rand;
//!
//! use std::sync::Arc;
//! use jsonrpc_core::*;
//! use json_ipc_server::Server;
//!
//! struct SayHello;
//! impl MethodCommand for SayHello {
//! 	fn execute(&self, _params: Params) -> Result<Value, Error> {
//! 		Ok(Value::String("hello".to_string()))
//! 	}
//! }
//!
//! fn main() {
//! 	let io = IoHandler::new();
//! 	io.add_method("say_hello", SayHello);
//! 	let server = Server::new("/tmp/json-ipc-test.ipc", &Arc::new(io)).unwrap();
//!     ::std::thread::spawn(move || server.run());
//! }
//! ```

use mio::*;
use mio::unix::*;
use bytes::{Buf, ByteBuf, MutByteBuf};
use std::io;
use jsonrpc_core::IoHandler;
use std::sync::*;
use std::sync::atomic::*;
use std;
use slab;
use validator;
#[cfg(test)]
use tests;
use std::collections::VecDeque;

const SERVER: Token = Token(0);
const MAX_CONCURRENT_CONNECTIONS: usize = 16;
const MAX_WRITE_LENGTH: usize = 8192;

struct SocketConnection {
    socket: UnixStream,
    buf: Option<ByteBuf>,
    mut_buf: Option<MutByteBuf>,
    token: Option<Token>,
    interest: EventSet,
}

type Slab<T> = slab::Slab<T, Token>;

impl SocketConnection {
    fn new(sock: UnixStream) -> Self {
        SocketConnection {
            socket: sock,
            buf: None,
            mut_buf: Some(ByteBuf::mut_with_capacity(4096)),
            token: None,
            interest: EventSet::hup(),
        }
    }

    fn writable(&mut self, event_loop: &mut EventLoop<RpcServer>, _handler: &IoHandler) -> io::Result<()> {
        use std::io::Write;
        if let Some(buf) = self.buf.take() {
			if buf.remaining() < MAX_WRITE_LENGTH {
	            try!(self.socket.write_all(&buf.bytes()));
				self.interest.remove(EventSet::writable());
				self.interest.insert(EventSet::readable());
			}
			else {
				try!(self.socket.write_all(&buf.bytes()[0..MAX_WRITE_LENGTH]));
				self.buf = Some(ByteBuf::from_slice(&buf.bytes()[MAX_WRITE_LENGTH..]));
			}
        }

        event_loop.reregister(&self.socket, self.token.unwrap(), self.interest, PollOpt::edge() | PollOpt::oneshot())
    }

    fn readable(&mut self, event_loop: &mut EventLoop<RpcServer>, handler: &IoHandler) -> io::Result<()> {
        let mut buf = self.mut_buf.take().unwrap_or_else(|| panic!("unwrapping mutable buffer which is None"));

        match self.socket.try_read_buf(&mut buf) {
            Ok(None) => {
				trace!(target: "ipc", "Empty read ({:?})", self.token);
                self.mut_buf = Some(buf);
				//return Ok(());
            }
            Ok(Some(_)) => {
                let (requests, last_index) = validator::extract_requests(buf.bytes());
                if requests.len() > 0 {
                    let mut response_bytes = Vec::new();
                    for rpc_msg in requests {
                        trace!(target: "ipc", "Request: {}", rpc_msg);
                        let response: Option<String> = handler.handle_request(&rpc_msg);
                        if let Some(response_str) = response {
                            trace!(target: "ipc", "Response: {}", &response_str);
                            response_bytes.extend(response_str.into_bytes());
                        }
                    }
                    self.buf = Some(ByteBuf::from_slice(&response_bytes[..]));

                    let mut new_buf = ByteBuf::mut_with_capacity(4096);
                    new_buf.write_slice(&buf.bytes()[last_index+1..]);
                    self.mut_buf = Some(new_buf);

                    self.interest.remove(EventSet::readable());
                    self.interest.insert(EventSet::writable());
                }
                else {
                    self.mut_buf = Some(buf);
                }
            }
            Err(e) => {
                trace!(target: "ipc", "Error receiving data ({:?}): {:?}", self.token, e);
                self.interest.remove(EventSet::readable());
            }

        };
        event_loop.reregister(&self.socket, self.token.unwrap(), self.interest, PollOpt::edge() | PollOpt::oneshot())
    }
}

struct RpcServer {
    socket: UnixListener,
    connections: Slab<SocketConnection>,
    io_handler: Arc<IoHandler>,
	tokens: VecDeque<Token>,
}

pub struct Server {
    rpc_server: Arc<RwLock<RpcServer>>,
    event_loop: Arc<RwLock<EventLoop<RpcServer>>>,
    is_stopping: Arc<AtomicBool>,
    is_stopped: Arc<AtomicBool>,
    addr: String,
}

#[derive(Debug)]
pub enum Error {
    Io(std::io::Error),
    NotStarted,
    AlreadyStopping,
    NotStopped,
    IsStopping,
}

impl std::convert::From<std::io::Error> for Error {
    fn from(io_error: std::io::Error) -> Error {
        Error::Io(io_error)
    }
}

impl Server {
    /// New server
    pub fn new(socket_addr: &str, io_handler: &Arc<IoHandler>) -> Result<Server, Error> {
        let (server, event_loop) = try!(RpcServer::start(socket_addr, io_handler));
        Ok(Server {
            rpc_server: Arc::new(RwLock::new(server)),
            event_loop: Arc::new(RwLock::new(event_loop)),
            is_stopping: Arc::new(AtomicBool::new(false)),
            is_stopped: Arc::new(AtomicBool::new(true)),
            addr: socket_addr.to_owned(),
        })
    }

    /// Run server (in current thread)
    pub fn run(&self) {
        let mut event_loop = self.event_loop.write().unwrap();
        let mut server = self.rpc_server.write().unwrap();
        event_loop.run(&mut server).unwrap();
    }

    /// Poll server requests (for manual async scenarios)
    pub fn poll(&self) {
        let mut event_loop = self.event_loop.write().unwrap();
        let mut server = self.rpc_server.write().unwrap();

        event_loop.run_once(&mut server, Some(100)).unwrap();
    }

    /// Run server (in separate thread)
    pub fn run_async(&self) -> Result<(), Error> {
        if self.is_stopping.load(Ordering::Relaxed) { return Err(Error::IsStopping) }
        if !self.is_stopped.load(Ordering::Relaxed) { return Err(Error::NotStopped) }

        self.is_stopped.store(false, Ordering::Relaxed);

        let event_loop = self.event_loop.clone();
        let server = self.rpc_server.clone();
        let thread_stopping = self.is_stopping.clone();
        let thread_stopped = self.is_stopped.clone();
        std::thread::spawn(move || {
            let mut event_loop = event_loop.write().unwrap();
            let mut server = server.write().unwrap();
            while !thread_stopping.load(Ordering::Relaxed) {
                event_loop.run_once(&mut server, Some(100)).unwrap();
            }
            thread_stopped.store(true, Ordering::Relaxed);
        });
        Ok(())
    }

    pub fn stop_async(&self) -> Result<(), Error> {
        if self.is_stopped.load(Ordering::Relaxed) { return Err(Error::NotStarted) }
        if self.is_stopping.load(Ordering::Relaxed) { return Err(Error::AlreadyStopping)}
        self.is_stopping.store(true, Ordering::Relaxed);
        Ok(())
    }

    pub fn stop(&self) -> Result<(), Error> {
        if self.is_stopped.load(Ordering::Relaxed) { return Err(Error::NotStarted) }
        if self.is_stopping.load(Ordering::Relaxed) { return Err(Error::AlreadyStopping)}
        self.is_stopping.store(true, Ordering::Relaxed);
        while !self.is_stopped.load(Ordering::Relaxed) { std::thread::sleep(std::time::Duration::new(0, 10)); }
        Ok(())
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        self.stop().unwrap_or_else(|_| {}); // ignore error - can be stopped already
        ::std::fs::remove_file(&self.addr).unwrap_or_else(|_| {}); // ignoer error - server could have never been started
    }
}

impl RpcServer {

    /// start ipc rpc server (blocking)
    pub fn start(addr: &str, io_handler: &Arc<IoHandler>) -> Result<(RpcServer, EventLoop<RpcServer>), Error> {
        let mut event_loop = try!(EventLoop::new());
        ::std::fs::remove_file(addr).unwrap_or_else(|_| {} ); // ignore error (if no file)
        let socket = try!(UnixListener::bind(&addr));
        event_loop.register(&socket, SERVER, EventSet::readable(), PollOpt::edge()).unwrap();
        let server = RpcServer {
            socket: socket,
            connections: Slab::new_starting_at(Token(1), MAX_CONCURRENT_CONNECTIONS),
            io_handler: io_handler.clone(),
			tokens: VecDeque::new(),
        };
        Ok((server, event_loop))
    }

    fn accept(&mut self, event_loop: &mut EventLoop<RpcServer>) -> io::Result<()> {
        let new_client_socket = self.socket.accept().unwrap().unwrap();
        let connection = SocketConnection::new(new_client_socket);
        if self.connections.count() >= MAX_CONCURRENT_CONNECTIONS {
            // max connections
            return Ok(());
        }
        let token = self.connections.insert(connection).ok().expect("fatal: Could not add connection to slab (memory issue?)");
		self.tokens.push_back(token);

		trace!(target: "ipc", "Accepted connection with token {:?}", token);

        self.connections[token].token = Some(token);
        event_loop.register(
            &self.connections[token].socket,
            token,
            EventSet::readable(),
            PollOpt::edge() | PollOpt::oneshot()
        ).ok().expect("fatal: could not register socket with event loop (memory issue?)");

        Ok(())
    }

    fn connection_readable(&mut self, event_loop: &mut EventLoop<RpcServer>, tok: Token) -> io::Result<()> {
        let io_handler = self.io_handler.clone();
        self.connection(tok).readable(event_loop, &io_handler)
    }

    fn connection_writable(&mut self, event_loop: &mut EventLoop<RpcServer>, tok: Token) -> io::Result<()> {
        let io_handler = self.io_handler.clone();
        self.connection(tok).writable(event_loop, &io_handler)
    }

    fn connection<'a>(&'a mut self, tok: Token) -> &'a mut SocketConnection {
        &mut self.connections[tok]
    }

    fn drop_connection(&mut self, tok: Token) {
        trace!(target: "ipc", "Dropping connection {:?}", tok);
        self.connections.remove(tok);
    }
}

impl Handler for RpcServer {
    type Timeout = usize;
    type Message = ();

    fn ready(&mut self, event_loop: &mut EventLoop<RpcServer>, token: Token, events: EventSet) {
        if events.is_readable() {
            match token {
                SERVER => self.accept(event_loop).unwrap(),
                _ => self.connection_readable(event_loop, token).unwrap()
            };
        }

        if events.is_hup() {
            match token {
                SERVER => { trace!(target: "ipc", "Server hup"); },
                other_token => {
                    self.drop_connection(other_token)
                }
            }
        }

        if events.is_writable() {
            match token {
                SERVER => { },
                _ => self.connection_writable(event_loop, token).unwrap_or_else(|_| {}), // todo: disqualify connection from list on error
            };
        }
    }
}

#[test]
pub fn test_reqrep_poll() {
    let addr = tests::random_ipc_endpoint();
    let io = tests::dummy_io_handler();
    let server = Server::new(&addr, &io).unwrap();
    std::thread::spawn(move || {
        loop {
            server.poll();
        }
    });

    let request = r#"{"jsonrpc": "2.0", "method": "say_hello", "params": [42, 23], "id": 1}"#;
    let response = r#"{"jsonrpc":"2.0","result":"hello 42! you sent 23","id":1}"#;
    assert_eq!(String::from_utf8(tests::dummy_request(&addr, request.as_bytes())).unwrap(), response.to_string());

    std::thread::sleep(std::time::Duration::from_millis(500));
}

#[test]
pub fn test_file_removed() {
    let addr = tests::random_ipc_endpoint();
    let io = tests::dummy_io_handler();
    {
        let server = Server::new(&addr, &io).unwrap();
        server.run_async().unwrap();
        std::thread::sleep(std::time::Duration::from_millis(50));

        let request = r#"{"jsonrpc": "2.0", "method": "say_hello", "params": [42, 23], "id": 1}"#;
        let response = r#"{"jsonrpc":"2.0","result":"hello 42! you sent 23","id":1}"#;
        assert_eq!(String::from_utf8(tests::dummy_request(&addr, request.as_bytes())).unwrap(), response.to_string());
    }
    assert!(::std::fs::metadata(addr).is_err()); // err is file not exists
}
<commit_msg>max connections increase<commit_after>// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.

// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.

//! jsonrpc server over unix sockets
//!
//! ```no_run
//! extern crate jsonrpc_core;
//! extern crate json_ipc_server;
//! extern crate rand;
//!
//! use std::sync::Arc;
//! use jsonrpc_core::*;
//! use json_ipc_server::Server;
//!
//! struct SayHello;
//! impl MethodCommand for SayHello {
//! 	fn execute(&self, _params: Params) -> Result<Value, Error> {
//! 		Ok(Value::String("hello".to_string()))
//! 	}
//! }
//!
//! fn main() {
//! 	let io = IoHandler::new();
//! 	io.add_method("say_hello", SayHello);
//! 	let server = Server::new("/tmp/json-ipc-test.ipc", &Arc::new(io)).unwrap();
//!     ::std::thread::spawn(move || server.run());
//! }
//! ```

use mio::*;
use mio::unix::*;
use bytes::{Buf, ByteBuf, MutByteBuf};
use std::io;
use jsonrpc_core::IoHandler;
use std::sync::*;
use std::sync::atomic::*;
use std;
use slab;
use validator;
#[cfg(test)]
use tests;
use std::collections::VecDeque;

const SERVER: Token = Token(0);
const MAX_CONCURRENT_CONNECTIONS: usize = 1024;
const MAX_WRITE_LENGTH: usize = 8192;

struct SocketConnection {
    socket: UnixStream,
    buf: Option<ByteBuf>,
    mut_buf: Option<MutByteBuf>,
    token: Option<Token>,
    interest: EventSet,
}

type Slab<T> = slab::Slab<T, Token>;

impl SocketConnection {
    fn new(sock: UnixStream) -> Self {
        SocketConnection {
            socket: sock,
            buf: None,
            mut_buf: Some(ByteBuf::mut_with_capacity(4096)),
            token: None,
            interest: EventSet::hup(),
        }
    }

    fn writable(&mut self, event_loop: &mut EventLoop<RpcServer>, _handler: &IoHandler) -> io::Result<()> {
        use std::io::Write;
        if let Some(buf) = self.buf.take() {
			if buf.remaining() < MAX_WRITE_LENGTH {
	            try!(self.socket.write_all(&buf.bytes()));
				self.interest.remove(EventSet::writable());
				self.interest.insert(EventSet::readable());
			}
			else {
				try!(self.socket.write_all(&buf.bytes()[0..MAX_WRITE_LENGTH]));
				self.buf = Some(ByteBuf::from_slice(&buf.bytes()[MAX_WRITE_LENGTH..]));
			}
        }

        event_loop.reregister(&self.socket, self.token.unwrap(), self.interest, PollOpt::edge() | PollOpt::oneshot())
    }

    fn readable(&mut self, event_loop: &mut EventLoop<RpcServer>, handler: &IoHandler) -> io::Result<()> {
        let mut buf = self.mut_buf.take().unwrap_or_else(|| panic!("unwrapping mutable buffer which is None"));

        match self.socket.try_read_buf(&mut buf) {
            Ok(None) => {
				trace!(target: "ipc", "Empty read ({:?})", self.token);
                self.mut_buf = Some(buf);
				//return Ok(());
            }
            Ok(Some(_)) => {
                let (requests, last_index) = validator::extract_requests(buf.bytes());
                if requests.len() > 0 {
                    let mut response_bytes = Vec::new();
                    for rpc_msg in requests {
                        trace!(target: "ipc", "Request: {}", rpc_msg);
                        let response: Option<String> = handler.handle_request(&rpc_msg);
                        if let Some(response_str) = response {
                            trace!(target: "ipc", "Response: {}", &response_str);
                            response_bytes.extend(response_str.into_bytes());
                        }
                    }
                    self.buf = Some(ByteBuf::from_slice(&response_bytes[..]));

                    let mut new_buf = ByteBuf::mut_with_capacity(4096);
                    new_buf.write_slice(&buf.bytes()[last_index+1..]);
                    self.mut_buf = Some(new_buf);

                    self.interest.remove(EventSet::readable());
                    self.interest.insert(EventSet::writable());
                }
                else {
                    self.mut_buf = Some(buf);
                }
            }
            Err(e) => {
                trace!(target: "ipc", "Error receiving data ({:?}): {:?}", self.token, e);
                self.interest.remove(EventSet::readable());
            }

        };
        event_loop.reregister(&self.socket, self.token.unwrap(), self.interest, PollOpt::edge() | PollOpt::oneshot())
    }
}

struct RpcServer {
    socket: UnixListener,
    connections: Slab<SocketConnection>,
    io_handler: Arc<IoHandler>,
	tokens: VecDeque<Token>,
}

pub struct Server {
    rpc_server: Arc<RwLock<RpcServer>>,
    event_loop: Arc<RwLock<EventLoop<RpcServer>>>,
    is_stopping: Arc<AtomicBool>,
    is_stopped: Arc<AtomicBool>,
    addr: String,
}

#[derive(Debug)]
pub enum Error {
    Io(std::io::Error),
    NotStarted,
    AlreadyStopping,
    NotStopped,
    IsStopping,
}

impl std::convert::From<std::io::Error> for Error {
    fn from(io_error: std::io::Error) -> Error {
        Error::Io(io_error)
    }
}

impl Server {
    /// New server
    pub fn new(socket_addr: &str, io_handler: &Arc<IoHandler>) -> Result<Server, Error> {
        let (server, event_loop) = try!(RpcServer::start(socket_addr, io_handler));
        Ok(Server {
            rpc_server: Arc::new(RwLock::new(server)),
            event_loop: Arc::new(RwLock::new(event_loop)),
            is_stopping: Arc::new(AtomicBool::new(false)),
            is_stopped: Arc::new(AtomicBool::new(true)),
            addr: socket_addr.to_owned(),
        })
    }

    /// Run server (in current thread)
    pub fn run(&self) {
        let mut event_loop = self.event_loop.write().unwrap();
        let mut server = self.rpc_server.write().unwrap();
        event_loop.run(&mut server).unwrap();
    }

    /// Poll server requests (for manual async scenarios)
    pub fn poll(&self) {
        let mut event_loop = self.event_loop.write().unwrap();
        let mut server = self.rpc_server.write().unwrap();

        event_loop.run_once(&mut server, Some(100)).unwrap();
    }

    /// Run server (in separate thread)
    pub fn run_async(&self) -> Result<(), Error> {
        if self.is_stopping.load(Ordering::Relaxed) { return Err(Error::IsStopping) }
        if !self.is_stopped.load(Ordering::Relaxed) { return Err(Error::NotStopped) }

        self.is_stopped.store(false, Ordering::Relaxed);

        let event_loop = self.event_loop.clone();
        let server = self.rpc_server.clone();
        let thread_stopping = self.is_stopping.clone();
        let thread_stopped = self.is_stopped.clone();
        std::thread::spawn(move || {
            let mut event_loop = event_loop.write().unwrap();
            let mut server = server.write().unwrap();
            while !thread_stopping.load(Ordering::Relaxed) {
                event_loop.run_once(&mut server, Some(100)).unwrap();
            }
            thread_stopped.store(true, Ordering::Relaxed);
        });
        Ok(())
    }

    pub fn stop_async(&self) -> Result<(), Error> {
        if self.is_stopped.load(Ordering::Relaxed) { return Err(Error::NotStarted) }
        if self.is_stopping.load(Ordering::Relaxed) { return Err(Error::AlreadyStopping)}
        self.is_stopping.store(true, Ordering::Relaxed);
        Ok(())
    }

    pub fn stop(&self) -> Result<(), Error> {
        if self.is_stopped.load(Ordering::Relaxed) { return Err(Error::NotStarted) }
        if self.is_stopping.load(Ordering::Relaxed) { return Err(Error::AlreadyStopping)}
        self.is_stopping.store(true, Ordering::Relaxed);
        while !self.is_stopped.load(Ordering::Relaxed) { std::thread::sleep(std::time::Duration::new(0, 10)); }
        Ok(())
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        self.stop().unwrap_or_else(|_| {}); // ignore error - can be stopped already
        ::std::fs::remove_file(&self.addr).unwrap_or_else(|_| {}); // ignoer error - server could have never been started
    }
}

impl RpcServer {

    /// start ipc rpc server (blocking)
    pub fn start(addr: &str, io_handler: &Arc<IoHandler>) -> Result<(RpcServer, EventLoop<RpcServer>), Error> {
        let mut event_loop = try!(EventLoop::new());
        ::std::fs::remove_file(addr).unwrap_or_else(|_| {} ); // ignore error (if no file)
        let socket = try!(UnixListener::bind(&addr));
        event_loop.register(&socket, SERVER, EventSet::readable(), PollOpt::edge()).unwrap();
        let server = RpcServer {
            socket: socket,
            connections: Slab::new_starting_at(Token(1), MAX_CONCURRENT_CONNECTIONS),
            io_handler: io_handler.clone(),
			tokens: VecDeque::new(),
        };
        Ok((server, event_loop))
    }

    fn accept(&mut self, event_loop: &mut EventLoop<RpcServer>) -> io::Result<()> {
        let new_client_socket = self.socket.accept().unwrap().unwrap();
        let connection = SocketConnection::new(new_client_socket);
        if self.connections.count() >= MAX_CONCURRENT_CONNECTIONS {
            // max connections
            return Ok(());
        }
        let token = self.connections.insert(connection).ok().expect("fatal: Could not add connection to slab (memory issue?)");
		self.tokens.push_back(token);

		trace!(target: "ipc", "Accepted connection with token {:?}", token);

        self.connections[token].token = Some(token);
        event_loop.register(
            &self.connections[token].socket,
            token,
            EventSet::readable(),
            PollOpt::edge() | PollOpt::oneshot()
        ).ok().expect("fatal: could not register socket with event loop (memory issue?)");

        Ok(())
    }

    fn connection_readable(&mut self, event_loop: &mut EventLoop<RpcServer>, tok: Token) -> io::Result<()> {
        let io_handler = self.io_handler.clone();
        self.connection(tok).readable(event_loop, &io_handler)
    }

    fn connection_writable(&mut self, event_loop: &mut EventLoop<RpcServer>, tok: Token) -> io::Result<()> {
        let io_handler = self.io_handler.clone();
        self.connection(tok).writable(event_loop, &io_handler)
    }

    fn connection<'a>(&'a mut self, tok: Token) -> &'a mut SocketConnection {
        &mut self.connections[tok]
    }

    fn drop_connection(&mut self, tok: Token) {
        trace!(target: "ipc", "Dropping connection {:?}", tok);
        self.connections.remove(tok);
    }
}

impl Handler for RpcServer {
    type Timeout = usize;
    type Message = ();

    fn ready(&mut self, event_loop: &mut EventLoop<RpcServer>, token: Token, events: EventSet) {
        if events.is_readable() {
            match token {
                SERVER => self.accept(event_loop).unwrap(),
                _ => self.connection_readable(event_loop, token).unwrap()
            };
        }

        if events.is_hup() {
            match token {
                SERVER => { trace!(target: "ipc", "Server hup"); },
                other_token => {
                    self.drop_connection(other_token)
                }
            }
        }

        if events.is_writable() {
            match token {
                SERVER => { },
                _ => self.connection_writable(event_loop, token).unwrap_or_else(|_| {}), // todo: disqualify connection from list on error
            };
        }
    }
}

#[test]
pub fn test_reqrep_poll() {
    let addr = tests::random_ipc_endpoint();
    let io = tests::dummy_io_handler();
    let server = Server::new(&addr, &io).unwrap();
    std::thread::spawn(move || {
        loop {
            server.poll();
        }
    });

    let request = r#"{"jsonrpc": "2.0", "method": "say_hello", "params": [42, 23], "id": 1}"#;
    let response = r#"{"jsonrpc":"2.0","result":"hello 42! you sent 23","id":1}"#;
    assert_eq!(String::from_utf8(tests::dummy_request(&addr, request.as_bytes())).unwrap(), response.to_string());

    std::thread::sleep(std::time::Duration::from_millis(500));
}

#[test]
pub fn test_file_removed() {
    let addr = tests::random_ipc_endpoint();
    let io = tests::dummy_io_handler();
    {
        let server = Server::new(&addr, &io).unwrap();
        server.run_async().unwrap();
        std::thread::sleep(std::time::Duration::from_millis(50));

        let request = r#"{"jsonrpc": "2.0", "method": "say_hello", "params": [42, 23], "id": 1}"#;
        let response = r#"{"jsonrpc":"2.0","result":"hello 42! you sent 23","id":1}"#;
        assert_eq!(String::from_utf8(tests::dummy_request(&addr, request.as_bytes())).unwrap(), response.to_string());
    }
    assert!(::std::fs::metadata(addr).is_err()); // err is file not exists
}
<|endoftext|>


<commit_before>use std::f64::consts::PI;

/// Calculates the volume of the n-sphere.
pub fn sphere_volume(radius: f64, dim: u64) -> f64 {
    let gamma = if dim % 2 == 0 {
        // This works because dim / 2 is a whole number.
        fact(dim / 2) as f64
    } else {
        // This works because the function is gamma(1/2 + n) where n = dim / 2 + 1
        let n = dim / 2 + 1;
        (fact(2 * n) as f64 / (4u64.pow(n as u32) * fact(n)) as f64) * PI.sqrt()
    };
    (PI.powf(0.5 * dim as f64) * radius.powf(dim as f64)) / gamma
}

#[test]
fn volume_of_1_sphere_works() {
    for radius in (0..1000000).map(|n| n as f64 / 1000.) {
        let expected = PI * radius.powi(2);
        let actual = sphere_volume(radius, 2);
        assert!(equals(expected, actual, 0.0001, 1), "Expected: {}, Actual: {}", expected, actual);
    }
}

#[test]
fn volume_of_2_sphere_works() {
    for radius in (0..1000000).map(|n| n as f64 / 1000.) {
        let expected = (4. / 3.) * PI * radius.powi(3);
        let actual = sphere_volume(radius, 3);
        assert!(equals(expected, actual, 0.0001, 1), "Expected: {}, Actual: {}", expected, actual);
    }
}

#[test]
fn volume_of_3_sphere_works() {
    for radius in (0..1000000).map(|n| n as f64 / 1000.) {
        let expected = (1. / 2.) * PI.powi(2) * radius.powi(4);
        let actual = sphere_volume(radius, 4);
        assert!(equals(expected, actual, 0.0001, 1), "Expected: {}, Actual: {}", expected, actual);
    }
}

#[cfg(test)]
fn equals(a: f64, b: f64, max_diff: f64, max_ulps_diff: i64) -> bool {
    let diff = f64::abs(a - b);
    if diff <= max_diff {
        return true;
    }
    if a.is_sign_positive() && !b.is_sign_positive() {
        return false;
    }
    let a_i64 = unsafe{::std::mem::transmute::<_, i64>(a)};
    let b_i64 = unsafe{::std::mem::transmute::<_, i64>(b)};
    let ulps_diff = i64::abs(a_i64 - b_i64);
    return ulps_diff <= max_ulps_diff;
}

#[inline]
fn fact(n: u64) -> u64 {
    //TODO: This could be made faster with better algorithm, but it's called with low values so it doesn't matter much.
    if n < 2 {
        1
    } else {
        n * fact(n - 1)
    }
}

#[test]
fn factorial_works() {
    assert_eq!(1, fact(0));
    let mut x = 1;
    for n in 1..21 {
        x *= n;
        assert_eq!(x, fact(n));
    }
}
<commit_msg>Changed tests.<commit_after>use std::f64::consts::PI;

/// Calculates the volume of the n-sphere.
pub fn sphere_volume(radius: f64, dim: u64) -> f64 {
    let gamma = if dim % 2 == 0 {
        // This works because dim / 2 is a whole number.
        fact(dim / 2) as f64
    } else {
        // This works because the function is gamma(1/2 + n) where n = dim / 2 + 1
        let n = dim / 2 + 1;
        (fact(2 * n) as f64 / (4u64.pow(n as u32) * fact(n)) as f64) * PI.sqrt()
    };
    (PI.powf(0.5 * dim as f64) * radius.powf(dim as f64)) / gamma
}

#[test]
fn volume_of_1_sphere_works() {
    for radius in (0..1000000).map(|n| n as f64 / 1000.) {
        let expected = PI * radius.powi(2);
        let actual = sphere_volume(radius, 2);
        assert!(equals(expected, actual, 0.0001, 10), "Expected: {}, Actual: {}", expected, actual);
    }
}

#[test]
fn volume_of_2_sphere_works() {
    for radius in (0..1000000).map(|n| n as f64 / 1000.) {
        let expected = (4. / 3.) * PI * radius.powi(3);
        let actual = sphere_volume(radius, 3);
        assert!(equals(expected, actual, 0.0001, 10), "Expected: {}, Actual: {}", expected, actual);
    }
}

#[test]
fn volume_of_3_sphere_works() {
    for radius in (0..1000000).map(|n| n as f64 / 1000.) {
        let expected = (1. / 2.) * PI.powi(2) * radius.powi(4);
        let actual = sphere_volume(radius, 4);
        assert!(equals(expected, actual, 0.0001, 10), "Expected: {}, Actual: {}", expected, actual);
    }
}

#[cfg(test)]
fn equals(a: f64, b: f64, max_diff: f64, max_ulps_diff: i64) -> bool {
    let diff = f64::abs(a - b);
    if diff <= max_diff {
        return true;
    }
    if a.is_sign_positive() && !b.is_sign_positive() {
        return false;
    }
    let a_i64 = unsafe{::std::mem::transmute::<_, i64>(a)};
    let b_i64 = unsafe{::std::mem::transmute::<_, i64>(b)};
    let ulps_diff = i64::abs(a_i64 - b_i64);
    return ulps_diff <= max_ulps_diff;
}

#[inline]
fn fact(n: u64) -> u64 {
    //TODO: This could be made faster with better algorithm, but it's called with low values so it doesn't matter much.
    if n < 2 {
        1
    } else {
        n * fact(n - 1)
    }
}

#[test]
fn factorial_works() {
    assert_eq!(1, fact(0));
    let mut x = 1;
    for n in 1..21 {
        x *= n;
        assert_eq!(x, fact(n));
    }
}
<|endoftext|>


<commit_before>//! CHIP-8 emulator backend.
//! You can develop your own frontends for it.
//!
//! The reference frontend is
//! [crusty-chip-sfml](https://github.com/crumblingstatue/crusty-chip-sfml).
//!
//! The CHIP-8 technical documentation in the comments is copied from
//! http://devernay.free.fr/hacks/chip8/C8TECH10.HTM,
//! Copyright (c) Thomas P. Greene.

#![experimental]

use std::slice::bytes::copy_memory;

mod ops;

const START_ADDR: u16 = 0x200;
const MEM_SIZE: uint = 4096;
pub const DISPLAY_WIDTH: uint = 64;
pub const DISPLAY_HEIGHT: uint = 32;

static FONTSET: [u8, .. 5 * 0x10] = [
    0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
    0x20, 0x60, 0x20, 0x20, 0x70, // 1
    0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
    0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
    0x90, 0x90, 0xF0, 0x10, 0x10, // 4
    0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
    0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
    0xF0, 0x10, 0x20, 0x40, 0x40, // 7
    0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
    0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
    0xF0, 0x90, 0xF0, 0x90, 0x90, // A
    0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
    0xF0, 0x80, 0x80, 0x80, 0xF0, // C
    0xE0, 0x90, 0x90, 0x90, 0xE0, // D
    0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
    0xF0, 0x80, 0xF0, 0x80, 0x80, // F
];

/// Draw callback.
///
/// Takes a slice of u8, where each u8 is a pixel.
///
/// A **non-zero** pixel is visible, a **zero** pixel is not visible.
///
/// The coordinate system is from top-left to bottom-right.
///
/// Example:
///
/// ```rust
///     use crusty_chip::{ DISPLAY_WIDTH, VirtualMachine };
///     // Dump the pixels to stdout
///     fn dump_pixels(pixels: &[u8]) {
///         for (i, px) in pixels.iter().enumerate() {
///             match *px {
///                 0 => print!(" "),
///                 _ => print!("#")
///             }
///             if i % DISPLAY_WIDTH == 0 {
///                 print!("\n");
///             }
///         }
///     }
///     let mut ch8 = VirtualMachine::new(dump_pixels);
///     // ...
/// ```
pub type DrawCallback<'a> = |pixels: &[u8]|: 'a;

struct KeypressWait {
    wait: bool,
    vx: uint
}

/// CHIP-8 virtual machine
pub struct VirtualMachine<'a> {
    ram: [u8, .. MEM_SIZE],
    v: [u8, .. 16],
    i: u16,
    delay_timer: u8,
    sound_timer: u8,
    pc: u16,
    sp: u8,
    stack: [u16, .. 16],
    display: [u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT],
    draw_callback: DrawCallback<'a>,
    keys: [bool, .. 16],
    keypress_wait: KeypressWait
}

impl <'a> VirtualMachine <'a> {

    /// Constructs a new `VirtualMachine`.
    ///
    /// ## Arguments ##
    /// * draw_callback - Callback used when drawing
    pub fn new(draw_callback: DrawCallback<'a>) -> VirtualMachine<'a> {
        let mut ch8 = VirtualMachine {
            ram: [0, .. MEM_SIZE],
            v: [0, .. 16],
            i: 0,
            delay_timer: 0,
            sound_timer: 0,
            pc: START_ADDR,
            sp: 0,
            stack: [0, .. 16],
            display: [0, .. DISPLAY_WIDTH * DISPLAY_HEIGHT],
            draw_callback: draw_callback,
            keys: [false, .. 16],
            keypress_wait: KeypressWait {
                wait: false,
                vx: 0
            }
        };
        copy_memory(ch8.ram.slice_mut(0u, 5 * 0x10), FONTSET);
        ch8
    }

    /// Load a ROM
    ///
    /// ## Arguments ##
    /// * rom - ROM to load
    pub fn load_rom(&mut self, rom: &[u8]) {
        let len = self.ram.len();
        copy_memory(self.ram.slice_mut(START_ADDR as uint, len), rom);
    }

    /// Do an emulation cycle.
    pub fn do_cycle(&mut self) {
        if self.keypress_wait.wait {
            return;
        }

        let ins = self.fetch_ins();
        self.dispatch(ins);
    }

    // Decode instruction and execute it
    fn dispatch(&mut self, ins: u16) {
        // A 12-bit value, the lowest 12 bits of the instruction
        let nnn = ins & 0x0FFF;
        // A 4-bit value, the lowest 4 bits of the instruction
        let n = ins & 0x000F;
        // A 4-bit value, the lower 4 bits of the high byte of the instruction
        let x = (ins & 0x0F00) >> 8;
        // A 4-bit value, the upper 4 bits of the low byte of the instruction
        let y = (ins & 0x00F0) >> 4;
        // kk or byte - An 8-bit value, the lowest 8 bits of the instruction
        let kk = (ins & 0x00FF) as u8;

        match (ins & 0xF000) >> 12 {
            0x0 => match nnn {
                0x0E0 => ops::clear_display(self, ),
                0x0EE => ops::ret_from_subroutine(self, ),
                _ => ops::jump_to_sys_routine(self, 0)
            },
            0x1 => ops::jump_addr(self, nnn),
            0x2 => ops::call_subroutine(self, nnn as uint),
            0x3 => ops::skip_next_vx_eq(self, x as uint, kk),
            0x4 => ops::skip_next_vx_ne(self, x as uint, kk),
            0x5 => match n {
                0x0 => ops::skip_next_vx_eq_vy(self, x as uint, y as uint),
                _ => fail!("Unknown 0x5XXX instruction: {:x}", ins)
            },
            0x6 => ops::set_vx_byte(self, x as uint, kk),
            0x7 => ops::add_vx_byte(self, x as uint, kk),
            0x8 => {
                let (x, y) = (x as uint, y as uint);
                match n {
                    0x0 => ops::set_vx_to_vy(self, x, y),
                    0x1 => ops::set_vx_to_vx_or_vy(self, x, y),
                    0x2 => ops::set_vx_to_vx_and_vy(self, x, y),
                    0x3 => ops::set_vx_to_vx_xor_vy(self, x, y),
                    0x4 => ops::add_vx_vy(self, x, y),
                    0x5 => ops::sub_vx_vy(self, x, y),
                    0x6 => ops::set_vx_to_vx_shr_1(self, x),
                    0xE => ops::set_vx_to_vx_shl_1(self, x),
                    _ => fail!("Unknown 0x8XXX instruction: {:x}", ins)
                }
            },
            0x9 => match n {
                0x0 => ops::skip_next_vx_ne_vy(self, x as uint, y as uint),
                _ => fail!("Unknown 0x9XXX instruction: {:x}", ins)
            },
            0xA => ops::set_i(self, nnn),
            0xC => ops::set_vx_rand_and(self, x as uint, kk),
            0xD => ops::display_sprite(self, x as uint, y as uint, n as uint),
            0xE => match kk {
                0xA1 => ops::skip_next_key_vx_not_pressed(self, x as uint),
                0x9E => ops::skip_next_key_vx_pressed(self, x as uint),
                _ => fail!("Unknown 0xEXXX instruction: {:x}", ins)
            },
            0xF => {
                match kk {
                    0x07 => ops::set_vx_to_delay_timer(self, x as uint),
                    0x0A => ops::wait_for_keypress_store_in_vx(self, x as uint),
                    0x15 => ops::set_delay_timer(self, x as uint),
                    0x18 => ops::set_sound_timer(self, x as uint),
                    0x1E => ops::add_vx_to_i(self, x as uint),
                    0x29 => ops::set_i_to_loc_of_digit_vx(self, x as uint),
                    0x33 => ops::store_bcd_of_vx_to_i(self, x as uint),
                    0x55 => ops::copy_v0_through_vx_to_mem(self, x as uint),
                    0x65 => ops::read_v0_through_vx_from_mem(self, x as uint),
                    _ => fail!("Unknown 0xFXXX instruction: {:x}", ins)
                }
            },
            _ => fail!("Unknown instruction: {:04x}", ins)
        }
    }

    fn fetch_ins(&mut self) -> u16 {
        let b1 = self.ram[self.pc as uint];
        let b2 = self.ram[(self.pc + 1) as uint];
        self.pc += 2;
        b1 as u16 << 8 | b2 as u16
    }

    /// Press a key on the hexadecimal keypad
    ///
    /// `key` should be in the range `0..15`
    pub fn press_key(&mut self, key: uint) {
        assert!(key <= 15);
        self.keys[key] = true;
        if self.keypress_wait.wait {
            self.v[self.keypress_wait.vx] = key as u8;
            self.keypress_wait.wait = false;
        }
    }

    /// Release a key on the hexadecimal keypad
    ///
    /// `key` should be in the range `0..15`
    pub fn release_key(&mut self, key: uint) {
        assert!(key <= 15);
        self.keys[key] = false;
    }

    /// Decrement the sound and delay timers
    ///
    /// They should be decremented at a rate of 60 Hz
    pub fn decrement_timers(&mut self) {
        if self.delay_timer > 0 {
            self.delay_timer -= 1;
        }
        if self.sound_timer > 0 {
            self.sound_timer -= 1;
        }
    }
}
<commit_msg>Update to latest Rust<commit_after>//! CHIP-8 emulator backend.
//! You can develop your own frontends for it.
//!
//! The reference frontend is
//! [crusty-chip-sfml](https://github.com/crumblingstatue/crusty-chip-sfml).
//!
//! The CHIP-8 technical documentation in the comments is copied from
//! http://devernay.free.fr/hacks/chip8/C8TECH10.HTM,
//! Copyright (c) Thomas P. Greene.

#![experimental]

use std::slice::bytes::copy_memory;

mod ops;

const START_ADDR: u16 = 0x200;
const MEM_SIZE: uint = 4096;
pub const DISPLAY_WIDTH: uint = 64;
pub const DISPLAY_HEIGHT: uint = 32;

static FONTSET: [u8, .. 5 * 0x10] = [
    0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
    0x20, 0x60, 0x20, 0x20, 0x70, // 1
    0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
    0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
    0x90, 0x90, 0xF0, 0x10, 0x10, // 4
    0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
    0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
    0xF0, 0x10, 0x20, 0x40, 0x40, // 7
    0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
    0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
    0xF0, 0x90, 0xF0, 0x90, 0x90, // A
    0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
    0xF0, 0x80, 0x80, 0x80, 0xF0, // C
    0xE0, 0x90, 0x90, 0x90, 0xE0, // D
    0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
    0xF0, 0x80, 0xF0, 0x80, 0x80, // F
];

/// Draw callback.
///
/// Takes a slice of u8, where each u8 is a pixel.
///
/// A **non-zero** pixel is visible, a **zero** pixel is not visible.
///
/// The coordinate system is from top-left to bottom-right.
///
/// Example:
///
/// ```rust
///     use crusty_chip::{ DISPLAY_WIDTH, VirtualMachine };
///     // Dump the pixels to stdout
///     fn dump_pixels(pixels: &[u8]) {
///         for (i, px) in pixels.iter().enumerate() {
///             match *px {
///                 0 => print!(" "),
///                 _ => print!("#")
///             }
///             if i % DISPLAY_WIDTH == 0 {
///                 print!("\n");
///             }
///         }
///     }
///     let mut ch8 = VirtualMachine::new(dump_pixels);
///     // ...
/// ```
pub type DrawCallback<'a> = |pixels: &[u8]|: 'a;

struct KeypressWait {
    wait: bool,
    vx: uint
}

/// CHIP-8 virtual machine
pub struct VirtualMachine<'a> {
    ram: [u8, .. MEM_SIZE],
    v: [u8, .. 16],
    i: u16,
    delay_timer: u8,
    sound_timer: u8,
    pc: u16,
    sp: u8,
    stack: [u16, .. 16],
    display: [u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT],
    draw_callback: DrawCallback<'a>,
    keys: [bool, .. 16],
    keypress_wait: KeypressWait
}

impl <'a> VirtualMachine <'a> {

    /// Constructs a new `VirtualMachine`.
    ///
    /// ## Arguments ##
    /// * draw_callback - Callback used when drawing
    pub fn new(draw_callback: DrawCallback<'a>) -> VirtualMachine<'a> {
        let mut ch8 = VirtualMachine {
            ram: [0, .. MEM_SIZE],
            v: [0, .. 16],
            i: 0,
            delay_timer: 0,
            sound_timer: 0,
            pc: START_ADDR,
            sp: 0,
            stack: [0, .. 16],
            display: [0, .. DISPLAY_WIDTH * DISPLAY_HEIGHT],
            draw_callback: draw_callback,
            keys: [false, .. 16],
            keypress_wait: KeypressWait {
                wait: false,
                vx: 0
            }
        };
        copy_memory(ch8.ram.slice_mut(0u, 5 * 0x10), FONTSET);
        ch8
    }

    /// Load a ROM
    ///
    /// ## Arguments ##
    /// * rom - ROM to load
    pub fn load_rom(&mut self, rom: &[u8]) {
        let len = self.ram.len();
        copy_memory(self.ram.slice_mut(START_ADDR as uint, len), rom);
    }

    /// Do an emulation cycle.
    pub fn do_cycle(&mut self) {
        if self.keypress_wait.wait {
            return;
        }

        let ins = self.fetch_ins();
        self.dispatch(ins);
    }

    // Decode instruction and execute it
    fn dispatch(&mut self, ins: u16) {
        // A 12-bit value, the lowest 12 bits of the instruction
        let nnn = ins & 0x0FFF;
        // A 4-bit value, the lowest 4 bits of the instruction
        let n = ins & 0x000F;
        // A 4-bit value, the lower 4 bits of the high byte of the instruction
        let x = (ins & 0x0F00) >> 8;
        // A 4-bit value, the upper 4 bits of the low byte of the instruction
        let y = (ins & 0x00F0) >> 4;
        // kk or byte - An 8-bit value, the lowest 8 bits of the instruction
        let kk = (ins & 0x00FF) as u8;

        match (ins & 0xF000) >> 12 {
            0x0 => match nnn {
                0x0E0 => ops::clear_display(self, ),
                0x0EE => ops::ret_from_subroutine(self, ),
                _ => ops::jump_to_sys_routine(self, 0)
            },
            0x1 => ops::jump_addr(self, nnn),
            0x2 => ops::call_subroutine(self, nnn as uint),
            0x3 => ops::skip_next_vx_eq(self, x as uint, kk),
            0x4 => ops::skip_next_vx_ne(self, x as uint, kk),
            0x5 => match n {
                0x0 => ops::skip_next_vx_eq_vy(self, x as uint, y as uint),
                _ => panic!("Unknown 0x5XXX instruction: {:x}", ins)
            },
            0x6 => ops::set_vx_byte(self, x as uint, kk),
            0x7 => ops::add_vx_byte(self, x as uint, kk),
            0x8 => {
                let (x, y) = (x as uint, y as uint);
                match n {
                    0x0 => ops::set_vx_to_vy(self, x, y),
                    0x1 => ops::set_vx_to_vx_or_vy(self, x, y),
                    0x2 => ops::set_vx_to_vx_and_vy(self, x, y),
                    0x3 => ops::set_vx_to_vx_xor_vy(self, x, y),
                    0x4 => ops::add_vx_vy(self, x, y),
                    0x5 => ops::sub_vx_vy(self, x, y),
                    0x6 => ops::set_vx_to_vx_shr_1(self, x),
                    0xE => ops::set_vx_to_vx_shl_1(self, x),
                    _ => panic!("Unknown 0x8XXX instruction: {:x}", ins)
                }
            },
            0x9 => match n {
                0x0 => ops::skip_next_vx_ne_vy(self, x as uint, y as uint),
                _ => panic!("Unknown 0x9XXX instruction: {:x}", ins)
            },
            0xA => ops::set_i(self, nnn),
            0xC => ops::set_vx_rand_and(self, x as uint, kk),
            0xD => ops::display_sprite(self, x as uint, y as uint, n as uint),
            0xE => match kk {
                0xA1 => ops::skip_next_key_vx_not_pressed(self, x as uint),
                0x9E => ops::skip_next_key_vx_pressed(self, x as uint),
                _ => panic!("Unknown 0xEXXX instruction: {:x}", ins)
            },
            0xF => {
                match kk {
                    0x07 => ops::set_vx_to_delay_timer(self, x as uint),
                    0x0A => ops::wait_for_keypress_store_in_vx(self, x as uint),
                    0x15 => ops::set_delay_timer(self, x as uint),
                    0x18 => ops::set_sound_timer(self, x as uint),
                    0x1E => ops::add_vx_to_i(self, x as uint),
                    0x29 => ops::set_i_to_loc_of_digit_vx(self, x as uint),
                    0x33 => ops::store_bcd_of_vx_to_i(self, x as uint),
                    0x55 => ops::copy_v0_through_vx_to_mem(self, x as uint),
                    0x65 => ops::read_v0_through_vx_from_mem(self, x as uint),
                    _ => panic!("Unknown 0xFXXX instruction: {:x}", ins)
                }
            },
            _ => panic!("Unknown instruction: {:04x}", ins)
        }
    }

    fn fetch_ins(&mut self) -> u16 {
        let b1 = self.ram[self.pc as uint];
        let b2 = self.ram[(self.pc + 1) as uint];
        self.pc += 2;
        b1 as u16 << 8 | b2 as u16
    }

    /// Press a key on the hexadecimal keypad
    ///
    /// `key` should be in the range `0..15`
    pub fn press_key(&mut self, key: uint) {
        assert!(key <= 15);
        self.keys[key] = true;
        if self.keypress_wait.wait {
            self.v[self.keypress_wait.vx] = key as u8;
            self.keypress_wait.wait = false;
        }
    }

    /// Release a key on the hexadecimal keypad
    ///
    /// `key` should be in the range `0..15`
    pub fn release_key(&mut self, key: uint) {
        assert!(key <= 15);
        self.keys[key] = false;
    }

    /// Decrement the sound and delay timers
    ///
    /// They should be decremented at a rate of 60 Hz
    pub fn decrement_timers(&mut self) {
        if self.delay_timer > 0 {
            self.delay_timer -= 1;
        }
        if self.sound_timer > 0 {
            self.sound_timer -= 1;
        }
    }
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate url;
extern crate serde;
extern crate serde_json;

use hyper::client::{Client};
use hyper::header::{ContentType};
use hyper::client::response::{Response};
use hyper::error::Error as HyperError;
use url::form_urlencoded::{serialize};
use std::io::Read;
use std::io::Error;
use std::collections::BTreeMap;
use serde_json::error::Error as JsonError;

#[derive(Debug)]
pub enum CleverbotError {
    IncorrectCredentials,
    DuplicatedReferenceNames,
    Io(HyperError),
    Api(String),
    Std(Error),
    Json(JsonError),
    MissingValue(String)
}

impl From<HyperError> for CleverbotError {
    fn from(err: HyperError) -> CleverbotError {
        CleverbotError::Io(err)
    }
}

impl From<Error> for CleverbotError {
    fn from(err: Error) -> CleverbotError {
        CleverbotError::Std(err)
    }
}

impl From<JsonError> for CleverbotError {
    fn from(err: JsonError) -> CleverbotError {
        CleverbotError::Json(err)
    }
}

pub struct Cleverbot {
    user: String,
    key: String,
    pub nick: String,
}

impl Cleverbot {
    /// Creates a new Cleverbot instance.
    /// * `user` - The API User.
    /// * `key` - The API Key.
    pub fn new(user: String, key: String, nick: Option<String>) -> Result<Cleverbot, CleverbotError> {
        let mut response = {
            let mut args = vec![
                ("user", &*user),
                ("key", &*key),
            ];
            if let Some(ref nick) = nick { args.push(("nick", &*nick)) };
            try!(request("https://cleverbot.io/1.0/create", &*args))
        };
        let mut body = String::new();
        try!(response.read_to_string(&mut body));
        let json: BTreeMap<String, String> = try!(serde_json::from_str(&body));
        let opt_result = json.get("status");
        let result = match opt_result {
            Some(result) => result,
            None => return Err(CleverbotError::MissingValue(String::from("status"))),
        };
        match result.as_ref() {
            "success" => {
                let json_nick = json.get("nick");
                match json_nick {
                    Some(nick) => Ok(Cleverbot {
                        user: user,
                        key: key,
                        nick: nick.to_string()
                    }),
                    None => Err(CleverbotError::MissingValue(String::from("nick"))),
                }
            },
            "Error: API credentials incorrect" => Err(CleverbotError::IncorrectCredentials),
            "Error: reference name already exists" => Err(CleverbotError::DuplicatedReferenceNames),
            _ => Err(CleverbotError::Api(result.to_owned()))
        }
    }

    /// Sends the bot a message and returns its response. If the nick is not set, it will
    /// set it randomly through set_nick_randomly. Returns its response or error string.
    /// * `message` - The message to send to the bot.
    pub fn say(&mut self, message: &str) -> Result<String, CleverbotError> {
        let args = vec![
            ("user", &*self.user),
            ("key", &*self.key),
            ("nick", &*self.nick),
            ("text", message),
        ];
        let mut response = try!(request("https://cleverbot.io/1.0/ask", &*args));
        let mut body = String::new();
        try!(response.read_to_string(&mut body));
        let json: BTreeMap<String, String> = try!(serde_json::from_str(&body));
        let opt_result = json.get("status");
        let result = match opt_result {
            Some(result) => result,
            None => return Err(CleverbotError::MissingValue(String::from("status"))),
        };
        match result.as_ref() {
            "success" => {
                let json_response = json.get("response");
                match json_response {
                    Some(response) => Ok(response.to_string()),
                    None => Err(CleverbotError::MissingValue(String::from("nick"))),
                }
            },
            "Error: API credentials incorrect" => Err(CleverbotError::IncorrectCredentials),
            "Error: reference name already exists" => Err(CleverbotError::DuplicatedReferenceNames),
            _ => Err(CleverbotError::Api(result.to_owned()))
        }
    }
}

/// Submits a POST request to the URL with the given vec body.
/// * `base` - The URL
/// * `args` - A vector representing the request body.
fn request(base: &str, args: &[(&str, &str)]) -> Result<Response, HyperError> {
    let client = Client::new();
    let body = serialize(args.into_iter());
    client.post(base)
        .body(&body)
        .header(ContentType::form_url_encoded())
        .send()
}
<commit_msg>Fix rendering of lists in doc comments<commit_after>extern crate hyper;
extern crate url;
extern crate serde;
extern crate serde_json;

use hyper::client::{Client};
use hyper::header::{ContentType};
use hyper::client::response::{Response};
use hyper::error::Error as HyperError;
use url::form_urlencoded::{serialize};
use std::io::Read;
use std::io::Error;
use std::collections::BTreeMap;
use serde_json::error::Error as JsonError;

#[derive(Debug)]
pub enum CleverbotError {
    IncorrectCredentials,
    DuplicatedReferenceNames,
    Io(HyperError),
    Api(String),
    Std(Error),
    Json(JsonError),
    MissingValue(String)
}

impl From<HyperError> for CleverbotError {
    fn from(err: HyperError) -> CleverbotError {
        CleverbotError::Io(err)
    }
}

impl From<Error> for CleverbotError {
    fn from(err: Error) -> CleverbotError {
        CleverbotError::Std(err)
    }
}

impl From<JsonError> for CleverbotError {
    fn from(err: JsonError) -> CleverbotError {
        CleverbotError::Json(err)
    }
}

pub struct Cleverbot {
    user: String,
    key: String,
    pub nick: String,
}

impl Cleverbot {
    /// Creates a new Cleverbot instance.
    ///
    /// * `user` - The API User.
    /// * `key` - The API Key.
    pub fn new(user: String, key: String, nick: Option<String>) -> Result<Cleverbot, CleverbotError> {
        let mut response = {
            let mut args = vec![
                ("user", &*user),
                ("key", &*key),
            ];
            if let Some(ref nick) = nick { args.push(("nick", &*nick)) };
            try!(request("https://cleverbot.io/1.0/create", &*args))
        };
        let mut body = String::new();
        try!(response.read_to_string(&mut body));
        let json: BTreeMap<String, String> = try!(serde_json::from_str(&body));
        let opt_result = json.get("status");
        let result = match opt_result {
            Some(result) => result,
            None => return Err(CleverbotError::MissingValue(String::from("status"))),
        };
        match result.as_ref() {
            "success" => {
                let json_nick = json.get("nick");
                match json_nick {
                    Some(nick) => Ok(Cleverbot {
                        user: user,
                        key: key,
                        nick: nick.to_string()
                    }),
                    None => Err(CleverbotError::MissingValue(String::from("nick"))),
                }
            },
            "Error: API credentials incorrect" => Err(CleverbotError::IncorrectCredentials),
            "Error: reference name already exists" => Err(CleverbotError::DuplicatedReferenceNames),
            _ => Err(CleverbotError::Api(result.to_owned()))
        }
    }

    /// Sends the bot a message and returns its response. If the nick is not set, it will
    /// set it randomly through set_nick_randomly. Returns its response or error string.
    ///
    /// * `message` - The message to send to the bot.
    pub fn say(&mut self, message: &str) -> Result<String, CleverbotError> {
        let args = vec![
            ("user", &*self.user),
            ("key", &*self.key),
            ("nick", &*self.nick),
            ("text", message),
        ];
        let mut response = try!(request("https://cleverbot.io/1.0/ask", &*args));
        let mut body = String::new();
        try!(response.read_to_string(&mut body));
        let json: BTreeMap<String, String> = try!(serde_json::from_str(&body));
        let opt_result = json.get("status");
        let result = match opt_result {
            Some(result) => result,
            None => return Err(CleverbotError::MissingValue(String::from("status"))),
        };
        match result.as_ref() {
            "success" => {
                let json_response = json.get("response");
                match json_response {
                    Some(response) => Ok(response.to_string()),
                    None => Err(CleverbotError::MissingValue(String::from("nick"))),
                }
            },
            "Error: API credentials incorrect" => Err(CleverbotError::IncorrectCredentials),
            "Error: reference name already exists" => Err(CleverbotError::DuplicatedReferenceNames),
            _ => Err(CleverbotError::Api(result.to_owned()))
        }
    }
}

/// Submits a POST request to the URL with the given vec body.
///
/// * `base` - The URL
/// * `args` - A vector representing the request body.
fn request(base: &str, args: &[(&str, &str)]) -> Result<Response, HyperError> {
    let client = Client::new();
    let body = serialize(args.into_iter());
    client.post(base)
        .body(&body)
        .header(ContentType::form_url_encoded())
        .send()
}
<|endoftext|>


<commit_before>#![desc = "Omnomnom incremental byte parser"]
#![license = "MIT"]
#![macro_escape]

extern crate collections;

use std::fmt::Show;
use internal::*;
use internal::IResult::*;

#[macro_export]
macro_rules! tag(
  ($name:ident $inp:expr) => (
    fn $name(i:&[u8]) -> IResult<&[u8], &[u8]>{
      if i.len() >= $inp.len() && i.slice(0, $inp.len()) == $inp {
        Done(i.slice_from($inp.len()), i.slice(0, 0))
      } else {
        Error(0)
      }
    }
  )
)

macro_rules! o (
  ($name:ident<$i:ty,$o:ty> $f1:expr $($rest:tt)*) => (
    #[allow(unused_variables)]
    fn $name(input:$i) -> IResult<$i, $o>{
      match $f1(input) {
        IResult::Error(e)      => IResult::Error(e),
        IResult::Incomplete(i) => IResult::Incomplete(i),
        IResult::Done(i,o)     => {
          o_parser!(i o $($rest)*)
        }
      }
    }
  );
)

macro_rules! o_parser (
  ($i:expr $o:expr) => (Done($i,$o));

  ($i:expr $o:expr ~ $e:expr ~ $($rest:tt)*) => (
    match $e($i) {
      IResult::Error(e)      => IResult::Error(e),
      IResult::Incomplete(i) => IResult::Incomplete(i),
      IResult::Done(i,o)     => {
        o_parser!(i o $($rest)*)
      }
    }

   );
  ($i:expr $o:expr $e:expr $($rest:tt)*) => (
    match $e($i) {
      IResult::Error(e)      => IResult::Error(e),
      IResult::Incomplete(i) => IResult::Incomplete(i),
      IResult::Done(i,_)     => {
        o_parser!(i $o $($rest)*)
      }
    }
   );
)

macro_rules! chain (
  ($name:ident<$i:ty,$o:ty>, $assemble:expr, $($rest:tt)*) => (
    fn $name(i:$i) -> IResult<$i,$o>{
      chaining_parser!(i, $assemble, $($rest)*)
    }
  );
)

macro_rules! chaining_parser (
  ($i:expr, $assemble:expr, $field:ident : $e:expr, $($rest:tt)*) => (
    match $e($i) {
      IResult::Error(e)      => IResult::Error(e),
      IResult::Incomplete(i) => IResult::Incomplete(i),
      IResult::Done(i,o)     => {
        let $field = o;
        chaining_parser!(i, $assemble, $($rest)*)
      }
    }
  );

  ($i:expr, $assemble:expr, ) => (
    IResult::Done($i, $assemble())
  )
)

macro_rules! alt (
  ($name:ident<$i:ty,$o:ty>, $($rest:tt)*) => (
    fn $name(i:$i) -> IResult<$i,$o>{
      alt_parser!(i, $($rest)*)
    }
  );
)

macro_rules! alt_parser (
  ($i:expr, $e:expr $($rest:tt)*) => (
    match $e($i) {
      IResult::Error(_)      => alt_parser!($i, $($rest)*),
      IResult::Incomplete(_) => alt_parser!($i, $($rest)*),
      IResult::Done(i,o)     => IResult::Done(i,o)
    }
  );

  ($i:expr, ) => (
    IResult::Error(1)
  )
)

pub fn print<'a,T: Show>(input: T) -> IResult<T, ()> {
  println!("{}", input);
  Done(input, ())
}

pub fn begin<'a>(input: &'a [u8]) -> IResult<(), &'a [u8]> {
  Done((), input)
}

#[macro_export]
macro_rules! is_not(
  ($name:ident $arr:expr) => (
    fn $name(input:&[u8]) -> IResult<&[u8], &[u8]> {
      for idx in range(0, input.len()) {
        for &i in $arr.iter() {
          if input[idx] == i {
            return IResult::Done(input.slice_from(idx), input.slice(0, idx))
          }
        }
      }
      IResult::Done("".as_bytes(), input)
    }
  )
)

#[macro_export]
macro_rules! is_a(
  ($name:ident $arr:expr) => (
    fn $name(input:&[u8]) -> IResult<&[u8], &[u8]> {
      for idx in range(0, input.len()) {
        var res = false
        for &i in $arr.iter() {
          if input[idx] == i {
            res = true
          }
        }
        if !res {
          return IResult::Done(input.slice_from(idx), input.slice(0, idx))
        }
      }
      IResult::Done("".as_bytes(), input)
    }
  )
)

#[macro_export]
macro_rules! filter(
  ($name:ident $f:ident) => (
    fn $name(input:&[u8]) -> IResult<&[u8], &[u8]> {
      for idx in range(0, input.len()) {
        if !$f(input[idx]) {
          return IResult::Done(input.slice_from(idx), input.slice(0, idx))
        }
      }
      IResult::Done("".as_bytes(), input)
    }
  )
)

// FIXME: when rust-lang/rust#17436 is fixed, macros will be able to export
// public methods
//pub is_not!(line_ending "\r\n".as_bytes())
pub fn line_ending(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    for &i in "\r\n".as_bytes().iter() {
      if input[idx] == i {
        return Done(input.slice_from(idx), input.slice(0, idx))
      }
    }
  }
  Done("".as_bytes(), input)
}

pub fn is_alphabetic(chr:u8) -> bool {
  (chr >= 0x41 && chr <= 0x5A) || (chr >= 0x61 && chr <= 0x7A)
}

pub fn is_digit(chr: u8) -> bool {
  chr >= 0x30 && chr <= 0x39
}

pub fn is_alphanumeric(chr: u8) -> bool {
  is_alphabetic(chr) || is_digit(chr)
}

// FIXME: when rust-lang/rust#17436 is fixed, macros will be able to export
//pub filter!(alpha is_alphabetic)
//pub filter!(digit is_digit)
//pub filter!(alphanumeric is_alphanumeric)
pub fn alpha(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    if !is_alphabetic(input[idx]) {
      return Done(input.slice_from(idx), input.slice(0, idx))
    }
  }
  Done("".as_bytes(), input)
}

pub fn digit(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    if !is_digit(input[idx]) {
      return Done(input.slice_from(idx), input.slice(0, idx))
    }
  }
  Done("".as_bytes(), input)
}

pub fn alphanumeric(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    if !is_alphanumeric(input[idx]) {
      return Done(input.slice_from(idx), input.slice(0, idx))
    }
  }
  Done("".as_bytes(), input)
}

pub fn sized_buffer(input:&[u8]) -> IResult<&[u8], &[u8]> {
  if input.len() == 0 {
    //FIXME: should return Incomplete
    return Error(0)
  }

  let len = input[0] as uint;

  if input.len() >= len + 1 {
    return Done(input.slice_from(len+1), input.slice(1, len+1))
  } else {
    //FIXME: should return Incomplete
    return Error(0)
  }
}

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

  #[test]
  fn character_test() {
    let empty = "".as_bytes();
    let a = "abcd".as_bytes();
    let b = "1234".as_bytes();
    let c = "a123".as_bytes();
    let d = "azé12".as_bytes();
    assert_eq!(Done((),a).flat_map(alpha), Done(empty, a))
    assert_eq!(Done((),b).flat_map(alpha), Done(b, empty))
    assert_eq!(Done((),c).flat_map(alpha), Done(c.slice_from(1), "a".as_bytes()))
    assert_eq!(Done((),d).flat_map(alpha), Done("é12".as_bytes(), "az".as_bytes()))
    assert_eq!(Done((),a).flat_map(digit), Done(a, empty))
    assert_eq!(Done((),b).flat_map(digit), Done(empty, b))
    assert_eq!(Done((),c).flat_map(digit), Done(c, empty))
    assert_eq!(Done((),d).flat_map(digit), Done(d, empty))
    assert_eq!(Done((),a).flat_map(alphanumeric), Done(empty, a))
    assert_eq!(Done((),b).flat_map(alphanumeric), Done(empty, b))
    assert_eq!(Done((),c).flat_map(alphanumeric), Done(empty, c))
    assert_eq!(Done((),d).flat_map(alphanumeric), Done("é12".as_bytes(), "az".as_bytes()))
  }

  #[test]
  fn is_not_test() {
    let a = "ab12cd\nefgh".as_bytes();
    assert_eq!(Done((), a).flat_map(line_ending), Done("\nefgh".as_bytes(), "ab12cd".as_bytes()))
  }

  #[test]
  fn sized_buffer_test() {
    let arr:[u8, ..6] = [3, 4, 5, 6, 7, 8];
    let res = Done((), arr.as_slice()).flat_map(sized_buffer);
    let i = [7,8];
    let o = [4,5,6];
    assert_eq!(res, Done(i.as_slice(), o.as_slice()))
  }

  #[test]
  fn t1() {
    let v1:Vec<u8> = vec![1,2,3];
    let v2:Vec<u8> = vec![4,5,6];
    let d = Done(v1.as_slice(), v2.as_slice());
    let res = d.flat_map(print);
    assert_eq!(res, Done(v2.as_slice(), ()));
  }

  #[deriving(PartialEq,Eq,Show)]
  struct B {
    a: int,
    b: int
  }

  #[test]
  fn chain_and_ignore_test() {
    tag!(x "abcd".as_bytes());
    tag!(y "efgh".as_bytes());
    fn ret_int(i:&[u8]) -> IResult<&[u8], int> { Done(i,1) };
    //o!(z<&[u8], int>  x S x S retInt Z y);
    o!(z<&[u8], int>  x  x ~ret_int~ y);

    let r = Done((), "abcdabcdefgh".as_bytes()).flat_map(z);
    assert_eq!(r, Done("".as_bytes(), 1));
  }

  #[test]
  fn chain_test() {
    tag!(x "abcd".as_bytes());
    fn temp_ret_int1(i:&[u8]) -> IResult<&[u8], int> { Done(i,1) };
    o!(ret_int1<&[u8],int> x ~ temp_ret_int1 ~);
    fn ret_int2(i:&[u8]) -> IResult<&[u8], int> { Done(i,2) };
    chain!(f<&[u8],B>, ||{B{a: aa, b: bb}}, aa: ret_int1, bb: ret_int2,);

    let r = Done((), "abcde".as_bytes()).flat_map(f);
    assert_eq!(r, Done("e".as_bytes(), B{a: 1, b: 2}));
  }

  #[test]
  fn alt_test() {
    fn work(input: &[u8]) -> IResult<&[u8],&[u8]> {
      Done("".as_bytes(), input)
    }

    #[allow(unused_variables)]
    fn dont_work(input: &[u8]) -> IResult<&[u8],&[u8]> {
      Error(3)
    }

    fn work2(input: &[u8]) -> IResult<&[u8],&[u8]> {
      Done(input, "".as_bytes())
    }

    alt!(alt1<&[u8],&[u8]>, dont_work dont_work)
    alt!(alt2<&[u8],&[u8]>, dont_work work)
    alt!(alt3<&[u8],&[u8]>, dont_work dont_work work2 dont_work)

    let a = "abcd".as_bytes();
    assert_eq!(Done((), a).flat_map(alt1), Error(1))
    assert_eq!(Done((), a).flat_map(alt2), Done("".as_bytes(), a))
    assert_eq!(Done((), a).flat_map(alt3), Done(a, "".as_bytes()))
  }

  /* FIXME: this makes rustc weep
  fn pr(par: IResult<(),&[u8]>) -> IResult<&[u8], ()> {
    Error(0)
  }

  #[test]
  fn rustc_panic_test() {
    FileProducer::new("links.txt", 20).map(|producer: FileProducer| {
      let mut p = producer;
      p.push(pr);
    });
  }*/
}
<commit_msg>sized_buffer returns incomplete<commit_after>#![desc = "Omnomnom incremental byte parser"]
#![license = "MIT"]
#![macro_escape]

extern crate collections;

use std::fmt::Show;
use internal::*;
use internal::IResult::*;

#[macro_export]
macro_rules! tag(
  ($name:ident $inp:expr) => (
    fn $name(i:&[u8]) -> IResult<&[u8], &[u8]>{
      if i.len() >= $inp.len() && i.slice(0, $inp.len()) == $inp {
        Done(i.slice_from($inp.len()), i.slice(0, 0))
      } else {
        Error(0)
      }
    }
  )
)

macro_rules! o (
  ($name:ident<$i:ty,$o:ty> $f1:expr $($rest:tt)*) => (
    #[allow(unused_variables)]
    fn $name(input:$i) -> IResult<$i, $o>{
      match $f1(input) {
        IResult::Error(e)      => IResult::Error(e),
        IResult::Incomplete(i) => IResult::Incomplete(i),
        IResult::Done(i,o)     => {
          o_parser!(i o $($rest)*)
        }
      }
    }
  );
)

macro_rules! o_parser (
  ($i:expr $o:expr) => (Done($i,$o));

  ($i:expr $o:expr ~ $e:expr ~ $($rest:tt)*) => (
    match $e($i) {
      IResult::Error(e)      => IResult::Error(e),
      IResult::Incomplete(i) => IResult::Incomplete(i),
      IResult::Done(i,o)     => {
        o_parser!(i o $($rest)*)
      }
    }

   );
  ($i:expr $o:expr $e:expr $($rest:tt)*) => (
    match $e($i) {
      IResult::Error(e)      => IResult::Error(e),
      IResult::Incomplete(i) => IResult::Incomplete(i),
      IResult::Done(i,_)     => {
        o_parser!(i $o $($rest)*)
      }
    }
   );
)

macro_rules! chain (
  ($name:ident<$i:ty,$o:ty>, $assemble:expr, $($rest:tt)*) => (
    fn $name(i:$i) -> IResult<$i,$o>{
      chaining_parser!(i, $assemble, $($rest)*)
    }
  );
)

macro_rules! chaining_parser (
  ($i:expr, $assemble:expr, $field:ident : $e:expr, $($rest:tt)*) => (
    match $e($i) {
      IResult::Error(e)      => IResult::Error(e),
      IResult::Incomplete(i) => IResult::Incomplete(i),
      IResult::Done(i,o)     => {
        let $field = o;
        chaining_parser!(i, $assemble, $($rest)*)
      }
    }
  );

  ($i:expr, $assemble:expr, ) => (
    IResult::Done($i, $assemble())
  )
)

macro_rules! alt (
  ($name:ident<$i:ty,$o:ty>, $($rest:tt)*) => (
    fn $name(i:$i) -> IResult<$i,$o>{
      alt_parser!(i, $($rest)*)
    }
  );
)

macro_rules! alt_parser (
  ($i:expr, $e:expr $($rest:tt)*) => (
    match $e($i) {
      IResult::Error(_)      => alt_parser!($i, $($rest)*),
      IResult::Incomplete(_) => alt_parser!($i, $($rest)*),
      IResult::Done(i,o)     => IResult::Done(i,o)
    }
  );

  ($i:expr, ) => (
    IResult::Error(1)
  )
)

pub fn print<'a,T: Show>(input: T) -> IResult<T, ()> {
  println!("{}", input);
  Done(input, ())
}

pub fn begin<'a>(input: &'a [u8]) -> IResult<(), &'a [u8]> {
  Done((), input)
}

#[macro_export]
macro_rules! is_not(
  ($name:ident $arr:expr) => (
    fn $name(input:&[u8]) -> IResult<&[u8], &[u8]> {
      for idx in range(0, input.len()) {
        for &i in $arr.iter() {
          if input[idx] == i {
            return IResult::Done(input.slice_from(idx), input.slice(0, idx))
          }
        }
      }
      IResult::Done("".as_bytes(), input)
    }
  )
)

#[macro_export]
macro_rules! is_a(
  ($name:ident $arr:expr) => (
    fn $name(input:&[u8]) -> IResult<&[u8], &[u8]> {
      for idx in range(0, input.len()) {
        var res = false
        for &i in $arr.iter() {
          if input[idx] == i {
            res = true
          }
        }
        if !res {
          return IResult::Done(input.slice_from(idx), input.slice(0, idx))
        }
      }
      IResult::Done("".as_bytes(), input)
    }
  )
)

#[macro_export]
macro_rules! filter(
  ($name:ident $f:ident) => (
    fn $name(input:&[u8]) -> IResult<&[u8], &[u8]> {
      for idx in range(0, input.len()) {
        if !$f(input[idx]) {
          return IResult::Done(input.slice_from(idx), input.slice(0, idx))
        }
      }
      IResult::Done("".as_bytes(), input)
    }
  )
)

// FIXME: when rust-lang/rust#17436 is fixed, macros will be able to export
// public methods
//pub is_not!(line_ending "\r\n".as_bytes())
pub fn line_ending(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    for &i in "\r\n".as_bytes().iter() {
      if input[idx] == i {
        return Done(input.slice_from(idx), input.slice(0, idx))
      }
    }
  }
  Done("".as_bytes(), input)
}

pub fn is_alphabetic(chr:u8) -> bool {
  (chr >= 0x41 && chr <= 0x5A) || (chr >= 0x61 && chr <= 0x7A)
}

pub fn is_digit(chr: u8) -> bool {
  chr >= 0x30 && chr <= 0x39
}

pub fn is_alphanumeric(chr: u8) -> bool {
  is_alphabetic(chr) || is_digit(chr)
}

// FIXME: when rust-lang/rust#17436 is fixed, macros will be able to export
//pub filter!(alpha is_alphabetic)
//pub filter!(digit is_digit)
//pub filter!(alphanumeric is_alphanumeric)
pub fn alpha(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    if !is_alphabetic(input[idx]) {
      return Done(input.slice_from(idx), input.slice(0, idx))
    }
  }
  Done("".as_bytes(), input)
}

pub fn digit(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    if !is_digit(input[idx]) {
      return Done(input.slice_from(idx), input.slice(0, idx))
    }
  }
  Done("".as_bytes(), input)
}

pub fn alphanumeric(input:&[u8]) -> IResult<&[u8], &[u8]> {
  for idx in range(0, input.len()) {
    if !is_alphanumeric(input[idx]) {
      return Done(input.slice_from(idx), input.slice(0, idx))
    }
  }
  Done("".as_bytes(), input)
}

pub fn sized_buffer(input:&[u8]) -> IResult<&[u8], &[u8]> {
  if input.len() == 0 {
    return Incomplete(0)
  }

  let len = input[0] as uint;

  if input.len() >= len + 1 {
    return Done(input.slice_from(len+1), input.slice(1, len+1))
  } else {
    return Incomplete(0)
  }
}

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

  #[test]
  fn character_test() {
    let empty = "".as_bytes();
    let a = "abcd".as_bytes();
    let b = "1234".as_bytes();
    let c = "a123".as_bytes();
    let d = "azé12".as_bytes();
    assert_eq!(Done((),a).flat_map(alpha), Done(empty, a))
    assert_eq!(Done((),b).flat_map(alpha), Done(b, empty))
    assert_eq!(Done((),c).flat_map(alpha), Done(c.slice_from(1), "a".as_bytes()))
    assert_eq!(Done((),d).flat_map(alpha), Done("é12".as_bytes(), "az".as_bytes()))
    assert_eq!(Done((),a).flat_map(digit), Done(a, empty))
    assert_eq!(Done((),b).flat_map(digit), Done(empty, b))
    assert_eq!(Done((),c).flat_map(digit), Done(c, empty))
    assert_eq!(Done((),d).flat_map(digit), Done(d, empty))
    assert_eq!(Done((),a).flat_map(alphanumeric), Done(empty, a))
    assert_eq!(Done((),b).flat_map(alphanumeric), Done(empty, b))
    assert_eq!(Done((),c).flat_map(alphanumeric), Done(empty, c))
    assert_eq!(Done((),d).flat_map(alphanumeric), Done("é12".as_bytes(), "az".as_bytes()))
  }

  #[test]
  fn is_not_test() {
    let a = "ab12cd\nefgh".as_bytes();
    assert_eq!(Done((), a).flat_map(line_ending), Done("\nefgh".as_bytes(), "ab12cd".as_bytes()))
  }

  #[test]
  fn sized_buffer_test() {
    let arr:[u8, ..6] = [3, 4, 5, 6, 7, 8];
    let res = Done((), arr.as_slice()).flat_map(sized_buffer);
    let i = [7,8];
    let o = [4,5,6];
    assert_eq!(res, Done(i.as_slice(), o.as_slice()))
  }

  #[test]
  fn t1() {
    let v1:Vec<u8> = vec![1,2,3];
    let v2:Vec<u8> = vec![4,5,6];
    let d = Done(v1.as_slice(), v2.as_slice());
    let res = d.flat_map(print);
    assert_eq!(res, Done(v2.as_slice(), ()));
  }

  #[deriving(PartialEq,Eq,Show)]
  struct B {
    a: int,
    b: int
  }

  #[test]
  fn chain_and_ignore_test() {
    tag!(x "abcd".as_bytes());
    tag!(y "efgh".as_bytes());
    fn ret_int(i:&[u8]) -> IResult<&[u8], int> { Done(i,1) };
    //o!(z<&[u8], int>  x S x S retInt Z y);
    o!(z<&[u8], int>  x  x ~ret_int~ y);

    let r = Done((), "abcdabcdefgh".as_bytes()).flat_map(z);
    assert_eq!(r, Done("".as_bytes(), 1));
  }

  #[test]
  fn chain_test() {
    tag!(x "abcd".as_bytes());
    fn temp_ret_int1(i:&[u8]) -> IResult<&[u8], int> { Done(i,1) };
    o!(ret_int1<&[u8],int> x ~ temp_ret_int1 ~);
    fn ret_int2(i:&[u8]) -> IResult<&[u8], int> { Done(i,2) };
    chain!(f<&[u8],B>, ||{B{a: aa, b: bb}}, aa: ret_int1, bb: ret_int2,);

    let r = Done((), "abcde".as_bytes()).flat_map(f);
    assert_eq!(r, Done("e".as_bytes(), B{a: 1, b: 2}));
  }

  #[test]
  fn alt_test() {
    fn work(input: &[u8]) -> IResult<&[u8],&[u8]> {
      Done("".as_bytes(), input)
    }

    #[allow(unused_variables)]
    fn dont_work(input: &[u8]) -> IResult<&[u8],&[u8]> {
      Error(3)
    }

    fn work2(input: &[u8]) -> IResult<&[u8],&[u8]> {
      Done(input, "".as_bytes())
    }

    alt!(alt1<&[u8],&[u8]>, dont_work dont_work)
    alt!(alt2<&[u8],&[u8]>, dont_work work)
    alt!(alt3<&[u8],&[u8]>, dont_work dont_work work2 dont_work)

    let a = "abcd".as_bytes();
    assert_eq!(Done((), a).flat_map(alt1), Error(1))
    assert_eq!(Done((), a).flat_map(alt2), Done("".as_bytes(), a))
    assert_eq!(Done((), a).flat_map(alt3), Done(a, "".as_bytes()))
  }

  /* FIXME: this makes rustc weep
  fn pr(par: IResult<(),&[u8]>) -> IResult<&[u8], ()> {
    Error(0)
  }

  #[test]
  fn rustc_panic_test() {
    FileProducer::new("links.txt", 20).map(|producer: FileProducer| {
      let mut p = producer;
      p.push(pr);
    });
  }*/
}
<|endoftext|>


<commit_before>/// Compute the signed distance function from a line segment given as the level set of a linear
/// function on an isosceles right-angle triangle.
///
/// Input are `u`, the values at the verteces. The vertex 0 is the one with the right angle.
///
/// `h` is the length of the side.
///
/// The return is the values of the signed distance function or `None` if there line segment does
/// not pass through the triangle.
pub fn triangle_dist(mut u: [f64; 3]) -> Option<[f64; 3]> {
    // normalize so that u[0] >= 0.
    if u[0] < 0. {
        for i in 0..3 {
            u[i] = -u[i];
        }
    }

    // gradient vector
    let gx = u[1] - u[0];
    let gy = u[2] - u[0];

    let g_norm = (gx * gx + gy * gy).sqrt();

    if u[1] >= 0. {
        if u[2] >= 0. {
            return None;
        } else { // u[2] < 0.
            // intersect position
            let i02 = u[0] / (u[0] - u[2]);
            let i12 = (2f64).sqrt() * u[1] / (u[1] - u[2]);
            // find the direction of the gradient
            // to deduce the vertex that is closest to the line
            if gx <= 0. { // 0
                return Some([u[0] / g_norm, i12, 1. - i02]);
            } else if gx > -gy { // 1
                return Some([i02, u[1] / g_norm, (2f64).sqrt() - i12]);
            } else { // 2
                return Some([i02, i12, -u[2] / g_norm]);
            }
        }
    } else { // u[1] < 0.
        if u[2] >= 0. {
            // intersect position
            let i01 = u[0] / (u[0] - u[1]);
            let i12 = (2f64).sqrt() * u[1] / (u[1] - u[2]);
            // find the direction of the gradient
            // to deduce the vertex that is closest to the line
            if gy <= 0. { // 0
                return Some([u[0] / g_norm, 1. - i01, (2f64).sqrt() - i12]);
            } else if -gx > gy { // 1
                return Some([i01, -u[1] / g_norm, (2f64).sqrt() - i12]);
            } else { // 2
                return Some([i01, i12, u[2] / g_norm]);
            }
        } else { // u[2] < 0.
            // intersect position
            let i10 = u[1] / (u[1] - u[0]);
            let i20 = u[2] / (u[2] - u[0]);

            return Some([u[0] / g_norm, i10, i20]);
        }
    }

    Some([0., 0., 0.])
}

/// Initialize distance around the free boundary.
///
/// Splits every square into two triangles and computes the distance on each of them.
pub fn init_dist(d: &mut [f64], u: &[f64], dim: (usize, usize)) {
    assert_eq!(dim.0 * dim.1, u.len());
    assert_eq!(dim.0 * dim.1, d.len());

    for i in 0..d.len() {
        d[i] = std::f64::MAX;
    }

    for j in 1..dim.1 {
        for i in 1..dim.0 {
            let s = j * dim.0 + i;
            let r = triangle_dist([u[s - dim.0 - 1], u[s - dim.0], u[s - 1]]);
            if let Some(e) = r {
                d[s - dim.0 - 1] = e[0].min(d[s - dim.0 - 1]);
                d[s - dim.0] = e[1].min(d[s - dim.0]);
                d[s - 1] = e[2].min(d[s - 1]);
            }
            let r = triangle_dist([u[s], u[s - dim.0], u[s - 1]]);
            if let Some(e) = r {
                d[s] = e[0].min(d[s]);
                d[s - dim.0] = e[1].min(d[s - dim.0]);
                d[s - 1] = e[2].min(d[s - 1]);
            }
        }
    }

    // for i in 0..d.len() {
    //     if u[i] < 0. {
    //         d[i] = -d[i];
    //     }
    // }
}

/// Computes the signed distance function in 2D using the Fast Sweeping algorithm.
pub fn fast_sweep_dist(d: &mut [f64], dim: (usize, usize)) {

    for k in 1..5 {
        for q in 0..dim.1 {
            let j = if k == 3 || k == 4 {
                dim.1 - 1 - q
            } else {
                q
            };
            for p in 0..dim.0 {
                let i = if k == 2 || k == 3 {
                    dim.0 - 1 - p
                } else {
                    p
                };
                let s = j * dim.0 + i;
                let a = if i == 0 {
                    d[s + 1]
                } else if i == dim.0 - 1 {
                    d[s - 1]
                } else {
                    d[s - 1].min(d[s + 1])
                };
                let b = if j == 0 {
                    d[s + dim.0]
                } else if j == dim.1 - 1 {
                    d[s - dim.0]
                } else {
                    d[s - dim.0].min(d[s + dim.0])
                };
                let x = if (a - b).abs() >= 1. {
                    a.min(b) + 1.
                } else {
                    0.5 * (a + b + (2. - (a - b) * (a - b)).sqrt())
                };

                d[s] = d[s].min(x);
            }
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    extern crate quickcheck;
    use self::quickcheck::quickcheck;

    #[test]
    fn it_works() {
        let n = 8;
        let mut u = vec![0.; (n + 1) * (n + 1)];

        let h = 1f64;

        let gx = 0.5f64;
        let gy = 0.4f64;
        let g_norm = (gx * gx + gy * gy).sqrt();
        let gx = gx / g_norm;
        let gy = gy / g_norm;
        let c = -2.;

        for i in 0..(n+1) {
            for j in 0..(n+1) {
                let x = i as f64 * h;
                let y = j as f64 * h;
                u[i + j * (n + 1)] = x * gx + y * gy + c;
            }
        }

        let mut d = vec![0f64; (n + 1) * (n + 1)];

        init_dist(&mut d, &u, (n+1, n+1));
        fast_sweep_dist(&mut d, (n+1, n+1));

        for i in 0..d.len() {
            if u[i] < 0. {
                d[i] = -d[i];
            }
        }
        for (d, u) in d.iter_mut().zip(u.iter()) {
            *d -= *u;
        }
        println!("");
        println!("{:?}", u);
        println!("{:?}", d);
        panic!();
    }

    #[test]
    fn it_is_nonnegative() {
        fn prop(x: f64, y: f64, z: f64) -> bool {
            if let Some(e) = triangle_dist([x, y, z]) {
                // println!("{:?} -> {:?}", (x, y, z), e);
                e.into_iter().all(|&x| x >= 0.)
            } else {
                true
            }
        }
        quickcheck(prop as fn(f64, f64, f64) -> bool);
    }
}
<commit_msg>rustfmt<commit_after>/// Compute the signed distance function from a line segment given as the level set of a linear
/// function on an isosceles right-angle triangle.
///
/// Input are `u`, the values at the verteces. The vertex 0 is the one with the right angle.
///
/// `h` is the length of the side.
///
/// The return is the values of the signed distance function or `None` if there line segment does
/// not pass through the triangle.
pub fn triangle_dist(mut u: [f64; 3]) -> Option<[f64; 3]> {
    // normalize so that u[0] >= 0.
    if u[0] < 0. {
        for i in 0..3 {
            u[i] = -u[i];
        }
    }

    // gradient vector
    let gx = u[1] - u[0];
    let gy = u[2] - u[0];

    let g_norm = (gx * gx + gy * gy).sqrt();

    if u[1] >= 0. {
        if u[2] >= 0. {
            return None;
        } else {
            // u[2] < 0.
            // intersect position
            let i02 = u[0] / (u[0] - u[2]);
            let i12 = (2f64).sqrt() * u[1] / (u[1] - u[2]);
            // find the direction of the gradient
            // to deduce the vertex that is closest to the line
            if gx <= 0. {
                // 0
                return Some([u[0] / g_norm, i12, 1. - i02]);
            } else if gx > -gy {
                // 1
                return Some([i02, u[1] / g_norm, (2f64).sqrt() - i12]);
            } else {
                // 2
                return Some([i02, i12, -u[2] / g_norm]);
            }
        }
    } else {
        // u[1] < 0.
        if u[2] >= 0. {
            // intersect position
            let i01 = u[0] / (u[0] - u[1]);
            let i12 = (2f64).sqrt() * u[1] / (u[1] - u[2]);
            // find the direction of the gradient
            // to deduce the vertex that is closest to the line
            if gy <= 0. {
                // 0
                return Some([u[0] / g_norm, 1. - i01, (2f64).sqrt() - i12]);
            } else if -gx > gy {
                // 1
                return Some([i01, -u[1] / g_norm, (2f64).sqrt() - i12]);
            } else {
                // 2
                return Some([i01, i12, u[2] / g_norm]);
            }
        } else {
            // u[2] < 0.
            // intersect position
            let i10 = u[1] / (u[1] - u[0]);
            let i20 = u[2] / (u[2] - u[0]);

            return Some([u[0] / g_norm, i10, i20]);
        }
    }

    Some([0., 0., 0.])
}

/// Initialize distance around the free boundary.
///
/// Splits every square into two triangles and computes the distance on each of them.
pub fn init_dist(d: &mut [f64], u: &[f64], dim: (usize, usize)) {
    assert_eq!(dim.0 * dim.1, u.len());
    assert_eq!(dim.0 * dim.1, d.len());

    for i in 0..d.len() {
        d[i] = std::f64::MAX;
    }

    for j in 1..dim.1 {
        for i in 1..dim.0 {
            let s = j * dim.0 + i;
            let r = triangle_dist([u[s - dim.0 - 1], u[s - dim.0], u[s - 1]]);
            if let Some(e) = r {
                d[s - dim.0 - 1] = e[0].min(d[s - dim.0 - 1]);
                d[s - dim.0] = e[1].min(d[s - dim.0]);
                d[s - 1] = e[2].min(d[s - 1]);
            }
            let r = triangle_dist([u[s], u[s - dim.0], u[s - 1]]);
            if let Some(e) = r {
                d[s] = e[0].min(d[s]);
                d[s - dim.0] = e[1].min(d[s - dim.0]);
                d[s - 1] = e[2].min(d[s - 1]);
            }
        }
    }

    // for i in 0..d.len() {
    //     if u[i] < 0. {
    //         d[i] = -d[i];
    //     }
    // }
}

/// Computes the signed distance function in 2D using the Fast Sweeping algorithm.
pub fn fast_sweep_dist(d: &mut [f64], dim: (usize, usize)) {

    for k in 1..5 {
        for q in 0..dim.1 {
            let j = if k == 3 || k == 4 {
                dim.1 - 1 - q
            } else {
                q
            };
            for p in 0..dim.0 {
                let i = if k == 2 || k == 3 {
                    dim.0 - 1 - p
                } else {
                    p
                };
                let s = j * dim.0 + i;
                let a = if i == 0 {
                    d[s + 1]
                } else if i == dim.0 - 1 {
                    d[s - 1]
                } else {
                    d[s - 1].min(d[s + 1])
                };
                let b = if j == 0 {
                    d[s + dim.0]
                } else if j == dim.1 - 1 {
                    d[s - dim.0]
                } else {
                    d[s - dim.0].min(d[s + dim.0])
                };
                let x = if (a - b).abs() >= 1. {
                    a.min(b) + 1.
                } else {
                    0.5 * (a + b + (2. - (a - b) * (a - b)).sqrt())
                };

                d[s] = d[s].min(x);
            }
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    extern crate quickcheck;
    use self::quickcheck::quickcheck;

    #[test]
    fn it_works() {
        let n = 8;
        let mut u = vec![0.; (n + 1) * (n + 1)];

        let h = 1f64;

        let gx = 0.5f64;
        let gy = 0.4f64;
        let g_norm = (gx * gx + gy * gy).sqrt();
        let gx = gx / g_norm;
        let gy = gy / g_norm;
        let c = -2.;

        for i in 0..(n + 1) {
            for j in 0..(n + 1) {
                let x = i as f64 * h;
                let y = j as f64 * h;
                u[i + j * (n + 1)] = x * gx + y * gy + c;
            }
        }

        let mut d = vec![0f64; (n + 1) * (n + 1)];

        init_dist(&mut d, &u, (n + 1, n + 1));
        fast_sweep_dist(&mut d, (n + 1, n + 1));

        for i in 0..d.len() {
            if u[i] < 0. {
                d[i] = -d[i];
            }
        }
        for (d, u) in d.iter_mut().zip(u.iter()) {
            *d -= *u;
        }
        println!("");
        println!("{:?}", u);
        println!("{:?}", d);
        panic!();
    }

    #[test]
    fn it_is_nonnegative() {
        fn prop(x: f64, y: f64, z: f64) -> bool {
            if let Some(e) = triangle_dist([x, y, z]) {
                // println!("{:?} -> {:?}", (x, y, z), e);
                e.into_iter().all(|&x| x >= 0.)
            } else {
                true
            }
        }
        quickcheck(prop as fn(f64, f64, f64) -> bool);
    }
}
<|endoftext|>


<commit_before>
pub fn puzzle(input: &str) -> u32 {
    let mut total = 0;
    for line in input.lines() {
        if supports_tls(line) {
            total += 1;
        }
    }
    total
}

pub fn supports_tls(candidate: &str) -> bool {
    println!("considering {}", candidate);
    let mut start_index = 0;
    let end_index = candidate.len();

    let mut abba_outside = false;

    for (i, c) in candidate.match_indices(|c| c == '[' || c == ']') {
        println!("looking at slice ending in {}, [{}..{}]", c, start_index, i);
        println!("slice is {}", &candidate[start_index..i]);
        println!("abba_outside = {}", abba_outside);
        if c == "[" {
            abba_outside = abba_outside || contains_abba(&candidate[start_index..i]);
            println!("after looking, abba_outside = {}", abba_outside);
        } else {
            if contains_abba(&candidate[start_index..i]) {
                println!("womp womp, found an abba inside");
                return false;
            }
        }
        start_index = i + 1;
        println!("start_index = {}", start_index);
    }
    println!("looking at final slice [{}..{}]: '{}", start_index, end_index, &candidate[start_index..end_index]);

    abba_outside = abba_outside || contains_abba(&candidate[start_index..end_index]);

    println!("final answer: {}", abba_outside);

    abba_outside
}

pub fn contains_abba(candidate: &str) -> bool {
    let by_chars: Vec<char> = candidate.chars().collect();

    for (i, &c) in by_chars.iter().enumerate() {
        if i + 3 < by_chars.len() &&
            c != by_chars[i + 1] &&
            by_chars[i + 1] == by_chars[i + 2] &&
            by_chars[i + 3] == c {
            return true
        }
    }
    false
}

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

    #[test]
    fn does_support_tls() {
        assert!(supports_tls("abba[mnop]qrst"));
        assert!(supports_tls("ioxxoj[asdfgh]zxcvbn"));
        assert!(supports_tls("abcd[efgh]ijk[lmn]oppo"))
    }

    #[test]
    fn does_not_support_tls() {
        assert!( ! supports_tls("abcd[bddb]xyyx") );
        assert!( ! supports_tls("aaaa[qwer]tyui") );
        assert!( ! supports_tls("aaaa[qwer]tyui[foof]poop") );
    }

    #[test]
    fn does_contain_abba() {
        assert!(contains_abba("abba"));
        assert!(contains_abba("ioxxoj"));
    }

    #[test]
    fn does_not_contain_abba() {
        assert!( ! contains_abba("mnop") );
        assert!( ! contains_abba("aaaa") );
    }
}
<commit_msg>Add some failing tests<commit_after>
pub fn puzzle(input: &str) -> u32 {
    let mut total = 0;
    for line in input.lines() {
        if supports_tls(line) {
            total += 1;
        }
    }
    total
}

pub fn supports_tls(candidate: &str) -> bool {
    println!("considering {}", candidate);
    let mut start_index = 0;
    let end_index = candidate.len();

    let mut abba_outside = false;

    for (i, c) in candidate.match_indices(|c| c == '[' || c == ']') {
        println!("looking at slice ending in {}, [{}..{}]", c, start_index, i);
        println!("slice is {}", &candidate[start_index..i]);
        println!("abba_outside = {}", abba_outside);
        if c == "[" {
            abba_outside = abba_outside || contains_abba(&candidate[start_index..i]);
            println!("after looking, abba_outside = {}", abba_outside);
        } else {
            if contains_abba(&candidate[start_index..i]) {
                println!("womp womp, found an abba inside");
                return false;
            }
        }
        start_index = i + 1;
        println!("start_index = {}", start_index);
    }
    println!("looking at final slice [{}..{}]: '{}", start_index, end_index, &candidate[start_index..end_index]);

    abba_outside = abba_outside || contains_abba(&candidate[start_index..end_index]);

    println!("final answer: {}", abba_outside);

    abba_outside
}

pub fn contains_abba(candidate: &str) -> bool {
    let by_chars: Vec<char> = candidate.chars().collect();

    for (i, &c) in by_chars.iter().enumerate() {
        if i + 3 < by_chars.len() &&
            c != by_chars[i + 1] &&
            by_chars[i + 1] == by_chars[i + 2] &&
            by_chars[i + 3] == c {
            return true
        }
    }
    false
}

pub fn supports_ssl(candidate: &str) -> bool {
    false
}

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

    #[test]
    fn does_support_ssl() {
        assert!(supports_ssl("aba[bab]xyz"));
        assert!(supports_ssl("aaa[kek]eke"));
        assert!(supports_ssl("zazbz[bzb]cdb"));
        assert!(supports_ssl("zazaaabz[bzb]cdb[foo]zbz"));
    }

    #[test]
    fn does_not_support_ssl() {
        assert!( ! supports_ssl("xyx[xyx]xyx") );
    }

    #[test]
    fn does_support_tls() {
        assert!(supports_tls("abba[mnop]qrst"));
        assert!(supports_tls("ioxxoj[asdfgh]zxcvbn"));
        assert!(supports_tls("abcd[efgh]ijk[lmn]oppo"))
    }

    #[test]
    fn does_not_support_tls() {
        assert!( ! supports_tls("abcd[bddb]xyyx") );
        assert!( ! supports_tls("aaaa[qwer]tyui") );
        assert!( ! supports_tls("aaaa[qwer]tyui[foof]poop") );
    }

    #[test]
    fn does_contain_abba() {
        assert!(contains_abba("abba"));
        assert!(contains_abba("ioxxoj"));
    }

    #[test]
    fn does_not_contain_abba() {
        assert!( ! contains_abba("mnop") );
        assert!( ! contains_abba("aaaa") );
    }
}
<|endoftext|>