<commit_before>#![deny(warnings)]
#![allow(unknown_lints)]
use std::ascii::*;

pub struct CamelOptions {
    pub new_word: bool,
    pub last_char: char,
    pub first_word: bool,
    pub injectable_char: char,
    pub has_seperator: bool,
    pub inverted: bool,
}

pub fn to_case_snake_like(convertable_string: &str, replace_with: &str, case: &str) -> String {
    let mut first_character: bool = true;
    let string_size: f64 =  convertable_string.len() as f64;
    let mut result: String = String::with_capacity((string_size * 1.25) as usize);
    for char_with_index  in convertable_string.char_indices() {
        if char_is_seperator(&char_with_index.1) {
            first_character = true;
            result.push(replace_with.chars().nth(0).unwrap_or('_'));
        } else if requires_seperator(char_with_index, first_character, &convertable_string) {
            first_character = false;
            result = snake_like_with_seperator(result, replace_with, &char_with_index.1, case)
        } else {
            first_character = false;
            result = snake_like_no_seperator(result, &char_with_index.1, case)
        }
    }
    result.shrink_to_fit();
    result
}

pub fn to_case_camel_like(convertable_string: &str, camel_options: CamelOptions) -> String {
    let mut new_word: bool = camel_options.new_word;
    let mut first_word: bool = camel_options.first_word;
    let mut last_char: char = camel_options.last_char;
    let string_size: usize =  convertable_string.len();
    let mut result: String = String::with_capacity(string_size);
    for character in convertable_string.chars() {
        if char_is_seperator(&character) {
            new_word = true;
        } else if character.is_numeric() {
            new_word = true;
            result.push(character);
        } else if last_char_lower_current_is_upper_or_new_word(new_word, last_char, character) {
            new_word = false;
            result = append_on_new_word(result, first_word, character, &camel_options);
            first_word = false;
        } else {
            last_char = character;
            result.push(character.to_ascii_lowercase());
        }
    }
    result.shrink_to_fit();
    result
}

#[inline]
fn append_on_new_word(mut result: String, first_word: bool, character: char, camel_options: &CamelOptions) -> String {
    if not_first_word_and_has_seperator(first_word, camel_options.has_seperator) {
        result.push(camel_options.injectable_char);
    }
    if first_word_or_not_inverted(first_word, camel_options.inverted) {
        result.push(character.to_ascii_uppercase());
    } else {
        result.push(character.to_ascii_lowercase());
    }
    result
}

fn not_first_word_and_has_seperator(first_word: bool, has_seperator: bool) -> bool {
    has_seperator && !first_word
}

fn first_word_or_not_inverted(first_word: bool, inverted: bool) -> bool {
    !inverted || first_word
}

fn last_char_lower_current_is_upper_or_new_word(new_word: bool, last_char: char, character: char) -> bool{
    new_word ||
        ((last_char.is_lowercase() && character.is_uppercase()) &&
         (last_char != ' '))
}

fn char_is_seperator(character: &char) -> bool {
    character == &'-' || character == &'_' || character == &' '
}

#[inline]
fn requires_seperator(char_with_index: (usize, char), first_character: bool, convertable_string: &str) -> bool {
    !first_character &&
        char_is_uppercase(char_with_index.1) &&
            next_or_previous_char_is_lowercase(convertable_string, char_with_index.0)
}

#[inline]
fn snake_like_no_seperator(mut accumlator: String, current_char: &char, case: &str) -> String {
    if case == "lower" {
        accumlator.push(current_char.to_ascii_lowercase());
        accumlator
    } else {
        accumlator.push(current_char.to_ascii_uppercase());
        accumlator
    }
}

#[inline]
fn snake_like_with_seperator(mut accumlator: String, replace_with: &str, current_char: &char, case: &str) -> String {
    if case == "lower" {
        accumlator.push(replace_with.chars().nth(0).unwrap_or('_'));
        accumlator.push(current_char.to_ascii_lowercase());
        accumlator
    } else {
        accumlator.push(replace_with.chars().nth(0).unwrap_or('_'));
        accumlator.push(current_char.to_ascii_uppercase());
        accumlator
    }
}

fn next_or_previous_char_is_lowercase(convertable_string: &str, char_with_index: usize) -> bool {
    convertable_string.chars().nth(char_with_index + 1).unwrap_or('A').is_lowercase() ||
        convertable_string.chars().nth(char_with_index - 1).unwrap_or('A').is_lowercase()
}

fn char_is_uppercase(test_char: char) -> bool {
    test_char == test_char.to_ascii_uppercase()
}

#[test]
fn test_char_is_uppercase_when_it_is() {
    assert_eq!(char_is_uppercase('A'), true)
}

#[test]
fn test_char_is_uppercase_when_it_is_not() {
    assert_eq!(char_is_uppercase('a'), false)
}

#[test]
fn test_next_or_previous_char_is_lowercase_true() {
    assert_eq!(next_or_previous_char_is_lowercase("TestWWW", 3), true)
}

#[test]
fn test_next_or_previous_char_is_lowercase_false() {
    assert_eq!(next_or_previous_char_is_lowercase("TestWWW", 5), false)
}

#[test]
fn snake_like_with_seperator_lowers() {
    assert_eq!(snake_like_with_seperator("".to_owned(), "^", &'c', "lower"), "^c".to_string())
}

#[test]
fn snake_like_with_seperator_upper() {
    assert_eq!(snake_like_with_seperator("".to_owned(), "^", &'c', "upper"), "^C".to_string())
}

#[test]
fn snake_like_no_seperator_lower() {
    assert_eq!(snake_like_no_seperator("".to_owned(), &'C', "lower"), "c".to_string())
}

#[test]
fn snake_like_no_seperator_upper() {
    assert_eq!(snake_like_no_seperator("".to_owned(), &'c', "upper"), "C".to_string())
}

#[test]
fn requires_seperator_upper_not_first_wrap_is_safe_current_upper() {
    assert_eq!(requires_seperator((2, 'C'), false, "test"), true)
}

#[test]
fn requires_seperator_upper_not_first_wrap_is_safe_current_lower() {
    assert_eq!(requires_seperator((2, 'c'), false, "test"), false)
}

#[test]
fn requires_seperator_upper_first_wrap_is_safe_current_upper() {
    assert_eq!(requires_seperator((0, 'T'), true, "Test"), false)
}

#[test]
fn requires_seperator_upper_first_wrap_is_safe_current_lower() {
    assert_eq!(requires_seperator((0, 't'), true, "Test"), false)
}

#[test]
fn requires_seperator_upper_first_wrap_is_safe_current_lower_next_is_too() {
    assert_eq!(requires_seperator((0, 't'), true, "test"), false)
}

#[test]
fn test_char_is_seperator_dash() {
    assert_eq!(char_is_seperator(&'-'), true)
}

#[test]
fn test_char_is_seperator_underscore() {
    assert_eq!(char_is_seperator(&'_'), true)
}

#[test]
fn test_char_is_seperator_space() {
    assert_eq!(char_is_seperator(&' '), true)
}

#[test]
fn test_char_is_seperator_when_not() {
    assert_eq!(char_is_seperator(&'A'), false)
}

#[test]
fn test_last_char_lower_current_is_upper_or_new_word_with_new_word() {
    assert_eq!(last_char_lower_current_is_upper_or_new_word(true, ' ', '-'), true)
}

#[test]
fn test_last_char_lower_current_is_upper_or_new_word_last_char_space() {
    assert_eq!(last_char_lower_current_is_upper_or_new_word(false, ' ', '-'), false)
}

#[test]
fn test_last_char_lower_current_is_upper_or_new_word_last_char_lower_current_upper() {
    assert_eq!(last_char_lower_current_is_upper_or_new_word(false, 'a', 'A'), true)
}

#[test]
fn test_last_char_lower_current_is_upper_or_new_word_last_char_upper_current_upper() {
    assert_eq!(last_char_lower_current_is_upper_or_new_word(false, 'A', 'A'), false)
}

#[test]
fn test_last_char_lower_current_is_upper_or_new_word_last_char_upper_current_lower() {
    assert_eq!(last_char_lower_current_is_upper_or_new_word(false, 'A', 'a'), false)
}

#[test]
fn test_first_word_or_not_inverted_with_first_word() {
    assert_eq!(first_word_or_not_inverted(true, false), true)
}

#[test]
fn test_first_word_or_not_inverted_not_first_word_not_inverted() {
    assert_eq!(first_word_or_not_inverted(false, false), true)
}

#[test]
fn test_first_word_or_not_inverted_not_first_word_is_inverted() {
    assert_eq!(first_word_or_not_inverted(false, true), false)
}

#[test]
fn test_not_first_word_and_has_seperator_is_first_and_not_seperator() {
    assert_eq!(not_first_word_and_has_seperator(true, false), false)
}

#[test]
fn test_not_first_word_and_has_seperator_not_first_and_not_seperator() {
    assert_eq!(not_first_word_and_has_seperator(false, false), false)
}

#[test]
fn test_not_first_word_and_has_seperator_not_first_and_has_seperator() {
    assert_eq!(not_first_word_and_has_seperator(false, true), true)
}
<commit_msg>Provide extra space<commit_after>#![deny(warnings)]
#![allow(unknown_lints)]
use std::ascii::*;

pub struct CamelOptions {
    pub new_word: bool,
    pub last_char: char,
    pub first_word: bool,
    pub injectable_char: char,
    pub has_seperator: bool,
    pub inverted: bool,
}

pub fn to_case_snake_like(convertable_string: &str, replace_with: &str, case: &str) -> String {
    let mut first_character: bool = true;
    let mut result: String = String::with_capacity(convertable_string.len() * 2);
    for char_with_index  in convertable_string.char_indices() {
        if char_is_seperator(&char_with_index.1) {
            first_character = true;
            result.push(replace_with.chars().nth(0).unwrap_or('_'));
        } else if requires_seperator(char_with_index, first_character, &convertable_string) {
            first_character = false;
            result = snake_like_with_seperator(result, replace_with, &char_with_index.1, case)
        } else {
            first_character = false;
            result = snake_like_no_seperator(result, &char_with_index.1, case)
        }
    }
    result
}

pub fn to_case_camel_like(convertable_string: &str, camel_options: CamelOptions) -> String {
    let mut new_word: bool = camel_options.new_word;
    let mut first_word: bool = camel_options.first_word;
    let mut last_char: char = camel_options.last_char;
    let mut result: String = String::with_capacity(convertable_string.len() * 2);
    for character in convertable_string.chars() {
        if char_is_seperator(&character) {
            new_word = true;
        } else if character.is_numeric() {
            new_word = true;
            result.push(character);
        } else if last_char_lower_current_is_upper_or_new_word(new_word, last_char, character) {
            new_word = false;
            result = append_on_new_word(result, first_word, character, &camel_options);
            first_word = false;
        } else {
            last_char = character;
            result.push(character.to_ascii_lowercase());
        }
    }
    result
}

#[inline]
fn append_on_new_word(mut result: String, first_word: bool, character: char, camel_options: &CamelOptions) -> String {
    if not_first_word_and_has_seperator(first_word, camel_options.has_seperator) {
        result.push(camel_options.injectable_char);
    }
    if first_word_or_not_inverted(first_word, camel_options.inverted) {
        result.push(character.to_ascii_uppercase());
    } else {
        result.push(character.to_ascii_lowercase());
    }
    result
}

