<commit_before>extern crate puzrs;
extern crate rand;
extern crate getopts;

use getopts::Options;
use getopts::Matches;
use std::env;

use puzrs::*;
use std::io;
use std::time::Instant;
use rand::Rng;

use std::thread;
use std::sync::Mutex;
use std::io::Write;

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

#[derive(Clone, Copy, Debug)]
struct GeneratorOption {
    height: i32,
    width: i32,
    jobs: i32,
    no_adjacent_clues: bool,
    symmetry_clue: bool,
    minimum_path_length: i32,
    empty_width: i32,
    max_clue: Option<i32>,
    corner: Option<(i32, i32)>,
}

fn run_generator(opts: GeneratorOption) {
    let height = opts.height;
    let width = opts.width;
    let mut ths = vec![];
    let gen_probs = std::sync::Arc::new(Mutex::new(0i64));

    for _ in 0..opts.jobs {
        let gen_probs = gen_probs.clone();
        let opts = opts;

        ths.push(thread::spawn(move || {
            let start = Instant::now();

            let mut generator = numberlink::PlacementGenerator::new(height, width);

            let mut rng = rand::thread_rng();
            loop {
                let mut end = Grid::new(height, width, numberlink::Endpoint::Any);

                let trans = move |x: i32, y: i32, d: i32| {
                    let mut x = x;
                    let mut y = y;
                    if d == 1 || d == 3 {
                        x = width - 1 - x;
                    }
                    if d == 2 || d == 3 {
                        y = height - 1 - y;
                    }
                    (Y(y), X(x))
                };
                let fr = opts.empty_width;
                for y in 0..height {
                    for x in 0..width {
                        if y < fr || y >= height - fr || x < fr || x >= width - fr {
                            end[(Y(y), X(x))] = numberlink::Endpoint::Prohibited;
                        }
                    }
                }
                if let Some((lo, hi)) = opts.corner {
                    if opts.symmetry_clue {
                        for d in 0..2 {
                            let i = rng.gen_range(lo, hi + 1);
                            let (d0, d1) = if d == 0 { (0, 3) } else { (1, 2) };

                            end[trans(i, i, d0)] = numberlink::Endpoint::Forced;
                            end[trans(i, i + 1, d0)] = numberlink::Endpoint::Prohibited;
                            end[trans(i + 1, i, d0)] = numberlink::Endpoint::Prohibited;
                            for j in 0..i {
                                end[trans(j, j, d0)] = numberlink::Endpoint::Prohibited;
                            }
                            end[trans(i, i, d1)] = numberlink::Endpoint::Forced;
                            end[trans(i, i + 1, d1)] = numberlink::Endpoint::Prohibited;
                            end[trans(i + 1, i, d1)] = numberlink::Endpoint::Prohibited;
                            for j in 0..i {
                                end[trans(j, j, d1)] = numberlink::Endpoint::Prohibited;
                            }
                        }
                    } else {
                        for d in 0..4 {
                            let i = rng.gen_range(lo, hi + 1);
                            end[trans(i, i, d)] = numberlink::Endpoint::Forced;
                            end[trans(i, i + 1, d)] = numberlink::Endpoint::Prohibited;
                            end[trans(i + 1, i, d)] = numberlink::Endpoint::Prohibited;
                            for j in 0..i {
                                end[trans(j, j, d)] = numberlink::Endpoint::Prohibited;
                            }
                        }
                    }
                }
                let opt = numberlink::GeneratorOption {
                    chain_threshold: opts.minimum_path_length,
                    endpoint_constraint: Some(&end),
                    forbid_adjacent_clue: opts.no_adjacent_clues,
                    symmetry_clue: opts.symmetry_clue,
                    clue_limit: opts.max_clue,
                };

                let placement = generator.generate(&opt, &mut rng);
                if let Some(placement) = placement {
                    // pretest
                    if !numberlink::uniqueness_pretest(&placement) { continue; }

                    let problem = numberlink::extract_problem(&placement, &mut rng);
                    let ans = numberlink::solve2(&problem, Some(2), false, true);

                    if ans.len() == 1 && !ans.found_not_fully_filled {
                        let stdin = io::stdout();
                        let handle = &mut stdin.lock();

                        let end = start.elapsed();
                        let cost_time = (end.as_secs() as f64 + end.subsec_nanos() as f64 / 1e9f64) / 60f64;
                        let mut cnt = gen_probs.lock().unwrap();
                        *cnt += 1;
                        eprintln!("{} problem(s) in {:.3}[min] ({:.3} [prob/min])", *cnt, cost_time, (*cnt) as f64 / cost_time);

                        writeln!(handle, "{} {}", height, width).unwrap();
                        for y in 0..height {
                            for x in 0..width {
                                let numberlink::Clue(c) = problem[(Y(y), X(x))];
                                if c >= 1 {
                                    write!(handle, "{}{}", c, if x == width - 1 { '\n' } else { ' ' }).unwrap();
                                } else {
                                    write!(handle, ".{}", if x == width - 1 { '\n' } else { ' ' }).unwrap();
                                }
                            }
                        }
                        writeln!(handle).unwrap();
                    }
                }
            }
        }));
    }
    for th in ths {
        th.join().unwrap();
    }
}

fn parse_options(matches: Matches) -> Result<GeneratorOption, &'static str> {
    let height = try!(
        matches.opt_str("h")
            .ok_or("'height' must be specified")
            .and_then(|arg| arg.parse::<i32>().map_err(|_| "Could not parse value for 'height'"))
            .and_then(|arg| if arg > 0 { Ok(arg) } else { Err("'height' must be a positive integer") }));
    let width = try!(
        matches.opt_str("w")
            .ok_or("'width' must be specified")
            .and_then(|arg| arg.parse::<i32>().map_err(|_| "Could not parse value for 'width'"))
            .and_then(|arg| if arg > 0 { Ok(arg) } else { Err("'width' must be a positive integer") }));
    let jobs = try!(
        matches.opt_str("j").map(|s|
            s.parse::<i32>()
                .map_err(|_| "Could not parse value for 'jobs'")
                .and_then(|arg| if arg > 0 { Ok(arg) } else { Err("'jobs' must be a positive integer") })
        ).unwrap_or(Ok(1)));
    let no_adjacent_clues = matches.opt_present("no-adjacent-clues");
    let symmetry_clue = matches.opt_present("symmetry");
    let minimum_path_length = try!(
        matches.opt_str("minimum-path-length").map(|s|
            s.parse::<i32>()
                .map_err(|_| "Could not parse value for 'minimum-path-length'")
                .and_then(|arg| if arg > 0 { Ok(arg) } else { Err("'minimum-path-length' must be a positive integer") })
        ).unwrap_or(Ok(1)));
    let empty_width = try!(
        matches.opt_str("empty-width").map(|s|
            s.parse::<i32>()
                .map_err(|_| "Could not parse value for 'empty-width'")
                .and_then(|arg| if arg > 0 { Ok(arg) } else { Err("'empty-width' must be a positive integer") })
        ).unwrap_or(Ok(1)));
    let max_clue = try!(
        matches.opt_str("max-clue").map(|s|
            s.parse::<i32>()
                .map_err(|_| "Could not parse value for 'max-clue'")
                .and_then(|arg| if arg > 0 { Ok(Some(arg)) } else { Err("'max-clue' must be a positive integer") })
        ).unwrap_or(Ok(None)));
    let corner = match matches.opt_str("corner") {
        Some(s) => {
            let split = s.split(",").collect::<Vec<&str>>();
            if split.len() != 2 {
                return Err("Could not parse value for 'corner'");
            }
            let lo = try!(split[0].parse::<i32>().map_err(|_| "Could not parse value for 'corner'"));
            let hi = try!(split[1].parse::<i32>().map_err(|_| "Could not parse value for 'corner'"));
            if !(1 <= lo && lo <= hi) {
                return Err("'corner' must be a valid range on positive integers");
            }
            Some((lo, hi))
        },
        None => None,
    };
    Ok(GeneratorOption {
        height,
        width,
        jobs,
        no_adjacent_clues,
        symmetry_clue,
        minimum_path_length,
        empty_width,
        max_clue,
        corner
    })
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut options = Options::new();
    options.optflag("", "help", "Show this help menu");
    options.optopt("h", "height", "Height of desired problems", "10");
    options.optopt("w", "width", "Width of desired problems", "10");
    options.optopt("j", "jobs", "Number of workers (threads)", "2");
    options.optflag("a", "no-adjacent-clues", "Disallow adjacent clues");
    options.optflag("s", "symmetry", "Force symmetry");
    options.optopt("m", "minimum-path-length", "Minimum length of paths in the answer", "12");
    options.optopt("e", "empty-width", "Disallow clues on n cell(s) from the outer border", "1");
    options.optopt("c", "corner", "Put one clue within specified range from each corner", "1,3");
    options.optopt("x", "max-clue", "Maximum value of clues", "10");

    let matches = match options.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            eprintln!("error: {}", f);
            return;
        },
    };

    if matches.opt_present("help") {
        print_usage(&program, options);
        return;
    }

    let opt = match parse_options(matches) {
        Ok(opt) => opt,
        Err(f) => {
            eprintln!("error: {}", f);
            return;
        },
    };
    run_generator(opt);
}
<commit_msg>Numberlink: support profiler in nl_generator<commit_after>extern crate puzrs;
extern crate rand;
extern crate getopts;

use getopts::Options;
use getopts::Matches;
use std::env;

use puzrs::*;
use std::io;
use std::time::Instant;
use rand::Rng;

use std::thread;
use std::sync::Mutex;
use std::io::Write;

