<commit_before>#[macro_use]
extern crate lazy_static;

use std::ascii::AsciiExt;
use std::collections::HashMap;

// pub use pinyin_dict;
mod pinyin_dict;
mod phonetic_symbol;

lazy_static! {
    static ref PINYINMAP: HashMap<&'static str, &'static str> = {
        let m = pinyin_dict::init();
        m
    };
    static ref PHONETICSYMBOL: HashMap<&'static str, &'static str> = {
        let m = phonetic_symbol::init();
        m
    };
}

const NORMAL: u32       = 0; // 普通风格，不带声调（默认风格）。如： pin yin
const TONE: u32         = 1; // 声调风格1，拼音声调在韵母第一个字母上。如： pīn yīn
const TONE2: u32        = 2; // 声调风格2，即拼音声调在各个拼音之后，用数字 [0-4] 进行表示。如： pi1n yi1n
const INITIALS: u32     = 3; // 声母风格，只返回各个拼音的声母部分。如： 中国 的拼音 zh g
const FIRST_LETTER: u32 = 4; // 首字母风格，只返回拼音的首字母部分。如： p y
const FINALS: u32       = 5; // 韵母风格1，只返回各个拼音的韵母部分，不带声调。如： ong uo
const FINALS_TONE: u32  = 6; // 韵母风格2，带声调，声调在韵母第一个字母上。如： ōng uó
const FINALS_TONE2: u32 = 7; // 韵母风格2，带声调，声调在各个拼音之后，用数字 [0-4] 进行表示。如： o1ng uo2
enum Styles {
    NORMAL,
    TONE,
    TONE2,
    INITIALS,
    FIRST_LETTER,
    FINALS,
    FINALS_TONE,
    FINALS_TONE2,
}

// 声母表
const initials: [&'static str; 24] = [
    "zh", "ch", "sh", "b", "p", "m", "f", "d", "t", "n", "l", "g",
    "k", "h", "j", "q", "x", "r", "z", "c", "s", "yu", "y", "w",
];

// 所有带声调的字符
const rePhoneticSymbol: &'static str = (
    "āáǎàēéěèōóǒòīíǐìūúǔùüǘǚǜńň"
);

// // 匹配带声调字符的正则表达式
// var rePhoneticSymbol = regexp.MustCompile("[" + rePhoneticSymbolSource + "]")
//
// // 匹配使用数字标识声调的字符的正则表达式
// var reTone2 = regexp.MustCompile("([aeoiuvnm])([0-4])$")
//
// Args 配置信息
pub struct Args {
    style:     Styles,    // 拼音风格（默认： NORMAL)
    heteronym: bool,   // 是否启用多音字模式（默认：禁用）
    separator: String, // Slug 中使用的分隔符（默认：-)
}
//
// 默认配置：风格
const Style: Styles = Styles::NORMAL;

// 默认配置：是否启用多音字模式
const Heteronym: bool = false;

// 默认配置： `Slug` 中 Join 所用的分隔符
const Separator: &'static str = "-";

// NewArgs 返回包含默认配置的 `Args`
pub fn NewArgs() -> Args {
    return Args{
        style: Style,
        heteronym: Heteronym,
        separator: Separator.to_string(),
    }
}

// 获取单个拼音中的声母
fn initial(p: &str) -> String {
    let mut s = "".to_string();
    for v in initials.iter() {
        if p.starts_with(v) {
            s = v.to_string();
            break;
        }
    }
    s
}

// 获取单个拼音中的韵母
fn _final(p: &str) -> String {
    let i = initial(&p);
    if i == "" {
        return p.to_string();
    }
    // let s: Vec<&str> = p.splitn(2, i).collect();
    let s = p.splitn(2, i);
    // s.concat()
    s.to_string()
}

// func toFixed(p string, a Args) string {
//     if a.Style == Initials {
//         return initial(p)
//     }
//
//     // 替换拼音中的带声调字符
//     py := rePhoneticSymbol.ReplaceAllStringFunc(p, func(m string) string {
//         symbol, _ := phoneticSymbol[m]
//         switch a.Style {
//         // 不包含声调
//         case Normal, FirstLetter, Finals:
//             // 去掉声调: a1 -> a
//             m = reTone2.ReplaceAllString(symbol, "$1")
//         case Tone2, FinalsTone2:
//             // 返回使用数字标识声调的字符
//             m = symbol
//         default:
//             //  // 声调在头上
//         }
//         return m
//     })
//
//     switch a.Style {
//     // 首字母
//     case FirstLetter:
//         py = string([]byte(py)[0])
//     // 韵母
//     case Finals, FinalsTone, FinalsTone2:
//         py = final(py)
//     }
//     return py
// }
//
// func applyStyle(p []string, a Args) []string {
//     newP := []string{}
//     for _, v := range p {
//         newP = append(newP, toFixed(v, a))
//     }
//     return newP
// }
//
// // SinglePinyin 把单个 `rune` 类型的汉字转换为拼音.
// func SinglePinyin(r rune, a Args) []string {
//     value, ok := PinyinDict[int(r)]
//     pys := []string{}
//     if ok {
//         if len(value) < 1 || a.Heteronym {
//             pys = strings.Split(value, ",")
//         } else {
//             pys = strings.Split(value, ",")[:1]
//         }
//     }
//     return applyStyle(pys, a)
// }

// Pinyin 汉字转拼音，支持多音字模式.
pub fn pinyin(s: &str) -> Vec<&str> {
    let mut ret = vec![""];
    let v: Vec<char> = s.chars().collect();
    for n in v {
        let m1: String = n.escape_unicode().collect();
        // let m2: String = m1.trim_matches(' ').to_ascii_uppercase();
        // let m: &str = m2.trim_matches(' ');
        let m: &str = m1.trim_matches(' ');
        match PINYINMAP.get(m) {
            Some(&pys) => {
                ret = pys.split(',').collect();
            },
            None => {
            }
        }
    }
    return ret
}

// LazyPinyin 汉字转拼音，与 `Pinyin` 的区别是：
// 返回值类型不同，并且不支持多音字模式，每个汉字只取第一个音.
// func LazyPinyin(s string, a Args) []string {
//     a.Heteronym = false
//     pys := []string{}
//     for _, v := range Pinyin(s, a) {
//         pys = append(pys, v[0])
//     }
//     return pys
// }

// // Slug join `LazyPinyin` 的返回值.
// func Slug(s string, a Args) string {
//     separator := a.Separator
//     return strings.Join(LazyPinyin(s, a), separator)
// }

#[test]
fn it_works() {
    // assert_eq!(PINYINMAP.get(&0x36B0), Some(&"bǐ"));
}
<commit_msg>fix broke<commit_after>#[macro_use]
extern crate lazy_static;

use std::ascii::AsciiExt;
use std::collections::HashMap;

// pub use pinyin_dict;
mod pinyin_dict;
mod phonetic_symbol;

lazy_static! {
    static ref PINYINMAP: HashMap<&'static str, &'static str> = {
        let m = pinyin_dict::init();
        m
    };
    static ref PHONETICSYMBOL: HashMap<&'static str, &'static str> = {
        let m = phonetic_symbol::init();
        m
    };
}

enum Style {
    // 普通风格，不带声调（默认风格）。如： pin yin
    Normal,
    // 声调风格1，拼音声调在韵母第一个字母上。如： pīn yīn
    Tone,
    // 声调风格2，即拼音声调在各个拼音之后，用数字 [0-4] 进行表示。如： pi1n yi1n
    Tone2,
    // 声母风格，只返回各个拼音的声母部分。如： 中国 的拼音 zh g
    Initials,
    // 首字母风格，只返回拼音的首字母部分。如： p y
    FirstLetter,
    // 韵母风格1，只返回各个拼音的韵母部分，不带声调。如： ong uo
    Finals,
    // 韵母风格2，带声调，声调在韵母第一个字母上。如： ōng uó
    FinalsTone,
    // 韵母风格2，带声调，声调在各个拼音之后，用数字 [0-4] 进行表示。如： o1ng uo2
    FinalsTone2,
}

// 声母表
const initials: [&'static str; 24] = [
    "zh", "ch", "sh", "b", "p", "m", "f", "d", "t", "n", "l", "g",
    "k", "h", "j", "q", "x", "r", "z", "c", "s", "yu", "y", "w",
];

// 所有带声调的字符
const rePhoneticSymbol: &'static str = (
    "āáǎàēéěèōóǒòīíǐìūúǔùüǘǚǜńň"
);

// // 匹配带声调字符的正则表达式
// var rePhoneticSymbol = regexp.MustCompile("[" + rePhoneticSymbolSource + "]")
//
// // 匹配使用数字标识声调的字符的正则表达式
// var reTone2 = regexp.MustCompile("([aeoiuvnm])([0-4])$")
//
// Args 配置信息
pub struct Args {
    style:     Style,    // 拼音风格（默认： NORMAL)
    heteronym: bool,   // 是否启用多音字模式（默认：禁用）
    separator: String, // Slug 中使用的分隔符（默认：-)
}

impl Args {
    fn New() -> Args {
        Args{
            style: Style::Normal,
            heteronym: false,
            separator: "-".to_string(),
        }
    }
}

// 获取单个拼音中的声母
fn initial(p: &str) -> &str {
    let mut s = "";
    for v in initials.iter() {
        if p.starts_with(v) {
            s = v;
            break;
        }
    }
    s
}

// 获取单个拼音中的韵母
fn _final(p: &str) -> String {
    let i = initial(p);
    if i == "" {
        return p.to_string();
    }
    let s: Vec<&str> = p.splitn(2, i).collect();
    s.concat()
}

// func toFixed(p string, a Args) string {
//     if a.Style == Initials {
//         return initial(p)
//     }
//
//     // 替换拼音中的带声调字符
//     py := rePhoneticSymbol.ReplaceAllStringFunc(p, func(m string) string {
//         symbol, _ := phoneticSymbol[m]
//         switch a.Style {
//         // 不包含声调
//         case Normal, FirstLetter, Finals:
//             // 去掉声调: a1 -> a
//             m = reTone2.ReplaceAllString(symbol, "$1")
//         case Tone2, FinalsTone2:
//             // 返回使用数字标识声调的字符
//             m = symbol
//         default:
//             //  // 声调在头上
//         }
//         return m
//     })
//
//     switch a.Style {
//     // 首字母
//     case FirstLetter:
//         py = string([]byte(py)[0])
//     // 韵母
//     case Finals, FinalsTone, FinalsTone2:
//         py = final(py)
//     }
//     return py
// }
//
// func applyStyle(p []string, a Args) []string {
//     newP := []string{}
//     for _, v := range p {
//         newP = append(newP, toFixed(v, a))
//     }
//     return newP
// }
//
// // SinglePinyin 把单个 `rune` 类型的汉字转换为拼音.
// func SinglePinyin(r rune, a Args) []string {
//     value, ok := PinyinDict[int(r)]
//     pys := []string{}
//     if ok {
//         if len(value) < 1 || a.Heteronym {
//             pys = strings.Split(value, ",")
//         } else {
//             pys = strings.Split(value, ",")[:1]
//         }
//     }
//     return applyStyle(pys, a)
// }

// Pinyin 汉字转拼音，支持多音字模式.
pub fn pinyin(s: &str) -> Vec<&str> {
    let mut ret = vec![""];
    let v: Vec<char> = s.chars().collect();
    for n in v {
        let m1: String = n.escape_unicode().collect();
        // let m2: String = m1.trim_matches(' ').to_ascii_uppercase();
        // let m: &str = m2.trim_matches(' ');
        let m: &str = m1.trim_matches(' ');
        match PINYINMAP.get(m) {
            Some(&pys) => {
                ret = pys.split(',').collect();
            },
            None => {
            }
        }
    }
    return ret
}
<|endoftext|>


