<commit_before>#![crate_id = "rust_js"]
#![crate_type = "lib"]
#![comment = "Rust Javascript parsing and interpretation library"]
#![license = "MIT"]
#![deny(deprecated_owned_vector)]
#![deny(non_uppercase_statics)]
#![deny(missing_doc)]
#![deny(unnecessary_parens)]
#![deny(unrecognized_lint)]
#![deny(unreachable_code)]
#![deny(unnecessary_allocation)]
#![deny(unnecessary_typecast)]
#![deny(unnecessary_allocation)]
#![deny(uppercase_variables)]
#![deny(non_camel_case_types)]
#![deny(unused_must_use)]

//! A Javascript Parser / Interpreter library
extern crate collections;
extern crate time;
extern crate serialize;
extern crate rand;
/// The Abstract Syntax Tree module
pub mod ast;
/// The lexing module
pub mod lexer;
/// The parsing module
pub mod parser;
/// The execution module
pub mod exec;
/// The javascript core library module
pub mod js {
	/// Contains the Javascript value
	pub mod value;
	/// Functions
	pub mod function;
	/// Contains the Javascript object
	pub mod object;
	/// Contains the Javascript array
	pub mod array;
	/// The global console object
	pub mod console;
	/// The global math object
	pub mod math;
	/// The global JSON object
	pub mod json;
	/// Errors
	pub mod error;
}<commit_msg>Remove lint for managed vectors so JSON can be parsed<commit_after>#![crate_id = "rust_js"]
#![crate_type = "lib"]
#![comment = "Rust Javascript parsing and interpretation library"]
#![license = "MIT"]
#![deny(non_uppercase_statics)]
#![deny(missing_doc)]
#![deny(unnecessary_parens)]
#![deny(unrecognized_lint)]
#![deny(unreachable_code)]
#![deny(unnecessary_allocation)]
#![deny(unnecessary_typecast)]
#![deny(unnecessary_allocation)]
#![deny(uppercase_variables)]
#![deny(non_camel_case_types)]
#![deny(unused_must_use)]

//! A Javascript Parser / Interpreter library
extern crate collections;
extern crate time;
extern crate serialize;
extern crate rand;
/// The Abstract Syntax Tree module
pub mod ast;
/// The lexing module
pub mod lexer;
/// The parsing module
pub mod parser;
/// The execution module
pub mod exec;
/// The javascript core library module
pub mod js {
	/// Contains the Javascript value
	pub mod value;
	/// Functions
	pub mod function;
	/// Contains the Javascript object
	pub mod object;
	/// Contains the Javascript array
	pub mod array;
	/// The global console object
	pub mod console;
	/// The global math object
	pub mod math;
	/// The global JSON object
	pub mod json;
	/// Errors
	pub mod error;
}<|endoftext|>


<commit_before>
#[macro_use] extern crate log;
#[macro_use] extern crate quick_error;

extern crate serde_json;
extern crate sodiumoxide;
extern crate rustc_serialize;
extern crate chrono;
extern crate openssl;
extern crate serde;

pub mod key;
pub mod signedjson;

use serde_json::builder;

pub fn sign_request_b64(
    key: &signedjson::SigningKey,
    method: String,
    uri: String,
    origin: String,
    destination: String,
    content: Option<&signedjson::Object>,
) -> String {
    let mut builder = builder::ObjectBuilder::new()
        .insert("method", method)
        .insert("uri", uri)
        .insert("origin", origin)
        .insert("destination", destination);

    if let Some(obj) = content {
        builder = builder.insert("content", obj.clone());
    }

    let val = builder.unwrap();

    let obj = val.as_object().unwrap();
    signedjson::get_sig_for_json_b64(key, obj).unwrap()
}

// struct MakeQuery {
//     signing_key: signedjson::SigningKey,
//     server_name: String,
// }
//
// impl MakeQuery {
//     fn make_query(&self) {
//         let path = "/_matrix/federation/v1/query/directory?room_alias=%23test%3Alocalhost%3A8480";
//         let url = "http://localhost:8080".to_string() + path;
//         let client = hyper::Client::new();
//
//         loop {
//             sleep(Duration::from_secs(5));
//
//             info!("Making request");
//
//             let sig = sign_request_b64(
//                 &self.signing_key,
//                 "GET".to_string(),
//                 path.to_string(),
//                 self.server_name.clone(),
//                 "localhost:8480".to_string(),
//                 None,
//             );
//
//             let auth_header = format!(
//                 r#"X-Matrix origin={},key="{}",sig="{}""#,
//                 &self.server_name, self.signing_key.key_id, sig,
//             );
//
//             let response_builder = client.get(&url)
//                 .header(hyper::header::Authorization(auth_header));
//
//             let resp = match response_builder.send() {
//                 Ok(response) => response,
//                 Err(e) => {
//                     error!("Got error when sending request: {}", e.description());
//                     continue;
//                 },
//             };
//
//             if !resp.status.is_success() {
//                 warn!("Got non-200 response: {}", resp.status);
//                 continue;
//             }
//
//             let val : value::Value = serde_json::from_reader(resp).expect("Invalid json response");
//             let room_id = val.find("room_id").expect("Expected room_id")
//                 .as_string().expect("Expected string");
//             println!("room_id: {}", room_id);
//             return;
//         }
//
//     }
// }
<commit_msg>Error handling<commit_after>
#[macro_use] extern crate log;
#[macro_use] extern crate quick_error;

extern crate serde_json;
extern crate sodiumoxide;
extern crate rustc_serialize;
extern crate chrono;
extern crate openssl;
extern crate serde;

pub mod key;
pub mod signedjson;

use serde_json::builder;

pub fn sign_request_b64(
    key: &signedjson::SigningKey,
    method: String,
    uri: String,
    origin: String,
    destination: String,
    content: Option<&signedjson::Object>,
) -> signedjson::Result<String> {
    let mut builder = builder::ObjectBuilder::new()
        .insert("method", method)
        .insert("uri", uri)
        .insert("origin", origin)
        .insert("destination", destination);

    if let Some(obj) = content {
        builder = builder.insert("content", obj.clone());
    }

    let val = builder.unwrap();

    let obj = val.as_object().unwrap();
    try!(signedjson::get_sig_for_json_b64(key, obj))
}

// struct MakeQuery {
//     signing_key: signedjson::SigningKey,
//     server_name: String,
// }
//
// impl MakeQuery {
//     fn make_query(&self) {
//         let path = "/_matrix/federation/v1/query/directory?room_alias=%23test%3Alocalhost%3A8480";
//         let url = "http://localhost:8080".to_string() + path;
//         let client = hyper::Client::new();
//
//         loop {
//             sleep(Duration::from_secs(5));
//
//             info!("Making request");
//
//             let sig = sign_request_b64(
//                 &self.signing_key,
//                 "GET".to_string(),
//                 path.to_string(),
//                 self.server_name.clone(),
//                 "localhost:8480".to_string(),
//                 None,
//             );
//
//             let auth_header = format!(
//                 r#"X-Matrix origin={},key="{}",sig="{}""#,
//                 &self.server_name, self.signing_key.key_id, sig,
//             );
//
//             let response_builder = client.get(&url)
//                 .header(hyper::header::Authorization(auth_header));
//
//             let resp = match response_builder.send() {
//                 Ok(response) => response,
//                 Err(e) => {
//                     error!("Got error when sending request: {}", e.description());
//                     continue;
//                 },
//             };
//
//             if !resp.status.is_success() {
//                 warn!("Got non-200 response: {}", resp.status);
//                 continue;
//             }
//
//             let val : value::Value = serde_json::from_reader(resp).expect("Invalid json response");
//             let room_id = val.find("room_id").expect("Expected room_id")
//                 .as_string().expect("Expected string");
//             println!("room_id: {}", room_id);
//             return;
//         }
//
//     }
// }
<|endoftext|>


<commit_before>// Copyright 2015 The tiny-http Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/*!
# Simple usage

## Creating the server

The easiest way to create a server is to call `Server::http()`.

The `http()` function returns an `IoResult<Server>` which will return an error
in the case where the server creation fails (for example if the listening port is already
occupied).

```no_run
let server = tiny_http::Server::http("0.0.0.0:0").unwrap();
```

A newly-created `Server` will immediatly start listening for incoming connections and HTTP
requests.

## Receiving requests

Calling `server.recv()` will block until the next request is available.
This function returns an `IoResult<Request>`, so you need to handle the possible errors.

```no_run
# let server = tiny_http::Server::http("0.0.0.0:0").unwrap();

loop {
    // blocks until the next request is received
    let request = match server.recv() {
        Ok(rq) => rq,
        Err(e) => { println!("error: {}", e); break }
    };

    // do something with the request
    // ...
}
```

In a real-case scenario, you will probably want to spawn multiple worker tasks and call
`server.recv()` on all of them. Like this:

```no_run
# use std::sync::Arc;
# use std::thread;
# let server = tiny_http::Server::http("0.0.0.0:0").unwrap();
let server = Arc::new(server);
let mut guards = Vec::with_capacity(4);

for _ in (0 .. 4) {
    let server = server.clone();

    let guard = thread::spawn(move || {
        loop {
            let rq = server.recv().unwrap();

            // ...
        }
    });

    guards.push(guard);
}
```

If you don't want to block, you can call `server.try_recv()` instead.

## Handling requests

The `Request` object returned by `server.recv()` contains informations about the client's request.
The most useful methods are probably `request.method()` and `request.url()` which return
the requested method (`GET`, `POST`, etc.) and url.

To handle a request, you need to create a `Response` object. See the docs of this object for
more infos. Here is an example of creating a `Response` from a file:

```no_run
# use std::fs::File;
# use std::path::Path;
let response = tiny_http::Response::from_file(File::open(&Path::new("image.png")).unwrap());
```

All that remains to do is call `request.respond()`:

```no_run
# use std::fs::File;
# use std::path::Path;
# let server = tiny_http::Server::http("0.0.0.0:0").unwrap();
# let request = server.recv().unwrap();
# let response = tiny_http::Response::from_file(File::open(&Path::new("image.png")).unwrap());
let _ = request.respond(response);
```
*/
#![crate_name = "tiny_http"]
#![crate_type = "lib"]
#![forbid(unsafe_code)]

#[macro_use]
extern crate log;

extern crate ascii;
extern crate chunked_transfer;
extern crate encoding;
extern crate url;
extern crate chrono;

#[cfg(feature = "ssl")]
extern crate openssl;

use std::error::Error;
use std::io::Error as IoError;
use std::io::Result as IoResult;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use std::thread;
use std::net;
use std::net::ToSocketAddrs;
use std::time::Duration;
use std::sync::atomic::Ordering::Relaxed;

use client::ClientConnection;
use util::MessagesQueue;

pub use common::{Header, HeaderField, HTTPVersion, Method, StatusCode};
pub use request::Request;
pub use response::{ResponseBox, Response};

mod client;
mod common;
mod request;
mod response;

#[allow(dead_code)]     // TODO: remove when everything is implemented
mod util;

/// The main class of this library.
///
/// Destroying this object will immediatly close the listening socket annd the reading
///  part of all the client's connections. Requests that have already been returned by
///  the `recv()` function will not close and the responses will be transferred to the client.
pub struct Server {
    // should be false as long as the server exists
    // when set to true, all the subtasks will close within a few hundreds ms
    close: Arc<AtomicBool>,

    // queue for messages received by child threads
    messages: Arc<MessagesQueue<Message>>,