macro_rules! run_timed {
    ($timer: ident, $flag: ident, $e: expr) => {
        if $flag {
            let start = Instant::now();
            let ret = $e;
            let end = start.elapsed();
            let cost_time = end.as_secs() as f64 + end.subsec_nanos() as f64 / 1e9f64;

            let mut timer_lock = $timer.lock().unwrap();
            *timer_lock += cost_time;

            ret
        } else {
            $e
        }
    };
}
fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

#[derive(Clone, Copy, Debug)]
struct GeneratorOption {
    height: i32,
    width: i32,
    jobs: i32,
    no_adjacent_clues: bool,
    symmetry_clue: bool,
    minimum_path_length: i32,
    empty_width: i32,
    max_clue: Option<i32>,
    corner: Option<(i32, i32)>,
    use_profiler: bool,
}

fn run_generator(opts: GeneratorOption) {
    let height = opts.height;
    let width = opts.width;
    let mut ths = vec![];
    let gen_probs = std::sync::Arc::new(Mutex::new(0i64));

    // profiling
    let use_profiler = opts.use_profiler;
    let cost_genenerator = std::sync::Arc::new(Mutex::new(0.0f64));
    let cost_pretest = std::sync::Arc::new(Mutex::new(0.0f64));
    let cost_exact_test = std::sync::Arc::new(Mutex::new(0.0f64));

    for _ in 0..opts.jobs {
        let gen_probs = gen_probs.clone();
        let cost_genenerator = cost_genenerator.clone();
        let cost_pretest = cost_pretest.clone();
        let cost_exact_test = cost_exact_test.clone();

        let opts = opts;

        ths.push(thread::spawn(move || {
            let start = Instant::now();

            let mut generator = numberlink::PlacementGenerator::new(height, width);

            let mut rng = rand::thread_rng();
            loop {
                let mut end = Grid::new(height, width, numberlink::Endpoint::Any);

                let trans = move |x: i32, y: i32, d: i32| {
                    let mut x = x;
                    let mut y = y;
                    if d == 1 || d == 3 {
                        x = width - 1 - x;
                    }
                    if d == 2 || d == 3 {
                        y = height - 1 - y;
                    }
                    (Y(y), X(x))
                };
                let fr = opts.empty_width;
                for y in 0..height {
                    for x in 0..width {
                        if y < fr || y >= height - fr || x < fr || x >= width - fr {
                            end[(Y(y), X(x))] = numberlink::Endpoint::Prohibited;
                        }
                    }
                }
                if let Some((lo, hi)) = opts.corner {
                    if opts.symmetry_clue {
                        for d in 0..2 {
                            let i = rng.gen_range(lo, hi + 1);
                            let (d0, d1) = if d == 0 { (0, 3) } else { (1, 2) };

                            end[trans(i, i, d0)] = numberlink::Endpoint::Forced;
                            end[trans(i, i + 1, d0)] = numberlink::Endpoint::Prohibited;
                            end[trans(i + 1, i, d0)] = numberlink::Endpoint::Prohibited;
                            for j in 0..i {
                                end[trans(j, j, d0)] = numberlink::Endpoint::Prohibited;
                            }
                            end[trans(i, i, d1)] = numberlink::Endpoint::Forced;
                            end[trans(i, i + 1, d1)] = numberlink::Endpoint::Prohibited;
                            end[trans(i + 1, i, d1)] = numberlink::Endpoint::Prohibited;
                            for j in 0..i {
                                end[trans(j, j, d1)] = numberlink::Endpoint::Prohibited;
                            }
                        }
                    } else {
                        for d in 0..4 {
                            let i = rng.gen_range(lo, hi + 1);
                            end[trans(i, i, d)] = numberlink::Endpoint::Forced;
                            end[trans(i, i + 1, d)] = numberlink::Endpoint::Prohibited;
                            end[trans(i + 1, i, d)] = numberlink::Endpoint::Prohibited;
                            for j in 0..i {
                                end[trans(j, j, d)] = numberlink::Endpoint::Prohibited;
                            }
                        }
                    }
                }
                let opt = numberlink::GeneratorOption {
                    chain_threshold: opts.minimum_path_length,
                    endpoint_constraint: Some(&end),
                    forbid_adjacent_clue: opts.no_adjacent_clues,
                    symmetry_clue: opts.symmetry_clue,
                    clue_limit: opts.max_clue,
                };

                let placement = run_timed!(cost_genenerator, use_profiler, generator.generate(&opt, &mut rng));
                if let Some(placement) = placement {
                    // pretest
                    let pretest_res = run_timed!(cost_pretest, use_profiler, numberlink::uniqueness_pretest(&placement));
                    if !pretest_res { continue; }

                    let problem = numberlink::extract_problem(&placement, &mut rng);

                    let ans = run_timed!(cost_exact_test, use_profiler, numberlink::solve2(&problem, Some(2), false, true));

                    if ans.len() == 1 && !ans.found_not_fully_filled {
                        let stdin = io::stdout();
                        let handle = &mut stdin.lock();

                        let end = start.elapsed();
                        let cost_time = (end.as_secs() as f64 + end.subsec_nanos() as f64 / 1e9f64) / 60f64;
                        let mut cnt = gen_probs.lock().unwrap();
                        *cnt += 1;
                        eprintln!("{} problem(s) in {:.3}[min] ({:.3} [prob/min])", *cnt, cost_time, (*cnt) as f64 / cost_time);
                        if use_profiler {
                            let cost_genenerator = *(cost_genenerator.lock().unwrap());
                            let cost_pretest = *(cost_pretest.lock().unwrap());
                            let cost_exact_test = *(cost_exact_test.lock().unwrap());
                            let cost_total = cost_genenerator + cost_pretest + cost_exact_test;

                            eprintln!("Generator: {:.3}[s] ({:.2}%) / Pretest: {:.3}[s] ({:.2}%) / Exact test: {:.3}[s] ({:.2}%)",
                                cost_genenerator, cost_genenerator / cost_total * 100.0f64,
                                cost_pretest, cost_pretest / cost_total * 100.0f64,
                                cost_exact_test, cost_exact_test / cost_total * 100.0f64);
                        }

                        writeln!(handle, "{} {}", height, width).unwrap();
                        for y in 0..height {
                            for x in 0..width {
                                let numberlink::Clue(c) = problem[(Y(y), X(x))];
                                if c >= 1 {
                                    write!(handle, "{}{}", c, if x == width - 1 { '\n' } else { ' ' }).unwrap();
                                } else {
                                    write!(handle, ".{}", if x == width - 1 { '\n' } else { ' ' }).unwrap();
                                }
                            }
                        }
                        writeln!(handle).unwrap();
                    }
                }
            }
        }));
    }
    for th in ths {
        th.join().unwrap();
    }
}

fn parse_options(matches: Matches) -> Result<GeneratorOption, &'static str> {
    let height = try!(
        matches.opt_str("h")
            .ok_or("'height' must be specified")
            .and_then(|arg| arg.parse::<i32>().map_err(|_| "Could not parse value for 'height'"))
            .and_then(|arg| if arg > 0 { Ok(arg) } else { Err("'height' must be a positive integer") }));
    let width = try!(
        matches.opt_str("w")
            .ok_or("'width' must be specified")
            .and_then(|arg| arg.parse::<i32>().map_err(|_| "Could not parse value for 'width'"))
            .and_then(|arg| if arg > 0 { Ok(arg) } else { Err("'width' must be a positive integer") }));
    let jobs = try!(
        matches.opt_str("j").map(|s|
            s.parse::<i32>()
                .map_err(|_| "Could not parse value for 'jobs'")
                .and_then(|arg| if arg > 0 { Ok(arg) } else { Err("'jobs' must be a positive integer") })
        ).unwrap_or(Ok(1)));
    let no_adjacent_clues = matches.opt_present("no-adjacent-clues");
    let symmetry_clue = matches.opt_present("symmetry");
    let minimum_path_length = try!(
        matches.opt_str("minimum-path-length").map(|s|
            s.parse::<i32>()
                .map_err(|_| "Could not parse value for 'minimum-path-length'")
                .and_then(|arg| if arg > 0 { Ok(arg) } else { Err("'minimum-path-length' must be a positive integer") })
        ).unwrap_or(Ok(1)));
    let empty_width = try!(
        matches.opt_str("empty-width").map(|s|
            s.parse::<i32>()
                .map_err(|_| "Could not parse value for 'empty-width'")
                .and_then(|arg| if arg > 0 { Ok(arg) } else { Err("'empty-width' must be a positive integer") })
        ).unwrap_or(Ok(1)));
    let max_clue = try!(
        matches.opt_str("max-clue").map(|s|
            s.parse::<i32>()
                .map_err(|_| "Could not parse value for 'max-clue'")
                .and_then(|arg| if arg > 0 { Ok(Some(arg)) } else { Err("'max-clue' must be a positive integer") })
        ).unwrap_or(Ok(None)));
    let use_profiler = matches.opt_present("use-profiler");
    let corner = match matches.opt_str("corner") {
        Some(s) => {
            let split = s.split(",").collect::<Vec<&str>>();
            if split.len() != 2 {
                return Err("Could not parse value for 'corner'");
            }
            let lo = try!(split[0].parse::<i32>().map_err(|_| "Could not parse value for 'corner'"));
            let hi = try!(split[1].parse::<i32>().map_err(|_| "Could not parse value for 'corner'"));
            if !(1 <= lo && lo <= hi) {
                return Err("'corner' must be a valid range on positive integers");
            }
            Some((lo, hi))
        },
        None => None,
    };
    Ok(GeneratorOption {
        height,
        width,
        jobs,
        no_adjacent_clues,
        symmetry_clue,
        minimum_path_length,
        empty_width,
        max_clue,
        corner,
        use_profiler,
    })
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut options = Options::new();
    options.optflag("", "help", "Show this help menu");
    options.optopt("h", "height", "Height of desired problems", "10");
    options.optopt("w", "width", "Width of desired problems", "10");
    options.optopt("j", "jobs", "Number of workers (threads)", "2");
    options.optflag("a", "no-adjacent-clues", "Disallow adjacent clues");
    options.optflag("s", "symmetry", "Force symmetry");
    options.optopt("m", "minimum-path-length", "Minimum length of paths in the answer", "12");
    options.optopt("e", "empty-width", "Disallow clues on n cell(s) from the outer border", "1");
    options.optopt("c", "corner", "Put one clue within specified range from each corner", "1,3");
    options.optopt("x", "max-clue", "Maximum value of clues", "10");
    options.optflag("p", "use-profiler", "Enable profiler");

    let matches = match options.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            eprintln!("error: {}", f);
            return;
        },
    };

    if matches.opt_present("help") {
        print_usage(&program, options);
        return;
    }

    let opt = match parse_options(matches) {
        Ok(opt) => opt,
        Err(f) => {
            eprintln!("error: {}", f);
            return;
        },
    };
    run_generator(opt);
}
<|endoftext|>