fn not_first_word_and_has_seperator(first_word: bool, has_seperator: bool) -> bool {
    has_seperator && !first_word
}

fn first_word_or_not_inverted(first_word: bool, inverted: bool) -> bool {
    !inverted || first_word
}

fn last_char_lower_current_is_upper_or_new_word(new_word: bool, last_char: char, character: char) -> bool{
    new_word ||
        ((last_char.is_lowercase() && character.is_uppercase()) &&
         (last_char != ' '))
}

fn char_is_seperator(character: &char) -> bool {
    character == &'-' || character == &'_' || character == &' '
}

#[inline]
fn requires_seperator(char_with_index: (usize, char), first_character: bool, convertable_string: &str) -> bool {
    !first_character &&
        char_is_uppercase(char_with_index.1) &&
            next_or_previous_char_is_lowercase(convertable_string, char_with_index.0)
}

#[inline]
fn snake_like_no_seperator(mut accumlator: String, current_char: &char, case: &str) -> String {
    if case == "lower" {
        accumlator.push(current_char.to_ascii_lowercase());
        accumlator
    } else {
        accumlator.push(current_char.to_ascii_uppercase());
        accumlator
    }
}

#[inline]
fn snake_like_with_seperator(mut accumlator: String, replace_with: &str, current_char: &char, case: &str) -> String {
    if case == "lower" {
        accumlator.push(replace_with.chars().nth(0).unwrap_or('_'));
        accumlator.push(current_char.to_ascii_lowercase());
        accumlator
    } else {
        accumlator.push(replace_with.chars().nth(0).unwrap_or('_'));
        accumlator.push(current_char.to_ascii_uppercase());
        accumlator
    }
}

fn next_or_previous_char_is_lowercase(convertable_string: &str, char_with_index: usize) -> bool {
    convertable_string.chars().nth(char_with_index + 1).unwrap_or('A').is_lowercase() ||
        convertable_string.chars().nth(char_with_index - 1).unwrap_or('A').is_lowercase()
}

fn char_is_uppercase(test_char: char) -> bool {
    test_char == test_char.to_ascii_uppercase()
}

#[test]
fn test_char_is_uppercase_when_it_is() {
    assert_eq!(char_is_uppercase('A'), true)
}

#[test]
fn test_char_is_uppercase_when_it_is_not() {
    assert_eq!(char_is_uppercase('a'), false)
}

#[test]
fn test_next_or_previous_char_is_lowercase_true() {
    assert_eq!(next_or_previous_char_is_lowercase("TestWWW", 3), true)
}

#[test]
fn test_next_or_previous_char_is_lowercase_false() {
    assert_eq!(next_or_previous_char_is_lowercase("TestWWW", 5), false)
}

#[test]
fn snake_like_with_seperator_lowers() {
    assert_eq!(snake_like_with_seperator("".to_owned(), "^", &'c', "lower"), "^c".to_string())
}

#[test]
fn snake_like_with_seperator_upper() {
    assert_eq!(snake_like_with_seperator("".to_owned(), "^", &'c', "upper"), "^C".to_string())
}

#[test]
fn snake_like_no_seperator_lower() {
    assert_eq!(snake_like_no_seperator("".to_owned(), &'C', "lower"), "c".to_string())
}

#[test]
fn snake_like_no_seperator_upper() {
    assert_eq!(snake_like_no_seperator("".to_owned(), &'c', "upper"), "C".to_string())
}

#[test]
fn requires_seperator_upper_not_first_wrap_is_safe_current_upper() {
    assert_eq!(requires_seperator((2, 'C'), false, "test"), true)
}

#[test]
fn requires_seperator_upper_not_first_wrap_is_safe_current_lower() {
    assert_eq!(requires_seperator((2, 'c'), false, "test"), false)
}

#[test]
fn requires_seperator_upper_first_wrap_is_safe_current_upper() {
    assert_eq!(requires_seperator((0, 'T'), true, "Test"), false)
}

#[test]
fn requires_seperator_upper_first_wrap_is_safe_current_lower() {
    assert_eq!(requires_seperator((0, 't'), true, "Test"), false)
}

#[test]
fn requires_seperator_upper_first_wrap_is_safe_current_lower_next_is_too() {
    assert_eq!(requires_seperator((0, 't'), true, "test"), false)
}

#[test]
fn test_char_is_seperator_dash() {
    assert_eq!(char_is_seperator(&'-'), true)
}

#[test]
fn test_char_is_seperator_underscore() {
    assert_eq!(char_is_seperator(&'_'), true)
}

#[test]
fn test_char_is_seperator_space() {
    assert_eq!(char_is_seperator(&' '), true)
}

#[test]
fn test_char_is_seperator_when_not() {
    assert_eq!(char_is_seperator(&'A'), false)
}

#[test]
fn test_last_char_lower_current_is_upper_or_new_word_with_new_word() {
    assert_eq!(last_char_lower_current_is_upper_or_new_word(true, ' ', '-'), true)
}

#[test]
fn test_last_char_lower_current_is_upper_or_new_word_last_char_space() {
    assert_eq!(last_char_lower_current_is_upper_or_new_word(false, ' ', '-'), false)
}

#[test]
fn test_last_char_lower_current_is_upper_or_new_word_last_char_lower_current_upper() {
    assert_eq!(last_char_lower_current_is_upper_or_new_word(false, 'a', 'A'), true)
}

#[test]
fn test_last_char_lower_current_is_upper_or_new_word_last_char_upper_current_upper() {
    assert_eq!(last_char_lower_current_is_upper_or_new_word(false, 'A', 'A'), false)
}

#[test]
fn test_last_char_lower_current_is_upper_or_new_word_last_char_upper_current_lower() {
    assert_eq!(last_char_lower_current_is_upper_or_new_word(false, 'A', 'a'), false)
}

#[test]
fn test_first_word_or_not_inverted_with_first_word() {
    assert_eq!(first_word_or_not_inverted(true, false), true)
}

#[test]
fn test_first_word_or_not_inverted_not_first_word_not_inverted() {
    assert_eq!(first_word_or_not_inverted(false, false), true)
}

#[test]
fn test_first_word_or_not_inverted_not_first_word_is_inverted() {
    assert_eq!(first_word_or_not_inverted(false, true), false)
}

#[test]
fn test_not_first_word_and_has_seperator_is_first_and_not_seperator() {
    assert_eq!(not_first_word_and_has_seperator(true, false), false)
}

#[test]
fn test_not_first_word_and_has_seperator_not_first_and_not_seperator() {
    assert_eq!(not_first_word_and_has_seperator(false, false), false)
}

#[test]
fn test_not_first_word_and_has_seperator_not_first_and_has_seperator() {
    assert_eq!(not_first_word_and_has_seperator(false, true), true)
}
<|endoftext|>


<commit_before>//! redis-rs is a rust implementation of a Redis client library.  It exposes
//! a general purpose interface to Redis and also provides specific helpers for
//! commonly used functionality.
//!
//! # Basic Operation
//!
//! To open a connection you need to create a client and then to fetch a
//! connection from it.  In the future there will be a connection pool for
//! those, currently each connection is separate and not pooled.
//!
//! Queries are then performed through the `execute` and `query` methods.
//!
//! ```rust,no_run
//! extern crate redis;
//!
//! fn main() {
//!     let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//!     let con = client.get_connection().unwrap();
//!     redis::cmd("SET").arg("my_key").arg(42i).execute(&con);
//!     assert_eq!(redis::cmd("GET").arg("my_key").query(&con), Ok(42i));
//! }
//! ```
//!
//! ## Type Conversions
//!
//! Because redis inherently is mostly type-less and the protocol is not
//! exactly friendly to developers, this library provides flexible support
//! for casting values to the intended results.  This is driven through the
//! `FromRedisValue` and `ToRedisArgs` traits.
//!
//! The `arg` method of the command will accept a wide range of types through
//! the `ToRedisArgs` trait and the `query` method of a command can convert the
//! value to what you expect the function to return through the `FromRedisValue`
//! trait.  This is quite flexible and allows vectors, tuples, hashsets, hashmaps
//! as well as optional values:
//!
//! ```rust,no_run
//! # use std::collections::{HashMap, HashSet};
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let count : i32 = redis::cmd("GET").arg("my_counter").query(&con).unwrap();
//! let count = redis::cmd("GET").arg("my_counter").query(&con).unwrap_or(0i32);
//! let k : Option<String> = redis::cmd("GET").arg("missing_key").query(&con).unwrap();
//! let name : String = redis::cmd("GET").arg("my_name").query(&con).unwrap();
//! let bin : Vec<u8> = redis::cmd("GET").arg("my_binary").query(&con).unwrap();
//! let map : HashMap<String, i32> = redis::cmd("HGETALL").arg("my_hash").query(&con).unwrap();
//! let keys : Vec<String> = redis::cmd("KEYS").query(&con).unwrap();
//! let mems : HashSet<i32> = redis::cmd("SMEMBERS").arg("s").query(&con).unwrap();
//! let (k1, k2) : (String, String) = redis::cmd("MGET").arg("k1").arg("k2").query(&con).unwrap();
//! ```
//!
//! ## Iteration Protocol
//!
//! In addition to sending a single query you iterators are also supported.  When
//! used with regular bulk responses they don't give you much over querying and
//! converting into a vector (both use a vector internally) but they can also
//! be used with `SCAN` like commands in which case iteration will send more
//! queries until the cursor is exhausted:
//!
//! ```rust,no_run
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let mut cmd = redis::cmd("SSCAN");
//! let mut iter : redis::Iter<int> = cmd.arg("my_set").cursor_arg(0).iter(&con).unwrap();
//! for x in iter {
//!     // do something with the item
//! }
//! ```
//!
//! As you can see the cursor argument needs to be defined with `cursor_arg` instead
//! of `arg` so that the library knows which argument needs updating as the
//! query is run for more items.
//!
//! ## Pipelining
//!
//! In addition to simple queries you can also send command pipelines.  This
//! is provided through the `pipe` function.  It works very similar to sending
//! individual commands but you can send more than one in one go.  This also
//! allows you to ignore individual results so that matching on the end result
//! is easier:
//!
//! ```rust,no_run
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let (k1, k2) : (i32, i32) = redis::pipe()
//!     .cmd("SET").arg("key_1").arg(42i).ignore()
//!     .cmd("SET").arg("key_2").arg(43i).ignore()
//!     .cmd("GET").arg("key_1")
//!     .cmd("GET").arg("key_2").query(&con).unwrap();
//! ```
//!
//! If you want the pipeline to be wrapped in a `MULTI`/`EXEC` block you can
//! easily do that by switching the pipeline into `atomic` mode.  From the
//! caller's point of view nothing changes, the pipeline itself will take
//! care of the rest for you:
//!
//! ```rust,no_run
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let (k1, k2) : (i32, i32) = redis::pipe()
//!     .atomic()
//!     .cmd("SET").arg("key_1").arg(42i).ignore()
//!     .cmd("SET").arg("key_2").arg(43i).ignore()
//!     .cmd("GET").arg("key_1")
//!     .cmd("GET").arg("key_2").query(&con).unwrap();
//! ```
//!
//! ## Transactions
//!
//! Transactions are available through atomic pipelines.  In order to use
//! them in a more simple way you can use the `transaction` function of a
//! connection:
//! ```rust,no_run
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let key = "the_key";
//! let (new_val,) : (int,) = con.transaction([key][], |pipe| {
//!     let old_val : int = try!(redis::cmd("GET").arg(key).query(&con));
//!     pipe
//!         .cmd("SET").arg(key).arg(old_val + 1).ignore()
//!         .cmd("GET").arg(key).query(&con)
//! }).unwrap();
//! println!("The incremented number is: {}", new_val);
//! ```
//!
//! For more information see the `transaction` function.
//!
//! ## PubSub
//!
//! Pubsub is currently work in progress but provided through the `PubSub`
//! connection object.  Due to the fact that Rust does not have support
//! for async IO in libnative yet, the API does not provide a way to
//! read messages with any form of timeout yet.
//!
//! Example usage:
//!
//! ```rust,no_run
//! let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! let mut pubsub = client.get_pubsub().unwrap();
//! pubsub.subscribe("channel_1").unwrap();
//! pubsub.subscribe("channel_2").unwrap();
//!
//! loop {
//!     let msg = pubsub.get_message().unwrap();
//!     let payload : String = msg.get_payload().unwrap();
//!     println!("channel '{}': {}", msg.get_channel_name(), payload);
//! }
//! ```

