<commit_before>#[macro_export]
macro_rules! char_class {
    ($c: expr, [$head:expr]) => ($c == $head);
    ($c: expr, [$head:expr $(, $cs:expr)+]) => ($c == $head || $crate::char_class!($c, [$($cs),*]));
}

#[macro_export]
macro_rules! alpha_char {
    ($c: expr) => {
        $c.is_alphabetic() || $c == '_'
    };
}

#[macro_export]
macro_rules! alpha_numeric_char {
    ($c: expr) => {
        $crate::alpha_char!($c) || $crate::decimal_digit_char!($c)
    };
}

#[macro_export]
macro_rules! backslash_char {
    ($c: expr) => {
        $c == '\\'
    };
}

#[macro_export]
macro_rules! back_quote_char {
    ($c: expr) => {
        $c == '`'
    };
}

#[macro_export]
macro_rules! octet_char {
    ($c: expr) => {
        ('\u{0000}'..='\u{00FF}').contains(&$c)
    };
}

#[macro_export]
macro_rules! capital_letter_char {
    ($c: expr) => {
        $c.is_uppercase()
    };
}

#[macro_export]
macro_rules! comment_1_char {
    ($c: expr) => {
        $c == '/'
    };
}

#[macro_export]
macro_rules! comment_2_char {
    ($c: expr) => {
        $c == '*'
    };
}

#[macro_export]
macro_rules! cut_char {
    ($c: expr) => {
        $c == '!'
    };
}

#[macro_export]
macro_rules! decimal_digit_char {
    ($c: expr) => {
        ('0'..='9').contains(&$c)
    };
}

#[macro_export]
macro_rules! decimal_point_char {
    ($c: expr) => {
        $c == '.'
    };
}

#[macro_export]
macro_rules! double_quote_char {
    ($c: expr) => {
        $c == '"'
    };
}

#[macro_export]
macro_rules! end_line_comment_char {
    ($c: expr) => {
        $c == '%'
    };
}

#[macro_export]
macro_rules! exponent_char {
    ($c: expr) => {
        $c == 'e' || $c == 'E'
    };
}

#[macro_export]
macro_rules! graphic_char {
    ($c: expr) => ($crate::char_class!($c, ['#', '$', '&', '*', '+', '-', '.', '/', ':',
                                            '<', '=', '>', '?', '@', '^', '~']))
}

#[macro_export]
macro_rules! graphic_token_char {
    ($c: expr) => {
        $crate::graphic_char!($c) || $crate::backslash_char!($c)
    };
}

#[macro_export]
macro_rules! hexadecimal_digit_char {
    ($c: expr) => {
        ('0'..='9').contains(&$c) || ('A'..='F').contains(&$c) || ('a'..='f').contains(&$c)
    };
}

#[macro_export]
macro_rules! layout_char {
    ($c: expr) => {
        $crate::char_class!($c, [' ', '\n', '\t', '\u{0B}', '\u{0C}'])
    };
}

#[macro_export]
macro_rules! meta_char {
    ($c: expr) => {
        $crate::char_class!($c, ['\\', '\'', '"', '`'])
    };
}

#[macro_export]
macro_rules! new_line_char {
    ($c: expr) => {
        $c == '\n'
    };
}

#[macro_export]
macro_rules! octal_digit_char {
    ($c: expr) => {
        ('0'..='7').contains(&$c)
    };
}

#[macro_export]
macro_rules! binary_digit_char {
    ($c: expr) => {
        $c == '0' || $c == '1'
    };
}

#[macro_export]
macro_rules! prolog_char {
    ($c: expr) => {
        $crate::graphic_char!($c)
            || $crate::alpha_numeric_char!($c)
            || $crate::solo_char!($c)
            || $crate::layout_char!($c)
            || $crate::meta_char!($c)
    };
}

#[macro_export]
macro_rules! semicolon_char {
    ($c: expr) => {
        $c == ';'
    };
}

#[macro_export]
macro_rules! sign_char {
    ($c: expr) => {
        $c == '-' || $c == '+'
    };
}

#[macro_export]
macro_rules! single_quote_char {
    ($c: expr) => {
        $c == '\''
    };
}

#[macro_export]
macro_rules! small_letter_char {
    ($c: expr) => {
        $c.is_lowercase()
    };
}

#[macro_export]
macro_rules! solo_char {
    ($c: expr) => {
        $crate::char_class!($c, ['!', '(', ')', ',', ';', '[', ']', '{', '}', '|', '%'])
    };
}

#[macro_export]
macro_rules! space_char {
    ($c: expr) => {
        $c == ' '
    };
}

#[macro_export]
macro_rules! symbolic_control_char {
    ($c: expr) => {
        $crate::char_class!($c, ['a', 'b', 'f', 'n', 'r', 't', 'v', '0'])
    };
}

#[macro_export]
macro_rules! symbolic_hexadecimal_char {
    ($c: expr) => {
        $c == 'x'
    };
}