    // result of TcpListener::local_addr()
    listening_addr: net::SocketAddr,
}

enum Message {
    Error(IoError),
    NewRequest(Request),
}

impl From<IoError> for Message {
    fn from(e: IoError) -> Message {
        Message::Error(e)
    }
}

impl From<Request> for Message {
    fn from(rq: Request) -> Message {
        Message::NewRequest(rq)
    }
}

// this trait is to make sure that Server implements Share and Send
#[doc(hidden)]
trait MustBeShareDummy : Sync + Send {}
#[doc(hidden)]
impl MustBeShareDummy for Server {}

pub struct IncomingRequests<'a> {
    server: &'a Server
}

/// Represents the parameters required to create a server.
#[derive(Debug, Clone)]
pub struct ServerConfig<A> where A: ToSocketAddrs {
    /// The addresses to listen to.
    pub addr: A,

    /// If `Some`, then the server will use SSL to encode the communications.
    pub ssl: Option<SslConfig>,
}

/// Configuration of the server for SSL.
#[derive(Debug, Clone)]
pub struct SslConfig {
    /// Contains the public certificate to send to clients.
    pub certificate: Vec<u8>,
    /// Contains the ultra-secret private key used to decode communications.
    pub private_key: Vec<u8>,
}

impl Server {
    /// Shortcut for a simple server on a specific address.
    #[inline]
    pub fn http<A>(addr: A) -> Result<Server, Box<Error + Send + Sync + 'static>>
        where A: ToSocketAddrs
    {
        Server::new(ServerConfig {
            addr: addr,
            ssl: None,
        })
    }

    /// Shortcut for an HTTPS server on a specific address.
    #[cfg(feature = "ssl")]
    #[inline]
    pub fn https<A>(addr: A, config: SslConfig)
                    -> Result<Server, Box<Error + Send + Sync + 'static>>
        where A: ToSocketAddrs
    {
        Server::new(ServerConfig {
            addr: addr,
            ssl: Some(config),
        })
    }

    /// Builds a new server that listens on the specified address.
    pub fn new<A>(config: ServerConfig<A>) -> Result<Server, Box<Error + Send + Sync + 'static>>
        where A: ToSocketAddrs
    {
        // building the "close" variable
        let close_trigger = Arc::new(AtomicBool::new(false));

        // building the TcpListener
        let (server, local_addr) = {
            let listener = try!(net::TcpListener::bind(config.addr));
            let local_addr = try!(listener.local_addr());
            debug!("Server listening on {}", local_addr);
            (listener, local_addr)
        };

        // building the SSL capabilities
        #[cfg(feature = "ssl")]
        type SslContext = openssl::ssl::SslContext;
        #[cfg(not(feature = "ssl"))]
        type SslContext = ();
        let ssl: Option<SslContext> = match config.ssl {
            #[cfg(feature = "ssl")]
            Some(mut config) => {
                use std::io::Cursor;
                use openssl::ssl;
                use openssl::x509::X509;
                use openssl::crypto::pkey::PKey;
                use openssl::ssl::SSL_VERIFY_NONE;

                let mut ctxt = try!(SslContext::new(ssl::SslMethod::Sslv23));
                try!(ctxt.set_cipher_list("DEFAULT"));
                let certificate = try!(X509::from_pem(&mut Cursor::new(&config.certificate[..])));
                try!(ctxt.set_certificate(&certificate));
                let private_key = try!(PKey::private_key_from_pem(&mut Cursor::new(&config.private_key[..])));
                try!(ctxt.set_private_key(&private_key));
                ctxt.set_verify(SSL_VERIFY_NONE, None);
                try!(ctxt.check_private_key());

                // let's wipe the certificate and private key from memory, because we're
                // better safe than sorry
                for b in &mut config.certificate { *b = 0; }
                for b in &mut config.private_key { *b = 0; }

                Some(ctxt)
            },
            #[cfg(not(feature = "ssl"))]
            Some(_) => return Err("Building a server with SSL requires enabling the `ssl` feature \
                                   in tiny-http".to_owned().into()),
            None => None,
        };

        // creating a task where server.accept() is continuously called
        // and ClientConnection objects are pushed in the messages queue
        let messages = MessagesQueue::with_capacity(8);

        let inside_close_trigger = close_trigger.clone();
        let inside_messages = messages.clone();
        thread::spawn(move || {
            // a tasks pool is used to dispatch the connections into threads
            let tasks_pool = util::TaskPool::new();

            debug!("Running accept thread");
            while !inside_close_trigger.load(Relaxed) {
                let new_client = match server.accept() {
                    Ok((sock, _)) => {
                        use util::RefinedTcpStream;

                        let (read_closable, write_closable) = match ssl {
                            None => {
                                RefinedTcpStream::new(sock)
                            },
                            #[cfg(feature = "ssl")]
                            Some(ref ssl) => {
                                // trying to apply SSL over the connection
                                // if an error occurs, we just close the socket and resume listening
                                let sock = match openssl::ssl::SslStream::accept(ssl, sock) {
                                    Ok(s) => s,
                                    Err(_) => continue
                                };

                                RefinedTcpStream::new(sock)
                            },
                            #[cfg(not(feature = "ssl"))]
                            Some(_) => unreachable!(),
                        };

                        Ok(ClientConnection::new(write_closable, read_closable))
                    },
                    Err(e) => Err(e),
                };

                match new_client {
                    Ok(client) => {
                        let messages = inside_messages.clone();
                        let mut client = Some(client);
                        tasks_pool.spawn(Box::new(move || {
                            if let Some(client) = client.take() {
                                for rq in client {
                                    messages.push(rq.into());
                                }
                            }
                        }));
                    },

                    Err(e) => {
                        error!("Error accepting new client: {}", e);
                        inside_messages.push(e.into());
                        break;
                    }
                }
            }
            debug!("Terminating accept thread");
        });

        // result
        Ok(Server {
            messages: messages,
            close: close_trigger,
            listening_addr: local_addr,
        })
    }

    /// Returns an iterator for all the incoming requests.
    ///
    /// The iterator will return `None` if the server socket is shutdown.
    #[inline]
    pub fn incoming_requests(&self) -> IncomingRequests {
        IncomingRequests { server: self }
    }

    /// Returns the address the server is listening to.
    #[inline]
    pub fn server_addr(&self) -> net::SocketAddr {
        self.listening_addr.clone()
    }

    /// Returns the number of clients currently connected to the server.
    pub fn num_connections(&self) -> usize {
        unimplemented!()
        //self.requests_receiver.lock().len()
    }

    /// Blocks until an HTTP request has been submitted and returns it.
    pub fn recv(&self) -> IoResult<Request> {
        match self.messages.pop() {
            Message::Error(err) => return Err(err),
            Message::NewRequest(rq) => return Ok(rq),
        }
    }

    /// Same as `recv()` but doesn't block longer than timeout
    pub fn recv_timeout(&self, timeout: Duration) -> IoResult<Option<Request>> {
        match self.messages.pop_timeout(timeout) {
            Some(Message::Error(err)) => return Err(err),
            Some(Message::NewRequest(rq)) => return Ok(Some(rq)),
            None => return Ok(None)
        }
    }

    /// Same as `recv()` but doesn't block.
    pub fn try_recv(&self) -> IoResult<Option<Request>> {
        match self.messages.try_pop() {
            Some(Message::Error(err)) => return Err(err),
            Some(Message::NewRequest(rq)) => return Ok(Some(rq)),
            None => return Ok(None)
        }
    }
}

impl<'a> Iterator for IncomingRequests<'a> {
    type Item = Request;
    fn next(&mut self) -> Option<Request> {
        self.server.recv().ok()
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        self.close.store(true, Relaxed);
    }
}
<commit_msg>Unblock the accept thread on shutdown<commit_after>// Copyright 2015 The tiny-http Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/*!
# Simple usage

## Creating the server

The easiest way to create a server is to call `Server::http()`.

The `http()` function returns an `IoResult<Server>` which will return an error
in the case where the server creation fails (for example if the listening port is already
occupied).

```no_run
let server = tiny_http::Server::http("0.0.0.0:0").unwrap();
```

A newly-created `Server` will immediatly start listening for incoming connections and HTTP
requests.

## Receiving requests

Calling `server.recv()` will block until the next request is available.
This function returns an `IoResult<Request>`, so you need to handle the possible errors.

```no_run
# let server = tiny_http::Server::http("0.0.0.0:0").unwrap();

loop {
    // blocks until the next request is received
    let request = match server.recv() {
        Ok(rq) => rq,
        Err(e) => { println!("error: {}", e); break }
    };

    // do something with the request
    // ...
}
```

In a real-case scenario, you will probably want to spawn multiple worker tasks and call
`server.recv()` on all of them. Like this:

```no_run
# use std::sync::Arc;
# use std::thread;
# let server = tiny_http::Server::http("0.0.0.0:0").unwrap();
let server = Arc::new(server);
let mut guards = Vec::with_capacity(4);

for _ in (0 .. 4) {
    let server = server.clone();

    let guard = thread::spawn(move || {
        loop {
            let rq = server.recv().unwrap();

            // ...
        }
    });

    guards.push(guard);
}
```

If you don't want to block, you can call `server.try_recv()` instead.

## Handling requests

The `Request` object returned by `server.recv()` contains informations about the client's request.
The most useful methods are probably `request.method()` and `request.url()` which return
the requested method (`GET`, `POST`, etc.) and url.

To handle a request, you need to create a `Response` object. See the docs of this object for
more infos. Here is an example of creating a `Response` from a file:

```no_run
# use std::fs::File;
# use std::path::Path;
let response = tiny_http::Response::from_file(File::open(&Path::new("image.png")).unwrap());
```

All that remains to do is call `request.respond()`:

```no_run
# use std::fs::File;
# use std::path::Path;
# let server = tiny_http::Server::http("0.0.0.0:0").unwrap();
# let request = server.recv().unwrap();
# let response = tiny_http::Response::from_file(File::open(&Path::new("image.png")).unwrap());
let _ = request.respond(response);
```
*/
#![crate_name = "tiny_http"]
#![crate_type = "lib"]
#![forbid(unsafe_code)]

#[macro_use]
extern crate log;

extern crate ascii;
extern crate chunked_transfer;
extern crate encoding;
extern crate url;
extern crate chrono;

#[cfg(feature = "ssl")]
extern crate openssl;

use std::error::Error;
use std::io::Error as IoError;
use std::io::Result as IoResult;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use std::thread;
use std::net;
use std::net::{ToSocketAddrs, TcpStream, Shutdown};
use std::time::Duration;
use std::sync::atomic::Ordering::Relaxed;

use client::ClientConnection;
use util::MessagesQueue;

pub use common::{Header, HeaderField, HTTPVersion, Method, StatusCode};
pub use request::Request;
pub use response::{ResponseBox, Response};

mod client;
mod common;
mod request;
mod response;

#[allow(dead_code)]     // TODO: remove when everything is implemented
mod util;

/// The main class of this library.
///
/// Destroying this object will immediatly close the listening socket annd the reading
///  part of all the client's connections. Requests that have already been returned by
///  the `recv()` function will not close and the responses will be transferred to the client.
pub struct Server {
    // should be false as long as the server exists
    // when set to true, all the subtasks will close within a few hundreds ms
    close: Arc<AtomicBool>,

    // queue for messages received by child threads
    messages: Arc<MessagesQueue<Message>>,