#![crate_name = "redis"]
#![crate_type = "lib"]
#![license = "BSD"]
#![comment = "Bindings and wrapper functions for redis."]

#![deny(non_camel_case_types)]

#![feature(macro_rules)]
#![feature(default_type_params)]

#![experimental]

extern crate url;
extern crate serialize;

/* public api */
pub use parser::{parse_redis_value, Parser};
pub use client::Client;
pub use connection::{Connection, PubSub, Msg};
pub use cmd::{cmd, Cmd, pipe, Pipeline, Iter, pack_command};

#[doc(hidden)]
pub use types::{
    /* low level values */
    Value,
        Nil,
        Int,
        Data,
        Bulk,
        Okay,
        Status,

    /* error and result types */
    Error,
    RedisResult,

    /* error kinds */
    ErrorKind,
        ResponseError,
        TypeError,
        ExecAbortError,
        BusyLoadingError,
        NoScriptError,
        ExtensionError,
        InternalIoError,

    /* utility types */
    InfoDict,

    /* conversion traits */
    FromRedisValue,
    ToRedisArgs,

    /* utility functions */
    from_redis_value,
};

pub mod macros;

mod parser;
mod client;
mod connection;
mod types;
mod cmd;
<commit_msg>Fixed example formatting<commit_after>//! redis-rs is a rust implementation of a Redis client library.  It exposes
//! a general purpose interface to Redis and also provides specific helpers for
//! commonly used functionality.
//!
//! # Basic Operation
//!
//! To open a connection you need to create a client and then to fetch a
//! connection from it.  In the future there will be a connection pool for
//! those, currently each connection is separate and not pooled.
//!
//! Queries are then performed through the `execute` and `query` methods.
//!
//! ```rust,no_run
//! extern crate redis;
//!
//! fn main() {
//!     let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//!     let con = client.get_connection().unwrap();
//!     redis::cmd("SET").arg("my_key").arg(42i).execute(&con);
//!     assert_eq!(redis::cmd("GET").arg("my_key").query(&con), Ok(42i));
//! }
//! ```
//!
//! ## Type Conversions
//!
//! Because redis inherently is mostly type-less and the protocol is not
//! exactly friendly to developers, this library provides flexible support
//! for casting values to the intended results.  This is driven through the
//! `FromRedisValue` and `ToRedisArgs` traits.
//!
//! The `arg` method of the command will accept a wide range of types through
//! the `ToRedisArgs` trait and the `query` method of a command can convert the
//! value to what you expect the function to return through the `FromRedisValue`
//! trait.  This is quite flexible and allows vectors, tuples, hashsets, hashmaps
//! as well as optional values:
//!
//! ```rust,no_run
//! # use std::collections::{HashMap, HashSet};
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let count : i32 = redis::cmd("GET").arg("my_counter").query(&con).unwrap();
//! let count = redis::cmd("GET").arg("my_counter").query(&con).unwrap_or(0i32);
//! let k : Option<String> = redis::cmd("GET").arg("missing_key").query(&con).unwrap();
//! let name : String = redis::cmd("GET").arg("my_name").query(&con).unwrap();
//! let bin : Vec<u8> = redis::cmd("GET").arg("my_binary").query(&con).unwrap();
//! let map : HashMap<String, i32> = redis::cmd("HGETALL").arg("my_hash").query(&con).unwrap();
//! let keys : Vec<String> = redis::cmd("KEYS").query(&con).unwrap();
//! let mems : HashSet<i32> = redis::cmd("SMEMBERS").arg("s").query(&con).unwrap();
//! let (k1, k2) : (String, String) = redis::cmd("MGET").arg("k1").arg("k2").query(&con).unwrap();
//! ```
//!
//! ## Iteration Protocol
//!
//! In addition to sending a single query you iterators are also supported.  When
//! used with regular bulk responses they don't give you much over querying and
//! converting into a vector (both use a vector internally) but they can also
//! be used with `SCAN` like commands in which case iteration will send more
//! queries until the cursor is exhausted:
//!
//! ```rust,no_run
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let mut cmd = redis::cmd("SSCAN");
//! let mut iter : redis::Iter<int> = cmd.arg("my_set").cursor_arg(0).iter(&con).unwrap();
//! for x in iter {
//!     // do something with the item
//! }
//! ```
//!
//! As you can see the cursor argument needs to be defined with `cursor_arg` instead
//! of `arg` so that the library knows which argument needs updating as the
//! query is run for more items.
//!
//! ## Pipelining
//!
//! In addition to simple queries you can also send command pipelines.  This
//! is provided through the `pipe` function.  It works very similar to sending
//! individual commands but you can send more than one in one go.  This also
//! allows you to ignore individual results so that matching on the end result
//! is easier:
//!
//! ```rust,no_run
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let (k1, k2) : (i32, i32) = redis::pipe()
//!     .cmd("SET").arg("key_1").arg(42i).ignore()
//!     .cmd("SET").arg("key_2").arg(43i).ignore()
//!     .cmd("GET").arg("key_1")
//!     .cmd("GET").arg("key_2").query(&con).unwrap();
//! ```
//!
//! If you want the pipeline to be wrapped in a `MULTI`/`EXEC` block you can
//! easily do that by switching the pipeline into `atomic` mode.  From the
//! caller's point of view nothing changes, the pipeline itself will take
//! care of the rest for you:
//!
//! ```rust,no_run
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let (k1, k2) : (i32, i32) = redis::pipe()
//!     .atomic()
//!     .cmd("SET").arg("key_1").arg(42i).ignore()
//!     .cmd("SET").arg("key_2").arg(43i).ignore()
//!     .cmd("GET").arg("key_1")
//!     .cmd("GET").arg("key_2").query(&con).unwrap();
//! ```
//!
//! ## Transactions
//!
//! Transactions are available through atomic pipelines.  In order to use
//! them in a more simple way you can use the `transaction` function of a
//! connection:
//!
//! ```rust,no_run
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let key = "the_key";
//! let (new_val,) : (int,) = con.transaction([key][], |pipe| {
//!     let old_val : int = try!(redis::cmd("GET").arg(key).query(&con));
//!     pipe
//!         .cmd("SET").arg(key).arg(old_val + 1).ignore()
//!         .cmd("GET").arg(key).query(&con)
//! }).unwrap();
//! println!("The incremented number is: {}", new_val);
//! ```
//!
//! For more information see the `transaction` function.
//!
//! ## PubSub
//!
//! Pubsub is currently work in progress but provided through the `PubSub`
//! connection object.  Due to the fact that Rust does not have support
//! for async IO in libnative yet, the API does not provide a way to
//! read messages with any form of timeout yet.
//!
//! Example usage:
//!
//! ```rust,no_run
//! let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! let mut pubsub = client.get_pubsub().unwrap();
//! pubsub.subscribe("channel_1").unwrap();
//! pubsub.subscribe("channel_2").unwrap();
//!
//! loop {
//!     let msg = pubsub.get_message().unwrap();
//!     let payload : String = msg.get_payload().unwrap();
//!     println!("channel '{}': {}", msg.get_channel_name(), payload);
//! }
//! ```

#![crate_name = "redis"]
#![crate_type = "lib"]
#![license = "BSD"]
#![comment = "Bindings and wrapper functions for redis."]

#![deny(non_camel_case_types)]

#![feature(macro_rules)]
#![feature(default_type_params)]

#![experimental]

extern crate url;
extern crate serialize;

/* public api */
pub use parser::{parse_redis_value, Parser};
pub use client::Client;
pub use connection::{Connection, PubSub, Msg};
pub use cmd::{cmd, Cmd, pipe, Pipeline, Iter, pack_command};

#[doc(hidden)]
pub use types::{
    /* low level values */
    Value,
        Nil,
        Int,
        Data,
        Bulk,
        Okay,
        Status,

    /* error and result types */
    Error,
    RedisResult,

    /* error kinds */
    ErrorKind,
        ResponseError,
        TypeError,
        ExecAbortError,
        BusyLoadingError,
        NoScriptError,
        ExtensionError,
        InternalIoError,

    /* utility types */
    InfoDict,

    /* conversion traits */
    FromRedisValue,
    ToRedisArgs,

    /* utility functions */
    from_redis_value,
};

pub mod macros;

mod parser;
mod client;
mod connection;
mod types;
mod cmd;
<|endoftext|>


<commit_before>extern crate regex;

mod matching;
mod support;
mod tokens;
mod lexer;
mod files;
mod parser;
mod symbols;
mod symbol_table;

use std::vec::Vec;
use tokens::*;
use lexer::*;
use parser::*;
use symbols::*;
use symbol_table::*;

fn main()
{
    let source_file = "sampleData/BasicArithmatic.java";
    let lex_output_file = "sampleData/output/stable/BasicArithmatic.java.lexed";
    let preprocessed_output_file = "sampleData/output/stable/BasicArithmatic.java.preprocessed";

    let mut tokens: Vec<Token> = lex_file(source_file);

    println!("\n\nFound Tokens:");
    tokens.print_to(lex_output_file, true);

    remove_meta(&mut tokens);
    println!("\n\nPerged Tokens:");
    tokens.print_to(preprocessed_output_file, true);

    let mut symbols_table = SymbolTable::new();
    parse_class(&tokens, 1, &mut symbols_table);

    if tokens[0].value != "class"
    {
        panic!("Unexpected token: {}: {}", tokens[0].value, tokens[0].name);
    }

    let (last_index, asm_string) = compile_class(&tokens, 1);
}