<commit_before>//! The export module for Tdo server.
#![deny(missing_docs, unsafe_code,
        missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unused_import_braces, unused_qualifications)]
#![warn(missing_debug_implementations)]
extern crate tdo_core;
extern crate libc;
extern crate colored;

use std::{slice, io, ptr};
use colored::*;
use libc::{ioctl, c_ushort, STDOUT_FILENO, TIOCGWINSZ};

#[repr(C)]
struct winsize {
    ws_row: c_ushort, /* rows, in characters */
    ws_col: c_ushort, /* columns, in characters */
    ws_xpixel: c_ushort, /* horizontal size, pixels */
    ws_ypixel: c_ushort, /* vertical size, pixels */
}

/// Generates a well formated String of all undone Todos
pub fn gen_tasks_mail(tdo: &tdo_core::tdo::Tdo) -> Option<String> {
    let mut listed = String::new();
    for list in tdo.to_owned().lists.into_iter() {
        let undone = list.list_undone();
        if undone.len() > 0 {
            listed.push_str("\n------------------------------------------------------------\n\t");
            listed.push_str(&list.name);
            listed.push_str("\n------------------------------------------------------------\n");
            for entry in undone {
                if entry.done {
                    listed.push_str(&format!("- {:?}\n", entry.name));
                }
            }
            listed.push_str("\n\n");
        }
    }
    match listed.len() {
        0 => None,
        _ => Some(listed),
    }
}

/// Generates a markdown String to export the lists.
pub fn gen_tasks_md(tdo: &tdo_core::tdo::Tdo, list_done: bool) -> Option<String> {
    let mut markdown = String::from("# Your tasks\n\n");
    let name = get_full_name();
    if name.is_ok() {
        markdown.push_str(&format!("Here are the tasks for {}\n\n", &name.unwrap()));
    }
    let mut intern = String::new();
    for list in tdo.to_owned().lists.iter() {
        let tasks: Vec<tdo_core::todo::Todo>;
        if list_done {
            tasks = list.list.to_owned();
        } else {
            tasks = list.list_undone();
        }
        if tasks.len() > 0 {
            intern.push_str(&format!("\n### {}\n", &list.name));
            for entry in tasks {
                if entry.done {
                    intern.push_str(&format!("- [x] {}\n", &entry.name));
                } else {
                    intern.push_str(&format!("- [ ] {}\n", &entry.name));
                }
            }
        } else if list_done {
            intern.push_str(&format!("\n### {}\n", &list.name));
        }
    }
    match intern.len() {
        0 => None,
        _ => {
            markdown.push_str(&intern);
            Some(markdown)
        }
    }
}

/// Returns the formated output for the terminal printout.
#[allow(unused_variables, unused_mut)] //for now
pub fn render_terminal_output(tdo: &tdo_core::tdo::Tdo, all: bool) -> Option<Vec<String>> {
    let (col, _): (usize, _) = match get_winsize() {
        Ok(res) => res,
        Err(_) => {
            println!("{} Terminalsize could not be fetched.", "error:".red().bold());
            std::process::exit(1);
        }
    };
    let id_space = tdo.get_highest_id().to_string().len();
    let mut formated_printout: Vec<String> = Vec::new();
    for list in tdo.lists.to_owned().iter() {
        let tasks: Vec<tdo_core::todo::Todo>;
        if all {
            tasks = list.list.to_owned();
        } else {
            tasks = list.list_undone();
        }
        if tasks.len() > 0 {
            formated_printout.push(format!("## {}", &list.name));
            for entry in tasks {
                let space = id_space - entry.id.to_string().len();
                let mut task_vec: Vec<String> = Vec::new();
                let mut entr_str = entry.name;
                let mut tmp_str: String;
                while entr_str.len() > col - 9 - id_space {
                    tmp_str = entr_str.split_off(col - 9 - id_space);
                    task_vec.push(entr_str);
                    entr_str = tmp_str;
                }
                task_vec.push(entr_str);
                if entry.done {
                    formated_printout.push(format!("  [x] {}{} | {}",
                                                   " ".repeat(space),
                                                   entry.id,
                                                   task_vec.remove(0)));
                } else {
                    formated_printout.push(format!("  [ ] {}{} | {}",
                                                   " ".repeat(space),
                                                   entry.id,
                                                   task_vec.remove(0)));
                }
                if task_vec.capacity() > 0 {
                    for part in task_vec {
                        formated_printout.push(format!("{}| {}",
                                                       " ".repeat(7+id_space),
                                                       part));
                    }
                }
            }
            formated_printout.push(String::new());
        } else if all {
            formated_printout.push(format!("## {}", &list.name));
            formated_printout.push(String::new());
        }
    }
    match formated_printout.len() {
        0 => None,
        _ => Some(formated_printout),
    }
}

#[allow(unsafe_code)]
fn get_full_name() -> Result<String, io::Error> {
    unsafe {
        let uid = libc::geteuid();
        let user = ptr::read(libc::getpwuid(uid));
        let name = String::from_utf8_unchecked(slice::from_raw_parts(user.pw_gecos as *const u8,
                                                                     libc::strlen(user.pw_gecos))
            .to_vec());
        if name == "" {
            Err(io::Error::last_os_error())
        } else {
            let results: Vec<&str> = name.split(",").collect();
            Ok(results[0].to_string())
        }
    }
}

#[allow(unsafe_code)]
fn get_winsize() -> io::Result<(usize, usize)> {
    let w = winsize {
        ws_row: 0,
        ws_col: 0,
        ws_xpixel: 0,
        ws_ypixel: 0,
    };
    let r = unsafe { ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) };

    match r {
        0 => Ok((w.ws_col as usize, w.ws_row as usize)),
        _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "No valid data.")),
    }
}
<commit_msg>check if Fullname is empty<commit_after>//! The export module for Tdo server.
#![deny(missing_docs, unsafe_code,
        missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unused_import_braces, unused_qualifications)]
#![warn(missing_debug_implementations)]
extern crate tdo_core;
extern crate libc;
extern crate colored;

use std::{slice, io, ptr};
use colored::*;
use libc::{ioctl, c_ushort, STDOUT_FILENO, TIOCGWINSZ};

#[repr(C)]
struct winsize {
    ws_row: c_ushort, /* rows, in characters */
    ws_col: c_ushort, /* columns, in characters */
    ws_xpixel: c_ushort, /* horizontal size, pixels */
    ws_ypixel: c_ushort, /* vertical size, pixels */
}

/// Generates a well formated String of all undone Todos
pub fn gen_tasks_mail(tdo: &tdo_core::tdo::Tdo) -> Option<String> {
    let mut listed = String::new();
    for list in tdo.to_owned().lists.into_iter() {
        let undone = list.list_undone();
        if undone.len() > 0 {
            listed.push_str("\n------------------------------------------------------------\n\t");
            listed.push_str(&list.name);
            listed.push_str("\n------------------------------------------------------------\n");
            for entry in undone {
                if entry.done {
                    listed.push_str(&format!("- {:?}\n", entry.name));
                }
            }
            listed.push_str("\n\n");
        }
    }
    match listed.len() {
        0 => None,
        _ => Some(listed),
    }
}

/// Generates a markdown String to export the lists.
pub fn gen_tasks_md(tdo: &tdo_core::tdo::Tdo, list_done: bool) -> Option<String> {
    let mut markdown = String::from("# Your tasks\n\n");
    let name = get_full_name();
    if name.is_ok() {
        markdown.push_str(&format!("Here are the tasks for {}\n\n", &name.unwrap()));
    }
    let mut intern = String::new();
    for list in tdo.to_owned().lists.iter() {
        let tasks: Vec<tdo_core::todo::Todo>;
        if list_done {
            tasks = list.list.to_owned();
        } else {
            tasks = list.list_undone();
        }
        if tasks.len() > 0 {
            intern.push_str(&format!("\n### {}\n", &list.name));
            for entry in tasks {
                if entry.done {
                    intern.push_str(&format!("- [x] {}\n", &entry.name));
                } else {
                    intern.push_str(&format!("- [ ] {}\n", &entry.name));
                }
            }
        } else if list_done {
            intern.push_str(&format!("\n### {}\n", &list.name));
        }
    }
    match intern.len() {
        0 => None,
        _ => {
            markdown.push_str(&intern);
            Some(markdown)
        }
    }
}

/// Returns the formated output for the terminal printout.
#[allow(unused_variables, unused_mut)] //for now
pub fn render_terminal_output(tdo: &tdo_core::tdo::Tdo, all: bool) -> Option<Vec<String>> {
    let (col, _): (usize, _) = match get_winsize() {
        Ok(res) => res,
        Err(_) => {
            println!("{} Terminalsize could not be fetched.", "error:".red().bold());
            std::process::exit(1);
        }
    };
    let id_space = tdo.get_highest_id().to_string().len();
    let mut formated_printout: Vec<String> = Vec::new();
    for list in tdo.lists.to_owned().iter() {
        let tasks: Vec<tdo_core::todo::Todo>;
        if all {
            tasks = list.list.to_owned();
        } else {
            tasks = list.list_undone();
        }
        if tasks.len() > 0 {
            formated_printout.push(format!("## {}", &list.name));
            for entry in tasks {
                let space = id_space - entry.id.to_string().len();
                let mut task_vec: Vec<String> = Vec::new();
                let mut entr_str = entry.name;
                let mut tmp_str: String;
                while entr_str.len() > col - 9 - id_space {
                    tmp_str = entr_str.split_off(col - 9 - id_space);
                    task_vec.push(entr_str);
                    entr_str = tmp_str;
                }
                task_vec.push(entr_str);
                if entry.done {
                    formated_printout.push(format!("  [x] {}{} | {}",
                                                   " ".repeat(space),
                                                   entry.id,
                                                   task_vec.remove(0)));
                } else {
                    formated_printout.push(format!("  [ ] {}{} | {}",
                                                   " ".repeat(space),
                                                   entry.id,
                                                   task_vec.remove(0)));
                }
                if task_vec.capacity() > 0 {
                    for part in task_vec {
                        formated_printout.push(format!("{}| {}",
                                                       " ".repeat(7+id_space),
                                                       part));
                    }
                }
            }
            formated_printout.push(String::new());
        } else if all {
            formated_printout.push(format!("## {}", &list.name));
            formated_printout.push(String::new());
        }
    }
    match formated_printout.len() {
        0 => None,
        _ => Some(formated_printout),
    }
}

#[allow(unsafe_code)]
fn get_full_name() -> Result<String, io::Error> {
    unsafe {
        let uid = libc::geteuid();
        let user = ptr::read(libc::getpwuid(uid));
        let res = String::from_utf8_unchecked(slice::from_raw_parts(user.pw_gecos as *const u8,
                                                                     libc::strlen(user.pw_gecos))
            .to_vec());
        let results: Vec<&str> = res.split(",").collect();
        let name = results[0].to_string();
        if name == "" {
            Err(io::Error::last_os_error())
        } else {

            Ok(name)
        }
    }
}

#[allow(unsafe_code)]
fn get_winsize() -> io::Result<(usize, usize)> {
    let w = winsize {
        ws_row: 0,
        ws_col: 0,
        ws_xpixel: 0,
        ws_ypixel: 0,
    };
    let r = unsafe { ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) };

    match r {
        0 => Ok((w.ws_col as usize, w.ws_row as usize)),
        _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "No valid data.")),
    }
}
<|endoftext|>