    // result of TcpListener::local_addr()
    listening_addr: net::SocketAddr,
}

enum Message {
    Error(IoError),
    NewRequest(Request),
}

impl From<IoError> for Message {
    fn from(e: IoError) -> Message {
        Message::Error(e)
    }
}

impl From<Request> for Message {
    fn from(rq: Request) -> Message {
        Message::NewRequest(rq)
    }
}

// this trait is to make sure that Server implements Share and Send
#[doc(hidden)]
trait MustBeShareDummy : Sync + Send {}
#[doc(hidden)]
impl MustBeShareDummy for Server {}

pub struct IncomingRequests<'a> {
    server: &'a Server
}

/// Represents the parameters required to create a server.
#[derive(Debug, Clone)]
pub struct ServerConfig<A> where A: ToSocketAddrs {
    /// The addresses to listen to.
    pub addr: A,

    /// If `Some`, then the server will use SSL to encode the communications.
    pub ssl: Option<SslConfig>,
}

/// Configuration of the server for SSL.
#[derive(Debug, Clone)]
pub struct SslConfig {
    /// Contains the public certificate to send to clients.
    pub certificate: Vec<u8>,
    /// Contains the ultra-secret private key used to decode communications.
    pub private_key: Vec<u8>,
}

impl Server {
    /// Shortcut for a simple server on a specific address.
    #[inline]
    pub fn http<A>(addr: A) -> Result<Server, Box<Error + Send + Sync + 'static>>
        where A: ToSocketAddrs
    {
        Server::new(ServerConfig {
            addr: addr,
            ssl: None,
        })
    }

    /// Shortcut for an HTTPS server on a specific address.
    #[cfg(feature = "ssl")]
    #[inline]
    pub fn https<A>(addr: A, config: SslConfig)
                    -> Result<Server, Box<Error + Send + Sync + 'static>>
        where A: ToSocketAddrs
    {
        Server::new(ServerConfig {
            addr: addr,
            ssl: Some(config),
        })
    }

    /// Builds a new server that listens on the specified address.
    pub fn new<A>(config: ServerConfig<A>) -> Result<Server, Box<Error + Send + Sync + 'static>>
        where A: ToSocketAddrs
    {
        // building the "close" variable
        let close_trigger = Arc::new(AtomicBool::new(false));

        // building the TcpListener
        let (server, local_addr) = {
            let listener = try!(net::TcpListener::bind(config.addr));
            let local_addr = try!(listener.local_addr());
            debug!("Server listening on {}", local_addr);
            (listener, local_addr)
        };

        // building the SSL capabilities
        #[cfg(feature = "ssl")]
        type SslContext = openssl::ssl::SslContext;
        #[cfg(not(feature = "ssl"))]
        type SslContext = ();
        let ssl: Option<SslContext> = match config.ssl {
            #[cfg(feature = "ssl")]
            Some(mut config) => {
                use std::io::Cursor;
                use openssl::ssl;
                use openssl::x509::X509;
                use openssl::crypto::pkey::PKey;
                use openssl::ssl::SSL_VERIFY_NONE;

                let mut ctxt = try!(SslContext::new(ssl::SslMethod::Sslv23));
                try!(ctxt.set_cipher_list("DEFAULT"));
                let certificate = try!(X509::from_pem(&mut Cursor::new(&config.certificate[..])));
                try!(ctxt.set_certificate(&certificate));
                let private_key = try!(PKey::private_key_from_pem(&mut Cursor::new(&config.private_key[..])));
                try!(ctxt.set_private_key(&private_key));
                ctxt.set_verify(SSL_VERIFY_NONE, None);
                try!(ctxt.check_private_key());

                // let's wipe the certificate and private key from memory, because we're
                // better safe than sorry
                for b in &mut config.certificate { *b = 0; }
                for b in &mut config.private_key { *b = 0; }

                Some(ctxt)
            },
            #[cfg(not(feature = "ssl"))]
            Some(_) => return Err("Building a server with SSL requires enabling the `ssl` feature \
                                   in tiny-http".to_owned().into()),
            None => None,
        };

        // creating a task where server.accept() is continuously called
        // and ClientConnection objects are pushed in the messages queue
        let messages = MessagesQueue::with_capacity(8);

        let inside_close_trigger = close_trigger.clone();
        let inside_messages = messages.clone();
        thread::spawn(move || {
            // a tasks pool is used to dispatch the connections into threads
            let tasks_pool = util::TaskPool::new();

            debug!("Running accept thread");
            while !inside_close_trigger.load(Relaxed) {
                let new_client = match server.accept() {
                    Ok((sock, _)) => {
                        use util::RefinedTcpStream;
                        let (read_closable, write_closable) = match ssl {
                            None => {
                                RefinedTcpStream::new(sock)
                            },
                            #[cfg(feature = "ssl")]
                            Some(ref ssl) => {
                                // trying to apply SSL over the connection
                                // if an error occurs, we just close the socket and resume listening
                                let sock = match openssl::ssl::SslStream::accept(ssl, sock) {
                                    Ok(s) => s,
                                    Err(_) => continue
                                };

                                RefinedTcpStream::new(sock)
                            },
                            #[cfg(not(feature = "ssl"))]
                            Some(_) => unreachable!(),
                        };

                        Ok(ClientConnection::new(write_closable, read_closable))
                    },
                    Err(e) => Err(e),
                };

                match new_client {
                    Ok(client) => {
                        let messages = inside_messages.clone();
                        let mut client = Some(client);
                        tasks_pool.spawn(Box::new(move || {
                            if let Some(client) = client.take() {
                                for rq in client {
                                    messages.push(rq.into());
                                }
                            }
                        }));
                    },

                    Err(e) => {
                        error!("Error accepting new client: {}", e);
                        inside_messages.push(e.into());
                        break;
                    }
                }
            }
            debug!("Terminating accept thread");
        });

        // result
        Ok(Server {
            messages: messages,
            close: close_trigger,
            listening_addr: local_addr,
        })
    }

    /// Returns an iterator for all the incoming requests.
    ///
    /// The iterator will return `None` if the server socket is shutdown.
    #[inline]
    pub fn incoming_requests(&self) -> IncomingRequests {
        IncomingRequests { server: self }
    }

    /// Returns the address the server is listening to.
    #[inline]
    pub fn server_addr(&self) -> net::SocketAddr {
        self.listening_addr.clone()
    }

    /// Returns the number of clients currently connected to the server.
    pub fn num_connections(&self) -> usize {
        unimplemented!()
        //self.requests_receiver.lock().len()
    }

    /// Blocks until an HTTP request has been submitted and returns it.
    pub fn recv(&self) -> IoResult<Request> {
        match self.messages.pop() {
            Message::Error(err) => return Err(err),
            Message::NewRequest(rq) => return Ok(rq),
        }
    }

    /// Same as `recv()` but doesn't block longer than timeout
    pub fn recv_timeout(&self, timeout: Duration) -> IoResult<Option<Request>> {
        match self.messages.pop_timeout(timeout) {
            Some(Message::Error(err)) => return Err(err),
            Some(Message::NewRequest(rq)) => return Ok(Some(rq)),
            None => return Ok(None)
        }
    }

    /// Same as `recv()` but doesn't block.
    pub fn try_recv(&self) -> IoResult<Option<Request>> {
        match self.messages.try_pop() {
            Some(Message::Error(err)) => return Err(err),
            Some(Message::NewRequest(rq)) => return Ok(Some(rq)),
            None => return Ok(None)
        }
    }
}

impl<'a> Iterator for IncomingRequests<'a> {
    type Item = Request;
    fn next(&mut self) -> Option<Request> {
        self.server.recv().ok()
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        self.close.store(true, Relaxed);
        // Connect briefly to ourselves to unblock the accept thread
        let maybe_stream = TcpStream::connect(self.listening_addr);
        if let Ok(stream) = maybe_stream {
            let _ = stream.shutdown(Shutdown::Both);
        }
    }
}
<|endoftext|>


<commit_before>#![warn(bad_style, missing_docs,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results)]

#![feature(into_cow)]

extern crate oauth_client as oauth;

use std::borrow::{Cow, IntoCow};
use std::collections::HashMap;
use oauth::Token;

mod api {
    pub const REQUEST_TOKEN: &'static str   = "https://api.twitter.com/oauth/request_token";
    pub const AUTHORIZE: &'static str       = "https://api.twitter.com/oauth/authorize";
    pub const ACCESS_TOKEN: &'static str    = "https://api.twitter.com/oauth/access_token";
    pub const STATUSES_UPDATE: &'static str = "https://api.twitter.com/1.1/statuses/update.json";
}

fn split_query<'a>(query: &'a str) -> HashMap<Cow<'a, str>, Cow<'a, str>> {
    let mut param = HashMap::new();
    for q in query.split('&') {
        let mut s = q.splitn(2, '=');
        let k = s.next().unwrap();
        let v = s.next().unwrap();
        let _ = param.insert(k.into_cow(), v.into_cow());
    }
    param
}

pub fn get_request_token(consumer: &Token) -> Token<'static> {
    let resp = oauth::get(api::REQUEST_TOKEN, consumer, None, None);
    let param = split_query(&resp);
    Token::new(param.get("oauth_token").unwrap().to_string(),
               param.get("oauth_token_secret").unwrap().to_string())
}

pub fn get_authorize_url(request: &Token) -> String {
    format!("{}?oauth_token={}", api::AUTHORIZE, request.key)
}

pub fn get_access_token(consumer: &Token, request: &Token, pin: &str) -> Token<'static> {
    let mut param = HashMap::new();
    let _ = param.insert("oauth_verifier".into_cow(), pin.into_cow());
    let resp = oauth::get(api::ACCESS_TOKEN, consumer, Some(request), Some(&param));
    let param = split_query(&resp);
    Token::new(param.get("oauth_token").unwrap().to_string(),
               param.get("oauth_token_secret").unwrap().to_string())
}

/// function to update the status
/// This function takes as arguments the consumer key, the access key, and the status (obviously)
pub fn update_status(consumer: &Token, access: &Token, status: &str) {
    let mut param = HashMap::new();
    let _ = param.insert("status".into_cow(), status.into_cow());
    let _ = oauth::post(api::STATUSES_UPDATE, consumer, Some(access), Some(&param));
}
<commit_msg>src/lib.rs : Differenciation between api software and api oauth<commit_after>#![warn(bad_style, missing_docs,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results)]

#![feature(into_cow)]

extern crate oauth_client as oauth;

use std::borrow::{Cow, IntoCow};
use std::collections::HashMap;
use oauth::Token;

mod api_twitter_oauth {
    pub const REQUEST_TOKEN: &'static str   = "https://api.twitter.com/oauth/request_token";
    pub const AUTHORIZE: &'static str       = "https://api.twitter.com/oauth/authorize";
    pub const ACCESS_TOKEN: &'static str    = "https://api.twitter.com/oauth/access_token";
}

mod api_twitter_soft {
    pub const STATUSES_UPDATE: &'static str = "https://api.twitter.com/1.1/statuses/update.json";
}

fn split_query<'a>(query: &'a str) -> HashMap<Cow<'a, str>, Cow<'a, str>> {
    let mut param = HashMap::new();
    for q in query.split('&') {
        let mut s = q.splitn(2, '=');
        let k = s.next().unwrap();
        let v = s.next().unwrap();
        let _ = param.insert(k.into_cow(), v.into_cow());
    }
    param
}

