<commit_before>use std::io::prelude::*;
use std::fs::File;
use std::process::{Command, Stdio};

extern crate clap;
use clap::{Arg, App};

extern crate isbfc;
use isbfc::Token::*;
use isbfc::parse;
use isbfc::optimize;

fn main() {
    let matches = App::new("isbfc")
        .version("0.0.1")
        .author("Ian D. Scott <ian@iandouglasscott.com>")
        .about("Brainfuck compiler")
        .arg(Arg::with_name("output_asm")
             .short("S")
             .help("Assemble but do not link"))
        .arg(Arg::with_name("debugging_symbols")
             .short("g")
             .help("Generate debugging information"))
        .arg(Arg::with_name("out_name")
             .short("o")
             .help("Output file name")
             .takes_value(true)
             .empty_values(false)
             .value_name("file"))
        .arg(Arg::with_name("tape_size")
             .long("tape-size")
             .help("Size of tape; defaults to 8192")
             .takes_value(true)
             .empty_values(false)
             .value_name("bytes"))
        .arg(Arg::with_name("FILENAME")
             .help("Source file to compile")
             .required(true)
             .index(1))
        .get_matches();

    let mut tape_size = 8192;
    if let Some(tape_size_str) = matches.value_of("tape_size") {
        tape_size = tape_size_str.parse::<i32>().unwrap();
    }

    let path = matches.value_of("FILENAME").unwrap();
    let name = path.rsplitn(2, '.').last().unwrap();
    let out_name = matches.value_of("out_name").unwrap_or(name);
    let mut file = File::open(&path).unwrap();
    let mut code = String::new();
    file.read_to_string(&mut code).unwrap();

    println!("Compiling...");
    let output = compile(&code, tape_size);
    if matches.is_present("output_asm") {
        let mut asmfile = File::create(format!("{}.s", name)).unwrap();
        asmfile.write_all(&output.into_bytes()).unwrap();
    } else {
        let debug = matches.is_present("debugging_symbols");
        asm_and_link(&output, &name, &out_name, debug);
    }
}

fn compile(code: &str, tape_size: i32) -> String {
    let tokens = parse(code);
    let tokens = optimize(tokens);

    let mut output = String::new();
    let mut loops: Vec<i32> = Vec::new();
    let mut ifs: Vec<i32> = Vec::new();
    let mut loopnum = 0;
    let mut ifnum = 0;
    let mut outbuffpos = 0;
    let mut outbuffsize = 0;
    for token in tokens.iter() {
        match *token {
            Add(offset, value) => {
                let dest = if offset == 0 {
                    "%r12".to_string()
                } else {
                    format!("{}(%rbx)", (offset*8))
                };
                if value == 1 && dest == "%r12" {
                    output.push_str("    inc %r12\n");
                } else if value >= 1 {
                    output.push_str(&format!("    addq ${}, {}\n", value, dest));
                } else if value == -1 && dest == "%r12" {
                    output.push_str("    dec %r12\n");
                } else if value <= -1 {
                    output.push_str(&format!("    subq ${}, {}\n", -value, dest));
                }
            },
            MulCopy(src_idx, dest_idx, mul) => {
                let mut src = if src_idx == 0 {
                    "%r12".to_string()
                } else {
                    format!("{}(%rbx)", (src_idx*8))
                };
                let dest = if dest_idx == 0 {
                    "%r12".to_string()
                } else {
                    format!("{}(%rbx)", (dest_idx*8))
                };

                if mul != -1 && mul != 1 {
                    output.push_str(&format!(concat!(
                                "    movq {}, %rax\n",
                                "    movq ${}, %rdx\n",
                                "    mulq %rdx\n"), src, mul.abs()));
                    src = "%rax".to_string();
                } else if src != "%r12" && dest != "%r12" {
                    // x86 cannot move memory to memory
                    output.push_str(&format!("    movq {}, %rax\n", src));
                    src = "%rax".to_string();
                }

                if mul > 0 {
                    output.push_str(&format!("    addq {}, {}\n", src, dest));
                } else {
                    output.push_str(&format!("    subq {}, {}\n", src, dest));
                }
            },
            Set(offset, value) => {
                if offset == 0 && value == 0 {
                    output.push_str("    xor %r12, %r12\n");
                } else if offset == 0 {
                    output.push_str(&format!("    movq ${}, %r12\n", value));
                } else {
                    output.push_str(&format!("    movq ${}, {}(%rbx)\n", value, offset*8));
                }
            },
            Move(offset) => {
                if offset != 0 {
                    output.push_str("    movq %r12, (%rbx)\n");
                    if offset > 0 {
                        output.push_str(&format!("    addq ${}, %rbx\n", offset*8));
                    } else {
                        output.push_str(&format!("    subq ${}, %rbx\n", -offset*8));
                    }
                    output.push_str("    movq (%rbx), %r12\n");
                }
            },
            Loop => {
                loopnum += 1;
                loops.push(loopnum);
                output.push_str(&format!(concat!(
                        "    jmp endloop{}\n",
                        "    loop{}:\n"),
                        loopnum, loopnum));
            },
            EndLoop => {
                let curloop = loops.pop().unwrap();
                output.push_str(&format!(concat!(
                            "    endloop{}:\n",
                            "    test %r12, %r12\n",
                            "    jnz loop{}\n"),
                            curloop, curloop))
            },
            If(offset) => {
                ifnum += 1;
                ifs.push(ifnum);
                if offset == 0 {
                    output.push_str("    test %r12, %r12\n");
                } else {
                    output.push_str(&format!("    cmpq $0, {}(%rbx)\n", offset*8));
                }
                output.push_str(&format!("    jz endif{}\n", ifnum));
            },
            EndIf =>
                output.push_str(&format!("    endif{}:\n", ifs.pop().unwrap())),
            Scan(offset) => {
                // Slighly more optimal than normal loop and move
                loopnum += 1;
                output.push_str(&format!(concat!(
                            "    movq %r12, (%rbx)\n",
                            "    jmp endloop{}\n",
                            "    loop{}:\n"),
                            loopnum, loopnum));
                if offset > 0 {
                    output.push_str(&format!("    addq ${}, %rbx\n", offset*8));
                } else {
                    output.push_str(&format!("    subq ${}, %rbx\n", -offset*8));
                }
                output.push_str(&format!(concat!(
                            "    endloop{}:\n",
                            "    cmp $0, (%rbx)\n",
                            "    jnz loop{}\n",
                            "    movq (%rbx), %r12\n"),
                            loopnum, loopnum));
            },
            Input =>
                output.push_str(concat!("\n    xor %rax, %rax\n",
                                        "    xor %rdi, %rdi\n",
                                        "    movq %rbx, %rsi\n",
                                        "    movq $1, %rdx\n",
                                        "    syscall\n",
                                        "    movq (%rbx), %r12\n\n")),
            LoadOut(offset, add) => {
                let outaddr = format!("(strbuff+{})", outbuffpos);
                if offset == 0 {
                    output.push_str(&format!("    movq %r12, {}\n", outaddr));
                } else {
                    output.push_str(&format!("    movq {}(%rbx), %rax\n", offset*8));
                    output.push_str(&format!("    movq %rax, {}\n", outaddr));
                }
                if add > 0 {
                    output.push_str(&format!("    addb ${}, {}\n", add, outaddr));
                } else if add < 0 {
                    output.push_str(&format!("    subb ${}, {}\n", -add, outaddr));
                }
                outbuffpos += 1;
            },
            LoadOutSet(value) => {
                let outaddr = format!("(strbuff+{})", outbuffpos);
                output.push_str(&format!("    movq ${}, {}\n", value, outaddr));
                outbuffpos += 1;
            },
            Output => {
                output.push_str(&format!(concat!(
                            "    movq $1, %rax\n",
                            "    movq $1, %rdi\n",
                            "    movq $strbuff, %rsi\n",
                            "    movq ${}, %rdx\n",
                            "    syscall\n\n"),
                            outbuffpos));

                if outbuffsize < outbuffpos + 8 {
                    outbuffsize = outbuffpos + 8;
                }
                outbuffpos = 0;
            }
        }
    }

    // Exit syscall
    output.push_str(concat!("\n    movq $60, %rax\n",
                            "    movq $0, %rdi\n",
                            "    syscall\n"));

    format!(concat!(
            ".section .bss\n",
            "    .lcomm strbuff, {outbuffsize}\n",
            "    .lcomm mem, {}\n",
            "    .set startidx, mem + {}\n",
            ".section .text\n",
            ".global _start\n",
            "_start:\n",
            "    xor %r12, %r12\n",
            "    movq $startidx, %rbx\n\n{}"),
            tape_size, tape_size/2, output, outbuffsize=outbuffsize)
}

fn asm_and_link(code: &str, name: &str, out_name: &str, debug: bool) {
    println!("Assembling...");

    let mut command = Command::new("as");
    if debug {
        command.arg("-g");
    }
    let mut child = command
        .arg("-") // Standard input
        .arg("-o")
        .arg(format!("{}.o", name))
        .stdin(Stdio::piped())
        .spawn().unwrap();

    child.stdin.take().unwrap().write_all(code.as_bytes()).unwrap();

    let status = child.wait().unwrap();
    if status.code() == Some(0) {
        println!("Linking...");
        Command::new("ld")
            .arg(format!("{}.o", name))
            .arg("-o")
            .arg(out_name)
            .spawn().unwrap();
    }
}
<commit_msg>Rearrange some code in bfcomp.rs<commit_after>use std::io::prelude::*;
use std::fs::File;
use std::process::{Command, Stdio};

extern crate clap;
use clap::{Arg, App};

extern crate isbfc;
use isbfc::Token;
use isbfc::Token::*;
use isbfc::parse;
use isbfc::optimize;

fn main() {
    let matches = App::new("isbfc")
        .version("0.0.1")
        .author("Ian D. Scott <ian@iandouglasscott.com>")
        .about("Brainfuck compiler")
        .arg(Arg::with_name("output_asm")
             .short("S")
             .help("Assemble but do not link"))
        .arg(Arg::with_name("debugging_symbols")
             .short("g")
             .help("Generate debugging information"))
        .arg(Arg::with_name("out_name")
             .short("o")
             .help("Output file name")
             .takes_value(true)
             .empty_values(false)
             .value_name("file"))
        .arg(Arg::with_name("tape_size")
             .long("tape-size")
             .help("Size of tape; defaults to 8192")
             .takes_value(true)
             .empty_values(false)
             .value_name("bytes"))
        .arg(Arg::with_name("FILENAME")
             .help("Source file to compile")
             .required(true)
             .index(1))
        .get_matches();

    let mut tape_size = 8192;
    if let Some(tape_size_str) = matches.value_of("tape_size") {
        tape_size = tape_size_str.parse::<i32>().unwrap();
    }

    let path = matches.value_of("FILENAME").unwrap();
    let name = path.rsplitn(2, '.').last().unwrap();
    let out_name = matches.value_of("out_name").unwrap_or(name);
    let mut file = File::open(&path).unwrap();
    let mut code = String::new();
    file.read_to_string(&mut code).unwrap();

    let tokens = parse(&code);
    let tokens = optimize(tokens);

    let output = compile(tokens, tape_size);
    if matches.is_present("output_asm") {
        let mut asmfile = File::create(format!("{}.s", name)).unwrap();
        asmfile.write_all(&output.into_bytes()).unwrap();
    } else {
        let debug = matches.is_present("debugging_symbols");
        asm_and_link(&output, &name, &out_name, debug);
    }
}

