<commit_before>use std;
use std::io::{Write, Read};
use egg_mode;

//This is not an example that can be built with cargo! This is some helper code for the other
//examples so they can load access keys from the same place.

pub struct Config {
    pub con_token: egg_mode::Token<'static>,
    pub access_token: egg_mode::Token<'static>,
    pub user_id: i64,
    pub screen_name: String,
}

impl Config {
    pub fn load() -> Self {
        //IMPORTANT: make an app for yourself at apps.twitter.com and get your
        //key/secret into these files; these examples won't work without them
        let consumer_key = include_str!("consumer_key").trim();
        let consumer_secret = include_str!("consumer_secret").trim();

        let token = egg_mode::Token::new(consumer_key, consumer_secret);

        let mut config = String::new();
        let user_id: i64;
        let username: String;
        let access_token: egg_mode::Token;

        //look at all this unwrapping! who told you it was my birthday?
        if let Ok(mut f) = std::fs::File::open("twitter_settings") {
            f.read_to_string(&mut config).unwrap();

            let mut iter = config.split('\n');

            username = iter.next().unwrap().to_string();
            user_id = i64::from_str_radix(&iter.next().unwrap(), 10).unwrap();
            access_token = egg_mode::Token::new(iter.next().unwrap().to_string(),
                                                     iter.next().unwrap().to_string());

            println!("Welcome back, {}!", username);
        }
        else {
            let request_token = egg_mode::request_token(&token, "oob").unwrap();

            println!("Go to the following URL, sign in, and give me the PIN that comes back:");
            println!("{}", egg_mode::authorize_url(&request_token));

            let mut pin = String::new();
            std::io::stdin().read_line(&mut pin).unwrap();
            println!("");

            let tok_result = egg_mode::access_token(&token, &request_token, pin).unwrap();

            access_token = tok_result.0;
            user_id = tok_result.1;
            username = tok_result.2;

            config.push_str(&username);
            config.push('\n');
            config.push_str(&format!("{}", user_id));
            config.push('\n');
            config.push_str(&access_token.key);
            config.push('\n');
            config.push_str(&access_token.secret);

            let mut f = std::fs::File::create("twitter_settings").unwrap();
            f.write_all(config.as_bytes()).unwrap();

            println!("Welcome, {}, let's get this show on the road!", username);
        }

        Config {
            con_token: token,
            access_token: access_token,
            user_id: user_id,
            screen_name: username,
        }
    }
}
<commit_msg>add verify_tokens to examples/common to show handling expired tokens<commit_after>use std;
use std::io::{Write, Read};
use egg_mode;

//This is not an example that can be built with cargo! This is some helper code for the other
//examples so they can load access keys from the same place.

pub struct Config {
    pub con_token: egg_mode::Token<'static>,
    pub access_token: egg_mode::Token<'static>,
    pub user_id: i64,
    pub screen_name: String,
}

impl Config {
    pub fn load() -> Self {
        //IMPORTANT: make an app for yourself at apps.twitter.com and get your
        //key/secret into these files; these examples won't work without them
        let consumer_key = include_str!("consumer_key").trim();
        let consumer_secret = include_str!("consumer_secret").trim();

        let token = egg_mode::Token::new(consumer_key, consumer_secret);

        let mut config = String::new();
        let user_id: i64;
        let username: String;
        let access_token: egg_mode::Token;

        //look at all this unwrapping! who told you it was my birthday?
        if let Ok(mut f) = std::fs::File::open("twitter_settings") {
            f.read_to_string(&mut config).unwrap();

            let mut iter = config.split('\n');

            username = iter.next().unwrap().to_string();
            user_id = i64::from_str_radix(&iter.next().unwrap(), 10).unwrap();
            access_token = egg_mode::Token::new(iter.next().unwrap().to_string(),
                                                     iter.next().unwrap().to_string());

            if let Err(err) = egg_mode::verify_tokens(&token, &access_token) {
                println!("We've hit an error using your old tokens: {:?}", err);
                println!("We'll have to reauthenticate before continuing.");
                std::fs::remove_file("twitter_settings").unwrap();
            }
            else {
                println!("Welcome back, {}!", username);
            }
        }
        else {
            let request_token = egg_mode::request_token(&token, "oob").unwrap();

            println!("Go to the following URL, sign in, and give me the PIN that comes back:");
            println!("{}", egg_mode::authorize_url(&request_token));

            let mut pin = String::new();
            std::io::stdin().read_line(&mut pin).unwrap();
            println!("");

            let tok_result = egg_mode::access_token(&token, &request_token, pin).unwrap();

            access_token = tok_result.0;
            user_id = tok_result.1;
            username = tok_result.2;

            config.push_str(&username);
            config.push('\n');
            config.push_str(&format!("{}", user_id));
            config.push('\n');
            config.push_str(&access_token.key);
            config.push('\n');
            config.push_str(&access_token.secret);

            let mut f = std::fs::File::create("twitter_settings").unwrap();
            f.write_all(config.as_bytes()).unwrap();

            println!("Welcome, {}, let's get this show on the road!", username);
        }

        //TODO: Is there a better way to query whether a file exists?
        if std::fs::metadata("twitter_settings").is_ok() {
            Config {
                con_token: token,
                access_token: access_token,
                user_id: user_id,
                screen_name: username,
            }
        }
        else {
            Self::load()
        }
    }
}
<|endoftext|>


<commit_before>use finder::Checker;
#[cfg(unix)]
use libc;
#[cfg(unix)]
use std::ffi::CString;
use std::fs;
#[cfg(unix)]
use std::os::unix::ffi::OsStrExt;
use std::path::Path;

pub struct ExecutableChecker;

impl ExecutableChecker {
    pub fn new() -> ExecutableChecker {
        ExecutableChecker
    }
}

impl Checker for ExecutableChecker {
    #[cfg(unix)]
    fn is_valid(&self, path: &Path) -> bool {
        CString::new(path.as_os_str().as_bytes())
            .and_then(|c| Ok(unsafe { libc::access(c.as_ptr(), libc::X_OK) == 0 }))
            .unwrap_or(false)
    }

    #[cfg(windows)]
    fn is_valid(&self, _path: &Path) -> bool {
        true
    }
}

pub struct ExistedChecker;

impl ExistedChecker {
    pub fn new() -> ExistedChecker {
        ExistedChecker
    }
}

impl Checker for ExistedChecker {
    fn is_valid(&self, path: &Path) -> bool {
        fs::metadata(path)
            .map(|metadata| metadata.is_file())
            .unwrap_or(false)
    }
}

pub struct CompositeChecker {
    checkers: Vec<Box<dyn Checker>>,
}

impl CompositeChecker {
    pub fn new() -> CompositeChecker {
        CompositeChecker {
            checkers: Vec::new(),
        }
    }

    pub fn add_checker(mut self, checker: Box<dyn Checker>) -> CompositeChecker {
        self.checkers.push(checker);
        self
    }
}

impl Checker for CompositeChecker {
    fn is_valid(&self, path: &Path) -> bool {
        self.checkers.iter().all(|checker| checker.is_valid(path))
    }
}
<commit_msg>Allow checker to support reparsepoints in Windows<commit_after>use finder::Checker;
#[cfg(unix)]
use libc;
#[cfg(unix)]
use std::ffi::CString;
use std::fs;
#[cfg(unix)]
use std::os::unix::ffi::OsStrExt;
use std::path::Path;

pub struct ExecutableChecker;

impl ExecutableChecker {
    pub fn new() -> ExecutableChecker {
        ExecutableChecker
    }
}

impl Checker for ExecutableChecker {
    #[cfg(unix)]
    fn is_valid(&self, path: &Path) -> bool {
        CString::new(path.as_os_str().as_bytes())
            .and_then(|c| Ok(unsafe { libc::access(c.as_ptr(), libc::X_OK) == 0 }))
            .unwrap_or(false)
    }

    #[cfg(windows)]
    fn is_valid(&self, _path: &Path) -> bool {
        true
    }
}

pub struct ExistedChecker;

impl ExistedChecker {
    pub fn new() -> ExistedChecker {
        ExistedChecker
    }
}

impl Checker for ExistedChecker {
    fn is_valid(&self, path: &Path) -> bool {
        fs::symlink_metadata(path)
            .map(|metadata| metadata.is_file())
            .unwrap_or(false)
    }
}

pub struct CompositeChecker {
    checkers: Vec<Box<dyn Checker>>,
}

impl CompositeChecker {
    pub fn new() -> CompositeChecker {
        CompositeChecker {
            checkers: Vec::new(),
        }
    }

    pub fn add_checker(mut self, checker: Box<dyn Checker>) -> CompositeChecker {
        self.checkers.push(checker);
        self
    }
}

impl Checker for CompositeChecker {
    fn is_valid(&self, path: &Path) -> bool {
        self.checkers.iter().all(|checker| checker.is_valid(path))
    }
}
<|endoftext|>


<commit_before>#[derive(Debug)]
pub enum Command {
    Output,
    Input,
    Increment,
    Decrement,
    RightShift,
    LeftShift
}
<commit_msg>Make Command derive Clone trait<commit_after>#[derive(Debug,Clone)]
pub enum Command {
    Output,
    Input,
    Increment,
    Decrement,
    RightShift,
    LeftShift
}
<|endoftext|>


<commit_before>#![doc="Statistical moments
"]

// local imports
use entry::Zero;
use number::Number;
use matrix::matrix::Matrix;
use matrix::traits::{Shape, MatrixBuffer, Strided,
 StridedNumberMatrix};

/// Computes sum over columns and returns a row vector
pub fn sum_cw<T:Number>(m : & StridedNumberMatrix<T>) -> Matrix<T> {
    let cols = m.num_cols();
    let rows = m.num_rows();
    let mut result = Matrix::new(1, cols);
    let ptr = m.as_ptr();
    let stride = m.stride() as int;
    let mut offset = m.start_offset();
    for c in range(0, cols) {
        let mut sum : T = Zero::zero();
        for r in range(0, rows){
            sum = sum + unsafe{*ptr.offset(offset + r as int)};
        }
        offset += stride;
        result.set(0, c, sum);
    }
    result
}

/// Computes sum over rows and returns a column vector
pub fn sum_rw<T:Number>(m : & StridedNumberMatrix<T>) -> Matrix<T> {
    let cols = m.num_cols();
    let rows = m.num_rows();
    let mut result = Matrix::new(rows, 1);
    let ptr = m.as_ptr();
    let stride = m.stride() as int;
    let mut offset = m.start_offset();
    for r in range(0, rows) {
        let mut sum : T = Zero::zero();
        let mut src_offset  = offset;
        for _ in range(0, cols){
            sum = sum + unsafe{*ptr.offset(src_offset)};
            src_offset += stride;
        }
        offset += 1;
        result.set(r, 0, sum);
    }
    result
}