#[macro_export]
macro_rules! variable_indicator_char {
    ($c: expr) => {
        $c == '_'
    };
}
<commit_msg>extend small_letter_char! to include all non-uppercase letters (#1364)<commit_after>#[macro_export]
macro_rules! char_class {
    ($c: expr, [$head:expr]) => ($c == $head);
    ($c: expr, [$head:expr $(, $cs:expr)+]) => ($c == $head || $crate::char_class!($c, [$($cs),*]));
}

#[macro_export]
macro_rules! alpha_char {
    ($c: expr) => {
        $c.is_alphabetic() || $c == '_'
    };
}

#[macro_export]
macro_rules! alpha_numeric_char {
    ($c: expr) => {
        $crate::alpha_char!($c) || $crate::decimal_digit_char!($c)
    };
}

#[macro_export]
macro_rules! backslash_char {
    ($c: expr) => {
        $c == '\\'
    };
}

#[macro_export]
macro_rules! back_quote_char {
    ($c: expr) => {
        $c == '`'
    };
}

#[macro_export]
macro_rules! octet_char {
    ($c: expr) => {
        ('\u{0000}'..='\u{00FF}').contains(&$c)
    };
}

#[macro_export]
macro_rules! capital_letter_char {
    ($c: expr) => {
        $c.is_uppercase()
    };
}

#[macro_export]
macro_rules! comment_1_char {
    ($c: expr) => {
        $c == '/'
    };
}

#[macro_export]
macro_rules! comment_2_char {
    ($c: expr) => {
        $c == '*'
    };
}

#[macro_export]
macro_rules! cut_char {
    ($c: expr) => {
        $c == '!'
    };
}

#[macro_export]
macro_rules! decimal_digit_char {
    ($c: expr) => {
        ('0'..='9').contains(&$c)
    };
}

#[macro_export]
macro_rules! decimal_point_char {
    ($c: expr) => {
        $c == '.'
    };
}

#[macro_export]
macro_rules! double_quote_char {
    ($c: expr) => {
        $c == '"'
    };
}

#[macro_export]
macro_rules! end_line_comment_char {
    ($c: expr) => {
        $c == '%'
    };
}

#[macro_export]
macro_rules! exponent_char {
    ($c: expr) => {
        $c == 'e' || $c == 'E'
    };
}

#[macro_export]
macro_rules! graphic_char {
    ($c: expr) => ($crate::char_class!($c, ['#', '$', '&', '*', '+', '-', '.', '/', ':',
                                            '<', '=', '>', '?', '@', '^', '~']))
}

#[macro_export]
macro_rules! graphic_token_char {
    ($c: expr) => {
        $crate::graphic_char!($c) || $crate::backslash_char!($c)
    };
}

#[macro_export]
macro_rules! hexadecimal_digit_char {
    ($c: expr) => {
        ('0'..='9').contains(&$c) || ('A'..='F').contains(&$c) || ('a'..='f').contains(&$c)
    };
}

#[macro_export]
macro_rules! layout_char {
    ($c: expr) => {
        $crate::char_class!($c, [' ', '\n', '\t', '\u{0B}', '\u{0C}'])
    };
}

#[macro_export]
macro_rules! meta_char {
    ($c: expr) => {
        $crate::char_class!($c, ['\\', '\'', '"', '`'])
    };
}

#[macro_export]
macro_rules! new_line_char {
    ($c: expr) => {
        $c == '\n'
    };
}

#[macro_export]
macro_rules! octal_digit_char {
    ($c: expr) => {
        ('0'..='7').contains(&$c)
    };
}

#[macro_export]
macro_rules! binary_digit_char {
    ($c: expr) => {
        $c == '0' || $c == '1'
    };
}

#[macro_export]
macro_rules! prolog_char {
    ($c: expr) => {
        $crate::graphic_char!($c)
            || $crate::alpha_numeric_char!($c)
            || $crate::solo_char!($c)
            || $crate::layout_char!($c)
            || $crate::meta_char!($c)
    };
}

#[macro_export]
macro_rules! semicolon_char {
    ($c: expr) => {
        $c == ';'
    };
}

#[macro_export]
macro_rules! sign_char {
    ($c: expr) => {
        $c == '-' || $c == '+'
    };
}

#[macro_export]
macro_rules! single_quote_char {
    ($c: expr) => {
        $c == '\''
    };
}

#[macro_export]
macro_rules! small_letter_char {
    ($c: expr) => {
        $c.is_alphabetic() && !$c.is_uppercase()
    };
}

#[macro_export]
macro_rules! solo_char {
    ($c: expr) => {
        $crate::char_class!($c, ['!', '(', ')', ',', ';', '[', ']', '{', '}', '|', '%'])
    };
}

#[macro_export]
macro_rules! space_char {
    ($c: expr) => {
        $c == ' '
    };
}

#[macro_export]
macro_rules! symbolic_control_char {
    ($c: expr) => {
        $crate::char_class!($c, ['a', 'b', 'f', 'n', 'r', 't', 'v', '0'])
    };
}

#[macro_export]
macro_rules! symbolic_hexadecimal_char {
    ($c: expr) => {
        $c == 'x'
    };
}

#[macro_export]
macro_rules! variable_indicator_char {
    ($c: expr) => {
        $c == '_'
    };
}
<|endoftext|>


<commit_before>use std::result::Result;

use super::ModuleError;
use storage::backend::{StorageBackend, StorageBackendError};

type CommandError = Result<ModuleError, StorageBackendError>;
type CommandResult = Result<(), Result<ModuleError, CommandError>>;

pub trait ExecutableCommand {
    fn get_callname() -> &'static str;
    fn exec(&self, rt: &Runtime, s: StorageBackend) -> CommandResult;
}
<commit_msg>Make these types public<commit_after>use std::result::Result;

use super::ModuleError;
use storage::backend::{StorageBackend, StorageBackendError};

pub type CommandError = Result<ModuleError, StorageBackendError>;
pub type CommandResult = Result<(), Result<ModuleError, CommandError>>;

pub trait ExecutableCommand {
    fn get_callname() -> &'static str;
    fn exec(&self, rt: &Runtime, s: StorageBackend) -> CommandResult;
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::hash_map::{
    Vacant,
    Occupied,
};
use std::default::Default;
use std::rand::distributions::{Sample, Range};
use std::cmp::{Less, Equal, Greater};
use std::fmt::{Formatter, FormatError, Show};
use std::rand::{task_rng, Rng, Rand};

use irc::IrcMessage;

use command_mapper::{
    RustBotPlugin,
    CommandMapperDispatch,
    IrcBotConfigurator,
    Format,
};
use state::{
    BotChannelId,
    BotUserId,
    KnownChannel,
    KnownUser,
};

type ScorePrefix = [u8, ..6];
type ScoreRec = (uint, ScorePrefix, int);

pub static SCORING_TABLE: [ScoreRec, ..28] = [
    (6, [1, 2, 3, 4, 5, 6], 1200),
    (6, [2, 2, 3, 3, 4, 4],  800),
    (6, [1, 1, 1, 1, 1, 1], 8000),
    (5, [1, 1, 1, 1, 1, 0], 4000),
    (4, [1, 1, 1, 1, 0, 0], 2000),
    (3, [1, 1, 1, 0, 0, 0], 1000),
    (1, [1, 0, 0, 0, 0, 0],  100),
    (6, [2, 2, 2, 2, 2, 2], 1600),
    (5, [2, 2, 2, 2, 2, 0],  800),
    (4, [2, 2, 2, 2, 0, 0],  400),
    (3, [2, 2, 2, 0, 0, 0],  200),
    (6, [3, 3, 3, 3, 3, 3], 2400),
    (5, [3, 3, 3, 3, 3, 0], 1200),
    (4, [3, 3, 3, 3, 0, 0],  600),
    (3, [3, 3, 3, 0, 0, 0],  300),
    (6, [4, 4, 4, 4, 4, 4], 3200),
    (5, [4, 4, 4, 4, 4, 0], 1600),
    (4, [4, 4, 4, 4, 0, 0],  800),
    (3, [4, 4, 4, 0, 0, 0],  400),
    (6, [5, 5, 5, 5, 5, 5], 4000),
    (5, [5, 5, 5, 5, 5, 0], 2000),
    (4, [5, 5, 5, 5, 0, 0], 1000),
    (3, [5, 5, 5, 0, 0, 0],  500),
    (1, [5, 0, 0, 0, 0, 0],   50),
    (6, [6, 6, 6, 6, 6, 6], 4800),
    (5, [6, 6, 6, 6, 6, 0], 2400),
    (4, [6, 6, 6, 6, 0, 0], 1200),
    (3, [6, 6, 6, 0, 0, 0],  600),
];

struct RollResult([u8, ..6]);

#[inline]
fn is_prefix(rec: &ScoreRec, roll_res: &RollResult, start_idx: uint) -> bool {
    let RollResult(ref roll_data) = *roll_res;
    let (prefix_len, ref roll_target, _) = *rec;

    if roll_data.len() < start_idx + prefix_len {
        return false;
    }
    for idx in range(0, prefix_len) {
        if roll_data[idx + start_idx] != roll_target[idx] {
            return false;
        }
    }
    true
}

impl RollResult {
    fn get_scores(&self) -> Vec<&'static ScoreRec> {
        let RollResult(ref roll) = *self;
        let mut idx = 0;
        let mut score_comps = Vec::new();
        while idx < roll.len() {
            let mut idx_incr = 1;
            for score_rec in SCORING_TABLE.iter() {
                if is_prefix(score_rec, self, idx) {
                    let (prefix_len, _, _) = *score_rec;
                    idx_incr = prefix_len;
                    score_comps.push(score_rec);
                    break;
                }
            }
            idx += idx_incr;
        }
        score_comps
    }

    fn total_score(&self) -> int {
        let mut sum = 0;
        for score in self.get_scores().iter() {
            let (_, _, score_val) = **score;
            sum += score_val;
        }
        sum
    }

    fn format_score_component_bare(score_pref: &ScorePrefix) -> String {
        let mut rolls = String::new();
        for value in score_pref.iter() {
            if *value == 0 {
                break
            }
            rolls.push_str(format!("{}, ", value).as_slice());
        }
        rolls.pop(); rolls.pop();
        format!("{}", rolls.as_slice())
    }

    fn format_score_component(score_components: &ScoreRec) -> String {
        let (_, ref prefix_data, _) = *score_components;
        RollResult::format_score_component_bare(prefix_data)
    }

    fn format_score(score_components: &Vec<&ScoreRec>) -> String {
        let mut output = String::new();
        for tuple in score_components.iter() {
            let (_, _, score) = **tuple;
            output.push_str(format!(
                "[{} => {}], ",
                RollResult::format_score_component(*tuple).as_slice(),
                score
            ).as_slice());
        }
        output.pop(); output.pop();
        output
    }
}

impl Rand for RollResult {
    fn rand<R: Rng>(rng: &mut R) -> RollResult {
        let mut out: ScorePrefix = [0u8, ..6];
        let mut between = Range::new(1u8, 7u8);
        for val in out.iter_mut() {
            *val = between.sample(rng);
        }
        out.sort();
        RollResult(out)
    }
}

impl Show for RollResult {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> {
        let RollResult(ref roll) = *self;
        write!(f, "[{}] => [{}] for {} points",
            RollResult::format_score_component_bare(roll),
            RollResult::format_score(&self.get_scores()),
            self.total_score())
    }
}

pub struct GreedPlugin {
    games: HashMap<BotChannelId, GreedPlayResult>,
    userstats: HashMap<BotUserId, UserStats>,
}

enum GreedCommandType {
    Greed,
    GreedStats
}

struct GreedPlayResult {
    user_id: BotUserId,
    user_nick: String,
    roll: RollResult,
}

fn parse_command<'a>(m: &CommandMapperDispatch) -> Option<GreedCommandType> {
    let command_phrase = match m.command() {
        Some(command_phrase) => command_phrase,
        None => return None
    };
    match command_phrase.command[] {
        "greed" => Some(Greed),
        "greed-stats" => Some(GreedStats),
        _ => None
    }
}

struct UserStats {
    games: uint,
    wins: uint,
    score_sum: uint,
    opponent_score_sum: uint
}

impl Default for UserStats {
    fn default() -> UserStats {
        UserStats {
            games: 0,
            wins: 0,
            score_sum: 0,
            opponent_score_sum: 0,
        }
    }
}

impl Show for UserStats {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> {
        write!(f, "{} wins over {} games; net score {}",
            self.wins, self.games, self.score_sum - self.opponent_score_sum)
    }
}

impl GreedPlugin {
    pub fn new() -> GreedPlugin {
        GreedPlugin {
            games: HashMap::new(),
            userstats: HashMap::new(),
        }
    }

    pub fn get_plugin_name() -> &'static str {
        "greed"
    }

    fn dispatch_cmd_greed_stats(&mut self, m: &CommandMapperDispatch, message: &IrcMessage) {
        let user_id = match m.source {
            Some(KnownUser(uid)) => uid,
            _ => return
        };
        let source_nick = match message.source_nick() {
            Some(nickname) => nickname,
            None => return
        };
        m.reply(match self.userstats.get(&user_id) {
            Some(stats) => format!("{}: {}", source_nick, stats),
            None => format!("{}: You haven't played any games yet", source_nick)
        })
    }

    fn dispatch_cmd_greed(&mut self, m: &CommandMapperDispatch, message: &IrcMessage) {
        let (user_id, channel_id) = match (m.source.clone(), m.target.clone()) {
            (Some(KnownUser(uid)), Some(KnownChannel(cid))) => (uid, cid),
            _ => return
        };

        let source_nick = match message.source_nick() {
            Some(nickname) => nickname,
            None => return
        };

        match self.games.entry(channel_id) {
            Vacant(entry) => {
                let roll = task_rng().gen::<RollResult>();
                m.reply(format!("{}: {}", source_nick, roll));
                entry.set(GreedPlayResult {
                    user_id: user_id,
                    user_nick: source_nick.to_string(),
                    roll: roll
                });
                return;
            },
            Occupied(entry) => {
                {
                    let prev_play = entry.get();
                    if prev_play.user_id == user_id {
                        m.reply(format!("You can't go twice in a row, {}", source_nick));
                        return;
                    }
                }

                let prev_play = entry.take();
                let roll = task_rng().gen::<RollResult>();
                m.reply(format!("{}: {}", source_nick, roll));

                let prev_play_nick = match m.get_state().resolve_user(prev_play.user_id) {
                    Some(user) => user.get_nick().to_string(),
                    None => format!("{} (deceased)", prev_play.user_nick)
                };

                let prev_play_score = prev_play.roll.total_score() as uint;
                let cur_play_score = roll.total_score() as uint;
                let cmp_result = prev_play_score.cmp(&cur_play_score);

                let (prev_user_wins, cur_user_wins) = match cmp_result {
                    Less => (0, 1),
                    Equal => (0, 0),
                    Greater => (1, 0)
                };
                m.reply(match cmp_result {
                     Less => format!("{} wins!", source_nick),
                     Equal => format!("{} and {} tie.", source_nick, prev_play_nick),
                     Greater => format!("{} wins!", prev_play_nick)
                });
                {
                    let cur_user = match self.userstats.entry(user_id) {
                        Occupied(entry) => entry.into_mut(),
                        Vacant(entry) => entry.set(Default::default())
                    };
                    cur_user.games += 1;
                    cur_user.wins += cur_user_wins;
                    cur_user.score_sum += cur_play_score;
                    cur_user.opponent_score_sum += prev_play_score;
                }
                {
                    let prev_user = match self.userstats.entry(user_id) {
                        Occupied(entry) => entry.into_mut(),
                        Vacant(entry) => entry.set(Default::default())
                    };
                    prev_user.games += 1;
                    prev_user.wins += prev_user_wins;
                    prev_user.score_sum += prev_play_score;
                    prev_user.opponent_score_sum += cur_play_score;
                }
            }
        }
    }
}

impl RustBotPlugin for GreedPlugin {
    fn configure(&mut self, conf: &mut IrcBotConfigurator) {
        conf.map_format(Format::from_str("greed").unwrap());
        conf.map_format(Format::from_str("greed-stats").unwrap());
    }