fn compile(tokens: Vec<Token>, tape_size: i32) -> String {
    println!("Compiling...");

    let mut output = String::new();
    let mut loops: Vec<i32> = Vec::new();
    let mut ifs: Vec<i32> = Vec::new();
    let mut loopnum = 0;
    let mut ifnum = 0;
    let mut outbuffpos = 0;
    let mut outbuffsize = 0;
    for token in tokens.iter() {
        match *token {
            Add(offset, value) => {
                let dest = if offset == 0 {
                    "%r12".to_string()
                } else {
                    format!("{}(%rbx)", (offset*8))
                };
                if value == 1 && dest == "%r12" {
                    output.push_str("    inc %r12\n");
                } else if value >= 1 {
                    output.push_str(&format!("    addq ${}, {}\n", value, dest));
                } else if value == -1 && dest == "%r12" {
                    output.push_str("    dec %r12\n");
                } else if value <= -1 {
                    output.push_str(&format!("    subq ${}, {}\n", -value, dest));
                }
            },
            MulCopy(src_idx, dest_idx, mul) => {
                let mut src = if src_idx == 0 {
                    "%r12".to_string()
                } else {
                    format!("{}(%rbx)", (src_idx*8))
                };
                let dest = if dest_idx == 0 {
                    "%r12".to_string()
                } else {
                    format!("{}(%rbx)", (dest_idx*8))
                };

                if mul != -1 && mul != 1 {
                    output.push_str(&format!(concat!(
                                "    movq {}, %rax\n",
                                "    movq ${}, %rdx\n",
                                "    mulq %rdx\n"), src, mul.abs()));
                    src = "%rax".to_string();
                } else if src != "%r12" && dest != "%r12" {
                    // x86 cannot move memory to memory
                    output.push_str(&format!("    movq {}, %rax\n", src));
                    src = "%rax".to_string();
                }

                if mul > 0 {
                    output.push_str(&format!("    addq {}, {}\n", src, dest));
                } else {
                    output.push_str(&format!("    subq {}, {}\n", src, dest));
                }
            },
            Set(offset, value) => {
                if offset == 0 && value == 0 {
                    output.push_str("    xor %r12, %r12\n");
                } else if offset == 0 {
                    output.push_str(&format!("    movq ${}, %r12\n", value));
                } else {
                    output.push_str(&format!("    movq ${}, {}(%rbx)\n", value, offset*8));
                }
            },
            Move(offset) => {
                if offset != 0 {
                    output.push_str("    movq %r12, (%rbx)\n");
                    if offset > 0 {
                        output.push_str(&format!("    addq ${}, %rbx\n", offset*8));
                    } else {
                        output.push_str(&format!("    subq ${}, %rbx\n", -offset*8));
                    }
                    output.push_str("    movq (%rbx), %r12\n");
                }
            },
            Loop => {
                loopnum += 1;
                loops.push(loopnum);
                output.push_str(&format!(concat!(
                        "    jmp endloop{}\n",
                        "    loop{}:\n"),
                        loopnum, loopnum));
            },
            EndLoop => {
                let curloop = loops.pop().unwrap();
                output.push_str(&format!(concat!(
                            "    endloop{}:\n",
                            "    test %r12, %r12\n",
                            "    jnz loop{}\n"),
                            curloop, curloop))
            },
            If(offset) => {
                ifnum += 1;
                ifs.push(ifnum);
                if offset == 0 {
                    output.push_str("    test %r12, %r12\n");
                } else {
                    output.push_str(&format!("    cmpq $0, {}(%rbx)\n", offset*8));
                }
                output.push_str(&format!("    jz endif{}\n", ifnum));
            },
            EndIf =>
                output.push_str(&format!("    endif{}:\n", ifs.pop().unwrap())),
            Scan(offset) => {
                // Slighly more optimal than normal loop and move
                loopnum += 1;
                output.push_str(&format!(concat!(
                            "    movq %r12, (%rbx)\n",
                            "    jmp endloop{}\n",
                            "    loop{}:\n"),
                            loopnum, loopnum));
                if offset > 0 {
                    output.push_str(&format!("    addq ${}, %rbx\n", offset*8));
                } else {
                    output.push_str(&format!("    subq ${}, %rbx\n", -offset*8));
                }
                output.push_str(&format!(concat!(
                            "    endloop{}:\n",
                            "    cmp $0, (%rbx)\n",
                            "    jnz loop{}\n",
                            "    movq (%rbx), %r12\n"),
                            loopnum, loopnum));
            },
            Input =>
                output.push_str(concat!("\n    xor %rax, %rax\n",
                                        "    xor %rdi, %rdi\n",
                                        "    movq %rbx, %rsi\n",
                                        "    movq $1, %rdx\n",
                                        "    syscall\n",
                                        "    movq (%rbx), %r12\n\n")),
            LoadOut(offset, add) => {
                let outaddr = format!("(strbuff+{})", outbuffpos);
                if offset == 0 {
                    output.push_str(&format!("    movq %r12, {}\n", outaddr));
                } else {
                    output.push_str(&format!("    movq {}(%rbx), %rax\n", offset*8));
                    output.push_str(&format!("    movq %rax, {}\n", outaddr));
                }
                if add > 0 {
                    output.push_str(&format!("    addb ${}, {}\n", add, outaddr));
                } else if add < 0 {
                    output.push_str(&format!("    subb ${}, {}\n", -add, outaddr));
                }
                outbuffpos += 1;
            },
            LoadOutSet(value) => {
                let outaddr = format!("(strbuff+{})", outbuffpos);
                output.push_str(&format!("    movq ${}, {}\n", value, outaddr));
                outbuffpos += 1;
            },
            Output => {
                output.push_str(&format!(concat!(
                            "    movq $1, %rax\n",
                            "    movq $1, %rdi\n",
                            "    movq $strbuff, %rsi\n",
                            "    movq ${}, %rdx\n",
                            "    syscall\n\n"),
                            outbuffpos));

                if outbuffsize < outbuffpos + 8 {
                    outbuffsize = outbuffpos + 8;
                }
                outbuffpos = 0;
            }
        }
    }

    // Exit syscall
    output.push_str(concat!("\n    movq $60, %rax\n",
                            "    movq $0, %rdi\n",
                            "    syscall\n"));

    format!(concat!(
            ".section .bss\n",
            "    .lcomm strbuff, {outbuffsize}\n",
            "    .lcomm mem, {}\n",
            "    .set startidx, mem + {}\n",
            ".section .text\n",
            ".global _start\n",
            "_start:\n",
            "    xor %r12, %r12\n",
            "    movq $startidx, %rbx\n\n{}"),
            tape_size, tape_size/2, output, outbuffsize=outbuffsize)
}

fn asm_and_link(code: &str, name: &str, out_name: &str, debug: bool) {
    println!("Assembling...");

    let mut command = Command::new("as");
    if debug {
        command.arg("-g");
    }
    let mut child = command
        .arg("-") // Standard input
        .arg("-o")
        .arg(format!("{}.o", name))
        .stdin(Stdio::piped())
        .spawn().unwrap();

    child.stdin.take().unwrap().write_all(code.as_bytes()).unwrap();

    let status = child.wait().unwrap();
    if status.code() == Some(0) {
        println!("Linking...");
        Command::new("ld")
            .arg(format!("{}.o", name))
            .arg("-o")
            .arg(out_name)
            .spawn().unwrap();
    }
}
<|endoftext|>


<commit_before>use itertools::Itertools;
use ordered_float::OrderedFloat;
use rayon::prelude::*;

use super::CharIndex;
use super::enigma::Enigma;

use constants::MAX_PLUGS;
use fitness::{IoC, Bigram, Quadgram, FitnessFn};

lazy_static! {
    // The vector of key/ring settings ["AAA", "AAB", ..., "ZZY", "ZZZ"].
    static ref ALPHAS: Vec<String> = {
        iproduct!('A'..='Z', 'A'..='Z', 'A'..='Z')
            .map(|(a, b, c)| [a, b, c].iter().collect())
            .collect()
    };

    // The vector of permutations ["123", "124", "125", ..., "542", "543"].
    static ref ROTORS: Vec<String> = {
        ('1'..='5').permutations(3)
            .map(|p| p.iter().collect())
            .collect()
    };
}

type ScoreFn = fn(&str) -> f64;

/// Decrypts the given string by iterating through multiple possible Enigma
/// configurations, returning `(plaintext, Enigma)` corresponding to the most
/// probable decryption.
///
/// Assumes `msg` contains only uppercase ASCII characters.
pub fn decrypt(msg: &str) -> (String, Enigma) {
    let (rotor, first_key) = guess_rotor_and_first_key(msg, IoC::score);
    let (key, ring) = guess_key_and_ring(msg, Bigram::score, rotor.clone(), first_key);
    let mut enigma = guess_plugboard(msg, Quadgram::score, rotor, key, ring);

    (enigma.encrypt(msg), enigma)
}

/// Given a piece of ciphertext and a fitness function, tries all valid rotor
/// and key combinations, and returns the rotor settings and first key that
/// best decrypt the ciphertext.
fn guess_rotor_and_first_key(msg: &str, score_fn: ScoreFn) -> (String, char) {
    let (rotor, key) = iproduct!(ROTORS.iter(), ALPHAS.iter())
        .collect::<Vec<_>>()
        .into_par_iter()
        .max_by_key(|&(rotor, key)| {
            let mut enigma = Enigma::new(rotor, key, "AAA", 'B', "");
            OrderedFloat(score_fn(&enigma.encrypt(msg)))
        }).unwrap();

    (rotor.clone(), key.chars().nth(0).unwrap())
}

/// Given the a set of rotors and the first key setting, tries all 26^4 ==
/// 456,976 key and ring settings for the mid and fast rotors, and returns
/// the key and ring settings corresponding to the best decryption.
fn guess_key_and_ring(msg: &str, score_fn: ScoreFn, rotor: String, first_key: char)
    -> (String, String) {
    // Compute the key offset based on the first key setting, so that we only
    // iterate over the next 676 key settings (this implicitly fixes the slow
    // rotor's key setting at 'A', which is intentional because this setting
    // does not affect the overall decryption).
    let key_offset = first_key.index() * 676;

    let (_, key, ring) = iproduct!(key_offset..(key_offset + 676), 0..676)
        .collect::<Vec<_>>()
        .par_iter()
        .map(|&(key_index, ring_index)| {
            let key = &ALPHAS[key_index];
            let ring = &ALPHAS[ring_index];

            let mut enigma = Enigma::new(&rotor, key, ring, 'B', "");
            (OrderedFloat(score_fn(&enigma.encrypt(msg))), key, ring)
        }).max().unwrap();

    (key.clone(), ring.clone())
}

/// Given rotor, key, and ring settings, repeatedly adds plugs until adding
/// a plug does not increase the overall fitness of the decryption. Returns
/// the resulting `Enigma`.
fn guess_plugboard(msg: &str, score_fn: ScoreFn, rotor: String, key: String,
        ring: String) -> Enigma {
    let mut plug_pool: Vec<char> = ('A'..='Z').collect();

    let mut best_plugboard = "".to_string();
    let mut best_score = score_fn(&msg);

    for _ in 0..MAX_PLUGS {
        let pool = plug_pool.clone();
        let combos = pool.iter().combinations(2).collect::<Vec<_>>();
        let (score, plugs, plugboard) = combos.par_iter()
            .map(|plugs| {
                let plugboard = format!("{} {}{}", best_plugboard, plugs[0], plugs[1]);
                let mut enigma = Enigma::new(&rotor, &key, &ring, 'B', &plugboard.trim());
                (OrderedFloat(score_fn(&enigma.encrypt(&msg))), plugs, plugboard)
            }).max().unwrap();

        if *score > best_score {
            best_score = *score;
            best_plugboard = plugboard.trim().to_string();
            plug_pool.retain(|&c| c != *plugs[0] && c != *plugs[1]);
        } else {
            break;
        }
    }

    Enigma::new(&rotor, &key, &ring, 'B', &best_plugboard)
}

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

    #[test]
    fn static_vars() {
        assert_eq!(ALPHAS.len(), 26 * 26 * 26);
        assert_eq!(ROTORS.len(), 120 / 2);  // n! / (n - k)!
    }
}

<commit_msg>Update Enigma setting printing format<commit_after>use itertools::Itertools;
use ordered_float::OrderedFloat;
use rayon::prelude::*;

use super::CharIndex;
use super::enigma::Enigma;

use constants::MAX_PLUGS;
use fitness::{IoC, Bigram, Quadgram, FitnessFn};

lazy_static! {
    // The vector of key/ring settings ["AAA", "AAB", ..., "ZZY", "ZZZ"].
    static ref ALPHAS: Vec<String> = {
        iproduct!('A'..='Z', 'A'..='Z', 'A'..='Z')
            .map(|(a, b, c)| [a, b, c].iter().collect())
            .collect()
    };

    // The vector of permutations ["123", "124", "125", ..., "542", "543"].
    static ref ROTORS: Vec<String> = {
        ('1'..='5').permutations(3)
            .map(|p| p.iter().collect())
            .collect()
    };
}