/// Computes sum over columns and returns a row vector
pub fn sum_sqr_cw<T:Number>(m : & StridedNumberMatrix<T>) -> Matrix<T> {
    let cols = m.num_cols();
    let rows = m.num_rows();
    let mut result = Matrix::new(1, cols);
    let ptr = m.as_ptr();
    let stride = m.stride() as int;
    let mut offset = m.start_offset();
    for c in range(0, cols) {
        let mut sum : T = Zero::zero();
        for r in range(0, rows){
            let v  = unsafe{*ptr.offset(offset + r as int)};
            sum = sum + v * v;
        }
        offset += stride;
        result.set(0, c, sum);
    }
    result
}

/// Computes sum over rows and returns a column vector
pub fn sum_sqr_rw<T:Number>(m : & StridedNumberMatrix<T>) -> Matrix<T> {
    let cols = m.num_cols();
    let rows = m.num_rows();
    let mut result = Matrix::new(rows, 1);
    let ptr = m.as_ptr();
    let stride = m.stride() as int;
    let mut offset = m.start_offset();
    for r in range(0, rows) {
        let mut sum : T = Zero::zero();
        let mut src_offset  = offset;
        for _ in range(0, cols){
            let v = unsafe{*ptr.offset(src_offset)};
            sum = sum + v * v;
            src_offset += stride;
        }
        offset += 1;
        result.set(r, 0, sum);
    }
    result
}

/******************************************************
 *
 *   Unit tests
 *
 *******************************************************/
#[cfg(test)]
mod test{

    use super::*;
    use api::*;

    #[test]
    fn test_moment_sum_cw_1(){
        let m = matrix_rw_i32(3, 3, &[
            1, 2, 3,
            4, 5, 6,
            7, 8, 9]);
        let s = sum_cw(&m);
        assert_eq!(s, matrix_cw_i32(1,3, &[12, 15, 18]));
    }

    #[test]
    fn test_moment_sum_cw_2(){
        let m = matrix_rw_i32(3, 3, &[
            1, 2, 3,
            4, 5, 6,
            7, 8, 9]);
        let v = m.view(1, 1, 2, 2);
        let s = sum_cw(&v);
        assert_eq!(s, matrix_cw_i32(1,2, &[13, 15]));
    }

    #[test]
    fn test_moment_sum_rw_1(){
        let m = matrix_rw_i32(3, 3, &[
            1, 2, 3,
            4, 5, 6,
            7, 8, 9]);
        let s = sum_rw(&m);
        assert_eq!(s, matrix_rw_i32(3,1, &[6, 15, 24]));
    }

    #[test]
    fn test_moment_sum_rw_2(){
        let m = matrix_rw_i32(3, 3, &[
            1, 2, 3,
            4, 5, 6,
            7, 8, 9]);
        let v = m.view(1, 1, 2, 2);
        let s = sum_rw(&v);
        assert_eq!(s, matrix_rw_i32(2,1, &[11, 17]));
    }

    #[test]
    fn test_moment_sum_sqr_cw_1(){
        let m = matrix_rw_i32(3, 3, &[
            1, 1, 2,
            2, 2, 1,
            3, 2, 2]);
        let s = sum_sqr_cw(&m);
        assert_eq!(s, matrix_cw_i32(1,3, &[14, 9, 9]));
    }

    #[test]
    fn test_moment_sum_sqr_cw_2(){
        let m = matrix_rw_i32(3, 3, &[
            1, 1, 2,
            2, 2, 1,
            3, 2, 2]);
        let v = m.view(1, 1, 2, 2);
        let s = sum_sqr_cw(&v);
        assert_eq!(s, matrix_cw_i32(1,2, &[8, 5]));
    }

    #[test]
    fn test_moment_sum_sqr_rw_1(){
        let m = matrix_rw_i32(3, 3, &[
            1, 1, 2,
            2, 2, 1,
            3, 2, 2]);
        let s = sum_sqr_rw(&m);
        assert_eq!(s, matrix_cw_i32(3,1, &[6, 9, 17]));
    }

    #[test]
    fn test_moment_sum_sqr_rw_2(){
        let m = matrix_rw_i32(3, 3, &[
            1, 1, 2,
            2, 2, 1,
            3, 2, 2]);
        let v = m.view(1, 1, 2, 2);
        let s = sum_sqr_rw(&v);
        assert_eq!(s, matrix_cw_i32(2,1, &[5, 8]));
    }
}<commit_msg>Implemented mean for float matrices.<commit_after>#![doc="Statistical moments
"]

// std imports
use std::num::Float;

// local imports
use entry::Zero;
use number::Number;
use matrix::matrix::Matrix;
use matrix::traits::{Shape, MatrixBuffer, Strided,
 StridedNumberMatrix,
 StridedFloatMatrix};

/// Computes sum over columns and returns a row vector
pub fn sum_cw<T:Number>(m : & StridedNumberMatrix<T>) -> Matrix<T> {
    let cols = m.num_cols();
    let rows = m.num_rows();
    let mut result = Matrix::new(1, cols);
    let ptr = m.as_ptr();
    let stride = m.stride() as int;
    let mut offset = m.start_offset();
    for c in range(0, cols) {
        let mut sum : T = Zero::zero();
        for r in range(0, rows){
            sum = sum + unsafe{*ptr.offset(offset + r as int)};
        }
        offset += stride;
        result.set(0, c, sum);
    }
    result
}

/// Computes sum over rows and returns a column vector
pub fn sum_rw<T:Number>(m : & StridedNumberMatrix<T>) -> Matrix<T> {
    let cols = m.num_cols();
    let rows = m.num_rows();
    let mut result = Matrix::new(rows, 1);
    let ptr = m.as_ptr();
    let stride = m.stride() as int;
    let mut offset = m.start_offset();
    for r in range(0, rows) {
        let mut sum : T = Zero::zero();
        let mut src_offset  = offset;
        for _ in range(0, cols){
            sum = sum + unsafe{*ptr.offset(src_offset)};
            src_offset += stride;
        }
        offset += 1;
        result.set(r, 0, sum);
    }
    result
}

/// Computes sum over columns and returns a row vector
pub fn sum_sqr_cw<T:Number>(m : & StridedNumberMatrix<T>) -> Matrix<T> {
    let cols = m.num_cols();
    let rows = m.num_rows();
    let mut result = Matrix::new(1, cols);
    let ptr = m.as_ptr();
    let stride = m.stride() as int;
    let mut offset = m.start_offset();
    for c in range(0, cols) {
        let mut sum : T = Zero::zero();
        for r in range(0, rows){
            let v  = unsafe{*ptr.offset(offset + r as int)};
            sum = sum + v * v;
        }
        offset += stride;
        result.set(0, c, sum);
    }
    result
}

/// Computes sum over rows and returns a column vector
pub fn sum_sqr_rw<T:Number>(m : & StridedNumberMatrix<T>) -> Matrix<T> {
    let cols = m.num_cols();
    let rows = m.num_rows();
    let mut result = Matrix::new(rows, 1);
    let ptr = m.as_ptr();
    let stride = m.stride() as int;
    let mut offset = m.start_offset();
    for r in range(0, rows) {
        let mut sum : T = Zero::zero();
        let mut src_offset  = offset;
        for _ in range(0, cols){
            let v = unsafe{*ptr.offset(src_offset)};
            sum = sum + v * v;
            src_offset += stride;
        }
        offset += 1;
        result.set(r, 0, sum);
    }
    result
}

/// Computes mean over columns and returns a row vector
pub fn mean_cw<T:Number+Float+FromPrimitive>(m : & StridedFloatMatrix<T>) -> Matrix<T> {
    let cols = m.num_cols();
    let rows = m.num_rows();
    let rows_t : T = FromPrimitive::from_uint(rows).unwrap();
    let mut result = Matrix::new(1, cols);
    let ptr = m.as_ptr();
    let stride = m.stride() as int;
    let mut offset = m.start_offset();
    for c in range(0, cols) {
        let mut sum : T = Zero::zero();
        for r in range(0, rows){
            sum = sum + unsafe{*ptr.offset(offset + r as int)};
        }
        offset += stride;
        result.set(0, c, sum / rows_t);
    }
    result
}

/// Computes mean over rows and returns a column vector
pub fn mean_rw<T:Number+Float+FromPrimitive>(m : & StridedFloatMatrix<T>) -> Matrix<T> {
    let cols = m.num_cols();
    let rows = m.num_rows();
    let rows_t : T = FromPrimitive::from_uint(rows).unwrap();
    let mut result = Matrix::new(rows, 1);
    let ptr = m.as_ptr();
    let stride = m.stride() as int;
    let mut offset = m.start_offset();
    for r in range(0, rows) {
        let mut sum : T = Zero::zero();
        let mut src_offset  = offset;
        for _ in range(0, cols){
            sum = sum + unsafe{*ptr.offset(src_offset)};
            src_offset += stride;
        }
        offset += 1;
        result.set(r, 0, sum / rows_t);
    }
    result
}

/******************************************************
 *
 *   Unit tests
 *
 *******************************************************/
#[cfg(test)]
mod test{

    use super::*;
    use api::*;

    #[test]
    fn test_moment_sum_cw_1(){
        let m = matrix_rw_i32(3, 3, &[
            1, 2, 3,
            4, 5, 6,
            7, 8, 9]);
        let s = sum_cw(&m);
        assert_eq!(s, matrix_cw_i32(1,3, &[12, 15, 18]));
    }

    #[test]
    fn test_moment_sum_cw_2(){
        let m = matrix_rw_i32(3, 3, &[
            1, 2, 3,
            4, 5, 6,
            7, 8, 9]);
        let v = m.view(1, 1, 2, 2);
        let s = sum_cw(&v);
        assert_eq!(s, matrix_cw_i32(1,2, &[13, 15]));
    }

    #[test]
    fn test_moment_sum_rw_1(){
        let m = matrix_rw_i32(3, 3, &[
            1, 2, 3,
            4, 5, 6,
            7, 8, 9]);
        let s = sum_rw(&m);
        assert_eq!(s, matrix_rw_i32(3,1, &[6, 15, 24]));
    }

    #[test]
    fn test_moment_sum_rw_2(){
        let m = matrix_rw_i32(3, 3, &[
            1, 2, 3,
            4, 5, 6,
            7, 8, 9]);
        let v = m.view(1, 1, 2, 2);
        let s = sum_rw(&v);
        assert_eq!(s, matrix_rw_i32(2,1, &[11, 17]));
    }

    #[test]
    fn test_moment_sum_sqr_cw_1(){
        let m = matrix_rw_i32(3, 3, &[
            1, 1, 2,
            2, 2, 1,
            3, 2, 2]);
        let s = sum_sqr_cw(&m);
        assert_eq!(s, matrix_cw_i32(1,3, &[14, 9, 9]));
    }