<commit_before>use std::env;
use std::process::Command;
use std::sync::{Arc, Mutex};
use std::io;

lazy_static! {
    /// On non-Windows systems, the `SHELL` environment variable will be used to determine the
    /// preferred shell of choice for execution. Windows will simply use `cmd`.
    static ref COMMAND: (String, &'static str) = if cfg!(target_os = "windows") {
        ("cmd".into(), "/C")
    } else {
        (env::var("SHELL").unwrap_or("/bin/sh".into()), "-c")
    };
}

/// A state that offers access to executing a generated command.
///
/// The ticket holds a mutable reference to a string that contains the command to be executed.
/// After execution of the the command via the `then_execute()` method, the string will be
/// cleared so that a new command can be written to the string in the future.
pub struct CommandTicket<'a> {
    command: &'a mut String,
    out_perm: Arc<Mutex<()>>,
}

impl<'a> CommandTicket<'a> {
    pub fn new(command: &'a mut String, out_perm: Arc<Mutex<()>>) -> CommandTicket<'a> {
        CommandTicket { command, out_perm }
    }

    /// Executes the command stored within the ticket, and
    /// clearing the command's buffer when finished.'
    #[cfg(not(all(unix, not(target_os = "redox"))))]
    pub fn then_execute(self) {
        use std::process::Stdio;
        use std::io::Write;

        // Spawn a shell with the supplied command.
        let cmd = Command::new(COMMAND.0.as_str())
            .arg(COMMAND.1)
            .arg(&self.command)
            .stdout(Stdio::piped())
            .stderr(Stdio::piped())
            .output();

        // Then wait for the command to exit, if it was spawned.
        match cmd {
            Ok(output) => {
                // While this lock is active, this thread will be the only thread allowed
                // to write it's outputs.
                let _lock = self.out_perm.lock().unwrap();

                let stdout = io::stdout();
                let stderr = io::stderr();

                let _ = stdout.lock().write_all(&output.stdout);
                let _ = stderr.lock().write_all(&output.stderr);
            }
            Err(why) => eprintln!("fd: exec error: {}", why),
        }

        // Clear the buffer for later re-use.
        self.command.clear();
    }

    #[cfg(all(unix, not(target_os = "redox")))]
    pub fn then_execute(self) {
        use libc::*;
        use std::fs::File;
        use std::os::unix::process::CommandExt;
        use std::os::unix::io::FromRawFd;

        // Initial a pair of pipes that will be used to
        // pipe the std{out,err} of the spawned process.
        let mut stdout_fds = [0; 2];
        let mut stderr_fds = [0; 2];

        unsafe {
            pipe(stdout_fds.as_mut_ptr());
            pipe(stderr_fds.as_mut_ptr());
        }

        // Spawn a shell with the supplied command.
        let cmd = Command::new(COMMAND.0.as_str())
            .arg(COMMAND.1)
            .arg(&self.command)
            // Configure the pipes accordingly in the child.
            .before_exec(move || unsafe {
                // Redirect the child's std{out,err} to the write ends of our pipe.
                dup2(stdout_fds[1], STDOUT_FILENO);
                dup2(stderr_fds[1], STDERR_FILENO);

                // Close all the fds we created here, so EOF will be sent when the program exits.
                close(stdout_fds[0]);
                close(stdout_fds[1]);
                close(stderr_fds[0]);
                close(stderr_fds[1]);
                Ok(())
            })
            .spawn();

        // Open the read end of the pipes as `File`s.
        let (mut pout, mut perr) = unsafe {
            // Close the write ends of the pipes in the parent
            close(stdout_fds[1]);
            close(stderr_fds[1]);
            (
                // But create files from the read ends.
                File::from_raw_fd(stdout_fds[0]),
                File::from_raw_fd(stderr_fds[0]),
            )
        };

        match cmd {
            Ok(mut child) => {
                let _ = child.wait();

                // Create a lock to ensure that this thread has exclusive access to writing.
                let _lock = self.out_perm.lock().unwrap();

                // And then write the outputs of the process until EOF is sent to each file.
                let stdout = io::stdout();
                let stderr = io::stderr();
                let _ = io::copy(&mut pout, &mut stdout.lock());
                let _ = io::copy(&mut perr, &mut stderr.lock());
            }
            Err(why) => eprintln!("fd: exec error: {}", why),
        }

        // Clear the command string's buffer for later re-use.
        self.command.clear();
    }
}
<commit_msg>Removed unnecessary exclusion of Redox in cond-compilation and narrowed what we import from .<commit_after>use std::env;
use std::process::Command;
use std::sync::{Arc, Mutex};
use std::io;

lazy_static! {
    /// On non-Windows systems, the `SHELL` environment variable will be used to determine the
    /// preferred shell of choice for execution. Windows will simply use `cmd`.
    static ref COMMAND: (String, &'static str) = if cfg!(target_os = "windows") {
        ("cmd".into(), "/C")
    } else {
        (env::var("SHELL").unwrap_or("/bin/sh".into()), "-c")
    };
}

/// A state that offers access to executing a generated command.
///
/// The ticket holds a mutable reference to a string that contains the command to be executed.
/// After execution of the the command via the `then_execute()` method, the string will be
/// cleared so that a new command can be written to the string in the future.
pub struct CommandTicket<'a> {
    command: &'a mut String,
    out_perm: Arc<Mutex<()>>,
}

impl<'a> CommandTicket<'a> {
    pub fn new(command: &'a mut String, out_perm: Arc<Mutex<()>>) -> CommandTicket<'a> {
        CommandTicket { command, out_perm }
    }

    /// Executes the command stored within the ticket, and
    /// clearing the command's buffer when finished.'
    #[cfg(not(unix))]
    pub fn then_execute(self) {
        use std::process::Stdio;
        use std::io::Write;

        // Spawn a shell with the supplied command.
        let cmd = Command::new(COMMAND.0.as_str())
            .arg(COMMAND.1)
            .arg(&self.command)
            .stdout(Stdio::piped())
            .stderr(Stdio::piped())
            .output();

        // Then wait for the command to exit, if it was spawned.
        match cmd {
            Ok(output) => {
                // While this lock is active, this thread will be the only thread allowed
                // to write it's outputs.
                let _lock = self.out_perm.lock().unwrap();

                let stdout = io::stdout();
                let stderr = io::stderr();

                let _ = stdout.lock().write_all(&output.stdout);
                let _ = stderr.lock().write_all(&output.stderr);
            }
            Err(why) => eprintln!("fd: exec error: {}", why),
        }

        // Clear the buffer for later re-use.
        self.command.clear();
    }

    #[cfg(all(unix))]
    pub fn then_execute(self) {
        use libc::{close, dup2, pipe, STDERR_FILENO, STDOUT_FILENO};
        use std::fs::File;
        use std::os::unix::process::CommandExt;
        use std::os::unix::io::FromRawFd;

        // Initial a pair of pipes that will be used to
        // pipe the std{out,err} of the spawned process.
        let mut stdout_fds = [0; 2];
        let mut stderr_fds = [0; 2];

        unsafe {
            pipe(stdout_fds.as_mut_ptr());
            pipe(stderr_fds.as_mut_ptr());
        }

        // Spawn a shell with the supplied command.
        let cmd = Command::new(COMMAND.0.as_str())
            .arg(COMMAND.1)
            .arg(&self.command)
            // Configure the pipes accordingly in the child.
            .before_exec(move || unsafe {
                // Redirect the child's std{out,err} to the write ends of our pipe.
                dup2(stdout_fds[1], STDOUT_FILENO);
                dup2(stderr_fds[1], STDERR_FILENO);

                // Close all the fds we created here, so EOF will be sent when the program exits.
                close(stdout_fds[0]);
                close(stdout_fds[1]);
                close(stderr_fds[0]);
                close(stderr_fds[1]);
                Ok(())
            })
            .spawn();

        // Open the read end of the pipes as `File`s.
        let (mut pout, mut perr) = unsafe {
            // Close the write ends of the pipes in the parent
            close(stdout_fds[1]);
            close(stderr_fds[1]);
            (
                // But create files from the read ends.
                File::from_raw_fd(stdout_fds[0]),
                File::from_raw_fd(stderr_fds[0]),
            )
        };

        match cmd {
            Ok(mut child) => {
                let _ = child.wait();

                // Create a lock to ensure that this thread has exclusive access to writing.
                let _lock = self.out_perm.lock().unwrap();

                // And then write the outputs of the process until EOF is sent to each file.
                let stdout = io::stdout();
                let stderr = io::stderr();
                let _ = io::copy(&mut pout, &mut stdout.lock());
                let _ = io::copy(&mut perr, &mut stderr.lock());
            }
            Err(why) => eprintln!("fd: exec error: {}", why),
        }

        // Clear the command string's buffer for later re-use.
        self.command.clear();
    }
}
<|endoftext|>


<commit_before>extern crate lichen;

use lichen::parse::Parser;
use lichen::var::Var;
use lichen::eval::{Eval,Evaluator};

struct Data; // we'll just make up an empty struct

impl Eval for Data { // implement the required traits, but to keep it simple we wont actually do anything
    #[allow(unused_variables)]
    fn get (&self, path: Option<Vec<&str>>, lookup: &str) -> Option<Var> {
        None
    }