/// Decrypts the given string by iterating through multiple possible Enigma
/// configurations, returning `(plaintext, Enigma)` corresponding to the most
/// probable decryption.
///
/// Assumes `msg` contains only uppercase ASCII characters.
pub fn decrypt(msg: &str) -> (String, Enigma) {
    let (rotor, first_key) = guess_rotor_and_first_key(msg, IoC::score);
    let (key, ring) = guess_key_and_ring(msg, Bigram::score, rotor.clone(), first_key);
    let mut enigma = guess_plugboard(msg, Quadgram::score, rotor, key, ring);

    (enigma.encrypt(msg), enigma)
}

type ScoreFn = fn(&str) -> f64;

/// Given a piece of ciphertext and a fitness function, tries all valid rotor
/// and key combinations, and returns the rotor settings and first key that
/// best decrypt the ciphertext.
///
/// This method checks 60 * 26^3 == 1,054,560 settings in parallel.
fn guess_rotor_and_first_key(msg: &str, score_fn: ScoreFn) -> (String, char) {
    let (rotor, key) = iproduct!(ROTORS.iter(), ALPHAS.iter())
        .collect::<Vec<_>>()
        .into_par_iter()
        .max_by_key(|&(rotor, key)| {
            let mut enigma = Enigma::new(rotor, key, "AAA", 'B', "");
            OrderedFloat(score_fn(&enigma.encrypt(msg)))
        }).unwrap();

    (rotor.clone(), key.chars().nth(0).unwrap())
}

/// Given the a set of rotors and the first key setting, tries all key and
/// ring settings for the mid and fast rotors, and returns the key and ring
/// settings corresponding to the best decryption.
///
/// This method checks 26^4 == 456,976 settings in parallel.
fn guess_key_and_ring(msg: &str, score_fn: ScoreFn, rotor: String, first_key: char)
    -> (String, String) {
    // Compute the key offset based on the first key setting, so that we only
    // iterate over the next 676 key settings (this implicitly fixes the slow
    // rotor's key setting at 'A', which is intentional because this setting
    // does not affect the overall decryption).
    let key_offset = first_key.index() * 676;

    let (_, key, ring) = iproduct!(key_offset..(key_offset + 676), 0..676)
        .collect::<Vec<_>>()
        .par_iter()
        .map(|&(key_index, ring_index)| {
            let key = &ALPHAS[key_index];
            let ring = &ALPHAS[ring_index];

            let mut enigma = Enigma::new(&rotor, key, ring, 'B', "");
            (OrderedFloat(score_fn(&enigma.encrypt(msg))), key, ring)
        }).max().unwrap();

    (key.clone(), ring.clone())
}

/// Given rotor, key, and ring settings, repeatedly adds plugs until adding
/// a plug does not increase the overall fitness of the decryption. Returns
/// the resulting `Enigma`.
///
/// At most, this is MAX_PLUGS * 26^2 == 6,760 tests.
fn guess_plugboard(msg: &str, score_fn: ScoreFn, rotor: String, key: String,
        ring: String) -> Enigma {
    let mut plug_pool: Vec<char> = ('A'..='Z').collect();

    let mut best_plugboard = "".to_string();
    let mut best_score = score_fn(&msg);

    for _ in 0..MAX_PLUGS {
        let pool = plug_pool.clone();
        let combos = pool.iter().combinations(2).collect::<Vec<_>>();
        let (score, plugs, plugboard) = combos.par_iter()
            .map(|plugs| {
                let plugboard = format!("{} {}{}", best_plugboard, plugs[0], plugs[1]);
                let mut enigma = Enigma::new(&rotor, &key, &ring, 'B', &plugboard.trim());
                (OrderedFloat(score_fn(&enigma.encrypt(&msg))), plugs, plugboard)
            }).max().unwrap();

        if *score > best_score {
            best_score = *score;
            best_plugboard = plugboard.trim().to_string();
            plug_pool.retain(|&c| c != *plugs[0] && c != *plugs[1]);
        } else {
            break;
        }
    }

    Enigma::new(&rotor, &key, &ring, 'B', &best_plugboard)
}

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

    #[test]
    fn static_vars() {
        assert_eq!(ALPHAS.len(), 26 * 26 * 26);
        assert_eq!(ROTORS.len(), 120 / 2);  // n! / (n - k)!
    }
}

<|endoftext|>


<commit_before>#![cfg(feature = "stable_graph")]

extern crate petgraph;
extern crate itertools;
#[macro_use] extern crate defmac;

use petgraph::prelude::*;
use petgraph::stable_graph::node_index as n;
use petgraph::EdgeType;
use petgraph::algo::{scc, tarjan_scc};
use petgraph::visit::{
    EdgeRef,
    NodeIndexable,
    IntoEdgeReferences,
};

use itertools::assert_equal;

#[test]
fn node_indices() {
    let mut g = StableGraph::<_, ()>::new();
    let a = g.add_node(0);
    let b = g.add_node(1);
    let c = g.add_node(2);
    g.remove_node(b);
    let mut iter = g.node_indices();
    assert_eq!(iter.next(), Some(a));
    assert_eq!(iter.next(), Some(c));
    assert_eq!(iter.next(), None);
}

fn assert_sccs_eq(mut res: Vec<Vec<NodeIndex>>, normalized: Vec<Vec<NodeIndex>>) {
    // normalize the result and compare with the answer.
    for scc in res.iter_mut() {
        scc.sort();
    }
    // sort by minimum element
    res.sort_by(|v, w| v[0].cmp(&w[0]));
    assert_eq!(res, normalized);
}

#[test]
fn test_scc() {
    let mut gr: StableGraph<(), ()> = StableGraph::from_edges(&[
        (6, 0),
        (0, 3),
        (3, 6),
        (8, 6), (8, 2),
        (2, 5), (5, 8), (7, 5),
        (1, 7),
        (7, 4),
        (4, 1)]);
    // make an identical replacement of n(4) and leave a hole
    let x = gr.add_node(());
    gr.add_edge(n(7), x, ());
    gr.add_edge(x, n(1), ());
    gr.remove_node(n(4));
    println!("{:?}", gr);

    assert_sccs_eq(scc(&gr), vec![
        vec![n(0), n(3), n(6)],
        vec![n(1), n(7),   x ],
        vec![n(2), n(5), n(8)],
    ]);
}

#[test]
fn test_tarjan_scc() {
    let mut gr: StableGraph<(), ()> = StableGraph::from_edges(&[
        (6, 0),
        (0, 3),
        (3, 6),
        (8, 6), (8, 2),
        (2, 5), (5, 8), (7, 5),
        (1, 7),
        (7, 4),
        (4, 1)]);
    // make an identical replacement of n(4) and leave a hole
    let x = gr.add_node(());
    gr.add_edge(n(7), x, ());
    gr.add_edge(x, n(1), ());
    gr.remove_node(n(4));

    assert_sccs_eq(tarjan_scc(&gr), vec![
        vec![n(0), n(3), n(6)],
        vec![n(1), n(7),   x ],
        vec![n(2), n(5), n(8)],
    ]);
}

fn make_graph<Ty>() -> StableGraph<(), i32, Ty>
    where Ty: EdgeType,
{
    let mut gr = StableGraph::default();
    let mut c = 0..;
    let mut e = || -> i32 { c.next().unwrap() };
    gr.extend_with_edges(&[
        (6, 0, e()),
        (0, 3, e()),
        (3, 6, e()),
        (8, 6, e()),
        (8, 2, e()),
        (2, 5, e()),
        (5, 8, e()),
        (7, 5, e()),
        (1, 7, e()),
        (7, 4, e()),
        (8, 6, e()), // parallel edge
        (4, 1, e())]);
    // make an identical replacement of n(4) and leave a hole
    let x = gr.add_node(());
    gr.add_edge(n(7), x, e());
    gr.add_edge(x, n(1), e());
    gr.add_edge(x, x, e()); // make two self loops
    let rm_self_loop = gr.add_edge(x, x, e());
    gr.add_edge(x, x, e());
    gr.remove_node(n(4));
    gr.remove_node(n(6));
    gr.remove_edge(rm_self_loop);
    gr
}

defmac!(edges ref gr, x => gr.edges(x).map(|r| (r.target(), *r.weight())));
defmac!(edges_dir ref gr, x => gr.edges_directed(x, Outgoing).map(|r| (r.target(), *r.weight())));

#[test]
fn test_edges_directed() {
    let gr = make_graph::<Directed>();
    let x = n(9);
    assert_equal(edges!(gr, x), vec![(x, 16), (x, 14), (n(1), 13)]);
    assert_equal(edges!(gr, n(0)), vec![(n(3), 1)]);
    assert_equal(edges!(gr, n(4)), vec![]);
}

#[test]
fn test_edge_references() {
    let gr = make_graph::<Directed>();
    assert_eq!(gr.edge_count(), gr.edge_references().count());
}

#[test]
fn test_edges_undirected() {
    let gr = make_graph::<Undirected>();
    let x = n(9);
    assert_equal(edges!(gr, x), vec![(x, 16), (x, 14), (n(1), 13), (n(7), 12)]);
    assert_equal(edges!(gr, n(0)), vec![(n(3), 1)]);
    assert_equal(edges!(gr, n(4)), vec![]);
}

#[test]
fn test_edge_iterators_directed() {
    let gr = make_graph::<Directed>();
    for i in gr.node_indices() {
        itertools::assert_equal(
            gr.edges_directed(i, Outgoing),
            gr.edges(i));
    }
    let mut incoming = vec![Vec::new(); gr.node_bound()];

    for i in gr.node_indices() {
        for j in gr.neighbors(i) {
            incoming[j.index()].push(i);
        }
    }

    println!("{:#?}", gr);
    for i in gr.node_indices() {
        println!("Check incoming for {:?}, {:?}", i, incoming[i.index()]);
        itertools::assert_equal(
            gr.edges_directed(i, Incoming).map(|e| e.source()),
            incoming[i.index()].iter().rev().cloned());
    }
}

#[test]
fn test_edge_iterators_undir() {
    let gr = make_graph::<Undirected>();
    for i in gr.node_indices() {
        itertools::assert_equal(
            gr.edges_directed(i, Outgoing),
            gr.edges(i));
    }
    for i in gr.node_indices() {
        itertools::assert_equal(
            gr.edges_directed(i, Incoming),
            gr.edges(i));
    }
}
<commit_msg>Reduce verbosity of tests<commit_after>#![cfg(feature = "stable_graph")]

extern crate petgraph;
extern crate itertools;
#[macro_use] extern crate defmac;

use petgraph::prelude::*;
use petgraph::stable_graph::node_index as n;
use petgraph::EdgeType;
use petgraph::algo::{scc, tarjan_scc};
use petgraph::visit::{
    EdgeRef,
    NodeIndexable,
    IntoEdgeReferences,
};

use itertools::assert_equal;

#[test]
fn node_indices() {
    let mut g = StableGraph::<_, ()>::new();
    let a = g.add_node(0);
    let b = g.add_node(1);
    let c = g.add_node(2);
    g.remove_node(b);
    let mut iter = g.node_indices();
    assert_eq!(iter.next(), Some(a));
    assert_eq!(iter.next(), Some(c));
    assert_eq!(iter.next(), None);
}

fn assert_sccs_eq(mut res: Vec<Vec<NodeIndex>>, normalized: Vec<Vec<NodeIndex>>) {
    // normalize the result and compare with the answer.
    for scc in res.iter_mut() {
        scc.sort();
    }
    // sort by minimum element
    res.sort_by(|v, w| v[0].cmp(&w[0]));
    assert_eq!(res, normalized);
}

#[test]
fn test_scc() {
    let mut gr: StableGraph<(), ()> = StableGraph::from_edges(&[
        (6, 0),
        (0, 3),
        (3, 6),
        (8, 6), (8, 2),
        (2, 5), (5, 8), (7, 5),
        (1, 7),
        (7, 4),
        (4, 1)]);
    // make an identical replacement of n(4) and leave a hole
    let x = gr.add_node(());
    gr.add_edge(n(7), x, ());
    gr.add_edge(x, n(1), ());
    gr.remove_node(n(4));
    println!("{:?}", gr);

    assert_sccs_eq(scc(&gr), vec![
        vec![n(0), n(3), n(6)],
        vec![n(1), n(7),   x ],
        vec![n(2), n(5), n(8)],
    ]);
}

#[test]
fn test_tarjan_scc() {
    let mut gr: StableGraph<(), ()> = StableGraph::from_edges(&[
        (6, 0),
        (0, 3),
        (3, 6),
        (8, 6), (8, 2),
        (2, 5), (5, 8), (7, 5),
        (1, 7),
        (7, 4),
        (4, 1)]);
    // make an identical replacement of n(4) and leave a hole
    let x = gr.add_node(());
    gr.add_edge(n(7), x, ());
    gr.add_edge(x, n(1), ());
    gr.remove_node(n(4));

    assert_sccs_eq(tarjan_scc(&gr), vec![
        vec![n(0), n(3), n(6)],
        vec![n(1), n(7),   x ],
        vec![n(2), n(5), n(8)],
    ]);
}