fn parse_class(tokens: &Vec<Token>, start_index: usize, symbols_table: &mut SymbolTable)
{
    let mut static_variables: Vec<(usize, usize)> = Vec::new();
    let mut static_methods: Vec<(usize, usize)> = Vec::new();
    let mut static_classes: Vec<(usize, usize)> = Vec::new();
    let mut non_static_variables: Vec<(usize, usize)> = Vec::new();
    let mut non_static_methods: Vec<(usize, usize)> = Vec::new();
    let mut non_static_classes: Vec<(usize, usize)> = Vec::new();

    println!("\n<------------ Parse Class --------------->");
    let mut min_value = 0;
    let mut skip_amount = 0;

    for (index, token) in tokens.iter().enumerate()
    {
        if min_value != 0
        {
            min_value -= 1;
            continue;
        }
        //Static Variable/Method/Class
        if token.name == "mod.access"
        {
            skip_amount = 3;
            if tokens[index + skip_amount].name.starts_with("operator")
            {
                println!("------Incoming Static Variable Decl!");

                let (low, high) = symbols_table.get_variable_locations(tokens, index + 1);
                symbols_table.static_variables.push((low, high));

                min_value =  low;
                min_value -= index;
            }
            else if tokens[index + 1].name.starts_with("construct")
            {
                if tokens[index + skip_amount].name.starts_with("control")
                {
                    println!("------Incoming Static Class Decl!");
                    min_value = find_outer_ending_brace(tokens, index);
                    static_classes.push((index + 2, min_value));
                    min_value -= index;
                }
                else
                {
                    panic!("Unsupported or Unexpected token: {} + {}.", tokens[index + skip_amount].value, tokens[index + skip_amount].name);
                }

            }
            else if tokens[index + skip_amount].name.starts_with("control")
            {
                println!("------Incoming Static Method Decl!");
                min_value = find_outer_ending_brace(tokens, index);
                static_methods.push((index + 1, min_value));
                min_value -=  index;
            }
            else
            {
                panic!("Unsupported or Unexpected token: {} + {}.", tokens[index + skip_amount].value, tokens[index + skip_amount].name);
            }

        }
        //Non-Static Variable/Method/Class
        else if token.name.starts_with("construct")
        {
            skip_amount = 2;
            if tokens[index + skip_amount].name.starts_with("control")
            {
                println!("------Incoming Non-Static Class Decl!");
                min_value = find_outer_ending_brace(tokens, index);
                non_static_classes.push((index + 1, min_value));
                min_value = 0;
            }
            else
            {
                panic!("Unsupported or Unexpected token: {} + {}.", tokens[index + skip_amount].value, tokens[index + skip_amount].name);
            }
        }
        //Non-Static Variable/Method/Class
        else if token.name == "type"
        {
            skip_amount = 2;

            if tokens[index + skip_amount].name.starts_with("control")
            {
                println!("------Incoming Non-Static Method Decl!");
                min_value = find_outer_ending_brace(tokens, index);
                non_static_methods.push((index, min_value));
                min_value -= index;
                //check for control
            }
            else if tokens[index + skip_amount].name.starts_with("operator")
            {
                println!("------Incoming Non-Static Variable Decl!");
                min_value =  find_next_semicolon(tokens, index);
                non_static_variables.push((index, min_value));
                min_value -= index;
            }
        }
        println!("\tIndex: {} | Token -> {} : {}", index, token.value, token.name );
        //deal with parameters
    }
    println!("\n<---------------- Static Variables --------------->");
    for &(start, end) in symbols_table.static_variables.iter()
    {
        println!("Start/End {}/{}", start, end);
    }

    println!("\n<---------------- Static Classes ----------------->");
    for &(start, end) in static_classes.iter()
    {
        println!("Start/End {}/{}", start, end);
    }

    println!("\n<---------------- Static Methods ----------------->");
    for &(start, end) in static_methods.iter()
    {
        println!("Start/End {}/{}", start, end);
    }

    println!("\n<---------------- Non-Static Variables --------------->");
    for &(start, end) in non_static_variables.iter()
    {
        println!("Start/End {}/{}", start, end);
    }

    println!("\n<---------------- Non-Static Classes ----------------->");
    for &(start, end) in non_static_classes.iter()
    {
        println!("Start/End {}/{}", start, end);
    }

    println!("\n<---------------- Non-Static Methods ----------------->");
    for &(start, end) in non_static_methods.iter()
    {
        println!("Start/End {}/{}", start, end);
    }
    println!("\n");
}

fn compile_class(tokens: &Vec<Token>, start_index: usize) -> (usize, String)
{
    let invalid_types = get_invalid_token_types();
    let invalid_values = get_invalid_token_values();

    let mut plp_string: String = String::new();
    let mut current_index: usize = start_index;

    if tokens[current_index].value != "{" { panic!("Expected '{{' received: {}", tokens[current_index].value); }
    else { current_index += 1; }

    for (index, token) in tokens.iter().enumerate()
    {
        // Handle forward skipping
        if index < current_index { continue; }
        else { current_index = index; }

        // TODO: encapsulate into token_rules.validate(token)
        // Panic! if token type is invalid
        if invalid_types.contains(&token.name)
        {
            panic!("Unsupported token type: {}", token.name);
        }
        // Panic! if token value is invalid
        else if invalid_values.contains(&&*token.value)
        {
            panic!("Unsupported token value: {}", token.value);
        }

        if token.value == "class"
        {
            // parse class body
            let (end_index, compiled_class) = compile_class(&tokens, index + 1);
            plp_string.push_str(&*compiled_class);

            current_index = end_index;
        }
        else if token.name == "type" // || token.name == "identifier"
        {
            // look ahead
            // parse variable declaration
            // OR parse method declaration
        }
        else if token.value == "if"
        {
            // parse if body
            // Unsupported for now
        }
        else if token.name == "construct.conditional"
        {
            // parse conditional
            // Unsupported for now
        }
        else
        {
            panic!("Unexpected token: {}\t{}", token.name, token.value);
        }
    }

    (current_index + 1, plp_string)
}

fn remove_meta(tokens: &mut Vec<Token>)
{
    // Indecies of tokens vector to be removed
    let mut invalid_indecies: Vec<usize> = Vec::new();

    let mut min_index: usize = 0;
    for (index, token) in tokens.iter().enumerate()
    {
        // Allow forward skipping (by setting min_index)
        if index < min_index
        {
            invalid_indecies.push(index);
        }
        // Remove imports
        else if token.name == "special.import"
        {
            invalid_indecies.push(index);
            min_index = index + 2; // skip the next token (semi-colon)
        }
        // Remove comments
        else if token.name.starts_with("comment")
        {
            invalid_indecies.push(index);
        }
        // Remove all modifiers (public, private, volatile, transient, static, etc.)
        else if token.name.starts_with("mod")
        {
            if token.name.ends_with("access")
            {
                continue;
            }
            invalid_indecies.push(index);
        }
        // Remove package declarations
        else if token.name == "special.package"
        {
            if token.name.ends_with("package")
            {
                continue;
            }
            invalid_indecies.push(index);
            min_index = find_next_semicolon(tokens, index) + 1;
        }
    }

    // count := how many indecies have already been removed
    // index := the index in the original tokens vector that should be removed
    for (count, index) in invalid_indecies.iter().enumerate()
    {
        // "index" refers to the index before any others were removed. Therefore, it must be offset by the number of removed tokens
        tokens.remove(index - count);
    }
}

fn compile_arithmetic_statement(tokens: &Vec<Token>, start: usize, temp_registers: (&str, &str), var_registers: (&str, &str), load_registers: (&str, &str)) -> (String, usize)
{
    let mut compiled_code = String::new();
    if tokens[start].value.starts_with("literal")
    {
        compiled_code.push_str("li ");
        compiled_code.push_str(temp_registers.0);
        compiled_code.push_str(", ");
        compiled_code.push_str(&*tokens[start].value);
        compiled_code.push_str("\n");
    }

    let mut index = start;
    while tokens[index].value != ";"
    {
        while tokens[index].name == "control" // ignore parenthesis
        {
            index += 1;
        }
        if !tokens[index].name.starts_with("operator")
        {
            let current_token = &tokens[index];
            panic!("Unexpected token while parsing arithmetic statement: {}: {}", current_token.value, current_token.name);
        }

        let operator = &tokens[index];
        while tokens[index].name == "control" // ignore parenthesis
        {
            index += 1;
        }
        let operand = &tokens[index + 1];
        if operand.name.starts_with("literal")
        {
            // TODO: use immediate operators
            compiled_code.push_str("li ");
            compiled_code.push_str(temp_registers.1);
            compiled_code.push_str(", ");
            compiled_code.push_str(&*operand.value);
            compiled_code.push_str("\n");
        }
        else if operand.name.starts_with("identifier")
        {
            // TODO: lookup memory location from symbols table

            // TODO: parse method calls
        }

        let line = compile_arithmetic_operation(operator, temp_registers, temp_registers.0);
        compiled_code.push_str(&*line);
        index += 2;
    }

    (compiled_code, index + 1)
}

fn compile_arithmetic_operation(operator: &Token, operand_registers: (&str, &str), result_register: &str) -> String
{
    let mut compiled_code = String::new();

    if operator.name != "operator.binary"
    {
        panic!("Unsupported operator: {}: {}", operator.name, operator.value);
    }
    else if operator.value == "+"
    {
        compiled_code.push_str("addu ");
    }
    else if operator.value == "-"
    {
        compiled_code.push_str("subu ");
    }
    else if operator.value == "*"
    {
        compiled_code.push_str("mullo ");
    }
    else
    {
        panic!("Unsupported operator: {}: {}", operator.name, operator.value);
    }

    compiled_code.push_str(result_register);
    compiled_code.push_str(", ");
    compiled_code.push_str(operand_registers.0);
    compiled_code.push_str(", ");
    compiled_code.push_str(operand_registers.1);
    compiled_code.push_str("\n");

    compiled_code
}

fn find_next_semicolon(tokens: &Vec<Token>, start: usize) -> usize
{
    for (index, token) in tokens[start..].iter().enumerate()
    {
        if token.value == ";" { return index + start; }
    }

    return 0;
}

fn find_outer_ending_brace(tokens: &Vec<Token>, start: usize) -> usize
{
    let mut open_braces = 0;

    for(index, token) in tokens[start..].iter().enumerate()
    {
        if token.value == "{"
        {
            open_braces += 1;
        }
        else if token.value == "}"
        {
            open_braces -= 1;
            if open_braces == 0
            {
                return index + start;
            }
        }
    }

    return 0;
}
<commit_msg>Update remove_meta() function<commit_after>extern crate regex;

mod matching;
mod support;
mod tokens;
mod lexer;
mod files;
mod parser;
mod symbols;
mod symbol_table;

use std::vec::Vec;
use tokens::*;
use lexer::*;
use parser::*;
use symbols::*;
use symbol_table::*;

fn main()
{
    let source_file = "sampleData/BasicArithmatic.java";
    let lex_output_file = "sampleData/output/stable/BasicArithmatic.java.lexed";
    let preprocessed_output_file = "sampleData/output/stable/BasicArithmatic.java.preprocessed";

    let mut tokens: Vec<Token> = lex_file(source_file);

    println!("\n\nFound Tokens:");
    tokens.print_to(lex_output_file, true);

    remove_meta(&mut tokens);
    println!("\n\nPerged Tokens:");
    tokens.print_to(preprocessed_output_file, true);

    let mut symbols_table = SymbolTable::new();
    parse_class(&tokens, 1, &mut symbols_table);

    if tokens[0].value != "class"
    {
        panic!("Unexpected token: {}: {}", tokens[0].value, tokens[0].name);
    }

    let (last_index, asm_string) = compile_class(&tokens, 1);
}