<commit_before>//! Rust bindings for [libpcuid](https://github.com/anrieff/libcpuid)
//! CPU detection and feature extraction library.
//!
//! `rust-cpuid` provides a high-level interface for getting information
//! about the features of the CPU that runs your code. All the essential
//! work is done by the `libcpuid` C library and exposed through Rust's
//! FFI mechanism as a simple and convenient API.
//!
//! # Available features
//!
//! * CPU vendor, brand and codename detection
//! * information about number of cores (both physical and logical)
//! * cache size
//! * clock frequency
//!
//! # Installation
//!
//! First - download, and build libcpuid as [described in the readme](https://github.com/anrieff/libcpuid). Install it by running `make install` (you may want to run `ldconfig` afterwards).
//!
//! Add to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies.cpuid]
//! git = "https://github.com/zsiciarz/rust-cpuid.git"
//! ```
//!
//! # Example
//!
//! ```rust
//! extern crate cpuid;
//!
//! fn main () {
//!     match cpuid::identify() {
//!         Ok(info) => {
//!             println!("Found: {} CPU, model: {}", info.vendor, info.codename);
//!             println!("The full brand string is: {}", info.brand);
//!         },
//!         Err(err) => println!("cpuid error: {}", err),
//!     };
//!     match cpuid::clock_frequency() {
//!         Some(frequency) => println!("CPU speed: {} MHz", frequency),
//!         None => println!("Couldn't get CPU speed."),
//!     };
//! }
//! ```

extern crate libc;

use std::c_str::CString;
use std::default::Default;

mod ffi;

/// A struct holding information about CPU features.
///
/// This data structure is returned by identify(). You can consult
/// [libcpuid docs for cpu_id_t](http://libcpuid.sourceforge.net/doxy/structcpu__id__t.html)
/// for more detailed descriptions of these fields.
#[deriving(Show)]
pub struct CpuInfo {
    /// CPU vendor string, for example "GenuineIntel".
    pub vendor: String,
    /// Brand string, for example "Intel(R) Core(TM) i5-2410M CPU @ 2.30GHz".
    pub brand: String,
    /// Brief CPU codename, such as "Sandy Bridge (Core i5)".
    pub codename: String,
    /// Number of physical cores of the current CPU.
    pub num_cores: int,
    /// Number of logical processors (may include HyperThreading or such).
    pub num_logical_cpus: int,
    /// Total number of logical processors.
    pub total_logical_cpus: int,
    /// L1 data cache size in kB. Some(0) if the CPU lacks cache, None if it couldn't be determined.
    pub l1_data_cache: Option<int>,
    /// L1 instruction cache size in kB. Some(0) if the CPU lacks cache, None if it couldn't be determined.
    pub l1_instruction_cache: Option<int>,
    /// L2 cache size in kB. Some(0) if the CPU lacks L2 cache, None if it couldn't be determined.
    pub l2_cache: Option<int>,
    /// L3 cache size in kB. Some(0) if the CPU lacks L3 cache, None if it couldn't be determined.
    pub l3_cache: Option<int>,
}

pub fn is_present() -> bool {
    unsafe {
        ffi::cpuid_present() == 1
    }
}

pub fn version() -> String {
    let version_string = unsafe {
        let ptr = ffi::cpuid_lib_version();
        CString::new(ptr, false)
    };
    version_string.as_str().unwrap().to_string()
}

pub fn error() -> String {
    let error_string = unsafe {
        let ptr = ffi::cpuid_error();
        CString::new(ptr, false)
    };
    error_string.as_str().unwrap().to_string()
}

pub fn identify() -> Result<CpuInfo, String> {
    let mut raw: ffi::cpu_raw_data_t = Default::default();
    let raw_result = unsafe {
        ffi::cpuid_get_raw_data(&mut raw)
    };
    if raw_result != 0 {
        return Err(error());
    }
    let mut data: ffi::cpu_id_t = Default::default();
    let identify_result = unsafe {
        ffi::cpu_identify(&mut raw, &mut data)
    };
    if identify_result != 0 {
        Err(error())
    } else {
        Ok(CpuInfo {
            vendor: String::from_utf8(data.vendor_str.iter().map(|&x| x as u8).collect()).ok().expect("Invalid vendor string"),
            brand: String::from_utf8(data.brand_str.iter().map(|&x| x as u8).collect()).ok().expect("Invalid brand string"),
            codename: String::from_utf8(data.cpu_codename.iter().map(|&x| x as u8).collect()).ok().expect("Invalid codename string"),
            num_cores: data.num_cores as int,
            num_logical_cpus: data.num_logical_cpus as int,
            total_logical_cpus: data.total_logical_cpus as int,
            l1_data_cache: if data.l1_data_cache != -1 { Some(data.l1_data_cache as int) } else { None },
            l1_instruction_cache: if data.l1_instruction_cache != -1 { Some(data.l1_instruction_cache as int) } else { None },
            l2_cache: if data.l2_cache != -1 { Some(data.l2_cache as int) } else { None },
            l3_cache: if data.l3_cache != -1 { Some(data.l3_cache as int) } else { None },
        })
    }
}

pub fn clock_frequency() -> Option<int> {
    let frequency = unsafe {
        ffi::cpu_clock()
    };
    if frequency != -1 {
        Some(frequency as int)
    } else {
        None
    }
}

#[test]
fn test_is_present() {
    assert!(is_present());
}
<commit_msg>Basic docs for all functions.<commit_after>//! Rust bindings for [libpcuid](https://github.com/anrieff/libcpuid)
//! CPU detection and feature extraction library.
//!
//! `rust-cpuid` provides a high-level interface for getting information
//! about the features of the CPU that runs your code. All the essential
//! work is done by the `libcpuid` C library and exposed through Rust's
//! FFI mechanism as a simple and convenient API.
//!
//! # Available features
//!
//! * CPU vendor, brand and codename detection
//! * information about number of cores (both physical and logical)
//! * cache size
//! * clock frequency
//!
//! # Installation
//!
//! First - download, and build libcpuid as [described in the readme](https://github.com/anrieff/libcpuid). Install it by running `make install` (you may want to run `ldconfig` afterwards).
//!
//! Add to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies.cpuid]
//! git = "https://github.com/zsiciarz/rust-cpuid.git"
//! ```
//!
//! # Example
//!
//! ```rust
//! extern crate cpuid;
//!
//! fn main () {
//!     match cpuid::identify() {
//!         Ok(info) => {
//!             println!("Found: {} CPU, model: {}", info.vendor, info.codename);
//!             println!("The full brand string is: {}", info.brand);
//!         },
//!         Err(err) => println!("cpuid error: {}", err),
//!     };
//!     match cpuid::clock_frequency() {
//!         Some(frequency) => println!("CPU speed: {} MHz", frequency),
//!         None => println!("Couldn't get CPU speed."),
//!     };
//! }
//! ```

extern crate libc;

use std::c_str::CString;
use std::default::Default;

mod ffi;

/// A struct holding information about CPU features.
///
/// This data structure is returned by `identify()`. You can consult
/// [libcpuid docs for cpu_id_t](http://libcpuid.sourceforge.net/doxy/structcpu__id__t.html)
/// for more detailed descriptions of these fields.
#[deriving(Show)]
pub struct CpuInfo {
    /// CPU vendor string, for example *GenuineIntel*.
    pub vendor: String,
    /// Brand string, for example *Intel(R) Core(TM) i5-2410M CPU @ 2.30GHz*.
    pub brand: String,
    /// Brief CPU codename, such as *Sandy Bridge (Core i5)*.
    pub codename: String,
    /// Number of physical cores of the current CPU.
    pub num_cores: int,
    /// Number of logical processors (may include HyperThreading or such).
    pub num_logical_cpus: int,
    /// Total number of logical processors.
    pub total_logical_cpus: int,
    /// L1 data cache size in kB. `Some(0)` if the CPU lacks cache, `None` if it couldn't be determined.
    pub l1_data_cache: Option<int>,
    /// L1 instruction cache size in kB. `Some(0)` if the CPU lacks cache, `None` if it couldn't be determined.
    pub l1_instruction_cache: Option<int>,
    /// L2 cache size in kB. `Some(0)` if the CPU lacks L2 cache, `None` if it couldn't be determined.
    pub l2_cache: Option<int>,
    /// L3 cache size in kB. `Some(0)` if the CPU lacks L3 cache, `None` if it couldn't be determined.
    pub l3_cache: Option<int>,
}

/// Checks if the CPUID instruction is present.
pub fn is_present() -> bool {
    unsafe {
        ffi::cpuid_present() == 1
    }
}

/// Returns libcpuid version string.
pub fn version() -> String {
    let version_string = unsafe {
        let ptr = ffi::cpuid_lib_version();
        CString::new(ptr, false)
    };
    version_string.as_str().unwrap().to_string()
}

/// Returns last libcpuid error string.
pub fn error() -> String {
    let error_string = unsafe {
        let ptr = ffi::cpuid_error();
        CString::new(ptr, false)
    };
    error_string.as_str().unwrap().to_string()
}

/// Tries to identify the current CPU and its features.
///
/// In case of successful detection, a `CpuInfo` struct is returned (wrapped
/// with `Ok`) which contains all available data about the processor.
/// If libcpuid encounters an error, `identify` returns an `Err` with
/// the error message inside.
pub fn identify() -> Result<CpuInfo, String> {
    let mut raw: ffi::cpu_raw_data_t = Default::default();
    let raw_result = unsafe {
        ffi::cpuid_get_raw_data(&mut raw)
    };
    if raw_result != 0 {
        return Err(error());
    }
    let mut data: ffi::cpu_id_t = Default::default();
    let identify_result = unsafe {
        ffi::cpu_identify(&mut raw, &mut data)
    };
    if identify_result != 0 {
        Err(error())
    } else {
        Ok(CpuInfo {
            vendor: String::from_utf8(data.vendor_str.iter().map(|&x| x as u8).collect()).ok().expect("Invalid vendor string"),
            brand: String::from_utf8(data.brand_str.iter().map(|&x| x as u8).collect()).ok().expect("Invalid brand string"),
            codename: String::from_utf8(data.cpu_codename.iter().map(|&x| x as u8).collect()).ok().expect("Invalid codename string"),
            num_cores: data.num_cores as int,
            num_logical_cpus: data.num_logical_cpus as int,
            total_logical_cpus: data.total_logical_cpus as int,
            l1_data_cache: if data.l1_data_cache != -1 { Some(data.l1_data_cache as int) } else { None },
            l1_instruction_cache: if data.l1_instruction_cache != -1 { Some(data.l1_instruction_cache as int) } else { None },
            l2_cache: if data.l2_cache != -1 { Some(data.l2_cache as int) } else { None },
            l3_cache: if data.l3_cache != -1 { Some(data.l3_cache as int) } else { None },
        })
    }
}

/// Gets the CPU clock frequency in MHz.
///
/// The underlying implementation uses several methods to discover CPU
/// speed, including direct measurement. If all these methods fail, function
/// returns `None`.
pub fn clock_frequency() -> Option<int> {
    let frequency = unsafe {
        ffi::cpu_clock()
    };
    if frequency != -1 {
        Some(frequency as int)
    } else {
        None
    }
}

#[test]
fn test_is_present() {
    assert!(is_present());
}
<|endoftext|>