fn make_graph<Ty>() -> StableGraph<(), i32, Ty>
    where Ty: EdgeType,
{
    let mut gr = StableGraph::default();
    let mut c = 0..;
    let mut e = || -> i32 { c.next().unwrap() };
    gr.extend_with_edges(&[
        (6, 0, e()),
        (0, 3, e()),
        (3, 6, e()),
        (8, 6, e()),
        (8, 2, e()),
        (2, 5, e()),
        (5, 8, e()),
        (7, 5, e()),
        (1, 7, e()),
        (7, 4, e()),
        (8, 6, e()), // parallel edge
        (4, 1, e())]);
    // make an identical replacement of n(4) and leave a hole
    let x = gr.add_node(());
    gr.add_edge(n(7), x, e());
    gr.add_edge(x, n(1), e());
    gr.add_edge(x, x, e()); // make two self loops
    let rm_self_loop = gr.add_edge(x, x, e());
    gr.add_edge(x, x, e());
    gr.remove_node(n(4));
    gr.remove_node(n(6));
    gr.remove_edge(rm_self_loop);
    gr
}

defmac!(edges ref gr, x => gr.edges(x).map(|r| (r.target(), *r.weight())));
defmac!(edges_dir ref gr, x => gr.edges_directed(x, Outgoing).map(|r| (r.target(), *r.weight())));

#[test]
fn test_edges_directed() {
    let gr = make_graph::<Directed>();
    let x = n(9);
    assert_equal(edges!(gr, x), vec![(x, 16), (x, 14), (n(1), 13)]);
    assert_equal(edges!(gr, n(0)), vec![(n(3), 1)]);
    assert_equal(edges!(gr, n(4)), vec![]);
}

#[test]
fn test_edge_references() {
    let gr = make_graph::<Directed>();
    assert_eq!(gr.edge_count(), gr.edge_references().count());
}

#[test]
fn test_edges_undirected() {
    let gr = make_graph::<Undirected>();
    let x = n(9);
    assert_equal(edges!(gr, x), vec![(x, 16), (x, 14), (n(1), 13), (n(7), 12)]);
    assert_equal(edges!(gr, n(0)), vec![(n(3), 1)]);
    assert_equal(edges!(gr, n(4)), vec![]);
}

#[test]
fn test_edge_iterators_directed() {
    let gr = make_graph::<Directed>();
    for i in gr.node_indices() {
        itertools::assert_equal(
            gr.edges_directed(i, Outgoing),
            gr.edges(i));
    }
    let mut incoming = vec![Vec::new(); gr.node_bound()];

    for i in gr.node_indices() {
        for j in gr.neighbors(i) {
            incoming[j.index()].push(i);
        }
    }

    println!("{:#?}", gr);
    for i in gr.node_indices() {
        itertools::assert_equal(
            gr.edges_directed(i, Incoming).map(|e| e.source()),
            incoming[i.index()].iter().rev().cloned());
    }
}

#[test]
fn test_edge_iterators_undir() {
    let gr = make_graph::<Undirected>();
    for i in gr.node_indices() {
        itertools::assert_equal(
            gr.edges_directed(i, Outgoing),
            gr.edges(i));
    }
    for i in gr.node_indices() {
        itertools::assert_equal(
            gr.edges_directed(i, Incoming),
            gr.edges(i));
    }
}
<|endoftext|>


<commit_before>extern crate image;

use self::image::imageops::resize;

use braille::make_braille;

pub struct Display {
    image: image::GrayImage,
    pub char_width: u32,
    pub char_height: u32,
}

impl Display {
    pub fn new(img: image::GrayImage, width: u32, height: u32) -> Display {
        Display {
            image: resize(&img, width*2, height*4, image::Lanczos3),
            char_width: width,
            char_height: height,
        }
    }

    pub fn render(&self) -> String {
        let mut target = String::with_capacity(
            // The char_height is added to account for newlines
            (self.char_height*self.char_width + self.char_height) as usize
        );
        for y in 0..self.char_height {
            for x in 0..self.char_width {
                target.push(self.braillify_block(x, y));
            }
            target.push('\n');
        }
        target
    }

    fn braillify_block(&self, x: u32, y: u32) -> char {
        let mut dot_map = 0b0000_0000;
        for i in 0..8 {
            let abs_x = (x*2) + (i % 2);
            let abs_y = (y*4) + (i / 2);

            dot_map |= if self.sample(abs_x, abs_y) {
                0b1000_0000 >> i
            } else {
                0
            };
        }
        make_braille(dot_map)
    }

    fn sample(&self, x: u32, y: u32) -> bool {
        self.image[(x, y)][0] < 128
    }
}

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

    #[test]
    fn test_overall_functionality() {
        let image = image::open("tests/rust-logo.png").unwrap().to_luma();
        let display = Display::new(image, 20, 10);

        let expected = "\
⠀⠀⠀⠀⠀⠀⣤⣰⣦⣴⣦⣴⣄⣤
⠀⠀⠀⣤⣼⣿⡿⠟⠛⢧⡼⠛⠻⢿⣿⣧⡤
⠀⠀⣶⣿⣿⣥⣤⣤⣤⣤⣤⣤⣄⣀⠉⢿⣷⡶
⠀⣻⡿⢿⡿⣿⣿⣿⡿⠿⠿⢿⣿⣿⡧⢠⠟⢿⣏
⢈⣿⣷⠚⠁⣿⣿⣿⣷⣶⣶⣾⣿⡿⠃⠈⠓⣿⣟⡁
⢈⣿⣿⠀⠀⣿⣿⣿⡏⠉⠙⢿⣿⣿⡆⠀⣶⣿⣯⡁
⠀⣽⣿⣿⣿⣿⣿⣿⣿⣿⠀⠸⣿⣿⣿⣿⣿⣿⣏
⠀⠀⠿⣿⣧⠴⣆⠀⠀⠀⠀⠀⠀⡴⢤⣾⡿⠷
⠀⠀⠀⠛⢻⣶⣿⣶⣤⣤⣤⣤⣶⣷⣾⡟⠓
⠀⠀⠀⠀⠀⠀⠛⠙⠟⠻⠟⠻⠋⠛
";

        assert!(display.sample(0, 0) == false);
        assert!(display.sample(4, 19) == true);

        assert!(display.braillify_block(5, 0) == '⠀');
        assert!(display.braillify_block(6, 0) == '⣤');
        assert!(display.braillify_block(7, 0) == '⣰');

        assert!(display.render() == expected);
    }
}
<commit_msg>Made a few needlessly-public struct members private<commit_after>extern crate image;

use self::image::imageops::resize;

use braille::make_braille;

pub struct Display {
    image: image::GrayImage,
    char_width: u32,
    char_height: u32,
}

impl Display {
    pub fn new(img: image::GrayImage, width: u32, height: u32) -> Display {
        Display {
            image: resize(&img, width*2, height*4, image::Lanczos3),
            char_width: width,
            char_height: height,
        }
    }

    pub fn render(&self) -> String {
        let mut target = String::with_capacity(
            // The char_height is added to account for newlines
            (self.char_height*self.char_width + self.char_height) as usize
        );
        for y in 0..self.char_height {
            for x in 0..self.char_width {
                target.push(self.braillify_block(x, y));
            }
            target.push('\n');
        }
        target
    }

    fn braillify_block(&self, x: u32, y: u32) -> char {
        let mut dot_map = 0b0000_0000;
        for i in 0..8 {
            let abs_x = (x*2) + (i % 2);
            let abs_y = (y*4) + (i / 2);

            dot_map |= if self.sample(abs_x, abs_y) {
                0b1000_0000 >> i
            } else {
                0
            };
        }
        make_braille(dot_map)
    }

    fn sample(&self, x: u32, y: u32) -> bool {
        self.image[(x, y)][0] < 128
    }
}

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

    #[test]
    fn test_overall_functionality() {
        let image = image::open("tests/rust-logo.png").unwrap().to_luma();
        let display = Display::new(image, 20, 10);

        let expected = "\
⠀⠀⠀⠀⠀⠀⣤⣰⣦⣴⣦⣴⣄⣤
⠀⠀⠀⣤⣼⣿⡿⠟⠛⢧⡼⠛⠻⢿⣿⣧⡤
⠀⠀⣶⣿⣿⣥⣤⣤⣤⣤⣤⣤⣄⣀⠉⢿⣷⡶
⠀⣻⡿⢿⡿⣿⣿⣿⡿⠿⠿⢿⣿⣿⡧⢠⠟⢿⣏
⢈⣿⣷⠚⠁⣿⣿⣿⣷⣶⣶⣾⣿⡿⠃⠈⠓⣿⣟⡁
⢈⣿⣿⠀⠀⣿⣿⣿⡏⠉⠙⢿⣿⣿⡆⠀⣶⣿⣯⡁
⠀⣽⣿⣿⣿⣿⣿⣿⣿⣿⠀⠸⣿⣿⣿⣿⣿⣿⣏
⠀⠀⠿⣿⣧⠴⣆⠀⠀⠀⠀⠀⠀⡴⢤⣾⡿⠷
⠀⠀⠀⠛⢻⣶⣿⣶⣤⣤⣤⣤⣶⣷⣾⡟⠓
⠀⠀⠀⠀⠀⠀⠛⠙⠟⠻⠟⠻⠋⠛
";

        assert!(display.sample(0, 0) == false);
        assert!(display.sample(4, 19) == true);

        assert!(display.braillify_block(5, 0) == '⠀');
        assert!(display.braillify_block(6, 0) == '⣤');
        assert!(display.braillify_block(7, 0) == '⣰');

        assert!(display.render() == expected);
    }
}
<|endoftext|>


<commit_before>use error::Error;
use num_traits::NumCast;
use serde::de::{self, Visitor};
use serde::{Serialize, Serializer, Deserialize, Deserializer};
use std::fmt::{self, Debug, Display};
use std::i64;

/// Represents a JSON number, whether integer or floating point.
#[derive(Clone, PartialEq)]
pub struct Number {
    n: N,
}

// "N" is a prefix of "NegInt"... this is a false positive.
// https://github.com/Manishearth/rust-clippy/issues/1241
#[cfg_attr(feature = "cargo-clippy", allow(enum_variant_names))]
#[derive(Copy, Clone, Debug, PartialEq)]
enum N {
    PosInt(u64),
    /// Always less than zero.
    NegInt(i64),
    /// Always finite.
    Float(f64),
}

impl Number {
    /// Returns true if the number can be represented by i64.
    #[inline]
    pub fn is_i64(&self) -> bool {
        match self.n {
            N::PosInt(v) => v <= i64::MAX as u64,
            N::NegInt(_) => true,
            N::Float(_) => false,
        }
    }

    /// Returns true if the number can be represented as u64.
    #[inline]
    pub fn is_u64(&self) -> bool {
        match self.n {
            N::PosInt(_) => true,
            N::NegInt(_) | N::Float(_) => false,
        }
    }

    /// Returns true if the number can be represented as f64.
    #[inline]
    pub fn is_f64(&self) -> bool {
        match self.n {
            N::Float(_) => true,
            N::PosInt(_) | N::NegInt(_) => false,
        }
    }

    /// Returns the number represented as i64 if possible, or else None.
    #[inline]
    pub fn as_i64(&self) -> Option<i64> {
        match self.n {
            N::PosInt(n) => NumCast::from(n),
            N::NegInt(n) => Some(n),
            N::Float(_) => None,
        }
    }

    /// Returns the number represented as u64 if possible, or else None.
    #[inline]
    pub fn as_u64(&self) -> Option<u64> {
        match self.n {
            N::PosInt(n) => Some(n),
            N::NegInt(n) => NumCast::from(n),
            N::Float(_) => None,
        }
    }

    /// Returns the number represented as f64 if possible, or else None.
    #[inline]
    pub fn as_f64(&self) -> Option<f64> {
        match self.n {
            N::PosInt(n) => NumCast::from(n),
            N::NegInt(n) => NumCast::from(n),
            N::Float(n) => Some(n),
        }
    }