pub fn get_request_token(consumer: &Token) -> Token<'static> {
    let resp = oauth::get(api_twitter_oauth::REQUEST_TOKEN, consumer, None, None);
    let param = split_query(&resp);
    Token::new(param.get("oauth_token").unwrap().to_string(),
               param.get("oauth_token_secret").unwrap().to_string())
}

pub fn get_authorize_url(request: &Token) -> String {
    format!("{}?oauth_token={}", api_twitter_oauth::AUTHORIZE, request.key)
}

pub fn get_access_token(consumer: &Token, request: &Token, pin: &str) -> Token<'static> {
    let mut param = HashMap::new();
    let _ = param.insert("oauth_verifier".into_cow(), pin.into_cow());
    let resp = oauth::get(api_twitter_oauth::ACCESS_TOKEN, consumer, Some(request), Some(&param));
    let param = split_query(&resp);
    Token::new(param.get("oauth_token").unwrap().to_string(),
               param.get("oauth_token_secret").unwrap().to_string())
}

/// function to update the status
/// This function takes as arguments the consumer key, the access key, and the status (obviously)
pub fn update_status(consumer: &Token, access: &Token, status: &str) {
    let mut param = HashMap::new();
    let _ = param.insert("status".into_cow(), status.into_cow());
    let _ = oauth::post(api_twitter_soft::STATUSES_UPDATE, consumer, Some(access), Some(&param));
}
}
<|endoftext|>


<commit_before>extern crate petgraph;

// XXX: Self-loops?

use petgraph::{Graph, Directed};
use petgraph::graph::{NodeIndex, IndexType};
use std::collections::HashSet;
use std::hash::Hash;

#[repr(u8)]
#[derive(Debug)]
pub enum TriadType {
    T003 = 0,
    T012,
    T102,
    T021D,

    T021U,
    T021C,
    T111D,
    T111U,

    T030T,
    T030C,
    T201,
    T120D,

    T120U,
    T120C,
    T210,
    T300,
}

impl TriadType {
    #[inline(always)]
    fn from_u8(i: u8) -> TriadType {
        use std::mem;
        assert!(i < 16);
        unsafe { mem::transmute(i) }
    }
}

fn tricode<N, E, I: IndexType>(graph: &Graph<N, E, Directed, I>,
                               v: NodeIndex<I>,
                               u: NodeIndex<I>,
                               w: NodeIndex<I>)
                               -> usize {
    let mut tricode = 0;
    if let Some(_) = graph.find_edge(v, u) {
        tricode |= 1 << 0;
    }
    if let Some(_) = graph.find_edge(u, v) {
        tricode |= 1 << 1;
    }
    if let Some(_) = graph.find_edge(v, w) {
        tricode |= 1 << 2;
    }
    if let Some(_) = graph.find_edge(w, v) {
        tricode |= 1 << 3;
    }
    if let Some(_) = graph.find_edge(u, w) {
        tricode |= 1 << 4;
    }
    if let Some(_) = graph.find_edge(w, u) {
        tricode |= 1 << 5;
    }
    return tricode;
}

const TRITYPES: [u8; 64] = [0, 1, 1, 2, 1, 3, 5, 7, 1, 5, 4, 6, 2, 7, 6, 10, 1, 5, 3, 7, 4, 8, 8,
                            12, 5, 9, 8, 13, 6, 13, 11, 14, 1, 4, 5, 6, 5, 8, 9, 13, 3, 8, 8, 11,
                            7, 12, 13, 14, 2, 6, 7, 10, 6, 11, 13, 14, 7, 13, 12, 14, 10, 14, 14,
                            15];

#[derive(Debug)]
pub struct TriadicCensus {
    census: [u64; 16],
}

impl TriadicCensus {
    /// Calculates the `distance` between two TriadicCensus structs, treated as
    /// points in a 16-dimensional space.
    pub fn distance(a: &TriadicCensus, b: &TriadicCensus) -> f64 {
        let mut sum = 0.0f64;
        for i in 0..16 {
            let va = a.census[i];
            let vb = b.census[i];
            let diff = (if va > vb {
                va - vb
            } else {
                vb - va
            }) as f64;
            sum += diff * diff;
        }
        sum.sqrt()
    }

    #[inline(always)]
    fn new() -> TriadicCensus {
        TriadicCensus { census: [0; 16] }
    }

    #[inline(always)]
    fn add(&mut self, triad_type: TriadType, cnt: u64) {
        self.census[triad_type as usize] += cnt;
    }

    #[inline(always)]
    fn set(&mut self, triad_type: TriadType, cnt: u64) {
        self.census[triad_type as usize] = cnt;
    }

    #[inline(always)]
    pub fn get(&self, triad_type: TriadType) -> u64 {
        self.census[triad_type as usize]
    }

    #[inline(always)]
    pub fn as_slice<'a>(&'a self) -> &'a [u64] {
        &self.census[..]
    }

    /// XXX: Optimize: find_edge() is O(k) with k the number of edges.
    pub fn from_graph<N, E, I: IndexType + Hash>(graph: &Graph<N, E, Directed, I>) -> TriadicCensus {
        let n = graph.node_count();

        let mut census = TriadicCensus::new();

        for i in 0..n {
            let v = NodeIndex::new(i);

            let mut neighbors_v = HashSet::new();
            for u in graph.neighbors_undirected(v) {
                if v < u {
                    neighbors_v.insert(u);
                }
            }

            for u in neighbors_v {
                let mut s = HashSet::new();
                for nu in graph.neighbors_undirected(u) {
                    s.insert(nu);
                }
                for nv in graph.neighbors_undirected(v) {
                    s.insert(nv);
                }
                let _ = s.remove(&u);
                let _ = s.remove(&v);

                let tri_type = if graph.find_edge(v, u).is_some() &&
                                  graph.find_edge(u, v).is_some() {
                    TriadType::T102
                } else {
                    TriadType::T012
                };

                let cnt = n as i64 - s.len() as i64 - 2;
                assert!(cnt >= 0);
                census.add(tri_type, cnt as u64);
                for w in s {
                    if u < w ||
                       (v < w && w < u &&
                        !(graph.find_edge(v, w).is_some() || graph.find_edge(w, v).is_some())) {
                        let tri_type = TriadType::from_u8(TRITYPES[tricode(graph, v, u, w)]);
                        census.add(tri_type, 1);
                    }
                }
            }
        }

        let mut sum = 0;
        for &cnt in &census.as_slice()[1..] {
            sum += cnt;
        }
        let n = n as u64;
        // Integer division below is guaranteed to produce an integral result
        census.set(TriadType::T003, (n * (n - 1) * (n - 2)) / 6 - sum);
        return census;
    }
}

