<commit_before>use crate::utils;
use dirs;
use std::fs;
use std::io::ErrorKind;
use std::process::Command;

pub fn setup() {
    // Environment (Unix)

    utils::install_package("ripgrep");

    // Version control (Git)

    utils::install_package("git");

    let home_path = match dirs::home_dir() {
        Some(directory) => directory,
        None => panic!("Cannot find the home directory."),
    };

    // Editor (Vim)

    utils::install_package("vim");

    let editor_plugins_path = home_path
        .join(".vim")
        .join("pack")
        .join("plugins")
        .join("start");

    utils::create_dir(&editor_plugins_path);

    let editor_configuration_path = home_path.join(".vimrc");

    utils::create_file(&editor_configuration_path);

    match fs::read_dir(&editor_plugins_path) {
        Ok(_) => println!("The editor plugins are already installed."),
        Err(_) => {
            utils::clone_repo(&editor_plugins_path, "https://github.com/tpope/vim-sensible");
            utils::clone_repo(&editor_plugins_path, "https://github.com/tpope/vim-sleuth");
            utils::clone_repo(&editor_plugins_path, "https://github.com/sheerun/vim-polyglot");
            utils::clone_repo(&editor_plugins_path, "https://github.com/octref/RootIgnore");
            utils::clone_repo(&editor_plugins_path, "https://github.com/dense-analysis/ale");
            utils::clone_repo(&editor_plugins_path, "https://github.com/arcticicestudio/nord-vim");

            println!("Adding editor configuration.");
            match fs::write(&editor_configuration_path, "set grepprg=rg\\ --vimgrep\nset grepformat=%f:%l:%c:%m\ncolorscheme nord") {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }
        }
    };

    // Application programming (JavaScript)

    utils::install_package("node");

    // Systems programming (Rust)

    utils::install_package("rustup-init");

    let rustup_path_check = match Command::new("which").arg("rustup").output() {
        Ok(output) => output.stdout,
        Err(error) => panic!("There was a problem: {:?}", error),
    };

    if rustup_path_check.is_empty() {
        match Command::new("rustup-init").output() {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The rustup-init command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }
    } else {
        println!("The rustup-init has already been run.")
    }
}