    #[allow(unused_variables)]
    fn set (&mut self, path: Option<Vec<&str>>, lookup: &str, var: Var) {
    }

    #[allow(unused_variables)]
    fn call (&mut self, var: Var, fun: &str, vars: &Vec<Var>) -> Option<Var> {
        None
    }
}

fn main() {
    //load the lichen source file as a string
    let bytes = include_bytes!("basic.ls");
    let mut src = String::from_utf8_lossy(bytes);

    let mut env = Parser::parse_blocks(src.to_mut()).expect("ERROR: Unable to parse source").into_env(); //parse the source and build the environment

    let mut data = Data;
    let mut ev = Evaluator::new(&mut env, &mut data); // build the evaluator based on the environment and any data

    while let Some((vars, _next_node)) = ev.next() { // here we loop through the evaluator steps
        for var in vars {
            match var {
                Var::String(s) => { println!("{:}", s); }, // print out the emitted variables
                _ => {},
            }
        }

        // if we wanted to we could look at the next_node returned,
        // and advance it manually if needed
        // you'd do this if the node were an await-style node,
        // which either advances or continues on during the next step
        // see the contrived example to see this
    }
}
<commit_msg>use empty<commit_after>extern crate lichen;

use lichen::parse::Parser;
use lichen::var::Var;
use lichen::eval::{Evaluator,Empty};

fn main() {
    //load the lichen source file as a string
    let bytes = include_bytes!("basic.ls");
    let mut src = String::from_utf8_lossy(bytes);

    let mut env = Parser::parse_blocks(src.to_mut()).expect("ERROR: Unable to parse source").into_env(); //parse the source and build the environment

    let mut empty = Empty;
    let mut ev = Evaluator::new(&mut env, &mut empty); // build the evaluator based on the environment and any data

    while let Some((vars, _next_node)) = ev.next() { // here we loop through the evaluator steps
        for var in vars {
            match var {
                Var::String(s) => { println!("{:}", s); }, // print out the emitted variables
                _ => {},
            }
        }

        // if we wanted to we could look at the next_node returned,
        // and advance it manually if needed
        // you'd do this if the node were an await-style node,
        // which either advances or continues on during the next step
        // see the contrived example to see this
    }
}
<|endoftext|>


<commit_before>//! OpenGL back-end for Rust-Graphics.

// External crates.
use gl;
use gl::types::{
    GLfloat,
    GLsizeiptr,
    GLuint,
};
use std::ptr;
use std::mem;
use shader_utils::{compile_shader};
use BackEnd = graphics::BackEnd;

// Local crate.
use AssetStore;

static VERTEX_SHADER_TRI_LIST_XY_RGBA: &'static str = "
attribute vec4 a_v4Position;
attribute vec4 a_v4FillColor;

varying vec4 v_v4FillColor;

void main()
{
    v_v4FillColor = a_v4FillColor;
    gl_Position = a_v4Position;
}
";

static FRAGMENT_SHADER_TRI_LIST_XY_RGBA: &'static str = "
varying vec4 v_v4FillColor;

void main()
{
        gl_FragColor = v_v4FillColor;
}
";

static VERTEX_SHADER_TRI_LIST_XY_RGBA_UV: &'static str = "
attribute vec4 a_v4Position;
attribute vec4 a_v4FillColor;
attribute vec2 a_v2TexCoord;

uniform sampler2D s_texture;

varying vec2 v_v2TexCoord;
varying vec4 v_v4FillColor;

void main()
{
        v_v2TexCoord = a_v2TexCoord;
        v_v4FillColor = a_v4FillColor;
        gl_Position = a_v4Position;
}
";

static FRAGMENT_SHADER_TRI_LIST_XY_RGBA_UV: &'static str = "
uniform sampler2D s_texture;

varying vec2 v_v2TexCoord;
varying vec4 v_v4FillColor;

void main()
{
        gl_FragColor = texture2D(s_texture, v_v2TexCoord) * v_v4FillColor;
}
";

/// OpenGL back-end for Rust-Graphics.
pub struct Gl<'a> {
    gl_data: &'a mut GlData,
    asset_store: &'a AssetStore,
}

impl<'a> Gl<'a> {
    /// Creates a new OpenGl back-end.
    pub fn new(
        gl_data: &'a mut GlData,
        asset_store: &'a AssetStore
    ) -> Gl<'a> {
        Gl {
            gl_data: gl_data,
            asset_store: asset_store,
        }
    }
}

struct TriListXYRGBA {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    a_v4Position: GLuint,
    a_v4FillColor: GLuint,
}

impl TriListXYRGBA {
    fn new() -> TriListXYRGBA {
        let vertex_shader = match compile_shader(gl::VERTEX_SHADER, VERTEX_SHADER_TRI_LIST_XY_RGBA) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(gl::FRAGMENT_SHADER, FRAGMENT_SHADER_TRI_LIST_XY_RGBA) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let program = gl::CreateProgram();

        gl::AttachShader(program, vertex_shader);
        gl::AttachShader(program, fragment_shader);
        gl::LinkProgram(program);
        gl::UseProgram(program);
        unsafe {
            let a_v4Position = "a_v4Position".with_c_str(|ptr| gl::GetAttribLocation(program, ptr));
            gl::EnableVertexAttribArray(a_v4Position as GLuint);
            let a_v4FillColor = "a_v4FillColor".with_c_str(|ptr| gl::GetAttribLocation(program, ptr));
            gl::EnableVertexAttribArray(a_v4FillColor as GLuint);
            TriListXYRGBA {
                vertex_shader: vertex_shader,
                fragment_shader: fragment_shader,
                program: program,
                a_v4Position: a_v4Position as GLuint,
                a_v4FillColor: a_v4FillColor as GLuint,
            }
        }
    }
}

struct TriListXYRGBAUV {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    a_v4Position: GLuint,
    a_v4FillColor: GLuint,
    a_v2TexCoord: GLuint,
}

impl TriListXYRGBAUV {
    fn new() -> TriListXYRGBAUV {
        let vertex_shader = match compile_shader(gl::VERTEX_SHADER, VERTEX_SHADER_TRI_LIST_XY_RGBA_UV) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(gl::FRAGMENT_SHADER, FRAGMENT_SHADER_TRI_LIST_XY_RGBA_UV) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };

        let program = gl::CreateProgram();
        gl::AttachShader(program, vertex_shader);
        gl::AttachShader(program, fragment_shader);
        gl::LinkProgram(program);
        gl::UseProgram(program);
        unsafe {
            let a_v4Position = "a_v4Position".with_c_str(|ptr| gl::GetAttribLocation(program, ptr));
            gl::EnableVertexAttribArray(a_v4Position as GLuint);
            let a_v4FillColor = "a_v4FillColor".with_c_str(|ptr| gl::GetAttribLocation(program, ptr));
            gl::EnableVertexAttribArray(a_v4FillColor as GLuint);
            let a_v2TexCoord = "a_v2TexCoord".with_c_str(|ptr| gl::GetAttribLocation(program, ptr));
            gl::EnableVertexAttribArray(a_v4FillColor as GLuint);
            TriListXYRGBAUV {
                vertex_shader: vertex_shader,
                fragment_shader: fragment_shader,
                program: program,
                a_v4Position: a_v4Position as GLuint,
                a_v4FillColor: a_v4FillColor as GLuint,
                a_v2TexCoord: a_v2TexCoord as GLuint,
            }
        }
    }
}

/// Contains OpenGL data.
pub struct GlData {
    tri_list_xy_rgba: TriListXYRGBA,
    tri_list_xy_rgba_uv: TriListXYRGBAUV,
    // id of buffer for xy positions.
    position_id: GLuint,
    // id of buffer for rgba colors.
    fill_color_id: GLuint,
    // id of buffer for uv texture coords.
    tex_coord_id: GLuint,
    // Keeps track of the current shader program.
    current_program: Option<GLuint>,
}

impl<'a> GlData {
    /// Creates a new OpenGl back-end.
    pub fn new() -> GlData {
        // Load the vertices, color and texture coord buffers.
        unsafe {
            let mut vbo : [GLuint, ..3] = [0, ..3];
            gl::GenBuffers(3, vbo.as_mut_ptr());
            let position_id = vbo[0];
            let fill_color_id = vbo[1];
            let tex_coord_id = vbo[2];

            GlData {
                tri_list_xy_rgba: TriListXYRGBA::new(),
                tri_list_xy_rgba_uv: TriListXYRGBAUV::new(),
                position_id: position_id,
                fill_color_id: fill_color_id,
                tex_coord_id: tex_coord_id,
                current_program: None,
            }
        }
    }

    /// Sets the current program only if the program is not in use.
    pub fn use_program(&mut self, program: GLuint) {
        match self.current_program {
            None => {},
            Some(current_program) => {
                if program == current_program { return; }
            },
        }

        gl::UseProgram(program);
        self.current_program = Some(program);
    }
}

