<commit_before>use std::thread;
use std::cell::UnsafeCell;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver, RecvError};
use basetypes::*;
use chess_move::MoveStack;
use tt::*;
use position::Position;

pub enum Command {
    Search {
        search_id: usize,
        position: Position,
        depth: u8,
        lower_bound: Value,
        upper_bound: Value,
    },
    Stop,
    Exit,
}

pub enum Report {
    Progress {
        search_id: usize,
        searched_nodes: NodeCount,
        depth: u8,
    },
    Done {
        search_id: usize,
        searched_nodes: NodeCount,
        value: Option<Value>,
    },
}

pub fn run(tt: Arc<TranspositionTable>, commands: Receiver<Command>, reports: Sender<Report>) {
    thread_local!(
        static MOVE_STACK: UnsafeCell<MoveStack> = UnsafeCell::new(MoveStack::new())
    );
    MOVE_STACK.with(|s| {
        let mut move_stack = unsafe { &mut *s.get() };
        let mut pending_command = None;
        loop {
            // If there is a pending command, we take it, otherwise we
            // block and wait to receive a new one.
            match pending_command.take().unwrap_or(commands.recv()
                                                           .or::<RecvError>(Ok(Command::Exit))
                                                           .unwrap()) {
                Command::Search { search_id, mut position, depth, lower_bound, upper_bound } => {
                    let mut reported_nodes = 0;
                    let mut unreported_nodes = 0;
                    let value = search(&tt,
                                       &mut position,
                                       move_stack,
                                       &mut unreported_nodes,
                                       &mut |n| {
                                           reported_nodes += n;
                                           reports.send(Report::Progress {
                                                      search_id: search_id,
                                                      searched_nodes: reported_nodes,
                                                      depth: depth,
                                                  })
                                                  .ok();
                                           match commands.try_recv() {
                                               Ok(x) => {
                                                   pending_command = Some(x);
                                                   Err(TerminatedSearch)
                                               }
                                               _ => Ok(()),
                                           }
                                       },
                                       lower_bound,
                                       upper_bound,
                                       depth)
                                    .ok();
                    reported_nodes += unreported_nodes;
                    reports.send(Report::Progress {
                               search_id: search_id,
                               searched_nodes: reported_nodes,
                               depth: depth,
                           })
                           .ok();
                    reports.send(Report::Done {
                               search_id: search_id,
                               searched_nodes: reported_nodes,
                               value: value,
                           })
                           .ok();
                    move_stack.clear();
                }
                Command::Stop => continue,
                Command::Exit => break,
            }
        }
    })
}

pub fn run_deepening(tt: Arc<TranspositionTable>,
                     commands: Receiver<Command>,
                     reports: Sender<Report>) {
    let (slave_commands_tx, slave_commands_rx) = channel();
    let (slave_reports_tx, slave_reports_rx) = channel();
    let slave = thread::spawn(move || {
        run(tt, slave_commands_rx, slave_reports_tx);
    });
    let mut pending_command = None;
    loop {
        // If there is a pending command, we take it, otherwise we
        // block and wait to receive a new one.
        match pending_command.take().unwrap_or(commands.recv()
                                                       .or::<RecvError>(Ok(Command::Exit))
                                                       .unwrap()) {
            Command::Search { search_id, position, depth, lower_bound, upper_bound } => {
                let mut searched_nodes_final = 0;
                let mut value_final = None;
                'depthloop: for n in 1..(depth + 1) {
                    slave_commands_tx.send(Command::Search {
                                         search_id: n as usize,
                                         position: position.clone(),
                                         depth: n,
                                         lower_bound: lower_bound,
                                         upper_bound: upper_bound,
                                     })
                                     .unwrap();
                    loop {
                        match slave_reports_rx.recv().unwrap() {
                            Report::Progress { searched_nodes, .. } => {
                                reports.send(Report::Progress {
                                           search_id: search_id,
                                           searched_nodes: searched_nodes_final + searched_nodes,
                                           depth: n,
                                       })
                                       .ok();
                                if pending_command.is_none() {
                                    pending_command = match commands.try_recv() {
                                        Ok(cmd) => {
                                            slave_commands_tx.send(Command::Stop).unwrap();
                                            Some(cmd)
                                        }
                                        _ => None,
                                    }
                                }
                            }
                            Report::Done { searched_nodes, value, .. } => {
                                searched_nodes_final += searched_nodes;
                                if n == depth {
                                    value_final = value;
                                }
                                if pending_command.is_none() {
                                    // TODO: Consider stopping if the
                                    // value is +-20000.
                                    break;
                                } else {
                                    break 'depthloop;
                                }
                            }
                        }
                    }
                }
                reports.send(Report::Done {
                           search_id: search_id,
                           searched_nodes: searched_nodes_final,
                           value: value_final,
                       })
                       .ok();
            }
            Command::Stop => {
                slave_commands_tx.send(Command::Stop).unwrap();
                continue;
            }
            Command::Exit => {
                slave_commands_tx.send(Command::Exit).unwrap();
                break;
            }
        }
    }
    slave.join().unwrap();
}

// Represents a terminated search condition.
struct TerminatedSearch;

// Helper function for `run()`. It implements the principal variation
// search algorithm. When returning `Err(TerminatedSearch)`, this
// function may leave un-restored move lists in `moves`.
fn search(tt: &TranspositionTable,
          p: &mut Position,
          moves: &mut MoveStack,
          nc: &mut NodeCount,
          report: &mut FnMut(NodeCount) -> Result<(), TerminatedSearch>,
          mut alpha: Value, // lower bound
          beta: Value, // upper bound
          depth: u8)
          -> Result<Value, TerminatedSearch> {
    assert!(alpha < beta);
    if depth == 0 {
        // On leaf nodes, do quiescence search.
        let (value, nodes) = p.evaluate_quiescence(alpha, beta);
        *nc += nodes;
        Ok(value)
    } else {
        moves.save();
        p.generate_moves(moves);

        // TODO: Consult `tt` here.
        if let Some(entry) = tt.probe(p.hash()) {
            let move16 = entry.move16();
            if  move16 != 0 {
                for m in moves.iter_mut() {
                    if m.move16() == move16 {
                        m.set_score(0b11);
                    }
                }
            }
        }

        let mut bound_type = BOUND_UPPER;
        let mut move16 = 0;
        let mut no_moves_yet = true;
        while let Some(m) = moves.remove_best_move() {
            if p.do_move(m) {
                // From time to time, we report how many nodes had
                // been searched since the last report. This also
                // gives an opportunity for the search to be
                // terminated.
                *nc += 1;
                if *nc > NODE_COUNT_REPORT_INTERVAL {
                    try!(report(*nc));
                    *nc = 0;
                }

                let value = if no_moves_yet {
                    // The first move we analyze with a fully open
                    // window (alpha, beta).
                    -try!(search(tt, p, moves, nc, report, -beta, -alpha, depth - 1))
                } else {
                    // For the next moves we first try to prove that
                    // they are not better than our current best
                    // move. For this purpose we analyze them with a
                    // null window (alpha, alpha + 1). This is faster
                    // than a full window search. Only when we are
                    // certain that the move is better than our
                    // current best move, we do a full-window search.
                    match -try!(search(tt, p, moves, nc, report, -alpha - 1, -alpha, depth - 1)) {
                        x if x <= alpha => x,
                        _ => -try!(search(tt, p, moves, nc, report, -beta, -alpha, depth - 1)),
                    }
                };
                no_moves_yet = false;
                p.undo_move();

                if value >= beta {
                    // This move is too good, so that the opponent
                    // will not allow this line of play to
                    // happen. Therefore we can stop here.
                    alpha = beta;
                    bound_type = BOUND_LOWER;
                    move16 = m.move16();
                    break;
                }
                if value > alpha {
                    // We found ourselves a new best move.
                    alpha = value;
                    bound_type = BOUND_EXACT;
                    move16 = m.move16();
                }
            }
        }
        moves.restore();
        if no_moves_yet {
            // No legal moves -- this is a final position.
            alpha = p.evaluate_final();
        }
        // TODO: Do not store values with too small `depth`.
        tt.store(p.hash(),
                 EntryData::new(alpha, bound_type, depth, move16, 0));
        Ok(alpha)
    }
}

const NODE_COUNT_REPORT_INTERVAL: NodeCount = 10000;

#[cfg(test)]
mod tests {
    use super::search;
    use chess_move::*;
    use tt::*;
    use position::Position;

    #[test]
    fn test_search() {
        let mut p = Position::from_fen("8/8/8/8/3q3k/7n/6PP/2Q2R1K b - - 0 1").ok().unwrap();
        let value = search(&TranspositionTable::new(),
                           &mut p,
                           &mut MoveStack::new(),
                           &mut 0,
                           &mut |_| Ok(()),
                           -20000,
                           20000,
                           2)
                        .ok()
                        .unwrap();
        assert!(value < -300);
        let value = search(&TranspositionTable::new(),
                           &mut p,
                           &mut MoveStack::new(),
                           &mut 0,
                           &mut |_| Ok(()),
                           -20000,
                           20000,
                           3)
                        .ok()
                        .unwrap();
        assert!(value >= 20000);
    }
}
<commit_msg>fixed nasty bug with Option.take()<commit_after>use std::thread;
use std::cell::UnsafeCell;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver, RecvError};
use basetypes::*;
use chess_move::MoveStack;
use tt::*;
use position::Position;

pub enum Command {
    Search {
        search_id: usize,
        position: Position,
        depth: u8,
        lower_bound: Value,
        upper_bound: Value,
    },
    Stop,
    Exit,
}

pub enum Report {
    Progress {
        search_id: usize,
        searched_nodes: NodeCount,
        depth: u8,
    },
    Done {
        search_id: usize,
        searched_nodes: NodeCount,
        value: Option<Value>,
    },
}

pub fn run(tt: Arc<TranspositionTable>, commands: Receiver<Command>, reports: Sender<Report>) {
    thread_local!(
        static MOVE_STACK: UnsafeCell<MoveStack> = UnsafeCell::new(MoveStack::new())
    );
    MOVE_STACK.with(|s| {
        let mut move_stack = unsafe { &mut *s.get() };
        let mut pending_command = None;
        loop {
            // If there is a pending command, we take it, otherwise we
            // block and wait to receive a new one.
            let command = match pending_command.take() {
                Some(cmd) => cmd,
                None => commands.recv().or::<RecvError>(Ok(Command::Exit)).unwrap()
            };

            match command {
                Command::Search { search_id, mut position, depth, lower_bound, upper_bound } => {
                    let mut reported_nodes = 0;
                    let mut unreported_nodes = 0;
                    let value = search(&tt,
                                       &mut position,
                                       move_stack,
                                       &mut unreported_nodes,
                                       &mut |n| {
                                           reported_nodes += n;
                                           reports.send(Report::Progress {
                                                      search_id: search_id,
                                                      searched_nodes: reported_nodes,
                                                      depth: depth,
                                                  })
                                                  .ok();
                                           match commands.try_recv() {
                                               Ok(x) => {
                                                   pending_command = Some(x);
                                                   Err(TerminatedSearch)
                                               }
                                               _ => Ok(()),
                                           }
                                       },
                                       lower_bound,
                                       upper_bound,
                                       depth)
                                    .ok();
                    reported_nodes += unreported_nodes;
                    reports.send(Report::Progress {
                               search_id: search_id,
                               searched_nodes: reported_nodes,
                               depth: depth,
                           })
                           .ok();
                    reports.send(Report::Done {
                               search_id: search_id,
                               searched_nodes: reported_nodes,
                               value: value,
                           })
                           .ok();
                    move_stack.clear();
                }
                Command::Stop => continue,
                Command::Exit => break,
            }
        }
    })
}