pub fn upgrade() {
    // Environment (Unix)

    println!("Upgrading package manager.");

    match Command::new("brew").arg("update").output() {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    utils::upgrade_package("ripgrep");

    // Version control (Git)

    utils::upgrade_package("git");

    // Editor (Vim)

    utils::upgrade_package("vim");

    println!("Upgrading editor plugins.");

    let home_path = match dirs::home_dir() {
        Some(directory) => directory,
        None => panic!("Cannot find the home directory."),
    };

    let editor_plugins_path = home_path
        .join(".vim")
        .join("pack")
        .join("plugins")
        .join("start");

    match fs::read_dir(&editor_plugins_path) {
        Ok(paths) => {
            for path in paths {
                match Command::new("git")
                    .current_dir(match path {
                        Ok(path) => path.path(),
                        Err(error) => panic!("There was a problem: {:?}", error),
                    })
                    .arg("pull")
                    .output()
                {
                    Ok(_) => (),
                    Err(error) => panic!("There was a problem: {:?}", error),
                }
            }
        }
        Err(error) => panic!("There was a problem: {:?}", error),
    };

    // Application programming (JavaScript)

    utils::upgrade_package("node");

    // Systems programming (Rust)

    utils::upgrade_package("rustup-init");

    println!("Upgrading systems programming toolchain.");

    match Command::new("rustup").arg("update").output() {
        Ok(_) => (),
        Err(error) => match error.kind() {
            ErrorKind::NotFound => panic!("The rustup command is missing."),
            other_error => panic!("There was a problem: {:?}", other_error),
        },
    }
}

pub fn end() {
    // Environment (Unix)

    println!("Removing package manager artifacts.");

    match Command::new("brew").arg("cleanup").output() {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    // Version control (Git)

    println!("Making sure all repos are clean.");

    let home_path = match dirs::home_dir() {
        Some(directory) => directory,
        None => panic!("Cannot find the home directory."),
    };

    let repos_path = home_path.join("repos");

    match fs::read_dir(&repos_path) {
        Ok(paths) => {
            let mut all_repos_clean = true;

            for path in paths {
                let path = match &path {
                    Ok(path) => path.path(),
                    Err(error) => panic!("There was a problem: {:?}", error),
                };

                let status_check = match Command::new("git")
                    .current_dir(&path)
                    .arg("status")
                    .arg("--porcelain")
                    .output()
                {
                    Ok(output) => output.stdout,
                    Err(error) => panic!("There was a problem: {:?}", error),
                };

                let unpushed_check = match Command::new("git")
                    .current_dir(&path)
                    .arg("log")
                    .arg("@{u}..")
                    .output()
                {
                    Ok(output) => output.stdout,
                    Err(error) => panic!("There was a problem: {:?}", error),
                };

                if !status_check.is_empty() || !unpushed_check.is_empty() {
                    all_repos_clean = false;
                    eprintln!("A dirty repo was found: {}", &path.display());
                }
            }

            if !all_repos_clean {
                panic!("Repos are dirty.");
            }
        }
        Err(error) => panic!("There was a problem: {:?}", error),
    };

    // Editor (Vim)

    println!("Quitting editor processes.");

    match Command::new("killall").arg("vim").output() {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    // Application programming (JavaScript)

    println!("Quitting application programming processes.");

    match Command::new("killall").arg("node").output() {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    // Systems programming (Rust)

    println!("Quitting systems programming processes.");

    match Command::new("killall").arg("rls").output() {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}
<commit_msg>Use defaults for terminal and vim colors<commit_after>use crate::utils;
use dirs;
use std::fs;
use std::io::ErrorKind;
use std::process::Command;

pub fn setup() {
    // Environment (Unix)

    utils::install_package("ripgrep");

    // Version control (Git)

    utils::install_package("git");

    let home_path = match dirs::home_dir() {
        Some(directory) => directory,
        None => panic!("Cannot find the home directory."),
    };

    // Editor (Vim)

    utils::install_package("vim");

    let editor_plugins_path = home_path
        .join(".vim")
        .join("pack")
        .join("plugins")
        .join("start");

    utils::create_dir(&editor_plugins_path);

    let editor_configuration_path = home_path.join(".vimrc");

    utils::create_file(&editor_configuration_path);

    match fs::read_dir(&editor_plugins_path) {
        Ok(_) => println!("The editor plugins are already installed."),
        Err(_) => {
            utils::clone_repo(&editor_plugins_path, "https://github.com/tpope/vim-sensible");
            utils::clone_repo(&editor_plugins_path, "https://github.com/tpope/vim-sleuth");
            utils::clone_repo(&editor_plugins_path, "https://github.com/sheerun/vim-polyglot");
            utils::clone_repo(&editor_plugins_path, "https://github.com/octref/RootIgnore");
            utils::clone_repo(&editor_plugins_path, "https://github.com/dense-analysis/ale");

            println!("Adding editor configuration.");
            match fs::write(&editor_configuration_path, "set grepprg=rg\\ --vimgrep\nset grepformat=%f:%l:%c:%m") {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }
        }
    };

    // Application programming (JavaScript)

    utils::install_package("node");

    // Systems programming (Rust)

    utils::install_package("rustup-init");

    let rustup_path_check = match Command::new("which").arg("rustup").output() {
        Ok(output) => output.stdout,
        Err(error) => panic!("There was a problem: {:?}", error),
    };

    if rustup_path_check.is_empty() {
        match Command::new("rustup-init").output() {
            Ok(_) => (),
            Err(error) => match error.kind() {
                ErrorKind::NotFound => panic!("The rustup-init command is missing."),
                other_error => panic!("There was a problem: {:?}", other_error),
            },
        }
    } else {
        println!("The rustup-init has already been run.")
    }
}

pub fn upgrade() {
    // Environment (Unix)

    println!("Upgrading package manager.");

    match Command::new("brew").arg("update").output() {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    utils::upgrade_package("ripgrep");

    // Version control (Git)

    utils::upgrade_package("git");

    // Editor (Vim)

    utils::upgrade_package("vim");

    println!("Upgrading editor plugins.");

    let home_path = match dirs::home_dir() {
        Some(directory) => directory,
        None => panic!("Cannot find the home directory."),
    };

    let editor_plugins_path = home_path
        .join(".vim")
        .join("pack")
        .join("plugins")
        .join("start");

    match fs::read_dir(&editor_plugins_path) {
        Ok(paths) => {
            for path in paths {
                match Command::new("git")
                    .current_dir(match path {
                        Ok(path) => path.path(),
                        Err(error) => panic!("There was a problem: {:?}", error),
                    })
                    .arg("pull")
                    .output()
                {
                    Ok(_) => (),
                    Err(error) => panic!("There was a problem: {:?}", error),
                }
            }
        }
        Err(error) => panic!("There was a problem: {:?}", error),
    };

    // Application programming (JavaScript)

    utils::upgrade_package("node");

    // Systems programming (Rust)

    utils::upgrade_package("rustup-init");

    println!("Upgrading systems programming toolchain.");

    match Command::new("rustup").arg("update").output() {
        Ok(_) => (),
        Err(error) => match error.kind() {
            ErrorKind::NotFound => panic!("The rustup command is missing."),
            other_error => panic!("There was a problem: {:?}", other_error),
        },
    }
}

pub fn end() {
    // Environment (Unix)

    println!("Removing package manager artifacts.");

    match Command::new("brew").arg("cleanup").output() {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    // Version control (Git)

    println!("Making sure all repos are clean.");

    let home_path = match dirs::home_dir() {
        Some(directory) => directory,
        None => panic!("Cannot find the home directory."),
    };

    let repos_path = home_path.join("repos");

    match fs::read_dir(&repos_path) {
        Ok(paths) => {
            let mut all_repos_clean = true;

            for path in paths {
                let path = match &path {
                    Ok(path) => path.path(),
                    Err(error) => panic!("There was a problem: {:?}", error),
                };

                let status_check = match Command::new("git")
                    .current_dir(&path)
                    .arg("status")
                    .arg("--porcelain")
                    .output()
                {
                    Ok(output) => output.stdout,
                    Err(error) => panic!("There was a problem: {:?}", error),
                };

                let unpushed_check = match Command::new("git")
                    .current_dir(&path)
                    .arg("log")
                    .arg("@{u}..")
                    .output()
                {
                    Ok(output) => output.stdout,
                    Err(error) => panic!("There was a problem: {:?}", error),
                };

                if !status_check.is_empty() || !unpushed_check.is_empty() {
                    all_repos_clean = false;
                    eprintln!("A dirty repo was found: {}", &path.display());
                }
            }

            if !all_repos_clean {
                panic!("Repos are dirty.");
            }
        }
        Err(error) => panic!("There was a problem: {:?}", error),
    };

    // Editor (Vim)

    println!("Quitting editor processes.");

    match Command::new("killall").arg("vim").output() {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    // Application programming (JavaScript)

    println!("Quitting application programming processes.");

    match Command::new("killall").arg("node").output() {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    // Systems programming (Rust)

    println!("Quitting systems programming processes.");

    match Command::new("killall").arg("rls").output() {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}
<|endoftext|>


<commit_before>/*

Idea: provide functions for 'exhaustive' and 'random' modification of vecs.

  two functions, "return all edits" and "return a random edit" <-- leaning toward this model
    or
  two functions, "return the number of possible edits" and "return edit #n"

It would be nice if this could be data-driven, so the two functions could share information:
  type vec_modifier = rec(fn (&<T> v, uint i) -> [T] fun, uint lo, uint di);
  const [vec_modifier] vec_modifiers = ~[rec(fun=vec_omit, 0u, 1u), ...];
But that gives me "error: internal compiler error unimplemented consts that's not a plain literal".
https://github.com/graydon/rust/issues/570

vec_edits is not an iter because iters might go away and:
https://github.com/graydon/rust/issues/639

vec_omit and friends are not type-parameterized because:
https://github.com/graydon/rust/issues/640

*/

use std;
import std::vec;
import std::vec::slice;
import std::vec::len;
import std::int;

//fn vec_reverse(&<T> v) -> [T] { ... }

fn vec_omit<T>(v: &[T], i: uint) -> [T] {
    slice(v, 0u, i) + slice(v, i + 1u, len(v))
}
fn vec_dup<T>(v: &[T], i: uint) -> [T] {
    slice(v, 0u, i) + [v[i]] + slice(v, i, len(v))
}
fn vec_swadj<T>(v: &[T], i: uint) -> [T] {
    slice(v, 0u, i) + [v[i + 1u], v[i]] + slice(v, i + 2u, len(v))
}
fn vec_prefix<T>(v: &[T], i: uint) -> [T] { slice(v, 0u, i) }
fn vec_suffix<T>(v: &[T], i: uint) -> [T] { slice(v, i, len(v)) }

fn vec_poke<T>(v: &[T], i: uint, x: &T) -> [T] {
    slice(v, 0u, i) + [x] + slice(v, i + 1u, len(v))
}
fn vec_insert<T>(v: &[T], i: uint, x: &T) -> [T] {
    slice(v, 0u, i) + [x] + slice(v, i, len(v))
}

// Iterates over 0...length, skipping the specified number on each side.
iter ix(skip_low: uint, skip_high: uint, length: uint) -> uint {
    let i: uint = skip_low;
    while i + skip_high <= length { put i; i += 1u; }
}

// Returns a bunch of modified versions of v, some of which introduce new elements (borrowed from xs).
fn vec_edits<T>(v: &[T], xs: &[T]) -> [[T]] {
    let edits: [[T]] = [];
    let Lv: uint = len(v);

    if Lv != 1u {
        edits +=
            [[]]; // When Lv == 1u, this is redundant with omit
                  //if (Lv >= 3u) { edits += ~[vec_reverse(v)]; }

    }
    for each i: uint in ix(0u, 1u, Lv) { edits += [vec_omit(v, i)]; }
    for each i: uint in ix(0u, 1u, Lv) { edits += [vec_dup(v, i)]; }
    for each i: uint in ix(0u, 2u, Lv) { edits += [vec_swadj(v, i)]; }
    for each i: uint in ix(1u, 2u, Lv) { edits += [vec_prefix(v, i)]; }
    for each i: uint in ix(2u, 1u, Lv) { edits += [vec_suffix(v, i)]; }

    for each j: uint in ix(0u, 1u, len(xs)) {
        for each i: uint in ix(0u, 1u, Lv) {
            edits += [vec_poke(v, i, xs[j])];
        }
        for each i: uint in ix(0u, 0u, Lv) {
            edits += [vec_insert(v, i, xs[j])];
        }
    }

    edits
}

// Would be nice if this were built in: https://github.com/graydon/rust/issues/424
fn vec_to_str(v: &[int]) -> str {
    let i = 0u;
    let s = "[";
    while i < len(v) {
        s += int::str(v[i]);
        if i + 1u < len(v) { s += ", " }
        i += 1u;
    }
    ret s + "]";
}

fn show_edits(a: &[int], xs: &[int]) {
    log_err "=== Edits of " + vec_to_str(a) + " ===";
    let b = vec_edits(a, xs);
    for each i: uint in ix(0u, 1u, len(b)) { log_err vec_to_str(b[i]); }
}

fn demo_edits() {
    let xs = [7, 8];
    show_edits([], xs);
    show_edits([1], xs);
    show_edits([1, 2], xs);
    show_edits([1, 2, 3], xs);
    show_edits([1, 2, 3, 4], xs);
}

fn main() { demo_edits(); }
<commit_msg>ivec_fuzz: require shared types, because that's what vec::slide requires<commit_after>/*

Idea: provide functions for 'exhaustive' and 'random' modification of vecs.

  two functions, "return all edits" and "return a random edit" <-- leaning toward this model
    or
  two functions, "return the number of possible edits" and "return edit #n"

It would be nice if this could be data-driven, so the two functions could share information:
  type vec_modifier = rec(fn (&<T> v, uint i) -> [T] fun, uint lo, uint di);
  const [vec_modifier] vec_modifiers = ~[rec(fun=vec_omit, 0u, 1u), ...];
But that gives me "error: internal compiler error unimplemented consts that's not a plain literal".
https://github.com/graydon/rust/issues/570

vec_edits is not an iter because iters might go away and:
https://github.com/graydon/rust/issues/639

vec_omit and friends are not type-parameterized because:
https://github.com/graydon/rust/issues/640

*/

use std;
import std::vec;
import std::vec::slice;
import std::vec::len;
import std::int;

//fn vec_reverse(&<T> v) -> [T] { ... }

fn vec_omit<@T>(v: &[T], i: uint) -> [T] {
    slice(v, 0u, i) + slice(v, i + 1u, len(v))
}
fn vec_dup<@T>(v: &[T], i: uint) -> [T] {
    slice(v, 0u, i) + [v[i]] + slice(v, i, len(v))
}
fn vec_swadj<@T>(v: &[T], i: uint) -> [T] {
    slice(v, 0u, i) + [v[i + 1u], v[i]] + slice(v, i + 2u, len(v))
}
fn vec_prefix<@T>(v: &[T], i: uint) -> [T] { slice(v, 0u, i) }
fn vec_suffix<@T>(v: &[T], i: uint) -> [T] { slice(v, i, len(v)) }

fn vec_poke<@T>(v: &[T], i: uint, x: &T) -> [T] {
    slice(v, 0u, i) + [x] + slice(v, i + 1u, len(v))
}
fn vec_insert<@T>(v: &[T], i: uint, x: &T) -> [T] {
    slice(v, 0u, i) + [x] + slice(v, i, len(v))
}

// Iterates over 0...length, skipping the specified number on each side.
iter ix(skip_low: uint, skip_high: uint, length: uint) -> uint {
    let i: uint = skip_low;
    while i + skip_high <= length { put i; i += 1u; }
}

// Returns a bunch of modified versions of v, some of which introduce new elements (borrowed from xs).
fn vec_edits<@T>(v: &[T], xs: &[T]) -> [[T]] {
    let edits: [[T]] = [];
    let Lv: uint = len(v);

    if Lv != 1u {
        edits +=
            [[]]; // When Lv == 1u, this is redundant with omit
                  //if (Lv >= 3u) { edits += ~[vec_reverse(v)]; }

    }
    for each i: uint in ix(0u, 1u, Lv) { edits += [vec_omit(v, i)]; }
    for each i: uint in ix(0u, 1u, Lv) { edits += [vec_dup(v, i)]; }
    for each i: uint in ix(0u, 2u, Lv) { edits += [vec_swadj(v, i)]; }
    for each i: uint in ix(1u, 2u, Lv) { edits += [vec_prefix(v, i)]; }
    for each i: uint in ix(2u, 1u, Lv) { edits += [vec_suffix(v, i)]; }

    for each j: uint in ix(0u, 1u, len(xs)) {
        for each i: uint in ix(0u, 1u, Lv) {
            edits += [vec_poke(v, i, xs[j])];
        }
        for each i: uint in ix(0u, 0u, Lv) {
            edits += [vec_insert(v, i, xs[j])];
        }
    }

    edits
}

// Would be nice if this were built in: https://github.com/graydon/rust/issues/424
fn vec_to_str(v: &[int]) -> str {
    let i = 0u;
    let s = "[";
    while i < len(v) {
        s += int::str(v[i]);
        if i + 1u < len(v) { s += ", " }
        i += 1u;
    }
    ret s + "]";
}

fn show_edits(a: &[int], xs: &[int]) {
    log_err "=== Edits of " + vec_to_str(a) + " ===";
    let b = vec_edits(a, xs);
    for each i: uint in ix(0u, 1u, len(b)) { log_err vec_to_str(b[i]); }
}

fn demo_edits() {
    let xs = [7, 8];
    show_edits([], xs);
    show_edits([1], xs);
    show_edits([1, 2], xs);
    show_edits([1, 2, 3], xs);
    show_edits([1, 2, 3, 4], xs);
}

fn main() { demo_edits(); }
<|endoftext|>


<commit_before>use std::sync::atomic::{AtomicUsize, Ordering};
use arena::{TypedArena};

use ast;
use resolve;
use resolve::Scope;
use resolve::block::EventClosure;
use exec::Step;
use ast::Value;
use resolve::scope::Item;
use resolve::types::Shape;
use grammar;
use eval::Expr;

use std::str;
use std::io::{self, Cursor};
use std::thread;
use exec;
use dumpfile;
use eval;

pub type ValueID = usize;

/// The data common to an entire resolve pass
pub struct Session<'session> {
    pub closure_arena: TypedArena<EventClosure<'session>>,
    module_ast_arena: TypedArena<ast::Module>,
    id_counter: AtomicUsize,
    pub prelude: Scope<'session>,
}

impl<'session> Session<'session> {
    pub fn new() -> Session<'session> {
        Session {
            closure_arena: TypedArena::new(),
            module_ast_arena: TypedArena::new(),
            id_counter: AtomicUsize::new(1),
            prelude: Scope::new(),
        }
    }

    pub fn make_id(&self) -> usize {
        self.id_counter.fetch_add(1, Ordering::Relaxed)
    }

    pub fn parse_module(&'session self, source: &str) -> Result<Module<'session>, grammar::ParseError> {
        grammar::module(source).map(|ast|
            self.resolve_module(self.module_ast_arena.alloc(ast))
        )
    }

    pub fn resolve_module(&'session self, modast: &'session ast::Module) -> Module<'session> {
        Module {
            session: self,
            scope: resolve::block::resolve_module(self, modast),
        }
    }

    pub fn var(&self, _ty: resolve::types::Type, is_down: bool, is_up: bool) -> Var {
        Var {
            id: self.make_id(),
            is_down: is_down,
            is_up: is_up,
        }
    }
}

pub trait IntoItem<'s>: Clone {
    fn into_item(self) -> Item<'s>;
}

impl <'s> IntoItem<'s> for Item<'s> {
    fn into_item(self) -> Item<'s> { self }
}

impl <'s> IntoItem<'s> for Value {
    fn into_item(self) -> Item<'s> { Item::Value(Expr::Const(self)) }
}

impl <'s> IntoItem<'s> for Expr {
    fn into_item(self) -> Item<'s> { Item::Value(self) }
}

#[derive(Copy, Clone, Debug)]
pub struct Var {
    pub id: ValueID,
    pub is_down: bool,
    pub is_up: bool,
}

impl <'s> IntoItem<'s> for Var {
    fn into_item(self) -> Item<'s> {
        let var = Expr::Variable(self.id);
        Item::Value(match (self.is_down, self.is_up) {
            (true, true) => var,
            (false, true) => Expr::Flip(box Expr::Ignored, box var),
            (true, false) => Expr::Flip(box var, box Expr::Ignored),
            (false, false) => Expr::Ignored
        })
    }
}

#[macro_escape]
macro_rules! tuple_item[
    ($($x:expr),*) => ({
        use session::IntoItem;
        use resolve::scope::Item::Tuple;
        Tuple(vec![$($x.into_item()),*])
    });
    ($($x:expr,)*) => (tuple_item![$($x),*])
];

impl <'s> IntoItem<'s> for () {
    fn into_item(self) -> Item<'s> { Item::Tuple(Vec::new()) }
}

pub struct Module<'s> {
    session: &'s Session<'s>,
    scope: Scope<'s>,
}

impl <'s> Module<'s> {
    pub fn get_def<'a>(&'a self, name: &str) -> &'a EventClosure<'s> {
        // TODO: return Result
        match self.scope.get(name).unwrap() {
            resolve::scope::Item::Def(s) => s,
            _ => panic!("Main is not an event"),
        }
    }

    pub fn compile_call<T: IntoItem<'s>>(&self, name: &str,
                        shape_down: Shape,
                        param: T) -> Result<Program, ()> {
        let def = self.get_def(name);

        let (shape_up, step) = def.resolve_call(&self.session, &shape_down, param.into_item());

        Ok(Program{ step: step, shape_down: shape_down, shape_up: shape_up})
    }
}

pub struct Program {
    pub step: Step,
    pub shape_down: Shape,
    pub shape_up: Shape,
}

impl Program {
    pub fn run_test(&self, bottom: &'static str, top: &'static str) -> (bool, eval::State) {
        let (mut s1, mut s2) = exec::Connection::new();
        let (mut t1, mut t2) = exec::Connection::new();
        let reader_thread = thread::scoped(move || {
            let mut reader = Cursor::new(bottom.as_bytes().to_vec());
            dumpfile::read_values(&mut reader, &mut s2);
        });
        let writer_thread = thread::scoped(move || {
            let mut writer = Vec::new();
            dumpfile::write_values(&mut writer, &mut t1);
            assert_eq!(top, str::from_utf8(&writer).unwrap());
        });
        let mut state = eval::State::new();

        let r = exec::exec(&mut state, &self.step, &mut s1, &mut t2);

        drop(s1);
        drop(t2);
        reader_thread.join();
        writer_thread.join();

        (r, state)
    }

    pub fn run_test_pass(&self, bottom: &'static str, top: &'static str) -> eval::State {
        let (m, r) = self.run_test(bottom, top);
        if !m {
            panic!("run_pass test failed to match: {}", bottom);
        }
        r
    }

    pub fn run_test_fail(&self, bottom: &'static str, top: &'static str) -> eval::State {
        let (m, r) = self.run_test(bottom, top);
        if m {
            panic!("run_fail test matched: {}", bottom);
        }
        r
    }
}

pub trait Process {
    fn run(&self, state: &mut eval::State, downwards: &mut exec::Connection, upwards: &mut exec::Connection) -> bool;
}

impl Process for Program {
    fn run(&self, state: &mut eval::State, downwards: &mut exec::Connection, upwards: &mut exec::Connection) -> bool {
        exec::exec(state, &self.step, downwards, upwards)
    }
}

pub trait IoProcess {
    fn run(&mut self, upwards: &mut exec::Connection) -> io::Result<()>;
}
<commit_msg>Add Process::shape_up getter<commit_after>use std::sync::atomic::{AtomicUsize, Ordering};
use arena::{TypedArena};

use ast;
use resolve;
use resolve::Scope;
use resolve::block::EventClosure;
use exec::Step;
use ast::Value;
use resolve::scope::Item;
use resolve::types::Shape;
use grammar;
use eval::Expr;

use std::str;
use std::io::{self, Cursor};
use std::thread;
use exec;
use dumpfile;
use eval;

pub type ValueID = usize;

/// The data common to an entire resolve pass
pub struct Session<'session> {
    pub closure_arena: TypedArena<EventClosure<'session>>,
    module_ast_arena: TypedArena<ast::Module>,
    id_counter: AtomicUsize,
    pub prelude: Scope<'session>,
}

impl<'session> Session<'session> {
    pub fn new() -> Session<'session> {
        Session {
            closure_arena: TypedArena::new(),
            module_ast_arena: TypedArena::new(),
            id_counter: AtomicUsize::new(1),
            prelude: Scope::new(),
        }
    }

    pub fn make_id(&self) -> usize {
        self.id_counter.fetch_add(1, Ordering::Relaxed)
    }

    pub fn parse_module(&'session self, source: &str) -> Result<Module<'session>, grammar::ParseError> {
        grammar::module(source).map(|ast|
            self.resolve_module(self.module_ast_arena.alloc(ast))
        )
    }

    pub fn resolve_module(&'session self, modast: &'session ast::Module) -> Module<'session> {
        Module {
            session: self,
            scope: resolve::block::resolve_module(self, modast),
        }
    }

    pub fn var(&self, _ty: resolve::types::Type, is_down: bool, is_up: bool) -> Var {
        Var {
            id: self.make_id(),
            is_down: is_down,
            is_up: is_up,
        }
    }
}