<commit_before>//! [(Link to repository page.)](https://github.com/C4K3/Ozelot)
//!
//! This is a library made for interacting with the Minecraft protocl
//! (MCMODERN only, not MCPE.)
//!
//! It is mostly a low-level library, its goals are to
//! handle everything network related, but nothing beyond that. For example
//! this library does not support any types beyond ones found in standard Rust,
//! this results in certain packets that contain compound datatypes not having
//! their complex fields serialized by this library, but instead handing the
//! raw binary data to consumers of this library to parse however they wish.
//! One example of this is packets that contain NBT data, the packets are read
//! but the NBT data is not in any way parsed by this library. You'll probably
//! want to see what the meanings of each of the packets are, which is
//! documented on [wiki.vg](http://wiki.vg/Main_Page). The [protocol
//! documentation](http://wiki.vg/Protocol) in particular is likely to be a
//! necessary companion to using this library.
//!
//! Currently the library is entirely synchronous, requiring consumers to handle
//! concurrency however they wish. It would be cool to add an asynchronous API
//! though, maybe using mio.
//!
//! The library nominally supports every packet used in MCMODERN, but the goal
//! is still to add lots more helper functions and other useful things. There
//! are still many errors and inconvenient things in the library, where changes
//! or helper functions would be good to add. If you find any errors or
//! suggestions for improvement, no matter how trivial, then post it on the
//! bugtracker.
//!
//! The library does not yet have any stable releases, not because it may
//! contain bugs (which it certainly does,) but because the API may be
//! significantly restructured without warning.
//!
//! # Examples
//!
//! Connecting to a remote server as an authenticated user, printing all chat
//! messages, and then echoing back messages that appear not to be written by us
//! (else we'd get into an infinite loop echoing our own messages.)
//!
//! (See the *textclient* example for a comprehensive version.)
//!
//! ```rust,no_run
//! use std::thread;
//! use std::time::Duration;
//! use ozelot::{mojang, Client, serverbound, utils};
//! use ozelot::clientbound::ClientboundPacket;
//!
//! let auth = mojang::Authenticate::new("my_email@example.com".to_string(),
//!                                      "my_password".to_string())
//!     .perform().unwrap();
//!
//!
//! /* By using connect_authenticated, auto_handle will be true and thus ozelot
//!  * will respond to keepalives automatically */
//! let mut client = Client::connect_authenticated("minecraft.example.com",
//!                                                25565, &auth).unwrap();
//!
//! let username = auth.selectedProfile.name;
//!
//! 'main: loop {
//!     let packets = client.read().unwrap();
//!     for packet in packets {
//!         match packet {
//!         ClientboundPacket::PlayDisconnect(ref p) => {
//!             println!("Disconnected, reason: {}",
//!                      utils::chat_to_str(p.get_reason()).unwrap());
//!             break 'main;
//!         },
//!         ClientboundPacket::ChatMessage(ref p) => {
//!             let msg = utils::chat_to_str(p.get_chat()).unwrap();
//!             println!("{}", msg);
//!             if !msg.contains(&username) {
//!                 /* Since we don't want an infinite loop, we don't echo back
//!                  * our own messages. We say that a received message wasn't
//!                  * written by us if it doesn't contain our username
//!                  *
//!                  * Note that this echoes back the raw chat message, that is
//!                  * playername and everything, and also non-chat messages. */
//!                 let response = serverbound::ChatMessage::new(msg);
//!                 let _: usize = client.send(response).unwrap();
//!             }
//!         },
//!         /* We throw away all other packets */
//!         _ => (),
//!         }
//!     }
//!     /* Make sure we don't consume the entire CPU trying to check if new packets have arrived */
//!     thread::sleep(Duration::from_millis(50));
//! }
//! ```
extern crate byteorder;
extern crate curl;
extern crate flate2;
extern crate netbuf;
extern crate openssl;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate serde_json;
#[macro_use]
extern crate error_chain;

mod client;
mod connection;
#[allow(non_snake_case)]
mod json;
mod server;
pub mod clientbound;
pub mod errors;
#[allow(non_snake_case)]
pub mod mojang;
pub mod read;
pub mod serverbound;
pub mod utils;
pub mod write;
#[cfg(test)]
mod tests;

pub use client::Client;
pub use server::Server;
pub use connection::Packet;

use std::fmt;

/// The protocol version supported by this version of ozelot
pub const PROTOCOL_VERSION: i32 = 340;

/// FIXME temporary struct until u128 lands in stable rust, used for uuids
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[allow(non_camel_case_types)]
pub struct u128(pub u64, pub u64);

/// This tracks which state of play the client is in. The value of this changes
/// the meaning of the different packet ids.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ClientState {
    Handshake,
    Status,
    Login,
    Play,
}
impl fmt::Display for ClientState {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match self {
            &ClientState::Handshake => "Handshake",
            &ClientState::Status => "Status",
            &ClientState::Login => "Login",
            &ClientState::Play => "Play",
        })
    }
}
<commit_msg>docs: Fix 1 typo<commit_after>//! [(Link to repository page.)](https://github.com/C4K3/Ozelot)
//!
//! This is a library made for interacting with the Minecraft protocol
//! (MCMODERN only, not MCPE.)
//!
//! It is mostly a low-level library, its goals are to
//! handle everything network related, but nothing beyond that. For example
//! this library does not support any types beyond ones found in standard Rust,
//! this results in certain packets that contain compound datatypes not having
//! their complex fields serialized by this library, but instead handing the
//! raw binary data to consumers of this library to parse however they wish.
//! One example of this is packets that contain NBT data, the packets are read
//! but the NBT data is not in any way parsed by this library. You'll probably
//! want to see what the meanings of each of the packets are, which is
//! documented on [wiki.vg](http://wiki.vg/Main_Page). The [protocol
//! documentation](http://wiki.vg/Protocol) in particular is likely to be a
//! necessary companion to using this library.
//!
//! Currently the library is entirely synchronous, requiring consumers to handle
//! concurrency however they wish. It would be cool to add an asynchronous API
//! though, maybe using mio.
//!
//! The library nominally supports every packet used in MCMODERN, but the goal
//! is still to add lots more helper functions and other useful things. There
//! are still many errors and inconvenient things in the library, where changes
//! or helper functions would be good to add. If you find any errors or
//! suggestions for improvement, no matter how trivial, then post it on the
//! bugtracker.
//!
//! The library does not yet have any stable releases, not because it may
//! contain bugs (which it certainly does,) but because the API may be
//! significantly restructured without warning.
//!
//! # Examples
//!
//! Connecting to a remote server as an authenticated user, printing all chat
//! messages, and then echoing back messages that appear not to be written by us
//! (else we'd get into an infinite loop echoing our own messages.)
//!
//! (See the *textclient* example for a comprehensive version.)
//!
//! ```rust,no_run
//! use std::thread;
//! use std::time::Duration;
//! use ozelot::{mojang, Client, serverbound, utils};
//! use ozelot::clientbound::ClientboundPacket;
//!
//! let auth = mojang::Authenticate::new("my_email@example.com".to_string(),
//!                                      "my_password".to_string())
//!     .perform().unwrap();
//!
//!
//! /* By using connect_authenticated, auto_handle will be true and thus ozelot
//!  * will respond to keepalives automatically */
//! let mut client = Client::connect_authenticated("minecraft.example.com",
//!                                                25565, &auth).unwrap();
//!
//! let username = auth.selectedProfile.name;
//!
//! 'main: loop {
//!     let packets = client.read().unwrap();
//!     for packet in packets {
//!         match packet {
//!         ClientboundPacket::PlayDisconnect(ref p) => {
//!             println!("Disconnected, reason: {}",
//!                      utils::chat_to_str(p.get_reason()).unwrap());
//!             break 'main;
//!         },
//!         ClientboundPacket::ChatMessage(ref p) => {
//!             let msg = utils::chat_to_str(p.get_chat()).unwrap();
//!             println!("{}", msg);
//!             if !msg.contains(&username) {
//!                 /* Since we don't want an infinite loop, we don't echo back
//!                  * our own messages. We say that a received message wasn't
//!                  * written by us if it doesn't contain our username
//!                  *
//!                  * Note that this echoes back the raw chat message, that is
//!                  * playername and everything, and also non-chat messages. */
//!                 let response = serverbound::ChatMessage::new(msg);
//!                 let _: usize = client.send(response).unwrap();
//!             }
//!         },
//!         /* We throw away all other packets */
//!         _ => (),
//!         }
//!     }
//!     /* Make sure we don't consume the entire CPU trying to check if new packets have arrived */
//!     thread::sleep(Duration::from_millis(50));
//! }
//! ```
extern crate byteorder;
extern crate curl;
extern crate flate2;
extern crate netbuf;
extern crate openssl;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate serde_json;
#[macro_use]
extern crate error_chain;

mod client;
mod connection;
#[allow(non_snake_case)]
mod json;
mod server;
pub mod clientbound;
pub mod errors;
#[allow(non_snake_case)]
pub mod mojang;
pub mod read;
pub mod serverbound;
pub mod utils;
pub mod write;
#[cfg(test)]
mod tests;

pub use client::Client;
pub use server::Server;
pub use connection::Packet;

use std::fmt;

/// The protocol version supported by this version of ozelot
pub const PROTOCOL_VERSION: i32 = 340;

/// FIXME temporary struct until u128 lands in stable rust, used for uuids
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[allow(non_camel_case_types)]
pub struct u128(pub u64, pub u64);

/// This tracks which state of play the client is in. The value of this changes
/// the meaning of the different packet ids.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ClientState {
    Handshake,
    Status,
    Login,
    Play,
}
impl fmt::Display for ClientState {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match self {
            &ClientState::Handshake => "Handshake",
            &ClientState::Status => "Status",
            &ClientState::Login => "Login",
            &ClientState::Play => "Play",
        })
    }
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate memchr;
extern crate aho_corasick;
extern crate rand;
extern crate regex_syntax;
extern crate regex;

use std::fs::{File, read_dir, remove_file};
use std::io::{Read, Write};
use std::path::Path;
use std::process::Command;
use rand::{Rng, thread_rng};
use regex::Regex;
use util::*;

static PROGNAME: &'static str = "./split";

#[path = "common/util.rs"]
#[macro_use]
mod util;

fn random_chars(n: usize) -> String {
    thread_rng().gen_ascii_chars().take(n).collect::<String>()
}

struct Glob {
    directory: String,
    regex: Regex
}

impl Glob {
    fn new(directory: &str, regex: &str) -> Glob {
        Glob {
            directory: directory.to_string(),
            regex: Regex::new(regex).unwrap()
        }
    }

    fn count(&self) -> usize {
        self.collect().len()
    }

    fn collect(&self) -> Vec<String> {
        read_dir(Path::new(&self.directory)).unwrap().filter_map(|entry| {
            let path = entry.unwrap().path();
            let name = path.as_path().to_str().unwrap_or("");
            if self.regex.is_match(name) { Some(name.to_string()) } else { None }
        }).collect()
    }

    fn collate(&self) -> Vec<u8> {
        let mut files = self.collect();
        files.sort();
        let mut data: Vec<u8> = vec!();
        for name in files.iter() {
            data.extend(get_file_contents(name).into_bytes());
        }
        data
    }

    fn remove_all(&self) {
        for name in self.collect().iter() {
            let _ = remove_file(name);
        }
    }
}

struct RandomFile {
    inner: File
}

impl RandomFile {
    fn new(name: &str) -> RandomFile {
        RandomFile { inner: File::create(Path::new(name)).unwrap() }
    }

    fn add_bytes(&mut self, bytes: usize) {
        let chunk_size: usize = if bytes >= 1024 { 1024 } else { bytes };
        let mut n = bytes;
        while n > chunk_size {
            let _ = write!(self.inner, "{}", random_chars(chunk_size));
            n -= chunk_size;
        }
        let _ = write!(self.inner, "{}", random_chars(n));
    }