pub fn run_deepening(tt: Arc<TranspositionTable>,
                     commands: Receiver<Command>,
                     reports: Sender<Report>) {
    let (slave_commands_tx, slave_commands_rx) = channel();
    let (slave_reports_tx, slave_reports_rx) = channel();
    let slave = thread::spawn(move || {
        run(tt, slave_commands_rx, slave_reports_tx);
    });
    let mut pending_command = None;
    loop {
        // If there is a pending command, we take it, otherwise we
        // block and wait to receive a new one.
        let command = match pending_command.take() {
            Some(cmd) => cmd,
            None => commands.recv().or::<RecvError>(Ok(Command::Exit)).unwrap()
        };

        match command {
            Command::Search { search_id, position, depth, lower_bound, upper_bound } => {
                let mut searched_nodes_final = 0;
                let mut value_final = None;
                'depthloop: for n in 1..(depth + 1) {
                    slave_commands_tx.send(Command::Search {
                                         search_id: n as usize,
                                         position: position.clone(),
                                         depth: n,
                                         lower_bound: lower_bound,
                                         upper_bound: upper_bound,
                                     })
                                     .unwrap();
                    loop {
                        match slave_reports_rx.recv().unwrap() {
                            Report::Progress { searched_nodes, .. } => {
                                reports.send(Report::Progress {
                                           search_id: search_id,
                                           searched_nodes: searched_nodes_final + searched_nodes,
                                           depth: n,
                                       })
                                       .ok();
                                if pending_command.is_none() {
                                    pending_command = match commands.try_recv() {
                                        Ok(cmd) => {
                                            slave_commands_tx.send(Command::Stop).unwrap();
                                            Some(cmd)
                                        }
                                        _ => None,
                                    }
                                }
                            }
                            Report::Done { searched_nodes, value, .. } => {
                                searched_nodes_final += searched_nodes;
                                if n == depth {
                                    value_final = value;
                                }
                                if pending_command.is_none() {
                                    // TODO: Consider stopping if the
                                    // value is +-20000.
                                    break;
                                } else {
                                    break 'depthloop;
                                }
                            }
                        }
                    }
                }
                reports.send(Report::Done {
                           search_id: search_id,
                           searched_nodes: searched_nodes_final,
                           value: value_final,
                       })
                       .ok();
            }
            Command::Stop => {
                slave_commands_tx.send(Command::Stop).unwrap();
                continue;
            }
            Command::Exit => {
                slave_commands_tx.send(Command::Exit).unwrap();
                break;
            }
        }
    }
    slave.join().unwrap();
}

// Represents a terminated search condition.
struct TerminatedSearch;

// Helper function for `run()`. It implements the principal variation
// search algorithm. When returning `Err(TerminatedSearch)`, this
// function may leave un-restored move lists in `moves`.
fn search(tt: &TranspositionTable,
          p: &mut Position,
          moves: &mut MoveStack,
          nc: &mut NodeCount,
          report: &mut FnMut(NodeCount) -> Result<(), TerminatedSearch>,
          mut alpha: Value, // lower bound
          beta: Value, // upper bound
          depth: u8)
          -> Result<Value, TerminatedSearch> {
    assert!(alpha < beta);
    if depth == 0 {
        // On leaf nodes, do quiescence search.
        let (value, nodes) = p.evaluate_quiescence(alpha, beta);
        *nc += nodes;
        Ok(value)
    } else {
        moves.save();
        p.generate_moves(moves);

        // TODO: Consult `tt` here.
        if let Some(entry) = tt.probe(p.hash()) {
            let move16 = entry.move16();
            if move16 != 0 {
                for m in moves.iter_mut() {
                    if m.move16() == move16 {
                        m.set_score(0b11);
                    }
                }
            }
        }

        let mut bound_type = BOUND_UPPER;
        let mut move16 = 0;
        let mut no_moves_yet = true;
        while let Some(m) = moves.remove_best_move() {
            if p.do_move(m) {
                // From time to time, we report how many nodes had
                // been searched since the last report. This also
                // gives an opportunity for the search to be
                // terminated.
                *nc += 1;
                if *nc > NODE_COUNT_REPORT_INTERVAL {
                    try!(report(*nc));
                    *nc = 0;
                }

                let value = if no_moves_yet {
                    // The first move we analyze with a fully open
                    // window (alpha, beta).
                    -try!(search(tt, p, moves, nc, report, -beta, -alpha, depth - 1))
                } else {
                    // For the next moves we first try to prove that
                    // they are not better than our current best
                    // move. For this purpose we analyze them with a
                    // null window (alpha, alpha + 1). This is faster
                    // than a full window search. Only when we are
                    // certain that the move is better than our
                    // current best move, we do a full-window search.
                    match -try!(search(tt, p, moves, nc, report, -alpha - 1, -alpha, depth - 1)) {
                        x if x <= alpha => x,
                        _ => -try!(search(tt, p, moves, nc, report, -beta, -alpha, depth - 1)),
                    }
                };
                no_moves_yet = false;
                p.undo_move();

                if value >= beta {
                    // This move is too good, so that the opponent
                    // will not allow this line of play to
                    // happen. Therefore we can stop here.
                    alpha = beta;
                    bound_type = BOUND_LOWER;
                    move16 = m.move16();
                    break;
                }
                if value > alpha {
                    // We found ourselves a new best move.
                    alpha = value;
                    bound_type = BOUND_EXACT;
                    move16 = m.move16();
                }
            }
        }
        moves.restore();
        if no_moves_yet {
            // No legal moves -- this is a final position.
            alpha = p.evaluate_final();
        }
        // TODO: Do not store values with too small `depth`.
        tt.store(p.hash(),
                 EntryData::new(alpha, bound_type, depth, move16, 0));
        Ok(alpha)
    }
}

const NODE_COUNT_REPORT_INTERVAL: NodeCount = 10000;

#[cfg(test)]
mod tests {
    use super::search;
    use chess_move::*;
    use tt::*;
    use position::Position;

    #[test]
    fn test_search() {
        let mut p = Position::from_fen("8/8/8/8/3q3k/7n/6PP/2Q2R1K b - - 0 1").ok().unwrap();
        let value = search(&TranspositionTable::new(),
                           &mut p,
                           &mut MoveStack::new(),
                           &mut 0,
                           &mut |_| Ok(()),
                           -20000,
                           20000,
                           2)
                        .ok()
                        .unwrap();
        assert!(value < -300);
        let value = search(&TranspositionTable::new(),
                           &mut p,
                           &mut MoveStack::new(),
                           &mut 0,
                           &mut |_| Ok(()),
                           -20000,
                           20000,
                           3)
                        .ok()
                        .unwrap();
        assert!(value >= 20000);
    }
}
<|endoftext|>


<commit_before>#![crate_name = "uu_factor"]