pub trait IntoItem<'s>: Clone {
    fn into_item(self) -> Item<'s>;
}

impl <'s> IntoItem<'s> for Item<'s> {
    fn into_item(self) -> Item<'s> { self }
}

impl <'s> IntoItem<'s> for Value {
    fn into_item(self) -> Item<'s> { Item::Value(Expr::Const(self)) }
}

impl <'s> IntoItem<'s> for Expr {
    fn into_item(self) -> Item<'s> { Item::Value(self) }
}

#[derive(Copy, Clone, Debug)]
pub struct Var {
    pub id: ValueID,
    pub is_down: bool,
    pub is_up: bool,
}

impl <'s> IntoItem<'s> for Var {
    fn into_item(self) -> Item<'s> {
        let var = Expr::Variable(self.id);
        Item::Value(match (self.is_down, self.is_up) {
            (true, true) => var,
            (false, true) => Expr::Flip(box Expr::Ignored, box var),
            (true, false) => Expr::Flip(box var, box Expr::Ignored),
            (false, false) => Expr::Ignored
        })
    }
}

#[macro_escape]
macro_rules! tuple_item[
    ($($x:expr),*) => ({
        use session::IntoItem;
        use resolve::scope::Item::Tuple;
        Tuple(vec![$($x.into_item()),*])
    });
    ($($x:expr,)*) => (tuple_item![$($x),*])
];

impl <'s> IntoItem<'s> for () {
    fn into_item(self) -> Item<'s> { Item::Tuple(Vec::new()) }
}

pub struct Module<'s> {
    session: &'s Session<'s>,
    scope: Scope<'s>,
}

impl <'s> Module<'s> {
    pub fn get_def<'a>(&'a self, name: &str) -> &'a EventClosure<'s> {
        // TODO: return Result
        match self.scope.get(name).unwrap() {
            resolve::scope::Item::Def(s) => s,
            _ => panic!("Main is not an event"),
        }
    }

    pub fn compile_call<T: IntoItem<'s>>(&self, name: &str,
                        shape_down: Shape,
                        param: T) -> Result<Program, ()> {
        let def = self.get_def(name);

        let (shape_up, step) = def.resolve_call(&self.session, &shape_down, param.into_item());

        Ok(Program{ step: step, shape_down: shape_down, shape_up: shape_up})
    }
}

pub struct Program {
    pub step: Step,
    pub shape_down: Shape,
    pub shape_up: Shape,
}

impl Program {
    pub fn run_test(&self, bottom: &'static str, top: &'static str) -> (bool, eval::State) {
        let (mut s1, mut s2) = exec::Connection::new();
        let (mut t1, mut t2) = exec::Connection::new();
        let reader_thread = thread::scoped(move || {
            let mut reader = Cursor::new(bottom.as_bytes().to_vec());
            dumpfile::read_values(&mut reader, &mut s2);
        });
        let writer_thread = thread::scoped(move || {
            let mut writer = Vec::new();
            dumpfile::write_values(&mut writer, &mut t1);
            assert_eq!(top, str::from_utf8(&writer).unwrap());
        });
        let mut state = eval::State::new();

        let r = exec::exec(&mut state, &self.step, &mut s1, &mut t2);

        drop(s1);
        drop(t2);
        reader_thread.join();
        writer_thread.join();

        (r, state)
    }

    pub fn run_test_pass(&self, bottom: &'static str, top: &'static str) -> eval::State {
        let (m, r) = self.run_test(bottom, top);
        if !m {
            panic!("run_pass test failed to match: {}", bottom);
        }
        r
    }

    pub fn run_test_fail(&self, bottom: &'static str, top: &'static str) -> eval::State {
        let (m, r) = self.run_test(bottom, top);
        if m {
            panic!("run_fail test matched: {}", bottom);
        }
        r
    }
}

pub trait Process: Send {
    fn run(&self, state: &mut eval::State, downwards: &mut exec::Connection, upwards: &mut exec::Connection) -> bool;
    fn shape_up(&self) -> &Shape;
}

impl Process for Program {
    fn run(&self, state: &mut eval::State, downwards: &mut exec::Connection, upwards: &mut exec::Connection) -> bool {
        exec::exec(state, &self.step, downwards, upwards)
    }

    fn shape_up(&self) -> &Shape {
        &self.shape_up
    }
}

pub trait IoProcess {
    fn run(&mut self, upwards: &mut exec::Connection) -> io::Result<()>;
}
<|endoftext|>


<commit_before>//!
//! A session runs a filesystem implementation while it is being mounted
//! to a specific mount point. A session begins by mounting the filesystem
//! and ends by unmounting it. While the filesystem is mounted, the session
//! loop receives, dispatches and replies to kernel requests for filesystem
//! operations under its mount point.
//!

use std::io;
use std::ffi::OsStr;
use std::path::{PathBuf, Path};
use std::thread::{Builder, JoinGuard};
use libc::{EAGAIN, EINTR, ENODEV, ENOENT};
use channel;
use channel::Channel;
use Filesystem;
use request::{request, dispatch};

/// The max size of write requests from the kernel. The absolute minimum is 4k,
/// FUSE recommends at least 128k, max 16M. The FUSE default is 16M on OS X
/// and 128k on other systems.
pub const MAX_WRITE_SIZE: usize = 16*1024*1024;

/// Size of the buffer for reading a request from the kernel. Since the kernel may send
/// up to MAX_WRITE_SIZE bytes in a write request, we use that value plus some extra space.
const BUFFER_SIZE: usize = MAX_WRITE_SIZE + 4096;

/// The session data structure
pub struct Session<FS: Filesystem> {
    /// Filesystem operation implementations
    pub filesystem: FS,
    /// Communication channel to the kernel driver
    ch: Channel,
    /// FUSE protocol major version
    pub proto_major: u32,
    /// FUSE protocol minor version
    pub proto_minor: u32,
    /// True if the filesystem is initialized (init operation done)
    pub initialized: bool,
    /// True if the filesystem was destroyed (destroy operation done)
    pub destroyed: bool,
}

impl<FS: Filesystem> Session<FS> {
    /// Create a new session by mounting the given filesystem to the given mountpoint
    pub fn new (filesystem: FS, mountpoint: &Path, options: &[&OsStr]) -> Session<FS> {
        info!("Mounting {}", mountpoint.display());
        let ch = match Channel::new(mountpoint, options) {
            Ok(ch) => ch,
            Err(err) => panic!("Unable to mount filesystem. Error {}", err),
        };
        Session {
            filesystem: filesystem,
            ch: ch,
            proto_major: 0,
            proto_minor: 0,
            initialized: false,
            destroyed: false,
        }
    }

    /// Return path of the mounted filesystem
    pub fn mountpoint (&self) -> &Path {
        &self.ch.mountpoint()
    }

    /// Run the session loop that receives kernel requests and dispatches them to method
    /// calls into the filesystem. This read-dispatch-loop is non-concurrent to prevent
    /// having multiple buffers (which take up much memory), but the filesystem methods
    /// may run concurrent by spawning threads.
    pub fn run (&mut self) {
        // Buffer for receiving requests from the kernel. Only one is allocated and
        // it is reused immediately after dispatching to conserve memory and allocations.
        let mut buffer: Vec<u8> = Vec::with_capacity(BUFFER_SIZE);
        loop {
            // Read the next request from the given channel to kernel driver
            // The kernel driver makes sure that we get exactly one request per read
            match self.ch.receive(&mut buffer) {
                Ok(()) => match request(self.ch.sender(), &buffer) {
                    // Dispatch request
                    Some(req) => dispatch(&req, self),
                    // Quit loop on illegal request
                    None => break,
                },
                Err(ref err) => match err.raw_os_error() {
                    // Operation interrupted. Accordingly to FUSE, this is safe to retry
                    Some(ENOENT) => continue,
                    // Interrupted system call, retry
                    Some(EINTR) => continue,
                    // Explicitly try again
                    Some(EAGAIN) => continue,
                    // Filesystem was unmounted, quit the loop
                    Some(ENODEV) => break,
                    // Unhandled error
                    _ => panic!("Lost connection to FUSE device. Error: {}", err),
                },
            }
        }
    }
}

impl<FS: Filesystem+Send+'static> Session<FS> {
    /// Run the session loop in a background thread
    pub fn spawn<'a> (self) -> io::Result<BackgroundSession<'a>> {
        BackgroundSession::new(self)
    }
}

impl<FS: Filesystem> Drop for Session<FS> {
    fn drop (&mut self) {
        info!("Unmounted {}", self.mountpoint().display());
    }
}

/// The background session data structure
pub struct BackgroundSession<'a> {
    /// Path of the mounted filesystem
    pub mountpoint: PathBuf,
    /// Thread guard of the background session
    pub guard: JoinGuard<'a ()>,
}

impl<'a> BackgroundSession<'a> {
    /// Create a new background session for the given session by running its
    /// session loop in a background thread. If the returned handle is dropped,
    /// the filesystem is unmounted and the given session ends.
    pub fn new<FS: Filesystem+Send+'static> (se: Session<FS>) -> io::Result<BackgroundSession<'a>> {
        let mountpoint = se.mountpoint().to_path_buf();
        let builder = Builder::new().name(format!("FUSE {}", mountpoint.display()));
        let guard = try!(builder.scoped(move || {
            let mut se = se;
            se.run();
        }));
        Ok(BackgroundSession { mountpoint: mountpoint, guard: guard })
    }
}