fn parse_class(tokens: &Vec<Token>, start_index: usize, symbols_table: &mut SymbolTable)
{
    let mut static_variables: Vec<(usize, usize)> = Vec::new();
    let mut static_methods: Vec<(usize, usize)> = Vec::new();
    let mut static_classes: Vec<(usize, usize)> = Vec::new();
    let mut non_static_variables: Vec<(usize, usize)> = Vec::new();
    let mut non_static_methods: Vec<(usize, usize)> = Vec::new();
    let mut non_static_classes: Vec<(usize, usize)> = Vec::new();

    println!("\n<------------ Parse Class --------------->");
    let mut min_value = 0;
    let mut skip_amount = 0;

    for (index, token) in tokens.iter().enumerate()
    {
        if min_value != 0
        {
            min_value -= 1;
            continue;
        }
        //Static Variable/Method/Class
        if token.name == "mod.access"
        {
            skip_amount = 3;
            if tokens[index + skip_amount].name.starts_with("operator")
            {
                println!("------Incoming Static Variable Decl!");

                let (low, high) = symbols_table.get_variable_locations(tokens, index + 1);
                symbols_table.static_variables.push((low, high));

                min_value =  low;
                min_value -= index;
            }
            else if tokens[index + 1].name.starts_with("construct")
            {
                if tokens[index + skip_amount].name.starts_with("control")
                {
                    println!("------Incoming Static Class Decl!");
                    min_value = find_outer_ending_brace(tokens, index);
                    static_classes.push((index + 2, min_value));
                    min_value -= index;
                }
                else
                {
                    panic!("Unsupported or Unexpected token: {} + {}.", tokens[index + skip_amount].value, tokens[index + skip_amount].name);
                }

            }
            else if tokens[index + skip_amount].name.starts_with("control")
            {
                println!("------Incoming Static Method Decl!");
                min_value = find_outer_ending_brace(tokens, index);
                static_methods.push((index + 1, min_value));
                min_value -=  index;
            }
            else
            {
                panic!("Unsupported or Unexpected token: {} + {}.", tokens[index + skip_amount].value, tokens[index + skip_amount].name);
            }

        }
        //Non-Static Variable/Method/Class
        else if token.name.starts_with("construct")
        {
            skip_amount = 2;
            if tokens[index + skip_amount].name.starts_with("control")
            {
                println!("------Incoming Non-Static Class Decl!");
                min_value = find_outer_ending_brace(tokens, index);
                non_static_classes.push((index + 1, min_value));
                min_value = 0;
            }
            else
            {
                panic!("Unsupported or Unexpected token: {} + {}.", tokens[index + skip_amount].value, tokens[index + skip_amount].name);
            }
        }
        //Non-Static Variable/Method/Class
        else if token.name == "type"
        {
            skip_amount = 2;

            if tokens[index + skip_amount].name.starts_with("control")
            {
                println!("------Incoming Non-Static Method Decl!");
                min_value = find_outer_ending_brace(tokens, index);
                non_static_methods.push((index, min_value));
                min_value -= index;
                //check for control
            }
            else if tokens[index + skip_amount].name.starts_with("operator")
            {
                println!("------Incoming Non-Static Variable Decl!");
                min_value =  find_next_semicolon(tokens, index);
                non_static_variables.push((index, min_value));
                min_value -= index;
            }
        }
        println!("\tIndex: {} | Token -> {} : {}", index, token.value, token.name );
        //deal with parameters
    }
    println!("\n<---------------- Static Variables --------------->");
    for &(start, end) in symbols_table.static_variables.iter()
    {
        println!("Start/End {}/{}", start, end);
    }

    println!("\n<---------------- Static Classes ----------------->");
    for &(start, end) in static_classes.iter()
    {
        println!("Start/End {}/{}", start, end);
    }

    println!("\n<---------------- Static Methods ----------------->");
    for &(start, end) in static_methods.iter()
    {
        println!("Start/End {}/{}", start, end);
    }

    println!("\n<---------------- Non-Static Variables --------------->");
    for &(start, end) in non_static_variables.iter()
    {
        println!("Start/End {}/{}", start, end);
    }

    println!("\n<---------------- Non-Static Classes ----------------->");
    for &(start, end) in non_static_classes.iter()
    {
        println!("Start/End {}/{}", start, end);
    }

    println!("\n<---------------- Non-Static Methods ----------------->");
    for &(start, end) in non_static_methods.iter()
    {
        println!("Start/End {}/{}", start, end);
    }
    println!("\n");
}

fn compile_class(tokens: &Vec<Token>, start_index: usize) -> (usize, String)
{
    let invalid_types = get_invalid_token_types();
    let invalid_values = get_invalid_token_values();

    let mut plp_string: String = String::new();
    let mut current_index: usize = start_index;

    if tokens[current_index].value != "{" { panic!("Expected '{{' received: {}", tokens[current_index].value); }
    else { current_index += 1; }

    for (index, token) in tokens.iter().enumerate()
    {
        // Handle forward skipping
        if index < current_index { continue; }
        else { current_index = index; }

        // TODO: encapsulate into token_rules.validate(token)
        // Panic! if token type is invalid
        if invalid_types.contains(&token.name)
        {
            panic!("Unsupported token type: {}", token.name);
        }
        // Panic! if token value is invalid
        else if invalid_values.contains(&&*token.value)
        {
            panic!("Unsupported token value: {}", token.value);
        }

        if token.value == "class"
        {
            // parse class body
            let (end_index, compiled_class) = compile_class(&tokens, index + 1);
            plp_string.push_str(&*compiled_class);

            current_index = end_index;
        }
        else if token.name == "type" // || token.name == "identifier"
        {
            // look ahead
            // parse variable declaration
            // OR parse method declaration
        }
        else if token.value == "if"
        {
            // parse if body
            // Unsupported for now
        }
        else if token.name == "construct.conditional"
        {
            // parse conditional
            // Unsupported for now
        }
        else
        {
            panic!("Unexpected token: {}\t{}", token.name, token.value);
        }
    }

    (current_index + 1, plp_string)
}

/// Removes all meta tokens from the give Vector
/// Meta tokens include:
/// * comments
/// * imports
/// * permission modifiers (public, private, protected)
///
/// Note that in future versions, imports will not be removed.
fn remove_meta(tokens: &mut Vec<Token>)
{
    // Indecies of tokens vector to be removed
    let mut invalid_indecies: Vec<usize> = Vec::new();

    let mut min_index: usize = 0;
    for (index, token) in tokens.iter().enumerate()
    {
        // Allow forward skipping (by setting min_index)
        if index < min_index
        {
            invalid_indecies.push(index);
        }
        // Remove imports
        else if token.name == "special.import"
        {
            invalid_indecies.push(index);
            min_index = index + 2; // skip the next token (semi-colon)
        }
        // Remove comments
        else if token.name.starts_with("comment")
        {
            invalid_indecies.push(index);
        }
        // Remove all permission modifiers (public, private, protected)
        else if token.name == "mod.permission"
        {
            invalid_indecies.push(index);
        }
    }

    // count := how many indecies have already been removed
    // index := the index in the original tokens vector that should be removed
    for (count, index) in invalid_indecies.iter().enumerate()
    {
        // "index" refers to the index before any others were removed. Therefore, it must be offset by the number of removed tokens
        tokens.remove(index - count);
    }
}

fn compile_arithmetic_statement(tokens: &Vec<Token>, start: usize, temp_registers: (&str, &str), var_registers: (&str, &str), load_registers: (&str, &str)) -> (String, usize)
{
    let mut compiled_code = String::new();
    if tokens[start].value.starts_with("literal")
    {
        compiled_code.push_str("li ");
        compiled_code.push_str(temp_registers.0);
        compiled_code.push_str(", ");
        compiled_code.push_str(&*tokens[start].value);
        compiled_code.push_str("\n");
    }

    let mut index = start;
    while tokens[index].value != ";"
    {
        while tokens[index].name == "control" // ignore parenthesis
        {
            index += 1;
        }
        if !tokens[index].name.starts_with("operator")
        {
            let current_token = &tokens[index];
            panic!("Unexpected token while parsing arithmetic statement: {}: {}", current_token.value, current_token.name);
        }

        let operator = &tokens[index];
        while tokens[index].name == "control" // ignore parenthesis
        {
            index += 1;
        }
        let operand = &tokens[index + 1];
        if operand.name.starts_with("literal")
        {
            // TODO: use immediate operators
            compiled_code.push_str("li ");
            compiled_code.push_str(temp_registers.1);
            compiled_code.push_str(", ");
            compiled_code.push_str(&*operand.value);
            compiled_code.push_str("\n");
        }
        else if operand.name.starts_with("identifier")
        {
            // TODO: lookup memory location from symbols table

            // TODO: parse method calls
        }

        let line = compile_arithmetic_operation(operator, temp_registers, temp_registers.0);
        compiled_code.push_str(&*line);
        index += 2;
    }

    (compiled_code, index + 1)
}

fn compile_arithmetic_operation(operator: &Token, operand_registers: (&str, &str), result_register: &str) -> String
{
    let mut compiled_code = String::new();

    if operator.name != "operator.binary"
    {
        panic!("Unsupported operator: {}: {}", operator.name, operator.value);
    }
    else if operator.value == "+"
    {
        compiled_code.push_str("addu ");
    }
    else if operator.value == "-"
    {
        compiled_code.push_str("subu ");
    }
    else if operator.value == "*"
    {
        compiled_code.push_str("mullo ");
    }
    else
    {
        panic!("Unsupported operator: {}: {}", operator.name, operator.value);
    }

    compiled_code.push_str(result_register);
    compiled_code.push_str(", ");
    compiled_code.push_str(operand_registers.0);
    compiled_code.push_str(", ");
    compiled_code.push_str(operand_registers.1);
    compiled_code.push_str("\n");

    compiled_code
}

fn find_next_semicolon(tokens: &Vec<Token>, start: usize) -> usize
{
    for (index, token) in tokens[start..].iter().enumerate()
    {
        if token.value == ";" { return index + start; }
    }

    return 0;
}

fn find_outer_ending_brace(tokens: &Vec<Token>, start: usize) -> usize
{
    let mut open_braces = 0;

    for(index, token) in tokens[start..].iter().enumerate()
    {
        if token.value == "{"
        {
            open_braces += 1;
        }
        else if token.value == "}"
        {
            open_braces -= 1;
            if open_braces == 0
            {
                return index + start;
            }
        }
    }

    return 0;
}
<|endoftext|>


<commit_before>/*!
Rectangle Functions
 */

use std::mem;
use libc::c_int;

/// A structure that defines a two dimensional point.
#[deriving(PartialEq, Clone, Show)]
#[repr(C)]
pub struct Point {
    pub x: i32,
    pub y: i32
}

/// A structure that defines a rectangle, with the origin at the upper left.
#[deriving(PartialEq, Clone, Show)]
#[repr(C)]
pub struct Rect {
    pub x: i32,
    pub y: i32,
    pub w: i32,
    pub h: i32
}

#[doc(hidden)]
#[allow(non_camel_case_types)]
pub mod ll {

    use libc::c_int;
    use super::Rect;
    use super::Point;

    pub type SDL_Rect = Rect;
    pub type SDL_Point = Point;
    pub type SDL_bool = c_int;