/*
* This file is part of the uutils coreutils package.
*
* (c) T. Jameson Little <t.jameson.little@gmail.com>
* (c) Wiktor Kuropatwa <wiktor.kuropatwa@gmail.com>
*     20150223 added Pollard rho method implementation
* (c) kwantam <kwantam@gmail.com>
*     20150429 sped up trial division by adding table of prime inverses
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/

extern crate rand;

#[macro_use]
extern crate uucore;

use numeric::*;
use rand::distributions::{Distribution, Uniform};
use rand::{SeedableRng, thread_rng};
use rand::rngs::SmallRng;
use std::cmp::{max, min};
use std::io::{stdin, BufRead, BufReader};
use std::num::Wrapping;
use std::mem::swap;

mod numeric;

include!(concat!(env!("OUT_DIR"), "/prime_table.rs"));

static SYNTAX: &str = "[OPTION] [NUMBER]...";
static SUMMARY: &str = "Print the prime factors of the given number(s).
 If none are specified, read from standard input.";
static LONG_HELP: &str = "";

fn rho_pollard_pseudorandom_function(x: u64, a: u64, b: u64, num: u64) -> u64 {
    if num < 1 << 63 {
        (sm_mul(a, sm_mul(x, x, num), num) + b) % num
    } else {
        big_add(big_mul(a, big_mul(x, x, num), num), b, num)
    }
}

fn gcd(mut a: u64, mut b: u64) -> u64 {
    while b > 0 {
        a %= b;
        swap(&mut a, &mut b);
    }
    a
}

fn rho_pollard_find_divisor(num: u64) -> u64 {
    let range = Uniform::new(1, num);
    let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
    let mut x = range.sample(&mut rng);
    let mut y = x;
    let mut a = range.sample(&mut rng);
    let mut b = range.sample(&mut rng);

    loop {
        x = rho_pollard_pseudorandom_function(x, a, b, num);
        y = rho_pollard_pseudorandom_function(y, a, b, num);
        y = rho_pollard_pseudorandom_function(y, a, b, num);
        let d = gcd(num, max(x, y) - min(x, y));
        if d == num {
            // Failure, retry with different function
            x = range.sample(&mut rng);
            y = x;
            a = range.sample(&mut rng);
            b = range.sample(&mut rng);
        } else if d > 1 {
            return d;
        }
    }
}

fn rho_pollard_factor(num: u64, factors: &mut Vec<u64>) {
    if is_prime(num) {
        factors.push(num);
        return;
    }
    let divisor = rho_pollard_find_divisor(num);
    rho_pollard_factor(divisor, factors);
    rho_pollard_factor(num / divisor, factors);
}

fn table_division(mut num: u64, factors: &mut Vec<u64>) {
    if num < 2 {
        return;
    }
    while num % 2 == 0 {
        num /= 2;
        factors.push(2);
    }
    if num == 1 {
        return;
    }
    if is_prime(num) {
        factors.push(num);
        return;
    }
    for &(prime, inv, ceil) in P_INVS_U64 {
        if num == 1 {
            break;
        }

        // inv = prime^-1 mod 2^64
        // ceil = floor((2^64-1) / prime)
        // if (num * inv) mod 2^64 <= ceil, then prime divides num
        // See http://math.stackexchange.com/questions/1251327/
        // for a nice explanation.
        loop {
            let Wrapping(x) = Wrapping(num) * Wrapping(inv); // x = num * inv mod 2^64
            if x <= ceil {
                num = x;
                factors.push(prime);
                if is_prime(num) {
                    factors.push(num);
                    return;
                }
            } else {
                break;
            }
        }
    }

    // do we still have more factoring to do?
    // Decide whether to use Pollard Rho or slow divisibility based on
    // number's size:
    //if num >= 1 << 63 {
    // number is too big to use rho pollard without overflowing
    //trial_division_slow(num, factors);
    //} else if num > 1 {
    // number is still greater than 1, but not so big that we have to worry
    rho_pollard_factor(num, factors);
    //}
}

fn print_factors(num: u64) {
    print!("{}:", num);

    let mut factors = Vec::new();
    // we always start with table division, and go from there
    table_division(num, &mut factors);
    factors.sort();

    for fac in &factors {
        print!(" {}", fac);
    }
    println!();
}

fn print_factors_str(num_str: &str) {
    if let Err(e) = num_str.parse::<u64>().and_then(|x| Ok(print_factors(x))) {
        show_warning!("{}: {}", num_str, e);
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let matches = new_coreopts!(SYNTAX, SUMMARY, LONG_HELP).parse(args);

    if matches.free.is_empty() {
        for line in BufReader::new(stdin()).lines() {
            for number in line.unwrap().split_whitespace() {
                print_factors_str(number);
            }
        }
    } else {
        for num_str in &matches.free {
            print_factors_str(num_str);
        }
    }
    0
}
<commit_msg>factor: Don’t wrap stdin in BufReader & use lock()<commit_after>#![crate_name = "uu_factor"]

/*
* This file is part of the uutils coreutils package.
*
* (c) T. Jameson Little <t.jameson.little@gmail.com>
* (c) Wiktor Kuropatwa <wiktor.kuropatwa@gmail.com>
*     20150223 added Pollard rho method implementation
* (c) kwantam <kwantam@gmail.com>
*     20150429 sped up trial division by adding table of prime inverses
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/

extern crate rand;

#[macro_use]
extern crate uucore;

use numeric::*;
use rand::distributions::{Distribution, Uniform};
use rand::{SeedableRng, thread_rng};
use rand::rngs::SmallRng;
use std::cmp::{max, min};
use std::io::{stdin, BufRead};
use std::num::Wrapping;
use std::mem::swap;

mod numeric;

include!(concat!(env!("OUT_DIR"), "/prime_table.rs"));

static SYNTAX: &str = "[OPTION] [NUMBER]...";
static SUMMARY: &str = "Print the prime factors of the given number(s).
 If none are specified, read from standard input.";
static LONG_HELP: &str = "";

fn rho_pollard_pseudorandom_function(x: u64, a: u64, b: u64, num: u64) -> u64 {
    if num < 1 << 63 {
        (sm_mul(a, sm_mul(x, x, num), num) + b) % num
    } else {
        big_add(big_mul(a, big_mul(x, x, num), num), b, num)
    }
}

fn gcd(mut a: u64, mut b: u64) -> u64 {
    while b > 0 {
        a %= b;
        swap(&mut a, &mut b);
    }
    a
}

fn rho_pollard_find_divisor(num: u64) -> u64 {
    let range = Uniform::new(1, num);
    let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
    let mut x = range.sample(&mut rng);
    let mut y = x;
    let mut a = range.sample(&mut rng);
    let mut b = range.sample(&mut rng);

    loop {
        x = rho_pollard_pseudorandom_function(x, a, b, num);
        y = rho_pollard_pseudorandom_function(y, a, b, num);
        y = rho_pollard_pseudorandom_function(y, a, b, num);
        let d = gcd(num, max(x, y) - min(x, y));
        if d == num {
            // Failure, retry with different function
            x = range.sample(&mut rng);
            y = x;
            a = range.sample(&mut rng);
            b = range.sample(&mut rng);
        } else if d > 1 {
            return d;
        }
    }
}

fn rho_pollard_factor(num: u64, factors: &mut Vec<u64>) {
    if is_prime(num) {
        factors.push(num);
        return;
    }
    let divisor = rho_pollard_find_divisor(num);
    rho_pollard_factor(divisor, factors);
    rho_pollard_factor(num / divisor, factors);
}

fn table_division(mut num: u64, factors: &mut Vec<u64>) {
    if num < 2 {
        return;
    }
    while num % 2 == 0 {
        num /= 2;
        factors.push(2);
    }
    if num == 1 {
        return;
    }
    if is_prime(num) {
        factors.push(num);
        return;
    }
    for &(prime, inv, ceil) in P_INVS_U64 {
        if num == 1 {
            break;
        }

        // inv = prime^-1 mod 2^64
        // ceil = floor((2^64-1) / prime)
        // if (num * inv) mod 2^64 <= ceil, then prime divides num
        // See http://math.stackexchange.com/questions/1251327/
        // for a nice explanation.
        loop {
            let Wrapping(x) = Wrapping(num) * Wrapping(inv); // x = num * inv mod 2^64
            if x <= ceil {
                num = x;
                factors.push(prime);
                if is_prime(num) {
                    factors.push(num);
                    return;
                }
            } else {
                break;
            }
        }
    }

    // do we still have more factoring to do?
    // Decide whether to use Pollard Rho or slow divisibility based on
    // number's size:
    //if num >= 1 << 63 {
    // number is too big to use rho pollard without overflowing
    //trial_division_slow(num, factors);
    //} else if num > 1 {
    // number is still greater than 1, but not so big that we have to worry
    rho_pollard_factor(num, factors);
    //}
}

fn print_factors(num: u64) {
    print!("{}:", num);

    let mut factors = Vec::new();
    // we always start with table division, and go from there
    table_division(num, &mut factors);
    factors.sort();

    for fac in &factors {
        print!(" {}", fac);
    }
    println!();
}

fn print_factors_str(num_str: &str) {
    if let Err(e) = num_str.parse::<u64>().and_then(|x| Ok(print_factors(x))) {
        show_warning!("{}: {}", num_str, e);
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let matches = new_coreopts!(SYNTAX, SUMMARY, LONG_HELP).parse(args);

    if matches.free.is_empty() {
        let stdin = stdin();
        for line in stdin.lock().lines() {
            for number in line.unwrap().split_whitespace() {
                print_factors_str(number);
            }
        }
    } else {
        for num_str in &matches.free {
            print_factors_str(num_str);
        }
    }
    0
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate notify;

use notify::{RecommendedWatcher, Error, Watcher, Event};
use std::sync::mpsc::{channel, Receiver, RecvError};

use std::collections::HashMap;
use std::io;
use std::path::PathBuf;

use actions::Action;

pub struct FilesWatcher {
    watcher: Box<RecommendedWatcher>,
    rx: Receiver<Event>,
    watches: HashMap<PathBuf, Vec<Box<Action>>>
}

impl FilesWatcher {
    pub fn new() -> FilesWatcher {
        let (tx, rx) = channel();
        let watcher: Result<RecommendedWatcher, Error> = Watcher::new(tx);

        FilesWatcher {
            watcher: Box::new(watcher.unwrap()),
            rx: rx,
            watches: HashMap::new()
        }
    }

    pub fn add_file(&mut self, path: PathBuf, actions: Vec<Box<Action>>) {
        let result = self.watcher.watch(&path);

        if result.is_ok() {
            println!("Watching file: {:?}", path);
            self.watches.insert(path, actions);
        } else {
            println!("Error adding watch for file: {:?}", result.err());
        }
    }

    pub fn wait_for_events(&mut self) -> Result<Event, RecvError> {
        self.rx.recv()
    }

    pub fn wait_and_execute(&mut self) -> Result<i32, io::Error> {
        let mut num_actions = 0;
        let event_result = self.rx.recv();

        match event_result {
            Err(_) => Err(io::Error::new(io::ErrorKind::Other, "Error receiving event")),
            Ok(event) => {
                match event.path {
                    None => println!("Warning: event has no path"),
                    Some(ref path) => {
                        let actions = self.watches.get(path);
                        if actions.is_some() {
                            for action in actions.unwrap() {
                                action.handle_change(&event);
                                num_actions += 1;
                            }
                        } else {
                            println!("Error: no actions found for path: {:?}", path.display());
                        }
                    }
                }

                Ok(num_actions)
            }
        }
    }
}

#[cfg(test)]
mod test {
    extern crate rand;

    use super::*;

    use self::rand::{thread_rng, Rng};
    use std::env::temp_dir;
    use std::fs::File;
    use std::fs::remove_file;
    use std::io::Write;
    use std::path::Path;
    use std::path::PathBuf;
    use actions::Action;
    use actions::print::PrintAction;

    #[test]
    fn watch_a_single_file() {
        let (path, mut file) = create_temp_file();
        let filepath = path.clone();

        let mut fw = FilesWatcher::new();
        let actions: Vec<Box<Action + 'static>> = Vec::new();
        fw.add_file(path, actions);

        write_to(&mut file);

        {
            let event = fw.wait_for_events().unwrap();
            match event.path {
                None => assert!(false, "Error: event has no path"),
                Some(event_path) => {
                    assert_eq!(filepath, event_path);
                }
            }
        }

        remove_temp_file(&filepath);
    }

    #[test]
    fn watch_two_files() {
        let (path1, mut file1) = create_temp_file();
        let (path2, mut file2) = create_temp_file();

        let filepath1 = path1.clone();
        let filepath2 = path2.clone();
        let actions1: Vec<Box<Action + 'static>> = Vec::new();
        let actions2: Vec<Box<Action + 'static>> = Vec::new();

        let mut fw = FilesWatcher::new();
        fw.add_file(path1, actions1);
        fw.add_file(path2, actions2);

        write_to(&mut file1);
        write_to(&mut file2);

        {
            let event = fw.wait_for_events().unwrap();
            match event.path {
                None => assert!(false, "Error: event has no path"),
                Some(event_path) => {
                    assert_eq!(filepath1, event_path);
                }
            }

            let event = fw.wait_for_events().unwrap();
            match event.path {
                None => assert!(false, "Error: event has no path"),
                Some(event_path) => {
                    assert_eq!(filepath2, event_path);
                }
            }
        }

        remove_temp_file(&filepath1);
        remove_temp_file(&filepath2);
    }

    #[test]
    fn watch_file_and_execute_no_actions() {
        let (path, mut file) = create_temp_file();
        let filepath = path.clone();

        let mut fw = FilesWatcher::new();
        let actions: Vec<Box<Action + 'static>> = Vec::new();
        fw.add_file(path, actions);

        write_to(&mut file);

        {
            let actions_executed = fw.wait_and_execute().unwrap();
            assert_eq!(0, actions_executed);
        }

        remove_temp_file(&filepath);
    }

    #[test]
    fn watch_file_and_execute_one_print_action() {
        let (path, mut file) = create_temp_file();
        let filepath = path.clone();

        let mut fw = FilesWatcher::new();

        let print = PrintAction::new();
        let actions: Vec<Box<Action + 'static>> = vec![Box::new(print)];
        fw.add_file(path, actions);

        write_to(&mut file);

        {
            let actions_executed = fw.wait_and_execute().unwrap();
            assert_eq!(1, actions_executed);
        }

        remove_temp_file(&filepath);
    }

    #[test]
    fn watch_file_and_execute_five_print_actions() {
        let (path, mut file) = create_temp_file();
        let filepath = path.clone();

        let mut fw = FilesWatcher::new();

        let print1 = PrintAction::new();
        let print2 = PrintAction::new();
        let print3 = PrintAction::new();
        let print4 = PrintAction::new();
        let print5 = PrintAction::new();

        let actions: Vec<Box<Action + 'static>> = vec![
            Box::new(print1),
            Box::new(print2),
            Box::new(print3),
            Box::new(print4),
            Box::new(print5)
        ];
        fw.add_file(path, actions);

        write_to(&mut file);

        {
            let actions_executed = fw.wait_and_execute().unwrap();
            assert_eq!(5, actions_executed);
        }

        remove_temp_file(&filepath);
    }

    fn create_temp_file() -> (PathBuf, File) {
        let rand_part: String = thread_rng()
            .gen_ascii_chars()
            .take(8)
            .collect();

        let filename = "eagleeye-test-".to_string() + &rand_part;
        let path = temp_dir().join(filename);
        let file = File::create(&path).unwrap_or_else(|error|
            panic!("Failed to create temporary file: {}", error)
        );
        let path_buf = PathBuf::from(path);

        (path_buf, file)
    }

    fn remove_temp_file(path: &Path) {
        remove_file(path).unwrap_or_else(|error|
            panic!("Failed to create temporary file: {}", error)
        );
    }

    fn write_to(file: &mut File) {
        file
            .write(b"This should trigger an inotify event.")
            .unwrap_or_else(|error|
                panic!("Failed to write to file: {}", error)
            );
    }

}

<commit_msg>Explicitly flush file writes in tests<commit_after>extern crate libc;
extern crate notify;

use notify::{RecommendedWatcher, Error, Watcher, Event};
use std::sync::mpsc::{channel, Receiver, RecvError};

use std::collections::HashMap;
use std::io;
use std::path::PathBuf;

use actions::Action;

pub struct FilesWatcher {
    watcher: Box<RecommendedWatcher>,
    rx: Receiver<Event>,
    watches: HashMap<PathBuf, Vec<Box<Action>>>
}

impl FilesWatcher {
    pub fn new() -> FilesWatcher {
        let (tx, rx) = channel();
        let watcher: Result<RecommendedWatcher, Error> = Watcher::new(tx);

        FilesWatcher {
            watcher: Box::new(watcher.unwrap()),
            rx: rx,
            watches: HashMap::new()
        }
    }

    pub fn add_file(&mut self, path: PathBuf, actions: Vec<Box<Action>>) {
        let result = self.watcher.watch(&path);

        if result.is_ok() {
            println!("Watching file: {:?}", path);
            self.watches.insert(path, actions);
        } else {
            println!("Error adding watch for file: {:?}", result.err());
        }
    }

    pub fn wait_for_events(&mut self) -> Result<Event, RecvError> {
        self.rx.recv()
    }

    pub fn wait_and_execute(&mut self) -> Result<i32, io::Error> {
        let mut num_actions = 0;
        let event_result = self.rx.recv();

        match event_result {
            Err(_) => Err(io::Error::new(io::ErrorKind::Other, "Error receiving event")),
            Ok(event) => {
                match event.path {
                    None => println!("Warning: event has no path"),
                    Some(ref path) => {
                        let actions = self.watches.get(path);
                        if actions.is_some() {
                            for action in actions.unwrap() {
                                action.handle_change(&event);
                                num_actions += 1;
                            }
                        } else {
                            println!("Error: no actions found for path: {:?}", path.display());
                        }
                    }
                }

                Ok(num_actions)
            }
        }
    }
}

#[cfg(test)]
mod test {
    extern crate rand;

    use super::*;

    use self::rand::{thread_rng, Rng};
    use std::env::temp_dir;
    use std::fs::File;
    use std::fs::remove_file;
    use std::io::Write;
    use std::path::Path;
    use std::path::PathBuf;
    use actions::Action;
    use actions::print::PrintAction;

    #[test]
    fn watch_a_single_file() {
        let (path, mut file) = create_temp_file();
        let filepath = path.clone();

        let mut fw = FilesWatcher::new();
        let actions: Vec<Box<Action + 'static>> = Vec::new();
        fw.add_file(path, actions);

        write_to(&mut file);

        {
            let event = fw.wait_for_events().unwrap();
            match event.path {
                None => assert!(false, "Error: event has no path"),
                Some(event_path) => {
                    assert_eq!(filepath, event_path);
                }
            }
        }

        remove_temp_file(&filepath);
    }

    #[test]
    fn watch_two_files() {
        let (path1, mut file1) = create_temp_file();
        let (path2, mut file2) = create_temp_file();

        let filepath1 = path1.clone();
        let filepath2 = path2.clone();
        let actions1: Vec<Box<Action + 'static>> = Vec::new();
        let actions2: Vec<Box<Action + 'static>> = Vec::new();

        let mut fw = FilesWatcher::new();
        fw.add_file(path1, actions1);
        fw.add_file(path2, actions2);

        write_to(&mut file1);
        write_to(&mut file2);

        {
            let event = fw.wait_for_events().unwrap();
            match event.path {
                None => assert!(false, "Error: event has no path"),
                Some(event_path) => {
                    assert_eq!(filepath1, event_path);
                }
            }

            let event = fw.wait_for_events().unwrap();
            match event.path {
                None => assert!(false, "Error: event has no path"),
                Some(event_path) => {
                    assert_eq!(filepath2, event_path);
                }
            }
        }

        remove_temp_file(&filepath1);
        remove_temp_file(&filepath2);
    }

    #[test]
    fn watch_file_and_execute_no_actions() {
        let (path, mut file) = create_temp_file();
        let filepath = path.clone();

        let mut fw = FilesWatcher::new();
        let actions: Vec<Box<Action + 'static>> = Vec::new();
        fw.add_file(path, actions);

        write_to(&mut file);

        {
            let actions_executed = fw.wait_and_execute().unwrap();
            assert_eq!(0, actions_executed);
        }

        remove_temp_file(&filepath);
    }

    #[test]
    fn watch_file_and_execute_one_print_action() {
        let (path, mut file) = create_temp_file();
        let filepath = path.clone();

        let mut fw = FilesWatcher::new();

        let print = PrintAction::new();
        let actions: Vec<Box<Action + 'static>> = vec![Box::new(print)];
        fw.add_file(path, actions);

        write_to(&mut file);

        {
            let actions_executed = fw.wait_and_execute().unwrap();
            assert_eq!(1, actions_executed);
        }

        remove_temp_file(&filepath);
    }

    #[test]
    fn watch_file_and_execute_five_print_actions() {
        let (path, mut file) = create_temp_file();
        let filepath = path.clone();

        let mut fw = FilesWatcher::new();

        let print1 = PrintAction::new();
        let print2 = PrintAction::new();
        let print3 = PrintAction::new();
        let print4 = PrintAction::new();
        let print5 = PrintAction::new();

        let actions: Vec<Box<Action + 'static>> = vec![
            Box::new(print1),
            Box::new(print2),
            Box::new(print3),
            Box::new(print4),
            Box::new(print5)
        ];
        fw.add_file(path, actions);

        write_to(&mut file);

        {
            let actions_executed = fw.wait_and_execute().unwrap();
            assert_eq!(5, actions_executed);
        }

        remove_temp_file(&filepath);
    }

    fn create_temp_file() -> (PathBuf, File) {
        let rand_part: String = thread_rng()
            .gen_ascii_chars()
            .take(8)
            .collect();

        let filename = "eagleeye-test-".to_string() + &rand_part;
        let path = temp_dir().join(filename);
        let file = File::create(&path).unwrap_or_else(|error|
            panic!("Failed to create temporary file: {}", error)
        );
        let path_buf = PathBuf::from(path);

        (path_buf, file)
    }

    fn remove_temp_file(path: &Path) {
        remove_file(path).unwrap_or_else(|error|
            panic!("Failed to create temporary file: {}", error)
        );
    }

    fn write_to(file: &mut File) {
        file
            .write_all(b"This should trigger an inotify event.")
            .unwrap_or_else(|error|
                panic!("Failed to write to file: {}", error)
            );

        file
            .flush()
            .unwrap();
    }

}

<|endoftext|>


<commit_before>use frame::ChannelAssignment;

pub fn decode_left_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let left = buffer[i];
    let side = buffer[i + block_size];

    // right channel
    buffer[i + block_size] = left - side;
  }
}

fn decode_right_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let side  = buffer[i];
    let right = buffer[i + block_size];

    // left channel
    buffer[i] = side + right;
  }
}

fn decode_middle_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let mut middle = buffer[i];
    let side       = buffer[i + block_size];

    middle = (middle << 1) | (side & 1);

    // left and right channel
    buffer[i]              = (middle + side) >> 1;
    buffer[i + block_size] = (middle - side) >> 1;
  }
}

pub fn decode(channel_assignment: ChannelAssignment, buffer: &mut [i32]) {
  match channel_assignment {
    ChannelAssignment::Independent => return,
    ChannelAssignment::LeftSide    => decode_left_side(buffer),
    ChannelAssignment::RightSide   => decode_right_side(buffer),
    ChannelAssignment::MiddleSide  => decode_middle_side(buffer),
  }
}

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

  #[test]
  fn test_decode_left_side() {
    let mut channels = [ 2, 5, 83, 113, 127, -63, -45, -15
                       , 7, 38, 142, 238, 0, -152, -52, -18
                       ];
    let result       = [-5, -33, -59, -125, 127, 89, 7, 3];

    decode_left_side(&mut channels);

    assert_eq!(&channels[8..16], &result);
  }
}
<commit_msg>Make `decode_right_side` public for testing<commit_after>use frame::ChannelAssignment;

pub fn decode_left_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let left = buffer[i];
    let side = buffer[i + block_size];

    // right channel
    buffer[i + block_size] = left - side;
  }
}

pub fn decode_right_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let side  = buffer[i];
    let right = buffer[i + block_size];

    // left channel
    buffer[i] = side + right;
  }
}

fn decode_middle_side(buffer: &mut [i32]) {
  let block_size = buffer.len() / 2;

  for i in 0..block_size {
    let mut middle = buffer[i];
    let side       = buffer[i + block_size];

    middle = (middle << 1) | (side & 1);

    // left and right channel
    buffer[i]              = (middle + side) >> 1;
    buffer[i + block_size] = (middle - side) >> 1;
  }
}

pub fn decode(channel_assignment: ChannelAssignment, buffer: &mut [i32]) {
  match channel_assignment {
    ChannelAssignment::Independent => return,
    ChannelAssignment::LeftSide    => decode_left_side(buffer),
    ChannelAssignment::RightSide   => decode_right_side(buffer),
    ChannelAssignment::MiddleSide  => decode_middle_side(buffer),
  }
}

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

  #[test]
  fn test_decode_left_side() {
    let mut channels = [ 2, 5, 83, 113, 127, -63, -45, -15
                       , 7, 38, 142, 238, 0, -152, -52, -18
                       ];
    let result       = [-5, -33, -59, -125, 127, 89, 7, 3];

    decode_left_side(&mut channels);

    assert_eq!(&channels[8..16], &result);
  }
}
<|endoftext|>


<commit_before>#[deriving(Show)]
struct Vec2<T> {
    x: T,
    y: T,
}

impl<
    // Bound: `T` must implement the `Add` trait
    T: Add<T, T>
> Add<Vec2<T>, Vec2<T>>
for Vec2<T> {
    fn add(&self, rhs: &Vec2<T>) -> Vec2<T> {
        Vec2 {
            // `x` and `y` are of type `T`, and implement the `add` method
            x: self.x.add(&rhs.x),
            // The sugary `+` operator can also be used
            y: self.y + rhs.y,
        }
    }
}

impl<
    // Bound: `T` must implement the `Sub` trait
    T: Sub<T, T>
> Sub<Vec2<T>, Vec2<T>>
for Vec2<T> {
    fn sub(&self, rhs: &Vec2<T>) -> Vec2<T> {
        Vec2 {
            x: self.x - rhs.x,
            y: self.y - rhs.y,
        }
    }
}

impl<
    // Bound: `T` must implement *both* the `Add` trait and the `Mul` trait
    T: Add<T, T> + Mul<T, T>
> Vec2<T> {
    fn dot(&self, rhs: &Vec2<T>) -> T {
        (self.x * rhs.x) + (self.y * rhs.y)
    }
}

fn main() {
    // Floats implement the `Add`, `Mul` and `Sub` traits
    let v1 = Vec2 { x: 1.2_f32, y: 3.4 };
    let v2 = Vec2 { x: 5.6_f32, y: 7.8 };

    println!("{} + {} = {}", v1, v2, v1 + v2);
    println!("{} - {} = {}", v1, v2, v1 - v2);
    println!("{} . {} = {}", v1, v2, v1.dot(&v2));

    // Error! `char` doesn't implement the `Add` trait
    println!("{}", Vec2 { x: ' ', y: 'b' } + Vec2 { x: 'c', y: 'd' });
    // FIXME ^ Comment out this line
}
<commit_msg>fixed Mul trait implementation for Vec2<T><commit_after>#[deriving(Show)]
struct Vec2<T> {
    x: T,
    y: T,
}

impl<
    // Bound: `T` must implement the `Add` trait
    T: Add<T, T>
> Add<Vec2<T>, Vec2<T>>
for Vec2<T> {
    fn add(&self, rhs: &Vec2<T>) -> Vec2<T> {
        Vec2 {
            // `x` and `y` are of type `T`, and implement the `add` method
            x: self.x.add(&rhs.x),
            // The sugary `+` operator can also be used
            y: self.y + rhs.y,
        }
    }
}

impl<
    // Bound: `T` must implement the `Sub` trait
    T: Sub<T, T>
> Sub<Vec2<T>, Vec2<T>>
for Vec2<T> {
    fn sub(&self, rhs: &Vec2<T>) -> Vec2<T> {
        Vec2 {
            x: self.x - rhs.x,
            y: self.y - rhs.y,
        }
    }
}

impl<
    // Bound: `T` must implement *both* the `Add` trait and the `Mul` trait
    T: Add<T, T> + Mul<T, T>
> Mul<Vec2<T>, T>
for Vec2<T> {
    fn mul(&self, rhs: &Vec2<T>) -> T {
        (self.x * rhs.x) + (self.y * rhs.y)
    }
}

fn main() {
    // Floats implement the `Add`, `Mul` and `Sub` traits
    let v1 = Vec2 { x: 1.2_f32, y: 3.4 };
    let v2 = Vec2 { x: 5.6_f32, y: 7.8 };

    println!("{} + {} = {}", v1, v2, v1 + v2);
    println!("{} - {} = {}", v1, v2, v1 - v2);
    println!("{} . {} = {}", v1, v2, v1.dot(&v2));

    // Error! `char` doesn't implement the `Add` trait
    println!("{}", Vec2 { x: ' ', y: 'b' } + Vec2 { x: 'c', y: 'd' });
    // FIXME ^ Comment out this line
}
<|endoftext|>


<commit_before>use std::slice;

use image::{RgbImage, ImageBuffer};
use discrete_transforms::dct_2d::Dct2D;
use itertools::Itertools;

#[derive(Debug)]
pub struct StegObject {
    steg_image: RgbImage,
    tiles: Vec<u8>,
    message_length: u32,
    dct_tiles: Vec<f64>,
    quantized_tiles: Vec<i32>,
    message_bits: Vec<u8>,
    message: String
}

impl StegObject {
    pub fn new() -> StegObject {
        StegObject {
            steg_image: ImageBuffer::new(0, 0),
            tiles: vec![],
            message_length: 0,
            dct_tiles: vec![],
            quantized_tiles: vec![],
            message_bits: vec![],
            message: String::new()
        }
    }

    pub fn set_steg_image(&mut self, input_path: &'static str) -> &mut Self {
        self.steg_image = image::open(input_path).unwrap().as_rgb8().unwrap().clone();

        self
    }

    pub fn set_message_length(&mut self, length: u32 ) -> &mut Self{
        self.message_length = length;

        self
    }

    pub fn decode(&mut self) {
        self.tile_image();

        let mut dct = Dct2D::new();

        for chunk in &self.tiles.iter().chunks(64) {
            let input = chunk.map(|x| *x as f64).collect_vec();

            dct.set_input(input);

            self.dct_tiles.extend(&dct.forward());
        }

        self.quantize();
        self.create_message();
    }

    fn tile_image(&mut self) {
        let (width, height) = self.steg_image.dimensions();
        let mut count = 0;
        let mut pixel_count = 0;

        for row_index in 0..(height / 8) as u32 {
            for col_index in 0..(width / 8) as u32 {
                for channel in 0..3 {
                    if count == self.message_length {
                        break
                    }

                    for row in 0..8 {
                        for column in 0..8 {
                            let pixel = self.steg_image.get_pixel(column + (col_index * 8),
                                                                     row + (row_index * 8));

                            pixel_count += 1;

                            self.tiles.push(pixel.data[channel]);
                        }
                    }

                    count += 1;
                }
            }
        }
    }

    fn quantize(&mut self) {
        for x in 0..self.dct_tiles.len() / 64 {
            let quantized_coeff = self.dct_tiles[x * 64].round() / 16.0;

            self.quantized_tiles.push(quantized_coeff.round() as i32);
        }
    }

    fn create_message(&mut self) {
        for chunk in &self.quantized_tiles.iter().chunks(8) {
            let mut byte = 0_u8;

            let mut message_bits = chunk.map(|b| (*b % 2) as u8).collect_vec();

            message_bits.reverse();

            for (index, bit) in message_bits.into_iter().enumerate() {
                let temp = bit << index as u8;
                byte = byte + temp;
            }

            self.message.push_str(&String::from_utf8(vec![byte; 1]).unwrap());
        }

        println!("{:?}", self.message);
    }
}

#[test]
fn test_decode() {
    let mut steg_object = StegObject::new();

    steg_object.set_message_length(8);
    steg_object.set_steg_image("output.png");
    steg_object.decode();
}<commit_msg>Remove unused code / import<commit_after>use image::{RgbImage, ImageBuffer};
use discrete_transforms::dct_2d::Dct2D;
use itertools::Itertools;

#[derive(Debug)]
pub struct StegObject {
    steg_image: RgbImage,
    tiles: Vec<u8>,
    message_length: u32,
    dct_tiles: Vec<f64>,
    quantized_tiles: Vec<i32>,
    message_bits: Vec<u8>,
    message: String
}

impl StegObject {
    pub fn new() -> StegObject {
        StegObject {
            steg_image: ImageBuffer::new(0, 0),
            tiles: vec![],
            message_length: 0,
            dct_tiles: vec![],
            quantized_tiles: vec![],
            message_bits: vec![],
            message: String::new()
        }
    }

    pub fn set_steg_image(&mut self, input_path: &'static str) -> &mut Self {
        self.steg_image = image::open(input_path).unwrap().as_rgb8().unwrap().clone();

        self
    }

    pub fn set_message_length(&mut self, length: u32 ) -> &mut Self{
        self.message_length = length;

        self
    }

    pub fn decode(&mut self) {
        self.tile_image();

        let mut dct = Dct2D::new();

        for chunk in &self.tiles.iter().chunks(64) {
            let input = chunk.map(|x| *x as f64).collect_vec();

            dct.set_input(input);

            self.dct_tiles.extend(&dct.forward());
        }

        self.quantize();
        self.create_message();
    }

    fn tile_image(&mut self) {
        let (width, height) = self.steg_image.dimensions();
        let mut count = 0;

        for row_index in 0..(height / 8) as u32 {
            for col_index in 0..(width / 8) as u32 {
                for channel in 0..3 {
                    if count == self.message_length {
                        break
                    }

                    for row in 0..8 {
                        for column in 0..8 {
                            let pixel = self.steg_image.get_pixel(column + (col_index * 8),
                                                                     row + (row_index * 8));

                            pixel_count += 1;

                            self.tiles.push(pixel.data[channel]);
                        }
                    }

                    count += 1;
                }
            }
        }
    }

    fn quantize(&mut self) {
        for x in 0..self.dct_tiles.len() / 64 {
            let quantized_coeff = self.dct_tiles[x * 64].round() / 16.0;

            self.quantized_tiles.push(quantized_coeff.round() as i32);
        }
    }

    fn create_message(&mut self) {
        for chunk in &self.quantized_tiles.iter().chunks(8) {
            let mut byte = 0_u8;

            let mut message_bits = chunk.map(|b| (*b % 2) as u8).collect_vec();

            message_bits.reverse();

            for (index, bit) in message_bits.into_iter().enumerate() {
                let temp = bit << index as u8;
                byte = byte + temp;
            }

            self.message.push_str(&String::from_utf8(vec![byte; 1]).unwrap());
        }

        println!("{:?}", self.message);
    }
}

#[test]
fn test_decode() {
    let mut steg_object = StegObject::new();

    steg_object.set_message_length(8);
    steg_object.set_steg_image("output.png");
    steg_object.decode();
}<|endoftext|>


<commit_before>mod completion_item;
mod completion_context;

mod complete_dot;
mod complete_fn_param;
mod complete_keyword;
mod complete_snippet;
mod complete_path;
mod complete_scope;

use ra_db::SyntaxDatabase;

use crate::{
    db,
    Cancelable, FilePosition,
    completion::{
        completion_item::{Completions, CompletionKind},
        completion_context::CompletionContext,
    },
};

pub use crate::completion::completion_item::{CompletionItem, InsertText, CompletionItemKind};

/// Main entry point for completion. We run completion as a two-phase process.
///
/// First, we look at the position and collect a so-called `CompletionContext.
/// This is a somewhat messy process, because, during completion, syntax tree is
/// incomplete and can look really weird.
///
/// Once the context is collected, we run a series of completion routines which
/// look at the context and produce completion items.
pub(crate) fn completions(
    db: &db::RootDatabase,
    position: FilePosition,
) -> Cancelable<Option<Completions>> {
    let original_file = db.source_file(position.file_id);
    let ctx = ctry!(CompletionContext::new(db, &original_file, position)?);

    let mut acc = Completions::default();

    complete_fn_param::complete_fn_param(&mut acc, &ctx);
    complete_keyword::complete_expr_keyword(&mut acc, &ctx);
    complete_keyword::complete_use_tree_keyword(&mut acc, &ctx);
    complete_snippet::complete_expr_snippet(&mut acc, &ctx);
    complete_snippet::complete_item_snippet(&mut acc, &ctx);
    complete_path::complete_path(&mut acc, &ctx)?;
    complete_scope::complete_scope(&mut acc, &ctx)?;
    complete_dot::complete_dot(&mut acc, &ctx)?;

    Ok(Some(acc))
}

#[cfg(test)]
fn check_completion(code: &str, expected_completions: &str, kind: CompletionKind) {
    use crate::mock_analysis::{single_file_with_position, analysis_and_position};
    let (analysis, position) = if code.contains("//-") {
        analysis_and_position(code)
    } else {
        single_file_with_position(code)
    };
    let completions = completions(&analysis.db, position).unwrap().unwrap();
    completions.assert_match(expected_completions, kind);
}
<commit_msg>explain that completion shouldn't do filtering<commit_after>mod completion_item;
mod completion_context;

mod complete_dot;
mod complete_fn_param;
mod complete_keyword;
mod complete_snippet;
mod complete_path;
mod complete_scope;

use ra_db::SyntaxDatabase;

use crate::{
    db,
    Cancelable, FilePosition,
    completion::{
        completion_item::{Completions, CompletionKind},
        completion_context::CompletionContext,
    },
};

pub use crate::completion::completion_item::{CompletionItem, InsertText, CompletionItemKind};

/// Main entry point for completion. We run completion as a two-phase process.
///
/// First, we look at the position and collect a so-called `CompletionContext.
/// This is a somewhat messy process, because, during completion, syntax tree is
/// incomplete and can look really weird.
///
/// Once the context is collected, we run a series of completion routines which
/// look at the context and produce completion items. One subtelty about this
/// phase is that completion engine should not filter by the substring which is
/// already present, it should give all possible variants for the identifier at
/// the caret. In other words, for
///
/// ```no-run
/// fn f() {
///     let foo = 92;
///     let _ = bar<|>
/// }
/// ```
///
/// `foo` *should* be present among the completion variants. Filtering by
/// identifier prefix/fuzzy match should be done higher in the stack, together
/// with ordering of completions (currently this is done by the client).
pub(crate) fn completions(
    db: &db::RootDatabase,
    position: FilePosition,
) -> Cancelable<Option<Completions>> {
    let original_file = db.source_file(position.file_id);
    let ctx = ctry!(CompletionContext::new(db, &original_file, position)?);

    let mut acc = Completions::default();

    complete_fn_param::complete_fn_param(&mut acc, &ctx);
    complete_keyword::complete_expr_keyword(&mut acc, &ctx);
    complete_keyword::complete_use_tree_keyword(&mut acc, &ctx);
    complete_snippet::complete_expr_snippet(&mut acc, &ctx);
    complete_snippet::complete_item_snippet(&mut acc, &ctx);
    complete_path::complete_path(&mut acc, &ctx)?;
    complete_scope::complete_scope(&mut acc, &ctx)?;
    complete_dot::complete_dot(&mut acc, &ctx)?;

    Ok(Some(acc))
}

#[cfg(test)]
fn check_completion(code: &str, expected_completions: &str, kind: CompletionKind) {
    use crate::mock_analysis::{single_file_with_position, analysis_and_position};
    let (analysis, position) = if code.contains("//-") {
        analysis_and_position(code)
    } else {
        single_file_with_position(code)
    };
    let completions = completions(&analysis.db, position).unwrap().unwrap();
    completions.assert_match(expected_completions, kind);
}
<|endoftext|>


<commit_before>use std;
use libc::*;

use cpu;
use ctxt::{Context, ctxt_ptr, get_ctxt};
use jit;
use mem::ptr::Ptr;
use os_cpu::*;

pub fn register_signals(ctxt: &Context) {
    unsafe {
        let ptr = Ptr::new(ctxt as *const Context as *mut c_void);
        ctxt_ptr = Some(ptr);

        let mut sa: sigaction = std::mem::uninitialized();

        sa.sa_sigaction = handler as usize;
        sigemptyset(&mut sa.sa_mask as *mut sigset_t);
        sa.sa_flags = SA_SIGINFO;

        if sigaction(SIGSEGV, &sa as *const sigaction, 0 as *mut sigaction) == -1 {
            perror("sigaction failed".as_ptr() as *const i8);
        }
    }
}

fn handler(signo: c_int, _: *const c_void, ucontext: *const c_void) {
    let mut es = read_execstate(ucontext);

    if let Some(trap) = detect_trap(signo as i32, &es) {
        use cpu::trap::{ASSERT, COMPILER};

        match trap {
            COMPILER => {
                let ctxt: &Context = get_ctxt();

                let ptr = Ptr::new(es.pc as *mut c_void);
                let code_map = ctxt.code_map.lock().unwrap();

                if let Some(fct_id) = code_map.get(ptr) {
                    let jit_fct = jit::generate(ctxt, fct_id);
                    cpu::trap::patch_fct_call(&mut es, jit_fct);
                    write_execstate(&es, ucontext as *mut c_void);
                } else {
                    println!("error: code not found for address {:x}", ptr.raw() as u64);
                    unsafe { _exit(200); }
                }
            }

            ASSERT => {
                println!("assert failed");
                unsafe { _exit(199); }
            }

            _ =>  {
                println!("error: trap {:?} not supported.", trap);
                unsafe { _exit(200); }
            }
        }

    // could not recognize trap -> crash vm
    } else {
        println!("error: trap not detected (signal {}).", signo);
        unsafe { _exit(1); }
    }
}
<commit_msg>signal: narrow lock-scope<commit_after>use std;
use libc::*;

use cpu;
use ctxt::{Context, ctxt_ptr, get_ctxt};
use jit;
use mem::ptr::Ptr;
use os_cpu::*;

pub fn register_signals(ctxt: &Context) {
    unsafe {
        let ptr = Ptr::new(ctxt as *const Context as *mut c_void);
        ctxt_ptr = Some(ptr);

        let mut sa: sigaction = std::mem::uninitialized();

        sa.sa_sigaction = handler as usize;
        sigemptyset(&mut sa.sa_mask as *mut sigset_t);
        sa.sa_flags = SA_SIGINFO;

        if sigaction(SIGSEGV, &sa as *const sigaction, 0 as *mut sigaction) == -1 {
            perror("sigaction failed".as_ptr() as *const i8);
        }
    }
}

fn handler(signo: c_int, _: *const c_void, ucontext: *const c_void) {
    let mut es = read_execstate(ucontext);

    if let Some(trap) = detect_trap(signo as i32, &es) {
        use cpu::trap::{ASSERT, COMPILER};

        match trap {
            COMPILER => {
                let ctxt: &Context = get_ctxt();

                let ptr = Ptr::new(es.pc as *mut c_void);
                let fct_id = {
                    let code_map = ctxt.code_map.lock().unwrap();

                    code_map.get(ptr)
                };

                if let Some(fct_id) = fct_id {
                    let jit_fct = jit::generate(ctxt, fct_id);
                    cpu::trap::patch_fct_call(&mut es, jit_fct);
                    write_execstate(&es, ucontext as *mut c_void);
                } else {
                    println!("error: code not found for address {:x}", ptr.raw() as u64);
                    unsafe { _exit(200); }
                }
            }

            ASSERT => {
                println!("assert failed");
                unsafe { _exit(199); }
            }

            _ =>  {
                println!("error: trap {:?} not supported.", trap);
                unsafe { _exit(200); }
            }
        }

    // could not recognize trap -> crash vm
    } else {
        println!("error: trap not detected (signal {}).", signo);
        unsafe { _exit(1); }
    }
}
<|endoftext|>


<commit_before>//! Miscellaneous helper traits, enums, and structs for models.

use super::prelude::*;
use crate::internal::RwLockExt;

#[cfg(all(feature = "model", feature = "utils"))]
use std::error::Error as StdError;
#[cfg(all(feature = "model", feature = "utils"))]
use std::result::Result as StdResult;
#[cfg(all(feature = "model", feature = "utils"))]
use std::str::FromStr;
#[cfg(all(feature = "model", feature = "utils"))]
use std::fmt;
#[cfg(all(feature = "model", any(feature = "cache", feature = "utils")))]
use crate::utils;

/// Allows something - such as a channel or role - to be mentioned in a message.
pub trait Mentionable {
    /// Creates a mentionable string, that will be able to notify and/or create
    /// a link to the item.
    fn mention(&self) -> String;
}

impl Mentionable for ChannelId {
    fn mention(&self) -> String { format!("<#{}>", self.0) }
}

impl Mentionable for Channel {
    fn mention(&self) -> String {
        match *self {
            Channel::Guild(ref x) => x.with(Mentionable::mention),
            Channel::Private(ref x) => x.with(Mentionable::mention),
            Channel::Category(ref x) => x.with(Mentionable::mention),
            Channel::__Nonexhaustive => unreachable!(),
        }
    }
}

impl Mentionable for ChannelCategory {
    fn mention(&self) -> String {
        format!("<#{}>", self.name)
    }
}

impl Mentionable for CurrentUser {
    fn mention(&self) -> String {
        format!("<@{}>", self.id.0)
    }
}

impl Mentionable for Emoji {
    fn mention(&self) -> String { format!("<:{}:{}>", self.name, self.id.0) }
}

impl Mentionable for Member {
    fn mention(&self) -> String { format!("<@{}>", self.user.with(|u| u.id.0)) }
}

impl Mentionable for PrivateChannel {
    fn mention(&self) -> String {
        format!("<#{}>", self.id.0)
    }
}

impl Mentionable for RoleId {
    fn mention(&self) -> String { format!("<@&{}>", self.0) }
}

impl Mentionable for Role {
    fn mention(&self) -> String { format!("<@&{}>", self.id.0) }
}

impl Mentionable for UserId {
    fn mention(&self) -> String { format!("<@{}>", self.0) }
}

impl Mentionable for User {
    fn mention(&self) -> String { format!("<@{}>", self.id.0) }
}

impl Mentionable for GuildChannel {
    fn mention(&self) -> String { format!("<#{}>", self.id.0) }
}

#[cfg(all(feature = "model", feature = "utils"))]
#[derive(Debug)]
pub enum UserParseError {
    InvalidUsername,
    Rest(Box<Error>),
    #[doc(hidden)]
    __Nonexhaustive,
}

#[cfg(all(feature = "model", feature = "utils"))]
impl fmt::Display for UserParseError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            UserParseError::InvalidUsername => f.write_str("invalid username"),
            UserParseError::Rest(_) => f.write_str("could not fetch"),
            UserParseError::__Nonexhaustive => unreachable!(),
        }
    }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl StdError for UserParseError {}

macro_rules! impl_from_str {
    (id: $($id:tt, $err:ident;)*) => {
        $(
            #[cfg(all(feature = "model", feature = "utils"))]
            #[derive(Debug)]
            pub enum $err {
                InvalidFormat,
            }

            #[cfg(all(feature = "model", feature = "utils"))]
            impl fmt::Display for $err {
                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                    match self {
                        $err::InvalidFormat => f.write_str("invalid id format"),
                    }
                }
            }

            #[cfg(all(feature = "model", feature = "utils"))]
            impl StdError for $err {}

            #[cfg(all(feature = "model", feature = "utils"))]
            impl FromStr for $id {
                type Err = $err;

                fn from_str(s: &str) -> StdResult<Self, Self::Err> {
                    Ok(match utils::parse_mention(s) {
                        Some(id) => $id(id),
                        None => s.parse::<u64>().map($id).map_err(|_| $err::InvalidFormat)?,
                    })
                }
            }
        )*
    };

    (struct: $($struct:ty, $id:tt, $err:ident, $invalid_variant:tt, $parse_fn:ident, $desc:expr;)*) => {
        $(
            #[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
            #[derive(Debug)]
            pub enum $err {
                NotPresentInCache,
                $invalid_variant,
            }

            #[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
            impl fmt::Display for $err {
                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                    match self {
                        $err::NotPresentInCache => f.write_str("not present in cache"),
                        $err::$invalid_variant => f.write_str($desc),
                    }
                }
            }

            #[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
            impl StdError for $err {}
        )*
    };
}

impl_from_str! { id:
    UserId, UserIdParseError;
    RoleId, RoleIdParseError;
    ChannelId, ChannelIdParseError;
}

impl_from_str! { struct:
    Channel, ChannelId, ChannelParseError, InvalidChannel, parse_channel, "invalid channel";
    Role, RoleId, RoleParseError, InvalidRole, parse_role, "invalid role";
}

/// A version of an emoji used only when solely the Id and name are known.
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct EmojiIdentifier {
    /// The Id of the emoji.
    pub id: EmojiId,
    /// The name of the emoji. It must be at least 2 characters long and can
    /// only contain alphanumeric characters and underscores.
    pub name: String,
}

#[cfg(all(feature = "model", feature = "utils"))]
impl EmojiIdentifier {
    /// Generates a URL to the emoji's image.
    #[inline]
    pub fn url(&self) -> String { format!(cdn!("/emojis/{}.png"), self.id) }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl FromStr for EmojiIdentifier {
    type Err = ();

    fn from_str(s: &str) -> StdResult<Self, ()> { utils::parse_emoji(s).ok_or_else(|| ()) }
}

/// A component that was affected during a service incident.
///
/// This is pulled from the Discord status page.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct AffectedComponent {
    pub name: String,
    #[serde(skip)]
    pub(crate) _nonexhaustive: (),
}

/// An incident retrieved from the Discord status page.
///
/// This is not necessarily a representation of an ongoing incident.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Incident {
    pub created_at: String,
    pub id: String,
    pub impact: String,
    pub incident_updates: Vec<IncidentUpdate>,
    pub monitoring_at: Option<String>,
    pub name: String,
    pub page_id: String,
    pub resolved_at: Option<String>,
    pub short_link: String,
    pub status: String,
    pub updated_at: String,
    #[serde(skip)]
    pub(crate) _nonexhaustive: (),
}

/// An update to an incident from the Discord status page.
///
/// This will typically state what new information has been discovered about an
/// incident.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct IncidentUpdate {
    pub affected_components: Vec<AffectedComponent>,
    pub body: String,
    pub created_at: String,
    pub display_at: String,
    pub id: String,
    pub incident_id: String,
    pub status: IncidentStatus,
    pub updated_at: String,
    #[serde(skip)]
    pub(crate) _nonexhaustive: (),
}

/// The type of status update during a service incident.
#[derive(Copy, Clone, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum IncidentStatus {
    Identified,
    Investigating,
    Monitoring,
    Postmortem,
    Resolved,
    #[doc(hidden)]
    __Nonexhaustive,
}

/// A Discord status maintenance message. This can be either for active
/// maintenances or for scheduled maintenances.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Maintenance {
    pub description: String,
    pub id: String,
    pub name: String,
    pub start: String,
    pub stop: String,
    #[serde(skip)]
    pub(crate) _nonexhaustive: (),
}

#[cfg(test)]
mod test {
    use crate::model::prelude::*;

    #[test]
    fn test_formatters() {
        assert_eq!(ChannelId(1).to_string(), "1");
        assert_eq!(EmojiId(2).to_string(), "2");
        assert_eq!(GuildId(3).to_string(), "3");
        assert_eq!(RoleId(4).to_string(), "4");
        assert_eq!(UserId(5).to_string(), "5");
    }

    #[cfg(feature = "utils")]
    mod utils {
        use crate::model::prelude::*;
        use parking_lot::RwLock;
        use std::sync::Arc;
        use crate::utils::Colour;

        #[test]
        fn test_mention() {
            let channel = Channel::Guild(Arc::new(RwLock::new(GuildChannel {
                bitrate: None,
                category_id: None,
                guild_id: GuildId(1),
                kind: ChannelType::Text,
                id: ChannelId(4),
                last_message_id: None,
                last_pin_timestamp: None,
                name: "a".to_string(),
                permission_overwrites: vec![],
                position: 1,
                topic: None,
                user_limit: None,
                nsfw: false,
                slow_mode_rate: Some(0),
                _nonexhaustive: (),
            })));
            let emoji = Emoji {
                animated: false,
                id: EmojiId(5),
                name: "a".to_string(),
                managed: true,
                require_colons: true,
                roles: vec![],
                _nonexhaustive: (),
            };
            let role = Role {
                id: RoleId(2),
                guild_id: GuildId(1),
                colour: Colour::ROSEWATER,
                hoist: false,
                managed: false,
                mentionable: false,
                name: "fake role".to_string(),
                permissions: Permissions::empty(),
                position: 1,
                _nonexhaustive: (),
            };
            let user = User {
                id: UserId(6),
                avatar: None,
                bot: false,
                discriminator: 4132,
                name: "fake".to_string(),
                _nonexhaustive: (),
            };
            let member = Member {
                deaf: false,
                guild_id: GuildId(2),
                joined_at: None,
                mute: false,
                nick: None,
                roles: vec![],
                user: Arc::new(RwLock::new(user.clone())),
                _nonexhaustive: (),
            };

            assert_eq!(ChannelId(1).mention(), "<#1>");
            assert_eq!(channel.mention(), "<#4>");
            assert_eq!(emoji.mention(), "<:a:5>");
            assert_eq!(member.mention(), "<@6>");
            assert_eq!(role.mention(), "<@&2>");
            assert_eq!(role.id.mention(), "<@&2>");
            assert_eq!(user.mention(), "<@6>");
            assert_eq!(user.id.mention(), "<@6>");
        }
    }
}
<commit_msg>Restrict mention parsing to be specific to the type of id (#880)<commit_after>//! Miscellaneous helper traits, enums, and structs for models.

use super::prelude::*;
use crate::internal::RwLockExt;

#[cfg(all(feature = "model", feature = "utils"))]
use std::error::Error as StdError;
#[cfg(all(feature = "model", feature = "utils"))]
use std::result::Result as StdResult;
#[cfg(all(feature = "model", feature = "utils"))]
use std::str::FromStr;
#[cfg(all(feature = "model", feature = "utils"))]
use std::fmt;
#[cfg(all(feature = "model", any(feature = "cache", feature = "utils")))]
use crate::utils;

/// Allows something - such as a channel or role - to be mentioned in a message.
pub trait Mentionable {
    /// Creates a mentionable string, that will be able to notify and/or create
    /// a link to the item.
    fn mention(&self) -> String;
}

impl Mentionable for ChannelId {
    fn mention(&self) -> String { format!("<#{}>", self.0) }
}

impl Mentionable for Channel {
    fn mention(&self) -> String {
        match *self {
            Channel::Guild(ref x) => x.with(Mentionable::mention),
            Channel::Private(ref x) => x.with(Mentionable::mention),
            Channel::Category(ref x) => x.with(Mentionable::mention),
            Channel::__Nonexhaustive => unreachable!(),
        }
    }
}

impl Mentionable for ChannelCategory {
    fn mention(&self) -> String {
        format!("<#{}>", self.name)
    }
}

impl Mentionable for CurrentUser {
    fn mention(&self) -> String {
        format!("<@{}>", self.id.0)
    }
}

impl Mentionable for Emoji {
    fn mention(&self) -> String { format!("<:{}:{}>", self.name, self.id.0) }
}

impl Mentionable for Member {
    fn mention(&self) -> String { format!("<@{}>", self.user.with(|u| u.id.0)) }
}

impl Mentionable for PrivateChannel {
    fn mention(&self) -> String {
        format!("<#{}>", self.id.0)
    }
}

impl Mentionable for RoleId {
    fn mention(&self) -> String { format!("<@&{}>", self.0) }
}

impl Mentionable for Role {
    fn mention(&self) -> String { format!("<@&{}>", self.id.0) }
}

impl Mentionable for UserId {
    fn mention(&self) -> String { format!("<@{}>", self.0) }
}

impl Mentionable for User {
    fn mention(&self) -> String { format!("<@{}>", self.id.0) }
}

impl Mentionable for GuildChannel {
    fn mention(&self) -> String { format!("<#{}>", self.id.0) }
}

#[cfg(all(feature = "model", feature = "utils"))]
#[derive(Debug)]
pub enum UserParseError {
    InvalidUsername,
    Rest(Box<Error>),
    #[doc(hidden)]
    __Nonexhaustive,
}

#[cfg(all(feature = "model", feature = "utils"))]
impl fmt::Display for UserParseError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            UserParseError::InvalidUsername => f.write_str("invalid username"),
            UserParseError::Rest(_) => f.write_str("could not fetch"),
            UserParseError::__Nonexhaustive => unreachable!(),
        }
    }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl StdError for UserParseError {}

macro_rules! impl_from_str {
    (id: $($id:ident, $err:ident, $parse_function:ident;)*) => {
        $(
            #[cfg(all(feature = "model", feature = "utils"))]
            #[derive(Debug)]
            pub enum $err {
                InvalidFormat,
            }

            #[cfg(all(feature = "model", feature = "utils"))]
            impl fmt::Display for $err {
                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                    match self {
                        $err::InvalidFormat => f.write_str("invalid id format"),
                    }
                }
            }

            #[cfg(all(feature = "model", feature = "utils"))]
            impl StdError for $err {}

            #[cfg(all(feature = "model", feature = "utils"))]
            impl FromStr for $id {
                type Err = $err;

                fn from_str(s: &str) -> StdResult<Self, Self::Err> {
                    let id = match utils::$parse_function(s) {
                        Some(id) => id,
                        None => s.parse::<u64>().map_err(|_| $err::InvalidFormat)?,
                    };

                    Ok($id(id))
                }
            }
        )*
    };

    (struct: $($struct:ty, $id:tt, $err:ident, $invalid_variant:tt, $parse_fn:ident, $desc:expr;)*) => {
        $(
            #[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
            #[derive(Debug)]
            pub enum $err {
                NotPresentInCache,
                $invalid_variant,
            }

            #[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
            impl fmt::Display for $err {
                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                    match self {
                        $err::NotPresentInCache => f.write_str("not present in cache"),
                        $err::$invalid_variant => f.write_str($desc),
                    }
                }
            }

            #[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
            impl StdError for $err {}
        )*
    };
}

impl_from_str! { id:
    UserId, UserIdParseError, parse_username;
    RoleId, RoleIdParseError, parse_role;
    ChannelId, ChannelIdParseError, parse_channel;
}

impl_from_str! { struct:
    Channel, ChannelId, ChannelParseError, InvalidChannel, parse_channel, "invalid channel";
    Role, RoleId, RoleParseError, InvalidRole, parse_role, "invalid role";
}

/// A version of an emoji used only when solely the Id and name are known.
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct EmojiIdentifier {
    /// The Id of the emoji.
    pub id: EmojiId,
    /// The name of the emoji. It must be at least 2 characters long and can
    /// only contain alphanumeric characters and underscores.
    pub name: String,
}

#[cfg(all(feature = "model", feature = "utils"))]
impl EmojiIdentifier {
    /// Generates a URL to the emoji's image.
    #[inline]
    pub fn url(&self) -> String { format!(cdn!("/emojis/{}.png"), self.id) }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl FromStr for EmojiIdentifier {
    type Err = ();

    fn from_str(s: &str) -> StdResult<Self, ()> { utils::parse_emoji(s).ok_or_else(|| ()) }
}

/// A component that was affected during a service incident.
///
/// This is pulled from the Discord status page.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct AffectedComponent {
    pub name: String,
    #[serde(skip)]
    pub(crate) _nonexhaustive: (),
}

/// An incident retrieved from the Discord status page.
///
/// This is not necessarily a representation of an ongoing incident.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Incident {
    pub created_at: String,
    pub id: String,
    pub impact: String,
    pub incident_updates: Vec<IncidentUpdate>,
    pub monitoring_at: Option<String>,
    pub name: String,
    pub page_id: String,
    pub resolved_at: Option<String>,
    pub short_link: String,
    pub status: String,
    pub updated_at: String,
    #[serde(skip)]
    pub(crate) _nonexhaustive: (),
}

/// An update to an incident from the Discord status page.
///
/// This will typically state what new information has been discovered about an
/// incident.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct IncidentUpdate {
    pub affected_components: Vec<AffectedComponent>,
    pub body: String,
    pub created_at: String,
    pub display_at: String,
    pub id: String,
    pub incident_id: String,
    pub status: IncidentStatus,
    pub updated_at: String,
    #[serde(skip)]
    pub(crate) _nonexhaustive: (),
}

/// The type of status update during a service incident.
#[derive(Copy, Clone, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum IncidentStatus {
    Identified,
    Investigating,
    Monitoring,
    Postmortem,
    Resolved,
    #[doc(hidden)]
    __Nonexhaustive,
}

/// A Discord status maintenance message. This can be either for active
/// maintenances or for scheduled maintenances.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Maintenance {
    pub description: String,
    pub id: String,
    pub name: String,
    pub start: String,
    pub stop: String,
    #[serde(skip)]
    pub(crate) _nonexhaustive: (),
}

#[cfg(test)]
mod test {
    use crate::model::prelude::*;

    #[test]
    fn test_formatters() {
        assert_eq!(ChannelId(1).to_string(), "1");
        assert_eq!(EmojiId(2).to_string(), "2");
        assert_eq!(GuildId(3).to_string(), "3");
        assert_eq!(RoleId(4).to_string(), "4");
        assert_eq!(UserId(5).to_string(), "5");
    }

    #[cfg(feature = "utils")]
    mod utils {
        use crate::model::prelude::*;
        use parking_lot::RwLock;
        use std::sync::Arc;
        use crate::utils::Colour;

        #[test]
        fn test_mention() {
            let channel = Channel::Guild(Arc::new(RwLock::new(GuildChannel {
                bitrate: None,
                category_id: None,
                guild_id: GuildId(1),
                kind: ChannelType::Text,
                id: ChannelId(4),
                last_message_id: None,
                last_pin_timestamp: None,
                name: "a".to_string(),
                permission_overwrites: vec![],
                position: 1,
                topic: None,
                user_limit: None,
                nsfw: false,
                slow_mode_rate: Some(0),
                _nonexhaustive: (),
            })));
            let emoji = Emoji {
                animated: false,
                id: EmojiId(5),
                name: "a".to_string(),
                managed: true,
                require_colons: true,
                roles: vec![],
                _nonexhaustive: (),
            };
            let role = Role {
                id: RoleId(2),
                guild_id: GuildId(1),
                colour: Colour::ROSEWATER,
                hoist: false,
                managed: false,
                mentionable: false,
                name: "fake role".to_string(),
                permissions: Permissions::empty(),
                position: 1,
                _nonexhaustive: (),
            };
            let user = User {
                id: UserId(6),
                avatar: None,
                bot: false,
                discriminator: 4132,
                name: "fake".to_string(),
                _nonexhaustive: (),
            };
            let member = Member {
                deaf: false,
                guild_id: GuildId(2),
                joined_at: None,
                mute: false,
                nick: None,
                roles: vec![],
                user: Arc::new(RwLock::new(user.clone())),
                _nonexhaustive: (),
            };

            assert_eq!(ChannelId(1).mention(), "<#1>");
            assert_eq!(channel.mention(), "<#4>");
            assert_eq!(emoji.mention(), "<:a:5>");
            assert_eq!(member.mention(), "<@6>");
            assert_eq!(role.mention(), "<@&2>");
            assert_eq!(role.id.mention(), "<@&2>");
            assert_eq!(user.mention(), "<@6>");
            assert_eq!(user.id.mention(), "<@6>");
        }

        #[test]
        fn parse_mentions() {
            assert_eq!("<@1234>".parse::<UserId>().unwrap(), UserId(1234));
            assert_eq!("<@&1234>".parse::<RoleId>().unwrap(), RoleId(1234));
            assert_eq!("<#1234>".parse::<ChannelId>().unwrap(), ChannelId(1234));

            assert!("<@1234>".parse::<ChannelId>().is_err());
            assert!("<@&1234>".parse::<UserId>().is_err());
            assert!("<#1234>".parse::<RoleId>().is_err());
        }
    }
}
<|endoftext|>


<commit_before>use criterion::{criterion_group, criterion_main, Criterion};

criterion_main!(benches);
criterion_group!(benches, analysis_bench);

fn analysis_bench(c: &mut Criterion) {
    let data = load_soundings();

    let mut group = c.benchmark_group("Analysis");
    group.sample_size(100);

    for (key, data_vec) in data {
        group.bench_function(key, |b| {
            let mut dvec = data_vec.clone();
            b.iter_batched(
                || {
                    if dvec.is_empty() {
                        dvec = data_vec.clone();
                    }

                    dvec.pop().unwrap()
                },
                |mut anal| {
                    anal.fill_in_missing_analysis_mut();
                },
                criterion::BatchSize::LargeInput,
            )
        });
    }

    group.finish();
}

fn load_soundings() -> std::collections::HashMap<String, Vec<sonde::Analysis>> {
    use std::collections::HashMap;

    let paths = std::fs::read_dir("bench_data").expect("Error reading bench data directory");

    let mut data = HashMap::new();
    for path in paths {
        let path = path.expect("Error unwrapping DirEntry");

        let key: String = path.file_name().to_string_lossy().to_string();

        if key.contains(".DS_Store") {
            continue;
        }

        let file_type = path.file_type().expect("Error getting file type");
        if file_type.is_dir() {
            let inner_paths =
                std::fs::read_dir(path.path()).expect("Error reading bench data sub-directory");
            let mut inner_data = vec![];
            for inner_path in inner_paths {
                let inner_path = inner_path.expect("Error unwraping DirEntry");
                let file_type = inner_path.file_type().expect("Error getting file type");
                assert!(file_type.is_file());
                let inner_vec = sonde::load_file(&inner_path.path()).expect("Error loading file");
                inner_data.extend(inner_vec);
            }

            let assume_none = data.insert(key, inner_data);
            if assume_none.is_some() {
                panic!("How did we get a file twice?");
            }
        } else {
            let anal_vec = sonde::load_file(&path.path()).expect("Error loading file.");
            let assume_none = data.insert(key, anal_vec);
            if assume_none.is_some() {
                panic!("How did we get a file twice?");
            }
        }
    }

    data
}
<commit_msg>Pass by reference when benching.<commit_after>use criterion::{criterion_group, criterion_main, Criterion};

criterion_main!(benches);
criterion_group!(benches, analysis_bench);

fn analysis_bench(c: &mut Criterion) {
    let data = load_soundings();

    let mut group = c.benchmark_group("Analysis");
    group.sample_size(100);

    for (key, data_vec) in data {
        group.bench_function(key, |b| {
            let mut dvec = data_vec.clone();
            b.iter_batched_ref(
                || {
                    if dvec.is_empty() {
                        dvec = data_vec.clone();
                    }

                    dvec.pop().unwrap()
                },
                |anal| {
                    anal.fill_in_missing_analysis_mut();
                },
                criterion::BatchSize::LargeInput,
            )
        });
    }

    group.finish();
}

fn load_soundings() -> std::collections::HashMap<String, Vec<sonde::Analysis>> {
    use std::collections::HashMap;

    let paths = std::fs::read_dir("bench_data").expect("Error reading bench data directory");

    let mut data = HashMap::new();
    for path in paths {
        let path = path.expect("Error unwrapping DirEntry");

        let key: String = path.file_name().to_string_lossy().to_string();

        if key.contains(".DS_Store") {
            continue;
        }

        let file_type = path.file_type().expect("Error getting file type");
        if file_type.is_dir() {
            let inner_paths =
                std::fs::read_dir(path.path()).expect("Error reading bench data sub-directory");
            let mut inner_data = vec![];
            for inner_path in inner_paths {
                let inner_path = inner_path.expect("Error unwraping DirEntry");
                let file_type = inner_path.file_type().expect("Error getting file type");
                assert!(file_type.is_file());
                let inner_vec = sonde::load_file(&inner_path.path()).expect("Error loading file");
                inner_data.extend(inner_vec);
            }

            let assume_none = data.insert(key, inner_data);
            if assume_none.is_some() {
                panic!("How did we get a file twice?");
            }
        } else {
            let anal_vec = sonde::load_file(&path.path()).expect("Error loading file.");
            let assume_none = data.insert(key, anal_vec);
            if assume_none.is_some() {
                panic!("How did we get a file twice?");
            }
        }
    }

    data
}
<|endoftext|>