impl<'a> Drop for BackgroundSession<'a> {
    fn drop (&mut self) {
        info!("Unmounting {}", self.mountpoint.display());
        // Unmounting the filesystem will eventually end the session loop,
        // drop the session and hence end the background thread.
        match channel::unmount(&self.mountpoint) {
            Ok(()) => (),
            Err(err) => error!("Failed to unmount {}: {}", self.mountpoint.display(), err),
        }
    }
}
<commit_msg>Update for latest nightly<commit_after>//!
//! A session runs a filesystem implementation while it is being mounted
//! to a specific mount point. A session begins by mounting the filesystem
//! and ends by unmounting it. While the filesystem is mounted, the session
//! loop receives, dispatches and replies to kernel requests for filesystem
//! operations under its mount point.
//!

use std::io;
use std::ffi::OsStr;
use std::path::{PathBuf, Path};
use std::thread::{Builder, JoinGuard};
use libc::{EAGAIN, EINTR, ENODEV, ENOENT};
use channel;
use channel::Channel;
use Filesystem;
use request::{request, dispatch};

/// The max size of write requests from the kernel. The absolute minimum is 4k,
/// FUSE recommends at least 128k, max 16M. The FUSE default is 16M on OS X
/// and 128k on other systems.
pub const MAX_WRITE_SIZE: usize = 16*1024*1024;

/// Size of the buffer for reading a request from the kernel. Since the kernel may send
/// up to MAX_WRITE_SIZE bytes in a write request, we use that value plus some extra space.
const BUFFER_SIZE: usize = MAX_WRITE_SIZE + 4096;

/// The session data structure
pub struct Session<FS: Filesystem> {
    /// Filesystem operation implementations
    pub filesystem: FS,
    /// Communication channel to the kernel driver
    ch: Channel,
    /// FUSE protocol major version
    pub proto_major: u32,
    /// FUSE protocol minor version
    pub proto_minor: u32,
    /// True if the filesystem is initialized (init operation done)
    pub initialized: bool,
    /// True if the filesystem was destroyed (destroy operation done)
    pub destroyed: bool,
}

impl<FS: Filesystem> Session<FS> {
    /// Create a new session by mounting the given filesystem to the given mountpoint
    pub fn new (filesystem: FS, mountpoint: &Path, options: &[&OsStr]) -> Session<FS> {
        info!("Mounting {}", mountpoint.display());
        let ch = match Channel::new(mountpoint, options) {
            Ok(ch) => ch,
            Err(err) => panic!("Unable to mount filesystem. Error {}", err),
        };
        Session {
            filesystem: filesystem,
            ch: ch,
            proto_major: 0,
            proto_minor: 0,
            initialized: false,
            destroyed: false,
        }
    }

    /// Return path of the mounted filesystem
    pub fn mountpoint (&self) -> &Path {
        &self.ch.mountpoint()
    }

    /// Run the session loop that receives kernel requests and dispatches them to method
    /// calls into the filesystem. This read-dispatch-loop is non-concurrent to prevent
    /// having multiple buffers (which take up much memory), but the filesystem methods
    /// may run concurrent by spawning threads.
    pub fn run (&mut self) {
        // Buffer for receiving requests from the kernel. Only one is allocated and
        // it is reused immediately after dispatching to conserve memory and allocations.
        let mut buffer: Vec<u8> = Vec::with_capacity(BUFFER_SIZE);
        loop {
            // Read the next request from the given channel to kernel driver
            // The kernel driver makes sure that we get exactly one request per read
            match self.ch.receive(&mut buffer) {
                Ok(()) => match request(self.ch.sender(), &buffer) {
                    // Dispatch request
                    Some(req) => dispatch(&req, self),
                    // Quit loop on illegal request
                    None => break,
                },
                Err(ref err) => match err.raw_os_error() {
                    // Operation interrupted. Accordingly to FUSE, this is safe to retry
                    Some(ENOENT) => continue,
                    // Interrupted system call, retry
                    Some(EINTR) => continue,
                    // Explicitly try again
                    Some(EAGAIN) => continue,
                    // Filesystem was unmounted, quit the loop
                    Some(ENODEV) => break,
                    // Unhandled error
                    _ => panic!("Lost connection to FUSE device. Error: {}", err),
                },
            }
        }
    }
}

impl<FS: Filesystem+Send+'static> Session<FS> {
    /// Run the session loop in a background thread
    pub fn spawn<'a> (self) -> io::Result<BackgroundSession<'a>> {
        BackgroundSession::new(self)
    }
}

impl<FS: Filesystem> Drop for Session<FS> {
    fn drop (&mut self) {
        info!("Unmounted {}", self.mountpoint().display());
    }
}

/// The background session data structure
pub struct BackgroundSession<'a> {
    /// Path of the mounted filesystem
    pub mountpoint: PathBuf,
    /// Thread guard of the background session
    pub guard: JoinGuard<'a, ()>,
}

impl<'a> BackgroundSession<'a> {
    /// Create a new background session for the given session by running its
    /// session loop in a background thread. If the returned handle is dropped,
    /// the filesystem is unmounted and the given session ends.
    pub fn new<FS: Filesystem+Send+'static> (se: Session<FS>) -> io::Result<BackgroundSession<'a>> {
        let mountpoint = se.mountpoint().to_path_buf();
        let builder = Builder::new().name(format!("FUSE {}", mountpoint.display()));
        let guard = try!(builder.scoped(move || {
            let mut se = se;
            se.run();
        }));
        Ok(BackgroundSession { mountpoint: mountpoint, guard: guard })
    }
}

impl<'a> Drop for BackgroundSession<'a> {
    fn drop (&mut self) {
        info!("Unmounting {}", self.mountpoint.display());
        // Unmounting the filesystem will eventually end the session loop,
        // drop the session and hence end the background thread.
        match channel::unmount(&self.mountpoint) {
            Ok(()) => (),
            Err(err) => error!("Failed to unmount {}: {}", self.mountpoint.display(), err),
        }
    }
}
<|endoftext|>


<commit_before>//! Create window.

// External crates.
use collections::Deque;
use collections::ringbuf::RingBuf;
use glfw;
use gl;
use piston::event;
use piston::keyboard;
use piston::mouse;
use piston::GameWindow;
use piston::GameWindowSettings;

/// Contains stuff for game window.
pub struct GameWindowGLFW {
    /// The window.
    window: glfw::Window,
    /// Receives events from window.
    events: Receiver<(f64, glfw::WindowEvent)>,
    /// GLFW context.
    glfw: glfw::Glfw,
    /// Game window settings.
    settings: GameWindowSettings,
    event_queue: RingBuf<event::Event>,
}

impl GameWindowGLFW {
    /// Creates a new game window for GLFW.
    pub fn new(settings: GameWindowSettings) -> GameWindowGLFW {
        use glfw::Context;

        // Create GLFW window.
        let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();
        let (window, events) = glfw.create_window(
            settings.size[0],
            settings.size[1],
            settings.title.as_slice(), glfw::Windowed
        ).expect("Failed to create GLFW window.");
        window.set_key_polling(true);
        window.set_mouse_button_polling(true);
        window.set_cursor_pos_polling(true);
        window.set_scroll_polling(true);
        // or polling all event
        //window.set_all_polling(true);
        window.make_current();

        // Load the OpenGL function pointers
        gl::load_with(|s| glfw.get_proc_address(s));

        GameWindowGLFW {
            window: window,
            events: events,
            glfw: glfw,
            settings: settings,
            event_queue: RingBuf::<event::Event>::new(),
        }
    }

    fn flush_messages(&mut self) {
        if self.event_queue.len() != 0 {
            return;
        }

        self.glfw.poll_events();
        for (_, event) in glfw::flush_messages(&self.events) {
            match event {
                glfw::KeyEvent(glfw::KeyEscape, _, glfw::Press, _)
                    if self.settings.exit_on_esc => {
                        self.window.set_should_close(true);
                    },
                glfw::KeyEvent(key, _, glfw::Press, _) => {
                    self.event_queue.push_back(
                        event::KeyPressed(glfw_map_key(key)));
                },
                glfw::KeyEvent(key, _, glfw::Release, _) => {
                    self.event_queue.push_back(
                        event::KeyReleased(glfw_map_key(key)));
                },
                glfw::MouseButtonEvent(button, glfw::Press, _) => {
                    self.event_queue.push_back(
                        event::MouseButtonPressed(glfw_map_mouse(button)));
                },
                glfw::MouseButtonEvent(button, glfw::Release, _) => {
                    self.event_queue.push_back(
                        event::MouseButtonReleased(glfw_map_mouse(button)));
                },
                glfw::CursorPosEvent(x, y) => {
                    self.event_queue.push_back(
                        event::MouseMoved(x, y, None));
                },
                glfw::ScrollEvent(x, y) => {
                    self.event_queue.push_back(
                        event::MouseScrolled(x, y));
                },
                _ => {},
            }
        }
    }
}

impl GameWindow for GameWindowGLFW {
    fn get_settings<'a>(&'a self) -> &'a GameWindowSettings {
        &self.settings
    }

    fn should_close(&self) -> bool {
        self.window.should_close()
    }

    fn swap_buffers(&self) {
        use glfw::Context;

        self.window.swap_buffers();
    }

    fn poll_event(&mut self) -> event::Event {
        self.flush_messages();

        if self.event_queue.len() != 0 {
            self.event_queue.pop_front().unwrap()
        } else {
            event::NoEvent
        }
    }
}