impl<'a> BackEnd for Gl<'a> {
    fn supports_clear_rgba(&self) -> bool { true }

    fn clear_rgba(&mut self, r: f32, g: f32, b: f32, a: f32) {
        gl::ClearColor(r, g, b, a);
        gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
    }

    fn enable_alpha_blend(&mut self) {
        gl::Enable(gl::BLEND);
        gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
    }

    fn disable_alpha_blend(&mut self) {
        gl::Disable(gl::BLEND);
    }

    fn supports_single_texture(&self) -> bool { true }

    fn enable_single_texture(&mut self, texture_id: uint) {
        let texture = self.asset_store.get_texture(texture_id);
        gl::BindTexture(gl::TEXTURE_2D, texture);
    }

    fn disable_single_texture(&mut self) {}

    // Assume all textures has alpha channel for now.
    fn has_texture_alpha(&self, _texture_id: uint) -> bool { true }

    fn supports_tri_list_xy_f32_rgba_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32]
    ) {
        {
            // Set shader program.
            let shader_program = self.gl_data.tri_list_xy_rgba.program;
            self.gl_data.use_program(shader_program);
        }
        let data = &self.gl_data;
        let shader = &data.tri_list_xy_rgba;
        let size_vertices: i32 = 2;
        unsafe {
            gl::BindBuffer(
                gl::ARRAY_BUFFER, data.position_id);
            gl::BufferData(
                gl::ARRAY_BUFFER, (vertices.len() * mem::size_of::<GLfloat>()) as GLsizeiptr, mem::transmute(&vertices[0]), gl::DYNAMIC_DRAW);
            gl::VertexAttribPointer(
                shader.a_v4Position as GLuint, size_vertices, gl::FLOAT, gl::TRUE, 0, ptr::null());

            gl::BindBuffer(
                gl::ARRAY_BUFFER, data.fill_color_id);
            gl::BufferData(
                gl::ARRAY_BUFFER, (colors.len() * mem::size_of::<GLfloat>()) as GLsizeiptr, mem::transmute(&colors[0]), gl::DYNAMIC_DRAW);
            gl::VertexAttribPointer(
                shader.a_v4FillColor as GLuint, 4, gl::FLOAT, gl::FALSE, 0, ptr::null());
        }
        // gl::enable(gl::DEPTH_TEST);
        gl::CullFace(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::DrawArrays(gl::TRIANGLES, 0, items);
    }

    fn supports_tri_list_xy_f32_rgba_f32_uv_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32_uv_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32],
        texture_coords: &[f32]
    ) {
        {
            // Set shader program.
            let shader_program = self.gl_data.tri_list_xy_rgba_uv.program;
            self.gl_data.use_program(shader_program);
        }
        let data = &self.gl_data;
        let shader = &data.tri_list_xy_rgba_uv;
        let size_vertices: i32 = 2;
        unsafe {
            gl::BindBuffer(
                gl::ARRAY_BUFFER, data.position_id);
            gl::BufferData(
                gl::ARRAY_BUFFER, (vertices.len() * mem::size_of::<GLfloat>()) as GLsizeiptr, mem::transmute(&vertices[0]), gl::DYNAMIC_DRAW);
            gl::VertexAttribPointer(
                shader.a_v4Position as GLuint, size_vertices, gl::FLOAT, gl::TRUE, 0, ptr::null());

            gl::BindBuffer(
                gl::ARRAY_BUFFER, data.fill_color_id);
            gl::BufferData(
                gl::ARRAY_BUFFER, (colors.len() * mem::size_of::<GLfloat>()) as GLsizeiptr, mem::transmute(&colors[0]), gl::DYNAMIC_DRAW);
            gl::VertexAttribPointer(
                shader.a_v4FillColor as GLuint, 4, gl::FLOAT, gl::FALSE, 0, ptr::null());

            gl::BindBuffer(
                gl::ARRAY_BUFFER, data.tex_coord_id);
            gl::BufferData(
                gl::ARRAY_BUFFER, (texture_coords.len() * mem::size_of::<GLfloat>()) as GLsizeiptr, mem::transmute(&texture_coords[0]), gl::DYNAMIC_DRAW);
            gl::VertexAttribPointer(
                shader.a_v2TexCoord as GLuint, 2, gl::FLOAT, gl::FALSE, 0, ptr::null());
        }
        // gl::enable(gl::DEPTH_TEST);
        gl::CullFace(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::DrawArrays(gl::TRIANGLES, 0, items);
    }
}

<commit_msg>Remove unnecessary alias in gl_back_end<commit_after>//! OpenGL back-end for Rust-Graphics.

// External crates.
use gl;
use gl::types::{
    GLfloat,
    GLsizeiptr,
    GLuint,
};
use std::ptr;
use std::mem;
use shader_utils::{compile_shader};
use graphics::BackEnd;

// Local crate.
use AssetStore;

static VERTEX_SHADER_TRI_LIST_XY_RGBA: &'static str = "
attribute vec4 a_v4Position;
attribute vec4 a_v4FillColor;

varying vec4 v_v4FillColor;

void main()
{
    v_v4FillColor = a_v4FillColor;
    gl_Position = a_v4Position;
}
";

static FRAGMENT_SHADER_TRI_LIST_XY_RGBA: &'static str = "
varying vec4 v_v4FillColor;

void main()
{
        gl_FragColor = v_v4FillColor;
}
";

static VERTEX_SHADER_TRI_LIST_XY_RGBA_UV: &'static str = "
attribute vec4 a_v4Position;
attribute vec4 a_v4FillColor;
attribute vec2 a_v2TexCoord;

uniform sampler2D s_texture;

varying vec2 v_v2TexCoord;
varying vec4 v_v4FillColor;

void main()
{
        v_v2TexCoord = a_v2TexCoord;
        v_v4FillColor = a_v4FillColor;
        gl_Position = a_v4Position;
}
";

static FRAGMENT_SHADER_TRI_LIST_XY_RGBA_UV: &'static str = "
uniform sampler2D s_texture;

varying vec2 v_v2TexCoord;
varying vec4 v_v4FillColor;

void main()
{
        gl_FragColor = texture2D(s_texture, v_v2TexCoord) * v_v4FillColor;
}
";

/// OpenGL back-end for Rust-Graphics.
pub struct Gl<'a> {
    gl_data: &'a mut GlData,
    asset_store: &'a AssetStore,
}

impl<'a> Gl<'a> {
    /// Creates a new OpenGl back-end.
    pub fn new(
        gl_data: &'a mut GlData,
        asset_store: &'a AssetStore
    ) -> Gl<'a> {
        Gl {
            gl_data: gl_data,
            asset_store: asset_store,
        }
    }
}

struct TriListXYRGBA {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    a_v4Position: GLuint,
    a_v4FillColor: GLuint,
}

impl TriListXYRGBA {
    fn new() -> TriListXYRGBA {
        let vertex_shader = match compile_shader(gl::VERTEX_SHADER, VERTEX_SHADER_TRI_LIST_XY_RGBA) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(gl::FRAGMENT_SHADER, FRAGMENT_SHADER_TRI_LIST_XY_RGBA) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let program = gl::CreateProgram();

        gl::AttachShader(program, vertex_shader);
        gl::AttachShader(program, fragment_shader);
        gl::LinkProgram(program);
        gl::UseProgram(program);
        unsafe {
            let a_v4Position = "a_v4Position".with_c_str(|ptr| gl::GetAttribLocation(program, ptr));
            gl::EnableVertexAttribArray(a_v4Position as GLuint);
            let a_v4FillColor = "a_v4FillColor".with_c_str(|ptr| gl::GetAttribLocation(program, ptr));
            gl::EnableVertexAttribArray(a_v4FillColor as GLuint);
            TriListXYRGBA {
                vertex_shader: vertex_shader,
                fragment_shader: fragment_shader,
                program: program,
                a_v4Position: a_v4Position as GLuint,
                a_v4FillColor: a_v4FillColor as GLuint,
            }
        }
    }
}

struct TriListXYRGBAUV {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    a_v4Position: GLuint,
    a_v4FillColor: GLuint,
    a_v2TexCoord: GLuint,
}

impl TriListXYRGBAUV {
    fn new() -> TriListXYRGBAUV {
        let vertex_shader = match compile_shader(gl::VERTEX_SHADER, VERTEX_SHADER_TRI_LIST_XY_RGBA_UV) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(gl::FRAGMENT_SHADER, FRAGMENT_SHADER_TRI_LIST_XY_RGBA_UV) {
            Ok(id) => id,
            Err(s) => fail!("compile_shader: {}", s)
        };

        let program = gl::CreateProgram();
        gl::AttachShader(program, vertex_shader);
        gl::AttachShader(program, fragment_shader);
        gl::LinkProgram(program);
        gl::UseProgram(program);
        unsafe {
            let a_v4Position = "a_v4Position".with_c_str(|ptr| gl::GetAttribLocation(program, ptr));
            gl::EnableVertexAttribArray(a_v4Position as GLuint);
            let a_v4FillColor = "a_v4FillColor".with_c_str(|ptr| gl::GetAttribLocation(program, ptr));
            gl::EnableVertexAttribArray(a_v4FillColor as GLuint);
            let a_v2TexCoord = "a_v2TexCoord".with_c_str(|ptr| gl::GetAttribLocation(program, ptr));
            gl::EnableVertexAttribArray(a_v4FillColor as GLuint);
            TriListXYRGBAUV {
                vertex_shader: vertex_shader,
                fragment_shader: fragment_shader,
                program: program,
                a_v4Position: a_v4Position as GLuint,
                a_v4FillColor: a_v4FillColor as GLuint,
                a_v2TexCoord: a_v2TexCoord as GLuint,
            }
        }
    }
}