    fn add_lines(&mut self, lines: usize) {
        let line_size: usize = 32;
        let mut n = lines;
        while n > 0 {
            let _ = writeln!(self.inner, "{}", random_chars(line_size));
            n -= 1;
        }
    }
}

#[test]
fn test_split_default() {
    let name = "split_default";
    let glob = Glob::new(".", r"x[:alpha:][:alpha:]$");
    RandomFile::new(name).add_lines(2000);
    if !Command::new(PROGNAME).args(&[name]).status().unwrap().success() {
        panic!();
    }
    assert_eq!(glob.count(), 2);
    assert_eq!(glob.collate(), get_file_contents(name).into_bytes());
    glob.remove_all();
}

#[test]
fn test_split_num_prefixed_chunks_by_bytes() {
    let name = "split_num_prefixed_chunks_by_bytes";
    let glob = Glob::new(".", r"x\d\d$");
    RandomFile::new(name).add_bytes(10000);
    if !Command::new(PROGNAME).args(&["-d", "-b", "1000", name]).status().unwrap().success() {
        panic!();
    }
    assert_eq!(glob.count(), 10);
    assert_eq!(glob.collate(), get_file_contents(name).into_bytes());
    glob.remove_all();
}

#[test]
fn test_split_str_prefixed_chunks_by_bytes() {
    let name = "split_str_prefixed_chunks_by_bytes";
    let glob = Glob::new(".", r"x[:alpha:][:alpha:]$");
    RandomFile::new(name).add_bytes(10000);
    if !Command::new(PROGNAME).args(&["-b", "1000", name]).status().unwrap().success() {
        panic!();
    }
    assert_eq!(glob.count(), 10);
    assert_eq!(glob.collate(), get_file_contents(name).into_bytes());
    glob.remove_all();
}

#[test]
fn test_split_num_prefixed_chunks_by_lines() {
    let name = "split_num_prefixed_chunks_by_lines";
    let glob = Glob::new(".", r"x\d\d$");
    RandomFile::new(name).add_lines(10000);
    if !Command::new(PROGNAME).args(&["-d", "-l", "1000", name]).status().unwrap().success() {
        panic!();
    }
    assert_eq!(glob.count(), 10);
    assert_eq!(glob.collate(), get_file_contents(name).into_bytes());
    glob.remove_all();
}

#[test]
fn test_split_str_prefixed_chunks_by_lines() {
    let name = "split_str_prefixed_chunks_by_lines";
    let glob = Glob::new(".", r"x[:alpha:][:alpha:]$");
    RandomFile::new(name).add_lines(10000);
    if !Command::new(PROGNAME).args(&["-l", "1000", name]).status().unwrap().success() {
        panic!();
    }
    assert_eq!(glob.count(), 10);
    assert_eq!(glob.collate(), get_file_contents(name).into_bytes());
    glob.remove_all();
}
<commit_msg>Fix broken split tests.<commit_after>extern crate libc;
extern crate memchr;
extern crate aho_corasick;
extern crate rand;
extern crate regex_syntax;
extern crate regex;

use std::fs::{File, read_dir, remove_file};
use std::io::{Read, Write};
use std::path::Path;
use std::process::Command;
use rand::{Rng, thread_rng};
use regex::Regex;
use util::*;

static PROGNAME: &'static str = "./split";

#[path = "common/util.rs"]
#[macro_use]
mod util;

fn random_chars(n: usize) -> String {
    thread_rng().gen_ascii_chars().take(n).collect::<String>()
}

struct Glob {
    directory: String,
    regex: Regex
}

impl Glob {
    fn new(directory: &str, regex: &str) -> Glob {
        Glob {
            directory: directory.to_string(),
            regex: Regex::new(regex).unwrap()
        }
    }

    fn count(&self) -> usize {
        self.collect().len()
    }

    fn collect(&self) -> Vec<String> {
        read_dir(Path::new(&self.directory)).unwrap().filter_map(|entry| {
            let path = entry.unwrap().path();
            let name = path.as_path().to_str().unwrap_or("");
            if self.regex.is_match(name) { Some(name.to_string()) } else { None }
        }).collect()
    }

    fn collate(&self) -> Vec<u8> {
        let mut files = self.collect();
        files.sort();
        let mut data: Vec<u8> = vec!();
        for name in files.iter() {
            data.extend(get_file_contents(name).into_bytes());
        }
        data
    }

    fn remove_all(&self) {
        for name in self.collect().iter() {
            let _ = remove_file(name);
        }
    }
}

struct RandomFile {
    inner: File
}

impl RandomFile {
    fn new(name: &str) -> RandomFile {
        RandomFile { inner: File::create(Path::new(name)).unwrap() }
    }

    fn add_bytes(&mut self, bytes: usize) {
        let chunk_size: usize = if bytes >= 1024 { 1024 } else { bytes };
        let mut n = bytes;
        while n > chunk_size {
            let _ = write!(self.inner, "{}", random_chars(chunk_size));
            n -= chunk_size;
        }
        let _ = write!(self.inner, "{}", random_chars(n));
    }

    fn add_lines(&mut self, lines: usize) {
        let line_size: usize = 32;
        let mut n = lines;
        while n > 0 {
            let _ = writeln!(self.inner, "{}", random_chars(line_size));
            n -= 1;
        }
    }
}

#[test]
fn test_split_default() {
    let name = "split_default";
    let glob = Glob::new(".", r"x[:alpha:][:alpha:]$");
    RandomFile::new(name).add_lines(2000);
    if !Command::new(PROGNAME).args(&[name]).status().unwrap().success() {
        panic!();
    }
    assert_eq!(glob.count(), 2);
    assert_eq!(glob.collate(), get_file_contents(name).into_bytes());
    glob.remove_all();
}

#[test]
fn test_split_num_prefixed_chunks_by_bytes() {
    let name = "split_num_prefixed_chunks_by_bytes";
    let glob = Glob::new(".", r"a\d\d$");
    RandomFile::new(name).add_bytes(10000);
    if !Command::new(PROGNAME).args(&["-d", "-b", "1000", name, "a"]).status().unwrap().success() {
        panic!();
    }
    assert_eq!(glob.count(), 10);
    assert_eq!(glob.collate(), get_file_contents(name).into_bytes());
    glob.remove_all();
}

#[test]
fn test_split_str_prefixed_chunks_by_bytes() {
    let name = "split_str_prefixed_chunks_by_bytes";
    let glob = Glob::new(".", r"b[:alpha:][:alpha:]$");
    RandomFile::new(name).add_bytes(10000);
    if !Command::new(PROGNAME).args(&["-b", "1000", name, "b"]).status().unwrap().success() {
        panic!();
    }
    assert_eq!(glob.count(), 10);
    assert_eq!(glob.collate(), get_file_contents(name).into_bytes());
    glob.remove_all();
}

#[test]
fn test_split_num_prefixed_chunks_by_lines() {
    let name = "split_num_prefixed_chunks_by_lines";
    let glob = Glob::new(".", r"c\d\d$");
    RandomFile::new(name).add_lines(10000);
    if !Command::new(PROGNAME).args(&["-d", "-l", "1000", name, "c"]).status().unwrap().success() {
        panic!();
    }
    assert_eq!(glob.count(), 10);
    assert_eq!(glob.collate(), get_file_contents(name).into_bytes());
    glob.remove_all();
}

#[test]
fn test_split_str_prefixed_chunks_by_lines() {
    let name = "split_str_prefixed_chunks_by_lines";
    let glob = Glob::new(".", r"d[:alpha:][:alpha:]$");
    RandomFile::new(name).add_lines(10000);
    if !Command::new(PROGNAME).args(&["-l", "1000", name, "d"]).status().unwrap().success() {
        panic!();
    }
    assert_eq!(glob.count(), 10);
    assert_eq!(glob.collate(), get_file_contents(name).into_bytes());
    glob.remove_all();
}
<|endoftext|>


<commit_before>use crate::evaluation::object;
use crate::lexer;
use crate::parser;
use crate::token;
use crate::ast;

// TODO: Consider this to be a hack.
//
// We have 3 types of untis now.
// 1. Program
// 2. Statement
// 3. Expression
//
// To generalize eval API we would wrap program in a special
// wrapper enum, which knows how to handle every unit.

#[derive(Debug)]
pub enum WrappedNode {
    P(ast::Program),
    S(token::Statements),
    E(token::Expression),
}
pub type WN = WrappedNode; // Just alias to avoid typing :)

// Option number 2.
// Write 3 different functions to work with 3
// different types of values.
//
// It's super bad design decision, cause I'll have to
// use different evalers in my REPL implementation,
// but I don't see the design clearly for now.

// For now we'll stick with design approach with WrappedNode.
// Perhaps use From/Into modification?

pub fn eval(node: WN) -> object::Object {
    match node {
        WN::P(program) => eval_statements(program.statements),
        WN::S(statement) => match statement {
            token::Statements::ExpressionStatement(expr) => eval(WN::E(expr.expression)),
            token::Statements::LetStatement(_) => panic!("don't know how to handle let statement"),
            token::Statements::ReturnStatement(_) => panic!("don't know how to handle return statement"),
        },
        WN::E(expression) => match expression {
            token::Expression::IntegerLiteral(il) => object::Object::Integer(object::Integer {
                value: il.value,
            }),
            token::Expression::Identifier(_i) => panic!("don't how to handle identifier"),
            token::Expression::PrefixExpression(_pe) => panic!("don't how to handle prefix expression"),
            token::Expression::InfixExpression(_ie) => panic!("don't how to handle infix expression"),
            token::Expression::Boolean(_b) => panic!("don't how to handle boolean"),
            token::Expression::IfExpression(_ie) => panic!("don't how to handle if expression"),
            token::Expression::FunctionLiteral(_fl) => panic!("don't how to handle function literal"),
            token::Expression::CallExpression(_ce) => panic!("don't how to handle call expression"),
        },
    }
}

pub fn eval_statements(statements: Vec<token::Statements>) -> object::Object {
    // TODO: not sure we need unwrap here.
    statements.into_iter().map(|statement| eval(WN::S(statement))).last().unwrap()
}

#[cfg(test)]
mod tests {
    use crate::evaluation;
    use crate::lexer;
    use crate::parser;
    use std::collections::HashMap;

    #[test]
    fn test_eval_integer_expression() {
        let pairs = vec![("1".to_string(), 1), ("2".to_string(), 2)];

        pairs.into_iter().for_each(|(value, expected)| {
            let evaluated = run_eval(value);
            assert_integer_object(evaluated, expected);
        })
    }

    fn run_eval(source_code: String) -> evaluation::object::Object {
        let lexer = lexer::Lexer::new(source_code);
        let mut parser = parser::Parser::new(lexer);

        let mut lambda_parsers = parser::LambdaParsers {
            prefix_parse_fns: HashMap::new(),
            infix_parse_fns: HashMap::new(),
        };
        lambda_parsers.register_parsers();

        let program = parser.parse_program(&lambda_parsers);

        evaluation::evaluator::eval(evaluation::evaluator::WN::P(program))
    }

    fn assert_integer_object(object: evaluation::object::Object, expected: i32) {
        let integer = match object {
            evaluation::object::Object::Integer(int) => int,
            otherwise => panic!("expected integer, got {:?}", otherwise),
        };

        assert_eq!(integer.value, expected)
    }
}
<commit_msg>add boolean evaluation to interpreter<commit_after>use crate::ast;
use crate::evaluation::object;
use crate::lexer;
use crate::parser;
use crate::token;