    fn dispatch_cmd(&mut self, m: &CommandMapperDispatch, message: &IrcMessage) {
        match parse_command(m) {
            Some(Greed) => self.dispatch_cmd_greed(m, message),
            Some(GreedStats) => self.dispatch_cmd_greed_stats(m, message),
            None => ()
        }
    }
}
<commit_msg>Negative net scores..<commit_after>use std::collections::HashMap;
use std::collections::hash_map::{
    Vacant,
    Occupied,
};
use std::default::Default;
use std::rand::distributions::{Sample, Range};
use std::cmp::{Less, Equal, Greater};
use std::fmt::{Formatter, FormatError, Show};
use std::rand::{task_rng, Rng, Rand};

use irc::IrcMessage;

use command_mapper::{
    RustBotPlugin,
    CommandMapperDispatch,
    IrcBotConfigurator,
    Format,
};
use state::{
    BotChannelId,
    BotUserId,
    KnownChannel,
    KnownUser,
};

type ScorePrefix = [u8, ..6];
type ScoreRec = (uint, ScorePrefix, int);

pub static SCORING_TABLE: [ScoreRec, ..28] = [
    (6, [1, 2, 3, 4, 5, 6], 1200),
    (6, [2, 2, 3, 3, 4, 4],  800),
    (6, [1, 1, 1, 1, 1, 1], 8000),
    (5, [1, 1, 1, 1, 1, 0], 4000),
    (4, [1, 1, 1, 1, 0, 0], 2000),
    (3, [1, 1, 1, 0, 0, 0], 1000),
    (1, [1, 0, 0, 0, 0, 0],  100),
    (6, [2, 2, 2, 2, 2, 2], 1600),
    (5, [2, 2, 2, 2, 2, 0],  800),
    (4, [2, 2, 2, 2, 0, 0],  400),
    (3, [2, 2, 2, 0, 0, 0],  200),
    (6, [3, 3, 3, 3, 3, 3], 2400),
    (5, [3, 3, 3, 3, 3, 0], 1200),
    (4, [3, 3, 3, 3, 0, 0],  600),
    (3, [3, 3, 3, 0, 0, 0],  300),
    (6, [4, 4, 4, 4, 4, 4], 3200),
    (5, [4, 4, 4, 4, 4, 0], 1600),
    (4, [4, 4, 4, 4, 0, 0],  800),
    (3, [4, 4, 4, 0, 0, 0],  400),
    (6, [5, 5, 5, 5, 5, 5], 4000),
    (5, [5, 5, 5, 5, 5, 0], 2000),
    (4, [5, 5, 5, 5, 0, 0], 1000),
    (3, [5, 5, 5, 0, 0, 0],  500),
    (1, [5, 0, 0, 0, 0, 0],   50),
    (6, [6, 6, 6, 6, 6, 6], 4800),
    (5, [6, 6, 6, 6, 6, 0], 2400),
    (4, [6, 6, 6, 6, 0, 0], 1200),
    (3, [6, 6, 6, 0, 0, 0],  600),
];

struct RollResult([u8, ..6]);

#[inline]
fn is_prefix(rec: &ScoreRec, roll_res: &RollResult, start_idx: uint) -> bool {
    let RollResult(ref roll_data) = *roll_res;
    let (prefix_len, ref roll_target, _) = *rec;

    if roll_data.len() < start_idx + prefix_len {
        return false;
    }
    for idx in range(0, prefix_len) {
        if roll_data[idx + start_idx] != roll_target[idx] {
            return false;
        }
    }
    true
}

impl RollResult {
    fn get_scores(&self) -> Vec<&'static ScoreRec> {
        let RollResult(ref roll) = *self;
        let mut idx = 0;
        let mut score_comps = Vec::new();
        while idx < roll.len() {
            let mut idx_incr = 1;
            for score_rec in SCORING_TABLE.iter() {
                if is_prefix(score_rec, self, idx) {
                    let (prefix_len, _, _) = *score_rec;
                    idx_incr = prefix_len;
                    score_comps.push(score_rec);
                    break;
                }
            }
            idx += idx_incr;
        }
        score_comps
    }

    fn total_score(&self) -> int {
        let mut sum = 0;
        for score in self.get_scores().iter() {
            let (_, _, score_val) = **score;
            sum += score_val;
        }
        sum
    }

    fn format_score_component_bare(score_pref: &ScorePrefix) -> String {
        let mut rolls = String::new();
        for value in score_pref.iter() {
            if *value == 0 {
                break
            }
            rolls.push_str(format!("{}, ", value).as_slice());
        }
        rolls.pop(); rolls.pop();
        format!("{}", rolls.as_slice())
    }

    fn format_score_component(score_components: &ScoreRec) -> String {
        let (_, ref prefix_data, _) = *score_components;
        RollResult::format_score_component_bare(prefix_data)
    }

    fn format_score(score_components: &Vec<&ScoreRec>) -> String {
        let mut output = String::new();
        for tuple in score_components.iter() {
            let (_, _, score) = **tuple;
            output.push_str(format!(
                "[{} => {}], ",
                RollResult::format_score_component(*tuple).as_slice(),
                score
            ).as_slice());
        }
        output.pop(); output.pop();
        output
    }
}

impl Rand for RollResult {
    fn rand<R: Rng>(rng: &mut R) -> RollResult {
        let mut out: ScorePrefix = [0u8, ..6];
        let mut between = Range::new(1u8, 7u8);
        for val in out.iter_mut() {
            *val = between.sample(rng);
        }
        out.sort();
        RollResult(out)
    }
}

impl Show for RollResult {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> {
        let RollResult(ref roll) = *self;
        write!(f, "[{}] => [{}] for {} points",
            RollResult::format_score_component_bare(roll),
            RollResult::format_score(&self.get_scores()),
            self.total_score())
    }
}

pub struct GreedPlugin {
    games: HashMap<BotChannelId, GreedPlayResult>,
    userstats: HashMap<BotUserId, UserStats>,
}

enum GreedCommandType {
    Greed,
    GreedStats
}

struct GreedPlayResult {
    user_id: BotUserId,
    user_nick: String,
    roll: RollResult,
}

fn parse_command<'a>(m: &CommandMapperDispatch) -> Option<GreedCommandType> {
    let command_phrase = match m.command() {
        Some(command_phrase) => command_phrase,
        None => return None
    };
    match command_phrase.command[] {
        "greed" => Some(Greed),
        "greed-stats" => Some(GreedStats),
        _ => None
    }
}

struct UserStats {
    games: uint,
    wins: uint,
    score_sum: int,
    opponent_score_sum: int
}

impl Default for UserStats {
    fn default() -> UserStats {
        UserStats {
            games: 0,
            wins: 0,
            score_sum: 0,
            opponent_score_sum: 0,
        }
    }
}

impl Show for UserStats {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> {
        write!(f, "{} wins over {} games; net score {}",
            self.wins, self.games, self.score_sum - self.opponent_score_sum)
    }
}

impl GreedPlugin {
    pub fn new() -> GreedPlugin {
        GreedPlugin {
            games: HashMap::new(),
            userstats: HashMap::new(),
        }
    }

    pub fn get_plugin_name() -> &'static str {
        "greed"
    }

    fn dispatch_cmd_greed_stats(&mut self, m: &CommandMapperDispatch, message: &IrcMessage) {
        let user_id = match m.source {
            Some(KnownUser(uid)) => uid,
            _ => return
        };
        let source_nick = match message.source_nick() {
            Some(nickname) => nickname,
            None => return
        };
        m.reply(match self.userstats.get(&user_id) {
            Some(stats) => format!("{}: {}", source_nick, stats),
            None => format!("{}: You haven't played any games yet", source_nick)
        })
    }

    fn dispatch_cmd_greed(&mut self, m: &CommandMapperDispatch, message: &IrcMessage) {
        let (user_id, channel_id) = match (m.source.clone(), m.target.clone()) {
            (Some(KnownUser(uid)), Some(KnownChannel(cid))) => (uid, cid),
            _ => return
        };

        let source_nick = match message.source_nick() {
            Some(nickname) => nickname,
            None => return
        };

        match self.games.entry(channel_id) {
            Vacant(entry) => {
                let roll = task_rng().gen::<RollResult>();
                m.reply(format!("{}: {}", source_nick, roll));
                entry.set(GreedPlayResult {
                    user_id: user_id,
                    user_nick: source_nick.to_string(),
                    roll: roll
                });
                return;
            },
            Occupied(entry) => {
                {
                    let prev_play = entry.get();
                    if prev_play.user_id == user_id {
                        m.reply(format!("You can't go twice in a row, {}", source_nick));
                        return;
                    }
                }

                let prev_play = entry.take();
                let roll = task_rng().gen::<RollResult>();
                m.reply(format!("{}: {}", source_nick, roll));

                let prev_play_nick = match m.get_state().resolve_user(prev_play.user_id) {
                    Some(user) => user.get_nick().to_string(),
                    None => format!("{} (deceased)", prev_play.user_nick)
                };

                let prev_play_score = prev_play.roll.total_score();
                let cur_play_score = roll.total_score();
                let cmp_result = prev_play_score.cmp(&cur_play_score);

                let (prev_user_wins, cur_user_wins) = match cmp_result {
                    Less => (0, 1),
                    Equal => (0, 0),
                    Greater => (1, 0)
                };
                m.reply(match cmp_result {
                     Less => format!("{} wins!", source_nick),
                     Equal => format!("{} and {} tie.", source_nick, prev_play_nick),
                     Greater => format!("{} wins!", prev_play_nick)
                });
                {
                    let cur_user = match self.userstats.entry(user_id) {
                        Occupied(entry) => entry.into_mut(),
                        Vacant(entry) => entry.set(Default::default())
                    };
                    cur_user.games += 1;
                    cur_user.wins += cur_user_wins;
                    cur_user.score_sum += cur_play_score;
                    cur_user.opponent_score_sum += prev_play_score;
                }
                {
                    let prev_user = match self.userstats.entry(user_id) {
                        Occupied(entry) => entry.into_mut(),
                        Vacant(entry) => entry.set(Default::default())
                    };
                    prev_user.games += 1;
                    prev_user.wins += prev_user_wins;
                    prev_user.score_sum += prev_play_score;
                    prev_user.opponent_score_sum += cur_play_score;
                }
            }
        }
    }
}

impl RustBotPlugin for GreedPlugin {
    fn configure(&mut self, conf: &mut IrcBotConfigurator) {
        conf.map_format(Format::from_str("greed").unwrap());
        conf.map_format(Format::from_str("greed-stats").unwrap());
    }

    fn dispatch_cmd(&mut self, m: &CommandMapperDispatch, message: &IrcMessage) {
        match parse_command(m) {
            Some(Greed) => self.dispatch_cmd_greed(m, message),
            Some(GreedStats) => self.dispatch_cmd_greed_stats(m, message),
            None => ()
        }
    }
}
<|endoftext|>


<commit_before>use std::ops::{Mul, Add};

extern crate nalgebra;
use self::nalgebra::{DMat, Transpose};