    #[test]
    fn test_moment_sum_sqr_cw_2(){
        let m = matrix_rw_i32(3, 3, &[
            1, 1, 2,
            2, 2, 1,
            3, 2, 2]);
        let v = m.view(1, 1, 2, 2);
        let s = sum_sqr_cw(&v);
        assert_eq!(s, matrix_cw_i32(1,2, &[8, 5]));
    }

    #[test]
    fn test_moment_sum_sqr_rw_1(){
        let m = matrix_rw_i32(3, 3, &[
            1, 1, 2,
            2, 2, 1,
            3, 2, 2]);
        let s = sum_sqr_rw(&m);
        assert_eq!(s, matrix_cw_i32(3,1, &[6, 9, 17]));
    }

    #[test]
    fn test_moment_sum_sqr_rw_2(){
        let m = matrix_rw_i32(3, 3, &[
            1, 1, 2,
            2, 2, 1,
            3, 2, 2]);
        let v = m.view(1, 1, 2, 2);
        let s = sum_sqr_rw(&v);
        assert_eq!(s, matrix_cw_i32(2,1, &[5, 8]));
    }

    #[test]
    fn test_moment_mean_cw_1(){
        let m = matrix_rw_f32(3, 3, &[
            1., 2., 3.,
            4., 5., 6.,
            7., 8., 9.]);
        let s = mean_cw(&m);
        assert_eq!(s, matrix_cw_f32(1,3, &[12./3., 15./3., 18./3.]));
    }

    #[test]
    fn test_moment_mean_cw_2(){
        let m = matrix_rw_f32(3, 3, &[
            1., 2., 3.,
            4., 5., 6.,
            7., 8., 9.]);
        let v = m.view(1, 1, 2, 2);
        let s = mean_cw(&v);
        assert_eq!(s, matrix_cw_f32(1,2, &[13./2., 15./2.]));
    }

    #[test]
    fn test_moment_mean_rw_1(){
        let m = matrix_rw_f32(3, 3, &[
            1., 2., 3.,
            4., 5., 6.,
            7., 8., 9.]);
        let s = mean_rw(&m);
        assert_eq!(s, matrix_rw_f32(3,1, &[6./3., 15./3., 24./3.]));
    }

    #[test]
    fn test_moment_mean_rw_2(){
        let m = matrix_rw_f32(3, 3, &[
            1., 2., 3.,
            4., 5., 6.,
            7., 8., 9.]);
        let v = m.view(1, 1, 2, 2);
        let s = mean_rw(&v);
        assert_eq!(s, matrix_rw_f32(2,1, &[11./2., 17./2.]));
    }

}<|endoftext|>


<commit_before>//! CMSHeap implementation.
use crate::countminsketch::CountMinSketch;
use std::cmp::Ordering;
use std::collections::hash_map::Entry;
use std::collections::{BTreeSet, HashMap};
use std::fmt;
use std::hash::Hash;
use std::rc::Rc;

#[derive(Debug)]
struct TreeEntry<T>
where
    T: Eq + Ord,
{
    obj: Rc<T>,
    n: usize,
}

impl<T> Clone for TreeEntry<T>
where
    T: Eq + Ord,
{
    fn clone(&self) -> Self {
        TreeEntry {
            obj: Rc::clone(&self.obj),
            n: self.n,
        }
    }
}

impl<T> PartialEq for TreeEntry<T>
where
    T: Eq + Ord,
{
    fn eq(&self, other: &TreeEntry<T>) -> bool {
        self.obj == other.obj
    }
}

impl<T> Eq for TreeEntry<T> where T: Eq + Ord {}

impl<T> PartialOrd for TreeEntry<T>
where
    T: Eq + Ord,
{
    fn partial_cmp(&self, other: &TreeEntry<T>) -> Option<Ordering> {
        match self.n.cmp(&other.n) {
            Ordering::Greater => Some(Ordering::Greater),
            Ordering::Less => Some(Ordering::Less),
            Ordering::Equal => Some(self.obj.cmp(&other.obj)),
        }
    }
}

impl<T> Ord for TreeEntry<T>
where
    T: Eq + Ord,
{
    fn cmp(&self, other: &TreeEntry<T>) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

/// A CMSHeap is a data structure keeps the `k` most frequent data points of a stream.
///
/// # Examples
/// ```
/// use pdatastructs::countminsketch::CountMinSketch;
/// use pdatastructs::topk::cmsheap::CMSHeap;
///
/// // set up filter
/// let epsilon = 0.1;  // error threshold
/// let delta = 0.2;  // epsilon is hit in (1 - 0.2) * 100% = 80%
/// let mut cms = CountMinSketch::with_point_query_properties(epsilon, delta);
/// let mut tk = CMSHeap::new(2, cms);
///
/// // add some data
/// for i in 0..1000 {
///     let x = i % 10;
///     let y = if x < 4 {
///         0
///     } else if x < 7 {
///         1
///     } else {
///         x
///     };
///     tk.add(y);
/// }
///
/// // later
/// let elements: Vec<u64> = tk.iter().collect();
/// assert_eq!(elements, vec![1, 0]);
/// ```
///
/// # Applications
/// - getting a fixed number of most common example of a large data set
/// - detect hotspots / very common events
///
/// # How It Works
/// The data structure is based on two parts:
///
/// 1. a reservoir for the most common elements that also stores precise (but not exact) counter
///    data
/// 2. a CountMinSketch to guess the count of all other elements
///
/// On insert, it is checked if the element is already in the reservoir. If so, the precise count
/// is updated. If not, the CountMinSketch is queried for a guess. If the guess is higher than the
/// least common element in the reservoir, the new element displaces this reservoir element. The
/// guess is used as an exact count and is stored alongside. In any case, the CountMinSketch is
/// updated.
///
/// # See Also
/// - `std::vec::Vec`: exact solution but needs to store the entire data stream
///
/// # References
/// - ["Top K Frequent Items Algorithm", Zhipeng Jiang, 2017](https://zpjiang.me/2017/11/13/top-k-elementes-system-design/)
#[derive(Clone)]
pub struct CMSHeap<T>
where
    T: Clone + Eq + Hash + Ord,
{
    cms: CountMinSketch<T>,
    obj2count: HashMap<Rc<T>, usize>,
    tree: BTreeSet<TreeEntry<T>>,
    k: usize,
}

impl<T> CMSHeap<T>
where
    T: Clone + Eq + Hash + Ord,
{
    /// Create new Top-K data structure.
    ///
    /// - `k`: number of elements to remember
    /// - `cms`: CountMinSketch that is used for guessing the frequency of elements not currently
    ///   hold. Refer to its documentation about parameter selection.
    ///
    /// Panics if `k == 0`.
    pub fn new(k: usize, cms: CountMinSketch<T>) -> Self {
        assert!(k > 0, "k must be greater than 0");

        Self {
            cms,
            obj2count: HashMap::new(),
            tree: BTreeSet::new(),
            k,
        }
    }

    /// Number of data points to remember.
    pub fn k(&self) -> usize {
        self.k
    }

    /// Observe a data point.
    pub fn add(&mut self, obj: T) {
        // create Rc so we can use obj in multiple data structs
        let rc = Rc::new(obj);

        // always increase CountMinSketch counts
        let count = self.cms.add(&rc);

        // check if entry is in top K
        let size = self.obj2count.len();
        let mut update_obj2count: Option<(usize, Rc<T>)> = None;
        match self.obj2count.entry(Rc::clone(&rc)) {
            Entry::Occupied(mut o) => {
                // it is => increase exact counter
                let n = o.get_mut();
                *n += 1;

                // update tree data
                let mut entry = TreeEntry {
                    obj: Rc::clone(&rc),
                    n: *n - 1,
                };
                self.tree.remove(&entry);
                entry.n += 1;
                self.tree.insert(entry);
            }
            Entry::Vacant(v) => {
                // it's not => check capicity
                if size < self.k {
                    // space left => add to top k
                    debug_assert!(count == 1);
                    v.insert(1);
                    self.tree.insert(TreeEntry {
                        obj: Rc::clone(&rc),
                        n: 1,
                    });
                } else {
                    // not enough space => check if it would be a top k element

                    // count at this point already contains the +1 from the current insertions
                    // because we've updated the CountMinSketch before the query

                    let min: TreeEntry<T> = (*self.tree.iter().next().unwrap()).clone();
                    if count > min.n {
                        // => kick out minimal element of top k
                        self.tree.remove(&min);
                        self.tree.insert(TreeEntry {
                            obj: Rc::clone(&rc),
                            n: count,
                        });

                        // delay obj2count changes, because it is currently borrowed
                        update_obj2count = Some((count, min.obj));
                    }
                }
            }
        }

        // trick the borrow checker
        if let Some((count, obj)) = update_obj2count {
            self.obj2count.insert(rc, count);
            self.obj2count.remove(&obj);
        }
    }

    /// Iterates over collected top-k values.
    ///
    /// The result may contain less than `k` values if less than `k` unique data points where
    /// observed.
    pub fn iter<'a>(&'a self) -> impl 'a + Iterator<Item = T> {
        self.tree.iter().map(|x| (*x.obj).clone())
    }

    /// Check whether the sampler is empty (i.e. no data points observer so far)
    pub fn is_empty(&self) -> bool {
        self.obj2count.is_empty()
    }

    /// Clear sampler, so that it behaves like it never observed any data points.
    pub fn clear(&mut self) {
        self.cms.clear();
        self.tree.clear();
        self.obj2count.clear();
    }
}

impl<T> fmt::Debug for CMSHeap<T>
where
    T: Clone + Eq + Hash + Ord,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "CMSHeap {{ k: {} }}", self.k)
    }
}