    extern "C" {
        pub fn SDL_HasIntersection(A: *const SDL_Rect, B: *const SDL_Rect) -> SDL_bool;
        pub fn SDL_IntersectRect(A: *const SDL_Rect, B: *const SDL_Rect, result: *const SDL_Rect) -> SDL_bool;
        pub fn SDL_UnionRect(A: *const SDL_Rect, B: *const SDL_Rect, result: *const SDL_Rect);
        pub fn SDL_EnclosePoints(points: *const SDL_Point, count: c_int, clip: *const SDL_Rect, result: *const SDL_Rect) -> SDL_bool;
        pub fn SDL_IntersectRectAndLine(rect: *const SDL_Rect, X1: *const c_int, Y1: *const c_int, X2: *const c_int, Y2: *const c_int) -> SDL_bool;
    }
}

impl Point {
    pub fn new(x: i32, y: i32) -> Point {
        Point {
            x: x,
            y: y
        }
    }
}

impl Rect {
    pub fn new(x: i32, y: i32, w: i32, h: i32) -> Rect {
        Rect {
            x: x,
            y: y,
            w: w,
            h: h
        }
    }

    /// Calculate a minimal rectangle enclosing a set of points.
    pub fn from_enclose_points(points: &[Point], clip: Option<Rect>) -> Option<Rect> {
        let out: Rect = Rect::new(0, 0, 0, 0);

        let result = unsafe {
            ll::SDL_EnclosePoints(
                mem::transmute(points.as_ptr()),
                points.len() as c_int,
                mem::transmute(clip.as_ref()),
                &out
            ) != 0
        };

        if result {
            Some(out)
        } else {
            None
        }
    }

    /// Check whether a rectangle has no area.
    pub fn is_empty(&self) -> bool {
        (self.w <= 0) || (self.h <= 0)
    }

    /// Determine whether two rectangles intersect.
    pub fn has_intersection(&self, other: &Rect) -> bool {
        unsafe {
            ll::SDL_HasIntersection(self, other) != 0
        }
    }

    /// Calculate the intersection of two rectangles.
    pub fn intersection(&self, other: &Rect) -> Option<Rect> {
        let out: Rect = Rect::new(0, 0, 0, 0);

        let result = unsafe {
            ll::SDL_IntersectRect(self, other, &out) != 0
        };

        if result {
            Some(out)
        } else {
            None
        }
    }

    /// Calculate the union of two rectangles.
    pub fn union(&self, other: &Rect) -> Rect {
        let out: Rect = Rect::new(0, 0, 0, 0);

        unsafe {
            ll::SDL_UnionRect(self, other, &out)
        };

        out
    }

    /// Calculate the intersection of a rectangle and line segment. return points of intersection.
    pub fn intersect_line(&self, start: &Point, end: &Point) -> Option<(Point, Point)> {
        let out_start: Point = start.clone();
        let out_end: Point = end.clone();

        let result = unsafe {
            ll::SDL_IntersectRectAndLine(self, &out_start.x, &out_start.y, &out_end.x, &out_end.y) != 0
        };

        if result {
            Some((out_start, out_end))
        } else {
            None
        }
    }
}

#[cfg(test)]
mod test {
    //use super::*;
    use super::{Rect, Point};

    #[test]
    fn test_from_enclose_points() {
        assert_eq!(Rect::from_enclose_points(&[Point::new(2, 4), Point::new(5,9)], None),
                   Some(Rect::new(2, 4, 4, 6)));
        assert!(Rect::from_enclose_points(&[Point::new(0, 0), Point::new(10,10)],
                                          Some(Rect::new(3, 3, 1, 1))).is_none());
    }

    #[test]
    fn test_has_intersection() {
        assert!(Rect::new(0, 0, 10, 10).has_intersection(&Rect::new(9, 9, 10, 10)));
        // edge
        assert!(! Rect::new(0, 0, 10, 10).has_intersection(&Rect::new(10, 10, 10, 10)));
        // out
        assert!(! Rect::new(0, 0, 10, 10).has_intersection(&Rect::new(11, 11, 10, 10)));
    }

    #[test]
    fn test_intersection() {
        assert_eq!(Rect::new(0, 0, 10, 10).intersection(&Rect::new(9, 9, 10, 10)),
                   Some(Rect::new(9, 9, 1, 1)));
        assert!(Rect::new(0, 0, 10, 10).intersection(&Rect::new(11, 11, 10, 10)).is_none());
    }

    #[test]
    fn test_union() {
        assert_eq!(Rect::new(0, 0, 1, 1).union(&Rect::new(9, 9, 1, 1)),
                   Rect::new(0, 0, 10, 10));
    }

    #[test]
    fn test_intersect_line() {
        assert_eq!(Rect::new(1, 1, 5, 5).intersect_line(&Point::new(0, 0), &Point::new(10, 10)),
                   Some((Point::new(1, 1), Point::new(5, 5))));
    }
 }
<commit_msg>remove commented out code<commit_after>/*!
Rectangle Functions
 */

use std::mem;
use libc::c_int;

/// A structure that defines a two dimensional point.
#[deriving(PartialEq, Clone, Show)]
#[repr(C)]
pub struct Point {
    pub x: i32,
    pub y: i32
}

/// A structure that defines a rectangle, with the origin at the upper left.
#[deriving(PartialEq, Clone, Show)]
#[repr(C)]
pub struct Rect {
    pub x: i32,
    pub y: i32,
    pub w: i32,
    pub h: i32
}

#[doc(hidden)]
#[allow(non_camel_case_types)]
pub mod ll {

    use libc::c_int;
    use super::Rect;
    use super::Point;

    pub type SDL_Rect = Rect;
    pub type SDL_Point = Point;
    pub type SDL_bool = c_int;

    extern "C" {
        pub fn SDL_HasIntersection(A: *const SDL_Rect, B: *const SDL_Rect) -> SDL_bool;
        pub fn SDL_IntersectRect(A: *const SDL_Rect, B: *const SDL_Rect, result: *const SDL_Rect) -> SDL_bool;
        pub fn SDL_UnionRect(A: *const SDL_Rect, B: *const SDL_Rect, result: *const SDL_Rect);
        pub fn SDL_EnclosePoints(points: *const SDL_Point, count: c_int, clip: *const SDL_Rect, result: *const SDL_Rect) -> SDL_bool;
        pub fn SDL_IntersectRectAndLine(rect: *const SDL_Rect, X1: *const c_int, Y1: *const c_int, X2: *const c_int, Y2: *const c_int) -> SDL_bool;
    }
}

impl Point {
    pub fn new(x: i32, y: i32) -> Point {
        Point {
            x: x,
            y: y
        }
    }
}

impl Rect {
    pub fn new(x: i32, y: i32, w: i32, h: i32) -> Rect {
        Rect {
            x: x,
            y: y,
            w: w,
            h: h
        }
    }

    /// Calculate a minimal rectangle enclosing a set of points.
    pub fn from_enclose_points(points: &[Point], clip: Option<Rect>) -> Option<Rect> {
        let out: Rect = Rect::new(0, 0, 0, 0);

        let result = unsafe {
            ll::SDL_EnclosePoints(
                mem::transmute(points.as_ptr()),
                points.len() as c_int,
                mem::transmute(clip.as_ref()),
                &out
            ) != 0
        };

        if result {
            Some(out)
        } else {
            None
        }
    }

    /// Check whether a rectangle has no area.
    pub fn is_empty(&self) -> bool {
        (self.w <= 0) || (self.h <= 0)
    }

    /// Determine whether two rectangles intersect.
    pub fn has_intersection(&self, other: &Rect) -> bool {
        unsafe {
            ll::SDL_HasIntersection(self, other) != 0
        }
    }

    /// Calculate the intersection of two rectangles.
    pub fn intersection(&self, other: &Rect) -> Option<Rect> {
        let out: Rect = Rect::new(0, 0, 0, 0);

        let result = unsafe {
            ll::SDL_IntersectRect(self, other, &out) != 0
        };

        if result {
            Some(out)
        } else {
            None
        }
    }

    /// Calculate the union of two rectangles.
    pub fn union(&self, other: &Rect) -> Rect {
        let out: Rect = Rect::new(0, 0, 0, 0);

        unsafe {
            ll::SDL_UnionRect(self, other, &out)
        };

        out
    }

    /// Calculate the intersection of a rectangle and line segment. return points of intersection.
    pub fn intersect_line(&self, start: &Point, end: &Point) -> Option<(Point, Point)> {
        let out_start: Point = start.clone();
        let out_end: Point = end.clone();

        let result = unsafe {
            ll::SDL_IntersectRectAndLine(self, &out_start.x, &out_start.y, &out_end.x, &out_end.y) != 0
        };

        if result {
            Some((out_start, out_end))
        } else {
            None
        }
    }
}

#[cfg(test)]
mod test {
    use super::{Rect, Point};

    #[test]
    fn test_from_enclose_points() {
        assert_eq!(Rect::from_enclose_points(&[Point::new(2, 4), Point::new(5,9)], None),
                   Some(Rect::new(2, 4, 4, 6)));
        assert!(Rect::from_enclose_points(&[Point::new(0, 0), Point::new(10,10)],
                                          Some(Rect::new(3, 3, 1, 1))).is_none());
    }

    #[test]
    fn test_has_intersection() {
        assert!(Rect::new(0, 0, 10, 10).has_intersection(&Rect::new(9, 9, 10, 10)));
        // edge
        assert!(! Rect::new(0, 0, 10, 10).has_intersection(&Rect::new(10, 10, 10, 10)));
        // out
        assert!(! Rect::new(0, 0, 10, 10).has_intersection(&Rect::new(11, 11, 10, 10)));
    }

    #[test]
    fn test_intersection() {
        assert_eq!(Rect::new(0, 0, 10, 10).intersection(&Rect::new(9, 9, 10, 10)),
                   Some(Rect::new(9, 9, 1, 1)));
        assert!(Rect::new(0, 0, 10, 10).intersection(&Rect::new(11, 11, 10, 10)).is_none());
    }

    #[test]
    fn test_union() {
        assert_eq!(Rect::new(0, 0, 1, 1).union(&Rect::new(9, 9, 1, 1)),
                   Rect::new(0, 0, 10, 10));
    }

    #[test]
    fn test_intersect_line() {
        assert_eq!(Rect::new(1, 1, 5, 5).intersect_line(&Point::new(0, 0), &Point::new(10, 10)),
                   Some((Point::new(1, 1), Point::new(5, 5))));
    }
 }
<|endoftext|>


<commit_before>#![crate_type = "lib"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![crate_name = "bitcoin-secp256k1-rs"]
#![comment = "Bindings and wrapper functions for bitcoin secp256k1 library."]
#![feature(phase)]

extern crate libc;
extern crate sync;

use std::rand;
use std::rand::Rng;

use libc::{c_int, c_uchar};
use sync::one::{Once, ONCE_INIT};