// TODO: Consider this to be a hack.
//
// We have 3 types of untis now.
// 1. Program
// 2. Statement
// 3. Expression
//
// To generalize eval API we would wrap program in a special
// wrapper enum, which knows how to handle every unit.

#[derive(Debug)]
pub enum WrappedNode {
    P(ast::Program),
    S(token::Statements),
    E(token::Expression),
}
pub type WN = WrappedNode; // Just alias to avoid typing :)

// Option number 2.
// Write 3 different functions to work with 3
// different types of values.
//
// It's super bad design decision, cause I'll have to
// use different evalers in my REPL implementation,
// but I don't see the design clearly for now.

// For now we'll stick with design approach with WrappedNode.
// Perhaps use From/Into modification?

pub fn eval(node: WN) -> object::Object {
    match node {
        WN::P(program) => eval_statements(program.statements),
        WN::S(statement) => match statement {
            token::Statements::ExpressionStatement(expr) => eval(WN::E(expr.expression)),
            token::Statements::LetStatement(_) => panic!("don't know how to handle let statement"),
            token::Statements::ReturnStatement(_) => {
                panic!("don't know how to handle return statement")
            }
        },
        WN::E(expression) => match expression {
            token::Expression::IntegerLiteral(il) => {
                object::Object::Integer(object::Integer { value: il.value })
            }
            token::Expression::Identifier(_i) => panic!("don't how to handle identifier"),
            token::Expression::PrefixExpression(_pe) => {
                panic!("don't how to handle prefix expression")
            }
            token::Expression::InfixExpression(_ie) => {
                panic!("don't how to handle infix expression")
            }
            token::Expression::Boolean(b) => {
                object::Object::Boolean(object::Boolean { value: b.value })
            }
            token::Expression::IfExpression(_ie) => panic!("don't how to handle if expression"),
            token::Expression::FunctionLiteral(_fl) => {
                panic!("don't how to handle function literal")
            }
            token::Expression::CallExpression(_ce) => panic!("don't how to handle call expression"),
        },
    }
}

pub fn eval_statements(statements: Vec<token::Statements>) -> object::Object {
    // TODO: not sure we need unwrap here.
    statements
        .into_iter()
        .map(|statement| eval(WN::S(statement)))
        .last()
        .unwrap()
}

#[cfg(test)]
mod tests {
    use crate::evaluation;
    use crate::lexer;
    use crate::parser;
    use std::collections::HashMap;

    #[test]
    fn test_eval_integer_expression() {
        let pairs = vec![("1".to_string(), 1), ("2".to_string(), 2)];

        pairs.into_iter().for_each(|(value, expected)| {
            let evaluated = run_eval(value);
            assert_integer_object(evaluated, expected);
        })
    }

    #[test]
    fn test_eval_boolean_expression() {
        let pairs = vec![("true".to_string(), true), ("false".to_string(), false)];

        pairs.into_iter().for_each(|(value, expected)| {
            let evaluated = run_eval(value);
            assert_boolean_object(evaluated, expected);
        })
    }

    fn run_eval(source_code: String) -> evaluation::object::Object {
        let lexer = lexer::Lexer::new(source_code);
        let mut parser = parser::Parser::new(lexer);

        let mut lambda_parsers = parser::LambdaParsers {
            prefix_parse_fns: HashMap::new(),
            infix_parse_fns: HashMap::new(),
        };
        lambda_parsers.register_parsers();

        let program = parser.parse_program(&lambda_parsers);

        evaluation::evaluator::eval(evaluation::evaluator::WN::P(program))
    }

    fn assert_integer_object(object: evaluation::object::Object, expected: i32) {
        let integer = match object {
            evaluation::object::Object::Integer(int) => int,
            otherwise => panic!("expected integer, got {:?}", otherwise),
        };

        assert_eq!(integer.value, expected)
    }

    fn assert_boolean_object(object: evaluation::object::Object, expected: bool) {
        let bool = match object {
            evaluation::object::Object::Boolean(b) => b,
            otherwise => panic!("expected boolean, got {:?}", otherwise),
        };

        assert_eq!(bool.value, expected)
    }
}
<|endoftext|>


<commit_before>pub mod event;

use self::event::EventStopable;
use std::collections::HashMap;

pub trait ListenerCallable: PartialEq {
    fn call(&self, event_name: &str, event: &mut EventStopable);
}

pub struct EventListener {
    callback: fn(event_name: &str, event: &mut EventStopable),
}

impl EventListener {
    pub fn new (callback: fn(event_name: &str, event: &mut EventStopable)) -> EventListener {
        EventListener {callback: callback}
    }
}

impl ListenerCallable for EventListener {
    fn call (&self, event_name: &str, event: &mut EventStopable) {
        let callback = self.callback;
        callback(event_name, event);
    }
}

impl PartialEq for EventListener {
    fn eq(&self, other: &EventListener) -> bool {
        (self.callback as *const()) == (other.callback as *const())
    }

    fn ne(&self, other: &EventListener) -> bool {
        !self.eq(other)
    }
}

pub trait Dispatchable<S> where S: EventStopable {
    fn dispatch (&self, event_name: &str, event: &mut S);
}

pub struct EventDispatcher<'a, 'b, L> where L: 'b + ListenerCallable {
    listeners: HashMap<&'a str, Vec<&'b L>>,
}

impl<'a, 'b, L: 'b + ListenerCallable> EventDispatcher<'a, 'b, L> {
    pub fn new() -> EventDispatcher<'a, 'b, L> {
        EventDispatcher{listeners: HashMap::new()}
    }

    pub fn add_listener(&mut self, event_name: &'a str, listener: &'b L) {
        if !self.listeners.contains_key(event_name) {
            self.listeners.insert(event_name, Vec::new());
        }

        if let Some(mut listeners) = self.listeners.get_mut(event_name) {
            listeners.push(listener);
        }
    }

    pub fn remove_listener(&mut self, event_name: &'a str, listener: &'b mut L) {
        if self.listeners.contains_key(event_name) {
            if let Some(mut listeners) = self.listeners.get_mut(event_name) {
                match listeners.iter().position(|x| *x == listener) {
                    Some(index) => {
                        listeners.remove(index);
                    },
                    _ => {},
                }
            }
        }
    }
}

impl<'a, 'b, S: 'b + EventStopable> Dispatchable<S> for EventDispatcher<'a, 'b, EventListener> {
    fn dispatch(&self, event_name: &str, event: &mut S) {
        if let Some(listeners) = self.listeners.get(event_name) {
            for listener in listeners {
                listener.call(event_name, event);

                if !event.is_propagation_stopped() {
                    break;
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use std::any::Any;
    use super::*;
    use super::event::*;

    fn print_event_info(event_name: &str, event: &mut EventStopable) {
        println!("callback from event: {}", event_name);
    }

    #[test]
    fn test_dispatcher() {
        let mut dispatcher = EventDispatcher::new();
        let event_name = "test_a";
        let mut event = Event::new();
        dispatcher.dispatch(event_name, &mut event);
        assert_eq!(false, event.is_propagation_stopped());
        dispatcher.dispatch(event_name, &mut event);
        assert_eq!(false, event.is_propagation_stopped());

        let callback_one: fn(event_name: &str, event: &mut EventStopable) = &print_event_info;

        let listener_one = EventListener::new(callback_one);
        dispatcher.add_listener(event_name, &mut listener_one);
        dispatcher.dispatch(event_name, &mut event);
        assert_eq!(false, event.is_propagation_stopped());
    }
}
<commit_msg>update test code<commit_after>pub mod event;

use self::event::EventStopable;
use std::collections::HashMap;

pub trait ListenerCallable: PartialEq {
    fn call(&self, event_name: &str, event: &mut EventStopable);
}

pub struct EventListener {
    callback: fn(event_name: &str, event: &mut EventStopable),
}

impl EventListener {
    pub fn new (callback: fn(event_name: &str, event: &mut EventStopable)) -> EventListener {
        EventListener {callback: callback}
    }
}

impl ListenerCallable for EventListener {
    fn call (&self, event_name: &str, event: &mut EventStopable) {
        let callback = self.callback;
        callback(event_name, event);
    }
}

impl PartialEq for EventListener {
    fn eq(&self, other: &EventListener) -> bool {
        (self.callback as *const()) == (other.callback as *const())
    }

    fn ne(&self, other: &EventListener) -> bool {
        !self.eq(other)
    }
}

pub trait Dispatchable<S> where S: EventStopable {
    fn dispatch (&self, event_name: &str, event: &mut S);
}

pub struct EventDispatcher<'a, L> where L: 'a + ListenerCallable {
    listeners: HashMap<&'a str, Vec<&'a L>>,
}

impl<'a, L: 'a + ListenerCallable> EventDispatcher<'a, L> {
    pub fn new() -> EventDispatcher<'a, L> {
        EventDispatcher{listeners: HashMap::new()}
    }

    pub fn add_listener(&mut self, event_name: &'a str, listener: &'a L) {
        if !self.listeners.contains_key(event_name) {
            self.listeners.insert(event_name, Vec::new());
        }

        if let Some(mut listeners) = self.listeners.get_mut(event_name) {
            listeners.push(listener);
        }
    }

    pub fn remove_listener(&mut self, event_name: &'a str, listener: &'a mut L) {
        if self.listeners.contains_key(event_name) {
            if let Some(mut listeners) = self.listeners.get_mut(event_name) {
                match listeners.iter().position(|x| *x == listener) {
                    Some(index) => {
                        listeners.remove(index);
                    },
                    _ => {},
                }
            }
        }
    }
}

impl<'a, S: 'a + EventStopable> Dispatchable<S> for EventDispatcher<'a, EventListener> {
    fn dispatch(&self, event_name: &str, event: &mut S) {
        if let Some(listeners) = self.listeners.get(event_name) {
            for listener in listeners {
                listener.call(event_name, event);

                if !event.is_propagation_stopped() {
                    break;
                }
            }
        }
    }
}

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

    fn print_event_info(event_name: &str, event: &mut EventStopable) {
        println!("callback from event: {}", event_name);

        event.stop_propagation();
    }

    #[test]
    fn test_dispatcher() {
        let event_name = "test_a";
        let mut event = Event::new();
        let callback_one: fn(event_name: &str, event: &mut EventStopable) = print_event_info;
        let mut listener_one = EventListener::new(callback_one);
        let mut dispatcher = EventDispatcher::new();

        dispatcher.dispatch(event_name, &mut event);
        assert_eq!(false, event.is_propagation_stopped());
        dispatcher.dispatch(event_name, &mut event);
        assert_eq!(false, event.is_propagation_stopped());

        dispatcher.add_listener(event_name, &mut listener_one);
        dispatcher.dispatch(event_name, &mut event);
        assert_eq!(true, event.is_propagation_stopped());
    }
}
<|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/
 */

//! Pair potentials traits and implementations.

use types::{Matrix3, Vector3D};

/// A `PotentialFunction` is a set of two parametric functions which takes a
/// single scalar variable and return the energy or the norm of the force
/// corresponding to the value of that variable.
///
/// The scalar variable will be the distance for pair potentials, the angle for
/// angles or dihedral angles potentials, *etc.*
pub trait PotentialFunction : Sync + Send {
    /// Get the energy corresponding to the variable `x`
    fn energy(&self, x: f64) -> f64;
    /// Get the force norm corresponding to the variable `x`
    fn force(&self, x: f64) -> f64;
}