impl<T> Extend<T> for CMSHeap<T>
where
    T: Clone + Eq + Hash + Ord,
{
    fn extend<S: IntoIterator<Item = T>>(&mut self, iter: S) {
        for elem in iter {
            self.add(elem);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::CMSHeap;
    use crate::countminsketch::CountMinSketch;

    #[test]
    #[should_panic(expected = "k must be greater than 0")]
    fn new_panics_k0() {
        let cms = CountMinSketch::with_params(10, 20);
        CMSHeap::<usize>::new(0, cms);
    }

    #[test]
    fn getter() {
        let cms = CountMinSketch::with_params(10, 20);
        let tk: CMSHeap<usize> = CMSHeap::new(2, cms);

        assert_eq!(tk.k(), 2);
    }

    #[test]
    fn add_1() {
        let cms = CountMinSketch::with_params(10, 20);
        let mut tk = CMSHeap::new(2, cms);

        tk.add(1);
        assert_eq!(tk.iter().collect::<Vec<u32>>(), vec![1]);
    }

    #[test]
    fn add_2_same() {
        let cms = CountMinSketch::with_params(10, 20);
        let mut tk = CMSHeap::new(2, cms);

        tk.add(1);
        tk.add(1);
        assert_eq!(tk.iter().collect::<Vec<u32>>(), vec![1]);
    }

    #[test]
    fn add_2_different() {
        let cms = CountMinSketch::with_params(10, 20);
        let mut tk = CMSHeap::new(2, cms);

        tk.add(1);
        tk.add(2);
        assert_eq!(tk.iter().collect::<Vec<u32>>(), vec![1, 2]);
    }

    #[test]
    fn add_n() {
        let cms = CountMinSketch::with_params(10, 20);
        let mut tk = CMSHeap::new(2, cms);

        for i in 0..5 {
            tk.add(i);
        }
        for _ in 0..100 {
            tk.add(99);
        }
        for _ in 0..100 {
            tk.add(100);
        }
        for i in 0..5 {
            tk.add(i);
        }
        assert_eq!(tk.iter().collect::<Vec<u32>>(), vec![99, 100]);
    }

    #[test]
    fn is_empty() {
        let cms = CountMinSketch::with_params(10, 20);
        let mut tk = CMSHeap::new(2, cms);
        assert_eq!(tk.is_empty(), true);

        tk.add(0);
        assert_eq!(tk.is_empty(), false);
    }

    #[test]
    fn clear() {
        let cms = CountMinSketch::with_params(10, 20);
        let mut tk = CMSHeap::new(2, cms);
        tk.add(0);

        tk.clear();
        assert_eq!(tk.is_empty(), true);

        tk.add(1);
        assert_eq!(tk.iter().collect::<Vec<u32>>(), vec![1]);
    }

    #[test]
    fn clone() {
        let cms = CountMinSketch::with_params(10, 20);
        let mut tk1 = CMSHeap::new(2, cms);
        tk1.add(0);

        let mut tk2 = tk1.clone();
        tk2.add(1);

        assert_eq!(tk1.iter().collect::<Vec<u32>>(), vec![0]);
        assert_eq!(tk2.iter().collect::<Vec<u32>>(), vec![0, 1]);
    }

    #[test]
    fn debug() {
        let cms = CountMinSketch::with_params(10, 20);
        let tk: CMSHeap<usize> = CMSHeap::new(2, cms);
        assert_eq!(format!("{:?}", tk), "CMSHeap { k: 2 }");
    }

    #[test]
    fn extend() {
        let cms = CountMinSketch::with_params(10, 10);
        let mut tk = CMSHeap::new(2, cms);

        tk.extend(vec![0, 1]);
        assert_eq!(tk.iter().collect::<Vec<u32>>(), vec![0, 1]);
    }
}
<commit_msg>cmsheap: use NLL<commit_after>//! CMSHeap implementation.
use crate::countminsketch::CountMinSketch;
use std::cmp::Ordering;
use std::collections::hash_map::Entry;
use std::collections::{BTreeSet, HashMap};
use std::fmt;
use std::hash::Hash;
use std::rc::Rc;

#[derive(Debug)]
struct TreeEntry<T>
where
    T: Eq + Ord,
{
    obj: Rc<T>,
    n: usize,
}

impl<T> Clone for TreeEntry<T>
where
    T: Eq + Ord,
{
    fn clone(&self) -> Self {
        TreeEntry {
            obj: Rc::clone(&self.obj),
            n: self.n,
        }
    }
}

impl<T> PartialEq for TreeEntry<T>
where
    T: Eq + Ord,
{
    fn eq(&self, other: &TreeEntry<T>) -> bool {
        self.obj == other.obj
    }
}

impl<T> Eq for TreeEntry<T> where T: Eq + Ord {}

impl<T> PartialOrd for TreeEntry<T>
where
    T: Eq + Ord,
{
    fn partial_cmp(&self, other: &TreeEntry<T>) -> Option<Ordering> {
        match self.n.cmp(&other.n) {
            Ordering::Greater => Some(Ordering::Greater),
            Ordering::Less => Some(Ordering::Less),
            Ordering::Equal => Some(self.obj.cmp(&other.obj)),
        }
    }
}

impl<T> Ord for TreeEntry<T>
where
    T: Eq + Ord,
{
    fn cmp(&self, other: &TreeEntry<T>) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

/// A CMSHeap is a data structure keeps the `k` most frequent data points of a stream.
///
/// # Examples
/// ```
/// use pdatastructs::countminsketch::CountMinSketch;
/// use pdatastructs::topk::cmsheap::CMSHeap;
///
/// // set up filter
/// let epsilon = 0.1;  // error threshold
/// let delta = 0.2;  // epsilon is hit in (1 - 0.2) * 100% = 80%
/// let mut cms = CountMinSketch::with_point_query_properties(epsilon, delta);
/// let mut tk = CMSHeap::new(2, cms);
///
/// // add some data
/// for i in 0..1000 {
///     let x = i % 10;
///     let y = if x < 4 {
///         0
///     } else if x < 7 {
///         1
///     } else {
///         x
///     };
///     tk.add(y);
/// }
///
/// // later
/// let elements: Vec<u64> = tk.iter().collect();
/// assert_eq!(elements, vec![1, 0]);
/// ```
///
/// # Applications
/// - getting a fixed number of most common example of a large data set
/// - detect hotspots / very common events
///
/// # How It Works
/// The data structure is based on two parts:
///
/// 1. a reservoir for the most common elements that also stores precise (but not exact) counter
///    data
/// 2. a CountMinSketch to guess the count of all other elements
///
/// On insert, it is checked if the element is already in the reservoir. If so, the precise count
/// is updated. If not, the CountMinSketch is queried for a guess. If the guess is higher than the
/// least common element in the reservoir, the new element displaces this reservoir element. The
/// guess is used as an exact count and is stored alongside. In any case, the CountMinSketch is
/// updated.
///
/// # See Also
/// - `std::vec::Vec`: exact solution but needs to store the entire data stream
///
/// # References
/// - ["Top K Frequent Items Algorithm", Zhipeng Jiang, 2017](https://zpjiang.me/2017/11/13/top-k-elementes-system-design/)
#[derive(Clone)]
pub struct CMSHeap<T>
where
    T: Clone + Eq + Hash + Ord,
{
    cms: CountMinSketch<T>,
    obj2count: HashMap<Rc<T>, usize>,
    tree: BTreeSet<TreeEntry<T>>,
    k: usize,
}

impl<T> CMSHeap<T>
where
    T: Clone + Eq + Hash + Ord,
{
    /// Create new Top-K data structure.
    ///
    /// - `k`: number of elements to remember
    /// - `cms`: CountMinSketch that is used for guessing the frequency of elements not currently
    ///   hold. Refer to its documentation about parameter selection.
    ///
    /// Panics if `k == 0`.
    pub fn new(k: usize, cms: CountMinSketch<T>) -> Self {
        assert!(k > 0, "k must be greater than 0");

        Self {
            cms,
            obj2count: HashMap::new(),
            tree: BTreeSet::new(),
            k,
        }
    }

    /// Number of data points to remember.
    pub fn k(&self) -> usize {
        self.k
    }

    /// Observe a data point.
    pub fn add(&mut self, obj: T) {
        // create Rc so we can use obj in multiple data structs
        let rc = Rc::new(obj);

        // always increase CountMinSketch counts
        let count = self.cms.add(&rc);

        // check if entry is in top K
        let size = self.obj2count.len();
        match self.obj2count.entry(Rc::clone(&rc)) {
            Entry::Occupied(mut o) => {
                // it is => increase exact counter
                let n = o.get_mut();
                *n += 1;

                // update tree data
                let mut entry = TreeEntry {
                    obj: Rc::clone(&rc),
                    n: *n - 1,
                };
                self.tree.remove(&entry);
                entry.n += 1;
                self.tree.insert(entry);
            }
            Entry::Vacant(v) => {
                // it's not => check capicity
                if size < self.k {
                    // space left => add to top k
                    debug_assert!(count == 1);
                    v.insert(1);
                    self.tree.insert(TreeEntry {
                        obj: Rc::clone(&rc),
                        n: 1,
                    });
                } else {
                    // not enough space => check if it would be a top k element

                    // count at this point already contains the +1 from the current insertions
                    // because we've updated the CountMinSketch before the query

                    let min: TreeEntry<T> = (*self.tree.iter().next().unwrap()).clone();
                    if count > min.n {
                        // => kick out minimal element of top k
                        self.tree.remove(&min);
                        self.tree.insert(TreeEntry {
                            obj: Rc::clone(&rc),
                            n: count,
                        });

                        self.obj2count.insert(rc, count);
                        self.obj2count.remove(&min.obj);
                    }
                }
            }
        }
    }

    /// Iterates over collected top-k values.
    ///
    /// The result may contain less than `k` values if less than `k` unique data points where
    /// observed.
    pub fn iter<'a>(&'a self) -> impl 'a + Iterator<Item = T> {
        self.tree.iter().map(|x| (*x.obj).clone())
    }

    /// Check whether the sampler is empty (i.e. no data points observer so far)
    pub fn is_empty(&self) -> bool {
        self.obj2count.is_empty()
    }

    /// Clear sampler, so that it behaves like it never observed any data points.
    pub fn clear(&mut self) {
        self.cms.clear();
        self.tree.clear();
        self.obj2count.clear();
    }
}

impl<T> fmt::Debug for CMSHeap<T>
where
    T: Clone + Eq + Hash + Ord,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "CMSHeap {{ k: {} }}", self.k)
    }
}