extern crate rand;
use self::rand::{Rand};

extern crate num;
use self::num::{Float, Zero, FromPrimitive};

pub struct OrthogonalNMF<FloatT> {
    // TODO add docstrings
    pub hidden: DMat<FloatT>,
    pub weights: DMat<FloatT>,
    pub iteration: usize,
}

impl<FloatT: Rand + Float + FromPrimitive + Mul + Zero> OrthogonalNMF<FloatT> {
    pub fn init_randomly(nhidden: usize, nobserved: usize, nsamples: usize) -> OrthogonalNMF<FloatT> {
        OrthogonalNMF {
            hidden: DMat::new_random(nhidden, nobserved),
            weights: DMat::new_random(nsamples, nhidden),
            iteration: 0,
        }
    }

    // TODO initialize with values from last time step t-1 instead of choosing randomly
    pub fn init(hidden: DMat<FloatT>, weights: DMat<FloatT>) -> OrthogonalNMF<FloatT> {
        OrthogonalNMF {
            hidden: hidden,
            weights: weights,
            iteration: 0,
        }
    }

    // TODO how many iterations ?
    // TODO compare this to the seoung solution
    /// it gets better and better with each iteration.
    /// one observed per column.
    /// one sample per row.
    pub fn iterate(&mut self, data: &DMat<FloatT>) {
        let nhidden = self.hidden.nrows();
        let nobserved = self.hidden.ncols();
        let nsamples = self.weights.nrows();
        assert_eq!(nsamples, data.nrows());
        assert_eq!(nobserved, data.ncols());

        let alpha: FloatT =
            FloatT::from_f32(0.1).unwrap() *
            FloatT::from_f32(1.01).unwrap().powi(self.iteration as i32);

        let hidden_transposed = self.hidden.transpose();
        let weights_transposed = self.weights.transpose();

        let new_weights_dividend = data.clone().mul(&hidden_transposed);
        let new_weights_divisor = self.weights.clone().mul(&self.hidden).mul(&hidden_transposed);

        let new_hidden_dividend = weights_transposed.clone().mul(data);

        // gamma is a symetric matrix with diagonal elements equal to zero
        // and other elements = alpha
        let gamma_size = nhidden;
        let mut gamma = DMat::from_elem(gamma_size, gamma_size, alpha);

        // set diagonal to zero
        for i in 0..gamma_size {
            gamma[(i, i)] = FloatT::zero();
        }

        let new_hidden_divisor = weights_transposed.clone()
            .mul(&self.weights)
            .mul(&self.hidden)
            // we add the previous latents
            // multiplied by alpha except for the diag which is set to zero
            .add(gamma.mul(&self.hidden));

        // compute new weights
        // TODO efficient order ?
        for col in 0..self.weights.ncols() {
            for row in 0..self.weights.nrows() {
                let index = (row, col);
                self.weights[index] =
                    self.weights[index] *
                    new_weights_dividend[index] /
                    // these get larger and larger
                    new_weights_divisor[index];
            }
        }

        // compute new hidden
        // TODO efficient order ?
        for col in 0..self.hidden.ncols() {
            for row in 0..self.hidden.nrows() {
                let index = (row, col);
                self.hidden[index] =
                    self.hidden[index] *
                    new_hidden_dividend[index] /
                    new_hidden_divisor[index];
            }
        }
    }
}
<commit_msg>ortho nmf: some debugging and fix that iteration is counted up<commit_after>use std::ops::{Mul, Add};

use std::fmt::{Display};

extern crate nalgebra;
use self::nalgebra::{DMat, Transpose};

extern crate rand;
use self::rand::{Rand};

extern crate num;
use self::num::{Float, Zero, FromPrimitive};

pub struct OrthogonalNMF<FloatT> {
    // TODO add docstrings
    pub hidden: DMat<FloatT>,
    pub weights: DMat<FloatT>,
    pub iteration: usize,
}

impl<FloatT: Rand + Float + FromPrimitive + Mul + Zero + Display> OrthogonalNMF<FloatT> {
    pub fn init_randomly(nhidden: usize, nobserved: usize, nsamples: usize) -> OrthogonalNMF<FloatT> {
        OrthogonalNMF {
            hidden: DMat::new_random(nhidden, nobserved),
            weights: DMat::new_random(nsamples, nhidden),
            iteration: 0,
        }
    }

    // TODO initialize with values from last time step t-1 instead of choosing randomly
    pub fn init(hidden: DMat<FloatT>, weights: DMat<FloatT>) -> OrthogonalNMF<FloatT> {
        OrthogonalNMF {
            hidden: hidden,
            weights: weights,
            iteration: 0,
        }
    }

    // TODO how many iterations ?
    // TODO compare this to the seoung solution
    /// it gets better and better with each iteration.
    /// one observed per column.
    /// one sample per row.
    pub fn iterate(&mut self, data: &DMat<FloatT>) {
        let nhidden = self.hidden.nrows();
        let nobserved = self.hidden.ncols();
        let nsamples = self.weights.nrows();
        assert_eq!(nsamples, data.nrows());
        assert_eq!(nobserved, data.ncols());

        // this gets smaller and smaller with each iteration
        let alpha: FloatT =
            FloatT::from_f32(0.1).unwrap() *
            FloatT::from_f32(1.01).unwrap().powi(self.iteration as i32);

        println!("iteration = {} alpha = {}", self.iteration, alpha);

        let hidden_transposed = self.hidden.transpose();
        let weights_transposed = self.weights.transpose();

        let new_weights_dividend = data.clone().mul(&hidden_transposed);
        let new_weights_divisor = self.weights.clone().mul(&self.hidden).mul(&hidden_transposed);

        let new_hidden_dividend = weights_transposed.clone().mul(data);

        // gamma is a symetric matrix with diagonal elements equal to zero
        // and other elements = alpha
        let gamma_size = nhidden;
        let mut gamma = DMat::from_elem(gamma_size, gamma_size, alpha);

        // set diagonal to zero
        for i in 0..gamma_size {
            gamma[(i, i)] = FloatT::zero();
        }

        let new_hidden_divisor = weights_transposed.clone()
            .mul(&self.weights)
            .mul(&self.hidden)
            // we add the previous latents
            // multiplied by alpha except for the diag which is set to zero
            .add(gamma.mul(&self.hidden));

        // compute new weights
        // TODO efficient order ?
        for col in 0..self.weights.ncols() {
            for row in 0..self.weights.nrows() {
                let index = (row, col);
                self.weights[index] =
                    self.weights[index] *
                    new_weights_dividend[index] /
                    // these get larger and larger
                    new_weights_divisor[index];
            }
        }

        // compute new hidden
        // TODO efficient order ?
        for col in 0..self.hidden.ncols() {
            for row in 0..self.hidden.nrows() {
                let index = (row, col);
                self.hidden[index] =
                    self.hidden[index] *
                    new_hidden_dividend[index] /
                    new_hidden_divisor[index];
            }
        }

        self.iteration += 1;
    }
}
<|endoftext|>


<commit_before>use backend::Backend;
use provider::error;
use provider::Provider;
use provider::Output;
use libc::{c_char, uint32_t};
use std::ffi::CString;

pub struct File<'a> {
    name: &'static str,
    backend: &'a Backend,
    provider: &'a Provider,
}

impl<'a> File<'a> {
    pub fn new(n: &'static str, b: &'a Backend, p: &'a Provider) -> File<'a> {
        File {
            name: n,
            backend: b,
            provider: p,
        }
    }

    pub fn mode(&self) -> Result<u32, error::Error> {
        self.backend
            .handle(self.provider.file.mode(self.name))
            .and_then(Output::to_u32)
    }

    pub fn size(&self) -> Result<i64, error::Error> {
        self.backend
            .handle(self.provider.file.size(self.name))
            .and_then(Output::to_i64)
    }

    pub fn is_file(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_file(self.name))
            .and_then(Output::to_bool)
    }