fn glfw_map_key(keycode: glfw::Key) -> keyboard::Key {
    match keycode {
        glfw::Key0 => keyboard::D0,
        glfw::Key1 => keyboard::D1,
        glfw::Key2 => keyboard::D2,
        glfw::Key3 => keyboard::D3,
        glfw::Key4 => keyboard::D4,
        glfw::Key5 => keyboard::D5,
        glfw::Key6 => keyboard::D6,
        glfw::Key7 => keyboard::D7,
        glfw::Key8 => keyboard::D8,
        glfw::Key9 => keyboard::D9,
        glfw::KeyA => keyboard::A,
        glfw::KeyB => keyboard::B,
        glfw::KeyC => keyboard::C,
        glfw::KeyD => keyboard::D,
        glfw::KeyE => keyboard::E,
        glfw::KeyF => keyboard::F,
        glfw::KeyG => keyboard::G,
        glfw::KeyH => keyboard::H,
        glfw::KeyI => keyboard::I,
        glfw::KeyJ => keyboard::J,
        glfw::KeyK => keyboard::K,
        glfw::KeyL => keyboard::L,
        glfw::KeyM => keyboard::M,
        glfw::KeyN => keyboard::N,
        glfw::KeyO => keyboard::O,
        glfw::KeyP => keyboard::P,
        glfw::KeyQ => keyboard::Q,
        glfw::KeyR => keyboard::R,
        glfw::KeyS => keyboard::S,
        glfw::KeyT => keyboard::T,
        glfw::KeyU => keyboard::U,
        glfw::KeyV => keyboard::V,
        glfw::KeyW => keyboard::W,
        glfw::KeyX => keyboard::X,
        glfw::KeyY => keyboard::Y,
        glfw::KeyZ => keyboard::Z,
        glfw::KeyApostrophe => keyboard::Unknown,
        glfw::KeyBackslash => keyboard::Backslash,
        glfw::KeyBackspace => keyboard::Backspace,
        glfw::KeyCapsLock => keyboard::CapsLock,
        glfw::KeyDelete => keyboard::Delete,
        glfw::KeyComma => keyboard::Comma,
        glfw::KeyDown => keyboard::Down,
        glfw::KeyEnd => keyboard::End,
        glfw::KeyEnter => keyboard::Return,
        glfw::KeyEqual => keyboard::Equals,
        glfw::KeyEscape => keyboard::Escape,
        glfw::KeyF1 => keyboard::F1,
        glfw::KeyF2 => keyboard::F2,
        glfw::KeyF3 => keyboard::F3,
        glfw::KeyF4 => keyboard::F4,
        glfw::KeyF5 => keyboard::F5,
        glfw::KeyF6 => keyboard::F6,
        glfw::KeyF7 => keyboard::F7,
        glfw::KeyF8 => keyboard::F8,
        glfw::KeyF9 => keyboard::F9,
        glfw::KeyF10 => keyboard::F10,
        glfw::KeyF11 => keyboard::F11,
        glfw::KeyF12 => keyboard::F12,
        glfw::KeyF13 => keyboard::F13,
        glfw::KeyF14 => keyboard::F14,
        glfw::KeyF15 => keyboard::F15,
        glfw::KeyF16 => keyboard::F16,
        glfw::KeyF17 => keyboard::F17,
        glfw::KeyF18 => keyboard::F18,
        glfw::KeyF19 => keyboard::F19,
        glfw::KeyF20 => keyboard::F20,
        glfw::KeyF21 => keyboard::F21,
        glfw::KeyF22 => keyboard::F22,
        glfw::KeyF23 => keyboard::F23,
        glfw::KeyF24 => keyboard::F24,
        // Possibly next code.
        glfw::KeyF25 => keyboard::Unknown,
        glfw::KeyKp0 => keyboard::NumPad0,
        glfw::KeyKp1 => keyboard::NumPad1,
        glfw::KeyKp2 => keyboard::NumPad2,
        glfw::KeyKp3 => keyboard::NumPad3,
        glfw::KeyKp4 => keyboard::NumPad4,
        glfw::KeyKp5 => keyboard::NumPad5,
        glfw::KeyKp6 => keyboard::NumPad6,
        glfw::KeyKp7 => keyboard::NumPad7,
        glfw::KeyKp8 => keyboard::NumPad8,
        glfw::KeyKp9 => keyboard::NumPad9,
        glfw::KeyKpDecimal => keyboard::NumPadDecimal,
        glfw::KeyKpDivide => keyboard::NumPadDivide,
        glfw::KeyKpMultiply => keyboard::NumPadMultiply,
        glfw::KeyKpSubtract => keyboard::NumPadMinus,
        glfw::KeyKpAdd => keyboard::NumPadPlus,
        glfw::KeyKpEnter => keyboard::NumPadEnter,
        glfw::KeyKpEqual => keyboard::NumPadEquals,
        glfw::KeyLeftShift => keyboard::LShift,
        glfw::KeyLeftControl => keyboard::LCtrl,
        glfw::KeyLeftAlt => keyboard::LAlt,
        glfw::KeyLeftSuper => keyboard::LGui,
        glfw::KeyRightShift => keyboard::RShift,
        glfw::KeyRightControl => keyboard::RCtrl,
        glfw::KeyRightAlt => keyboard::RAlt,
        glfw::KeyRightSuper => keyboard::RGui,
        // Map to backslash?
        glfw::KeyGraveAccent => keyboard::Unknown,
        glfw::KeyHome => keyboard::Home,
        glfw::KeyInsert => keyboard::Insert,
        glfw::KeyLeft => keyboard::Left,
        glfw::KeyLeftBracket => keyboard::LeftBracket,
        glfw::KeyMenu => keyboard::Menu,
        glfw::KeyMinus => keyboard::Minus,
        glfw::KeyNumLock => keyboard::NumLockClear,
        glfw::KeyPageDown => keyboard::PageDown,
        glfw::KeyPageUp => keyboard::PageUp,
        glfw::KeyPause => keyboard::Pause,
        glfw::KeyPeriod => keyboard::Period,
        glfw::KeyPrintScreen => keyboard::PrintScreen,
        glfw::KeyRight => keyboard::Right,
        glfw::KeyRightBracket => keyboard::RightBracket,
        glfw::KeyScrollLock => keyboard::ScrollLock,
        glfw::KeySemicolon => keyboard::Semicolon,
        glfw::KeySlash => keyboard::Slash,
        glfw::KeySpace => keyboard::Space,
        glfw::KeyTab => keyboard::Tab,
        glfw::KeyUp => keyboard::Up,
        glfw::KeyWorld1 => keyboard::Unknown,
        glfw::KeyWorld2 => keyboard::Unknown,
        // _ => keyboard::Unknown,
    }
}

fn glfw_map_mouse(mouse_button: glfw::MouseButton) -> mouse::Button {
    match mouse_button {
        glfw::MouseButton1 => mouse::Left,
        glfw::MouseButton2 => mouse::Right,
        glfw::MouseButton3 => mouse::Middle,
        glfw::MouseButton4 => mouse::X1,
        glfw::MouseButton5 => mouse::X2,
        glfw::MouseButton6 => mouse::Button6,
        glfw::MouseButton7 => mouse::Button7,
        glfw::MouseButton8 => mouse::Button8,
    }
}

<commit_msg>Added capture cursor support<commit_after>//! Create window.

// External crates.
use collections::Deque;
use collections::ringbuf::RingBuf;
use glfw;
use gl;
use piston::event;
use piston::keyboard;
use piston::mouse;
use piston::GameWindow;
use piston::GameWindowSettings;

/// Contains stuff for game window.
pub struct GameWindowGLFW {
    /// The window.
    window: glfw::Window,
    /// Receives events from window.
    events: Receiver<(f64, glfw::WindowEvent)>,
    /// GLFW context.
    glfw: glfw::Glfw,
    /// Game window settings.
    settings: GameWindowSettings,
    event_queue: RingBuf<event::Event>,
}

impl GameWindowGLFW {
    /// Creates a new game window for GLFW.
    pub fn new(settings: GameWindowSettings) -> GameWindowGLFW {
        use glfw::Context;

        // Create GLFW window.
        let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();
        let (window, events) = glfw.create_window(
            settings.size[0],
            settings.size[1],
            settings.title.as_slice(), glfw::Windowed
        ).expect("Failed to create GLFW window.");
        window.set_key_polling(true);
        window.set_mouse_button_polling(true);
        window.set_cursor_pos_polling(true);
        window.set_scroll_polling(true);
        // or polling all event
        //window.set_all_polling(true);
        window.make_current();

        // Load the OpenGL function pointers
        gl::load_with(|s| glfw.get_proc_address(s));

        GameWindowGLFW {
            window: window,
            events: events,
            glfw: glfw,
            settings: settings,
            event_queue: RingBuf::<event::Event>::new(),
        }
    }

    fn flush_messages(&mut self) {
        if self.event_queue.len() != 0 {
            return;
        }

        self.glfw.poll_events();
        for (_, event) in glfw::flush_messages(&self.events) {
            match event {
                glfw::KeyEvent(glfw::KeyEscape, _, glfw::Press, _)
                    if self.settings.exit_on_esc => {
                        self.window.set_should_close(true);
                    },
                glfw::KeyEvent(key, _, glfw::Press, _) => {
                    self.event_queue.push_back(
                        event::KeyPressed(glfw_map_key(key)));
                },
                glfw::KeyEvent(key, _, glfw::Release, _) => {
                    self.event_queue.push_back(
                        event::KeyReleased(glfw_map_key(key)));
                },
                glfw::MouseButtonEvent(button, glfw::Press, _) => {
                    self.event_queue.push_back(
                        event::MouseButtonPressed(glfw_map_mouse(button)));
                },
                glfw::MouseButtonEvent(button, glfw::Release, _) => {
                    self.event_queue.push_back(
                        event::MouseButtonReleased(glfw_map_mouse(button)));
                },
                glfw::CursorPosEvent(x, y) => {
                    self.event_queue.push_back(
                        event::MouseMoved(x, y, None));
                },
                glfw::ScrollEvent(x, y) => {
                    self.event_queue.push_back(
                        event::MouseScrolled(x, y));
                },
                _ => {},
            }
        }
    }
}

impl GameWindow for GameWindowGLFW {
    fn get_settings<'a>(&'a self) -> &'a GameWindowSettings {
        &self.settings
    }

    fn should_close(&self) -> bool {
        self.window.should_close()
    }

    fn swap_buffers(&self) {
        use glfw::Context;

        self.window.swap_buffers();
    }

    fn capture_cursor(&mut self, enabled: bool) {
        if enabled {
            self.window.set_cursor_mode(glfw::CursorDisabled)
        } else {
            self.window.set_cursor_mode(glfw::CursorNormal)
        }
    }

    fn poll_event(&mut self) -> event::Event {
        self.flush_messages();

        if self.event_queue.len() != 0 {
            self.event_queue.pop_front().unwrap()
        } else {
            event::NoEvent
        }
    }
}

fn glfw_map_key(keycode: glfw::Key) -> keyboard::Key {
    match keycode {
        glfw::Key0 => keyboard::D0,
        glfw::Key1 => keyboard::D1,
        glfw::Key2 => keyboard::D2,
        glfw::Key3 => keyboard::D3,
        glfw::Key4 => keyboard::D4,
        glfw::Key5 => keyboard::D5,
        glfw::Key6 => keyboard::D6,
        glfw::Key7 => keyboard::D7,
        glfw::Key8 => keyboard::D8,
        glfw::Key9 => keyboard::D9,
        glfw::KeyA => keyboard::A,
        glfw::KeyB => keyboard::B,
        glfw::KeyC => keyboard::C,
        glfw::KeyD => keyboard::D,
        glfw::KeyE => keyboard::E,
        glfw::KeyF => keyboard::F,
        glfw::KeyG => keyboard::G,
        glfw::KeyH => keyboard::H,
        glfw::KeyI => keyboard::I,
        glfw::KeyJ => keyboard::J,
        glfw::KeyK => keyboard::K,
        glfw::KeyL => keyboard::L,
        glfw::KeyM => keyboard::M,
        glfw::KeyN => keyboard::N,
        glfw::KeyO => keyboard::O,
        glfw::KeyP => keyboard::P,
        glfw::KeyQ => keyboard::Q,
        glfw::KeyR => keyboard::R,
        glfw::KeyS => keyboard::S,
        glfw::KeyT => keyboard::T,
        glfw::KeyU => keyboard::U,
        glfw::KeyV => keyboard::V,
        glfw::KeyW => keyboard::W,
        glfw::KeyX => keyboard::X,
        glfw::KeyY => keyboard::Y,
        glfw::KeyZ => keyboard::Z,
        glfw::KeyApostrophe => keyboard::Unknown,
        glfw::KeyBackslash => keyboard::Backslash,
        glfw::KeyBackspace => keyboard::Backspace,
        glfw::KeyCapsLock => keyboard::CapsLock,
        glfw::KeyDelete => keyboard::Delete,
        glfw::KeyComma => keyboard::Comma,
        glfw::KeyDown => keyboard::Down,
        glfw::KeyEnd => keyboard::End,
        glfw::KeyEnter => keyboard::Return,
        glfw::KeyEqual => keyboard::Equals,
        glfw::KeyEscape => keyboard::Escape,
        glfw::KeyF1 => keyboard::F1,
        glfw::KeyF2 => keyboard::F2,
        glfw::KeyF3 => keyboard::F3,
        glfw::KeyF4 => keyboard::F4,
        glfw::KeyF5 => keyboard::F5,
        glfw::KeyF6 => keyboard::F6,
        glfw::KeyF7 => keyboard::F7,
        glfw::KeyF8 => keyboard::F8,
        glfw::KeyF9 => keyboard::F9,
        glfw::KeyF10 => keyboard::F10,
        glfw::KeyF11 => keyboard::F11,
        glfw::KeyF12 => keyboard::F12,
        glfw::KeyF13 => keyboard::F13,
        glfw::KeyF14 => keyboard::F14,
        glfw::KeyF15 => keyboard::F15,
        glfw::KeyF16 => keyboard::F16,
        glfw::KeyF17 => keyboard::F17,
        glfw::KeyF18 => keyboard::F18,
        glfw::KeyF19 => keyboard::F19,
        glfw::KeyF20 => keyboard::F20,
        glfw::KeyF21 => keyboard::F21,
        glfw::KeyF22 => keyboard::F22,
        glfw::KeyF23 => keyboard::F23,
        glfw::KeyF24 => keyboard::F24,
        // Possibly next code.
        glfw::KeyF25 => keyboard::Unknown,
        glfw::KeyKp0 => keyboard::NumPad0,
        glfw::KeyKp1 => keyboard::NumPad1,
        glfw::KeyKp2 => keyboard::NumPad2,
        glfw::KeyKp3 => keyboard::NumPad3,
        glfw::KeyKp4 => keyboard::NumPad4,
        glfw::KeyKp5 => keyboard::NumPad5,
        glfw::KeyKp6 => keyboard::NumPad6,
        glfw::KeyKp7 => keyboard::NumPad7,
        glfw::KeyKp8 => keyboard::NumPad8,
        glfw::KeyKp9 => keyboard::NumPad9,
        glfw::KeyKpDecimal => keyboard::NumPadDecimal,
        glfw::KeyKpDivide => keyboard::NumPadDivide,
        glfw::KeyKpMultiply => keyboard::NumPadMultiply,
        glfw::KeyKpSubtract => keyboard::NumPadMinus,
        glfw::KeyKpAdd => keyboard::NumPadPlus,
        glfw::KeyKpEnter => keyboard::NumPadEnter,
        glfw::KeyKpEqual => keyboard::NumPadEquals,
        glfw::KeyLeftShift => keyboard::LShift,
        glfw::KeyLeftControl => keyboard::LCtrl,
        glfw::KeyLeftAlt => keyboard::LAlt,
        glfw::KeyLeftSuper => keyboard::LGui,
        glfw::KeyRightShift => keyboard::RShift,
        glfw::KeyRightControl => keyboard::RCtrl,
        glfw::KeyRightAlt => keyboard::RAlt,
        glfw::KeyRightSuper => keyboard::RGui,
        // Map to backslash?
        glfw::KeyGraveAccent => keyboard::Unknown,
        glfw::KeyHome => keyboard::Home,
        glfw::KeyInsert => keyboard::Insert,
        glfw::KeyLeft => keyboard::Left,
        glfw::KeyLeftBracket => keyboard::LeftBracket,
        glfw::KeyMenu => keyboard::Menu,
        glfw::KeyMinus => keyboard::Minus,
        glfw::KeyNumLock => keyboard::NumLockClear,
        glfw::KeyPageDown => keyboard::PageDown,
        glfw::KeyPageUp => keyboard::PageUp,
        glfw::KeyPause => keyboard::Pause,
        glfw::KeyPeriod => keyboard::Period,
        glfw::KeyPrintScreen => keyboard::PrintScreen,
        glfw::KeyRight => keyboard::Right,
        glfw::KeyRightBracket => keyboard::RightBracket,
        glfw::KeyScrollLock => keyboard::ScrollLock,
        glfw::KeySemicolon => keyboard::Semicolon,
        glfw::KeySlash => keyboard::Slash,
        glfw::KeySpace => keyboard::Space,
        glfw::KeyTab => keyboard::Tab,
        glfw::KeyUp => keyboard::Up,
        glfw::KeyWorld1 => keyboard::Unknown,
        glfw::KeyWorld2 => keyboard::Unknown,
        // _ => keyboard::Unknown,
    }
}