impl<T> Extend<T> for CMSHeap<T>
where
    T: Clone + Eq + Hash + Ord,
{
    fn extend<S: IntoIterator<Item = T>>(&mut self, iter: S) {
        for elem in iter {
            self.add(elem);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::CMSHeap;
    use crate::countminsketch::CountMinSketch;

    #[test]
    #[should_panic(expected = "k must be greater than 0")]
    fn new_panics_k0() {
        let cms = CountMinSketch::with_params(10, 20);
        CMSHeap::<usize>::new(0, cms);
    }

    #[test]
    fn getter() {
        let cms = CountMinSketch::with_params(10, 20);
        let tk: CMSHeap<usize> = CMSHeap::new(2, cms);

        assert_eq!(tk.k(), 2);
    }

    #[test]
    fn add_1() {
        let cms = CountMinSketch::with_params(10, 20);
        let mut tk = CMSHeap::new(2, cms);

        tk.add(1);
        assert_eq!(tk.iter().collect::<Vec<u32>>(), vec![1]);
    }

    #[test]
    fn add_2_same() {
        let cms = CountMinSketch::with_params(10, 20);
        let mut tk = CMSHeap::new(2, cms);

        tk.add(1);
        tk.add(1);
        assert_eq!(tk.iter().collect::<Vec<u32>>(), vec![1]);
    }

    #[test]
    fn add_2_different() {
        let cms = CountMinSketch::with_params(10, 20);
        let mut tk = CMSHeap::new(2, cms);

        tk.add(1);
        tk.add(2);
        assert_eq!(tk.iter().collect::<Vec<u32>>(), vec![1, 2]);
    }

    #[test]
    fn add_n() {
        let cms = CountMinSketch::with_params(10, 20);
        let mut tk = CMSHeap::new(2, cms);

        for i in 0..5 {
            tk.add(i);
        }
        for _ in 0..100 {
            tk.add(99);
        }
        for _ in 0..100 {
            tk.add(100);
        }
        for i in 0..5 {
            tk.add(i);
        }
        assert_eq!(tk.iter().collect::<Vec<u32>>(), vec![99, 100]);
    }

    #[test]
    fn is_empty() {
        let cms = CountMinSketch::with_params(10, 20);
        let mut tk = CMSHeap::new(2, cms);
        assert_eq!(tk.is_empty(), true);

        tk.add(0);
        assert_eq!(tk.is_empty(), false);
    }

    #[test]
    fn clear() {
        let cms = CountMinSketch::with_params(10, 20);
        let mut tk = CMSHeap::new(2, cms);
        tk.add(0);

        tk.clear();
        assert_eq!(tk.is_empty(), true);

        tk.add(1);
        assert_eq!(tk.iter().collect::<Vec<u32>>(), vec![1]);
    }

    #[test]
    fn clone() {
        let cms = CountMinSketch::with_params(10, 20);
        let mut tk1 = CMSHeap::new(2, cms);
        tk1.add(0);

        let mut tk2 = tk1.clone();
        tk2.add(1);

        assert_eq!(tk1.iter().collect::<Vec<u32>>(), vec![0]);
        assert_eq!(tk2.iter().collect::<Vec<u32>>(), vec![0, 1]);
    }

    #[test]
    fn debug() {
        let cms = CountMinSketch::with_params(10, 20);
        let tk: CMSHeap<usize> = CMSHeap::new(2, cms);
        assert_eq!(format!("{:?}", tk), "CMSHeap { k: 2 }");
    }

    #[test]
    fn extend() {
        let cms = CountMinSketch::with_params(10, 10);
        let mut tk = CMSHeap::new(2, cms);

        tk.extend(vec![0, 1]);
        assert_eq!(tk.iter().collect::<Vec<u32>>(), vec![0, 1]);
    }
}
<|endoftext|>


<commit_before>/* Cymbalum, Molecular Simulation in Rust - Copyright (C) 2015 Guillaume Fraux
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
 */
//! Array types, for storage of data in multidimentional arrays. The types in
//! this module are only intented for data storage, and do not provide any
//! mathematical operations.
use std::ops::{Index, IndexMut};
use std::cmp;

/// Trait bound for data in the array types
pub trait Data: Clone + PartialEq + Default {}
impl<T: Clone + PartialEq + Default> Data for T {}

/******************************************************************************/
/// Bidimensional array, with cache locality and runtime size. This type is
/// intended for storage of data only, and do not provide any mathematical
/// operations.
#[derive(Debug, Clone, PartialEq)]
pub struct Array2<T: Data> {
    /// Data storage
    data: Vec<T>,
    /// Size of the array
    size: (usize, usize)
}

impl<T: Data> Array2<T> {
    /// Get the size of the array
    pub fn size(&self) -> (usize, usize) {
        self.size
    }

    /// Create a new empty `Array2`.
    pub fn new() -> Array2<T> {
        Array2{
            data: Vec::new(),
            size: (0, 0)
        }
    }

    /// Create a new `Array2` of size `size` filed with `T::default()` values.
    pub fn with_size(size: (usize, usize)) -> Array2<T> {
        Array2::<T>::check_size(size);
        let data_size = size.0 * size.1;
        let vec = vec![T::default(); data_size];
        Array2{
            data: vec,
            size: size
        }
    }

    /// Get the index in the `data` vector corresponding to the point `i, j`
    #[inline] fn get_index(&self, i: usize, j: usize) -> usize {
        Array2::<T>::get_index_for_size(i, j, self.size)
    }

    /// Get the index in the `data` vector corresponding to the point `i, j`,
    /// and the size `size`.
    #[inline] fn get_index_for_size(i: usize, j: usize, size: (usize, usize)) -> usize {
        i * size.1 + j
    }

    fn check_size(size: (usize, usize)) {
        assert!(size.0 != 0, "size can not be null in dimmension 0");
        assert!(size.1 != 0, "size can not be null in dimmension 1");
    }

    /// Resize the array to be of size `new_size * new_size`. If the new size
    /// is bigger than the old size, the new values inserted are `T::default()`.
    /// Old values are preseved.
    pub fn resize(&mut self, size: (usize, usize)) {
        Array2::<T>::check_size(size);
        if size == self.size {return;}
        let mut new_data = vec![T::default(); size.0 * size.1];
        let n0 = cmp::min(self.size.0, size.0);
        let n1 = cmp::min(self.size.1, size.1);
        for i0 in 0..n0 {
            for i1 in 0..n1 {
                let new_idx = Array2::<T>::get_index_for_size(i0, i1, size);
                new_data[new_idx] = self[(i0, i1)].clone();
            }
        }
        self.data = new_data;
        self.size = size;
    }
}

impl<T: Data> Index<(usize, usize)> for Array2<T> {
    type Output = T;
    #[inline]
    fn index(&self, index: (usize, usize)) -> &T {
        debug_assert!(index.0 < self.size.0, format!("index out of bounds in dimmension 0: the len is {} but the index is {}", self.size.0, index.0));
        debug_assert!(index.1 < self.size.1, format!("index out of bounds in dimmension 1: the len is {} but the index is {}", self.size.1, index.1));
        let idx = self.get_index(index.0, index.1);
        unsafe {
            return self.data.get_unchecked(idx);
        }
    }
}

impl<T: Data> IndexMut<(usize, usize)> for Array2<T> {
    #[inline]
    fn index_mut(&mut self, index: (usize, usize)) -> &mut T {
        debug_assert!(index.0 < self.size.0, format!("index out of bounds in dimmension 0: the len is {} but the index is {}", self.size.0, index.0));
        debug_assert!(index.1 < self.size.1, format!("index out of bounds in dimmension 1: the len is {} but the index is {}", self.size.1, index.1));
        let idx = self.get_index(index.0, index.1);
        unsafe {
            return self.data.get_unchecked_mut(idx);
        }
    }
}

/******************************************************************************/
/// 3 dimmensional array type with cache locality, and runtime size. This type
/// is intended for storage of data only, and do not provide any mathematical
/// operations.
#[derive(Debug, Clone, PartialEq)]
pub struct Array3<T: Data> {
    data: Vec<T>,
    size: (usize, usize, usize),
}

impl<T: Data> Array3<T> {
    /// Create a new empty tensor
    pub fn new() -> Array3<T> {
        Array3 {
            data: Vec::new(),
            size: (0, 0, 0),
        }
    }

    /// Get the current size of the array
    pub fn size(&self) -> (usize, usize, usize) {
        self.size
    }

    /// Create a new `Array3` of size `size` filed with `T::default()` values.
    pub fn with_size(size: (usize, usize, usize)) -> Array3<T> {
        Array3::<T>::check_size(size);
        let data_size = size.0 * size.1 * size.2;
        let vec = vec![T::default(); data_size];
        Array3 {
            data: vec,
            size: size,
        }
    }

    /// Get the index in the `data` vector corresponding to the point `i, j, k`
    #[inline] fn get_index(&self, i: usize, j: usize, k: usize) -> usize {
        Array3::<T>::get_index_for_size(i, j, k, self.size)
    }

    /// Get the index in the `data` vector corresponding to the point `i, j`,
    /// and the size `size`.
    #[inline] fn get_index_for_size(i: usize, j: usize, k:usize, size: (usize, usize, usize)) -> usize {
        i * size.1 * size.2 + j * size.2 + k
    }

    fn check_size(size: (usize, usize, usize)) {
        assert!(size.0 != 0, "size can not be null in dimmension 0");
        assert!(size.1 != 0, "size can not be null in dimmension 1");
        assert!(size.2 != 0, "size can not be null in dimmension 2");
    }

    /// Resize the array to be of size `new_size * new_size`. If the new size
    /// is bigger than the old size, the new values inserted are `T::default()`.
    /// Old values are preseved.
    pub fn resize(&mut self, size: (usize, usize, usize)) {
        Array3::<T>::check_size(size);
        if size == self.size {return;}
        let mut new_data = vec![T::default(); size.0 * size.1 * size.2];
        let n0 = cmp::min(self.size.0, size.0);
        let n1 = cmp::min(self.size.1, size.1);
        let n2 = cmp::min(self.size.2, size.2);
        for i0 in 0..n0 {
            for i1 in 0..n1 {
                for i2 in 0..n2 {
                    let new_idx = Array3::<T>::get_index_for_size(i0, i1, i2, size);
                    new_data[new_idx] = self[(i0, i1, i2)].clone();
                }
            }
        }
        self.data = new_data;
        self.size = size;
    }
}

impl<T: Data> Index<(usize, usize, usize)> for Array3<T> {
    type Output = T;
    #[inline]
    fn index(&self, index: (usize, usize, usize)) -> &T {
        debug_assert!(index.0 < self.size.0, format!("index out of bounds in dimmension 0: the len is {} but the index is {}", self.size.0, index.0));
        debug_assert!(index.1 < self.size.1, format!("index out of bounds in dimmension 1: the len is {} but the index is {}", self.size.1, index.1));
        debug_assert!(index.2 < self.size.2, format!("index out of bounds in dimmension 2: the len is {} but the index is {}", self.size.2, index.2));
        let idx = self.get_index(index.0, index.1, index.2);
        unsafe {
            return self.data.get_unchecked(idx);
        }
    }
}