#[link(name = "secp256k1")]
extern "C" {
    pub fn secp256k1_start();
    pub fn secp256k1_stop();
    pub fn secp256k1_ecdsa_verify(
        msg : *const c_uchar, msglen : c_int,
        sig : *const c_uchar, siglen : c_int,
        pubkey : *const c_uchar, pubkeylen : c_int
        ) -> c_int;

    pub fn secp256k1_ecdsa_pubkey_create(
        pubkey : *mut c_uchar,
        pubkeylen : *mut c_int,
        seckey : *const c_uchar,
        compressed : c_int
        ) -> c_int;

    pub fn secp256k1_ecdsa_sign(
        msg : *const c_uchar, msglen : c_int,
        sig : *mut c_uchar, siglen : *mut c_int,
        seckey : *const c_uchar,
        nonce : *const c_uchar
        ) -> c_int;

    pub fn secp256k1_ecdsa_sign_compact(
        msg : *const c_uchar, msglen : c_int,
        sig64 : *mut c_uchar,
        seckey : *const c_uchar,
        nonce : *const c_uchar,
        recid : *mut c_int
        ) -> c_int;

    pub fn secp256k1_ecdsa_recover_compact(
        msg : *const c_uchar, msglen : c_int,
        sig64 : *const c_uchar,
        pubkey : *mut c_uchar,
        pubkeylen : *mut c_int,
        compressed : c_int,
        recid : c_int
        ) -> c_int;
}

pub type Nonce = [u8, ..32];
pub type SecKey = [u8, ..32];
pub type PubKeyCompressed = [u8, ..33];
pub type PubKeyUncompressed = [u8, ..65];
pub enum PubKey {
    Compressed(PubKeyCompressed),
    Uncompressed(PubKeyUncompressed)
}
pub type Signature = Vec<u8>;

#[deriving(Show)]
#[deriving(Eq)]
#[deriving(PartialEq)]
pub enum Error {
    InvalidPublicKey,
    InvalidSignature,
    InvalidSecretKey,
    InvalidNonce,
}

#[deriving(Eq)]
#[deriving(PartialEq)]
pub type VerifyResult = Result<bool, Error>;

static mut Secp256k1_init : Once = ONCE_INIT;

pub struct Secp256k1;

impl Secp256k1 {
    pub fn new() -> Secp256k1 {
        unsafe {
            Secp256k1_init.doit(|| {
                secp256k1_start();
            });
        }
        Secp256k1
    }

    pub fn pubkey_create(
        &self,
        pubkey : &mut PubKey,
        seckey : &SecKey
        ) -> Result<(), Error> {

        let (compressed, pub_ptr, pub_len) = match *pubkey {
            Uncompressed(ref mut key) => (false, key.as_mut_ptr(), key.len()),
            Compressed(ref mut key) => (true, key.as_mut_ptr(), key.len()),
        };
        let mut len = pub_len as c_int;
        let res = unsafe {
            secp256k1_ecdsa_pubkey_create(
                pub_ptr, &mut len,
                seckey.as_ptr(),
                if compressed {1} else {0}
                )
        };

        assert_eq!(pub_len as i32, len);

        match res {
            0 => Err(InvalidSecretKey),
            1 => Ok(()),
            _ => fail!("secp256k1_ecdsa_pubkey_create invalid return value"),
        }
    }

    pub fn sign(&self, sig : &mut Signature, msg : &[u8], seckey : &SecKey, nonce : &Nonce) -> Result<(), Error> {

        let origlen = 72u;
        let mut siglen = origlen as c_int;

        if sig.len() != origlen {
            fail!("invalid length of signature buffer");
        }

        let res = unsafe {
            secp256k1_ecdsa_sign(
                msg.as_ptr(), msg.len() as c_int,
                sig.as_mut_ptr(), &mut siglen,
                seckey.as_ptr(),
                nonce.as_ptr()
                )
        };

        if (origlen as c_int) < siglen {
            fail!("secp256k1_ecdsa_sign wrong return len");
        }

        match res {
            0 => Err(InvalidNonce),
            1 => { sig.truncate(siglen as uint); Ok(()) },
            _ => fail!("secp256k1_ecdsa_sign invalid return value"),
        }
    }

    pub fn sign_compact(
        &self,
        sig : &mut [u8],
        msg : &[u8],
        seckey : &SecKey,
        nonce : &Nonce
        ) -> Result<i32, Error> {

        let origlen = 64u;

        if sig.len() != origlen {
            fail!("invalid length of signature buffer");
        }

        let mut recid = 0;

        let res = unsafe {
            secp256k1_ecdsa_sign_compact(
                msg.as_ptr(), msg.len() as c_int,
                sig.as_mut_ptr(),
                seckey.as_ptr(),
                nonce.as_ptr(),
                &mut recid
                )
        };

        match res {
            0 => Err(InvalidNonce),
            1 => { Ok(recid) },
            _ => fail!("secp256k1_ecdsa_sign_compact invalid return value"),
        }
    }

    pub fn recover_compact(
        &self,
        msg : &[u8],
        sig : &[u8],
        pubkey : &mut PubKey,
        recid : i32
        ) -> Result<(), Error> {

        let (compressed, pub_ptr, pub_len) = match *pubkey {
            Uncompressed(ref mut key) => (false, key.as_mut_ptr(), key.len()),
            Compressed(ref mut key) => (true, key.as_mut_ptr(), key.len()),
        };

        let origlen = 64u;

        if sig.len() != origlen {
            fail!("invalid length of signature buffer");
        }

        let mut len = pub_len as c_int;
        let res = unsafe {
            secp256k1_ecdsa_recover_compact(
                msg.as_ptr(), msg.len() as i32,
                sig.as_ptr(),
                pub_ptr, &mut len,
                if compressed {1} else {0},
                recid
                )
        };

        assert_eq!(pub_len as i32, len);

        match res {
            0 => Err(InvalidSignature),
            1 => Ok(()),
            _ => fail!("secp256k1_ecdsa_recover_compact invalid return value"),
        }
    }

    pub fn verify(&self, msg : &[u8], sig : &[u8], pubkey : &PubKey) -> VerifyResult {

        let (pub_ptr, pub_len) = match *pubkey {
            Uncompressed(ref key) => (key.as_ptr(), key.len()),
            Compressed(ref key) => (key.as_ptr(), key.len()),
        };

        let res = unsafe {
            secp256k1_ecdsa_verify(
                msg.as_ptr(), msg.len() as c_int,
                sig.as_ptr(), sig.len() as c_int,
                pub_ptr, pub_len as c_int
                )
        };

        match res {
            1 => Ok(true),
            0 => Ok(false),
            -1 => Err(InvalidPublicKey),
            -2 => Err(InvalidSignature),
            _ => fail!("secp256k1_ecdsa_verify() invalid return value")
        }
    }
}

#[test]
fn invalid_pubkey() {
    let s = Secp256k1::new();

    let mut msg = Vec::from_elem(32, 0u8);
    let sig = Vec::from_elem(32, 0u8);
    let pubkey = Compressed([0u8, .. 33]);

    rand::task_rng().fill_bytes(msg.as_mut_slice());

    assert_eq!(s.verify(msg.as_mut_slice(), sig.as_slice(), &pubkey), Err(InvalidPublicKey));
}

#[test]
fn valid_pubkey_uncompressed() {
    let s = Secp256k1::new();

    let seckey = [0u8, ..32];
    let mut pubkey = Uncompressed([0u8, ..65]);
    s.pubkey_create(&mut pubkey, &seckey).unwrap();
    let mut msg = Vec::from_elem(32, 0u8);
    let sig = Vec::from_elem(32, 0u8);

    rand::task_rng().fill_bytes(msg.as_mut_slice());

    assert_eq!(s.verify(msg.as_mut_slice(), sig.as_slice(), &pubkey), Err(InvalidSignature));
}

#[test]
fn valid_pubkey_compressed() {
    let s = Secp256k1::new();

    let seckey = [0u8, ..32];
    let mut pubkey = Compressed([0u8, .. 33]);
    s.pubkey_create(&mut pubkey, &seckey).unwrap();
    let mut msg = Vec::from_elem(32, 0u8);
    let sig = Vec::from_elem(32, 0u8);

    rand::task_rng().fill_bytes(msg.as_mut_slice());

    assert_eq!(s.verify(msg.as_mut_slice(), sig.as_slice(), &pubkey), Err(InvalidSignature));
}

#[test]
fn sign() {
    let s = Secp256k1::new();

    let mut msg = [0u8, ..32];
    let mut seckey = [0u8, ..32];
    let mut nonce = [0u8, ..32];
    let mut sig = Vec::from_elem(72, 0u8);
    rand::task_rng().fill_bytes(msg);
    rand::task_rng().fill_bytes(nonce);
    rand::task_rng().fill_bytes(seckey);

    s.sign(&mut sig, msg.as_slice(), &seckey, &nonce).unwrap();
}

#[test]
fn sign_and_verify() {
    let s = Secp256k1::new();

    let mut msg = Vec::from_elem(32, 0u8);
    let mut seckey = [0u8, ..32];
    let mut pubkey = Compressed([0u8, .. 33]);
    let mut nonce = [0u8, ..32];
    let mut sig = Vec::from_elem(72, 0u8);
    rand::task_rng().fill_bytes(msg.as_mut_slice());
    rand::task_rng().fill_bytes(nonce);
    rand::task_rng().fill_bytes(seckey);

    s.pubkey_create(&mut pubkey, &seckey).unwrap();

    s.sign(&mut sig, msg.as_slice(), &seckey, &nonce).unwrap();

    assert_eq!(s.verify(msg.as_slice(), sig.as_slice(), &pubkey), Ok(true));
}

#[test]
fn sign_and_verify_fail() {
    let s = Secp256k1::new();

    let mut msg = Vec::from_elem(32, 0u8);
    let mut seckey = [0u8, ..32];
    let mut pubkey = Compressed([0u8, .. 33]);
    let mut nonce = [0u8, ..32];
    let mut sig = Vec::from_elem(72, 0u8);
    rand::task_rng().fill_bytes(msg.as_mut_slice());
    rand::task_rng().fill_bytes(nonce);
    rand::task_rng().fill_bytes(seckey);

    s.pubkey_create(&mut pubkey, &seckey).unwrap();
    s.sign(&mut sig, msg.as_slice(), &seckey, &nonce).unwrap();

    rand::task_rng().fill_bytes(msg.as_mut_slice());
    assert_eq!(s.verify(msg.as_slice(), sig.as_slice(), &pubkey), Ok(false));
}

#[test]
fn sign_compact_with_recovery() {
    let s = Secp256k1::new();

    let mut msg = [0u8, ..32];
    let mut seckey = [0u8, ..32];
    let mut pubkey = Uncompressed([0u8, ..65]);
    let mut nonce = [0u8, ..32];
    let mut sig = Vec::from_elem(64, 0u8);
    rand::task_rng().fill_bytes(msg.as_mut_slice());
    rand::task_rng().fill_bytes(nonce);
    rand::task_rng().fill_bytes(seckey);

    s.pubkey_create(&mut pubkey, &seckey).unwrap();

    let recid = s.sign_compact(sig.as_mut_slice(), msg.as_slice(), &seckey, &nonce).unwrap();

    assert_eq!(s.recover_compact(msg.as_slice(), sig.as_slice(), &mut pubkey, recid), Ok(()));
}

<commit_msg>fix unused import warning<commit_after>#![crate_type = "lib"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![crate_name = "bitcoin-secp256k1-rs"]
#![comment = "Bindings and wrapper functions for bitcoin secp256k1 library."]
#![feature(phase)]
#![feature(globs)]  // for tests only

extern crate libc;
extern crate sync;

use libc::{c_int, c_uchar};
use sync::one::{Once, ONCE_INIT};