    /// Converts a finite f64 to a Number. Infinite or NaN values are not JSON
    /// numbers.
    #[inline]
    pub fn from_f64(f: f64) -> Option<Number> {
        if f.is_finite() {
            Some(Number { n: N::Float(f) })
        } else {
            None
        }
    }
}

impl fmt::Display for Number {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        match self.n {
            N::PosInt(i) => Display::fmt(&i, formatter),
            N::NegInt(i) => Display::fmt(&i, formatter),
            N::Float(f) => Display::fmt(&f, formatter),
        }
    }
}

impl Debug for Number {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(&self.n, formatter)
    }
}

impl Serialize for Number {
    #[inline]
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        match self.n {
            N::PosInt(i) => serializer.serialize_u64(i),
            N::NegInt(i) => serializer.serialize_i64(i),
            N::Float(f) => serializer.serialize_f64(f),
        }
    }
}

impl Deserialize for Number {
    #[inline]
    fn deserialize<D>(deserializer: D) -> Result<Number, D::Error>
        where D: Deserializer
    {
        struct NumberVisitor;

        impl Visitor for NumberVisitor {
            type Value = Number;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a number")
            }

            #[inline]
            fn visit_i64<E>(self, value: i64) -> Result<Number, E> {
                Ok(value.into())
            }

            #[inline]
            fn visit_u64<E>(self, value: u64) -> Result<Number, E> {
                Ok(value.into())
            }

            #[inline]
            fn visit_f64<E>(self, value: f64) -> Result<Number, E>
                where E: de::Error
            {
                Number::from_f64(value).ok_or_else(|| de::Error::custom("not a JSON number"))
            }
        }

        deserializer.deserialize(NumberVisitor)
    }
}

impl Deserializer for Number {
    type Error = Error;

    #[inline]
    fn deserialize<V>(self, visitor: V) -> Result<V::Value, Error>
        where V: Visitor
    {
        match self.n {
            N::PosInt(i) => visitor.visit_u64(i),
            N::NegInt(i) => visitor.visit_i64(i),
            N::Float(f) => visitor.visit_f64(f),
        }
    }

    forward_to_deserialize! {
        bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit option
        seq seq_fixed_size bytes byte_buf map unit_struct newtype_struct
        tuple_struct struct struct_field tuple enum ignored_any
    }
}

macro_rules! from_signed {
    ($($signed_ty:ident)*) => {
        $(
            impl From<$signed_ty> for Number {
                #[inline]
                fn from(i: $signed_ty) -> Self {
                    if i < 0 {
                        Number { n: N::NegInt(i as i64) }
                    } else {
                        Number { n: N::PosInt(i as u64) }
                    }
                }
            }
        )*
    };
}

macro_rules! from_unsigned {
    ($($unsigned_ty:ident)*) => {
        $(
            impl From<$unsigned_ty> for Number {
                #[inline]
                fn from(u: $unsigned_ty) -> Self {
                    Number { n: N::PosInt(u as u64) }
                }
            }
        )*
    };
}

from_signed!(i8 i16 i32 i64 isize);
from_unsigned!(u8 u16 u32 u64 usize);
<commit_msg>Minor doc formatting improvements for `Number`.<commit_after>use error::Error;
use num_traits::NumCast;
use serde::de::{self, Visitor};
use serde::{Serialize, Serializer, Deserialize, Deserializer};
use std::fmt::{self, Debug, Display};
use std::i64;

/// Represents a JSON number, whether integer or floating point.
#[derive(Clone, PartialEq)]
pub struct Number {
    n: N,
}

// "N" is a prefix of "NegInt"... this is a false positive.
// https://github.com/Manishearth/rust-clippy/issues/1241
#[cfg_attr(feature = "cargo-clippy", allow(enum_variant_names))]
#[derive(Copy, Clone, Debug, PartialEq)]
enum N {
    PosInt(u64),
    /// Always less than zero.
    NegInt(i64),
    /// Always finite.
    Float(f64),
}

impl Number {
    /// Returns `true` if the number can be represented as `i64`.
    #[inline]
    pub fn is_i64(&self) -> bool {
        match self.n {
            N::PosInt(v) => v <= i64::MAX as u64,
            N::NegInt(_) => true,
            N::Float(_) => false,
        }
    }

    /// Returns `true` if the number can be represented as `u64`.
    #[inline]
    pub fn is_u64(&self) -> bool {
        match self.n {
            N::PosInt(_) => true,
            N::NegInt(_) | N::Float(_) => false,
        }
    }

    /// Returns `true` if the number can be represented as `f64`.
    #[inline]
    pub fn is_f64(&self) -> bool {
        match self.n {
            N::Float(_) => true,
            N::PosInt(_) | N::NegInt(_) => false,
        }
    }

    /// Returns the number represented as `i64` if possible, or else `None`.
    #[inline]
    pub fn as_i64(&self) -> Option<i64> {
        match self.n {
            N::PosInt(n) => NumCast::from(n),
            N::NegInt(n) => Some(n),
            N::Float(_) => None,
        }
    }

    /// Returns the number represented as `u64` if possible, or else `None`.
    #[inline]
    pub fn as_u64(&self) -> Option<u64> {
        match self.n {
            N::PosInt(n) => Some(n),
            N::NegInt(n) => NumCast::from(n),
            N::Float(_) => None,
        }
    }

    /// Returns the number represented as `f64` if possible, or else `None`.
    #[inline]
    pub fn as_f64(&self) -> Option<f64> {
        match self.n {
            N::PosInt(n) => NumCast::from(n),
            N::NegInt(n) => NumCast::from(n),
            N::Float(n) => Some(n),
        }
    }

    /// Converts a finite `f64` to a `Number`. Infinite or NaN values are not JSON
    /// numbers.
    #[inline]
    pub fn from_f64(f: f64) -> Option<Number> {
        if f.is_finite() {
            Some(Number { n: N::Float(f) })
        } else {
            None
        }
    }
}

impl fmt::Display for Number {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        match self.n {
            N::PosInt(i) => Display::fmt(&i, formatter),
            N::NegInt(i) => Display::fmt(&i, formatter),
            N::Float(f) => Display::fmt(&f, formatter),
        }
    }
}

impl Debug for Number {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(&self.n, formatter)
    }
}

impl Serialize for Number {
    #[inline]
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        match self.n {
            N::PosInt(i) => serializer.serialize_u64(i),
            N::NegInt(i) => serializer.serialize_i64(i),
            N::Float(f) => serializer.serialize_f64(f),
        }
    }
}

impl Deserialize for Number {
    #[inline]
    fn deserialize<D>(deserializer: D) -> Result<Number, D::Error>
        where D: Deserializer
    {
        struct NumberVisitor;

        impl Visitor for NumberVisitor {
            type Value = Number;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a number")
            }

            #[inline]
            fn visit_i64<E>(self, value: i64) -> Result<Number, E> {
                Ok(value.into())
            }

            #[inline]
            fn visit_u64<E>(self, value: u64) -> Result<Number, E> {
                Ok(value.into())
            }

            #[inline]
            fn visit_f64<E>(self, value: f64) -> Result<Number, E>
                where E: de::Error
            {
                Number::from_f64(value).ok_or_else(|| de::Error::custom("not a JSON number"))
            }
        }

        deserializer.deserialize(NumberVisitor)
    }
}

impl Deserializer for Number {
    type Error = Error;

    #[inline]
    fn deserialize<V>(self, visitor: V) -> Result<V::Value, Error>
        where V: Visitor
    {
        match self.n {
            N::PosInt(i) => visitor.visit_u64(i),
            N::NegInt(i) => visitor.visit_i64(i),
            N::Float(f) => visitor.visit_f64(f),
        }
    }

    forward_to_deserialize! {
        bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit option
        seq seq_fixed_size bytes byte_buf map unit_struct newtype_struct
        tuple_struct struct struct_field tuple enum ignored_any
    }
}

macro_rules! from_signed {
    ($($signed_ty:ident)*) => {
        $(
            impl From<$signed_ty> for Number {
                #[inline]
                fn from(i: $signed_ty) -> Self {
                    if i < 0 {
                        Number { n: N::NegInt(i as i64) }
                    } else {
                        Number { n: N::PosInt(i as u64) }
                    }
                }
            }
        )*
    };
}

macro_rules! from_unsigned {
    ($($unsigned_ty:ident)*) => {
        $(
            impl From<$unsigned_ty> for Number {
                #[inline]
                fn from(u: $unsigned_ty) -> Self {
                    Number { n: N::PosInt(u as u64) }
                }
            }
        )*
    };
}

from_signed!(i8 i16 i32 i64 isize);
from_unsigned!(u8 u16 u32 u64 usize);
<|endoftext|>


<commit_before>use super::dsp::Dsp;
use super::super::apu::Apu;
use super::envelope::Envelope;
use super::brr_block_decoder::BrrBlockDecoder;
use super::dsp_helpers;
use super::gaussian::{KERNEL_SIZE, KERNEL};

const RESAMPLE_BUFFER_LEN: usize = 4;

#[derive(Clone, Copy)]
pub enum ResamplingMode {
    Linear,
    Gaussian
}

#[derive(Clone, Copy)]
pub struct VoiceOutput {
    pub left_out: i32,
    pub right_out: i32,
    pub last_voice_out: i32
}

impl VoiceOutput {
    pub fn default() -> VoiceOutput {
        VoiceOutput {
            left_out: 0,
            right_out: 0,
            last_voice_out: 0
        }
    }
}

pub const VOICE_BUFFER_LEN: usize = 128;

// TODO: If Rust had facilities for specifying arrray sizes with generic parameters,
// this could be removed in favor of a more generalized RingBuffer.
pub struct VoiceBuffer {
    pub buffer: Box<[VoiceOutput; VOICE_BUFFER_LEN]>,
    pub pos: i32
}

impl VoiceBuffer {
    pub fn new() -> VoiceBuffer {
        VoiceBuffer {
            buffer: Box::new([VoiceOutput::default(); VOICE_BUFFER_LEN]),
            pos: 0
        }
    }

    pub fn reset(&mut self) {
        for i in 0..VOICE_BUFFER_LEN {
            self.buffer[i] = VoiceOutput::default();
        }
        self.pos = 0;
    }

    pub fn write(&mut self, value: VoiceOutput) {
        self.buffer[self.pos as usize] = value;
        self.pos = (self.pos + 1) % (VOICE_BUFFER_LEN as i32);
    }
}

pub struct Voice {
    dsp: *mut Dsp,
    emulator: *mut Apu,

    pub envelope: Box<Envelope>,

    pub vol_left: u8,
    pub vol_right: u8,
    pub pitch_low: u8,
    pitch_high: u8,
    pub source: u8,
    pub pitch_mod: bool,
    pub noise_on: bool,
    pub echo_on: bool,

    sample_start_address: u32,
    loop_start_address: u32,
    brr_block_decoder: Box<BrrBlockDecoder>,
    sample_address: u32,
    sample_pos: i32,

    pub resampling_mode: ResamplingMode,
    resample_buffer: [i32; RESAMPLE_BUFFER_LEN],
    resample_buffer_pos: usize,

    pub output_buffer: Box<VoiceBuffer>,
    pub is_muted: bool
}

impl Voice {
    pub fn new(dsp: *mut Dsp, emulator: *mut Apu, resampling_mode: ResamplingMode) -> Voice {
        let mut ret = Voice {
            dsp: dsp,
            emulator: emulator,

            envelope: Box::new(Envelope::new(dsp)),

            vol_left: 0,
            vol_right: 0,
            pitch_low: 0,
            pitch_high: 0,
            source: 0,
            pitch_mod: false,
            noise_on: false,
            echo_on: false,

            sample_start_address: 0,
            loop_start_address: 0,
            brr_block_decoder: Box::new(BrrBlockDecoder::new()),
            sample_address: 0,
            sample_pos: 0,

            resampling_mode: resampling_mode,
            resample_buffer: [0; RESAMPLE_BUFFER_LEN],
            resample_buffer_pos: 0,

            output_buffer: Box::new(VoiceBuffer::new()),
            is_muted: false,
        };
        ret.reset();
        ret
    }

    #[inline]
    fn dsp(&self) -> &mut Dsp {
        unsafe {
            &mut (*self.dsp)
        }
    }

    #[inline]
    fn emulator(&self) -> &mut Apu {
        unsafe {
            &mut (*self.emulator)
        }
    }