impl<T: Data> IndexMut<(usize, usize, usize)> for Array3<T> {
    #[inline]
    fn index_mut(&mut self, index: (usize, usize, usize)) -> &mut T {
        debug_assert!(index.0 < self.size.0, format!("index out of bounds in dimmension 0: the len is {} but the index is {}", self.size.0, index.0));
        debug_assert!(index.1 < self.size.1, format!("index out of bounds in dimmension 1: the len is {} but the index is {}", self.size.1, index.1));
        debug_assert!(index.2 < self.size.2, format!("index out of bounds in dimmension 2: the len is {} but the index is {}", self.size.2, index.2));
        let idx = self.get_index(index.0, index.1, index.2);
        unsafe {
            return self.data.get_unchecked_mut(idx);
        }
    }
}

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

    mod array_2 {
        use super::*;

        #[test]
        #[should_panic]
        fn out_of_bounds_dim_1() {
            let a = Array2::<f64>::with_size((4, 5));
            let _ = a[(6, 1)];
        }

        #[test]
        #[should_panic]
        fn out_of_bounds_dim_2() {
            let a = Array2::<f64>::with_size((4, 5));
            let _ = a[(1, 6)];
        }

        #[test]
        fn size() {
            let a = Array2::<f64>::with_size((6, 4));
            assert_eq!(a.size(), (6, 4));
        }

        #[test]
        fn index() {
            let mut a = Array2::<f64>::with_size((4, 8));
            for i in 0..4 {
                for j in 0..8 {
                    assert_eq!(a[(i, j)], 0.0);
                }
            }

            a[(2, 3)] = 7.0;
            assert_eq!(a[(2, 3)], 7.0);
        }

        #[test]
        fn resize() {
            let mut a = Array2::<f64>::with_size((6, 5));
            assert_eq!(a.size(), (6, 5));
            a[(2, 3)] = 42.0;

            a.resize((9, 7));
            assert_eq!(a.size(), (9, 7));
            assert_eq!(a[(2, 3)], 42.0);

            a.resize((3, 4));
            assert_eq!(a.size(), (3, 4));
            assert_eq!(a[(2, 3)], 42.0);
        }

        #[test]
        #[should_panic]
        fn resize_to_zero() {
            let mut a = Array2::<f64>::with_size((6, 5));
            a.resize((0, 3));
        }
    }

    mod array_3 {
        use super::*;

        #[test]
        #[should_panic]
        fn out_of_bounds_dim_1() {
            let a = Array3::<f64>::with_size((4, 5, 6));
            let _ = a[(6, 1, 3)];
        }

        #[test]
        #[should_panic]
        fn out_of_bounds_dim_2() {
            let a = Array3::<f64>::with_size((4, 5, 6));
            let _ = a[(1, 7, 3)];
        }

        #[test]
        #[should_panic]
        fn out_of_bounds_dim_3() {
            let a = Array3::<f64>::with_size((4, 5, 6));
            let _ = a[(0, 1, 8)];
        }

        #[test]
        fn size() {
            let a = Array3::<f64>::with_size((6, 4, 9));
            assert_eq!(a.size(), (6, 4, 9));
        }

        #[test]
        fn index() {
            let mut a = Array3::<f64>::with_size((4, 5, 3));
            for i in 0..4 {
                for j in 0..5 {
                    for k in 0..3 {
                        assert_eq!(a[(i, j, k)], 0.0);
                    }
                }
            }

            a[(2, 3, 0)] = 7.0;
            assert_eq!(a[(2, 3, 0)], 7.0);
        }

        #[test]
        fn resize() {
            let mut a = Array3::<f64>::with_size((6, 6, 8));
            assert_eq!(a.size(), (6, 6, 8));
            a[(2, 3, 0)] = 42.0;

            a.resize((9, 10, 2));
            assert_eq!(a.size(), (9, 10, 2));
            assert_eq!(a[(2, 3, 0)], 42.0);

            a.resize((3, 4, 1));
            assert_eq!(a.size(), (3, 4, 1));
            assert_eq!(a[(2, 3, 0)], 42.0);
        }

        #[test]
        #[should_panic]
        fn resize_to_zero() {
            let mut a = Array3::<f64>::with_size((6, 5, 7));
            a.resize((0, 3, 2));
        }
    }
}
<commit_msg>Add a note about the row-major storage used in Array<commit_after>/* Cymbalum, Molecular Simulation in Rust - Copyright (C) 2015 Guillaume Fraux
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
 */
//! Array types, for storage of data in multidimentional arrays. The types in
//! this module are only intented for data storage, and do not provide any
//! mathematical operations.
use std::ops::{Index, IndexMut};
use std::cmp;

/// Trait bound for data in the array types
pub trait Data: Clone + PartialEq + Default {}
impl<T: Clone + PartialEq + Default> Data for T {}

/******************************************************************************/
/// Bidimensional array, with cache locality and runtime size. This type is
/// intended for storage of data only, and do not provide any mathematical
/// operations. Data is stored in the row-major mode.
#[derive(Debug, Clone, PartialEq)]
pub struct Array2<T: Data> {
    /// Data storage
    data: Vec<T>,
    /// Size of the array
    size: (usize, usize)
}

impl<T: Data> Array2<T> {
    /// Get the size of the array
    pub fn size(&self) -> (usize, usize) {
        self.size
    }

    /// Create a new empty `Array2`.
    pub fn new() -> Array2<T> {
        Array2{
            data: Vec::new(),
            size: (0, 0)
        }
    }

    /// Create a new `Array2` of size `size` filed with `T::default()` values.
    pub fn with_size(size: (usize, usize)) -> Array2<T> {
        Array2::<T>::check_size(size);
        let data_size = size.0 * size.1;
        let vec = vec![T::default(); data_size];
        Array2{
            data: vec,
            size: size
        }
    }

    /// Get the index in the `data` vector corresponding to the point `i, j`
    #[inline] fn get_index(&self, i: usize, j: usize) -> usize {
        Array2::<T>::get_index_for_size(i, j, self.size)
    }

    /// Get the index in the `data` vector corresponding to the point `i, j`,
    /// and the size `size`.
    #[inline] fn get_index_for_size(i: usize, j: usize, size: (usize, usize)) -> usize {
        i * size.1 + j
    }

    fn check_size(size: (usize, usize)) {
        assert!(size.0 != 0, "size can not be null in dimmension 0");
        assert!(size.1 != 0, "size can not be null in dimmension 1");
    }

    /// Resize the array to be of size `new_size * new_size`. If the new size
    /// is bigger than the old size, the new values inserted are `T::default()`.
    /// Old values are preseved.
    pub fn resize(&mut self, size: (usize, usize)) {
        Array2::<T>::check_size(size);
        if size == self.size {return;}
        let mut new_data = vec![T::default(); size.0 * size.1];
        let n0 = cmp::min(self.size.0, size.0);
        let n1 = cmp::min(self.size.1, size.1);
        for i0 in 0..n0 {
            for i1 in 0..n1 {
                let new_idx = Array2::<T>::get_index_for_size(i0, i1, size);
                new_data[new_idx] = self[(i0, i1)].clone();
            }
        }
        self.data = new_data;
        self.size = size;
    }
}

impl<T: Data> Index<(usize, usize)> for Array2<T> {
    type Output = T;
    #[inline]
    fn index(&self, index: (usize, usize)) -> &T {
        debug_assert!(index.0 < self.size.0, format!("index out of bounds in dimmension 0: the len is {} but the index is {}", self.size.0, index.0));
        debug_assert!(index.1 < self.size.1, format!("index out of bounds in dimmension 1: the len is {} but the index is {}", self.size.1, index.1));
        let idx = self.get_index(index.0, index.1);
        unsafe {
            return self.data.get_unchecked(idx);
        }
    }
}

impl<T: Data> IndexMut<(usize, usize)> for Array2<T> {
    #[inline]
    fn index_mut(&mut self, index: (usize, usize)) -> &mut T {
        debug_assert!(index.0 < self.size.0, format!("index out of bounds in dimmension 0: the len is {} but the index is {}", self.size.0, index.0));
        debug_assert!(index.1 < self.size.1, format!("index out of bounds in dimmension 1: the len is {} but the index is {}", self.size.1, index.1));
        let idx = self.get_index(index.0, index.1);
        unsafe {
            return self.data.get_unchecked_mut(idx);
        }
    }
}

/******************************************************************************/
/// 3 dimmensional array type with cache locality, and runtime size. This type
/// is intended for storage of data only, and do not provide any mathematical
/// operations. Data is stored in the row-major mode.
#[derive(Debug, Clone, PartialEq)]
pub struct Array3<T: Data> {
    data: Vec<T>,
    size: (usize, usize, usize),
}

impl<T: Data> Array3<T> {
    /// Create a new empty tensor
    pub fn new() -> Array3<T> {
        Array3 {
            data: Vec::new(),
            size: (0, 0, 0),
        }
    }

    /// Get the current size of the array
    pub fn size(&self) -> (usize, usize, usize) {
        self.size
    }

    /// Create a new `Array3` of size `size` filed with `T::default()` values.
    pub fn with_size(size: (usize, usize, usize)) -> Array3<T> {
        Array3::<T>::check_size(size);
        let data_size = size.0 * size.1 * size.2;
        let vec = vec![T::default(); data_size];
        Array3 {
            data: vec,
            size: size,
        }
    }

    /// Get the index in the `data` vector corresponding to the point `i, j, k`
    #[inline] fn get_index(&self, i: usize, j: usize, k: usize) -> usize {
        Array3::<T>::get_index_for_size(i, j, k, self.size)
    }

    /// Get the index in the `data` vector corresponding to the point `i, j`,
    /// and the size `size`.
    #[inline] fn get_index_for_size(i: usize, j: usize, k:usize, size: (usize, usize, usize)) -> usize {
        i * size.1 * size.2 + j * size.2 + k
    }

    fn check_size(size: (usize, usize, usize)) {
        assert!(size.0 != 0, "size can not be null in dimmension 0");
        assert!(size.1 != 0, "size can not be null in dimmension 1");
        assert!(size.2 != 0, "size can not be null in dimmension 2");
    }

    /// Resize the array to be of size `new_size * new_size`. If the new size
    /// is bigger than the old size, the new values inserted are `T::default()`.
    /// Old values are preseved.
    pub fn resize(&mut self, size: (usize, usize, usize)) {
        Array3::<T>::check_size(size);
        if size == self.size {return;}
        let mut new_data = vec![T::default(); size.0 * size.1 * size.2];
        let n0 = cmp::min(self.size.0, size.0);
        let n1 = cmp::min(self.size.1, size.1);
        let n2 = cmp::min(self.size.2, size.2);
        for i0 in 0..n0 {
            for i1 in 0..n1 {
                for i2 in 0..n2 {
                    let new_idx = Array3::<T>::get_index_for_size(i0, i1, i2, size);
                    new_data[new_idx] = self[(i0, i1, i2)].clone();
                }
            }
        }
        self.data = new_data;
        self.size = size;
    }
}

impl<T: Data> Index<(usize, usize, usize)> for Array3<T> {
    type Output = T;
    #[inline]
    fn index(&self, index: (usize, usize, usize)) -> &T {
        debug_assert!(index.0 < self.size.0, format!("index out of bounds in dimmension 0: the len is {} but the index is {}", self.size.0, index.0));
        debug_assert!(index.1 < self.size.1, format!("index out of bounds in dimmension 1: the len is {} but the index is {}", self.size.1, index.1));
        debug_assert!(index.2 < self.size.2, format!("index out of bounds in dimmension 2: the len is {} but the index is {}", self.size.2, index.2));
        let idx = self.get_index(index.0, index.1, index.2);
        unsafe {
            return self.data.get_unchecked(idx);
        }
    }
}