/// Pair potential can be expressed by implenting the `PairPotential` trait.
pub trait PairPotential : PotentialFunction {
    /// Compute the virial contribution corresponding to the distance `r` between the particles
    fn virial(&self, r: &Vector3D) -> Matrix3 {
        let fact = self.force(r.norm());
        let rn = r.normalized();
        let force = - fact * rn;
        force.tensorial(r)
    }
}

/// Angle potential can be expressed by implenting the `AnglePotential` trait.
pub trait AnglePotential : PotentialFunction {}

/// Dihedral angles potential can be expressed by implenting the
/// `DihedralPotential` trait.
pub trait DihedralPotential : PotentialFunction {}

/******************************************************************************/
/// The `NullPotential` always returns 0.0 as energy and force.
///
/// It is to be used when there is no potential interaction between two
/// particles kinds.
#[derive(Clone, Copy)]
pub struct NullPotential;
impl PotentialFunction for NullPotential {
    #[inline] fn energy(&self, _: f64) -> f64 {0.0}
    #[inline] fn force(&self, _: f64) -> f64 {0.0}
}

impl PairPotential for NullPotential {}
impl AnglePotential for NullPotential {}
impl DihedralPotential for NullPotential {}

/******************************************************************************/
/// Lennard-Jones potential, using the following form:
/// $$ V(r) = 4 \epsilon \left[ (\sigma/r)^{12} - (\sigma/r)^{6} \right] $$
/// where $\sigma$ is a distance constant, and $\epsilon$ an energetic constant.
#[derive(Clone, Copy)]
pub struct LennardJones {
    /// Distance constant of the Lennard-Jones potential
    pub sigma: f64,
    /// Energy constant of the Lennard-Jones potential
    pub epsilon: f64,
}

impl PotentialFunction for LennardJones {
    #[inline]
    fn energy(&self, r: f64) -> f64 {
        let s6 = f64::powi(self.sigma/r, 6);
        4.0 * self.epsilon * (f64::powi(s6, 2) - s6)
    }

    #[inline]
    fn force(&self, r: f64) -> f64 {
        let s6 = f64::powi(self.sigma/r, 6);
        -24.0 * self.epsilon * (s6 - 2.0 * f64::powi(s6, 2)) / r
    }
}

impl PairPotential for LennardJones {}

/******************************************************************************/
/// Harmonic potential, using the following form:
/// $$ V(x) = \frac 12 k (x - x_0)^2 $$
/// where $x_0$ is the distance equilibrium, and $k$ the elastic constant.
#[derive(Clone, Copy)]
pub struct Harmonic {
    /// Spring constant
    pub k: f64,
    /// Equilibrium value
    pub x0: f64,
}

impl PotentialFunction for Harmonic {
    #[inline]
    fn energy(&self, x: f64) -> f64 {
        let dx = x - self.x0;
        0.5 * self.k * dx * dx
    }

    #[inline]
    fn force(&self, x: f64) -> f64 {
        self.k * (self.x0 - x)
    }
}

impl PairPotential for Harmonic {}
impl AnglePotential for Harmonic {}
impl DihedralPotential for Harmonic {}

/******************************************************************************/
/// Cosine harmonic potential, using the following form:
/// $$ V(r) = \frac 12 k (\cos r - \cos x_0)^2 $$
/// where $x_0$ is the distance equilibrium, and $k$ the elastic constant.
#[derive(Clone, Copy)]
pub struct CosineHarmonic {
    /// Spring constant
    k: f64,
    /// Cosine of the equilibrium value
    cos_x0: f64,
}

impl CosineHarmonic {
    /// Create a new `CosineHarmonic` potentials, with elastic constant of `k`
    /// and equilibrium value of `x0`
    pub fn new(k: f64, x0:f64) -> CosineHarmonic {
        CosineHarmonic{k: k, cos_x0: f64::cos(x0)}
    }
}

impl PotentialFunction for CosineHarmonic {
    #[inline]
    fn energy(&self, x: f64) -> f64 {
        let dr = f64::cos(x) - self.cos_x0;
        0.5 * self.k * dr * dr
    }

    #[inline]
    fn force(&self, x: f64) -> f64 {
        self.k * (f64::cos(x) - self.cos_x0) * f64::sin(x)
    }
}

impl AnglePotential for CosineHarmonic {}
impl DihedralPotential for CosineHarmonic {}

/******************************************************************************/
/// Torsion potential, using the following form:
/// $$ V(r) = k(1 + \cos(n\phi􏰈 - \delta)) $$
/// where $k$ is the force constant, `n` the periodicity of the potential, and
/// $\delta$ the equilibrium angle.
#[derive(Clone, Copy)]
pub struct Torsion {
    /// Force constant
    pub k: f64,
    /// Equilibrium value
    pub delta: f64,
    /// Multiplicity of the potential
    pub n: usize,
}

impl PotentialFunction for Torsion {
    #[inline]
    fn energy(&self, phi: f64) -> f64 {
        let n = self.n as f64;
        let cos = f64::cos(n * phi - self.delta);
        self.k * (1.0 + cos)
    }

    #[inline]
    fn force(&self, phi: f64) -> f64 {
        let n = self.n as f64;
        let sin = f64::sin(n * phi - self.delta);
        - self.k * n * sin
    }
}

impl DihedralPotential for Torsion {}

/******************************************************************************/

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

    #[test]
    fn null() {
        let null = NullPotential;
        assert_eq!(null.energy(2.0), 0.0);
        assert_eq!(null.energy(2.5), 0.0);

        assert_eq!(null.force(2.0), 0.0);
        assert_eq!(null.force(2.5), 0.0);
    }

    #[test]
    fn lj() {
        let lj = LennardJones{epsilon: 0.8, sigma: 2.0};
        assert_eq!(lj.energy(2.0), 0.0);
        assert_eq!(lj.energy(2.5), -0.6189584744448002);

        assert_approx_eq!(lj.force(f64::powf(2.0, 1.0/6.0) * 2.0), 0.0, 1e-15);
        assert_approx_eq!(lj.force(2.5), -0.95773475733504, 1e-15);
    }

    #[test]
    fn harmonic() {
        let harm = Harmonic{k: 50.0, x0: 2.0};
        assert_eq!(harm.energy(2.0), 0.0);
        assert_eq!(harm.energy(2.5), 6.25);

        assert_eq!(harm.force(2.0), 0.0);
        assert_eq!(harm.force(2.5), -25.0);
    }

    #[test]
    fn cosine_harmonic() {
        let harm = CosineHarmonic::new(50.0, 2.0);
        assert_eq!(harm.energy(2.0), 0.0);
        let dcos = f64::cos(2.5) - f64::cos(2.0);
        assert_eq!(harm.energy(2.5), 0.5 * 50.0 * dcos * dcos);

        assert_eq!(harm.force(2.0), 0.0);
        let dcos = f64::cos(2.5) - f64::cos(2.0);
        assert_eq!(harm.force(2.5), 50.0 * dcos * f64::sin(2.5));
    }

    #[test]
    fn torsion() {
        let torsion = Torsion{k: 5.0, n: 3, delta: 3.0};
        assert_eq!(torsion.energy(1.0), 10.0);
        let energy = 5.0 * (1.0 + f64::cos(3.0 * 1.1 - 3.0));
        assert_eq!(torsion.energy(1.1), energy);

        assert_eq!(torsion.force(1.0), 0.0);
    }
}
<commit_msg>Add finite difference tests for forces computation<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/
 */

//! Pair potentials traits and implementations.

use types::{Matrix3, Vector3D};

/// A `PotentialFunction` is a set of two parametric functions which takes a
/// single scalar variable and return the energy or the norm of the force
/// corresponding to the value of that variable.
///
/// The scalar variable will be the distance for pair potentials, the angle for
/// angles or dihedral angles potentials, *etc.*
pub trait PotentialFunction : Sync + Send {
    /// Get the energy corresponding to the variable `x`
    fn energy(&self, x: f64) -> f64;
    /// Get the force norm corresponding to the variable `x`
    fn force(&self, x: f64) -> f64;
}

/// Pair potential can be expressed by implenting the `PairPotential` trait.
pub trait PairPotential : PotentialFunction {
    /// Compute the virial contribution corresponding to the distance `r` between the particles
    fn virial(&self, r: &Vector3D) -> Matrix3 {
        let fact = self.force(r.norm());
        let rn = r.normalized();
        let force = - fact * rn;
        force.tensorial(r)
    }
}

/// Angle potential can be expressed by implenting the `AnglePotential` trait.
pub trait AnglePotential : PotentialFunction {}

/// Dihedral angles potential can be expressed by implenting the
/// `DihedralPotential` trait.
pub trait DihedralPotential : PotentialFunction {}

/******************************************************************************/
/// The `NullPotential` always returns 0.0 as energy and force.
///
/// It is to be used when there is no potential interaction between two
/// particles kinds.
#[derive(Clone, Copy)]
pub struct NullPotential;
impl PotentialFunction for NullPotential {
    #[inline] fn energy(&self, _: f64) -> f64 {0.0}
    #[inline] fn force(&self, _: f64) -> f64 {0.0}
}

impl PairPotential for NullPotential {}
impl AnglePotential for NullPotential {}
impl DihedralPotential for NullPotential {}

/******************************************************************************/
/// Lennard-Jones potential, using the following form:
/// $$ V(r) = 4 \epsilon \left[ (\sigma/r)^{12} - (\sigma/r)^{6} \right] $$
/// where $\sigma$ is a distance constant, and $\epsilon$ an energetic constant.
#[derive(Clone, Copy)]
pub struct LennardJones {
    /// Distance constant of the Lennard-Jones potential
    pub sigma: f64,
    /// Energy constant of the Lennard-Jones potential
    pub epsilon: f64,
}

impl PotentialFunction for LennardJones {
    #[inline]
    fn energy(&self, r: f64) -> f64 {
        let s6 = f64::powi(self.sigma/r, 6);
        4.0 * self.epsilon * (f64::powi(s6, 2) - s6)
    }

    #[inline]
    fn force(&self, r: f64) -> f64 {
        let s6 = f64::powi(self.sigma/r, 6);
        -24.0 * self.epsilon * (s6 - 2.0 * f64::powi(s6, 2)) / r
    }
}

impl PairPotential for LennardJones {}

/******************************************************************************/
/// Harmonic potential, using the following form:
/// $$ V(x) = \frac 12 k (x - x_0)^2 $$
/// where $x_0$ is the distance equilibrium, and $k$ the elastic constant.
#[derive(Clone, Copy)]
pub struct Harmonic {
    /// Spring constant
    pub k: f64,
    /// Equilibrium value
    pub x0: f64,
}

impl PotentialFunction for Harmonic {
    #[inline]
    fn energy(&self, x: f64) -> f64 {
        let dx = x - self.x0;
        0.5 * self.k * dx * dx
    }

    #[inline]
    fn force(&self, x: f64) -> f64 {
        self.k * (self.x0 - x)
    }
}

impl PairPotential for Harmonic {}
impl AnglePotential for Harmonic {}
impl DihedralPotential for Harmonic {}

/******************************************************************************/
/// Cosine harmonic potential, using the following form:
/// $$ V(r) = \frac 12 k (\cos r - \cos x_0)^2 $$
/// where $x_0$ is the distance equilibrium, and $k$ the elastic constant.
#[derive(Clone, Copy)]
pub struct CosineHarmonic {
    /// Spring constant
    k: f64,
    /// Cosine of the equilibrium value
    cos_x0: f64,
}