    pub fn reset(&mut self) {
        self.envelope.reset();

        self.vol_left = 0;
        self.vol_right = 0;
        self.pitch_low = 0;
        self.pitch_high = 0x10;
        self.source = 0;
        self.pitch_mod = false;
        self.noise_on = false;

        self.sample_start_address = 0;
        self.loop_start_address = 0;
        self.brr_block_decoder.reset(0, 0);
        self.sample_address = 0;
        self.sample_pos = 0;

        for i in 0..RESAMPLE_BUFFER_LEN {
            self.resample_buffer[i] = 0;
        }
        self.resample_buffer_pos = 0;

        self.output_buffer.reset();
        self.is_muted = false;
    }

    pub fn render_sample(&mut self, last_voice_out: i32, noise: i32) -> VoiceOutput {
        let mut pitch = ((self.pitch_high as i32) << 8) | (self.pitch_low as i32);
        if self.pitch_mod {
            pitch += ((last_voice_out >> 5) * pitch) >> 10;
        }
        if pitch < 0 {
            pitch = 0;
        }
        if pitch > 0x3fff {
            pitch = 0x3fff;
        }

        let mut sample = if !self.noise_on {
            let s1 = self.resample_buffer[self.resample_buffer_pos];
            let s2 = self.resample_buffer[(self.resample_buffer_pos + 1) % RESAMPLE_BUFFER_LEN];
            let resampled = match self.resampling_mode {
                ResamplingMode::Linear => {
                    let p1 = self.sample_pos;
                    let p2 = 0x1000 - p1;
                    (s1 * p1 + s2 * p2) >> 12
                },
                ResamplingMode::Gaussian => {
                    let s3 = self.resample_buffer[(self.resample_buffer_pos + 2) % RESAMPLE_BUFFER_LEN];
                    let s4 = self.resample_buffer[(self.resample_buffer_pos + 3) % RESAMPLE_BUFFER_LEN];
                    let kernel_index = (self.sample_pos >> 4) as usize;
                    let p1 = KERNEL[kernel_index];
                    let p2 = KERNEL[(kernel_index + KERNEL_SIZE / 4) % KERNEL_SIZE];
                    let p3 = KERNEL[(kernel_index + KERNEL_SIZE / 2) % KERNEL_SIZE];
                    let p4 = KERNEL[(kernel_index + KERNEL_SIZE * 3 / 4) % KERNEL_SIZE];
                    (s1 * p1 + s2 * p2 + s3 * p3 + s4 * p4) >> 11
                }
            };
            dsp_helpers::clamp(resampled) & !1
        } else {
            ((noise * 2) as i16) as i32
        };

        self.envelope.tick();
        let env_level = self.envelope.level;

        sample = ((sample * env_level) >> 11) & !1;

        if self.brr_block_decoder.is_end && !self.brr_block_decoder.is_looping {
            self.envelope.key_off();
            self.envelope.level = 0;
        }

        self.sample_pos += pitch;
        while self.sample_pos >= 0x1000 {
            self.sample_pos -= 0x1000;
            self.read_next_sample();

            if self.brr_block_decoder.is_finished() {
                if self.brr_block_decoder.is_end && self.brr_block_decoder.is_looping {
                    self.read_entry();
                    self.sample_address = self.loop_start_address;
                }
                self.read_next_block();
            }
        }

        let ret =
            if !self.is_muted {
                VoiceOutput {
                    left_out: dsp_helpers::multiply_volume(sample, self.vol_left),
                    right_out: dsp_helpers::multiply_volume(sample, self.vol_right),
                    last_voice_out: sample
                }
            } else {
                VoiceOutput {
                    left_out: 0,
                    right_out: 0,
                    last_voice_out: 0
                }
            };
        self.output_buffer.write(ret);
        ret
    }

    pub fn set_pitch_high(&mut self, value: u8) {
        self.pitch_high = value & 0x3f;
    }

    pub fn key_on(&mut self) {
        self.read_entry();
        self.sample_address = self.sample_start_address;
        self.brr_block_decoder.reset(0, 0);
        self.read_next_block();
        self.sample_pos = 0;
        self.resample_buffer[self.resample_buffer_pos] = 0;
        self.read_next_sample();
        self.envelope.key_on();
    }

    pub fn key_off(&mut self) {
        self.envelope.key_off();
    }

    fn read_entry(&mut self) {
        self.sample_start_address = self.dsp().read_source_dir_start_address(self.source as i32);
        self.loop_start_address = self.dsp().read_source_dir_loop_address(self.source as i32);
    }

    fn read_next_block(&mut self) {
        let mut buf = [0; 9];
        for i in 0..9 {
            buf[i] = self.emulator().read_u8(self.sample_address + (i as u32));
        }
        self.brr_block_decoder.read(&buf);
        self.sample_address += 9;
    }

    fn read_next_sample(&mut self) {
        self.resample_buffer_pos = match self.resample_buffer_pos {
            0 => RESAMPLE_BUFFER_LEN - 1,
            x => x - 1
        };
        self.resample_buffer[self.resample_buffer_pos] = self.brr_block_decoder.read_next_sample() as i32;
    }
}
<commit_msg>Fixed the clicks and pops<commit_after>use super::dsp::Dsp;
use super::super::apu::Apu;
use super::envelope::Envelope;
use super::brr_block_decoder::BrrBlockDecoder;
use super::dsp_helpers;
use super::gaussian::{KERNEL_SIZE, KERNEL};

const RESAMPLE_BUFFER_LEN: usize = 4;

#[derive(Clone, Copy)]
pub enum ResamplingMode {
    Linear,
    Gaussian
}

#[derive(Clone, Copy)]
pub struct VoiceOutput {
    pub left_out: i32,
    pub right_out: i32,
    pub last_voice_out: i32
}

impl VoiceOutput {
    pub fn default() -> VoiceOutput {
        VoiceOutput {
            left_out: 0,
            right_out: 0,
            last_voice_out: 0
        }
    }
}

pub const VOICE_BUFFER_LEN: usize = 128;

// TODO: If Rust had facilities for specifying arrray sizes with generic parameters,
// this could be removed in favor of a more generalized RingBuffer.
pub struct VoiceBuffer {
    pub buffer: Box<[VoiceOutput; VOICE_BUFFER_LEN]>,
    pub pos: i32
}

impl VoiceBuffer {
    pub fn new() -> VoiceBuffer {
        VoiceBuffer {
            buffer: Box::new([VoiceOutput::default(); VOICE_BUFFER_LEN]),
            pos: 0
        }
    }

    pub fn reset(&mut self) {
        for i in 0..VOICE_BUFFER_LEN {
            self.buffer[i] = VoiceOutput::default();
        }
        self.pos = 0;
    }

    pub fn write(&mut self, value: VoiceOutput) {
        self.buffer[self.pos as usize] = value;
        self.pos = (self.pos + 1) % (VOICE_BUFFER_LEN as i32);
    }
}

pub struct Voice {
    dsp: *mut Dsp,
    emulator: *mut Apu,

    pub envelope: Box<Envelope>,

    pub vol_left: u8,
    pub vol_right: u8,
    pub pitch_low: u8,
    pitch_high: u8,
    pub source: u8,
    pub pitch_mod: bool,
    pub noise_on: bool,
    pub echo_on: bool,

    sample_start_address: u32,
    loop_start_address: u32,
    brr_block_decoder: Box<BrrBlockDecoder>,
    sample_address: u32,
    sample_pos: i32,

    pub resampling_mode: ResamplingMode,
    resample_buffer: [i32; RESAMPLE_BUFFER_LEN],
    resample_buffer_pos: usize,

    pub output_buffer: Box<VoiceBuffer>,
    pub is_muted: bool
}

impl Voice {
    pub fn new(dsp: *mut Dsp, emulator: *mut Apu, resampling_mode: ResamplingMode) -> Voice {
        let mut ret = Voice {
            dsp: dsp,
            emulator: emulator,

            envelope: Box::new(Envelope::new(dsp)),

            vol_left: 0,
            vol_right: 0,
            pitch_low: 0,
            pitch_high: 0,
            source: 0,
            pitch_mod: false,
            noise_on: false,
            echo_on: false,

            sample_start_address: 0,
            loop_start_address: 0,
            brr_block_decoder: Box::new(BrrBlockDecoder::new()),
            sample_address: 0,
            sample_pos: 0,

            resampling_mode: resampling_mode,
            resample_buffer: [0; RESAMPLE_BUFFER_LEN],
            resample_buffer_pos: 0,

            output_buffer: Box::new(VoiceBuffer::new()),
            is_muted: false,
        };
        ret.reset();
        ret
    }

    #[inline]
    fn dsp(&self) -> &mut Dsp {
        unsafe {
            &mut (*self.dsp)
        }
    }

    #[inline]
    fn emulator(&self) -> &mut Apu {
        unsafe {
            &mut (*self.emulator)
        }
    }

    pub fn reset(&mut self) {
        self.envelope.reset();

        self.vol_left = 0;
        self.vol_right = 0;
        self.pitch_low = 0;
        self.pitch_high = 0x10;
        self.source = 0;
        self.pitch_mod = false;
        self.noise_on = false;

        self.sample_start_address = 0;
        self.loop_start_address = 0;
        self.brr_block_decoder.reset(0, 0);
        self.sample_address = 0;
        self.sample_pos = 0;

        for i in 0..RESAMPLE_BUFFER_LEN {
            self.resample_buffer[i] = 0;
        }
        self.resample_buffer_pos = 0;

        self.output_buffer.reset();
        self.is_muted = false;
    }

    pub fn render_sample(&mut self, last_voice_out: i32, noise: i32) -> VoiceOutput {
        let mut pitch = ((self.pitch_high as i32) << 8) | (self.pitch_low as i32);
        if self.pitch_mod {
            pitch += ((last_voice_out >> 5) * pitch) >> 10;
        }
        if pitch < 0 {
            pitch = 0;
        }
        if pitch > 0x3fff {
            pitch = 0x3fff;
        }

        let mut sample = if !self.noise_on {
            let s1 = self.resample_buffer[self.resample_buffer_pos];
            let s2 = self.resample_buffer[(self.resample_buffer_pos + 1) % RESAMPLE_BUFFER_LEN];
            let resampled = match self.resampling_mode {
                ResamplingMode::Linear => {
                    let p1 = self.sample_pos;
                    let p2 = 0x1000 - p1;
                    (s1 * p1 + s2 * p2) >> 12
                },
                ResamplingMode::Gaussian => {
                    let s3 = self.resample_buffer[(self.resample_buffer_pos + 2) % RESAMPLE_BUFFER_LEN];
                    let s4 = self.resample_buffer[(self.resample_buffer_pos + 3) % RESAMPLE_BUFFER_LEN];
                    let kernel_index = (self.sample_pos >> 4) as usize;
                    let p1 = KERNEL[kernel_index];
                    let p2 = KERNEL[(kernel_index + KERNEL_SIZE / 4) % KERNEL_SIZE];
                    let p3 = KERNEL[(kernel_index + KERNEL_SIZE / 2) % KERNEL_SIZE];
                    let p4 = KERNEL[(kernel_index + KERNEL_SIZE * 3 / 4) % KERNEL_SIZE];
                    (s1 * p1 + s2 * p2 + s3 * p3 + s4 * p4) >> 11
                }
            };
            dsp_helpers::clamp(resampled) & !1
        } else {
            ((noise * 2) as i16) as i32
        };

        self.envelope.tick();
        let env_level = self.envelope.level;

        sample = ((sample * env_level) >> 11) & !1;

        if self.brr_block_decoder.is_end && !self.brr_block_decoder.is_looping {
            self.envelope.key_off();
            self.envelope.level = 0;
        }

        self.sample_pos += pitch;
        while self.sample_pos >= 0x1000 {
            self.sample_pos -= 0x1000;
            self.read_next_sample();

            if self.brr_block_decoder.is_finished() {
                if self.brr_block_decoder.is_end && self.brr_block_decoder.is_looping {
                    self.read_entry();
                    self.sample_address = self.loop_start_address;
                }
                self.read_next_block();
            }
        }

        let ret =
            if !self.is_muted {
                VoiceOutput {
                    left_out: dsp_helpers::multiply_volume(sample, self.vol_left),
                    right_out: dsp_helpers::multiply_volume(sample, self.vol_right),
                    last_voice_out: sample
                }
            } else {
                VoiceOutput {
                    left_out: 0,
                    right_out: 0,
                    last_voice_out: 0
                }
            };
        self.output_buffer.write(ret);
        ret
    }