#[link(name = "secp256k1")]
extern "C" {
    pub fn secp256k1_start();
    pub fn secp256k1_stop();
    pub fn secp256k1_ecdsa_verify(
        msg : *const c_uchar, msglen : c_int,
        sig : *const c_uchar, siglen : c_int,
        pubkey : *const c_uchar, pubkeylen : c_int
        ) -> c_int;

    pub fn secp256k1_ecdsa_pubkey_create(
        pubkey : *mut c_uchar,
        pubkeylen : *mut c_int,
        seckey : *const c_uchar,
        compressed : c_int
        ) -> c_int;

    pub fn secp256k1_ecdsa_sign(
        msg : *const c_uchar, msglen : c_int,
        sig : *mut c_uchar, siglen : *mut c_int,
        seckey : *const c_uchar,
        nonce : *const c_uchar
        ) -> c_int;

    pub fn secp256k1_ecdsa_sign_compact(
        msg : *const c_uchar, msglen : c_int,
        sig64 : *mut c_uchar,
        seckey : *const c_uchar,
        nonce : *const c_uchar,
        recid : *mut c_int
        ) -> c_int;

    pub fn secp256k1_ecdsa_recover_compact(
        msg : *const c_uchar, msglen : c_int,
        sig64 : *const c_uchar,
        pubkey : *mut c_uchar,
        pubkeylen : *mut c_int,
        compressed : c_int,
        recid : c_int
        ) -> c_int;
}

pub type Nonce = [u8, ..32];
pub type SecKey = [u8, ..32];
pub type PubKeyCompressed = [u8, ..33];
pub type PubKeyUncompressed = [u8, ..65];
pub enum PubKey {
    Compressed(PubKeyCompressed),
    Uncompressed(PubKeyUncompressed)
}
pub type Signature = Vec<u8>;

#[deriving(Show)]
#[deriving(Eq)]
#[deriving(PartialEq)]
pub enum Error {
    InvalidPublicKey,
    InvalidSignature,
    InvalidSecretKey,
    InvalidNonce,
}

#[deriving(Eq)]
#[deriving(PartialEq)]
pub type VerifyResult = Result<bool, Error>;

static mut Secp256k1_init : Once = ONCE_INIT;

pub struct Secp256k1;

impl Secp256k1 {
    pub fn new() -> Secp256k1 {
        unsafe {
            Secp256k1_init.doit(|| {
                secp256k1_start();
            });
        }
        Secp256k1
    }

    pub fn pubkey_create(
        &self,
        pubkey : &mut PubKey,
        seckey : &SecKey
        ) -> Result<(), Error> {

        let (compressed, pub_ptr, pub_len) = match *pubkey {
            Uncompressed(ref mut key) => (false, key.as_mut_ptr(), key.len()),
            Compressed(ref mut key) => (true, key.as_mut_ptr(), key.len()),
        };
        let mut len = pub_len as c_int;
        let res = unsafe {
            secp256k1_ecdsa_pubkey_create(
                pub_ptr, &mut len,
                seckey.as_ptr(),
                if compressed {1} else {0}
                )
        };

        assert_eq!(pub_len as i32, len);

        match res {
            0 => Err(InvalidSecretKey),
            1 => Ok(()),
            _ => fail!("secp256k1_ecdsa_pubkey_create invalid return value"),
        }
    }

    pub fn sign(&self, sig : &mut Signature, msg : &[u8], seckey : &SecKey, nonce : &Nonce) -> Result<(), Error> {

        let origlen = 72u;
        let mut siglen = origlen as c_int;

        if sig.len() != origlen {
            fail!("invalid length of signature buffer");
        }

        let res = unsafe {
            secp256k1_ecdsa_sign(
                msg.as_ptr(), msg.len() as c_int,
                sig.as_mut_ptr(), &mut siglen,
                seckey.as_ptr(),
                nonce.as_ptr()
                )
        };

        if (origlen as c_int) < siglen {
            fail!("secp256k1_ecdsa_sign wrong return len");
        }

        match res {
            0 => Err(InvalidNonce),
            1 => { sig.truncate(siglen as uint); Ok(()) },
            _ => fail!("secp256k1_ecdsa_sign invalid return value"),
        }
    }

    pub fn sign_compact(
        &self,
        sig : &mut [u8],
        msg : &[u8],
        seckey : &SecKey,
        nonce : &Nonce
        ) -> Result<i32, Error> {

        let origlen = 64u;

        if sig.len() != origlen {
            fail!("invalid length of signature buffer");
        }

        let mut recid = 0;

        let res = unsafe {
            secp256k1_ecdsa_sign_compact(
                msg.as_ptr(), msg.len() as c_int,
                sig.as_mut_ptr(),
                seckey.as_ptr(),
                nonce.as_ptr(),
                &mut recid
                )
        };

        match res {
            0 => Err(InvalidNonce),
            1 => { Ok(recid) },
            _ => fail!("secp256k1_ecdsa_sign_compact invalid return value"),
        }
    }

    pub fn recover_compact(
        &self,
        msg : &[u8],
        sig : &[u8],
        pubkey : &mut PubKey,
        recid : i32
        ) -> Result<(), Error> {

        let (compressed, pub_ptr, pub_len) = match *pubkey {
            Uncompressed(ref mut key) => (false, key.as_mut_ptr(), key.len()),
            Compressed(ref mut key) => (true, key.as_mut_ptr(), key.len()),
        };

        let origlen = 64u;

        if sig.len() != origlen {
            fail!("invalid length of signature buffer");
        }

        let mut len = pub_len as c_int;
        let res = unsafe {
            secp256k1_ecdsa_recover_compact(
                msg.as_ptr(), msg.len() as i32,
                sig.as_ptr(),
                pub_ptr, &mut len,
                if compressed {1} else {0},
                recid
                )
        };

        assert_eq!(pub_len as i32, len);

        match res {
            0 => Err(InvalidSignature),
            1 => Ok(()),
            _ => fail!("secp256k1_ecdsa_recover_compact invalid return value"),
        }
    }

    pub fn verify(&self, msg : &[u8], sig : &[u8], pubkey : &PubKey) -> VerifyResult {

        let (pub_ptr, pub_len) = match *pubkey {
            Uncompressed(ref key) => (key.as_ptr(), key.len()),
            Compressed(ref key) => (key.as_ptr(), key.len()),
        };

        let res = unsafe {
            secp256k1_ecdsa_verify(
                msg.as_ptr(), msg.len() as c_int,
                sig.as_ptr(), sig.len() as c_int,
                pub_ptr, pub_len as c_int
                )
        };

        match res {
            1 => Ok(true),
            0 => Ok(false),
            -1 => Err(InvalidPublicKey),
            -2 => Err(InvalidSignature),
            _ => fail!("secp256k1_ecdsa_verify() invalid return value")
        }
    }
}

#[cfg(test)]
mod test {

    use std::rand;
    use std::rand::Rng;
    use super::*;

    #[test]
    fn invalid_pubkey() {
        let s = Secp256k1::new();

        let mut msg = Vec::from_elem(32, 0u8);
        let sig = Vec::from_elem(32, 0u8);
        let pubkey = Compressed([0u8, .. 33]);

        rand::task_rng().fill_bytes(msg.as_mut_slice());

        assert_eq!(s.verify(msg.as_mut_slice(), sig.as_slice(), &pubkey), Err(InvalidPublicKey));
    }

    #[test]
    fn valid_pubkey_uncompressed() {
        let s = Secp256k1::new();

        let seckey = [0u8, ..32];
        let mut pubkey = Uncompressed([0u8, ..65]);
        s.pubkey_create(&mut pubkey, &seckey).unwrap();
        let mut msg = Vec::from_elem(32, 0u8);
        let sig = Vec::from_elem(32, 0u8);

        rand::task_rng().fill_bytes(msg.as_mut_slice());

        assert_eq!(s.verify(msg.as_mut_slice(), sig.as_slice(), &pubkey), Err(InvalidSignature));
    }

    #[test]
    fn valid_pubkey_compressed() {
        let s = Secp256k1::new();

        let seckey = [0u8, ..32];
        let mut pubkey = Compressed([0u8, .. 33]);
        s.pubkey_create(&mut pubkey, &seckey).unwrap();
        let mut msg = Vec::from_elem(32, 0u8);
        let sig = Vec::from_elem(32, 0u8);

        rand::task_rng().fill_bytes(msg.as_mut_slice());

        assert_eq!(s.verify(msg.as_mut_slice(), sig.as_slice(), &pubkey), Err(InvalidSignature));
    }

    #[test]
    fn sign() {
        let s = Secp256k1::new();

        let mut msg = [0u8, ..32];
        let mut seckey = [0u8, ..32];
        let mut nonce = [0u8, ..32];
        let mut sig = Vec::from_elem(72, 0u8);
        rand::task_rng().fill_bytes(msg);
        rand::task_rng().fill_bytes(nonce);
        rand::task_rng().fill_bytes(seckey);

        s.sign(&mut sig, msg.as_slice(), &seckey, &nonce).unwrap();
    }

    #[test]
    fn sign_and_verify() {
        let s = Secp256k1::new();

        let mut msg = Vec::from_elem(32, 0u8);
        let mut seckey = [0u8, ..32];
        let mut pubkey = Compressed([0u8, .. 33]);
        let mut nonce = [0u8, ..32];
        let mut sig = Vec::from_elem(72, 0u8);
        rand::task_rng().fill_bytes(msg.as_mut_slice());
        rand::task_rng().fill_bytes(nonce);
        rand::task_rng().fill_bytes(seckey);

        s.pubkey_create(&mut pubkey, &seckey).unwrap();

        s.sign(&mut sig, msg.as_slice(), &seckey, &nonce).unwrap();

        assert_eq!(s.verify(msg.as_slice(), sig.as_slice(), &pubkey), Ok(true));
    }

    #[test]
    fn sign_and_verify_fail() {
        let s = Secp256k1::new();

        let mut msg = Vec::from_elem(32, 0u8);
        let mut seckey = [0u8, ..32];
        let mut pubkey = Compressed([0u8, .. 33]);
        let mut nonce = [0u8, ..32];
        let mut sig = Vec::from_elem(72, 0u8);
        rand::task_rng().fill_bytes(msg.as_mut_slice());
        rand::task_rng().fill_bytes(nonce);
        rand::task_rng().fill_bytes(seckey);

        s.pubkey_create(&mut pubkey, &seckey).unwrap();
        s.sign(&mut sig, msg.as_slice(), &seckey, &nonce).unwrap();

        rand::task_rng().fill_bytes(msg.as_mut_slice());
        assert_eq!(s.verify(msg.as_slice(), sig.as_slice(), &pubkey), Ok(false));
    }

    #[test]
    fn sign_compact_with_recovery() {
        let s = Secp256k1::new();

        let mut msg = [0u8, ..32];
        let mut seckey = [0u8, ..32];
        let mut pubkey = Uncompressed([0u8, ..65]);
        let mut nonce = [0u8, ..32];
        let mut sig = Vec::from_elem(64, 0u8);
        rand::task_rng().fill_bytes(msg.as_mut_slice());
        rand::task_rng().fill_bytes(nonce);
        rand::task_rng().fill_bytes(seckey);

        s.pubkey_create(&mut pubkey, &seckey).unwrap();

        let recid = s.sign_compact(sig.as_mut_slice(), msg.as_slice(), &seckey, &nonce).unwrap();

        assert_eq!(s.recover_compact(msg.as_slice(), sig.as_slice(), &mut pubkey, recid), Ok(()));
    }
}
<|endoftext|>