    pub fn exist(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.exist(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_directory(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_directory(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_block_device(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_block_device(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_character_device(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_character_device(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_pipe(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_pipe(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_socket(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_socket(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_symlink(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_symlink(self.name))
            .and_then(Output::to_bool)
    }

    pub fn contents(&self) -> Result<String, error::Error> {
        self.backend
            .handle(self.provider.file.contents(self.name))
            .and_then(Output::to_string)
    }

    pub fn owner(&self) -> Result<String, error::Error> {
        self.backend
            .handle(self.provider.file.owner(self.name))
            .and_then(Output::to_string)
    }

    pub fn group(&self) -> Result<String, error::Error> {
        self.backend
            .handle(self.provider.file.group(self.name))
            .and_then(Output::to_string)
    }

    pub fn linked_to(&self) -> Result<String, error::Error> {
        self.backend
            .handle(self.provider.file.linked_to(self.name))
            .and_then(Output::to_string)
    }

    pub fn is_readable(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_readable(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_readable_by_owner(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_readable_by_owner(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_readable_by_group(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_readable_by_group(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_readable_by_others(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_readable_by_others(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_readable_by_user(&self, user: &'static str) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_readable_by_user(self.name, user))
            .and_then(Output::to_bool)
    }

    pub fn is_writable(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_writable(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_writable_by_owner(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_writable_by_owner(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_writable_by_group(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_writable_by_group(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_writable_by_others(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_writable_by_others(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_writable_by_user(&self, user: &'static str) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_writable_by_user(self.name, user))
            .and_then(Output::to_bool)
    }

    pub fn md5sum(&self) -> Result<String, error::Error> {
        self.backend
            .handle(self.provider.file.md5sum(self.name))
            .and_then(Output::to_string)
    }

    pub fn sha256sum(&self) -> Result<String, error::Error> {
        self.backend
            .handle(self.provider.file.sha256sum(self.name))
            .and_then(Output::to_string)
    }
}

// Wrapper functions for FFI

#[no_mangle]
pub extern "C" fn resource_file_free(ptr: *mut File) {
    if ptr.is_null() {
        return;
    }
    unsafe {
        Box::from_raw(ptr);
    }
}

#[no_mangle]
pub extern "C" fn resource_file_mode(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    f.mode().unwrap()
}

#[no_mangle]
pub extern "C" fn resource_file_is_file(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_file().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_exist(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.exist().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_is_directory(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_directory().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_is_block_device(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_block_device().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_is_character_device(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_character_device().unwrap() {
        1
    } else {
        0
    }
}

#[no_mangle]
pub extern "C" fn resource_file_is_pipe(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_pipe().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_is_socket(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_socket().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_is_symlink(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_symlink().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_contents(ptr: *const File) -> *mut c_char {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };
    let c = f.contents().unwrap();
    CString::new(c).unwrap().into_raw()
}

#[no_mangle]
pub extern "C" fn resource_file_owner(ptr: *const File) -> *mut c_char {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };
    let c = f.owner().unwrap();
    CString::new(c).unwrap().into_raw()
}

#[no_mangle]
pub extern "C" fn resource_file_group(ptr: *const File) -> *mut c_char {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };
    let c = f.group().unwrap();
    CString::new(c).unwrap().into_raw()
}
<commit_msg>Add wrapper functions for file.is_readable() and so on<commit_after>use backend::Backend;
use provider::error;
use provider::Provider;
use provider::Output;
use libc::{c_char, uint32_t};
use std::ffi::CString;

pub struct File<'a> {
    name: &'static str,
    backend: &'a Backend,
    provider: &'a Provider,
}

impl<'a> File<'a> {
    pub fn new(n: &'static str, b: &'a Backend, p: &'a Provider) -> File<'a> {
        File {
            name: n,
            backend: b,
            provider: p,
        }
    }

    pub fn mode(&self) -> Result<u32, error::Error> {
        self.backend
            .handle(self.provider.file.mode(self.name))
            .and_then(Output::to_u32)
    }

    pub fn size(&self) -> Result<i64, error::Error> {
        self.backend
            .handle(self.provider.file.size(self.name))
            .and_then(Output::to_i64)
    }

    pub fn is_file(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_file(self.name))
            .and_then(Output::to_bool)
    }

    pub fn exist(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.exist(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_directory(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_directory(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_block_device(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_block_device(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_character_device(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_character_device(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_pipe(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_pipe(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_socket(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_socket(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_symlink(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_symlink(self.name))
            .and_then(Output::to_bool)
    }

    pub fn contents(&self) -> Result<String, error::Error> {
        self.backend
            .handle(self.provider.file.contents(self.name))
            .and_then(Output::to_string)
    }

    pub fn owner(&self) -> Result<String, error::Error> {
        self.backend
            .handle(self.provider.file.owner(self.name))
            .and_then(Output::to_string)
    }

    pub fn group(&self) -> Result<String, error::Error> {
        self.backend
            .handle(self.provider.file.group(self.name))
            .and_then(Output::to_string)
    }

    pub fn linked_to(&self) -> Result<String, error::Error> {
        self.backend
            .handle(self.provider.file.linked_to(self.name))
            .and_then(Output::to_string)
    }

    pub fn is_readable(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_readable(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_readable_by_owner(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_readable_by_owner(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_readable_by_group(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_readable_by_group(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_readable_by_others(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_readable_by_others(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_readable_by_user(&self, user: &'static str) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_readable_by_user(self.name, user))
            .and_then(Output::to_bool)
    }

    pub fn is_writable(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_writable(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_writable_by_owner(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_writable_by_owner(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_writable_by_group(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_writable_by_group(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_writable_by_others(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_writable_by_others(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_writable_by_user(&self, user: &'static str) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_writable_by_user(self.name, user))
            .and_then(Output::to_bool)
    }

    pub fn md5sum(&self) -> Result<String, error::Error> {
        self.backend
            .handle(self.provider.file.md5sum(self.name))
            .and_then(Output::to_string)
    }

    pub fn sha256sum(&self) -> Result<String, error::Error> {
        self.backend
            .handle(self.provider.file.sha256sum(self.name))
            .and_then(Output::to_string)
    }
}

// Wrapper functions for FFI

#[no_mangle]
pub extern "C" fn resource_file_free(ptr: *mut File) {
    if ptr.is_null() {
        return;
    }
    unsafe {
        Box::from_raw(ptr);
    }
}

#[no_mangle]
pub extern "C" fn resource_file_mode(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    f.mode().unwrap()
}

#[no_mangle]
pub extern "C" fn resource_file_is_file(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_file().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_exist(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.exist().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_is_directory(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_directory().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_is_block_device(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_block_device().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_is_character_device(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_character_device().unwrap() {
        1
    } else {
        0
    }
}

#[no_mangle]
pub extern "C" fn resource_file_is_pipe(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_pipe().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_is_socket(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_socket().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_is_symlink(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_symlink().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_contents(ptr: *const File) -> *mut c_char {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };
    let c = f.contents().unwrap();
    CString::new(c).unwrap().into_raw()
}

#[no_mangle]
pub extern "C" fn resource_file_owner(ptr: *const File) -> *mut c_char {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };
    let c = f.owner().unwrap();
    CString::new(c).unwrap().into_raw()
}

#[no_mangle]
pub extern "C" fn resource_file_group(ptr: *const File) -> *mut c_char {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };
    let c = f.group().unwrap();
    CString::new(c).unwrap().into_raw()
}

#[no_mangle]
pub extern "C" fn resource_file_is_readable(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_readable().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_is_readable_by_owner(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_readable_by_owner().unwrap() {
        1
    } else {
        0
    }
}

#[no_mangle]
pub extern "C" fn resource_file_is_readable_by_group(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_readable_by_group().unwrap() {
        1
    } else {
        0
    }
}
<|endoftext|>


<commit_before>use std::fmt::Debug;

pub mod base;
use self::base::literals;

use lexer::{
    Token,
    TokenType,
};

use parser::block_tree::{
    Branch,
    ChunkContent,
};

#[derive(Debug, Clone)]
pub enum ASTNode {
    NumberLiteral(literals::NumberLiteral),
    StringLiteral(literals::StringLiteral),
    BooleanLiteral(literals::BooleanLiteral),
}

pub trait ParserNode: Debug {
    fn parse(&self, parser: &mut Parser) -> ASTNode;
}

#[derive(Debug)]
pub struct Parser {
    tokens:     Vec<Token>,
    ast:        Vec<Box<ParserNode>>,
    pub pos:    usize,
}

#[derive(Debug)]
pub enum SignatureKey {
    Only(TokenType),
    Any(Vec<TokenType>),
}

#[derive(Debug)]
pub struct Signature {
    key:  Vec<SignatureKey>,
    node: Box<ParserNode>,
}

impl Signature {
    pub fn new(key: Vec<SignatureKey>, node: Box<ParserNode>) -> Signature {
        Signature {
            key:  key,
            node: node,
        }
    }
}

#[derive(Debug)]
pub struct SignaturePool {
    signatures: Vec<Signature>,
    longest:    usize,
}

pub fn create_pool(signatures: Vec<Signature>) -> SignaturePool {
    // TODO: automate sorting
    SignaturePool {
        signatures: signatures,
        longest:    0,
    }
}

pub fn flatten_branch<'a>(branch: &Branch<'a>) -> Vec<Token> {
    let mut flat: Vec<Token> = Vec::new();

    for chunk in branch.content.iter() {
        match chunk.content {
            ChunkContent::Tokens(ref t)    => flat.append(&mut t.clone()),
            ChunkContent::Block(ref b) => flat.push(
                    Token::new(TokenType::Block(flatten_branch(b)), 0, 0)
                ),
            _                          => (),
        }
    }

    flat
}

impl Parser {
    pub fn new(tokens: Vec<Token>) -> Parser {
        Parser {
            tokens: tokens,
            ast:    Vec::new(),
            pos:    0,
        }
    }

    pub fn parse(mut self, pool: &SignaturePool) -> (Option<ASTNode>, Parser) {
        if self.tokens.len() > 0 {
            for sig in &pool.signatures {
                let len = sig.key.len();

                if self.match_signature(&sig.key, 0) {
                    self.pos += len;

                    return (Some(sig.node.parse(&mut self)), self)
                }
            }
        }

        (None, self)
    }

    // TODO: work in progress
    pub fn expression(&mut self, offset: usize) -> Option<ASTNode> {
        let mut expr_stack: Vec<ASTNode> = Vec::new();

        match self.atom(offset) {
            Some(v) => expr_stack.push(v),
            None    => (),
        }

        Some(expr_stack[0].clone())
    }

    // TODO: work in progress
    pub fn atom(&mut self, offset: usize) -> Option<ASTNode> {

        // number
        if self.match_signature(&vec![
            SignatureKey::Only(TokenType::NumberLiteral(String::from(""))),
        ], offset) {
            let v = match self.get(offset).token_type {
                TokenType::NumberLiteral(v) => v,
                _                           => panic!("todo: make nice errors - number atom")
            };

            return Some(
                ASTNode::NumberLiteral(
                    literals::NumberLiteral::new(
                        v.parse::<f64>().unwrap()
                    )
                )
            )
        }

        // string
        if self.match_signature(&vec![
            SignatureKey::Only(TokenType::StringLiteral(String::from(""))),
        ], offset) {
            let v = match self.get(offset).token_type {
                TokenType::StringLiteral(v) => v,
                _                           => panic!("todo: make nice errors - number atom")
            };

            return Some(
                ASTNode::StringLiteral(literals::StringLiteral::new(v))
            )
        }

        // bool
        if self.match_signature(&vec![
            SignatureKey::Any(
                vec![TokenType::Keyword(String::from("true")), TokenType::Keyword(String::from("false"))]
            ),
        ], offset) {
            let v = match self.get(offset).token_type {
                TokenType::Keyword(v) => v == String::from("true"),

                _ => panic!("todo: make nice errors - boolean atom"),
            };

            return Some(
                ASTNode::BooleanLiteral(literals::BooleanLiteral::new(v))
            )
        }

        None
    }

    pub fn match_signature(&mut self, sequence: &Vec<SignatureKey>, offset: usize) -> bool {
        'seq: for e in sequence {
            let b = self.get(offset).token_type;

            match e {
                &SignatureKey::Only(ref a) => if !match_token(a.clone(), b.clone()) {
                    return false
                },

                &SignatureKey::Any(ref va) => {

                    for a in va.iter() {
                        if match_token(a.clone(), b.clone()) {
                            break 'seq
                        }
                    }

                    return false
                },
            }
        }

        true
    }

    pub fn get(&self, offset: usize) -> Token {
        if self.pos + offset > self.tokens.len() - 1 {
            return Token::new(TokenType::EOF, 0, 0)
        }

        self.tokens[self.pos + offset].clone()
    }

    pub fn get_backward(&self, offset: usize) -> Token {
        self.tokens[self.pos - offset].clone()
    }
}

fn match_token(a: TokenType, b: TokenType) -> bool {
    match a {
        TokenType::Keyword(k) => match b {
            TokenType::Keyword(k1) => {
                if k != k1 {
                    return false
                }
            },

            _ => return false,
        },

        TokenType::Identifier(_) => match b {
            TokenType::Identifier(_) => (),
            _                        => return false,
        },

        TokenType::NumberLiteral(_) => match b {
            TokenType::NumberLiteral(_) => (),
            _                           => return false,
        },

        TokenType::StringLiteral(_) => match b {
            TokenType::StringLiteral(_) => (),
            _                           => return false,
        },

        TokenType::BinaryOp(_) => match b {
            TokenType::BinaryOp(_) => (),
            _                      => return false,
        },

        TokenType::Block(_) => match b {
            TokenType::Block(_) => (),
            _                   => return false,
        },

        s => if s != b {
            return false
        }
    }

    true
}<commit_msg>Fix signature matching<commit_after>use std::fmt::Debug;

pub mod base;
use self::base::literals;

use lexer::{
    Token,
    TokenType,
};

use parser::block_tree::{
    Branch,
    ChunkContent,
};

#[derive(Debug, Clone)]
pub enum ASTNode {
    NumberLiteral(literals::NumberLiteral),
    StringLiteral(literals::StringLiteral),
    BooleanLiteral(literals::BooleanLiteral),
}

pub trait ParserNode: Debug {
    fn parse(&self, parser: &mut Parser) -> ASTNode;
}

#[derive(Debug)]
pub struct Parser {
    tokens:     Vec<Token>,
    ast:        Vec<Box<ParserNode>>,
    pub pos:    usize,
}

#[derive(Debug)]
pub enum SignatureKey {
    Only(TokenType),
    Any(Vec<TokenType>),
}

#[derive(Debug)]
pub struct Signature {
    key:  Vec<SignatureKey>,
    node: Box<ParserNode>,
}

impl Signature {
    pub fn new(key: Vec<SignatureKey>, node: Box<ParserNode>) -> Signature {
        Signature {
            key:  key,
            node: node,
        }
    }
}

#[derive(Debug)]
pub struct SignaturePool {
    signatures: Vec<Signature>,
    longest:    usize,
}

pub fn create_pool(signatures: Vec<Signature>) -> SignaturePool {
    // TODO: automate sorting
    SignaturePool {
        signatures: signatures,
        longest:    0,
    }
}

pub fn flatten_branch<'a>(branch: &Branch<'a>) -> Vec<Token> {
    let mut flat: Vec<Token> = Vec::new();

    for chunk in branch.content.iter() {
        match chunk.content {
            ChunkContent::Tokens(ref t)    => flat.append(&mut t.clone()),
            ChunkContent::Block(ref b) => flat.push(
                    Token::new(TokenType::Block(flatten_branch(b)), 0, 0)
                ),
            _                          => (),
        }
    }

    flat
}

impl Parser {
    pub fn new(tokens: Vec<Token>) -> Parser {
        Parser {
            tokens: tokens,
            ast:    Vec::new(),
            pos:    0,
        }
    }

    pub fn parse(mut self, pool: &SignaturePool) -> (Option<ASTNode>, Parser) {
        if self.tokens.len() > 0 {
            for sig in &pool.signatures {

                if self.match_signature(&sig.key, 0) {
                    return (Some(sig.node.parse(&mut self)), self)
                }
            }
        }

        (None, self)
    }

    // TODO: work in progress
    pub fn expression(&mut self, offset: usize) -> Option<ASTNode> {
        let mut expr_stack: Vec<ASTNode> = Vec::new();

        match self.atom(offset) {
            Some(v) => expr_stack.push(v),
            None    => (),
        }

        Some(expr_stack[0].clone())
    }

    // TODO: work in progress
    pub fn atom(&mut self, offset: usize) -> Option<ASTNode> {

        // number
        if self.match_signature(&vec![
            SignatureKey::Only(TokenType::NumberLiteral(String::from(""))),
        ], offset) {
            let v = match self.get(offset).token_type {
                TokenType::NumberLiteral(v) => v,
                _                           => panic!("todo: make nice errors - number atom")
            };

            return Some(
                ASTNode::NumberLiteral(
                    literals::NumberLiteral::new(
                        v.parse::<f64>().unwrap()
                    )
                )
            )
        }

        // string
        if self.match_signature(&vec![
            SignatureKey::Only(TokenType::StringLiteral(String::from(""))),
        ], offset) {
            let v = match self.get(offset).token_type {
                TokenType::StringLiteral(v) => v,
                _                           => panic!("todo: make nice errors - number atom")
            };

            return Some(
                ASTNode::StringLiteral(literals::StringLiteral::new(v))
            )
        }

        // bool
        if self.match_signature(&vec![
            SignatureKey::Any(
                vec![TokenType::Keyword(String::from("true")), TokenType::Keyword(String::from("false"))]
            ),
        ], offset) {
            let v = match self.get(offset).token_type {
                TokenType::Keyword(v) => v == String::from("true"),

                _ => panic!("todo: make nice errors - boolean atom"),
            };

            return Some(
                ASTNode::BooleanLiteral(literals::BooleanLiteral::new(v))
            )
        }

        None
    }

    pub fn match_signature(&mut self, sequence: &Vec<SignatureKey>, offset: usize) -> bool {
        'seq: for e in sequence {
            let b = self.get(offset).token_type;

            match e {
                &SignatureKey::Only(ref a) => if !match_token(a.clone(), b.clone()) {
                    return false
                },

                &SignatureKey::Any(ref va) => {

                    for a in va.iter() {
                        if match_token(a.clone(), b.clone()) {
                            break 'seq
                        }
                    }

                    return false
                },
            }
        }

        self.pos += sequence.len();

        true
    }

    pub fn get(&self, offset: usize) -> Token {
        if self.pos + offset > self.tokens.len() - 1 {
            return Token::new(TokenType::EOF, 0, 0)
        }

        self.tokens[self.pos + offset].clone()
    }

    pub fn get_backward(&self, offset: usize) -> Token {
        self.tokens[self.pos - offset].clone()
    }
}

fn match_token(a: TokenType, b: TokenType) -> bool {
    match a {
        TokenType::Keyword(k) => match b {
            TokenType::Keyword(k1) => {
                if k != k1 {
                    return false
                }
            },

            _ => return false,
        },

        TokenType::Identifier(_) => match b {
            TokenType::Identifier(_) => (),
            _                        => return false,
        },

        TokenType::NumberLiteral(_) => match b {
            TokenType::NumberLiteral(_) => (),
            _                           => return false,
        },

        TokenType::StringLiteral(_) => match b {
            TokenType::StringLiteral(_) => (),
            _                           => return false,
        },

        TokenType::BinaryOp(_) => match b {
            TokenType::BinaryOp(_) => (),
            _                      => return false,
        },

        TokenType::Block(_) => match b {
            TokenType::Block(_) => (),
            _                   => return false,
        },

        s => if s != b {
            return false
        }
    }

    true
}<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! # Node Builder
//!
//! ```
//! use commands::parser::builder::*;
//!
//! let mut tree = CommandTree::new();
//! tree.command(Command::new("again")
//!                  .hidden(false)
//!                  .parameter(Parameter::new("test")
//!                                 .required(false)
//!                                 .help("This is just a test parameter.")
//!                                 .finalize())
//!                  .finalize());
//! ```

use std::rc::Rc;
use super::nodes::*;

/// Indicate the type of parameter, so that the correct class and node
/// structures are created.
#[derive(Clone)]
pub enum ParameterKind {
    /// This parameter is a `FlagParameter`.
    Flag,
    /// This parameter is a `NamedParameter`.
    Named,
    /// This parameter is a `SimpleParameter`.
    Simple,
}

/// Store a command tree while populating it. This can be used
/// to construct a `RootNode` to be used with the `Parser`.
pub struct CommandTree {
    commands: Vec<Command>,
}

impl CommandTree {
    /// Create a new `CommandTree`.
    pub fn new() -> Self {
        CommandTree { commands: vec![] }
    }

    /// Add a `Command` to the `CommandTree`.
    pub fn command(&mut self, command: Command) {
        self.commands.push(command);
    }

    fn build_parameter(self, parameter: Parameter) -> Rc<Node> {
        match parameter.parameter_kind {
            ParameterKind::Flag => Rc::new(self.build_flag_parameter(parameter)),
            ParameterKind::Named => Rc::new(self.build_named_parameter(parameter)),
            ParameterKind::Simple => Rc::new(self.build_simple_parameter(parameter)),
        }
    }

    fn build_flag_parameter(self, parameter: Parameter) -> FlagParameterNode {
        FlagParameterNode::new(&*parameter.name,
                               parameter.help_text,
                               parameter.hidden,
                               parameter.priority,
                               vec![],
                               parameter.repeatable,
                               None,
                               parameter.required)
    }

    fn build_named_parameter(self, parameter: Parameter) -> NamedParameterNode {
        NamedParameterNode::new(&*parameter.name,
                                parameter.help_text,
                                parameter.hidden,
                                parameter.priority,
                                vec![],
                                parameter.repeatable,
                                None,
                                parameter.required)
    }

    fn build_simple_parameter(self, parameter: Parameter) -> SimpleParameterNode {
        SimpleParameterNode::new(&*parameter.name,
                                 parameter.help_text,
                                 parameter.hidden,
                                 parameter.priority,
                                 vec![],
                                 parameter.repeatable,
                                 None,
                                 parameter.required)
    }
}

/// Description of a command to be added to the `CommandTree`.
#[derive(Clone)]
pub struct Command {
    hidden: bool,
    priority: i32,
    name: String,
    help_text: Option<String>,
    parameters: Vec<Parameter>,
    wrapped_root: Option<String>,
}

impl Command {
    /// Construct a default (blank) command with the given `name`.
    pub fn new(name: &str) -> Self {
        Command {
            hidden: false,
            priority: PRIORITY_DEFAULT,
            name: name.to_string(),
            help_text: None,
            parameters: vec![],
            wrapped_root: None,
        }
    }

    /// Mark the command as hidden. Hidden commands will match
    /// within the parser, but are not listed during completion.
    pub fn hidden(&mut self, hidden: bool) -> &mut Self {
        self.hidden = hidden;
        self
    }

    /// Give the command a priority. This is used when sorting
    /// out conflicts during matching and completion.
    pub fn priority(&mut self, priority: i32) -> &mut Self {
        self.priority = priority;
        self
    }

    /// Supply help text for the command.
    pub fn help(&mut self, help_text: &str) -> &mut Self {
        self.help_text = Some(help_text.to_string());
        self
    }

    /// Add a `Parameter` to the command.
    pub fn parameter(&mut self, parameter: Parameter) -> &mut Self {
        self.parameters.push(parameter);
        self
    }

    /// Create a `WrapperNode` instead of a `CommandNode`. The
    /// `wrapped_root` signifies the path to the command that should
    /// be wrapped by this command.
    pub fn wraps(&mut self, wrapped_root: String) -> &mut Self {
        self.wrapped_root = Some(wrapped_root);
        self
    }

    /// Return an instance of `Command` that can be passed to the
    /// `CommandTree`. This is used to terminate the series of construction
    /// methods used to initialize and configure the command.
    pub fn finalize(&self) -> Self {
        self.clone()
    }
}

/// Description of a parameter to be added to the `Command`.
#[derive(Clone)]
pub struct Parameter {
    hidden: bool,
    priority: i32,
    name: String,
    repeatable: bool,
    aliases: Vec<String>,
    help_text: Option<String>,
    required: bool,
    parameter_kind: ParameterKind,
}

impl Parameter {
    /// Construct a default (blank) parameter with the given `name`.
    pub fn new(name: &str) -> Self {
        Parameter {
            hidden: false,
            priority: PRIORITY_PARAMETER,
            name: name.to_string(),
            repeatable: false,
            aliases: vec![],
            help_text: None,
            required: false,
            parameter_kind: ParameterKind::Simple,
        }
    }

    /// Mark the parameter as hidden. Hidden parameters will match
    /// within the parser, but are not listed during completion.
    pub fn hidden(&mut self, hidden: bool) -> &mut Self {
        self.hidden = hidden;
        self
    }

    /// Give the parameter a priority. This is used when sorting
    /// out conflicts during matching and completion.
    pub fn priority(&mut self, priority: i32) -> &mut Self {
        self.priority = priority;
        self
    }

    /// Establish whether or not this parameter is repeatable.
    /// Repeated parameters produce a vector of values and can
    /// be given multiple times within a single command invocation.
    pub fn repeatable(&mut self, repeatable: bool) -> &mut Self {
        self.repeatable = repeatable;
        self
    }

    /// Add an alias that this parameter can use.
    pub fn alias(&mut self, alias: &str) -> &mut Self {
        self.aliases.push(alias.to_string());
        self
    }

    /// Supply the help text for the parameter.
    pub fn help(&mut self, help_text: &str) -> &mut Self {
        self.help_text = Some(help_text.to_string());
        self
    }

    /// Establish whether or not this parameter is required.
    pub fn required(&mut self, required: bool) -> &mut Self {
        self.required = required;
        self
    }

    /// Set which type of `ParameterNode` is supposed to be created
    /// to represent this parameter.
    pub fn kind(&mut self, kind: ParameterKind) -> &mut Self {
        self.parameter_kind = kind;
        self
    }

    /// Return an instance of `Parameter` that can be passed to the
    /// `Command`. This is used to terminate the series of construction
    /// methods used to initialize and configure the parameter.
    pub fn finalize(&self) -> Self {
        self.clone()
    }
}
<commit_msg>ParameterKind must derive Copy and PartialEq.<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! # Node Builder
//!
//! ```
//! use commands::parser::builder::*;
//!
//! let mut tree = CommandTree::new();
//! tree.command(Command::new("again")
//!                  .hidden(false)
//!                  .parameter(Parameter::new("test")
//!                                 .required(false)
//!                                 .help("This is just a test parameter.")
//!                                 .finalize())
//!                  .finalize());
//! ```

use std::rc::Rc;
use super::nodes::*;

/// Indicate the type of parameter, so that the correct class and node
/// structures are created.
#[derive(Clone, Copy, PartialEq)]
pub enum ParameterKind {
    /// This parameter is a `FlagParameter`.
    Flag,
    /// This parameter is a `NamedParameter`.
    Named,
    /// This parameter is a `SimpleParameter`.
    Simple,
}

/// Store a command tree while populating it. This can be used
/// to construct a `RootNode` to be used with the `Parser`.
pub struct CommandTree {
    commands: Vec<Command>,
}

impl CommandTree {
    /// Create a new `CommandTree`.
    pub fn new() -> Self {
        CommandTree { commands: vec![] }
    }

    /// Add a `Command` to the `CommandTree`.
    pub fn command(&mut self, command: Command) {
        self.commands.push(command);
    }

    fn build_parameter(self, parameter: Parameter) -> Rc<Node> {
        match parameter.parameter_kind {
            ParameterKind::Flag => Rc::new(self.build_flag_parameter(parameter)),
            ParameterKind::Named => Rc::new(self.build_named_parameter(parameter)),
            ParameterKind::Simple => Rc::new(self.build_simple_parameter(parameter)),
        }
    }

    fn build_flag_parameter(self, parameter: Parameter) -> FlagParameterNode {
        FlagParameterNode::new(&*parameter.name,
                               parameter.help_text,
                               parameter.hidden,
                               parameter.priority,
                               vec![],
                               parameter.repeatable,
                               None,
                               parameter.required)
    }

    fn build_named_parameter(self, parameter: Parameter) -> NamedParameterNode {
        NamedParameterNode::new(&*parameter.name,
                                parameter.help_text,
                                parameter.hidden,
                                parameter.priority,
                                vec![],
                                parameter.repeatable,
                                None,
                                parameter.required)
    }

    fn build_simple_parameter(self, parameter: Parameter) -> SimpleParameterNode {
        SimpleParameterNode::new(&*parameter.name,
                                 parameter.help_text,
                                 parameter.hidden,
                                 parameter.priority,
                                 vec![],
                                 parameter.repeatable,
                                 None,
                                 parameter.required)
    }
}

/// Description of a command to be added to the `CommandTree`.
#[derive(Clone)]
pub struct Command {
    hidden: bool,
    priority: i32,
    name: String,
    help_text: Option<String>,
    parameters: Vec<Parameter>,
    wrapped_root: Option<String>,
}

impl Command {
    /// Construct a default (blank) command with the given `name`.
    pub fn new(name: &str) -> Self {
        Command {
            hidden: false,
            priority: PRIORITY_DEFAULT,
            name: name.to_string(),
            help_text: None,
            parameters: vec![],
            wrapped_root: None,
        }
    }

    /// Mark the command as hidden. Hidden commands will match
    /// within the parser, but are not listed during completion.
    pub fn hidden(&mut self, hidden: bool) -> &mut Self {
        self.hidden = hidden;
        self
    }

    /// Give the command a priority. This is used when sorting
    /// out conflicts during matching and completion.
    pub fn priority(&mut self, priority: i32) -> &mut Self {
        self.priority = priority;
        self
    }

    /// Supply help text for the command.
    pub fn help(&mut self, help_text: &str) -> &mut Self {
        self.help_text = Some(help_text.to_string());
        self
    }

    /// Add a `Parameter` to the command.
    pub fn parameter(&mut self, parameter: Parameter) -> &mut Self {
        self.parameters.push(parameter);
        self
    }

    /// Create a `WrapperNode` instead of a `CommandNode`. The
    /// `wrapped_root` signifies the path to the command that should
    /// be wrapped by this command.
    pub fn wraps(&mut self, wrapped_root: String) -> &mut Self {
        self.wrapped_root = Some(wrapped_root);
        self
    }

    /// Return an instance of `Command` that can be passed to the
    /// `CommandTree`. This is used to terminate the series of construction
    /// methods used to initialize and configure the command.
    pub fn finalize(&self) -> Self {
        self.clone()
    }
}

/// Description of a parameter to be added to the `Command`.
#[derive(Clone)]
pub struct Parameter {
    hidden: bool,
    priority: i32,
    name: String,
    repeatable: bool,
    aliases: Vec<String>,
    help_text: Option<String>,
    required: bool,
    parameter_kind: ParameterKind,
}

impl Parameter {
    /// Construct a default (blank) parameter with the given `name`.
    pub fn new(name: &str) -> Self {
        Parameter {
            hidden: false,
            priority: PRIORITY_PARAMETER,
            name: name.to_string(),
            repeatable: false,
            aliases: vec![],
            help_text: None,
            required: false,
            parameter_kind: ParameterKind::Simple,
        }
    }

    /// Mark the parameter as hidden. Hidden parameters will match
    /// within the parser, but are not listed during completion.
    pub fn hidden(&mut self, hidden: bool) -> &mut Self {
        self.hidden = hidden;
        self
    }

    /// Give the parameter a priority. This is used when sorting
    /// out conflicts during matching and completion.
    pub fn priority(&mut self, priority: i32) -> &mut Self {
        self.priority = priority;
        self
    }

    /// Establish whether or not this parameter is repeatable.
    /// Repeated parameters produce a vector of values and can
    /// be given multiple times within a single command invocation.
    pub fn repeatable(&mut self, repeatable: bool) -> &mut Self {
        self.repeatable = repeatable;
        self
    }

    /// Add an alias that this parameter can use.
    pub fn alias(&mut self, alias: &str) -> &mut Self {
        self.aliases.push(alias.to_string());
        self
    }

    /// Supply the help text for the parameter.
    pub fn help(&mut self, help_text: &str) -> &mut Self {
        self.help_text = Some(help_text.to_string());
        self
    }

    /// Establish whether or not this parameter is required.
    pub fn required(&mut self, required: bool) -> &mut Self {
        self.required = required;
        self
    }

    /// Set which type of `ParameterNode` is supposed to be created
    /// to represent this parameter.
    pub fn kind(&mut self, kind: ParameterKind) -> &mut Self {
        self.parameter_kind = kind;
        self
    }

    /// Return an instance of `Parameter` that can be passed to the
    /// `Command`. This is used to terminate the series of construction
    /// methods used to initialize and configure the parameter.
    pub fn finalize(&self) -> Self {
        self.clone()
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 Jeffery Olson
//
// Licensed under the 3-Clause BSD License, see LICENSE.txt
// at the top-level of this repository.
// This file may not be copied, modified, or distributed
// except according to those terms.
#![crate_id="http://olsonjeffery.github.io#schemers:0.0.1"]
#![desc = "Simple Scheme Interpreter"]
#![license = "3-Clause BSD"]

// this is starting out as a straight port of Peter Norvig's
// lis.py (the first iteration) to Rust

#[cfg(not(test))]
fn main() {
    use std::os::args;
    let args: Vec<~str> = args().move_iter().skip(1).collect();
    if args.len() == 0 {
        fail!("no program provided");
    }
    let program: ~str = args.move_iter()
        .fold(~"", |memo, arg| memo + arg + " ").trim().to_owned();
    println!("{}", tokenize(program));
}

// parser impl
fn pad_input(input: ~str) -> ~str {
    input.replace("(", " ( ").replace(")", " ) ")
}

fn tokenize(input: ~str) -> Vec<~str> {
    pad_input(input).split_str(" ")
        .filter(|i| *i != "").map(|i| i.to_owned()).collect()
}

#[cfg(test)]
mod parser_test {
    use super::pad_input;
    use super::tokenize;

    #[test]
    fn pad_input_should_insert_spaces_before_and_after_parens() {
        assert_eq!(pad_input(~"(x 1 2 3)"), ~" ( x 1 2 3 ) ");
    }

    #[test]
    fn tokenize_should_split_string_into_tokens() {
        let tokens = tokenize(~"(foo 12 3)");
        assert_eq!(tokens.len(), 5);
    }
}
<commit_msg>first test + impl for read()<commit_after>// Copyright 2013-2014 Jeffery Olson
//
// Licensed under the 3-Clause BSD License, see LICENSE.txt
// at the top-level of this repository.
// This file may not be copied, modified, or distributed
// except according to those terms.
#![crate_id="http://olsonjeffery.github.io#schemers:0.0.1"]
#![desc = "Simple Scheme Interpreter"]
#![license = "3-Clause BSD"]

// this is starting out as a straight port of Peter Norvig's
// lis.py (the first iteration) to Rust

#[cfg(not(test))]
fn main() {
    use std::os::args;
    let args: Vec<~str> = args().move_iter().skip(1).collect();
    if args.len() == 0 {
        fail!("no program provided");
    }
    let program: ~str = args.move_iter()
        .fold(~"", |memo, arg| memo + arg + " ").trim().to_owned();
    println!("{}", tokenize(program));
}

// parser impl
fn pad_input(input: ~str) -> ~str {
    input.replace("(", " ( ").replace(")", " ) ")
}

fn tokenize(input: ~str) -> Vec<~str> {
    pad_input(input).split_str(" ")
        .filter(|i| *i != "").map(|i| i.to_owned()).collect()
}

pub enum ParseItem {
    Atom(~str),
    List(Vec<~ParseItem>)
}

fn read(tokens: &mut Vec<~str>) -> ParseItem {
    if tokens.len() == 0 {
        fail!("calling read() with an empty tokens vector");
    }
    match tokens.pop().expect("calling read() w/ empty token list; shouldn't happen") {
        ref x if *x == ~"(" => {
            let mut list = Vec::new();
            while *tokens.get(0) != ~")" {
                list.push(box read(tokens));
            }
            tokens.pop();
            List(list)
        },
        ref x if *x == ~")" => fail!("hit ) token; shouldn't happen"),
        x => Atom(x)
    }
}

#[cfg(test)]
mod parser_test {
    use super::{pad_input, tokenize, read, Atom};

    #[test]
    fn pad_input_should_insert_spaces_before_and_after_parens() {
        assert_eq!(pad_input(~"(x 1 2 3)"), ~" ( x 1 2 3 ) ");
    }

    #[test]
    fn tokenize_should_split_string_into_tokens() {
        let tokens = tokenize(~"(foo 12 3)");
        assert_eq!(tokens.len(), 5);
    }

    #[test]
    fn parse_should_take_a_vector_consisting_an_atom_and_convert_it_to_a_parse_item() {
        let tokens = &mut tokenize(~"bar");
        match read(tokens) {
            Atom(val) => { assert_eq!(val, ~"bar")},
            _ => assert!(false)
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt;

use core::{ Float, TOLERANCE };
use maths::{ Matrix, Vector };
use utils::approx_eq;
use shapes::Shape;

/// A representation of a cuboid in 3 dimensions.
#[derive(Clone, Debug)]
pub struct Cuboid {
    width: Float,
    height: Float,
    depth: Float,
    vertices: Vec<Vector>,
}

impl Cuboid {
    /// Constructs a new `Cuboid` given the width, height and depth dimensions.
    pub fn new(width: Float, height: Float, depth: Float) -> Cuboid {
        let half_width = width / 2.0;
        let half_height = height / 2.0;
        let half_depth = depth / 2.0;

        // TODO refactor this to something else (z = height??)
        let mut vertices = Vec::new();
        vertices.push(Vector::new( half_width,  half_height,  half_depth));
        vertices.push(Vector::new(-half_width,  half_height,  half_depth));
        vertices.push(Vector::new(-half_width, -half_height,  half_depth));
        vertices.push(Vector::new( half_width, -half_height,  half_depth));

        vertices.push(Vector::new( half_width,  half_height, -half_depth));
        vertices.push(Vector::new(-half_width,  half_height, -half_depth));
        vertices.push(Vector::new(-half_width, -half_height, -half_depth));
        vertices.push(Vector::new( half_width, -half_height, -half_depth));

        Cuboid {
            width: width,
            height: height,
            depth: depth,
            vertices: vertices,
        }
    }

    /// Constructs a new `Cuboid` with equally sized edges.
    pub fn new_cube(size: Float) -> Cuboid {
        Cuboid::new(size, size, size)
    }

    /// Returns the width of the `Cuboid`.
    pub fn width(&self) -> Float {
        self.width
    }

    /// Returns the height of the `Cuboid`.
    pub fn height(&self) -> Float {
        self.height
    }

    /// Returns the depth of the `Cuboid`.
    pub fn depth(&self) -> Float {
        self.depth
    }
}

impl fmt::Display for Cuboid {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Cuboid{{ w={}, h={}, d={} }}", self.width, self.height, self.depth)
    }
}

/// Implements the `Eq` trait for the Cuboid to specify that equality is an
/// equivalence relation.
impl Eq for Cuboid {}

impl PartialEq for Cuboid {
    /// Implements the `==` operator for the `Cuboid` class. Compares the
    /// dimensions of the `Cuboid` to be within reasonable tolerance.
    fn eq(&self, other: &Cuboid) -> bool {
        approx_eq(self.width, other.width) &&
            approx_eq(self.height, other.height) &&
            approx_eq(self.depth, other.depth)
    }
}

impl Shape for Cuboid {
    /// Calculates the volume of the `Cuboid`.
    fn volume(&self) -> Float {
        self.width * self.height * self.depth
    }

    fn inertia(&self) -> Matrix {
        let w2 = self.width*self.width;
        let h2 = self.height*self.height;
        let d2 = self.depth*self.depth;

        return Matrix::new(
            (h2 + d2)/12.0,            0.0,            0.0,
                       0.0, (w2 + d2)/12.0,            0.0,
                       0.0,            0.0, (h2 + w2)/12.0,
        );
    }

    fn vertex(&self, index: usize) -> Vector {
        self.vertices[index]
    }

    fn vertices_len(&self) -> usize {
        8
    }

    fn vertices_iter<'a>(&'a self) -> Box<Iterator<Item=Vector> + 'a> {
        Box::new(self.vertices.iter().map(|&a| a))
    }

    fn support_indices_for(&self, direction: Vector) -> Vec<usize> {
        let new_direction = Vector::new(
            direction[0]/self.width,
            direction[1]/self.height,
            direction[2]/self.depth,
        );
        let mut max_value = 0.0;
        let mut max_indices = Vec::new();

        for (index, vertex) in self.vertices.iter().enumerate() {
            let value = vertex.dot(new_direction);

            let diff = value - max_value;
            if diff > TOLERANCE {
                max_value = value;
                max_indices = Vec::new();
                max_indices.push(index)
            } else if diff.abs() < TOLERANCE {
                max_indices.push(index)
            }
        }

        return max_indices;
    }
}
<commit_msg>Refactored Cuboid to use a fixed size array for vertices<commit_after>use std::fmt;

use core::{ Float, TOLERANCE };
use maths::{ Matrix, Vector };
use utils::approx_eq;
use shapes::Shape;

/// A representation of a cuboid in 3 dimensions.
#[derive(Clone, Debug)]
pub struct Cuboid {
    width: Float,
    height: Float,
    depth: Float,
    vertices: [Vector; 8],
}

impl Cuboid {
    /// Constructs a new `Cuboid` given the width, height and depth dimensions.
    pub fn new(width: Float, height: Float, depth: Float) -> Cuboid {
        let half_width = width / 2.0;
        let half_height = height / 2.0;
        let half_depth = depth / 2.0;

        Cuboid {
            width: width,
            height: height,
            depth: depth,
            vertices: [
                // TODO refactor this to something else (z = height??)
                Vector::new( half_width,  half_height,  half_depth),
                Vector::new(-half_width,  half_height,  half_depth),
                Vector::new(-half_width, -half_height,  half_depth),
                Vector::new( half_width, -half_height,  half_depth),
                Vector::new( half_width,  half_height, -half_depth),
                Vector::new(-half_width,  half_height, -half_depth),
                Vector::new(-half_width, -half_height, -half_depth),
                Vector::new( half_width, -half_height, -half_depth),
            ],
        }
    }

    /// Constructs a new `Cuboid` with equally sized edges.
    pub fn new_cube(size: Float) -> Cuboid {
        Cuboid::new(size, size, size)
    }

    /// Returns the width of the `Cuboid`.
    pub fn width(&self) -> Float {
        self.width
    }

    /// Returns the height of the `Cuboid`.
    pub fn height(&self) -> Float {
        self.height
    }

    /// Returns the depth of the `Cuboid`.
    pub fn depth(&self) -> Float {
        self.depth
    }
}

impl fmt::Display for Cuboid {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Cuboid{{ w={}, h={}, d={} }}", self.width, self.height, self.depth)
    }
}

/// Implements the `Eq` trait for the Cuboid to specify that equality is an
/// equivalence relation.
impl Eq for Cuboid {}

impl PartialEq for Cuboid {
    /// Implements the `==` operator for the `Cuboid` class. Compares the
    /// dimensions of the `Cuboid` to be within reasonable tolerance.
    fn eq(&self, other: &Cuboid) -> bool {
        approx_eq(self.width, other.width) &&
            approx_eq(self.height, other.height) &&
            approx_eq(self.depth, other.depth)
    }
}

impl Shape for Cuboid {
    /// Calculates the volume of the `Cuboid`.
    fn volume(&self) -> Float {
        self.width * self.height * self.depth
    }

    fn inertia(&self) -> Matrix {
        let w2 = self.width*self.width;
        let h2 = self.height*self.height;
        let d2 = self.depth*self.depth;

        return Matrix::new(
            (h2 + d2)/12.0,            0.0,            0.0,
                       0.0, (w2 + d2)/12.0,            0.0,
                       0.0,            0.0, (h2 + w2)/12.0,
        );
    }

    fn vertex(&self, index: usize) -> Vector {
        self.vertices[index]
    }

    fn vertices_len(&self) -> usize {
        8
    }

    fn vertices_iter<'a>(&'a self) -> Box<Iterator<Item=Vector> + 'a> {
        Box::new(self.vertices.iter().map(|&a| a))
    }

    fn support_indices_for(&self, direction: Vector) -> Vec<usize> {
        let new_direction = Vector::new(
            direction[0]/self.width,
            direction[1]/self.height,
            direction[2]/self.depth,
        );
        let mut max_value = 0.0;
        let mut max_indices = Vec::new();

        for (index, vertex) in self.vertices.iter().enumerate() {
            let value = vertex.dot(new_direction);

            let diff = value - max_value;
            if diff > TOLERANCE {
                max_value = value;
                max_indices = Vec::new();
                max_indices.push(index)
            } else if diff.abs() < TOLERANCE {
                max_indices.push(index)
            }
        }

        return max_indices;
    }
}
<|endoftext|>