    pub fn set_pitch_high(&mut self, value: u8) {
        self.pitch_high = value & 0x3f;
    }

    pub fn key_on(&mut self) {
        self.read_entry();
        self.sample_address = self.sample_start_address;
        self.brr_block_decoder.reset(0, 0);
        self.read_next_block();
        self.sample_pos = 0;
        for i in 0..RESAMPLE_BUFFER_LEN {
            self.resample_buffer[i] = 0;
        }
        self.read_next_sample();
        self.envelope.key_on();
    }

    pub fn key_off(&mut self) {
        self.envelope.key_off();
    }

    fn read_entry(&mut self) {
        self.sample_start_address = self.dsp().read_source_dir_start_address(self.source as i32);
        self.loop_start_address = self.dsp().read_source_dir_loop_address(self.source as i32);
    }

    fn read_next_block(&mut self) {
        let mut buf = [0; 9];
        for i in 0..9 {
            buf[i] = self.emulator().read_u8(self.sample_address + (i as u32));
        }
        self.brr_block_decoder.read(&buf);
        self.sample_address += 9;
    }

    fn read_next_sample(&mut self) {
        self.resample_buffer_pos = match self.resample_buffer_pos {
            0 => RESAMPLE_BUFFER_LEN - 1,
            x => x - 1
        };
        self.resample_buffer[self.resample_buffer_pos] = self.brr_block_decoder.read_next_sample() as i32;
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Matthew Collins
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use types::bit::Set as BSet;
use std::collections::HashMap;
use std::any::{Any, TypeId};
use std::cell::RefCell;
use std::marker::PhantomData;
use std::mem;
use std::ptr;

/// Used to reference an entity.
#[derive(Clone, Copy)]
pub struct Entity {
    id: usize,
    generation: u32,
}

/// Stores and manages a collection of entities.
pub struct Manager {
    num_components: usize,
    entities: Vec<(Option<BSet>, u32)>,
    free_entities: Vec<usize>,
    components: Vec<Option<ComponentMem>>,

    component_ids: RefCell<HashMap<TypeId, usize>>,
}

/// Used to access compoents on an entity in an efficient
/// way.
#[derive(Clone, Copy)]
pub struct Key<T> {
    id: usize,
    _t: PhantomData<T>,
}

/// Used to search for entities with the requested components.
pub struct Filter {
    bits: BSet,
}

impl Filter {
    /// Creates an empty filter which matches everything
    pub fn new() -> Filter {
        Filter {
            bits: BSet::new(0),
        }
    }

    /// Adds the component to the filter.
    pub fn with<T>(mut self, key: Key<T>) -> Self {
        if self.bits.capacity() <= key.id {
            self.bits.resize(key.id + 1);
        }
        self.bits.set(key.id, true);
        self
    }
}

impl Manager {
    /// Creates a new manager.
    pub fn new() -> Manager {
        Manager {
            num_components: 0,
            entities: vec![(Some(BSet::new(0)), 0)], // Has the world entity pre-defined
            free_entities: vec![],
            components: vec![],

            component_ids: RefCell::new(HashMap::new()),
        }
    }

    /// Returns the world entity. This should never be removed.
    pub fn get_world(&self) -> Entity {
        Entity {
            id: 0,
            generation: 0,
        }
    }

    /// Returns all entities matching the filter
    pub fn find(&self, filter: &Filter) -> Vec<Entity> {
        let mut ret = vec![];
        // Skip the world entity.
        for (i, &(ref set, gen)) in self.entities[1..].iter().enumerate() {
            if let Some(set) = set.as_ref() {
                if set.includes_set(&filter.bits) {
                    ret.push(Entity {
                        id: i + 1,
                        generation: gen,
                    });
                }
            }
        }
        ret
    }

    /// Allocates a new entity without any components.
    pub fn create_entity(&mut self) -> Entity {
        if let Some(id) = self.free_entities.pop() {
            let entity = &mut self.entities[id];
            entity.0 = Some(BSet::new(self.num_components));
            entity.1 += 1;
            return Entity {
                id: id,
                generation: entity.1,
            }
        }
        let id = self.entities.len();
        self.entities.push((
            Some(BSet::new(self.num_components)),
            0
        ));
        Entity {
            id: id,
            generation: 0,
        }
    }

    /// Deallocates an entity and frees its components
    pub fn remove_entity(&mut self, e: Entity) {
        if let Some(set) = self.entities[e.id].0.as_ref() {
            for i in 0 .. COMPONENTS_PER_BLOCK {
                if set.get(i) {
                    self.components[i].as_mut().unwrap().remove(e.id);
                }
            }
            self.free_entities.push(e.id);
        }
        self.entities[e.id].0 = None;
    }

    /// Returns whether an entity reference is valid.
    pub fn is_entity_valid(&self, e: Entity) -> bool {
        match self.entities.get(e.id) {
            Some(val) => val.1 == e.generation && val.0.is_some(),
            None => false,
        }
    }

    /// Gets a key for the component type. Creates one
    /// if the component has never been referenced before.
    pub fn get_key<T: Any>(&self) -> Key<T> {
        let mut ids = self.component_ids.borrow_mut();
        let next_id = ids.len();
        let id = ids.entry(TypeId::of::<T>()).or_insert(next_id);
        Key {
            id: *id,
            _t: PhantomData,
        }
    }

    /// Adds the component to the target entity
    /// # Panics
    /// Panics when the target entity doesn't exist
    pub fn add_component<T>(&mut self, entity: Entity, key: Key<T>, val: T) {
        if self.components.len() <= key.id {
            while self.components.len() <= key.id {
                self.components.push(None);
            }
        }
        if self.components[key.id].is_none() {
            self.components[key.id] = Some(ComponentMem::new::<T>());
            self.num_components += 1;
            for &mut (ref mut set, _) in &mut self.entities {
                if let Some(set) = set.as_mut() {
                    set.resize(self.num_components);
                }
            }
        }
        let components = self.components.get_mut(key.id).and_then(|v| v.as_mut()).unwrap();
        let mut e = self.entities.get_mut(entity.id);
        let set = match e {
            Some(ref mut val) => if val.1 == entity.generation { &mut val.0 } else { panic!("Missing entity") },
            None => panic!("Missing entity"),
        };
        let set = match set.as_mut() {
            Some(val) => val,
            None => panic!("Missing entity"),
        };
        if set.get(key.id) {
            panic!("Duplicate add");
        }
        set.set(key.id, true);
        components.add(entity.id, val);
    }

    /// Same as `add_component` but doesn't require a key. Using a key
    /// is better for frequent lookups.
    pub fn add_component_direct<T: Any>(&mut self, entity: Entity, val: T) {
        let key = self.get_key();
        self.add_component(entity, key, val);
    }

    /// Returns the given component that the key points to if it exists.
    pub fn get_component<T>(&self, entity: Entity, key: Key<T>) -> Option<&T> {
        let components = match self.components.get(key.id).and_then(|v| v.as_ref()) {
            Some(val) => val,
            None => return None,
        };
        let set = match self.entities.get(entity.id).as_ref() {
            Some(ref val) => if val.1 == entity.generation { &val.0 } else { return None },
            None => return None,
        };
        if !set.as_ref().map(|v| v.get(key.id)).unwrap_or(false) {
            return None;
        }

        Some(components.get(entity.id))
    }

    /// Same as `get_component` but doesn't require a key. Using a key
    /// is better for frequent lookups.
    pub fn get_component_direct<T: Any>(&self, entity: Entity) -> Option<&T> {
        let key = self.get_key();
        self.get_component(entity, key)
    }

    /// Returns the given component that the key points to if it exists.
    pub fn get_component_mut<T>(&mut self, entity: Entity, key: Key<T>) -> Option<&mut T> {
        let components = match self.components.get_mut(key.id).and_then(|v| v.as_mut()) {
            Some(val) => val,
            None => return None,
        };
        let set = match self.entities.get(entity.id).as_ref() {
            Some(ref val) => if val.1 == entity.generation { &val.0 } else { return None },
            None => return None,
        };
        if !set.as_ref().map(|v| v.get(key.id)).unwrap_or(false) {
            return None;
        }

        Some(components.get_mut(entity.id))
    }

    /// Same as `get_component_mut` but doesn't require a key. Using a key
    /// is better for frequent lookups.
    pub fn get_component_mut_direct<T: Any>(&mut self, entity: Entity) -> Option<&mut T> {
        let key = self.get_key();
        self.get_component_mut(entity, key)
    }
}

const COMPONENTS_PER_BLOCK: usize = 64;

struct ComponentMem {
    data: Vec<Option<(Vec<u8>, BSet, usize)>>,
    component_size: usize,
    drop_func: Box<Fn(*mut u8)>,
}

impl ComponentMem {
    fn new<T>() -> ComponentMem {
        ComponentMem {
            data: vec![],
            component_size: mem::size_of::<T>(),
            drop_func: Box::new(|data| {
                unsafe {
                    let mut val: T = mem::uninitialized();
                    ptr::copy(data as *mut T, &mut val, 1);
                    mem::drop(val);
                }
            }),
        }
    }

    fn add<T>(&mut self, index: usize, val: T) {
        while self.data.len() < (index / COMPONENTS_PER_BLOCK) + 1 {
            self.data.push(None);
        }
        let idx = index / COMPONENTS_PER_BLOCK;
        let rem = index % COMPONENTS_PER_BLOCK;
        if self.data[idx].is_none() {
            self.data[idx] = Some((vec![0; self.component_size * COMPONENTS_PER_BLOCK], BSet::new(COMPONENTS_PER_BLOCK), 0));
        }
        let data = self.data[idx].as_mut().unwrap();
        let start = rem * self.component_size;
        data.2 += 1;
        data.1.set(rem, true);
        unsafe {
            ptr::write(data.0.as_mut_ptr().offset(start as isize) as *mut T, val);
        }
    }

    fn remove(&mut self, index: usize) {
        let idx = index / COMPONENTS_PER_BLOCK;
        let rem = index % COMPONENTS_PER_BLOCK;

        let count = {
            let data = self.data[idx].as_mut().unwrap();
            let start = rem * self.component_size;
            data.1.set(rem, false);
            // We don't have access to the actual type in this method so
            // we use the drop_func which stores the type in its closure
            // to handle the dropping for us.
            unsafe { (self.drop_func)(data.0.as_mut_ptr().offset(start as isize)); }
            data.2 -= 1;
            data.2
        };
        if count == 0 {
            self.data[idx] = None;
        }
    }

    fn get<T>(&self, index: usize) -> &T {
        let idx = index / COMPONENTS_PER_BLOCK;
        let rem = index % COMPONENTS_PER_BLOCK;
        let data = self.data[idx].as_ref().unwrap();
        let start = rem * self.component_size;
        unsafe {
            mem::transmute(data.0.as_ptr().offset(start as isize))
        }
    }

    fn get_mut<T>(&mut self, index: usize) -> &mut T {
        let idx = index / COMPONENTS_PER_BLOCK;
        let rem = index % COMPONENTS_PER_BLOCK;
        let data = self.data[idx].as_mut().unwrap();
        let start = rem * self.component_size;
        unsafe {
            mem::transmute(data.0.as_mut_ptr().offset(start as isize))
        }
    }
}

impl Drop for ComponentMem {
    fn drop(&mut self) {
        for data in &mut self.data {
            if let Some(data) = data.as_mut() {
                for i in 0 .. COMPONENTS_PER_BLOCK {
                    if data.1.get(i) {
                        let start = i * self.component_size;
                        unsafe { (self.drop_func)(data.0.as_mut_ptr().offset(start as isize)); }
                    }
                }
            }
        }
    }
}
<commit_msg>Initial implementation for systems<commit_after>// Copyright 2016 Matthew Collins
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use types::bit::Set as BSet;
use std::collections::HashMap;
use std::any::{Any, TypeId};
use std::cell::RefCell;
use std::marker::PhantomData;
use std::mem;
use std::ptr;

/// Used to reference an entity.
#[derive(Clone, Copy)]
pub struct Entity {
    id: usize,
    generation: u32,
}

/// Used to access compoents on an entity in an efficient
/// way.
#[derive(Clone, Copy)]
pub struct Key<T> {
    id: usize,
    _t: PhantomData<T>,
}

/// Used to search for entities with the requested components.
pub struct Filter {
    bits: BSet,
}

impl Filter {
    /// Creates an empty filter which matches everything
    pub fn new() -> Filter {
        Filter {
            bits: BSet::new(0),
        }
    }

    /// Adds the component to the filter.
    pub fn with<T>(mut self, key: Key<T>) -> Self {
        if self.bits.capacity() <= key.id {
            self.bits.resize(key.id + 1);
        }
        self.bits.set(key.id, true);
        self
    }
}

/// A system processes entities
pub trait System {
    fn update(&mut self, m: &mut Manager);
}

/// Stores and manages a collection of entities.
pub struct Manager {
    num_components: usize,
    entities: Vec<(Option<BSet>, u32)>,
    free_entities: Vec<usize>,
    components: Vec<Option<ComponentMem>>,

    component_ids: RefCell<HashMap<TypeId, usize>>,

    systems: Vec<Box<System>>,
    render_systems: Vec<Box<System>>,
}

impl Manager {
    /// Creates a new manager.
    pub fn new() -> Manager {
        Manager {
            num_components: 0,
            entities: vec![(Some(BSet::new(0)), 0)], // Has the world entity pre-defined
            free_entities: vec![],
            components: vec![],

            component_ids: RefCell::new(HashMap::new()),
            systems: vec![],
            render_systems: vec![],
        }
    }

    /// Returns the world entity. This should never be removed.
    pub fn get_world(&self) -> Entity {
        Entity {
            id: 0,
            generation: 0,
        }
    }

    /// Adds a system which will be called every tick
    pub fn add_system<S: System + 'static>(&mut self, s: S) {
        self.systems.push(Box::new(s));
    }

    /// Adds a system which will be called every frame
    pub fn add_render_system<S: System + 'static>(&mut self, s: S) {
        self.render_systems.push(Box::new(s));
    }