fn glfw_map_mouse(mouse_button: glfw::MouseButton) -> mouse::Button {
    match mouse_button {
        glfw::MouseButton1 => mouse::Left,
        glfw::MouseButton2 => mouse::Right,
        glfw::MouseButton3 => mouse::Middle,
        glfw::MouseButton4 => mouse::X1,
        glfw::MouseButton5 => mouse::X2,
        glfw::MouseButton6 => mouse::Button6,
        glfw::MouseButton7 => mouse::Button7,
        glfw::MouseButton8 => mouse::Button8,
    }
}

<|endoftext|>


<commit_before>use std::marker::PhantomData;
use gl;
use gl::types::*;

pub struct Texture<T: TextureType> {
    gl_id: GLuint,
    phantom: PhantomData<*mut T>
}
pub type Texture2d = Texture<Tx2d>;
pub type TextureCubeMap = Texture<TxCubeMap>;

impl<T: TextureType> Texture<T> {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl<T: TextureType> Drop for Texture<T> {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteTextures(1, &self.gl_id as *const GLuint);
        }
    }
}

pub trait ImageTargetType {
    fn gl_enum(&self) -> GLenum;
}

pub trait TextureType {
    type ImageTargetType: ImageTargetType;

    fn target() -> TextureBindingTarget;
}

pub struct Tx2d;

gl_enum! {
    pub gl_enum Tx2dImageTarget {
        Texture2d as TEXTURE_2D_TARGET = gl::TEXTURE_2D
    }
}

impl ImageTargetType for Tx2dImageTarget {
    fn gl_enum(&self) -> GLenum {
        self.gl_enum()
    }
}

impl TextureType for Tx2d {
    type ImageTargetType = Tx2dImageTarget;

    fn target() -> TextureBindingTarget {
        TextureBindingTarget::Texture2d
    }
}

pub struct TxCubeMap;

gl_enum! {
    pub gl_enum TxCubeMapImageTarget {
        CubeMapPositiveX as TEXTURE_CUBE_MAP_POSITIVE_X =
            gl::TEXTURE_CUBE_MAP_POSITIVE_X,
        CubeMapNegativeX as TEXTURE_CUBE_MAP_NEGATIVE_X =
            gl::TEXTURE_CUBE_MAP_NEGATIVE_X,
        CubeMapPositiveY as TEXTURE_CUBE_MAP_POSITIVE_Y =
            gl::TEXTURE_CUBE_MAP_POSITIVE_Y,
        CubeMapNegativeY as TEXTURE_CUBE_MAP_NEGATIVE_Y =
            gl::TEXTURE_CUBE_MAP_NEGATIVE_Y,
        CubeMapPositiveZ as TEXTURE_CUBE_MAP_POSITIVE_Z =
            gl::TEXTURE_CUBE_MAP_POSITIVE_Z,
        CubeMapNegativeZ as TEXTURE_CUBE_MAP_NEGATIVE_Z =
            gl::TEXTURE_CUBE_MAP_NEGATIVE_Z
    }
}

impl ImageTargetType for TxCubeMapImageTarget {
    fn gl_enum(&self) -> GLenum {
        self.gl_enum()
    }
}

impl TextureType for TxCubeMap {
    type ImageTargetType = TxCubeMapImageTarget;

    fn target() -> TextureBindingTarget {
        TextureBindingTarget::TextureCubeMap
    }
}

gl_enum! {
    pub gl_enum TextureBindingTarget {
        Texture2d as TEXTURE_2D = gl::TEXTURE_2D,
        TextureCubeMap as TEXTURE_CUBE_MAP = gl::TEXTURE_CUBE_MAP
    }
}
<commit_msg>Add `Context::gen_texture()`<commit_after>use std::marker::PhantomData;
use gl;
use gl::types::*;
use context::Context;
use types::GLError;

pub struct Texture<T: TextureType> {
    gl_id: GLuint,
    phantom: PhantomData<*mut T>
}
pub type Texture2d = Texture<Tx2d>;
pub type TextureCubeMap = Texture<TxCubeMap>;

impl<T: TextureType> Texture<T> {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl<T: TextureType> Drop for Texture<T> {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteTextures(1, &self.gl_id as *const GLuint);
        }
    }
}

impl Context {
    pub fn gen_texture<T: TextureType>(&self) -> Texture<T> {
        unsafe {
            let mut id : GLuint =  0;

            gl::GenTextures(1, &mut id as *mut GLuint);
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`n` is negative",
                _ => "Unknown error"
            }

            Texture {
                gl_id: id,
                phantom: PhantomData
            }
        }
    }
}

pub trait ImageTargetType {
    fn gl_enum(&self) -> GLenum;
}

pub trait TextureType {
    type ImageTargetType: ImageTargetType;

    fn target() -> TextureBindingTarget;
}

pub struct Tx2d;

gl_enum! {
    pub gl_enum Tx2dImageTarget {
        Texture2d as TEXTURE_2D_TARGET = gl::TEXTURE_2D
    }
}

impl ImageTargetType for Tx2dImageTarget {
    fn gl_enum(&self) -> GLenum {
        self.gl_enum()
    }
}

impl TextureType for Tx2d {
    type ImageTargetType = Tx2dImageTarget;

    fn target() -> TextureBindingTarget {
        TextureBindingTarget::Texture2d
    }
}

pub struct TxCubeMap;

gl_enum! {
    pub gl_enum TxCubeMapImageTarget {
        CubeMapPositiveX as TEXTURE_CUBE_MAP_POSITIVE_X =
            gl::TEXTURE_CUBE_MAP_POSITIVE_X,
        CubeMapNegativeX as TEXTURE_CUBE_MAP_NEGATIVE_X =
            gl::TEXTURE_CUBE_MAP_NEGATIVE_X,
        CubeMapPositiveY as TEXTURE_CUBE_MAP_POSITIVE_Y =
            gl::TEXTURE_CUBE_MAP_POSITIVE_Y,
        CubeMapNegativeY as TEXTURE_CUBE_MAP_NEGATIVE_Y =
            gl::TEXTURE_CUBE_MAP_NEGATIVE_Y,
        CubeMapPositiveZ as TEXTURE_CUBE_MAP_POSITIVE_Z =
            gl::TEXTURE_CUBE_MAP_POSITIVE_Z,
        CubeMapNegativeZ as TEXTURE_CUBE_MAP_NEGATIVE_Z =
            gl::TEXTURE_CUBE_MAP_NEGATIVE_Z
    }
}

impl ImageTargetType for TxCubeMapImageTarget {
    fn gl_enum(&self) -> GLenum {
        self.gl_enum()
    }
}

impl TextureType for TxCubeMap {
    type ImageTargetType = TxCubeMapImageTarget;

    fn target() -> TextureBindingTarget {
        TextureBindingTarget::TextureCubeMap
    }
}

gl_enum! {
    pub gl_enum TextureBindingTarget {
        Texture2d as TEXTURE_2D = gl::TEXTURE_2D,
        TextureCubeMap as TEXTURE_CUBE_MAP = gl::TEXTURE_CUBE_MAP
    }
}
<|endoftext|>


<commit_before>use std::ptr;
use std::marker::PhantomData;
use gl;
use gl::types::*;
use context::Context;
use image_data::{Image2d, TextelFormat, ImageFormat};
use types::GLError;

pub struct Texture<T: TextureType> {
    gl_id: GLuint,
    phantom: PhantomData<*mut T>
}
pub type Texture2d = Texture<Tx2d>;
pub type TextureCubeMap = Texture<TxCubeMap>;

impl<T: TextureType> Texture<T> {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl<T: TextureType> Drop for Texture<T> {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteTextures(1, &self.gl_id as *const GLuint);
        }
    }
}

impl Context {
    pub unsafe fn gen_texture<T: TextureType>(&self) -> Texture<T> {
        let mut id : GLuint =  0;

        gl::GenTextures(1, &mut id as *mut GLuint);
        dbg_gl_sanity_check! {
            GLError::InvalidValue => "`n` is negative",
            _ => "Unknown error"
        }

        Texture {
            gl_id: id,
            phantom: PhantomData
        }
    }
}

pub trait ImageTargetType {
    fn gl_enum(&self) -> GLenum;
}

pub trait TextureType {
    type ImageTargetType: ImageTargetType;

    fn target() -> TextureBindingTarget;
}

pub struct Tx2d;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Tx2dImageTarget {
    Texture2d = gl::TEXTURE_2D as isize
}

impl ImageTargetType for Tx2dImageTarget {
    fn gl_enum(&self) -> GLenum {
        *self as GLenum
    }
}

impl TextureType for Tx2d {
    type ImageTargetType = Tx2dImageTarget;

    fn target() -> TextureBindingTarget {
        TextureBindingTarget::Texture2d
    }
}

pub struct TxCubeMap;

gl_enum! {
    pub gl_enum TxCubeMapImageTarget {
        CubeMapPositiveX as TEXTURE_CUBE_MAP_POSITIVE_X =
            gl::TEXTURE_CUBE_MAP_POSITIVE_X,
        CubeMapNegativeX as TEXTURE_CUBE_MAP_NEGATIVE_X =
            gl::TEXTURE_CUBE_MAP_NEGATIVE_X,
        CubeMapPositiveY as TEXTURE_CUBE_MAP_POSITIVE_Y =
            gl::TEXTURE_CUBE_MAP_POSITIVE_Y,
        CubeMapNegativeY as TEXTURE_CUBE_MAP_NEGATIVE_Y =
            gl::TEXTURE_CUBE_MAP_NEGATIVE_Y,
        CubeMapPositiveZ as TEXTURE_CUBE_MAP_POSITIVE_Z =
            gl::TEXTURE_CUBE_MAP_POSITIVE_Z,
        CubeMapNegativeZ as TEXTURE_CUBE_MAP_NEGATIVE_Z =
            gl::TEXTURE_CUBE_MAP_NEGATIVE_Z
    }
}

impl ImageTargetType for TxCubeMapImageTarget {
    fn gl_enum(&self) -> GLenum {
        self.gl_enum()
    }
}

impl TextureType for TxCubeMap {
    type ImageTargetType = TxCubeMapImageTarget;

    fn target() -> TextureBindingTarget {
        TextureBindingTarget::TextureCubeMap
    }
}