impl<T: Data> IndexMut<(usize, usize, usize)> for Array3<T> {
    #[inline]
    fn index_mut(&mut self, index: (usize, usize, usize)) -> &mut T {
        debug_assert!(index.0 < self.size.0, format!("index out of bounds in dimmension 0: the len is {} but the index is {}", self.size.0, index.0));
        debug_assert!(index.1 < self.size.1, format!("index out of bounds in dimmension 1: the len is {} but the index is {}", self.size.1, index.1));
        debug_assert!(index.2 < self.size.2, format!("index out of bounds in dimmension 2: the len is {} but the index is {}", self.size.2, index.2));
        let idx = self.get_index(index.0, index.1, index.2);
        unsafe {
            return self.data.get_unchecked_mut(idx);
        }
    }
}

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

    mod array_2 {
        use super::*;

        #[test]
        #[should_panic]
        fn out_of_bounds_dim_1() {
            let a = Array2::<f64>::with_size((4, 5));
            let _ = a[(6, 1)];
        }

        #[test]
        #[should_panic]
        fn out_of_bounds_dim_2() {
            let a = Array2::<f64>::with_size((4, 5));
            let _ = a[(1, 6)];
        }

        #[test]
        fn size() {
            let a = Array2::<f64>::with_size((6, 4));
            assert_eq!(a.size(), (6, 4));
        }

        #[test]
        fn index() {
            let mut a = Array2::<f64>::with_size((4, 8));
            for i in 0..4 {
                for j in 0..8 {
                    assert_eq!(a[(i, j)], 0.0);
                }
            }

            a[(2, 3)] = 7.0;
            assert_eq!(a[(2, 3)], 7.0);
        }

        #[test]
        fn resize() {
            let mut a = Array2::<f64>::with_size((6, 5));
            assert_eq!(a.size(), (6, 5));
            a[(2, 3)] = 42.0;

            a.resize((9, 7));
            assert_eq!(a.size(), (9, 7));
            assert_eq!(a[(2, 3)], 42.0);

            a.resize((3, 4));
            assert_eq!(a.size(), (3, 4));
            assert_eq!(a[(2, 3)], 42.0);
        }

        #[test]
        #[should_panic]
        fn resize_to_zero() {
            let mut a = Array2::<f64>::with_size((6, 5));
            a.resize((0, 3));
        }
    }

    mod array_3 {
        use super::*;

        #[test]
        #[should_panic]
        fn out_of_bounds_dim_1() {
            let a = Array3::<f64>::with_size((4, 5, 6));
            let _ = a[(6, 1, 3)];
        }

        #[test]
        #[should_panic]
        fn out_of_bounds_dim_2() {
            let a = Array3::<f64>::with_size((4, 5, 6));
            let _ = a[(1, 7, 3)];
        }

        #[test]
        #[should_panic]
        fn out_of_bounds_dim_3() {
            let a = Array3::<f64>::with_size((4, 5, 6));
            let _ = a[(0, 1, 8)];
        }

        #[test]
        fn size() {
            let a = Array3::<f64>::with_size((6, 4, 9));
            assert_eq!(a.size(), (6, 4, 9));
        }

        #[test]
        fn index() {
            let mut a = Array3::<f64>::with_size((4, 5, 3));
            for i in 0..4 {
                for j in 0..5 {
                    for k in 0..3 {
                        assert_eq!(a[(i, j, k)], 0.0);
                    }
                }
            }

            a[(2, 3, 0)] = 7.0;
            assert_eq!(a[(2, 3, 0)], 7.0);
        }

        #[test]
        fn resize() {
            let mut a = Array3::<f64>::with_size((6, 6, 8));
            assert_eq!(a.size(), (6, 6, 8));
            a[(2, 3, 0)] = 42.0;

            a.resize((9, 10, 2));
            assert_eq!(a.size(), (9, 10, 2));
            assert_eq!(a[(2, 3, 0)], 42.0);

            a.resize((3, 4, 1));
            assert_eq!(a.size(), (3, 4, 1));
            assert_eq!(a[(2, 3, 0)], 42.0);
        }

        #[test]
        #[should_panic]
        fn resize_to_zero() {
            let mut a = Array3::<f64>::with_size((6, 5, 7));
            a.resize((0, 3, 2));
        }
    }
}
<|endoftext|>


<commit_before>use pest::prelude::*;

impl_rdp! {
    grammar! {
        whitespace = _{ [" "]|["\t"]|["\n"]|["\r"] }

        raw_text = @{ ( !["{{"] ~ any )+ }
        raw_block_text = @{ ( !["{{{{"] ~ any )* }

// Note: this is not full and strict json literal definition, just for tokenize string,
// array and object types which may contains whitespace. We will use a real json parser
// for real json processing
        literal = { string_literal |
                    array_literal |
                    object_literal |
                    number_literal |
                    null_literal |
                    boolean_literal }

        null_literal = { ["null"] }
        boolean_literal = { ["true"]|["false"] }
        number_literal = @{ ["-"]? ~ ['0'..'9']+ ~ ["."]? ~ ['0'..'9']* ~ (["E"] ~ ["-"]? ~ ['0'..'9']+)? }
        string_literal = @{ ["\""] ~ (!["\""] ~ (["\\\""] | any))* ~ ["\""] }
        array_literal = { ["["] ~ literal? ~ ([","] ~ literal)* ~ ["]"] }
        object_literal = { ["{"] ~ (string_literal ~ [":"] ~ literal)? ~ ([","] ~ string_literal ~ [":"] ~ literal)* ~ ["}"] }

// FIXME: a[0], a["b]
        symbol_char = _{ ['a'..'z']|['A'..'Z']|['0'..'9']|["_"]|["."]|["@"]|["$"]|["<"]|[">"]|["-"] }
        path_char = _{ ["/"] }

        identifier = @{ symbol_char ~ ( symbol_char | path_char )* }
        reference = @{ identifier ~ (["["] ~ (string_literal|['0'..'9']+) ~ ["]"])* ~ ["-"]* ~ reference* }
        name = _{ subexpression | reference }

        param = { literal | reference | subexpression }
        hash = { identifier ~ ["="] ~ param }
        exp_line = _{ identifier ~ (hash|param)* }

        subexpression = { ["("] ~ name ~ (hash|param)* ~ [")"] }

        pre_whitespace_omitter = { ["~"] }
        pro_whitespace_omitter = { ["~"] }

        expression = { !invert_tag ~ ["{{"] ~ pre_whitespace_omitter? ~ name ~
                        pro_whitespace_omitter? ~ ["}}"] }

        html_expression = { ["{{{"] ~ pre_whitespace_omitter? ~ name ~
                                      pro_whitespace_omitter? ~ ["}}}"] }

        helper_expression = { !invert_tag ~ ["{{"] ~ pre_whitespace_omitter? ~ exp_line ~
                               pro_whitespace_omitter? ~ ["}}"] }

        invert_tag = { ["{{else}}"]|["{{^}}"] }
        helper_block_start = { ["{{"] ~ pre_whitespace_omitter? ~ ["#"] ~ exp_line ~
                                        pro_whitespace_omitter? ~ ["}}"] }
        helper_block_end = { ["{{"] ~ pre_whitespace_omitter? ~ ["/"] ~ name ~
                                      pro_whitespace_omitter? ~ ["}}"] }
        helper_block = _{ helper_block_start ~ template ~
                         (invert_tag ~ template)? ~
                         helper_block_end }

        raw_block_start = { ["{{{{"] ~ pre_whitespace_omitter? ~ exp_line ~
                                       pro_whitespace_omitter? ~ ["}}}}"] }
        raw_block_end = { ["{{{{"] ~ pre_whitespace_omitter? ~ ["/"] ~ name ~
                                     pro_whitespace_omitter? ~ ["}}}}"] }
        raw_block = _{ raw_block_start ~ raw_block_text ~ raw_block_end }

        hbs_comment = { ["{{!"] ~ (!["}}"] ~ any)* ~ ["}}"] }

        template = { (
            raw_text |
            expression |
            html_expression |
            helper_expression |
            helper_block |
            raw_block |
            hbs_comment )*
        }

        parameter = _{ param ~ eoi }
        handlebars = _{ template ~ eoi }
    }
}

#[test]
fn test_raw_text() {
    let mut rdp = Rdp::new(StringInput::new("<h1> helloworld </h1>    "));
    assert!(rdp.raw_text());
    assert!(rdp.end());
}

#[test]
fn test_raw_block_text() {
    let mut rdp = Rdp::new(StringInput::new("<h1> {{hello}} </h1>"));
    assert!(rdp.raw_block_text());
    assert!(rdp.end());
}

#[test]
fn test_reference() {
    let s = vec!["a",
                 "abc",
                 "../a",
                 "a.b",
                 "@abc",
                 "a[\"abc\"]",
                 "aBc[\"abc\"]",
                 "abc[0][\"nice\"]",
                 "some-name",
                 "this.[0].ok"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.reference());
        assert!(rdp.end());
    }
}

#[test]
fn test_name() {
    let s = vec!["if", "(abc)"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.name());
        assert!(rdp.end());
    }
}

#[test]
fn test_param() {
    let s = vec!["hello", "\"json literal\""];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.param());
        assert!(rdp.end());
    }
}

#[test]
fn test_hash() {
    let s = vec!["hello=world", "hello=\"world\"", "hello=(world)", "hello=(world 0)"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.hash());
        assert!(rdp.end());
    }
}

#[test]
fn test_json_literal() {
    let s = vec!["\"json string\"",
                 "\"quot: \\\"\"",
                 "[]",
                 "[\"hello\"]",
                 "[1,2,3,4,true]",
                 "{\"hello\": \"world\"}",
                 "{}",
                 "{\"a\":1, \"b\":2 }"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.literal());
        assert!(rdp.end());
    }
}

#[test]
fn test_comment() {
    let s = vec!["{{! hello }}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.hbs_comment());
        assert!(rdp.end());
    }
}

#[test]
fn test_subexpression() {
    let s = vec!["(sub)", "(sub 0)", "(sub a=1)"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.subexpression());
        assert!(rdp.end());
    }
}

#[test]
fn test_expression() {
    let s = vec!["{{exp}}", "{{(exp)}}", "{{this.name}}", "{{this.[0].name}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.expression());
        assert!(rdp.end());
    }
}

#[test]
fn test_helper_expression() {
    let s = vec!["{{exp 1}}",
                 "{{exp \"literal\"}}",
                 "{{exp ref}}",
                 "{{exp (sub)}}",
                 "{{exp (sub 123)}}",
                 "{{exp []}}",
                 "{{exp {}}}",
                 "{{exp key=1}}",
                 "{{exp key=ref}}",
                 "{{exp key=(sub)}}",
                 "{{exp key=(sub 0)}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.helper_expression());
        assert!(rdp.end());
    }
}