/// Contains OpenGL data.
pub struct GlData {
    tri_list_xy_rgba: TriListXYRGBA,
    tri_list_xy_rgba_uv: TriListXYRGBAUV,
    // id of buffer for xy positions.
    position_id: GLuint,
    // id of buffer for rgba colors.
    fill_color_id: GLuint,
    // id of buffer for uv texture coords.
    tex_coord_id: GLuint,
    // Keeps track of the current shader program.
    current_program: Option<GLuint>,
}

impl<'a> GlData {
    /// Creates a new OpenGl back-end.
    pub fn new() -> GlData {
        // Load the vertices, color and texture coord buffers.
        unsafe {
            let mut vbo : [GLuint, ..3] = [0, ..3];
            gl::GenBuffers(3, vbo.as_mut_ptr());
            let position_id = vbo[0];
            let fill_color_id = vbo[1];
            let tex_coord_id = vbo[2];

            GlData {
                tri_list_xy_rgba: TriListXYRGBA::new(),
                tri_list_xy_rgba_uv: TriListXYRGBAUV::new(),
                position_id: position_id,
                fill_color_id: fill_color_id,
                tex_coord_id: tex_coord_id,
                current_program: None,
            }
        }
    }

    /// Sets the current program only if the program is not in use.
    pub fn use_program(&mut self, program: GLuint) {
        match self.current_program {
            None => {},
            Some(current_program) => {
                if program == current_program { return; }
            },
        }

        gl::UseProgram(program);
        self.current_program = Some(program);
    }
}

impl<'a> BackEnd for Gl<'a> {
    fn supports_clear_rgba(&self) -> bool { true }

    fn clear_rgba(&mut self, r: f32, g: f32, b: f32, a: f32) {
        gl::ClearColor(r, g, b, a);
        gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
    }

    fn enable_alpha_blend(&mut self) {
        gl::Enable(gl::BLEND);
        gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
    }

    fn disable_alpha_blend(&mut self) {
        gl::Disable(gl::BLEND);
    }

    fn supports_single_texture(&self) -> bool { true }

    fn enable_single_texture(&mut self, texture_id: uint) {
        let texture = self.asset_store.get_texture(texture_id);
        gl::BindTexture(gl::TEXTURE_2D, texture);
    }

    fn disable_single_texture(&mut self) {}

    // Assume all textures has alpha channel for now.
    fn has_texture_alpha(&self, _texture_id: uint) -> bool { true }

    fn supports_tri_list_xy_f32_rgba_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32]
    ) {
        {
            // Set shader program.
            let shader_program = self.gl_data.tri_list_xy_rgba.program;
            self.gl_data.use_program(shader_program);
        }
        let data = &self.gl_data;
        let shader = &data.tri_list_xy_rgba;
        let size_vertices: i32 = 2;
        unsafe {
            gl::BindBuffer(
                gl::ARRAY_BUFFER, data.position_id);
            gl::BufferData(
                gl::ARRAY_BUFFER, (vertices.len() * mem::size_of::<GLfloat>()) as GLsizeiptr, mem::transmute(&vertices[0]), gl::DYNAMIC_DRAW);
            gl::VertexAttribPointer(
                shader.a_v4Position as GLuint, size_vertices, gl::FLOAT, gl::TRUE, 0, ptr::null());

            gl::BindBuffer(
                gl::ARRAY_BUFFER, data.fill_color_id);
            gl::BufferData(
                gl::ARRAY_BUFFER, (colors.len() * mem::size_of::<GLfloat>()) as GLsizeiptr, mem::transmute(&colors[0]), gl::DYNAMIC_DRAW);
            gl::VertexAttribPointer(
                shader.a_v4FillColor as GLuint, 4, gl::FLOAT, gl::FALSE, 0, ptr::null());
        }
        // gl::enable(gl::DEPTH_TEST);
        gl::CullFace(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::DrawArrays(gl::TRIANGLES, 0, items);
    }

    fn supports_tri_list_xy_f32_rgba_f32_uv_f32(&self) -> bool { true }

    fn tri_list_xy_f32_rgba_f32_uv_f32(
        &mut self,
        vertices: &[f32],
        colors: &[f32],
        texture_coords: &[f32]
    ) {
        {
            // Set shader program.
            let shader_program = self.gl_data.tri_list_xy_rgba_uv.program;
            self.gl_data.use_program(shader_program);
        }
        let data = &self.gl_data;
        let shader = &data.tri_list_xy_rgba_uv;
        let size_vertices: i32 = 2;
        unsafe {
            gl::BindBuffer(
                gl::ARRAY_BUFFER, data.position_id);
            gl::BufferData(
                gl::ARRAY_BUFFER, (vertices.len() * mem::size_of::<GLfloat>()) as GLsizeiptr, mem::transmute(&vertices[0]), gl::DYNAMIC_DRAW);
            gl::VertexAttribPointer(
                shader.a_v4Position as GLuint, size_vertices, gl::FLOAT, gl::TRUE, 0, ptr::null());

            gl::BindBuffer(
                gl::ARRAY_BUFFER, data.fill_color_id);
            gl::BufferData(
                gl::ARRAY_BUFFER, (colors.len() * mem::size_of::<GLfloat>()) as GLsizeiptr, mem::transmute(&colors[0]), gl::DYNAMIC_DRAW);
            gl::VertexAttribPointer(
                shader.a_v4FillColor as GLuint, 4, gl::FLOAT, gl::FALSE, 0, ptr::null());

            gl::BindBuffer(
                gl::ARRAY_BUFFER, data.tex_coord_id);
            gl::BufferData(
                gl::ARRAY_BUFFER, (texture_coords.len() * mem::size_of::<GLfloat>()) as GLsizeiptr, mem::transmute(&texture_coords[0]), gl::DYNAMIC_DRAW);
            gl::VertexAttribPointer(
                shader.a_v2TexCoord as GLuint, 2, gl::FLOAT, gl::FALSE, 0, ptr::null());
        }
        // gl::enable(gl::DEPTH_TEST);
        gl::CullFace(gl::FRONT_AND_BACK);

        let items: i32 = vertices.len() as i32 / size_vertices;
        gl::DrawArrays(gl::TRIANGLES, 0, items);
    }
}

<|endoftext|>


<commit_before>extern crate docopt;
extern crate flac;
extern crate hound;
extern crate nom;
extern crate rustc_serialize;

use docopt::Docopt;
use flac::Stream;

use std::env;
use std::error::Error;
use std::io;
use std::path::{Path, PathBuf};

const USAGE: &'static str = "
Usage: decode <input> <output>
       decode <input>... <dir>
       decode --help

Options:
  -h, --help   Show this message.
";

#[derive(RustcDecodable)]
struct Arguments {
  arg_input: Vec<String>,
  arg_output: Option<String>,
  arg_dir: Option<String>,
}

fn decode_file(input_file: &str, output_file: &str)
               -> Result<(), hound::Error> {
  let mut stream = try! {
    Stream::from_file(input_file).map_err(hound::Error::IoError)
  };
  let info       = stream.info();
  let frames_len = stream.frames.len();

  let spec = hound::WavSpec {
    channels: info.channels as u16,
    sample_rate: info.sample_rate,
    bits_per_sample: info.bits_per_sample as u16,
  };

  let mut output = try!(hound::WavWriter::create(output_file, spec));

  for _ in 0..frames_len {
    if let Some(buffer) = stream.next_frame() {
      let buffer_size = buffer.len();
      let block_size  = buffer_size / 2;
      let left        = &buffer[0..block_size];
      let right       = &buffer[block_size..buffer_size];

      for i in 0..block_size {
        try!(output.write_sample(left[i]));
        try!(output.write_sample(right[i]));
      }
    } else {
      break;
    }
  }

  output.finalize()
}

fn to_output_file(buffer: &mut PathBuf, path: &Path, directory: &str)
                  -> Result<(), hound::Error> {
  buffer.push(directory);

  path.file_name().map(|name| {
    buffer.push(name);
    buffer.set_extension("wav");
  }).ok_or_else(|| {
    let kind    = io::ErrorKind::NotFound;
    let message = "no file name found";
    let error   = io::Error::new(kind, message);

    hound::Error::IoError(error)
  })
}

fn main() {
  let args: Arguments = Docopt::new(USAGE)
    .and_then(|d| d.argv(env::args()).decode())
    .unwrap_or_else(|e| e.exit());

  if let Some(ref output_file) = args.arg_output {
    let input_file = &args.arg_input[0];

    if let Err(e) = decode_file(input_file, output_file) {
      println!("{:?}", e);
    } else {
      println!("decoded: {} -> {}", input_file, output_file);
    }
  }
}
<commit_msg>Add `decode_all_files` for simpler error handling<commit_after>extern crate docopt;
extern crate flac;
extern crate hound;
extern crate nom;
extern crate rustc_serialize;

use docopt::Docopt;
use flac::Stream;

use std::env;
use std::error::Error;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