gl_enum! {
    pub gl_enum TextureBindingTarget {
        Texture2d as TEXTURE_2D = gl::TEXTURE_2D,
        TextureCubeMap as TEXTURE_CUBE_MAP = gl::TEXTURE_CUBE_MAP
    }
}

// TODO: Use type refinements someday...
#[derive(Debug, Clone, Copy)]
pub enum TextureFilter {
    Nearest,
    Linear
}

#[derive(Debug, Clone, Copy)]
pub enum TextureMipmapFilter {
    Filter(TextureFilter),
    MipmapFilter { criterion: TextureFilter, mipmap: TextureFilter }
}

pub const NEAREST : TextureFilter = TextureFilter::Nearest;
pub const LINEAR : TextureFilter = TextureFilter::Linear;
pub const NEAREST_MIPMAP_NEAREST : TextureMipmapFilter =
    TextureMipmapFilter::MipmapFilter {
        criterion: TextureFilter::Nearest,
        mipmap: TextureFilter::Nearest
    };
pub const LINEAR_MIPMAP_NEAREST : TextureMipmapFilter =
    TextureMipmapFilter::MipmapFilter {
        criterion: TextureFilter::Linear,
        mipmap: TextureFilter::Nearest
    };
pub const NEAREST_MIPMAP_LINEAR : TextureMipmapFilter =
    TextureMipmapFilter::MipmapFilter {
        criterion: TextureFilter::Nearest,
        mipmap: TextureFilter::Linear
    };
pub const LINEAR_MIPMAP_LINEAR : TextureMipmapFilter =
    TextureMipmapFilter::MipmapFilter {
        criterion: TextureFilter::Linear,
        mipmap: TextureFilter::Linear
    };

#[allow(dead_code)]
impl TextureFilter {
    fn from_gl(gl_enum: GLenum) -> Result<Self, ()> {
        match gl_enum {
            gl::NEAREST => { Ok(self::NEAREST) },
            gl::LINEAR => { Ok(self::LINEAR) },
            _ => { Err(()) }
        }
    }

    fn gl_enum(&self) -> GLenum {
        match *self {
            self::NEAREST => gl::NEAREST,
            self::LINEAR => gl::LINEAR
        }
    }
}

#[allow(dead_code)]
impl TextureMipmapFilter {
    fn from_gl(gl_enum: GLenum) -> Result<Self, ()> {
        match gl_enum {
            gl::NEAREST => { Ok(TextureMipmapFilter::Filter(self::NEAREST)) },
            gl::LINEAR => { Ok(TextureMipmapFilter::Filter(self::LINEAR)) },
            gl::NEAREST_MIPMAP_NEAREST => { Ok(self::NEAREST_MIPMAP_NEAREST) },
            gl::LINEAR_MIPMAP_NEAREST => { Ok(self::LINEAR_MIPMAP_NEAREST) },
            gl::NEAREST_MIPMAP_LINEAR => { Ok(self::NEAREST_MIPMAP_LINEAR) },
            gl::LINEAR_MIPMAP_LINEAR => { Ok(self::LINEAR_MIPMAP_LINEAR) },
            _ => { Err(()) }
        }
    }

    fn gl_enum(&self) -> GLenum {
        match *self {
            TextureMipmapFilter::Filter(self::LINEAR) => { gl::LINEAR },
            TextureMipmapFilter::Filter(self::NEAREST) => { gl::NEAREST },
            self::NEAREST_MIPMAP_NEAREST => { gl::NEAREST_MIPMAP_NEAREST },
            self::LINEAR_MIPMAP_NEAREST => { gl::LINEAR_MIPMAP_NEAREST },
            self::NEAREST_MIPMAP_LINEAR => { gl::NEAREST_MIPMAP_LINEAR },
            self::LINEAR_MIPMAP_LINEAR => { gl::LINEAR_MIPMAP_LINEAR }
        }
    }
}

impl From<TextureFilter> for TextureMipmapFilter {
    fn from(filter: TextureFilter) -> TextureMipmapFilter {
        TextureMipmapFilter::Filter(filter)
    }
}

gl_enum! {
    pub gl_enum TextureWrapMode {
        ClampToEdge as CLAMP_TO_EDGE = gl::CLAMP_TO_EDGE,
        MirroredRepeat as MIRRORED_REPEAT = gl::MIRRORED_REPEAT,
        Repeat as REPEAT = gl::REPEAT
    }
}

unsafe fn _tex_parameter_iv(target: TextureBindingTarget,
                            pname: GLenum,
                            params: *const GLint)
{
    gl::TexParameteriv(target.gl_enum(), pname, params);
    dbg_gl_sanity_check! {
        GLError::InvalidEnum => "`target` or `pname` is not an accepted defined value, or `params` should have defined a symbolic constant and does not",
        _ => "Unknown error"
    }
}

unsafe fn _tex_image_2d<T: ImageTargetType>(target: T,
                                            level: u32,
                                            internal_format: TextelFormat,
                                            width: u32,
                                            height: u32,
                                            border: u32,
                                            format: ImageFormat,
                                            image_ptr: *const u8) {
    debug_assert!(internal_format == format.textel_format);
    gl::TexImage2D(target.gl_enum(),
                   level as GLint,
                   internal_format.gl_enum() as GLint,
                   width as GLint,
                   height as GLint,
                   border as GLint,
                   format.textel_format.gl_enum(),
                   format.textel_type.gl_enum(),
                   image_ptr as *const GLvoid);
    dbg_gl_sanity_check! {
        GLError::InvalidEnum => "`target`, `format`, or `type` is not an accepted value",
        GLError::InvalidValue => "`target`, `level`, `internalformat`, `width`, `height`, or `border` is an invalid value",
        GLError::InvalidOperation => "`format` conflicts with either `internalformat` or `type`",
        _ => "Unknown error"
    }
}

pub trait TextureBinding {
    type TextureType: TextureType;

    fn target() -> TextureBindingTarget {
        Self::TextureType::target()
    }

    fn set_min_filter<F: Into<TextureMipmapFilter>>(&mut self, filter: F) {
        let gl_int = filter.into().gl_enum() as GLint;
        unsafe {
            _tex_parameter_iv(Self::target(),
                              gl::TEXTURE_MIN_FILTER,
                              &gl_int as *const GLint);
        }
    }

    fn set_mag_filter(&mut self, filter: TextureFilter) {
        let gl_int = filter.gl_enum() as GLint;
        unsafe {
            _tex_parameter_iv(Self::target(),
                              gl::TEXTURE_MAG_FILTER,
                              &gl_int as *const GLint);
        }
    }

    fn set_wrap_s(&mut self, wrap_mode: TextureWrapMode) {
        let gl_int = wrap_mode.gl_enum() as GLint;
        unsafe {
            _tex_parameter_iv(Self::target(),
                              gl::TEXTURE_WRAP_S,
                              &gl_int as *const GLint);
        }
    }

    fn set_wrap_t(&mut self, wrap_mode: TextureWrapMode) {
        let gl_int = wrap_mode.gl_enum() as GLint;
        unsafe {
            _tex_parameter_iv(Self::target(),
                              gl::TEXTURE_WRAP_T,
                              &gl_int as *const GLint);
        }
    }

    fn image_2d<I>(&mut self,
                   target: <Self::TextureType as TextureType>::ImageTargetType,
                   level: u32,
                   img: &I)
        where I: Image2d
    {
        unsafe {
            _tex_image_2d(target,
                          level,
                          img.format().textel_format,
                          img.width() as u32,
                          img.height() as u32,
                          0,
                          img.format(),
                          img.textel_bytes().as_ptr());
        }
    }

    fn image_2d_empty<T: ImageTargetType>(&mut self,
                                          target: T,
                                          level: u32,
                                          format: ImageFormat,
                                          width: u32,
                                          height: u32)
    {
        unsafe {
            _tex_image_2d(target,
                          level,
                          format.textel_format,
                          width,
                          height,
                          0,
                          format,
                          ptr::null());
        }
    }
}

pub struct Texture2dBinding<'a> {
    phantom: PhantomData<&'a mut Texture2d>
}

impl<'a> TextureBinding for Texture2dBinding<'a> {
    type TextureType = Tx2d;
}

pub struct TextureCubeMapBinding<'a> {
    phantom: PhantomData<&'a mut TextureCubeMap>
}

impl<'a> TextureBinding for TextureCubeMapBinding<'a> {
    type TextureType = TxCubeMap;
}

unsafe fn _bind_texture<T: TextureType>(texture: &mut Texture<T>) {
    gl::BindTexture(T::target().gl_enum(), texture.gl_id());
    dbg_gl_error! {
        GLError::InvalidEnum => "`target` is not one of the allowed values",
        GLError::InvalidOperation => "`texture` was created with a target that doesn't match `target`",
        _ => "Unknown error"
    }
}

pub struct Texture2dBinder;
impl Texture2dBinder {
    pub fn bind(&mut self, texture: &mut Texture2d) -> Texture2dBinding {
        unsafe {
            _bind_texture(texture);
        }
        Texture2dBinding { phantom: PhantomData }
    }
}

pub struct TextureCubeMapBinder;
impl TextureCubeMapBinder {
    pub fn bind(&mut self, texture: &mut TextureCubeMap)
        -> TextureCubeMapBinding
    {
        unsafe {
            _bind_texture(texture);
        }
        TextureCubeMapBinding { phantom: PhantomData }
    }
}
<commit_msg>Don't use `gl_enum!` for `TextureBindingTarget`<commit_after>use std::ptr;
use std::marker::PhantomData;
use gl;
use gl::types::*;
use context::Context;
use image_data::{Image2d, TextelFormat, ImageFormat};
use types::GLError;

pub struct Texture<T: TextureType> {
    gl_id: GLuint,
    phantom: PhantomData<*mut T>
}
pub type Texture2d = Texture<Tx2d>;
pub type TextureCubeMap = Texture<TxCubeMap>;

impl<T: TextureType> Texture<T> {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl<T: TextureType> Drop for Texture<T> {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteTextures(1, &self.gl_id as *const GLuint);
        }
    }
}

impl Context {
    pub unsafe fn gen_texture<T: TextureType>(&self) -> Texture<T> {
        let mut id : GLuint =  0;

        gl::GenTextures(1, &mut id as *mut GLuint);
        dbg_gl_sanity_check! {
            GLError::InvalidValue => "`n` is negative",
            _ => "Unknown error"
        }

        Texture {
            gl_id: id,
            phantom: PhantomData
        }
    }
}

pub trait ImageTargetType {
    fn gl_enum(&self) -> GLenum;
}

pub trait TextureType {
    type ImageTargetType: ImageTargetType;

    fn target() -> TextureBindingTarget;
}

pub struct Tx2d;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Tx2dImageTarget {
    Texture2d = gl::TEXTURE_2D as isize
}

impl ImageTargetType for Tx2dImageTarget {
    fn gl_enum(&self) -> GLenum {
        *self as GLenum
    }
}

impl TextureType for Tx2d {
    type ImageTargetType = Tx2dImageTarget;

    fn target() -> TextureBindingTarget {
        TextureBindingTarget::Texture2d
    }
}

pub struct TxCubeMap;

gl_enum! {
    pub gl_enum TxCubeMapImageTarget {
        CubeMapPositiveX as TEXTURE_CUBE_MAP_POSITIVE_X =
            gl::TEXTURE_CUBE_MAP_POSITIVE_X,
        CubeMapNegativeX as TEXTURE_CUBE_MAP_NEGATIVE_X =
            gl::TEXTURE_CUBE_MAP_NEGATIVE_X,
        CubeMapPositiveY as TEXTURE_CUBE_MAP_POSITIVE_Y =
            gl::TEXTURE_CUBE_MAP_POSITIVE_Y,
        CubeMapNegativeY as TEXTURE_CUBE_MAP_NEGATIVE_Y =
            gl::TEXTURE_CUBE_MAP_NEGATIVE_Y,
        CubeMapPositiveZ as TEXTURE_CUBE_MAP_POSITIVE_Z =
            gl::TEXTURE_CUBE_MAP_POSITIVE_Z,
        CubeMapNegativeZ as TEXTURE_CUBE_MAP_NEGATIVE_Z =
            gl::TEXTURE_CUBE_MAP_NEGATIVE_Z
    }
}

impl ImageTargetType for TxCubeMapImageTarget {
    fn gl_enum(&self) -> GLenum {
        self.gl_enum()
    }
}

impl TextureType for TxCubeMap {
    type ImageTargetType = TxCubeMapImageTarget;