#[test]
fn test_simple() {
    let mut g: Graph<(), ()> = Graph::new();

    let n1 = g.add_node(());
    let n2 = g.add_node(());
    let n3 = g.add_node(());

    let c1 = TriadicCensus::from_graph(&g);
    assert_eq!(&[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c1.as_slice());

    g.add_edge(n1, n3, ());
    let c2 = TriadicCensus::from_graph(&g);
    assert_eq!(&[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c2.as_slice());

    let d = TriadicCensus::distance(&c1, &c2); // should be sqrt(2)
    assert!(d > 1.414 && d < 1.415);

    g.add_edge(n3, n1, ());
    let c3 = TriadicCensus::from_graph(&g);
    assert_eq!(&[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c3.as_slice());

    g.add_edge(n2, n3, ());
    let c4 = TriadicCensus::from_graph(&g);
    assert_eq!(&[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c4.as_slice());
}

#[cfg(test)]
fn line_graph(n: u32) -> Graph<(), (), Directed> {
    let mut g: Graph<(), (), Directed> = Graph::new();

    let mut prev = g.add_node(());
    for _ in 0..n - 1 {
        let cur = g.add_node(());
        g.add_edge(prev, cur, ());
        prev = cur;
    }
    return g;
}

#[cfg(test)]
fn circular_graph(n: u32) -> Graph<(), (), Directed> {
    let mut g: Graph<(), (), Directed> = Graph::new();

    let first = g.add_node(());
    let mut prev = first;
    for _ in 0..n - 1 {
        let cur = g.add_node(());
        g.add_edge(prev, cur, ());
        prev = cur;
    }
    g.add_edge(prev, first, ());
    return g;
}

#[test]
fn test_line_graph() {
    // Result compared with igraph.triad_census().
    let c = TriadicCensus::from_graph(&line_graph(20));
    assert_eq!(&[816, 306, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c.as_slice());

    let c = TriadicCensus::from_graph(&line_graph(40));
    assert_eq!(&[8436, 1406, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c.as_slice());
}

#[test]
fn test_circular_graph() {
    // Result compared with igraph.triad_census().
    let c = TriadicCensus::from_graph(&circular_graph(20));
    assert_eq!(&[800, 320, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c.as_slice());

    let c = TriadicCensus::from_graph(&circular_graph(40));
    assert_eq!(&[8400, 1440, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c.as_slice());

}
<commit_msg>Base implementation on trait DirectedGraph instead of using PetGraph directly<commit_after>extern crate petgraph;

// XXX: Self-loops?

use petgraph::{Graph, Directed};
use petgraph::graph::{NodeIndex, IndexType};
use std::collections::HashSet;

#[repr(u8)]
#[derive(Debug)]
pub enum TriadType {
    T003 = 0,
    T012,
    T102,
    T021D,

    T021U,
    T021C,
    T111D,
    T111U,

    T030T,
    T030C,
    T201,
    T120D,

    T120U,
    T120C,
    T210,
    T300,
}

impl TriadType {
    #[inline(always)]
    fn from_u8(i: u8) -> TriadType {
        use std::mem;
        assert!(i < 16);
        unsafe { mem::transmute(i) }
    }
}

pub type NodeIdx = usize;

/// Interface required for Triadic Census.
/// Nodes are externally represented by `NodeIdx`.
pub trait DirectedGraph {
    fn node_count(&self) -> NodeIdx;
    fn has_edge(&self, src: NodeIdx, dst: NodeIdx) -> bool;
    fn each_undirected_neighbor<F:FnMut(NodeIdx)>(&self, node: NodeIdx, callback: F);
}

fn tricode<G: DirectedGraph>(graph: &G,
                               v: NodeIdx,
                               u: NodeIdx,
                               w: NodeIdx)
                               -> usize {
    let mut tricode = 0;
    if graph.has_edge(v, u) {
        tricode |= 1 << 0;
    }
    if graph.has_edge(u, v) {
        tricode |= 1 << 1;
    }
    if graph.has_edge(v, w) {
        tricode |= 1 << 2;
    }
    if graph.has_edge(w, v) {
        tricode |= 1 << 3;
    }
    if graph.has_edge(u, w) {
        tricode |= 1 << 4;
    }
    if graph.has_edge(w, u) {
        tricode |= 1 << 5;
    }
    return tricode;
}

const TRITYPES: [u8; 64] = [0, 1, 1, 2, 1, 3, 5, 7, 1, 5, 4, 6, 2, 7, 6, 10, 1, 5, 3, 7, 4, 8, 8,
                            12, 5, 9, 8, 13, 6, 13, 11, 14, 1, 4, 5, 6, 5, 8, 9, 13, 3, 8, 8, 11,
                            7, 12, 13, 14, 2, 6, 7, 10, 6, 11, 13, 14, 7, 13, 12, 14, 10, 14, 14,
                            15];

#[derive(Debug)]
pub struct TriadicCensus {
    census: [u64; 16],
}

impl TriadicCensus {
    /// Calculates the `distance` between two TriadicCensus structs, treated as
    /// points in a 16-dimensional space.
    pub fn distance(a: &TriadicCensus, b: &TriadicCensus) -> f64 {
        let mut sum = 0.0f64;
        for i in 0..16 {
            let va = a.census[i];
            let vb = b.census[i];
            let diff = (if va > vb {
                va - vb
            } else {
                vb - va
            }) as f64;
            sum += diff * diff;
        }
        sum.sqrt()
    }

    #[inline(always)]
    fn new() -> TriadicCensus {
        TriadicCensus { census: [0; 16] }
    }

    #[inline(always)]
    fn add(&mut self, triad_type: TriadType, cnt: u64) {
        self.census[triad_type as usize] += cnt;
    }

    #[inline(always)]
    fn set(&mut self, triad_type: TriadType, cnt: u64) {
        self.census[triad_type as usize] = cnt;
    }

    #[inline(always)]
    pub fn get(&self, triad_type: TriadType) -> u64 {
        self.census[triad_type as usize]
    }

    #[inline(always)]
    pub fn as_slice<'a>(&'a self) -> &'a [u64] {
        &self.census[..]
    }

    /// XXX: Optimize: find_edge() is O(k) with k the number of edges.
    pub fn from_graph<G: DirectedGraph>(graph: &G) -> TriadicCensus {
        let n = graph.node_count();

        let mut census = TriadicCensus::new();

        for v in 0..n {
            let mut neighbors_v = HashSet::new();
            graph.each_undirected_neighbor(v, |u| if u > v { neighbors_v.insert(u); });

            for u in neighbors_v {
                let mut s = HashSet::new(); // XXX: Use bitset? // reuse
                graph.each_undirected_neighbor(u, |nu| {s.insert(nu);});
                graph.each_undirected_neighbor(v, |nv| {s.insert(nv);});
                let _ = s.remove(&u);
                let _ = s.remove(&v);

                let tri_type = if graph.has_edge(v, u) && graph.has_edge(u, v) {
                    TriadType::T102
                } else {
                    TriadType::T012
                };

                let cnt = n as i64 - s.len() as i64 - 2;
                assert!(cnt >= 0);
                census.add(tri_type, cnt as u64);
                for w in s {
                    if u < w ||
                       (v < w && w < u &&
                        !(graph.has_edge(v, w) || graph.has_edge(w, v))) {
                        let tri_type = TriadType::from_u8(TRITYPES[tricode(graph, v, u, w)]);
                        census.add(tri_type, 1);
                    }
                }
            }
        }

        let mut sum = 0;
        for &cnt in &census.as_slice()[1..] {
            sum += cnt;
        }
        let n = n as u64;
        // Integer division below is guaranteed to produce an integral result
        census.set(TriadType::T003, (n * (n - 1) * (n - 2)) / 6 - sum);
        return census;
    }
}

pub struct SimpleDiGraph {
    g: Graph<(), (), Directed>
}

impl SimpleDiGraph {
    pub fn new() -> SimpleDiGraph {
        SimpleDiGraph {g: Graph::new()}
    }

    pub fn add_node(&mut self) -> NodeIdx {
        self.g.add_node(()).index()
    }

    pub fn add_edge(&mut self, src: NodeIdx, dst: NodeIdx) {
        self.g.add_edge(NodeIndex::new(src), NodeIndex::new(dst), ());
    }
}

impl DirectedGraph for SimpleDiGraph {
    fn node_count(&self) -> NodeIdx {
        self.g.node_count()
    }

    #[inline]
    fn has_edge(&self, src: NodeIdx, dst: NodeIdx) -> bool {
        self.g.find_edge(NodeIndex::new(src), NodeIndex::new(dst)).is_some()
    }

    #[inline]
    fn each_undirected_neighbor<F:FnMut(NodeIdx)>(&self, node: NodeIdx, mut callback: F) {
        for n in self.g.neighbors_undirected(NodeIndex::new(node)) {
            callback(n.index())
        }
    }
}

#[test]
fn test_simple() {
    let mut g = SimpleDiGraph::new();

    let n1 = g.add_node();
    let n2 = g.add_node();
    let n3 = g.add_node();

    let c1 = TriadicCensus::from_graph(&g);
    assert_eq!(&[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c1.as_slice());

    g.add_edge(n1, n3);
    let c2 = TriadicCensus::from_graph(&g);
    assert_eq!(&[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c2.as_slice());

    let d = TriadicCensus::distance(&c1, &c2); // should be sqrt(2)
    assert!(d > 1.414 && d < 1.415);

    g.add_edge(n3, n1);
    let c3 = TriadicCensus::from_graph(&g);
    assert_eq!(&[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c3.as_slice());

    g.add_edge(n2, n3);
    let c4 = TriadicCensus::from_graph(&g);
    assert_eq!(&[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c4.as_slice());
}

#[cfg(test)]
fn line_graph(n: u32) -> SimpleDiGraph {
    let mut g = SimpleDiGraph::new();

    let mut prev = g.add_node();
    for _ in 0..n - 1 {
        let cur = g.add_node();
        g.add_edge(prev, cur);
        prev = cur;
    }
    return g;
}

#[cfg(test)]
fn circular_graph(n: u32) -> SimpleDiGraph {
    let mut g = SimpleDiGraph::new();

    let first = g.add_node();
    let mut prev = first;
    for _ in 0..n - 1 {
        let cur = g.add_node();
        g.add_edge(prev, cur);
        prev = cur;
    }
    g.add_edge(prev, first);
    return g;
}

#[test]
fn test_line_graph() {
    // Result compared with igraph.triad_census().
    let c = TriadicCensus::from_graph(&line_graph(20));
    assert_eq!(&[816, 306, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c.as_slice());

    let c = TriadicCensus::from_graph(&line_graph(40));
    assert_eq!(&[8436, 1406, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c.as_slice());
}

#[test]
fn test_circular_graph() {
    // Result compared with igraph.triad_census().
    let c = TriadicCensus::from_graph(&circular_graph(20));
    assert_eq!(&[800, 320, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c.as_slice());

    let c = TriadicCensus::from_graph(&circular_graph(40));
    assert_eq!(&[8400, 1440, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               c.as_slice());

}
<|endoftext|>


<commit_before>extern mod extra;
use std::rand;
use std::vec;
use std::num;
use extra::sort;

/**
 * Arbitrary is a trait for types that you can generate arbitrary
 * instances of. You should also be able to ask for their size, so
 * you can report small failing examples instead of large ones.
 *
 */
trait Arbitrary : Clone {
    fn gen() -> Self;
    fn size(&self) -> uint;
}

impl Arbitrary for uint {
    fn gen() -> uint {
        let n : uint = rand::random();
         n % num::pow_with_uint(2,10)
    }
    fn size(&self) -> uint {
        self.clone()
    }
}

impl Arbitrary for int {
    fn gen() -> int {
        let n : int = rand::random();
        n % num::pow_with_uint(2,10)
    }

    fn size(&self) -> uint {
        self.clone().to_uint()
    }
}

impl<T:Arbitrary> Arbitrary for ~[T] {
    fn gen() -> ~[T] {
        let _n : uint = rand::random();
        let n = _n % 100;
        vec::build_sized(n, |p| {
            for n.times {
                p(Arbitrary::gen());
            }
        })
    }

    fn size(&self) -> uint {
        self.len()
    }
}

/**
 * quick_check
 *   description: a string describing what the property being tested is
 *   f: function that takes arbitrary input and returns whether
 *      the invariant held.
 *
 *   returns whether all the tests passed.
 */
fn quick_check<T:Arbitrary>(description : &str,
                            f : extern fn(T) -> bool) -> bool {
    let num_tests = 100;
    let mut passing = 0;
    let mut failed = ~[];
    for num_tests.times {
        let t : T = Arbitrary::gen();
        if f(t.clone()) {
            passing += 1;
        } else {
            failed.push(t);
        }
    }
    if passing == num_tests {
        println(fmt!("+++ OK, passed 100 tests for %s", description));
        return true;
    } else {
        println(fmt!("*** Failed '%s' on:", description));
        if failed.len() < 5 {
            // is this really the best way? can't be...
            let mut i = 0;
            for failed.len().times {
                println(fmt!("%?", failed[i]));
                i += 1;
            }
        } else {
            let mut failed_with_sizes : ~[(uint, T)] =
                failed.iter().transform(|x| (x.size(), x.clone()))
                .collect();
            sort::quick_sort(failed_with_sizes, |e1, e2| {
                e1.first() <= e2.first()
            });
            let mut i = 0;
            for 5.times {
                println(fmt!("%?", failed_with_sizes[i].second()));
                i += 1;
            }
            println("...and more");
        }
        return false;
    }
}

fn quick_check2<T:Arbitrary>(description : &str,
                             f : extern fn(T,T) -> bool) -> bool {
    let num_tests = 100;
    let mut passing = 0;
    let mut failed = ~[];
    for num_tests.times {
        let t1 : T = Arbitrary::gen();
        let t2 : T = Arbitrary::gen();
        if f(t1.clone(), t2.clone()) {
            passing += 1;
        } else {
            failed.push((t1, t2));
        }
    }
    if passing == num_tests {
        println(fmt!("+++ OK, passed 100 tests for %s", description));
        return true;
    } else {
        println(fmt!("*** Failed '%s' on:", description));
        if failed.len() < 5 {
            // is this really the best way? can't be...
            let mut i = 0;
            for failed.len().times {
                println(fmt!("%?", failed[i]));
                i += 1;
            }
        } else {
            let mut failed_with_sizes : ~[(uint, (T,T))] =
                failed.iter().transform(|x| (x.first().size() + x.second().size(),
                                             x.clone()))
                .collect();
            sort::quick_sort(failed_with_sizes, |e1, e2| {
                e1.first() <= e2.first()
            });
            let mut i = 0;
            for 5.times {
                println(fmt!("%?", failed_with_sizes[i].second()));
                i += 1;
            }
            println("...and more");
        }
        return false;
    }
}

#[test]
fn reverse_uint_vecs() {
    fn reverse<A:Clone>(v : ~[A]) -> ~[A] {
        let mut newvec = ~[];
        for v.iter().advance |e| {
            // NOTE(dbp 2013-07-25): This is intentionally buggy.
            newvec.push(e.clone());
        }
        return newvec;
    }

    fn prop_reverse_reverse_uints(v : ~[uint]) -> bool {
        reverse(reverse(v.clone())) == v
    }

    fn prop_reverse_moves_first_to_last(v : ~[uint]) -> bool {
        if v.len() > 0 {
            reverse(v.clone())[v.len() - 1] == v[0]
        } else {
            true // trivially
        }
    }

    assert!(
        quick_check("reversing a list twice yields the same list",
                    prop_reverse_reverse_uints));
    assert!(
        !quick_check("reversing a list moves first to last",
                     prop_reverse_moves_first_to_last));
}

#[test]
fn struct_gen() {

    #[deriving(Clone, Eq)]
    struct Foo { n: uint, xs: ~[int] }

    impl Arbitrary for Foo {
        fn gen() -> Foo {
            Foo { n: Arbitrary::gen(), xs: Arbitrary::gen() }
        }
        fn size(&self) -> uint {
            self.xs.len()
        }
    }
    // NOTE(dbp 2013-07-27): Not sure why this isn't covered by `deriving`,
    // is in a not-yet-implemented feature?
    impl Clone for Foo {
        fn clone(&self) -> Foo {
            Foo { n: self.n, xs: self.xs.clone() }
        }
    }
    impl Eq for Foo {
        fn eq(&self, other: &Foo) -> bool {
            self.n == other.n && self.xs == other.xs
        }
    }

    fn add_foos(a1: &Foo, a2: &Foo) -> Foo {
        let mut new_xs = ~[];
        new_xs = vec::append(new_xs, a1.xs);
        new_xs = vec::append(new_xs, a2.xs);
        Foo {n: a1.n + a2.n, xs: new_xs}
    }

    // NOTE(dbp 2013-07-27): This is obviously not true.
    fn prop_add_foos_commutes(a1: Foo, a2: Foo) -> bool {
        add_foos(&a1, &a2) == add_foos(&a2, &a1)
    }

    fn prop_add_zero_foo_identity(a: Foo) -> bool {
        add_foos(&a, &Foo {n: 0, xs: ~[]}) == a
    }

    assert!(
        !quick_check2("add_foos is commutative",
                    prop_add_foos_commutes));

    assert!(
        quick_check("add_foos with a zero Foo is an identity",
                    prop_add_zero_foo_identity));
}<commit_msg>more documentation<commit_after>extern mod extra;
use std::rand;
use std::vec;
use std::num;
use extra::sort;

/**
 * Arbitrary is a trait for types that you can generate arbitrary
 * instances of. You should also be able to ask for their size, so
 * you can report small failing examples instead of large ones.
 *
 */
trait Arbitrary : Clone {
    fn gen() -> Self;
    fn size(&self) -> uint;
}

impl Arbitrary for uint {
    fn gen() -> uint {
        let n : uint = rand::random();
         n % num::pow_with_uint(2,10)
    }
    fn size(&self) -> uint {
        self.clone()
    }
}

impl Arbitrary for int {
    fn gen() -> int {
        let n : int = rand::random();
        n % num::pow_with_uint(2,10)
    }

    fn size(&self) -> uint {
        self.clone().to_uint()
    }
}

impl<T:Arbitrary> Arbitrary for ~[T] {
    fn gen() -> ~[T] {
        let _n : uint = rand::random();
        let n = _n % 100;
        vec::build_sized(n, |p| {
            for n.times {
                p(Arbitrary::gen());
            }
        })
    }

    fn size(&self) -> uint {
        self.len()
    }
}

/**
 * quick_check
 *   description: a string describing what the property being tested is
 *   f: function that takes arbitrary input and returns whether
 *      the invariant held.
 *
 *   returns whether all the tests passed.
 */
fn quick_check<T:Arbitrary>(description : &str,
                            f : extern fn(T) -> bool) -> bool {
    let num_tests = 100;
    let mut passing = 0;
    let mut failed = ~[];
    for num_tests.times {
        let t : T = Arbitrary::gen();
        if f(t.clone()) {
            passing += 1;
        } else {
            failed.push(t);
        }
    }
    if passing == num_tests {
        println(fmt!("+++ OK, passed 100 tests for %s", description));
        return true;
    } else {
        println(fmt!("*** Failed '%s' on:", description));
        if failed.len() < 5 {
            // is this really the best way? can't be...
            let mut i = 0;
            for failed.len().times {
                println(fmt!("%?", failed[i]));
                i += 1;
            }
        } else {
            let mut failed_with_sizes : ~[(uint, T)] =
                failed.iter().transform(|x| (x.size(), x.clone()))
                .collect();
            sort::quick_sort(failed_with_sizes, |e1, e2| {
                e1.first() <= e2.first()
            });
            let mut i = 0;
            for 5.times {
                println(fmt!("%?", failed_with_sizes[i].second()));
                i += 1;
            }
            println("...and more");
        }
        return false;
    }
}

/**
 * quick_check2
 *   description: a string describing what the property being tested is
 *   f: function that takes two arbitrary inputs and returns whether
 *      the invariant held.
 *
 *   returns whether all the tests passed.
 */
fn quick_check2<T:Arbitrary>(description : &str,
                             f : extern fn(T,T) -> bool) -> bool {
    let num_tests = 100;
    let mut passing = 0;
    let mut failed = ~[];
    for num_tests.times {
        let t1 : T = Arbitrary::gen();
        let t2 : T = Arbitrary::gen();
        if f(t1.clone(), t2.clone()) {
            passing += 1;
        } else {
            failed.push((t1, t2));
        }
    }
    if passing == num_tests {
        println(fmt!("+++ OK, passed 100 tests for %s", description));
        return true;
    } else {
        println(fmt!("*** Failed '%s' on:", description));
        if failed.len() < 5 {
            // is this really the best way? can't be...
            let mut i = 0;
            for failed.len().times {
                println(fmt!("%?", failed[i]));
                i += 1;
            }
        } else {
            let mut failed_with_sizes : ~[(uint, (T,T))] =
                failed.iter().transform(|x| (x.first().size() + x.second().size(),
                                             x.clone()))
                .collect();
            sort::quick_sort(failed_with_sizes, |e1, e2| {
                e1.first() <= e2.first()
            });
            let mut i = 0;
            for 5.times {
                println(fmt!("%?", failed_with_sizes[i].second()));
                i += 1;
            }
            println("...and more");
        }
        return false;
    }
}

#[test]
fn reverse_uint_vecs() {
    fn reverse<A:Clone>(v : ~[A]) -> ~[A] {
        let mut newvec = ~[];
        for v.iter().advance |e| {
            // NOTE(dbp 2013-07-25): This is intentionally buggy - should be unshift.
            newvec.push(e.clone());
        }
        return newvec;
    }

    fn prop_reverse_reverse_uints(v : ~[uint]) -> bool {
        reverse(reverse(v.clone())) == v
    }

    fn prop_reverse_moves_first_to_last(v : ~[uint]) -> bool {
        if v.len() > 0 {
            reverse(v.clone())[v.len() - 1] == v[0]
        } else {
            true // trivially
        }
    }

    assert!(
        quick_check("reversing a list twice yields the same list",
                    prop_reverse_reverse_uints));
    assert!(
        !quick_check("reversing a list moves first to last",
                     prop_reverse_moves_first_to_last));
}

#[test]
fn struct_gen() {

    #[deriving(Clone, Eq)]
    struct Foo { n: uint, xs: ~[int] }

    impl Arbitrary for Foo {
        fn gen() -> Foo {
            Foo { n: Arbitrary::gen(), xs: Arbitrary::gen() }
        }
        fn size(&self) -> uint {
            self.xs.len()
        }
    }
    // NOTE(dbp 2013-07-27): Not sure why this isn't covered by `deriving`,
    // is it a not-yet-implemented feature?
    impl Clone for Foo {
        fn clone(&self) -> Foo {
            Foo { n: self.n, xs: self.xs.clone() }
        }
    }
    impl Eq for Foo {
        fn eq(&self, other: &Foo) -> bool {
            self.n == other.n && self.xs == other.xs
        }
    }

    fn add_foos(a1: &Foo, a2: &Foo) -> Foo {
        let mut new_xs = ~[];
        new_xs = vec::append(new_xs, a1.xs);
        new_xs = vec::append(new_xs, a2.xs);
        Foo {n: a1.n + a2.n, xs: new_xs}
    }

    // NOTE(dbp 2013-07-27): This is obviously not true.
    fn prop_add_foos_commutes(a1: Foo, a2: Foo) -> bool {
        add_foos(&a1, &a2) == add_foos(&a2, &a1)
    }

    fn prop_add_zero_foo_identity(a: Foo) -> bool {
        add_foos(&a, &Foo {n: 0, xs: ~[]}) == a
    }

    assert!(
        !quick_check2("add_foos is commutative",
                    prop_add_foos_commutes));

    assert!(
        quick_check("add_foos with a zero Foo is an identity",
                    prop_add_zero_foo_identity));
}<|endoftext|>


<commit_before>#![allow(dead_code)]

#[cfg(test)]
mod parse_tests;

#[macro_use]
extern crate nom;

use nom::{ErrorKind, IResult, line_ending, space};

#[derive(Debug, PartialEq, Eq)]
pub enum Mnemonic {
    Adc,
    And,
    Asl,
    Bcc,
    Bcs,
    Beq,
    Bit,
    Bmi,
    Bne,
    Bpl,
    Brk,
    Bvc,
    Bvs,
    Clc,
    Cld,
    Cli,
    Clv,
    Cmp,
    Cpx,
    Cpy,
    Dec,
    Dex,
    Dey,
    Eor,
    Inc,
    Inx,
    Iny,
    Jmp,
    Jsr,
    Lda,
    Ldx,
    Ldy,
    Lsr,
    Nop,
    Ora,
    Pha,
    Php,
    Pla,
    Plp,
    Rol,
    Ror,
    Rti,
    Rts,
    Sbc,
    Sec,
    Sed,
    Sei,
    Sta,
    Stx,
    Sty,
    Tax,
    Tay,
    Tsx,
    Txa,
    Txs,
    Tya,
}

#[derive(Debug, PartialEq, Eq)]
pub enum Sign {
    Implied,
    Negative,
}

#[derive(Debug, PartialEq, Eq)]
pub enum AddressingMode {
    IndexedIndirect(u8),
    IndirectIndexed(u8),
    ZeroPageOrRelative(u8, Sign),
    Immediate(u8, Sign),
    Absolute(u16),
    AbsoluteX(u16),
    AbsoluteY(u16),
    ZeroPageX(u8),
    ZeroPageY(u8),
    Indirect(u16),
    Implied,
    Accumulator,
}

#[derive(Debug, PartialEq, Eq)]
pub struct OpCode(Mnemonic, AddressingMode);

named!(pub parse_lines <Vec<OpCode> >, separated_list!(line_ending, opcode));

named!(opcode <OpCode>, do_parse!(
        mnemonic: mnemonic >>
        space >>
        am: addressing_mode >>
        (OpCode(mnemonic, am))
    )
);

named!(mnemonic <Mnemonic>, alt!(
        tag!("ADC") => { |_| Mnemonic::Adc } |
        tag!("AND") => { |_| Mnemonic::And } |
        tag!("ASL") => { |_| Mnemonic::Asl } |
        tag!("BCC") => { |_| Mnemonic::Bcc } |
        tag!("BCS") => { |_| Mnemonic::Bcs } |
        tag!("BEQ") => { |_| Mnemonic::Beq } |
        tag!("BIT") => { |_| Mnemonic::Bit } |
        tag!("BMI") => { |_| Mnemonic::Bmi } |
        tag!("BNE") => { |_| Mnemonic::Bne } |
        tag!("BPL") => { |_| Mnemonic::Bpl } |
        tag!("BRK") => { |_| Mnemonic::Brk } |
        tag!("BVC") => { |_| Mnemonic::Bvc } |
        tag!("BVS") => { |_| Mnemonic::Bvs } |
        tag!("CLC") => { |_| Mnemonic::Clc } |
        tag!("CLD") => { |_| Mnemonic::Cld } |
        tag!("CLI") => { |_| Mnemonic::Cli } |
        tag!("CLV") => { |_| Mnemonic::Clv } |
        tag!("CMP") => { |_| Mnemonic::Cmp } |
        tag!("CPX") => { |_| Mnemonic::Cpx } |
        tag!("CPY") => { |_| Mnemonic::Cpy } |
        tag!("DEC") => { |_| Mnemonic::Dec } |
        tag!("DEX") => { |_| Mnemonic::Dex } |
        tag!("DEY") => { |_| Mnemonic::Dey } |
        tag!("EOR") => { |_| Mnemonic::Eor } |
        tag!("INC") => { |_| Mnemonic::Inc } |
        tag!("INX") => { |_| Mnemonic::Inx } |
        tag!("INY") => { |_| Mnemonic::Iny } |
        tag!("JMP") => { |_| Mnemonic::Jmp } |
        tag!("JSR") => { |_| Mnemonic::Jsr } |
        tag!("LDA") => { |_| Mnemonic::Lda } |
        tag!("LDX") => { |_| Mnemonic::Ldx } |
        tag!("LDY") => { |_| Mnemonic::Ldy } |
        tag!("LSR") => { |_| Mnemonic::Lsr } |
        tag!("NOP") => { |_| Mnemonic::Nop } |
        tag!("ORA") => { |_| Mnemonic::Ora } |
        tag!("PHA") => { |_| Mnemonic::Pha } |
        tag!("PHP") => { |_| Mnemonic::Php } |
        tag!("PLA") => { |_| Mnemonic::Pla } |
        tag!("PLP") => { |_| Mnemonic::Plp } |
        tag!("ROL") => { |_| Mnemonic::Rol } |
        tag!("ROR") => { |_| Mnemonic::Ror } |
        tag!("RTI") => { |_| Mnemonic::Rti } |
        tag!("RTS") => { |_| Mnemonic::Rts } |
        tag!("SBC") => { |_| Mnemonic::Sbc } |
        tag!("SEC") => { |_| Mnemonic::Sec } |
        tag!("SED") => { |_| Mnemonic::Sed } |
        tag!("SEI") => { |_| Mnemonic::Sei } |
        tag!("STA") => { |_| Mnemonic::Sta } |
        tag!("STX") => { |_| Mnemonic::Stx } |
        tag!("STY") => { |_| Mnemonic::Sty } |
        tag!("TAX") => { |_| Mnemonic::Tax } |
        tag!("TAY") => { |_| Mnemonic::Tay } |
        tag!("TSX") => { |_| Mnemonic::Tsx } |
        tag!("TXA") => { |_| Mnemonic::Txa } |
        tag!("TXS") => { |_| Mnemonic::Txs } |
        tag!("TYA") => { |_| Mnemonic::Tya }
        )
    );

named!(addressing_mode <AddressingMode>,
    alt_complete!(
        am_accumulator |
        am_immediate |
        am_indirect |
        am_indexed_indirect |
        am_indirect_indexed |
        am_zp_x |
        am_zp_y |
        am_zp_or_relative |
        am_abs_x |
        am_abs_y |
        am_abs |
        am_implied
    )
);

named!(am_implied <AddressingMode>,
   do_parse!(
       line_ending >>
       (AddressingMode::Implied)
   )
);

named!(am_indirect <AddressingMode>,
    do_parse!(
        word: delimited!(tag!("("), alt!(parse_word_hex | dec_u16), tag!(")")) >>
        not!(tag!(",")) >>
        (AddressingMode::Indirect(word))
    )
);

named!(am_indexed_indirect <AddressingMode>,
    do_parse!(
        byte: delimited!(tag!("("), alt!(parse_byte_hex | parse_byte_dec), tag!(",X")) >>
        ({ let (addr, _) = byte; AddressingMode::IndexedIndirect(addr) })
    )
);

named!(am_indirect_indexed <AddressingMode>,
    do_parse!(
        byte: delimited!(tag!("("), alt!(parse_byte_hex | parse_byte_dec), tag!("),Y")) >>
        ({ let (addr, _) = byte; AddressingMode::IndirectIndexed(addr) })
    )
);

named!(am_accumulator <AddressingMode>,
    do_parse!(
        tag!("A") >>
        (AddressingMode::Accumulator)
    )
);

named!(am_immediate <AddressingMode>,
    do_parse!(
        val: preceded!(tag!("#"), alt!(parse_byte_hex | parse_byte_dec)) >>
        ({ let (byte, sign) = val; AddressingMode::Immediate(byte, sign)})
    )
);

named!(am_abs <AddressingMode>,
    do_parse!(
        val: alt!(parse_word_hex | dec_u16) >>
        (AddressingMode::Absolute(val))
    )
);

named!(am_zp_or_relative <AddressingMode>,
    do_parse!(
        val: alt!(parse_byte_hex | parse_byte_dec) >>
        ({ let (byte, sign) = val; AddressingMode::ZeroPageOrRelative(byte, sign)})
    )
);

named!(am_zp_x <AddressingMode>,
    do_parse!(
        val: terminated!(alt!(parse_byte_hex | parse_byte_dec), tag!(",X")) >>
        ({ let (byte, _) = val; AddressingMode::ZeroPageX(byte)})
    )
);

named!(am_zp_y <AddressingMode>,
    do_parse!(
        val: terminated!(alt!(parse_byte_hex | parse_byte_dec), tag!(",Y")) >>
        ({ let (byte, _) = val; AddressingMode::ZeroPageY(byte)})
    )
);

named!(am_abs_x <AddressingMode>,
    do_parse!(
        val: terminated!(alt!(parse_word_hex | dec_u16), tag!(",X")) >>
        (AddressingMode::AbsoluteX(val))
    )
);

named!(am_abs_y <AddressingMode>,
    do_parse!(
        val: terminated!(alt!(parse_word_hex | dec_u16), tag!(",Y")) >>
        (AddressingMode::AbsoluteY(val))
    )
);

named!(parse_word_hex <u16>,
    do_parse!(
        val: preceded!(tag!("$"), hex_u16) >>
        (val)
    )
);

named!(parse_byte_hex <(u8, Sign)>,
    do_parse!(
        val: preceded!(tag!("$"), hex_u8) >>
        (val, Sign::Implied)
    )
);

named!(parse_byte_dec <(u8, Sign)>,
    do_parse!(
        sign: parse_sign >>
        val: dec_u8 >>
        (val, sign)
    )
);

named!(parse_sign <Sign>,
    do_parse!(
        sign: opt!(tag!("-")) >>
        (if let Some(_) = sign {
            Sign::Negative
        } else {
            Sign::Implied
        })
    )
);

pub fn hex_u16(input: &[u8]) -> IResult<&[u8], u16> {
    match is_a!(input, &b"0123456789abcdefABCDEF"[..]) {
        IResult::Error(e) => IResult::Error(e),
        IResult::Incomplete(e) => IResult::Incomplete(e),
        IResult::Done(i, o) => {
            let mut res = 0u16;

            // Do not parse more than 4 characters for a u16
            let mut remaining = i;
            let mut parsed = o;
            if o.len() > 4 {
                remaining = &input[4..];
                parsed = &input[..4];
            }

            for &e in parsed {
                let digit = e as char;
                let value = digit.to_digit(16).unwrap_or(0) as u16;
                res = value + (res << 4);
            }
            IResult::Done(remaining, res)
        }
    }
}

pub fn dec_u16(input: &[u8]) -> IResult<&[u8], u16> {
    match is_a!(input, &b"0123456789"[..]) {
        IResult::Error(e) => IResult::Error(e),
        IResult::Incomplete(e) => IResult::Incomplete(e),
        IResult::Done(remaining, parsed) => {
            // Do not parse more than 5 characters for a u16
            if parsed.len() > 5 {
                IResult::Error(ErrorKind::Custom(0))
            } else {
                let mut res = 0u32;
                for &e in parsed {
                    let digit = e as char;
                    let value = digit.to_digit(10).unwrap_or(0) as u32;
                    res = value + (res * 10);
                }
                if res > u16::max_value() as u32 {
                    IResult::Error(ErrorKind::Custom(0))
                } else {
                    IResult::Done(remaining, res as u16)
                }
            }
        }
    }
}

pub fn dec_u8(input: &[u8]) -> IResult<&[u8], u8> {
    match is_a!(input, &b"0123456789"[..]) {
        IResult::Error(e) => IResult::Error(e),
        IResult::Incomplete(e) => IResult::Incomplete(e),
        IResult::Done(remaining, parsed) => {
            // Do not parse more than 3 characters for a u16
            if parsed.len() > 3 {
                IResult::Error(ErrorKind::Custom(0))
            } else {
                let mut res = 0u16;
                for &e in parsed {
                    let digit = e as char;
                    let value = digit.to_digit(10).unwrap_or(0) as u16;
                    res = value + (res * 10);
                }
                if res > u8::max_value() as u16 {
                    IResult::Error(ErrorKind::Custom(0))
                } else {
                    IResult::Done(remaining, res as u8)
                }
            }
        }
    }
}

fn hex_u8(input: &[u8]) -> IResult<&[u8], u8> {
    match is_a!(input, &b"0123456789abcdefABCDEF"[..]) {
        IResult::Error(e) => IResult::Error(e),
        IResult::Incomplete(e) => IResult::Incomplete(e),
        IResult::Done(remaining, parsed) => {
            // Not valid if exceeds 2 characters
            if parsed.len() > 2 {
                IResult::Error(ErrorKind::Custom(0))
            } else {
                let mut res = 0u8;
                for &e in parsed {
                    let digit = e as char;
                    let value = digit.to_digit(16).unwrap_or(0) as u8;
                    res = value + (res << 4);
                }
                IResult::Done(remaining, res)
            }

        }
    }
}
<commit_msg>Case insensitive instructions and operands<commit_after>#![allow(dead_code)]

#[cfg(test)]
mod parse_tests;

#[macro_use]
extern crate nom;

use nom::{ErrorKind, IResult, line_ending, space};

#[derive(Debug, PartialEq, Eq)]
pub enum Mnemonic {
    Adc,
    And,
    Asl,
    Bcc,
    Bcs,
    Beq,
    Bit,
    Bmi,
    Bne,
    Bpl,
    Brk,
    Bvc,
    Bvs,
    Clc,
    Cld,
    Cli,
    Clv,
    Cmp,
    Cpx,
    Cpy,
    Dec,
    Dex,
    Dey,
    Eor,
    Inc,
    Inx,
    Iny,
    Jmp,
    Jsr,
    Lda,
    Ldx,
    Ldy,
    Lsr,
    Nop,
    Ora,
    Pha,
    Php,
    Pla,
    Plp,
    Rol,
    Ror,
    Rti,
    Rts,
    Sbc,
    Sec,
    Sed,
    Sei,
    Sta,
    Stx,
    Sty,
    Tax,
    Tay,
    Tsx,
    Txa,
    Txs,
    Tya,
}

#[derive(Debug, PartialEq, Eq)]
pub enum Sign {
    Implied,
    Negative,
}

#[derive(Debug, PartialEq, Eq)]
pub enum AddressingMode {
    IndexedIndirect(u8),
    IndirectIndexed(u8),
    ZeroPageOrRelative(u8, Sign),
    Immediate(u8, Sign),
    Absolute(u16),
    AbsoluteX(u16),
    AbsoluteY(u16),
    ZeroPageX(u8),
    ZeroPageY(u8),
    Indirect(u16),
    Implied,
    Accumulator,
}

#[derive(Debug, PartialEq, Eq)]
pub struct OpCode(Mnemonic, AddressingMode);

named!(pub parse_lines <Vec<OpCode> >, separated_list!(line_ending, opcode));

named!(opcode <OpCode>, do_parse!(
        mnemonic: mnemonic >>
        space >>
        am: addressing_mode >>
        (OpCode(mnemonic, am))
    )
);

named!(mnemonic <Mnemonic>, alt!(
        tag_no_case!("ADC") => { |_| Mnemonic::Adc } |
        tag_no_case!("AND") => { |_| Mnemonic::And } |
        tag_no_case!("ASL") => { |_| Mnemonic::Asl } |
        tag_no_case!("BCC") => { |_| Mnemonic::Bcc } |
        tag_no_case!("BCS") => { |_| Mnemonic::Bcs } |
        tag_no_case!("BEQ") => { |_| Mnemonic::Beq } |
        tag_no_case!("BIT") => { |_| Mnemonic::Bit } |
        tag_no_case!("BMI") => { |_| Mnemonic::Bmi } |
        tag_no_case!("BNE") => { |_| Mnemonic::Bne } |
        tag_no_case!("BPL") => { |_| Mnemonic::Bpl } |
        tag_no_case!("BRK") => { |_| Mnemonic::Brk } |
        tag_no_case!("BVC") => { |_| Mnemonic::Bvc } |
        tag_no_case!("BVS") => { |_| Mnemonic::Bvs } |
        tag_no_case!("CLC") => { |_| Mnemonic::Clc } |
        tag_no_case!("CLD") => { |_| Mnemonic::Cld } |
        tag_no_case!("CLI") => { |_| Mnemonic::Cli } |
        tag_no_case!("CLV") => { |_| Mnemonic::Clv } |
        tag_no_case!("CMP") => { |_| Mnemonic::Cmp } |
        tag_no_case!("CPX") => { |_| Mnemonic::Cpx } |
        tag_no_case!("CPY") => { |_| Mnemonic::Cpy } |
        tag_no_case!("DEC") => { |_| Mnemonic::Dec } |
        tag_no_case!("DEX") => { |_| Mnemonic::Dex } |
        tag_no_case!("DEY") => { |_| Mnemonic::Dey } |
        tag_no_case!("EOR") => { |_| Mnemonic::Eor } |
        tag_no_case!("INC") => { |_| Mnemonic::Inc } |
        tag_no_case!("INX") => { |_| Mnemonic::Inx } |
        tag_no_case!("INY") => { |_| Mnemonic::Iny } |
        tag_no_case!("JMP") => { |_| Mnemonic::Jmp } |
        tag_no_case!("JSR") => { |_| Mnemonic::Jsr } |
        tag_no_case!("LDA") => { |_| Mnemonic::Lda } |
        tag_no_case!("LDX") => { |_| Mnemonic::Ldx } |
        tag_no_case!("LDY") => { |_| Mnemonic::Ldy } |
        tag_no_case!("LSR") => { |_| Mnemonic::Lsr } |
        tag_no_case!("NOP") => { |_| Mnemonic::Nop } |
        tag_no_case!("ORA") => { |_| Mnemonic::Ora } |
        tag_no_case!("PHA") => { |_| Mnemonic::Pha } |
        tag_no_case!("PHP") => { |_| Mnemonic::Php } |
        tag_no_case!("PLA") => { |_| Mnemonic::Pla } |
        tag_no_case!("PLP") => { |_| Mnemonic::Plp } |
        tag_no_case!("ROL") => { |_| Mnemonic::Rol } |
        tag_no_case!("ROR") => { |_| Mnemonic::Ror } |
        tag_no_case!("RTI") => { |_| Mnemonic::Rti } |
        tag_no_case!("RTS") => { |_| Mnemonic::Rts } |
        tag_no_case!("SBC") => { |_| Mnemonic::Sbc } |
        tag_no_case!("SEC") => { |_| Mnemonic::Sec } |
        tag_no_case!("SED") => { |_| Mnemonic::Sed } |
        tag_no_case!("SEI") => { |_| Mnemonic::Sei } |
        tag_no_case!("STA") => { |_| Mnemonic::Sta } |
        tag_no_case!("STX") => { |_| Mnemonic::Stx } |
        tag_no_case!("STY") => { |_| Mnemonic::Sty } |
        tag_no_case!("TAX") => { |_| Mnemonic::Tax } |
        tag_no_case!("TAY") => { |_| Mnemonic::Tay } |
        tag_no_case!("TSX") => { |_| Mnemonic::Tsx } |
        tag_no_case!("TXA") => { |_| Mnemonic::Txa } |
        tag_no_case!("TXS") => { |_| Mnemonic::Txs } |
        tag_no_case!("TYA") => { |_| Mnemonic::Tya }
        )
    );

named!(addressing_mode <AddressingMode>,
    alt_complete!(
        am_accumulator |
        am_immediate |
        am_indirect |
        am_indexed_indirect |
        am_indirect_indexed |
        am_zp_x |
        am_zp_y |
        am_zp_or_relative |
        am_abs_x |
        am_abs_y |
        am_abs |
        am_implied
    )
);

named!(am_implied <AddressingMode>,
   do_parse!(
       line_ending >>
       (AddressingMode::Implied)
   )
);

named!(am_indirect <AddressingMode>,
    do_parse!(
        word: delimited!(tag!("("), alt!(parse_word_hex | dec_u16), tag!(")")) >>
        not!(tag!(",")) >>
        (AddressingMode::Indirect(word))
    )
);

named!(am_indexed_indirect <AddressingMode>,
    do_parse!(
        byte: delimited!(tag!("("), alt!(parse_byte_hex | parse_byte_dec), tag_no_case!(",X")) >>
        ({ let (addr, _) = byte; AddressingMode::IndexedIndirect(addr) })
    )
);

named!(am_indirect_indexed <AddressingMode>,
    do_parse!(
        byte: delimited!(tag!("("), alt!(parse_byte_hex | parse_byte_dec), tag_no_case!("),Y")) >>
        ({ let (addr, _) = byte; AddressingMode::IndirectIndexed(addr) })
    )
);

named!(am_accumulator <AddressingMode>,
    do_parse!(
        tag_no_case!("A") >>
        (AddressingMode::Accumulator)
    )
);

named!(am_immediate <AddressingMode>,
    do_parse!(
        val: preceded!(tag!("#"), alt!(parse_byte_hex | parse_byte_dec)) >>
        ({ let (byte, sign) = val; AddressingMode::Immediate(byte, sign)})
    )
);

named!(am_abs <AddressingMode>,
    do_parse!(
        val: alt!(parse_word_hex | dec_u16) >>
        (AddressingMode::Absolute(val))
    )
);

named!(am_zp_or_relative <AddressingMode>,
    do_parse!(
        val: alt!(parse_byte_hex | parse_byte_dec) >>
        ({ let (byte, sign) = val; AddressingMode::ZeroPageOrRelative(byte, sign)})
    )
);

named!(am_zp_x <AddressingMode>,
    do_parse!(
        val: terminated!(alt!(parse_byte_hex | parse_byte_dec), tag_no_case!(",X")) >>
        ({ let (byte, _) = val; AddressingMode::ZeroPageX(byte)})
    )
);

named!(am_zp_y <AddressingMode>,
    do_parse!(
        val: terminated!(alt!(parse_byte_hex | parse_byte_dec), tag_no_case!(",Y")) >>
        ({ let (byte, _) = val; AddressingMode::ZeroPageY(byte)})
    )
);

named!(am_abs_x <AddressingMode>,
    do_parse!(
        val: terminated!(alt!(parse_word_hex | dec_u16), tag_no_case!(",X")) >>
        (AddressingMode::AbsoluteX(val))
    )
);

named!(am_abs_y <AddressingMode>,
    do_parse!(
        val: terminated!(alt!(parse_word_hex | dec_u16), tag_no_case!(",Y")) >>
        (AddressingMode::AbsoluteY(val))
    )
);

named!(parse_word_hex <u16>,
    do_parse!(
        val: preceded!(tag!("$"), hex_u16) >>
        (val)
    )
);

named!(parse_byte_hex <(u8, Sign)>,
    do_parse!(
        val: preceded!(tag!("$"), hex_u8) >>
        (val, Sign::Implied)
    )
);

named!(parse_byte_dec <(u8, Sign)>,
    do_parse!(
        sign: parse_sign >>
        val: dec_u8 >>
        (val, sign)
    )
);

named!(parse_sign <Sign>,
    do_parse!(
        sign: opt!(tag!("-")) >>
        (if let Some(_) = sign {
            Sign::Negative
        } else {
            Sign::Implied
        })
    )
);

pub fn hex_u16(input: &[u8]) -> IResult<&[u8], u16> {
    match is_a!(input, &b"0123456789abcdefABCDEF"[..]) {
        IResult::Error(e) => IResult::Error(e),
        IResult::Incomplete(e) => IResult::Incomplete(e),
        IResult::Done(i, o) => {
            let mut res = 0u16;

            // Do not parse more than 4 characters for a u16
            let mut remaining = i;
            let mut parsed = o;
            if o.len() > 4 {
                remaining = &input[4..];
                parsed = &input[..4];
            }

            for &e in parsed {
                let digit = e as char;
                let value = digit.to_digit(16).unwrap_or(0) as u16;
                res = value + (res << 4);
            }
            IResult::Done(remaining, res)
        }
    }
}

pub fn dec_u16(input: &[u8]) -> IResult<&[u8], u16> {
    match is_a!(input, &b"0123456789"[..]) {
        IResult::Error(e) => IResult::Error(e),
        IResult::Incomplete(e) => IResult::Incomplete(e),
        IResult::Done(remaining, parsed) => {
            // Do not parse more than 5 characters for a u16
            if parsed.len() > 5 {
                IResult::Error(ErrorKind::Custom(0))
            } else {
                let mut res = 0u32;
                for &e in parsed {
                    let digit = e as char;
                    let value = digit.to_digit(10).unwrap_or(0) as u32;
                    res = value + (res * 10);
                }
                if res > u16::max_value() as u32 {
                    IResult::Error(ErrorKind::Custom(0))
                } else {
                    IResult::Done(remaining, res as u16)
                }
            }
        }
    }
}

pub fn dec_u8(input: &[u8]) -> IResult<&[u8], u8> {
    match is_a!(input, &b"0123456789"[..]) {
        IResult::Error(e) => IResult::Error(e),
        IResult::Incomplete(e) => IResult::Incomplete(e),
        IResult::Done(remaining, parsed) => {
            // Do not parse more than 3 characters for a u16
            if parsed.len() > 3 {
                IResult::Error(ErrorKind::Custom(0))
            } else {
                let mut res = 0u16;
                for &e in parsed {
                    let digit = e as char;
                    let value = digit.to_digit(10).unwrap_or(0) as u16;
                    res = value + (res * 10);
                }
                if res > u8::max_value() as u16 {
                    IResult::Error(ErrorKind::Custom(0))
                } else {
                    IResult::Done(remaining, res as u8)
                }
            }
        }
    }
}

fn hex_u8(input: &[u8]) -> IResult<&[u8], u8> {
    match is_a!(input, &b"0123456789abcdefABCDEF"[..]) {
        IResult::Error(e) => IResult::Error(e),
        IResult::Incomplete(e) => IResult::Incomplete(e),
        IResult::Done(remaining, parsed) => {
            // Not valid if exceeds 2 characters
            if parsed.len() > 2 {
                IResult::Error(ErrorKind::Custom(0))
            } else {
                let mut res = 0u8;
                for &e in parsed {
                    let digit = e as char;
                    let value = digit.to_digit(16).unwrap_or(0) as u8;
                    res = value + (res << 4);
                }
                IResult::Done(remaining, res)
            }

        }
    }
}
<|endoftext|>