const USAGE: &'static str = "
Usage: decode <input> <output>
       decode <input>... <dir>
       decode --help

Options:
  -h, --help   Show this message.
";

#[derive(RustcDecodable)]
struct Arguments {
  arg_input: Vec<String>,
  arg_output: Option<String>,
  arg_dir: Option<String>,
}

fn decode_file(input_file: &str, output_file: &str)
               -> Result<(), hound::Error> {
  let mut stream = try! {
    Stream::from_file(input_file).map_err(hound::Error::IoError)
  };
  let info       = stream.info();
  let frames_len = stream.frames.len();

  let spec = hound::WavSpec {
    channels: info.channels as u16,
    sample_rate: info.sample_rate,
    bits_per_sample: info.bits_per_sample as u16,
  };

  let mut output = try!(hound::WavWriter::create(output_file, spec));

  for _ in 0..frames_len {
    if let Some(buffer) = stream.next_frame() {
      let buffer_size = buffer.len();
      let block_size  = buffer_size / 2;
      let left        = &buffer[0..block_size];
      let right       = &buffer[block_size..buffer_size];

      for i in 0..block_size {
        try!(output.write_sample(left[i]));
        try!(output.write_sample(right[i]));
      }
    } else {
      break;
    }
  }

  output.finalize()
}

fn to_output_file(buffer: &mut PathBuf, path: &Path, directory: &str)
                  -> Result<(), hound::Error> {
  buffer.push(directory);

  path.file_name().map(|name| {
    buffer.push(name);
    buffer.set_extension("wav");
  }).ok_or_else(|| {
    let kind    = io::ErrorKind::NotFound;
    let message = "no file name found";
    let error   = io::Error::new(kind, message);

    hound::Error::IoError(error)
  })
}

fn decode_all_files(input_files: &Vec<String>, directory: &str)
                    -> Result<(), hound::Error> {
  let dir_path = Path::new(directory);

  if !dir_path.exists() {
    try!(fs::create_dir(dir_path).map_err(hound::Error::IoError))
  }

  for ref input_file in input_files {
    let mut buffer = PathBuf::new();
    let path       = Path::new(input_file);

    try!(to_output_file(&mut buffer, path, directory));

    let output_file = try! {
      buffer.to_str().ok_or_else(|| {
        let kind    = io::ErrorKind::InvalidInput;
        let message = "invalid unicode with file path";
        let error   = io::Error::new(kind, message);

        hound::Error::IoError(error)
      })
    };

    let result = decode_file(input_file, output_file);

    if result.is_ok() {
      println!("decoded: {} -> {}", input_file, output_file);
    } else {
      return result;
    }
  }

  Ok(())
}

fn main() {
  let args: Arguments = Docopt::new(USAGE)
    .and_then(|d| d.argv(env::args()).decode())
    .unwrap_or_else(|e| e.exit());

  if let Some(ref output_file) = args.arg_output {
    let input_file = &args.arg_input[0];

    if let Err(e) = decode_file(input_file, output_file) {
      println!("{:?}", e);
    } else {
      println!("decoded: {} -> {}", input_file, output_file);
    }
  }
}
<|endoftext|>


<commit_before>// Copyright 2013 The GLFW-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// 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.

extern crate glfw;

use glfw::{Action, Context, Key};

fn main() {
    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    glfw.window_hint(glfw::WindowHint::Resizable(true));

    let (mut window, events) = glfw.create_window(800, 600, "Hello, I am a window.", glfw::WindowMode::Windowed)
        .expect("Failed to create GLFW window.");

    window.set_sticky_keys(true);

    // Polling of events can be turned on and off by the specific event type
    window.set_pos_polling(true);
    window.set_all_polling(true);
    window.set_size_polling(true);
    window.set_close_polling(true);
    window.set_refresh_polling(true);
    window.set_focus_polling(true);
    window.set_iconify_polling(true);
    window.set_framebuffer_size_polling(true);
    window.set_key_polling(true);
    window.set_char_polling(true);
    window.set_mouse_button_polling(true);
    window.set_cursor_pos_polling(true);
    window.set_cursor_enter_polling(true);
    window.set_scroll_polling(true);

    // Alternatively, all event types may be set to poll at once. Note that
    // in this example, this call is redundant as all events have been set
    // to poll in the above code.
    window.set_all_polling(true);

    window.make_current();

    while !window.should_close() {
        glfw.poll_events();
        for event in glfw::flush_messages(&events) {
            handle_window_event(&mut window, event);
        }
    }
}

fn handle_window_event(window: &mut glfw::Window, (time, event): (f64, glfw::WindowEvent)) {
    match event {
        glfw::WindowEvent::Pos(x, y)                      => window.set_title(&format!("Time: {:?}, Window pos: ({:?}, {:?})", time, x, y)),
        glfw::WindowEvent::Size(w, h)                     => window.set_title(&format!("Time: {:?}, Window size: ({:?}, {:?})", time, w, h)),
        glfw::WindowEvent::Close                          => println!("Time: {:?}, Window close requested.", time),
        glfw::WindowEvent::Refresh                        => println!("Time: {:?}, Window refresh callback triggered.", time),
        glfw::WindowEvent::Focus(true)                    => println!("Time: {:?}, Window focus gained.", time),
        glfw::WindowEvent::Focus(false)                   => println!("Time: {:?}, Window focus lost.", time),
        glfw::WindowEvent::Iconify(true)                  => println!("Time: {:?}, Window was minimised", time),
        glfw::WindowEvent::Iconify(false)                 => println!("Time: {:?}, Window was maximised.", time),
        glfw::WindowEvent::FramebufferSize(w, h)          => println!("Time: {:?}, Framebuffer size: ({:?}, {:?})", time, w, h),
        glfw::WindowEvent::Char(character)                => println!("Time: {:?}, Character: {:?}", time, character),
        glfw::WindowEvent::MouseButton(btn, action, mods) => println!("Time: {:?}, Button: {:?}, Action: {:?}, Modifiers: [{:?}]", time, glfw::DebugAliases(btn), action, mods),
        glfw::WindowEvent::CursorPos(xpos, ypos)          => window.set_title(&format!("Time: {:?}, Cursor position: ({:?}, {:?})", time, xpos, ypos)),
        glfw::WindowEvent::CursorEnter(true)              => println!("Time: {:?}, Cursor entered window.", time),
        glfw::WindowEvent::CursorEnter(false)             => println!("Time: {:?}, Cursor left window.", time),
        glfw::WindowEvent::Scroll(x, y)                   => window.set_title(&format!("Time: {:?}, Scroll offset: ({:?}, {:?})", time, x, y)),
        glfw::WindowEvent::Key(key, scancode, action, mods) => {
            println!("Time: {:?}, Key: {:?}, ScanCode: {:?}, Action: {:?}, Modifiers: [{:?}]", time, key, scancode, action, mods);
            match (key, action) {
                (Key::Escape, Action::Press) => window.set_should_close(true),
                (Key::R, Action::Press) => {
                    // Resize should cause the window to "refresh"
                    let (window_width, window_height) = window.get_size();
                    window.set_size(window_width + 1, window_height);
                    window.set_size(window_width, window_height);
                }
                _ => {}
            }
        }
    }
}
<commit_msg>fix events example to check new FileDrop event<commit_after>// Copyright 2013 The GLFW-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// 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.

extern crate glfw;

use glfw::{Action, Context, Key};

fn main() {
    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    glfw.window_hint(glfw::WindowHint::Resizable(true));

    let (mut window, events) = glfw.create_window(800, 600, "Hello, I am a window.", glfw::WindowMode::Windowed)
        .expect("Failed to create GLFW window.");

    window.set_sticky_keys(true);

    // Polling of events can be turned on and off by the specific event type
    window.set_pos_polling(true);
    window.set_all_polling(true);
    window.set_size_polling(true);
    window.set_close_polling(true);
    window.set_refresh_polling(true);
    window.set_focus_polling(true);
    window.set_iconify_polling(true);
    window.set_framebuffer_size_polling(true);
    window.set_key_polling(true);
    window.set_char_polling(true);
    window.set_mouse_button_polling(true);
    window.set_cursor_pos_polling(true);
    window.set_cursor_enter_polling(true);
    window.set_scroll_polling(true);

    // Alternatively, all event types may be set to poll at once. Note that
    // in this example, this call is redundant as all events have been set
    // to poll in the above code.
    window.set_all_polling(true);

    window.make_current();

    while !window.should_close() {
        glfw.poll_events();
        for event in glfw::flush_messages(&events) {
            handle_window_event(&mut window, event);
        }
    }
}