impl CosineHarmonic {
    /// Create a new `CosineHarmonic` potentials, with elastic constant of `k`
    /// and equilibrium value of `x0`
    pub fn new(k: f64, x0:f64) -> CosineHarmonic {
        CosineHarmonic{k: k, cos_x0: f64::cos(x0)}
    }
}

impl PotentialFunction for CosineHarmonic {
    #[inline]
    fn energy(&self, x: f64) -> f64 {
        let dr = f64::cos(x) - self.cos_x0;
        0.5 * self.k * dr * dr
    }

    #[inline]
    fn force(&self, x: f64) -> f64 {
        self.k * (f64::cos(x) - self.cos_x0) * f64::sin(x)
    }
}

impl AnglePotential for CosineHarmonic {}
impl DihedralPotential for CosineHarmonic {}

/******************************************************************************/
/// Torsion potential, using the following form:
/// $$ V(r) = k(1 + \cos(n\phi􏰈 - \delta)) $$
/// where $k$ is the force constant, `n` the periodicity of the potential, and
/// $\delta$ the equilibrium angle.
#[derive(Clone, Copy)]
pub struct Torsion {
    /// Force constant
    pub k: f64,
    /// Equilibrium value
    pub delta: f64,
    /// Multiplicity of the potential
    pub n: usize,
}

impl PotentialFunction for Torsion {
    #[inline]
    fn energy(&self, phi: f64) -> f64 {
        let n = self.n as f64;
        let cos = f64::cos(n * phi - self.delta);
        self.k * (1.0 + cos)
    }

    #[inline]
    fn force(&self, phi: f64) -> f64 {
        let n = self.n as f64;
        let sin = f64::sin(n * phi - self.delta);
        self.k * n * sin
    }
}

impl DihedralPotential for Torsion {}

/******************************************************************************/

#[cfg(test)]
mod tests {
    use super::*;
    const EPS: f64 = 1e-9;

    #[test]
    fn null() {
        let null = NullPotential;
        assert_eq!(null.energy(2.0), 0.0);
        assert_eq!(null.energy(2.5), 0.0);

        assert_eq!(null.force(2.0), 0.0);
        assert_eq!(null.force(2.5), 0.0);

        let e0 = null.energy(2.0);
        let e1 = null.energy(2.0 + EPS);
        assert_approx_eq!((e0 - e1)/EPS, null.force(2.0), EPS);
    }

    #[test]
    fn lj() {
        let lj = LennardJones{epsilon: 0.8, sigma: 2.0};
        assert_eq!(lj.energy(2.0), 0.0);
        assert_eq!(lj.energy(2.5), -0.6189584744448002);

        assert_approx_eq!(lj.force(f64::powf(2.0, 1.0/6.0) * 2.0), 0.0, 1e-15);
        assert_approx_eq!(lj.force(2.5), -0.95773475733504, 1e-15);

        let e0 = lj.energy(4.0);
        let e1 = lj.energy(4.0 + EPS);
        assert_approx_eq!((e0 - e1)/EPS, lj.force(4.0), 1e-6);
    }

    #[test]
    fn harmonic() {
        let harm = Harmonic{k: 50.0, x0: 2.0};
        assert_eq!(harm.energy(2.0), 0.0);
        assert_eq!(harm.energy(2.5), 6.25);

        assert_eq!(harm.force(2.0), 0.0);
        assert_eq!(harm.force(2.5), -25.0);

        let e0 = harm.energy(2.1);
        let e1 = harm.energy(2.1 + EPS);
        assert_approx_eq!((e0 - e1)/EPS, harm.force(2.1), 1e-6);
    }

    #[test]
    fn cosine_harmonic() {
        let harm = CosineHarmonic::new(50.0, 2.0);
        assert_eq!(harm.energy(2.0), 0.0);
        let dcos = f64::cos(2.5) - f64::cos(2.0);
        assert_eq!(harm.energy(2.5), 0.5 * 50.0 * dcos * dcos);

        assert_eq!(harm.force(2.0), 0.0);
        let dcos = f64::cos(2.5) - f64::cos(2.0);
        assert_eq!(harm.force(2.5), 50.0 * dcos * f64::sin(2.5));

        let e0 = harm.energy(2.3);
        let e1 = harm.energy(2.3 + EPS);
        assert_approx_eq!((e0 - e1)/EPS, harm.force(2.3), 1e-6);
    }

    #[test]
    fn torsion() {
        let torsion = Torsion{k: 5.0, n: 3, delta: 3.0};
        assert_eq!(torsion.energy(1.0), 10.0);
        let energy = 5.0 * (1.0 + f64::cos(3.0 * 1.1 - 3.0));
        assert_eq!(torsion.energy(1.1), energy);

        assert_eq!(torsion.force(1.0), 0.0);

        let e0 = torsion.energy(4.0);
        let e1 = torsion.energy(4.0 + EPS);
        assert_approx_eq!((e0 - e1)/EPS, torsion.force(4.0), 1e-6);
    }
}
<|endoftext|>


<commit_before>use core::{Algorithm, Predictor, Parameter, Trace, Shared};
use domains::Transition;
use fa::{Approximator, VFunction, Parameterised, Projector, Projection, SimpleLFA};
use geometry::{Space, Vector, Matrix};
use ndarray::Axis;
use ndarray_linalg::solve::Solve;
use std::marker::PhantomData;
use utils::{argmaxima, pinv};

pub struct LSTD<S, P: Projector<S>> {
    pub fa_theta: Shared<SimpleLFA<S, P>>,
    pub gamma: Parameter,

    a: Matrix<f64>,
    b: Vector<f64>,

    phantom: PhantomData<S>,
}

impl<S, P: Projector<S>> LSTD<S, P> {
    pub fn new<T: Into<Parameter>>(fa_theta: Shared<SimpleLFA<S, P>>, gamma: T) -> Self {
        let n_features = fa_theta.borrow().projector.dim();

        LSTD {
            fa_theta,
            gamma: gamma.into(),

            a: Matrix::zeros((n_features, n_features)),
            b: Vector::zeros((n_features,)),

            phantom: PhantomData,
        }
    }
}

impl<S, P: Projector<S>> LSTD<S, P> {
    #[inline(always)]
    fn compute_dense_fv(&self, s: &S) -> Vector<f64> {
        self.fa_theta.borrow().projector.project(s).expanded(self.a.rows())
    }

    #[inline(always)]
    fn do_update(&mut self, phi_s: Vector<f64>, pd: Vector<f64>, reward: f64) {
        self.b.scaled_add(reward, &phi_s);
        self.a += &phi_s.insert_axis(Axis(1)).dot(&(pd.insert_axis(Axis(0))));
    }

    pub fn solve(&mut self) {
        // First try the clean approach:
        if let Ok(theta) = self.a.solve(&self.b) {
            self.fa_theta.borrow_mut().approximator.weights.assign(&theta);

        // Otherwise solve via SVD:
        } else if let Ok(ainv) = pinv(&self.a) {
            let theta = ainv.dot(&self.b);

            self.fa_theta.borrow_mut().approximator.weights.assign(&theta);
        }
    }
}

impl<S, A, P: Projector<S>> Algorithm<S, A> for LSTD<S, P> {
    fn handle_sample(&mut self, t: &Transition<S, A>) {
        let (s, ns) = (t.from.state(), t.to.state());

        // (D x 1)
        let phi_s = self.compute_dense_fv(s);
        let phi_ns = self.compute_dense_fv(ns);

        // (1 x D)
        let pd = phi_s.clone() - self.gamma.value()*phi_ns;

        self.do_update(phi_s, pd, t.reward);
    }

    fn handle_terminal(&mut self, t: &Transition<S, A>) {
        {
            let phi_s = self.compute_dense_fv(t.from.state());

            self.do_update(phi_s.clone(), phi_s, t.reward);
            self.solve();
        }

        self.gamma = self.gamma.step();
    }
}

impl<S, A, P: Projector<S>> Predictor<S, A> for LSTD<S, P> {
    fn predict_v(&mut self, s: &S) -> f64 {
        self.fa_theta.borrow().evaluate(s).unwrap()
    }
}

impl<S, P: Projector<S>> Parameterised for LSTD<S, P> {
    fn weights(&self) -> Matrix<f64> {
        self.fa_theta.borrow().weights()
    }
}
<commit_msg>style(prediction): rename LSTD::do_update to LSTD::update_matrices<commit_after>use core::{Algorithm, Predictor, Parameter, Trace, Shared};
use domains::Transition;
use fa::{Approximator, VFunction, Parameterised, Projector, Projection, SimpleLFA};
use geometry::{Space, Vector, Matrix};
use ndarray::Axis;
use ndarray_linalg::solve::Solve;
use std::marker::PhantomData;
use utils::{argmaxima, pinv};

pub struct LSTD<S, P: Projector<S>> {
    pub fa_theta: Shared<SimpleLFA<S, P>>,
    pub gamma: Parameter,

    a: Matrix<f64>,
    b: Vector<f64>,

    phantom: PhantomData<S>,
}

impl<S, P: Projector<S>> LSTD<S, P> {
    pub fn new<T: Into<Parameter>>(fa_theta: Shared<SimpleLFA<S, P>>, gamma: T) -> Self {
        let n_features = fa_theta.borrow().projector.dim();

        LSTD {
            fa_theta,
            gamma: gamma.into(),

            a: Matrix::zeros((n_features, n_features)),
            b: Vector::zeros((n_features,)),

            phantom: PhantomData,
        }
    }
}

impl<S, P: Projector<S>> LSTD<S, P> {
    #[inline(always)]
    fn compute_dense_fv(&self, s: &S) -> Vector<f64> {
        self.fa_theta.borrow().projector.project(s).expanded(self.a.rows())
    }

    #[inline(always)]
    fn update_matrices(&mut self, phi_s: Vector<f64>, pd: Vector<f64>, reward: f64) {
        self.b.scaled_add(reward, &phi_s);
        self.a += &phi_s.insert_axis(Axis(1)).dot(&(pd.insert_axis(Axis(0))));
    }

    pub fn solve(&mut self) {
        // First try the clean approach:
        if let Ok(theta) = self.a.solve(&self.b) {
            self.fa_theta.borrow_mut().approximator.weights.assign(&theta);

        // Otherwise solve via SVD:
        } else if let Ok(ainv) = pinv(&self.a) {
            let theta = ainv.dot(&self.b);

            self.fa_theta.borrow_mut().approximator.weights.assign(&theta);
        }
    }
}

impl<S, A, P: Projector<S>> Algorithm<S, A> for LSTD<S, P> {
    fn handle_sample(&mut self, t: &Transition<S, A>) {
        let (s, ns) = (t.from.state(), t.to.state());

        // (D x 1)
        let phi_s = self.compute_dense_fv(s);
        let phi_ns = self.compute_dense_fv(ns);

        // (1 x D)
        let pd = phi_s.clone() - self.gamma.value()*phi_ns;

        self.update_matrices(phi_s, pd, t.reward);
    }

    fn handle_terminal(&mut self, t: &Transition<S, A>) {
        {
            let phi_s = self.compute_dense_fv(t.from.state());

            self.update_matrices(phi_s.clone(), phi_s, t.reward);

            self.solve();
        }

        self.gamma = self.gamma.step();
    }
}

impl<S, A, P: Projector<S>> Predictor<S, A> for LSTD<S, P> {
    fn predict_v(&mut self, s: &S) -> f64 {
        self.fa_theta.borrow().evaluate(s).unwrap()
    }
}

impl<S, P: Projector<S>> Parameterised for LSTD<S, P> {
    fn weights(&self) -> Matrix<f64> {
        self.fa_theta.borrow().weights()
    }
}
<|endoftext|>