    /// Ticks all tick systems
    pub fn tick(&mut self) {
        let mut systems = mem::replace(&mut self.systems, vec![]);
        for sys in &mut systems {
            sys.update(self);
        }
        mem::replace(&mut self.systems, systems);
    }

    /// Ticks all render systems
    pub fn render_tick(&mut self) {
        let mut systems = mem::replace(&mut self.render_systems, vec![]);
        for sys in &mut systems {
            sys.update(self);
        }
        mem::replace(&mut self.render_systems, systems);
    }

    /// Returns all entities matching the filter
    pub fn find(&self, filter: &Filter) -> Vec<Entity> {
        let mut ret = vec![];
        // Skip the world entity.
        for (i, &(ref set, gen)) in self.entities[1..].iter().enumerate() {
            if let Some(set) = set.as_ref() {
                if set.includes_set(&filter.bits) {
                    ret.push(Entity {
                        id: i + 1,
                        generation: gen,
                    });
                }
            }
        }
        ret
    }

    /// Allocates a new entity without any components.
    pub fn create_entity(&mut self) -> Entity {
        if let Some(id) = self.free_entities.pop() {
            let entity = &mut self.entities[id];
            entity.0 = Some(BSet::new(self.num_components));
            entity.1 += 1;
            return Entity {
                id: id,
                generation: entity.1,
            }
        }
        let id = self.entities.len();
        self.entities.push((
            Some(BSet::new(self.num_components)),
            0
        ));
        Entity {
            id: id,
            generation: 0,
        }
    }

    /// Deallocates an entity and frees its components
    pub fn remove_entity(&mut self, e: Entity) {
        if let Some(set) = self.entities[e.id].0.as_ref() {
            for i in 0 .. COMPONENTS_PER_BLOCK {
                if set.get(i) {
                    self.components[i].as_mut().unwrap().remove(e.id);
                }
            }
            self.free_entities.push(e.id);
        }
        self.entities[e.id].0 = None;
    }

    /// Returns whether an entity reference is valid.
    pub fn is_entity_valid(&self, e: Entity) -> bool {
        match self.entities.get(e.id) {
            Some(val) => val.1 == e.generation && val.0.is_some(),
            None => false,
        }
    }

    /// Gets a key for the component type. Creates one
    /// if the component has never been referenced before.
    pub fn get_key<T: Any>(&self) -> Key<T> {
        let mut ids = self.component_ids.borrow_mut();
        let next_id = ids.len();
        let id = ids.entry(TypeId::of::<T>()).or_insert(next_id);
        Key {
            id: *id,
            _t: PhantomData,
        }
    }

    /// Adds the component to the target entity
    /// # Panics
    /// Panics when the target entity doesn't exist
    pub fn add_component<T>(&mut self, entity: Entity, key: Key<T>, val: T) {
        if self.components.len() <= key.id {
            while self.components.len() <= key.id {
                self.components.push(None);
            }
        }
        if self.components[key.id].is_none() {
            self.components[key.id] = Some(ComponentMem::new::<T>());
            self.num_components += 1;
            for &mut (ref mut set, _) in &mut self.entities {
                if let Some(set) = set.as_mut() {
                    set.resize(self.num_components);
                }
            }
        }
        let components = self.components.get_mut(key.id).and_then(|v| v.as_mut()).unwrap();
        let mut e = self.entities.get_mut(entity.id);
        let set = match e {
            Some(ref mut val) => if val.1 == entity.generation { &mut val.0 } else { panic!("Missing entity") },
            None => panic!("Missing entity"),
        };
        let set = match set.as_mut() {
            Some(val) => val,
            None => panic!("Missing entity"),
        };
        if set.get(key.id) {
            panic!("Duplicate add");
        }
        set.set(key.id, true);
        components.add(entity.id, val);
    }

    /// Same as `add_component` but doesn't require a key. Using a key
    /// is better for frequent lookups.
    pub fn add_component_direct<T: Any>(&mut self, entity: Entity, val: T) {
        let key = self.get_key();
        self.add_component(entity, key, val);
    }

    /// Returns the given component that the key points to if it exists.
    pub fn get_component<T>(&self, entity: Entity, key: Key<T>) -> Option<&T> {
        let components = match self.components.get(key.id).and_then(|v| v.as_ref()) {
            Some(val) => val,
            None => return None,
        };
        let set = match self.entities.get(entity.id).as_ref() {
            Some(ref val) => if val.1 == entity.generation { &val.0 } else { return None },
            None => return None,
        };
        if !set.as_ref().map(|v| v.get(key.id)).unwrap_or(false) {
            return None;
        }

        Some(components.get(entity.id))
    }

    /// Same as `get_component` but doesn't require a key. Using a key
    /// is better for frequent lookups.
    pub fn get_component_direct<T: Any>(&self, entity: Entity) -> Option<&T> {
        let key = self.get_key();
        self.get_component(entity, key)
    }

    /// Returns the given component that the key points to if it exists.
    pub fn get_component_mut<T>(&mut self, entity: Entity, key: Key<T>) -> Option<&mut T> {
        let components = match self.components.get_mut(key.id).and_then(|v| v.as_mut()) {
            Some(val) => val,
            None => return None,
        };
        let set = match self.entities.get(entity.id).as_ref() {
            Some(ref val) => if val.1 == entity.generation { &val.0 } else { return None },
            None => return None,
        };
        if !set.as_ref().map(|v| v.get(key.id)).unwrap_or(false) {
            return None;
        }

        Some(components.get_mut(entity.id))
    }

    /// Same as `get_component_mut` but doesn't require a key. Using a key
    /// is better for frequent lookups.
    pub fn get_component_mut_direct<T: Any>(&mut self, entity: Entity) -> Option<&mut T> {
        let key = self.get_key();
        self.get_component_mut(entity, key)
    }
}

const COMPONENTS_PER_BLOCK: usize = 64;

struct ComponentMem {
    data: Vec<Option<(Vec<u8>, BSet, usize)>>,
    component_size: usize,
    drop_func: Box<Fn(*mut u8)>,
}

impl ComponentMem {
    fn new<T>() -> ComponentMem {
        ComponentMem {
            data: vec![],
            component_size: mem::size_of::<T>(),
            drop_func: Box::new(|data| {
                unsafe {
                    let mut val: T = mem::uninitialized();
                    ptr::copy(data as *mut T, &mut val, 1);
                    mem::drop(val);
                }
            }),
        }
    }

    fn add<T>(&mut self, index: usize, val: T) {
        while self.data.len() < (index / COMPONENTS_PER_BLOCK) + 1 {
            self.data.push(None);
        }
        let idx = index / COMPONENTS_PER_BLOCK;
        let rem = index % COMPONENTS_PER_BLOCK;
        if self.data[idx].is_none() {
            self.data[idx] = Some((vec![0; self.component_size * COMPONENTS_PER_BLOCK], BSet::new(COMPONENTS_PER_BLOCK), 0));
        }
        let data = self.data[idx].as_mut().unwrap();
        let start = rem * self.component_size;
        data.2 += 1;
        data.1.set(rem, true);
        unsafe {
            ptr::write(data.0.as_mut_ptr().offset(start as isize) as *mut T, val);
        }
    }

    fn remove(&mut self, index: usize) {
        let idx = index / COMPONENTS_PER_BLOCK;
        let rem = index % COMPONENTS_PER_BLOCK;

        let count = {
            let data = self.data[idx].as_mut().unwrap();
            let start = rem * self.component_size;
            data.1.set(rem, false);
            // We don't have access to the actual type in this method so
            // we use the drop_func which stores the type in its closure
            // to handle the dropping for us.
            unsafe { (self.drop_func)(data.0.as_mut_ptr().offset(start as isize)); }
            data.2 -= 1;
            data.2
        };
        if count == 0 {
            self.data[idx] = None;
        }
    }

    fn get<T>(&self, index: usize) -> &T {
        let idx = index / COMPONENTS_PER_BLOCK;
        let rem = index % COMPONENTS_PER_BLOCK;
        let data = self.data[idx].as_ref().unwrap();
        let start = rem * self.component_size;
        unsafe {
            mem::transmute(data.0.as_ptr().offset(start as isize))
        }
    }

    fn get_mut<T>(&mut self, index: usize) -> &mut T {
        let idx = index / COMPONENTS_PER_BLOCK;
        let rem = index % COMPONENTS_PER_BLOCK;
        let data = self.data[idx].as_mut().unwrap();
        let start = rem * self.component_size;
        unsafe {
            mem::transmute(data.0.as_mut_ptr().offset(start as isize))
        }
    }
}

impl Drop for ComponentMem {
    fn drop(&mut self) {
        for data in &mut self.data {
            if let Some(data) = data.as_mut() {
                for i in 0 .. COMPONENTS_PER_BLOCK {
                    if data.1.get(i) {
                        let start = i * self.component_size;
                        unsafe { (self.drop_func)(data.0.as_mut_ptr().offset(start as isize)); }
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::collections::VecDeque;

fn factors_len(n: u32) -> usize {
    let mut n = n;
    let mut i = 2;
    let mut factors = HashSet::<u32>::new();
    while i <= n {
        if n % i == 0 {
            n /= i;
            factors.insert(i);
        } else {
            i += 1;
        }
    }
    factors.len()
}

pub fn main() {
    let mut buf = VecDeque::new();
    buf.push_back((1, factors_len(1)));
    buf.push_back((2, factors_len(2)));
    buf.push_back((3, factors_len(3)));
    buf.push_back((4, factors_len(4)));
    let mut i = 5;
    loop {
        buf.pop_front();
        buf.push_back((i, factors_len(i)));
        i += 1;
        if buf.iter().all(|&(_, len)| len == 4) {
            println!("{}", buf[0].0);
            break;
        }
    }
}
<commit_msg>add alternative (slower) one-liner to problem 47<commit_after>use std::collections::HashSet;
use std::collections::VecDeque;

fn factors_len(n: u32) -> usize {
    let mut n = n;
    let mut i = 2;
    let mut factors = HashSet::<u32>::new();
    while i <= n {
        if n % i == 0 {
            n /= i;
            factors.insert(i);
        } else {
            i += 1;
        }
    }
    factors.len()
}

pub fn main() {
    let mut buf = VecDeque::new();
    buf.push_back((1, factors_len(1)));
    buf.push_back((2, factors_len(2)));
    buf.push_back((3, factors_len(3)));
    buf.push_back((4, factors_len(4)));
    let mut i = 5;
    loop {
        buf.pop_front();
        buf.push_back((i, factors_len(i)));
        i += 1;
        if buf.iter().all(|&(_, len)| len == 4) {
            println!("{}", buf[0].0);
            break;
        }
    }

    // Alternative solution
    // let numbers = (1..200_000).collect::<Vec<_>>();
    // println!("{:?}", numbers.windows(4).find(|&l| l.iter().all(|&n| factors_len(n) == 4)));
}
<|endoftext|>