fn handle_window_event(window: &mut glfw::Window, (time, event): (f64, glfw::WindowEvent)) {
    match event {
        glfw::WindowEvent::Pos(x, y)                      => window.set_title(&format!("Time: {:?}, Window pos: ({:?}, {:?})", time, x, y)),
        glfw::WindowEvent::Size(w, h)                     => window.set_title(&format!("Time: {:?}, Window size: ({:?}, {:?})", time, w, h)),
        glfw::WindowEvent::Close                          => println!("Time: {:?}, Window close requested.", time),
        glfw::WindowEvent::Refresh                        => println!("Time: {:?}, Window refresh callback triggered.", time),
        glfw::WindowEvent::Focus(true)                    => println!("Time: {:?}, Window focus gained.", time),
        glfw::WindowEvent::Focus(false)                   => println!("Time: {:?}, Window focus lost.", time),
        glfw::WindowEvent::Iconify(true)                  => println!("Time: {:?}, Window was minimised", time),
        glfw::WindowEvent::Iconify(false)                 => println!("Time: {:?}, Window was maximised.", time),
        glfw::WindowEvent::FramebufferSize(w, h)          => println!("Time: {:?}, Framebuffer size: ({:?}, {:?})", time, w, h),
        glfw::WindowEvent::Char(character)                => println!("Time: {:?}, Character: {:?}", time, character),
        glfw::WindowEvent::MouseButton(btn, action, mods) => println!("Time: {:?}, Button: {:?}, Action: {:?}, Modifiers: [{:?}]", time, glfw::DebugAliases(btn), action, mods),
        glfw::WindowEvent::CursorPos(xpos, ypos)          => window.set_title(&format!("Time: {:?}, Cursor position: ({:?}, {:?})", time, xpos, ypos)),
        glfw::WindowEvent::CursorEnter(true)              => println!("Time: {:?}, Cursor entered window.", time),
        glfw::WindowEvent::CursorEnter(false)             => println!("Time: {:?}, Cursor left window.", time),
        glfw::WindowEvent::Scroll(x, y)                   => window.set_title(&format!("Time: {:?}, Scroll offset: ({:?}, {:?})", time, x, y)),
        glfw::WindowEvent::Key(key, scancode, action, mods) => {
            println!("Time: {:?}, Key: {:?}, ScanCode: {:?}, Action: {:?}, Modifiers: [{:?}]", time, key, scancode, action, mods);
            match (key, action) {
                (Key::Escape, Action::Press) => window.set_should_close(true),
                (Key::R, Action::Press) => {
                    // Resize should cause the window to "refresh"
                    let (window_width, window_height) = window.get_size();
                    window.set_size(window_width + 1, window_height);
                    window.set_size(window_width, window_height);
                }
                _ => {}
            }
        }
        glfw::WindowEvent::FileDrop(paths)                => println!("Time: {:?}, Files dropped: {:?}", time, paths),
    }
}
<|endoftext|>


<commit_before>use std::cmp;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};

/// A simple implementation of a [HyperLogLog](https://en.wikipedia.org/wiki/HyperLogLog)
pub struct HyperLogLog {
    registers: Vec<u64>,
    b: usize,
}

impl HyperLogLog {
    /// Creates a new, empty HyperLogLog.
    ///
    /// - `b` number of bits used for register selection, number of registers within the
    ///   HyperLogLog will be `2^b`. `b` must be in `[4, 16]`
    ///
    /// Panics when `b` is out of bounds.
    pub fn new(b: usize) -> HyperLogLog {
        assert!(b >= 4);
        assert!(b <= 16);

        let m = (1 as usize) << b;
        let registers = vec![0; m];
        HyperLogLog {
            registers: registers,
            b: b,
        }
    }

    /// Adds an element to the HyperLogLog.
    pub fn add<T>(&mut self, obj: &T)
    where
        T: Hash,
    {
        let mut hasher = DefaultHasher::new();
        obj.hash(&mut hasher);
        let h: u64 = hasher.finish();

        let w = h >> self.b;
        let j = h - (w << self.b);
        let p = w.leading_zeros() + 1 - (self.b as u32);

        let m_old = self.registers[j as usize];
        self.registers[j as usize] = cmp::max(m_old, p as u64);
    }

    /// Guess the number of unique elements seen by the HyperLogLog.
    pub fn count(&self) -> usize {
        let m = self.registers.len() as f64;

        let z = 1f64 /
            self.registers
                .iter()
                .map(|&x| 2f64.powi(-(x as i32)))
                .sum::<f64>();

        let am = if m >= 128. {
            0.7213 / (1. + 1.079 / m)
        } else if m >= 64. {
            0.709
        } else if m >= 32. {
            0.697
        } else {
            0.673
        };

        let e = am * m * m * z;

        let e_star = if e <= 5. / 2. * m {
            // small range correction
            let v = self.registers.iter().filter(|&&x| x == 0).count();
            if v != 0 {
                m * (m / (v as f64)).ln()
            } else {
                e
            }
        } else if e <= 1. / 30. * 2f64.powi(32) {
            // intermediate range => no correction
            e
        } else {
            // large range correction
            -2f64.powi(32) * (1. - e / 2f64.powi(32)).ln()
        };

        e_star as usize
    }

    /// Empties the HyperLogLog.
    pub fn clear(&mut self) {
        self.registers = vec![0; self.registers.len()];
    }

    /// Checks whether the HyperLogLog has never seen an element.
    pub fn is_empty(&self) -> bool {
        self.registers.iter().all(|&x| x == 0)
    }
}

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

    #[test]
    fn empty() {
        let hll = HyperLogLog::new(8);
        assert_eq!(hll.count(), 0);
        assert!(hll.is_empty());
    }

    #[test]
    fn add_b4_n1k() {
        let mut hll = HyperLogLog::new(4);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 571);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b8_n1k() {
        let mut hll = HyperLogLog::new(8);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 966);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b12_n1k() {
        let mut hll = HyperLogLog::new(12);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 984);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b16_n1k() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 998);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b8_n10k() {
        let mut hll = HyperLogLog::new(8);
        for i in 0..10000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 10196);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b12_n10k() {
        let mut hll = HyperLogLog::new(12);
        for i in 0..10000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 10303);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b16_n10k() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..10000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 10055);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b16_n100k() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..100000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 100551);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b16_n1m() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..1000000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 1000226);
        assert!(!hll.is_empty());
    }

    #[test]
    fn clear() {
        let mut hll = HyperLogLog::new(8);
        for i in 0..1000 {
            hll.add(&i);
        }
        hll.clear();
        assert_eq!(hll.count(), 0);
        assert!(hll.is_empty());
    }
}
<commit_msg>hyperloglog: use sufficient register size<commit_after>use std::cmp;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};

/// A simple implementation of a [HyperLogLog](https://en.wikipedia.org/wiki/HyperLogLog)
pub struct HyperLogLog {
    registers: Vec<u8>,
    b: usize,
}

impl HyperLogLog {
    /// Creates a new, empty HyperLogLog.
    ///
    /// - `b` number of bits used for register selection, number of registers within the
    ///   HyperLogLog will be `2^b`. `b` must be in `[4, 16]`
    ///
    /// Panics when `b` is out of bounds.
    pub fn new(b: usize) -> HyperLogLog {
        assert!(b >= 4);
        assert!(b <= 16);

        let m = (1 as usize) << b;
        let registers = vec![0; m];
        HyperLogLog {
            registers: registers,
            b: b,
        }
    }

    /// Adds an element to the HyperLogLog.
    pub fn add<T>(&mut self, obj: &T)
    where
        T: Hash,
    {
        let mut hasher = DefaultHasher::new();
        obj.hash(&mut hasher);
        let h: u64 = hasher.finish();

        let w = h >> self.b;
        let j = h - (w << self.b);
        let p = w.leading_zeros() + 1 - (self.b as u32);

        let m_old = self.registers[j as usize];
        self.registers[j as usize] = cmp::max(m_old, p as u8);
    }

    /// Guess the number of unique elements seen by the HyperLogLog.
    pub fn count(&self) -> usize {
        let m = self.registers.len() as f64;

        let z = 1f64 /
            self.registers
                .iter()
                .map(|&x| 2f64.powi(-(x as i32)))
                .sum::<f64>();

        let am = if m >= 128. {
            0.7213 / (1. + 1.079 / m)
        } else if m >= 64. {
            0.709
        } else if m >= 32. {
            0.697
        } else {
            0.673
        };

        let e = am * m * m * z;

        let e_star = if e <= 5. / 2. * m {
            // small range correction
            let v = self.registers.iter().filter(|&&x| x == 0).count();
            if v != 0 {
                m * (m / (v as f64)).ln()
            } else {
                e
            }
        } else if e <= 1. / 30. * 2f64.powi(32) {
            // intermediate range => no correction
            e
        } else {
            // large range correction
            -2f64.powi(32) * (1. - e / 2f64.powi(32)).ln()
        };

        e_star as usize
    }

    /// Empties the HyperLogLog.
    pub fn clear(&mut self) {
        self.registers = vec![0; self.registers.len()];
    }

    /// Checks whether the HyperLogLog has never seen an element.
    pub fn is_empty(&self) -> bool {
        self.registers.iter().all(|&x| x == 0)
    }
}

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

    #[test]
    fn empty() {
        let hll = HyperLogLog::new(8);
        assert_eq!(hll.count(), 0);
        assert!(hll.is_empty());
    }

    #[test]
    fn add_b4_n1k() {
        let mut hll = HyperLogLog::new(4);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 571);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b8_n1k() {
        let mut hll = HyperLogLog::new(8);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 966);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b12_n1k() {
        let mut hll = HyperLogLog::new(12);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 984);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b16_n1k() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..1000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 998);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b8_n10k() {
        let mut hll = HyperLogLog::new(8);
        for i in 0..10000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 10196);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b12_n10k() {
        let mut hll = HyperLogLog::new(12);
        for i in 0..10000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 10303);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b16_n10k() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..10000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 10055);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b16_n100k() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..100000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 100551);
        assert!(!hll.is_empty());
    }

    #[test]
    fn add_b16_n1m() {
        let mut hll = HyperLogLog::new(16);
        for i in 0..1000000 {
            hll.add(&i);
        }
        assert_eq!(hll.count(), 1000226);
        assert!(!hll.is_empty());
    }

    #[test]
    fn clear() {
        let mut hll = HyperLogLog::new(8);
        for i in 0..1000 {
            hll.add(&i);
        }
        hll.clear();
        assert_eq!(hll.count(), 0);
        assert!(hll.is_empty());
    }
}
<|endoftext|>