#[test]
fn test_identifier_with_dash() {
    let s = vec!["{{exp-foo}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.expression());
        assert!(rdp.end());
    }
}

#[test]
fn test_html_expression() {
    let s = vec!["{{{html}}}", "{{{(html)}}}", "{{{(html)}}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.html_expression());
        assert!(rdp.end());
    }
}

#[test]
fn test_helper_start() {
    let s = vec!["{{#if hello}}",
                 "{{#if (hello)}}",
                 "{{#if hello=world}}",
                 "{{#if hello hello=world}}",
                 "{{#if []}}",
                 "{{#if {}}}",
                 "{{#if}}",
                 "{{~#if hello~}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.helper_block_start());
        assert!(rdp.end());
    }
}

#[test]
fn test_helper_end() {
    let s = vec!["{{/if}}", "{{~/if}}", "{{~/if ~}}", "{{/if   ~}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.helper_block_end());
        assert!(rdp.end());
    }
}

#[test]
fn test_helper_block() {
    let s = vec!["{{#if hello}}hello{{/if}}",
                 "{{#if true}}hello{{/if}}",
                 "{{#if nice ok=1}}hello{{/if}}",
                 "{{#if}}hello{{else}}world{{/if}}",
                 "{{#if}}hello{{^}}world{{/if}}",
                 "{{#if}}{{#if}}hello{{/if}}{{/if}}",
                 "{{#if}}{{/if}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.helper_block());
        assert!(rdp.end());
    }
}

#[test]
fn test_raw_block() {
    let s = vec!["{{{{if hello}}}}good {{hello}}{{{{/if}}}}",
                 "{{{{if hello}}}}{{#if nice}}{{/if}}{{{{/if}}}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.raw_block());
        assert!(rdp.end());
    }
}
<commit_msg>(feat) added grammar for block params [#42]<commit_after>use pest::prelude::*;

impl_rdp! {
    grammar! {
        whitespace = _{ [" "]|["\t"]|["\n"]|["\r"] }

        raw_text = @{ ( !["{{"] ~ any )+ }
        raw_block_text = @{ ( !["{{{{"] ~ any )* }

// Note: this is not full and strict json literal definition, just for tokenize string,
// array and object types which may contains whitespace. We will use a real json parser
// for real json processing
        literal = { string_literal |
                    array_literal |
                    object_literal |
                    number_literal |
                    null_literal |
                    boolean_literal }

        null_literal = { ["null"] }
        boolean_literal = { ["true"]|["false"] }
        number_literal = @{ ["-"]? ~ ['0'..'9']+ ~ ["."]? ~ ['0'..'9']* ~ (["E"] ~ ["-"]? ~ ['0'..'9']+)? }
        string_literal = @{ ["\""] ~ (!["\""] ~ (["\\\""] | any))* ~ ["\""] }
        array_literal = { ["["] ~ literal? ~ ([","] ~ literal)* ~ ["]"] }
        object_literal = { ["{"] ~ (string_literal ~ [":"] ~ literal)? ~ ([","] ~ string_literal ~ [":"] ~ literal)* ~ ["}"] }

// FIXME: a[0], a["b]
        symbol_char = _{ ['a'..'z']|['A'..'Z']|['0'..'9']|["_"]|["."]|["@"]|["$"]|["<"]|[">"]|["-"] }
        path_char = _{ ["/"] }

        identifier = @{ symbol_char ~ ( symbol_char | path_char )* }
        reference = @{ identifier ~ (["["] ~ (string_literal|['0'..'9']+) ~ ["]"])* ~ ["-"]* ~ reference* }
        name = _{ subexpression | reference }

        param = { !["as"] ~ (literal | reference | subexpression) }
        hash = { identifier ~ ["="] ~ param }
        block_params = { ["as"] ~ ["|"] ~ identifier+ ~ ["|"]}
        exp_line = _{ identifier ~ (hash|param)* ~ block_params?}

        subexpression = { ["("] ~ name ~ (hash|param)* ~ [")"] }

        pre_whitespace_omitter = { ["~"] }
        pro_whitespace_omitter = { ["~"] }

        expression = { !invert_tag ~ ["{{"] ~ pre_whitespace_omitter? ~ name ~
                        pro_whitespace_omitter? ~ ["}}"] }

        html_expression = { ["{{{"] ~ pre_whitespace_omitter? ~ name ~
                                      pro_whitespace_omitter? ~ ["}}}"] }

        helper_expression = { !invert_tag ~ ["{{"] ~ pre_whitespace_omitter? ~ exp_line ~
                               pro_whitespace_omitter? ~ ["}}"] }

        invert_tag = { ["{{else}}"]|["{{^}}"] }
        helper_block_start = { ["{{"] ~ pre_whitespace_omitter? ~ ["#"] ~ exp_line ~
                                        pro_whitespace_omitter? ~ ["}}"] }
        helper_block_end = { ["{{"] ~ pre_whitespace_omitter? ~ ["/"] ~ name ~
                                      pro_whitespace_omitter? ~ ["}}"] }
        helper_block = _{ helper_block_start ~ template ~
                         (invert_tag ~ template)? ~
                         helper_block_end }

        raw_block_start = { ["{{{{"] ~ pre_whitespace_omitter? ~ exp_line ~
                                       pro_whitespace_omitter? ~ ["}}}}"] }
        raw_block_end = { ["{{{{"] ~ pre_whitespace_omitter? ~ ["/"] ~ name ~
                                     pro_whitespace_omitter? ~ ["}}}}"] }
        raw_block = _{ raw_block_start ~ raw_block_text ~ raw_block_end }

        hbs_comment = { ["{{!"] ~ (!["}}"] ~ any)* ~ ["}}"] }

        template = { (
            raw_text |
            expression |
            html_expression |
            helper_expression |
            helper_block |
            raw_block |
            hbs_comment )*
        }

        parameter = _{ param ~ eoi }
        handlebars = _{ template ~ eoi }
    }
}

#[test]
fn test_raw_text() {
    let mut rdp = Rdp::new(StringInput::new("<h1> helloworld </h1>    "));
    assert!(rdp.raw_text());
    assert!(rdp.end());
}

#[test]
fn test_raw_block_text() {
    let mut rdp = Rdp::new(StringInput::new("<h1> {{hello}} </h1>"));
    assert!(rdp.raw_block_text());
    assert!(rdp.end());
}

#[test]
fn test_reference() {
    let s = vec!["a",
                 "abc",
                 "../a",
                 "a.b",
                 "@abc",
                 "a[\"abc\"]",
                 "aBc[\"abc\"]",
                 "abc[0][\"nice\"]",
                 "some-name",
                 "this.[0].ok"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.reference());
        assert!(rdp.end());
    }
}

#[test]
fn test_name() {
    let s = vec!["if", "(abc)"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.name());
        assert!(rdp.end());
    }
}

#[test]
fn test_param() {
    let s = vec!["hello", "\"json literal\""];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.param());
        assert!(rdp.end());
    }
}

#[test]
fn test_hash() {
    let s = vec!["hello=world", "hello=\"world\"", "hello=(world)", "hello=(world 0)"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.hash());
        assert!(rdp.end());
    }
}

#[test]
fn test_json_literal() {
    let s = vec!["\"json string\"",
                 "\"quot: \\\"\"",
                 "[]",
                 "[\"hello\"]",
                 "[1,2,3,4,true]",
                 "{\"hello\": \"world\"}",
                 "{}",
                 "{\"a\":1, \"b\":2 }"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.literal());
        assert!(rdp.end());
    }
}

#[test]
fn test_comment() {
    let s = vec!["{{! hello }}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.hbs_comment());
        assert!(rdp.end());
    }
}

#[test]
fn test_subexpression() {
    let s = vec!["(sub)", "(sub 0)", "(sub a=1)"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.subexpression());
        assert!(rdp.end());
    }
}

#[test]
fn test_expression() {
    let s = vec!["{{exp}}", "{{(exp)}}", "{{this.name}}", "{{this.[0].name}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.expression());
        assert!(rdp.end());
    }
}

#[test]
fn test_helper_expression() {
    let s = vec!["{{exp 1}}",
                 "{{exp \"literal\"}}",
                 "{{exp ref}}",
                 "{{exp (sub)}}",
                 "{{exp (sub 123)}}",
                 "{{exp []}}",
                 "{{exp {}}}",
                 "{{exp key=1}}",
                 "{{exp key=ref}}",
                 "{{exp key=(sub)}}",
                 "{{exp key=(sub 0)}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.helper_expression());
        assert!(rdp.end());
    }
}

#[test]
fn test_identifier_with_dash() {
    let s = vec!["{{exp-foo}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.expression());
        assert!(rdp.end());
    }
}

#[test]
fn test_html_expression() {
    let s = vec!["{{{html}}}", "{{{(html)}}}", "{{{(html)}}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.html_expression());
        assert!(rdp.end());
    }
}

#[test]
fn test_helper_start() {
    let s = vec!["{{#if hello}}",
                 "{{#if (hello)}}",
                 "{{#if hello=world}}",
                 "{{#if hello hello=world}}",
                 "{{#if []}}",
                 "{{#if {}}}",
                 "{{#if}}",
                 "{{~#if hello~}}",
                 "{{#each people as |person|}}",
                 "{{#each-obj obj as |key val|}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.helper_block_start());
        assert!(rdp.end());
    }
}

#[test]
fn test_helper_end() {
    let s = vec!["{{/if}}", "{{~/if}}", "{{~/if ~}}", "{{/if   ~}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.helper_block_end());
        assert!(rdp.end());
    }
}

#[test]
fn test_helper_block() {
    let s = vec!["{{#if hello}}hello{{/if}}",
                 "{{#if true}}hello{{/if}}",
                 "{{#if nice ok=1}}hello{{/if}}",
                 "{{#if}}hello{{else}}world{{/if}}",
                 "{{#if}}hello{{^}}world{{/if}}",
                 "{{#if}}{{#if}}hello{{/if}}{{/if}}",
                 "{{#if}}{{/if}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.helper_block());
        assert!(rdp.end());
    }
}

#[test]
fn test_raw_block() {
    let s = vec!["{{{{if hello}}}}good {{hello}}{{{{/if}}}}",
                 "{{{{if hello}}}}{{#if nice}}{{/if}}{{{{/if}}}}"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.raw_block());
        assert!(rdp.end());
    }
}

#[test]
fn test_block_params() {
    let s = vec!["as |person|", "as |key val|"];
    for i in s.iter() {
        let mut rdp = Rdp::new(StringInput::new(i));
        assert!(rdp.block_params());
        assert!(rdp.end());
    }
}
<|endoftext|>