    fn target() -> TextureBindingTarget {
        TextureBindingTarget::TextureCubeMap
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TextureBindingTarget {
    Texture2d = gl::TEXTURE_2D as isize,
    TextureCubeMap = gl::TEXTURE_CUBE_MAP as isize
}

impl TextureBindingTarget {
    pub fn gl_enum(&self) -> GLenum {
        *self as GLenum
    }
}

// TODO: Use type refinements someday...
#[derive(Debug, Clone, Copy)]
pub enum TextureFilter {
    Nearest,
    Linear
}

#[derive(Debug, Clone, Copy)]
pub enum TextureMipmapFilter {
    Filter(TextureFilter),
    MipmapFilter { criterion: TextureFilter, mipmap: TextureFilter }
}

pub const NEAREST : TextureFilter = TextureFilter::Nearest;
pub const LINEAR : TextureFilter = TextureFilter::Linear;
pub const NEAREST_MIPMAP_NEAREST : TextureMipmapFilter =
    TextureMipmapFilter::MipmapFilter {
        criterion: TextureFilter::Nearest,
        mipmap: TextureFilter::Nearest
    };
pub const LINEAR_MIPMAP_NEAREST : TextureMipmapFilter =
    TextureMipmapFilter::MipmapFilter {
        criterion: TextureFilter::Linear,
        mipmap: TextureFilter::Nearest
    };
pub const NEAREST_MIPMAP_LINEAR : TextureMipmapFilter =
    TextureMipmapFilter::MipmapFilter {
        criterion: TextureFilter::Nearest,
        mipmap: TextureFilter::Linear
    };
pub const LINEAR_MIPMAP_LINEAR : TextureMipmapFilter =
    TextureMipmapFilter::MipmapFilter {
        criterion: TextureFilter::Linear,
        mipmap: TextureFilter::Linear
    };

#[allow(dead_code)]
impl TextureFilter {
    fn from_gl(gl_enum: GLenum) -> Result<Self, ()> {
        match gl_enum {
            gl::NEAREST => { Ok(self::NEAREST) },
            gl::LINEAR => { Ok(self::LINEAR) },
            _ => { Err(()) }
        }
    }

    fn gl_enum(&self) -> GLenum {
        match *self {
            self::NEAREST => gl::NEAREST,
            self::LINEAR => gl::LINEAR
        }
    }
}

#[allow(dead_code)]
impl TextureMipmapFilter {
    fn from_gl(gl_enum: GLenum) -> Result<Self, ()> {
        match gl_enum {
            gl::NEAREST => { Ok(TextureMipmapFilter::Filter(self::NEAREST)) },
            gl::LINEAR => { Ok(TextureMipmapFilter::Filter(self::LINEAR)) },
            gl::NEAREST_MIPMAP_NEAREST => { Ok(self::NEAREST_MIPMAP_NEAREST) },
            gl::LINEAR_MIPMAP_NEAREST => { Ok(self::LINEAR_MIPMAP_NEAREST) },
            gl::NEAREST_MIPMAP_LINEAR => { Ok(self::NEAREST_MIPMAP_LINEAR) },
            gl::LINEAR_MIPMAP_LINEAR => { Ok(self::LINEAR_MIPMAP_LINEAR) },
            _ => { Err(()) }
        }
    }

    fn gl_enum(&self) -> GLenum {
        match *self {
            TextureMipmapFilter::Filter(self::LINEAR) => { gl::LINEAR },
            TextureMipmapFilter::Filter(self::NEAREST) => { gl::NEAREST },
            self::NEAREST_MIPMAP_NEAREST => { gl::NEAREST_MIPMAP_NEAREST },
            self::LINEAR_MIPMAP_NEAREST => { gl::LINEAR_MIPMAP_NEAREST },
            self::NEAREST_MIPMAP_LINEAR => { gl::NEAREST_MIPMAP_LINEAR },
            self::LINEAR_MIPMAP_LINEAR => { gl::LINEAR_MIPMAP_LINEAR }
        }
    }
}

impl From<TextureFilter> for TextureMipmapFilter {
    fn from(filter: TextureFilter) -> TextureMipmapFilter {
        TextureMipmapFilter::Filter(filter)
    }
}

gl_enum! {
    pub gl_enum TextureWrapMode {
        ClampToEdge as CLAMP_TO_EDGE = gl::CLAMP_TO_EDGE,
        MirroredRepeat as MIRRORED_REPEAT = gl::MIRRORED_REPEAT,
        Repeat as REPEAT = gl::REPEAT
    }
}

unsafe fn _tex_parameter_iv(target: TextureBindingTarget,
                            pname: GLenum,
                            params: *const GLint)
{
    gl::TexParameteriv(target.gl_enum(), pname, params);
    dbg_gl_sanity_check! {
        GLError::InvalidEnum => "`target` or `pname` is not an accepted defined value, or `params` should have defined a symbolic constant and does not",
        _ => "Unknown error"
    }
}

unsafe fn _tex_image_2d<T: ImageTargetType>(target: T,
                                            level: u32,
                                            internal_format: TextelFormat,
                                            width: u32,
                                            height: u32,
                                            border: u32,
                                            format: ImageFormat,
                                            image_ptr: *const u8) {
    debug_assert!(internal_format == format.textel_format);
    gl::TexImage2D(target.gl_enum(),
                   level as GLint,
                   internal_format.gl_enum() as GLint,
                   width as GLint,
                   height as GLint,
                   border as GLint,
                   format.textel_format.gl_enum(),
                   format.textel_type.gl_enum(),
                   image_ptr as *const GLvoid);
    dbg_gl_sanity_check! {
        GLError::InvalidEnum => "`target`, `format`, or `type` is not an accepted value",
        GLError::InvalidValue => "`target`, `level`, `internalformat`, `width`, `height`, or `border` is an invalid value",
        GLError::InvalidOperation => "`format` conflicts with either `internalformat` or `type`",
        _ => "Unknown error"
    }
}

pub trait TextureBinding {
    type TextureType: TextureType;

    fn target() -> TextureBindingTarget {
        Self::TextureType::target()
    }

    fn set_min_filter<F: Into<TextureMipmapFilter>>(&mut self, filter: F) {
        let gl_int = filter.into().gl_enum() as GLint;
        unsafe {
            _tex_parameter_iv(Self::target(),
                              gl::TEXTURE_MIN_FILTER,
                              &gl_int as *const GLint);
        }
    }

    fn set_mag_filter(&mut self, filter: TextureFilter) {
        let gl_int = filter.gl_enum() as GLint;
        unsafe {
            _tex_parameter_iv(Self::target(),
                              gl::TEXTURE_MAG_FILTER,
                              &gl_int as *const GLint);
        }
    }

    fn set_wrap_s(&mut self, wrap_mode: TextureWrapMode) {
        let gl_int = wrap_mode.gl_enum() as GLint;
        unsafe {
            _tex_parameter_iv(Self::target(),
                              gl::TEXTURE_WRAP_S,
                              &gl_int as *const GLint);
        }
    }

    fn set_wrap_t(&mut self, wrap_mode: TextureWrapMode) {
        let gl_int = wrap_mode.gl_enum() as GLint;
        unsafe {
            _tex_parameter_iv(Self::target(),
                              gl::TEXTURE_WRAP_T,
                              &gl_int as *const GLint);
        }
    }

    fn image_2d<I>(&mut self,
                   target: <Self::TextureType as TextureType>::ImageTargetType,
                   level: u32,
                   img: &I)
        where I: Image2d
    {
        unsafe {
            _tex_image_2d(target,
                          level,
                          img.format().textel_format,
                          img.width() as u32,
                          img.height() as u32,
                          0,
                          img.format(),
                          img.textel_bytes().as_ptr());
        }
    }

    fn image_2d_empty<T: ImageTargetType>(&mut self,
                                          target: T,
                                          level: u32,
                                          format: ImageFormat,
                                          width: u32,
                                          height: u32)
    {
        unsafe {
            _tex_image_2d(target,
                          level,
                          format.textel_format,
                          width,
                          height,
                          0,
                          format,
                          ptr::null());
        }
    }
}

pub struct Texture2dBinding<'a> {
    phantom: PhantomData<&'a mut Texture2d>
}

impl<'a> TextureBinding for Texture2dBinding<'a> {
    type TextureType = Tx2d;
}

pub struct TextureCubeMapBinding<'a> {
    phantom: PhantomData<&'a mut TextureCubeMap>
}

impl<'a> TextureBinding for TextureCubeMapBinding<'a> {
    type TextureType = TxCubeMap;
}

unsafe fn _bind_texture<T: TextureType>(texture: &mut Texture<T>) {
    gl::BindTexture(T::target().gl_enum(), texture.gl_id());
    dbg_gl_error! {
        GLError::InvalidEnum => "`target` is not one of the allowed values",
        GLError::InvalidOperation => "`texture` was created with a target that doesn't match `target`",
        _ => "Unknown error"
    }
}

pub struct Texture2dBinder;
impl Texture2dBinder {
    pub fn bind(&mut self, texture: &mut Texture2d) -> Texture2dBinding {
        unsafe {
            _bind_texture(texture);
        }
        Texture2dBinding { phantom: PhantomData }
    }
}

pub struct TextureCubeMapBinder;
impl TextureCubeMapBinder {
    pub fn bind(&mut self, texture: &mut TextureCubeMap)
        -> TextureCubeMapBinding
    {
        unsafe {
            _bind_texture(texture);
        }
        TextureCubeMapBinding { phantom: PhantomData }
    }
}
<|endoftext|>


<commit_before>use std::ops::Add;
use std::marker::PhantomData;
use std::marker::Copy;

pub trait FletcherSum<T>
    : Add<Self> + From<T> + From<<Self as Add>::Output> + Copy {
    fn default_value() -> Self;
    fn max_chunk_size() -> usize;
    fn combine(lower: &Self, upper: &Self) -> Self;
    fn reduce(self) -> Self;
}

pub struct Fletcher<T, U> {
    a: T,
    b: T,
    phantom: PhantomData<U>,
}

impl<T, U> Fletcher<T, U>
where
    T: FletcherSum<U>,
    U: Copy,
{
    pub fn new() -> Fletcher<T, U> {
        Fletcher {
            a: T::default_value(),
            b: T::default_value(),
            phantom: PhantomData,
        }
    }

    pub fn update(&mut self, data: &Vec<U>) {
        let max_chunk_size = T::max_chunk_size();

        for chunk in data.chunks(max_chunk_size) {
            let mut intermediate_a = self.a;
            let mut intermediate_b = self.b;

            for byte in chunk {
                intermediate_a = T::from(intermediate_a + T::from(*byte));
                intermediate_b = T::from(intermediate_b + intermediate_a);
            }

            self.a = intermediate_a.reduce();
            self.b = intermediate_b.reduce();
        }

        self.a = self.a.reduce();
        self.b = self.b.reduce();
    }

    pub fn value(&self) -> T {
        T::combine(&self.a, &self.b)
    }
}
<commit_msg>Changed the update function to take in a slice rather than a Vector<commit_after>use std::ops::Add;
use std::marker::PhantomData;
use std::marker::Copy;

pub trait FletcherSum<T>
    : Add<Self> + From<T> + From<<Self as Add>::Output> + Copy {
    fn default_value() -> Self;
    fn max_chunk_size() -> usize;
    fn combine(lower: &Self, upper: &Self) -> Self;
    fn reduce(self) -> Self;
}

pub struct Fletcher<T, U> {
    a: T,
    b: T,
    phantom: PhantomData<U>,
}

impl<T, U> Fletcher<T, U>
where
    T: FletcherSum<U>,
    U: Copy,
{
    pub fn new() -> Fletcher<T, U> {
        Fletcher {
            a: T::default_value(),
            b: T::default_value(),
            phantom: PhantomData,
        }
    }

    pub fn update(&mut self, data: &[U]) {
        let max_chunk_size = T::max_chunk_size();

        for chunk in data.chunks(max_chunk_size) {
            let mut intermediate_a = self.a;
            let mut intermediate_b = self.b;

            for byte in chunk {
                intermediate_a = T::from(intermediate_a + T::from(*byte));
                intermediate_b = T::from(intermediate_b + intermediate_a);
            }

            self.a = intermediate_a.reduce();
            self.b = intermediate_b.reduce();
        }

        self.a = self.a.reduce();
        self.b = self.b.reduce();
    }

    pub fn value(&self) -> T {
        T::combine(&self.a, &self.b)
    }
}
<|endoftext|>