<commit_before>#![feature(rustc_private)]

extern crate env_logger;
extern crate getopts;
#[macro_use]
extern crate log;
extern crate log_settings;
extern crate miri;
extern crate rustc;
extern crate rustc_metadata;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_codegen_utils;
extern crate rustc_interface;
extern crate syntax;

use std::str::FromStr;
use std::env;

use hex::FromHexError;

use rustc_interface::interface;
use rustc::hir::def_id::LOCAL_CRATE;
use rustc_driver::Compilation;

struct MiriCompilerCalls {
    miri_config: miri::MiriConfig,
}

impl rustc_driver::Callbacks for MiriCompilerCalls {
    fn after_parsing(&mut self, compiler: &interface::Compiler) -> Compilation {
        let attr = (
            syntax::symbol::Symbol::intern("miri"),
            syntax::feature_gate::AttributeType::Whitelisted,
        );
        compiler.session().plugin_attributes.borrow_mut().push(attr);

        Compilation::Continue
    }

    fn after_analysis(&mut self, compiler: &interface::Compiler) -> Compilation {
        init_late_loggers();
        compiler.session().abort_if_errors();

        compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| {
            let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!");
            let mut config = self.miri_config.clone();

            // Add filename to `miri` arguments.
            config.args.insert(0, compiler.input().filestem().to_string());

            miri::eval_main(tcx, entry_def_id, config);
        });

        compiler.session().abort_if_errors();

        Compilation::Stop
    }
}

fn init_early_loggers() {
    // Note that our `extern crate log` is *not* the same as rustc's; as a result, we have to
    // initialize them both, and we always initialize `miri`'s first.
    let env = env_logger::Env::new().filter("MIRI_LOG").write_style("MIRI_LOG_STYLE");
    env_logger::init_from_env(env);
    // We only initialize `rustc` if the env var is set (so the user asked for it).
    // If it is not set, we avoid initializing now so that we can initialize
    // later with our custom settings, and *not* log anything for what happens before
    // `miri` gets started.
    if env::var("RUSTC_LOG").is_ok() {
        rustc_driver::init_rustc_env_logger();
    }
}

fn init_late_loggers() {
    // We initialize loggers right before we start evaluation. We overwrite the `RUSTC_LOG`
    // env var if it is not set, control it based on `MIRI_LOG`.
    if let Ok(var) = env::var("MIRI_LOG") {
        if env::var("RUSTC_LOG").is_err() {
            // We try to be a bit clever here: if `MIRI_LOG` is just a single level
            // used for everything, we only apply it to the parts of rustc that are
            // CTFE-related. Otherwise, we use it verbatim for `RUSTC_LOG`.
            // This way, if you set `MIRI_LOG=trace`, you get only the right parts of
            // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_mir::interpret=debug`.
            if log::Level::from_str(&var).is_ok() {
                env::set_var("RUSTC_LOG",
                    &format!("rustc::mir::interpret={0},rustc_mir::interpret={0}", var));
            } else {
                env::set_var("RUSTC_LOG", &var);
            }
            rustc_driver::init_rustc_env_logger();
        }
    }

    // If `MIRI_BACKTRACE` is set and `RUSTC_CTFE_BACKTRACE` is not, set `RUSTC_CTFE_BACKTRACE`.
    // Do this late, so we ideally only apply this to Miri's errors.
    if let Ok(var) = env::var("MIRI_BACKTRACE") {
        if env::var("RUSTC_CTFE_BACKTRACE") == Err(env::VarError::NotPresent) {
            env::set_var("RUSTC_CTFE_BACKTRACE", &var);
        }
    }
}

/// Returns the "default sysroot" that Miri will use if no `--sysroot` flag is set.
/// Should be a compile-time constant.
fn compile_time_sysroot() -> Option<String> {
    if option_env!("RUSTC_STAGE").is_some() {
        // This is being built as part of rustc, and gets shipped with rustup.
        // We can rely on the sysroot computation in librustc.
        return None;
    }
    // For builds outside rustc, we need to ensure that we got a sysroot
    // that gets used as a default.  The sysroot computation in librustc would
    // end up somewhere in the build dir.
    // Taken from PR <https://github.com/Manishearth/rust-clippy/pull/911>.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    Some(match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => {
            option_env!("RUST_SYSROOT")
                .expect("To build Miri without rustup, set the `RUST_SYSROOT` env var at build time")
                .to_owned()
        }
    })
}

fn main() {
    init_early_loggers();

    // Parse our arguments and split them across `rustc` and `miri`.
    let mut validate = true;
    let mut communicate = false;
    let mut seed: Option<u64> = None;
    let mut rustc_args = vec![];
    let mut miri_args = vec![];
    let mut after_dashdash = false;
    let mut excluded_env_vars = vec![];
    for arg in std::env::args() {
        if rustc_args.is_empty() {
            // Very first arg: for `rustc`.
            rustc_args.push(arg);
        }
        else if after_dashdash {
            // Everything that comes after are `miri` args.
            miri_args.push(arg);
        } else {
            match arg.as_str() {
                "-Zmiri-disable-validation" => {
                    validate = false;
                },
                "-Zmiri-disable-isolation" => {
                    communicate = true;
                },
                "--" => {
                    after_dashdash = true;
                }
                arg if arg.starts_with("-Zmiri-seed=") => {
                    if seed.is_some() {
                        panic!("Cannot specify -Zmiri-seed multiple times!");
                    }
                    let seed_raw = hex::decode(arg.trim_start_matches("-Zmiri-seed="))
                        .unwrap_or_else(|err| match err {
                            FromHexError::InvalidHexCharacter { .. } => panic!(
                                "-Zmiri-seed should only contain valid hex digits [0-9a-fA-F]"
                            ),
                            FromHexError::OddLength => panic!("-Zmiri-seed should have an even number of digits"),
                            err => panic!("Unknown error decoding -Zmiri-seed as hex: {:?}", err),
                        });
                    if seed_raw.len() > 8 {
                        panic!(format!("-Zmiri-seed must be at most 8 bytes, was {}", seed_raw.len()));
                    }

                    let mut bytes = [0; 8];
                    bytes[..seed_raw.len()].copy_from_slice(&seed_raw);
                    seed = Some(u64::from_be_bytes(bytes));

                },
                arg if arg.starts_with("-Zmiri-env-exclude=") => {
                    excluded_env_vars.push(arg.trim_start_matches("-Zmiri-env-exclude=").to_owned());
                },
                _ => {
                    rustc_args.push(arg);
                }
            }
        }
    }

    // Determine sysroot if needed.  Make sure we always call `compile_time_sysroot`
    // as that also does some sanity-checks of the environment we were built in.
    // FIXME: Ideally we'd turn a bad build env into a compile-time error, but
    // CTFE does not seem powerful enough for that yet.
    if let Some(sysroot) = compile_time_sysroot() {
        let sysroot_flag = "--sysroot";
        if !rustc_args.iter().any(|e| e == sysroot_flag) {
            // We need to overwrite the default that librustc would compute.
            rustc_args.push(sysroot_flag.to_owned());
            rustc_args.push(sysroot);
        }
    }

    // Finally, add the default flags all the way in the beginning, but after the binary name.
    rustc_args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string));

    debug!("rustc arguments: {:?}", rustc_args);
    debug!("miri arguments: {:?}", miri_args);
    let miri_config = miri::MiriConfig {
        validate,
        communicate,
        excluded_env_vars,
        seed,
        args: miri_args,
    };
    let result = rustc_driver::catch_fatal_errors(move || {
        rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None)
    }).and_then(|result| result);
    std::process::exit(result.is_err() as i32);
}
<commit_msg>install ICE hook<commit_after>#![feature(rustc_private)]

extern crate env_logger;
extern crate getopts;
#[macro_use]
extern crate log;
extern crate log_settings;
extern crate miri;
extern crate rustc;
extern crate rustc_metadata;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_codegen_utils;
extern crate rustc_interface;
extern crate syntax;

use std::str::FromStr;
use std::env;

use hex::FromHexError;

use rustc_interface::interface;
use rustc::hir::def_id::LOCAL_CRATE;
use rustc_driver::Compilation;

struct MiriCompilerCalls {
    miri_config: miri::MiriConfig,
}

impl rustc_driver::Callbacks for MiriCompilerCalls {
    fn after_parsing(&mut self, compiler: &interface::Compiler) -> Compilation {
        let attr = (
            syntax::symbol::Symbol::intern("miri"),
            syntax::feature_gate::AttributeType::Whitelisted,
        );
        compiler.session().plugin_attributes.borrow_mut().push(attr);

        Compilation::Continue
    }

    fn after_analysis(&mut self, compiler: &interface::Compiler) -> Compilation {
        init_late_loggers();
        compiler.session().abort_if_errors();

        compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| {
            let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!");
            let mut config = self.miri_config.clone();

            // Add filename to `miri` arguments.
            config.args.insert(0, compiler.input().filestem().to_string());

            miri::eval_main(tcx, entry_def_id, config);
        });

        compiler.session().abort_if_errors();

        Compilation::Stop
    }
}

fn init_early_loggers() {
    // Note that our `extern crate log` is *not* the same as rustc's; as a result, we have to
    // initialize them both, and we always initialize `miri`'s first.
    let env = env_logger::Env::new().filter("MIRI_LOG").write_style("MIRI_LOG_STYLE");
    env_logger::init_from_env(env);
    // We only initialize `rustc` if the env var is set (so the user asked for it).
    // If it is not set, we avoid initializing now so that we can initialize
    // later with our custom settings, and *not* log anything for what happens before
    // `miri` gets started.
    if env::var("RUSTC_LOG").is_ok() {
        rustc_driver::init_rustc_env_logger();
    }
}

fn init_late_loggers() {
    // We initialize loggers right before we start evaluation. We overwrite the `RUSTC_LOG`
    // env var if it is not set, control it based on `MIRI_LOG`.
    if let Ok(var) = env::var("MIRI_LOG") {
        if env::var("RUSTC_LOG").is_err() {
            // We try to be a bit clever here: if `MIRI_LOG` is just a single level
            // used for everything, we only apply it to the parts of rustc that are
            // CTFE-related. Otherwise, we use it verbatim for `RUSTC_LOG`.
            // This way, if you set `MIRI_LOG=trace`, you get only the right parts of
            // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_mir::interpret=debug`.
            if log::Level::from_str(&var).is_ok() {
                env::set_var("RUSTC_LOG",
                    &format!("rustc::mir::interpret={0},rustc_mir::interpret={0}", var));
            } else {
                env::set_var("RUSTC_LOG", &var);
            }
            rustc_driver::init_rustc_env_logger();
        }
    }

    // If `MIRI_BACKTRACE` is set and `RUSTC_CTFE_BACKTRACE` is not, set `RUSTC_CTFE_BACKTRACE`.
    // Do this late, so we ideally only apply this to Miri's errors.
    if let Ok(var) = env::var("MIRI_BACKTRACE") {
        if env::var("RUSTC_CTFE_BACKTRACE") == Err(env::VarError::NotPresent) {
            env::set_var("RUSTC_CTFE_BACKTRACE", &var);
        }
    }
}

/// Returns the "default sysroot" that Miri will use if no `--sysroot` flag is set.
/// Should be a compile-time constant.
fn compile_time_sysroot() -> Option<String> {
    if option_env!("RUSTC_STAGE").is_some() {
        // This is being built as part of rustc, and gets shipped with rustup.
        // We can rely on the sysroot computation in librustc.
        return None;
    }
    // For builds outside rustc, we need to ensure that we got a sysroot
    // that gets used as a default.  The sysroot computation in librustc would
    // end up somewhere in the build dir.
    // Taken from PR <https://github.com/Manishearth/rust-clippy/pull/911>.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    Some(match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => {
            option_env!("RUST_SYSROOT")
                .expect("To build Miri without rustup, set the `RUST_SYSROOT` env var at build time")
                .to_owned()
        }
    })
}

fn main() {
    init_early_loggers();

    // Parse our arguments and split them across `rustc` and `miri`.
    let mut validate = true;
    let mut communicate = false;
    let mut seed: Option<u64> = None;
    let mut rustc_args = vec![];
    let mut miri_args = vec![];
    let mut after_dashdash = false;
    let mut excluded_env_vars = vec![];
    for arg in std::env::args() {
        if rustc_args.is_empty() {
            // Very first arg: for `rustc`.
            rustc_args.push(arg);
        }
        else if after_dashdash {
            // Everything that comes after are `miri` args.
            miri_args.push(arg);
        } else {
            match arg.as_str() {
                "-Zmiri-disable-validation" => {
                    validate = false;
                },
                "-Zmiri-disable-isolation" => {
                    communicate = true;
                },
                "--" => {
                    after_dashdash = true;
                }
                arg if arg.starts_with("-Zmiri-seed=") => {
                    if seed.is_some() {
                        panic!("Cannot specify -Zmiri-seed multiple times!");
                    }
                    let seed_raw = hex::decode(arg.trim_start_matches("-Zmiri-seed="))
                        .unwrap_or_else(|err| match err {
                            FromHexError::InvalidHexCharacter { .. } => panic!(
                                "-Zmiri-seed should only contain valid hex digits [0-9a-fA-F]"
                            ),
                            FromHexError::OddLength => panic!("-Zmiri-seed should have an even number of digits"),
                            err => panic!("Unknown error decoding -Zmiri-seed as hex: {:?}", err),
                        });
                    if seed_raw.len() > 8 {
                        panic!(format!("-Zmiri-seed must be at most 8 bytes, was {}", seed_raw.len()));
                    }

                    let mut bytes = [0; 8];
                    bytes[..seed_raw.len()].copy_from_slice(&seed_raw);
                    seed = Some(u64::from_be_bytes(bytes));

                },
                arg if arg.starts_with("-Zmiri-env-exclude=") => {
                    excluded_env_vars.push(arg.trim_start_matches("-Zmiri-env-exclude=").to_owned());
                },
                _ => {
                    rustc_args.push(arg);
                }
            }
        }
    }

    // Determine sysroot if needed.  Make sure we always call `compile_time_sysroot`
    // as that also does some sanity-checks of the environment we were built in.
    // FIXME: Ideally we'd turn a bad build env into a compile-time error, but
    // CTFE does not seem powerful enough for that yet.
    if let Some(sysroot) = compile_time_sysroot() {
        let sysroot_flag = "--sysroot";
        if !rustc_args.iter().any(|e| e == sysroot_flag) {
            // We need to overwrite the default that librustc would compute.
            rustc_args.push(sysroot_flag.to_owned());
            rustc_args.push(sysroot);
        }
    }

    // Finally, add the default flags all the way in the beginning, but after the binary name.
    rustc_args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string));

    debug!("rustc arguments: {:?}", rustc_args);
    debug!("miri arguments: {:?}", miri_args);
    let miri_config = miri::MiriConfig {
        validate,
        communicate,
        excluded_env_vars,
        seed,
        args: miri_args,
    };
    rustc_driver::install_ice_hook();
    let result = rustc_driver::catch_fatal_errors(move || {
        rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None)
    }).and_then(|result| result);
    std::process::exit(result.is_err() as i32);
}
<|endoftext|>


<commit_before>// Copyright © 2015, Peter Atashian
// Licensed under the MIT License <LICENSE.md>
#![feature(collections, env, io, process, std_misc)]

extern crate "winapi" as win;
extern crate "kernel32-sys" as k32;

use std::env::{args, current_dir, set_exit_status};
use std::ffi::{AsOsStr};
use std::io::{Error};
use std::os::windows::prelude::*;
use std::process::{Command};
use std::ptr::{null_mut};

static mut job_handle: win::HANDLE = 0 as win::HANDLE;

extern "system" fn handler(_: win::DWORD) -> win::BOOL {
    // If we get any sort of signal, just kill the job object
    assert!(unsafe { k32::TerminateJobObject(job_handle, 273) } != 0,
        "Failed to terminate job object: {}", Error::last_os_error());
    win::TRUE
}
fn main() {
    // We use the current directory as the job object name
    // This way we can clean up job objects lingering from previous builds
    let dir = current_dir().unwrap();
    let name: Vec<_> = dir.as_os_str().encode_wide().collect();
    // Replace \ with /, otherwise it interprets the name as a path
    let name = name.map_in_place(|c| if c == '\\' as u16 { '/' as u16 } else { c });
    let mut handle = unsafe { k32::CreateJobObjectW(null_mut(), name.as_ptr()) };
    assert!(handle != null_mut(), "Failed to create job object: {}", Error::last_os_error());
    if unsafe { k32::GetLastError() } == win::ERROR_ALREADY_EXISTS {
        // If there is a previous job object, kill it and then create a new one
        assert!(unsafe { k32::TerminateJobObject(handle, 9001) } != 0,
            "Failed to terminate existing job object: {}", Error::last_os_error());
        // We have to sleep otherwise this process might get killed in the above termination
        unsafe { k32::Sleep(1000) };
        handle = unsafe { k32::CreateJobObjectW(null_mut(), name.as_ptr()) };
        assert!(handle != null_mut(), "Failed to recreate job object: {}", Error::last_os_error());
    }
    unsafe { job_handle = handle };
    let process = unsafe { k32::GetCurrentProcess() };
    // Everything created from this process will be part of the job object
    assert!(unsafe { k32::AssignProcessToJobObject(handle, process) } != 0,
        "Failed to assign process to job object: {}", Error::last_os_error());
    // Set up a signal handler to kill the job object if things go south
    assert!(unsafe { k32::SetConsoleCtrlHandler(handler, win::TRUE) } != 0,
        "Failed to set signal handler: {}", Error::last_os_error());
    let args: Vec<_> = args().collect();
    // Actually spawn the command you really wanted
    let status = Command::new(&args[1]).args(&args[2..]).status().unwrap();
    set_exit_status(status.code().unwrap())
}
<commit_msg>Also terminate anything that is left when dojob exits normally<commit_after>// Copyright © 2015, Peter Atashian
// Licensed under the MIT License <LICENSE.md>
#![feature(collections, env, io, process, std_misc)]

extern crate "winapi" as win;
extern crate "kernel32-sys" as k32;

use std::env::{args, current_dir, set_exit_status};
use std::ffi::{AsOsStr};
use std::io::{Error};
use std::os::windows::prelude::*;
use std::process::{Command};
use std::ptr::{null_mut};

static mut job_handle: win::HANDLE = 0 as win::HANDLE;

extern "system" fn handler(_: win::DWORD) -> win::BOOL {
    // If we get any sort of signal, just kill the job object
    assert!(unsafe { k32::TerminateJobObject(job_handle, 273) } != 0,
        "Failed to terminate job object: {}", Error::last_os_error());
    win::TRUE
}
fn main() {
    // We use the current directory as the job object name
    // This way we can clean up job objects lingering from previous builds
    let dir = current_dir().unwrap();
    let name: Vec<_> = dir.as_os_str().encode_wide().collect();
    // Replace \ with /, otherwise it interprets the name as a path
    let name = name.map_in_place(|c| if c == '\\' as u16 { '/' as u16 } else { c });
    let mut handle = unsafe { k32::CreateJobObjectW(null_mut(), name.as_ptr()) };
    assert!(handle != null_mut(), "Failed to create job object: {}", Error::last_os_error());
    if unsafe { k32::GetLastError() } == win::ERROR_ALREADY_EXISTS {
        // If there is a previous job object, kill it and then create a new one
        assert!(unsafe { k32::TerminateJobObject(handle, 9001) } != 0,
            "Failed to terminate existing job object: {}", Error::last_os_error());
        // We have to sleep otherwise this process might get killed in the above termination
        unsafe { k32::Sleep(1000) };
        handle = unsafe { k32::CreateJobObjectW(null_mut(), name.as_ptr()) };
        assert!(handle != null_mut(), "Failed to recreate job object: {}", Error::last_os_error());
    }
    unsafe { job_handle = handle };
    let process = unsafe { k32::GetCurrentProcess() };
    // Everything created from this process will be part of the job object
    assert!(unsafe { k32::AssignProcessToJobObject(handle, process) } != 0,
        "Failed to assign process to job object: {}", Error::last_os_error());
    // Set up a signal handler to kill the job object if things go south
    assert!(unsafe { k32::SetConsoleCtrlHandler(handler, win::TRUE) } != 0,
        "Failed to set signal handler: {}", Error::last_os_error());
    let args: Vec<_> = args().collect();
    // Actually spawn the command you really wanted
    let status = Command::new(&args[1]).args(&args[2..]).status().unwrap();
    assert!(unsafe { k32::TerminateJobObject(handle, 666) } != 0,
        "Failed to terminate job object leftovers: {}", Error::last_os_error());
    set_exit_status(status.code().unwrap())
}
<|endoftext|>


<commit_before>#![feature(drain, slice_patterns)]

extern crate glium;
use glium::DisplayBuild;

extern crate fps_counter;
extern crate time;

use std::cell::{Cell, RefCell};
use std::path::PathBuf;

#[macro_use]
extern crate r3;
pub use r3::{cfg, ui};
use r3::glyph::GlyphCache;

use ui::Px;
use ui::color::Scheme;
use ui::draw::DrawCx;
use ui::event::Dispatch;
use ui::tab::Tab;
use ui::text::FontFaces;

fn main() {
    r3::ide::rustc::init_env();

    let display = glium::glutin::WindowBuilder::new()
        .with_dimensions(800, 600)
        .with_title(String::from("rid3"))
        .build_glium()
        .unwrap();

    let renderer = &mut ui::render::Renderer::new(&display, FontFaces {
        regular: GlyphCache::from_data(include_bytes!("../../assets/NotoSans/NotoSans-Regular.ttf"), display.clone()).unwrap(),
        mono: GlyphCache::from_data(include_bytes!("../../assets/Hasklig/Hasklig-Regular.otf"), display.clone()).unwrap(),
        mono_bold: GlyphCache::from_data(include_bytes!("../../assets/Hasklig/Hasklig-Bold.otf"), display.clone()).unwrap()
    });

    let open_queue = RefCell::new(std::env::args().skip(1).map(PathBuf::from).collect::<Vec<_>>());
    let save_current = Cell::new(false);
    let run_current = Cell::new(false);
    let close_current = Cell::new(false);

    let tool_bar = tool_bar![
        ui::tool::Button::new("Open", || {
            open_queue.borrow_mut().extend(ui::dialog::open_file().into_iter())
        }),
        ui::tool::Button::new("Save", || save_current.set(true)),
        ui::tool::Button::new("Run", || {
            save_current.set(true);
            run_current.set(true);
        }),
        ui::tool::Button::new("Close", || close_current.set(true))
    ];
    let mut root = flow![down: tool_bar, ui::tab::Set::<ui::editor::Editor>::new()];

    let (mut x, mut y) = (0.0, 0.0);
    let mut key_tracker = ui::event::KeyTracker::default();
    let mut last_update = time::precise_time_ns();
    let mut cursor = ui::draw::MouseCursor::Default;
    let mut fps_counter = fps_counter::FPSCounter::new();
    let mut dirty = true;
    'main: loop {
        use glium::glutin::Event as E;
        use glium::glutin::{ElementState, MouseButton, MouseScrollDelta};

        for event in display.poll_events() {
            dirty |= match event {
                E::KeyboardInput(ElementState::Pressed, _, Some(key)) => {
                    dirty |= root.dispatch(&ui::event::KeyDown(key));
                    for e in key_tracker.down(key) {
                        dirty |= root.dispatch(&e);
                    }
                    false
                }
                E::KeyboardInput(ElementState::Released, _, Some(key)) => {
                    dirty |= root.dispatch(&ui::event::KeyUp(key));
                    for e in key_tracker.up(key) {
                        dirty |= root.dispatch(&e);
                    }
                    false
                }
                E::MouseInput(ElementState::Pressed, MouseButton::Left) => {
                    root.dispatch(&ui::event::MouseDown::new(x, y))
                }
                E::MouseInput(ElementState::Released, MouseButton::Left) => {
                    root.dispatch(&ui::event::MouseUp::new(x, y))
                }
                E::MouseMoved((nx, ny)) => {
                    x = nx as Px;
                    y = ny as Px;
                    root.dispatch(&ui::event::MouseMove::new(x, y))
                }
                // FIXME Convert lines into pixels, or vice-versa.
                E::MouseWheel(MouseScrollDelta::LineDelta(dx, dy)) |
                E::MouseWheel(MouseScrollDelta::PixelDelta(dx, dy)) => {
                    root.dispatch(&ui::event::MouseScroll::with(x, y,
                        ui::event::mouse::Scroll([dx as Px, dy as Px])))
                }
                E::ReceivedCharacter(c) => {
                    root.dispatch(&ui::event::TextInput(c))
                }
                E::Resized(..) => true,
                E::Closed => break 'main,
                _ => false
            }
        }

        let current = time::precise_time_ns();
        let dt = (current - last_update) as f32 / 1e9;
        dirty |= root.dispatch(&ui::event::Update(dt));
        for e in key_tracker.update(dt) {
            dirty |= root.dispatch(&e);
        }
        last_update = current;

        if save_current.get() {
            root.kids.1.current_mut().map(|e| e.save());
            save_current.set(false);
            dirty = true;
        }

        if run_current.get() {
            root.kids.1.current().map(|e| {
                println!("{}", std::iter::repeat('\n').take(200).collect::<String>());
                r3::ide::rustc::compile_and_run(e.path());
            });
            run_current.set(false);
        }

        if close_current.get() {
            let is_unsaved = root.kids.1.current().and_then(|e| {
                if e.is_saved() {
                    None
                } else {
                    Some(())
                }
            }).is_some();
            if is_unsaved {
                println!("Save file first!");
            } else {
                root.kids.1.remove();
                dirty = true;
            }
            close_current.set(false);
        }

        {
            let mut q = open_queue.borrow_mut();
            for file in q.drain(..) {
                root.kids.1.add(ui::editor::Editor::open(file));
                dirty = true;
            }
        }

        if dirty {
            let mut draw_cx = DrawCx::new(renderer, &display, display.draw());
            let [w, h] = draw_cx.dimensions();

            // TODO maybe integrate this with draw_cx?
            ui::layout::compute(&mut root, draw_cx.fonts(), w, h);

            draw_cx.clear(cfg::ColorScheme.background());
            draw_cx.draw(&root);

            let new_cursor = draw_cx.get_cursor();
            draw_cx.finish();

            if (new_cursor as usize) != (cursor as usize) {
                if !cfg!(windows) {
                    display.get_window().map(|w| w.set_cursor(new_cursor));
                }
                cursor = new_cursor;
            }

            let fps = fps_counter.tick();
            let tab_title = root.kids.1.current().map(|tab| tab.title());
            let title = format!("rid3: {} @ {}FPS", tab_title.as_ref().map_or("", |s| &s[..]), fps);
            display.get_window().map(|w| w.set_title(&title));

            dirty = false;
        } else {
            // Sleep for half a frame (assuming 60FPS).
            std::thread::sleep_ms(1000 / 120);
        }
    }
}
<commit_msg>Get the buffers ready so the first draw actually shows up on screen.<commit_after>#![feature(drain, slice_patterns)]

extern crate glium;
use glium::DisplayBuild;

extern crate fps_counter;
extern crate time;

use std::cell::{Cell, RefCell};
use std::path::PathBuf;

#[macro_use]
extern crate r3;
pub use r3::{cfg, ui};
use r3::glyph::GlyphCache;

use ui::Px;
use ui::color::Scheme;
use ui::draw::DrawCx;
use ui::event::Dispatch;
use ui::tab::Tab;
use ui::text::FontFaces;

fn main() {
    r3::ide::rustc::init_env();

    let display = glium::glutin::WindowBuilder::new()
        .with_dimensions(800, 600)
        .with_title(String::from("rid3"))
        .build_glium()
        .unwrap();

    let renderer = &mut ui::render::Renderer::new(&display, FontFaces {
        regular: GlyphCache::from_data(include_bytes!("../../assets/NotoSans/NotoSans-Regular.ttf"), display.clone()).unwrap(),
        mono: GlyphCache::from_data(include_bytes!("../../assets/Hasklig/Hasklig-Regular.otf"), display.clone()).unwrap(),
        mono_bold: GlyphCache::from_data(include_bytes!("../../assets/Hasklig/Hasklig-Bold.otf"), display.clone()).unwrap()
    });

    let open_queue = RefCell::new(std::env::args().skip(1).map(PathBuf::from).collect::<Vec<_>>());
    let save_current = Cell::new(false);
    let run_current = Cell::new(false);
    let close_current = Cell::new(false);

    let tool_bar = tool_bar![
        ui::tool::Button::new("Open", || {
            open_queue.borrow_mut().extend(ui::dialog::open_file().into_iter())
        }),
        ui::tool::Button::new("Save", || save_current.set(true)),
        ui::tool::Button::new("Run", || {
            save_current.set(true);
            run_current.set(true);
        }),
        ui::tool::Button::new("Close", || close_current.set(true))
    ];
    let mut root = flow![down: tool_bar, ui::tab::Set::<ui::editor::Editor>::new()];

    let (mut x, mut y) = (0.0, 0.0);
    let mut key_tracker = ui::event::KeyTracker::default();
    let mut last_update = time::precise_time_ns();
    let mut cursor = ui::draw::MouseCursor::Default;
    let mut fps_counter = fps_counter::FPSCounter::new();

    // Ready the buffers.
    display.draw().finish().unwrap();
    let mut dirty = true;
    'main: loop {
        use glium::glutin::Event as E;
        use glium::glutin::{ElementState, MouseButton, MouseScrollDelta};

        for event in display.poll_events() {
            dirty |= match event {
                E::KeyboardInput(ElementState::Pressed, _, Some(key)) => {
                    dirty |= root.dispatch(&ui::event::KeyDown(key));
                    for e in key_tracker.down(key) {
                        dirty |= root.dispatch(&e);
                    }
                    false
                }
                E::KeyboardInput(ElementState::Released, _, Some(key)) => {
                    dirty |= root.dispatch(&ui::event::KeyUp(key));
                    for e in key_tracker.up(key) {
                        dirty |= root.dispatch(&e);
                    }
                    false
                }
                E::MouseInput(ElementState::Pressed, MouseButton::Left) => {
                    root.dispatch(&ui::event::MouseDown::new(x, y))
                }
                E::MouseInput(ElementState::Released, MouseButton::Left) => {
                    root.dispatch(&ui::event::MouseUp::new(x, y))
                }
                E::MouseMoved((nx, ny)) => {
                    x = nx as Px;
                    y = ny as Px;
                    root.dispatch(&ui::event::MouseMove::new(x, y))
                }
                // FIXME Convert lines into pixels, or vice-versa.
                E::MouseWheel(MouseScrollDelta::LineDelta(dx, dy)) |
                E::MouseWheel(MouseScrollDelta::PixelDelta(dx, dy)) => {
                    root.dispatch(&ui::event::MouseScroll::with(x, y,
                        ui::event::mouse::Scroll([dx as Px, dy as Px])))
                }
                E::ReceivedCharacter(c) => {
                    root.dispatch(&ui::event::TextInput(c))
                }
                E::Resized(..) => true,
                E::Closed => break 'main,
                _ => false
            }
        }

        let current = time::precise_time_ns();
        let dt = (current - last_update) as f32 / 1e9;
        dirty |= root.dispatch(&ui::event::Update(dt));
        for e in key_tracker.update(dt) {
            dirty |= root.dispatch(&e);
        }
        last_update = current;

        if save_current.get() {
            root.kids.1.current_mut().map(|e| e.save());
            save_current.set(false);
            dirty = true;
        }

        if run_current.get() {
            root.kids.1.current().map(|e| {
                println!("{}", std::iter::repeat('\n').take(200).collect::<String>());
                r3::ide::rustc::compile_and_run(e.path());
            });
            run_current.set(false);
        }

        if close_current.get() {
            let is_unsaved = root.kids.1.current().and_then(|e| {
                if e.is_saved() {
                    None
                } else {
                    Some(())
                }
            }).is_some();
            if is_unsaved {
                println!("Save file first!");
            } else {
                root.kids.1.remove();
                dirty = true;
            }
            close_current.set(false);
        }

        {
            let mut q = open_queue.borrow_mut();
            for file in q.drain(..) {
                root.kids.1.add(ui::editor::Editor::open(file));
                dirty = true;
            }
        }

        if dirty {
            let mut draw_cx = DrawCx::new(renderer, &display, display.draw());
            let [w, h] = draw_cx.dimensions();

            // TODO maybe integrate this with draw_cx?
            ui::layout::compute(&mut root, draw_cx.fonts(), w, h);

            draw_cx.clear(cfg::ColorScheme.background());
            draw_cx.draw(&root);

            let new_cursor = draw_cx.get_cursor();
            draw_cx.finish();

            if (new_cursor as usize) != (cursor as usize) {
                if !cfg!(windows) {
                    display.get_window().map(|w| w.set_cursor(new_cursor));
                }
                cursor = new_cursor;
            }

            let fps = fps_counter.tick();
            let tab_title = root.kids.1.current().map(|tab| tab.title());
            let title = format!("rid3: {} @ {}FPS", tab_title.as_ref().map_or("", |s| &s[..]), fps);
            display.get_window().map(|w| w.set_title(&title));

            dirty = false;
        } else {
            // Sleep for half a frame (assuming 60FPS).
            std::thread::sleep_ms(1000 / 120);
        }
    }
}
<|endoftext|>


<commit_before>mod scanner;
mod ast;
mod pretty_printer;
mod parser;

extern crate itertools;

use std::env;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use pretty_printer::PrettyPrint;

#[derive(Debug)]
enum Error {
    IoError(String),
    ScannerError(scanner::ScannerError),
    ParserError(parser::ParseError),
}

fn run(source: &String) -> Result<(), Vec<Error>> {
    // TODO: change scan and parse to return both what they managed
    // to do and a list of the errors they encountered.
    // This way we can report all the issues at once instead of
    // requiring lots of attempts
    let (tokens, scanner_errors) = scanner::scan(source);
    let mut errors: Vec<Error> =
        scanner_errors.iter().map(|e| Error::ScannerError(e.clone())).collect();
    match parser::parse(tokens) {
        Ok(expr) => {
            println!("{:?}", expr.pretty_print());
        }
        Err(parse_errors) => {
            for error in parse_errors {
                errors.push(Error::ParserError(error))
            }
        }
    }
    if errors.is_empty() {
        Ok(())
    } else {
        Err(errors)
    }
}

fn run_file(file_name: &String) -> Result<(), Vec<Error>> {
    match File::open(file_name) {
        Err(_) => {
            Err(vec![Error::IoError("Error opening file".into())]) // TODO: add context
        }
        Ok(mut file) => {
            let mut source = String::new();
            match file.read_to_string(&mut source) {
                Err(_) => {
                    Err(vec![Error::IoError("Error reading file".into())]) // TODO: add context
                }
                Ok(_) => run(&source),
            }
        }
    }
}

fn run_prompt() -> Result<(), Vec<Error>> {
    println!("Rulox - A lox interpreter written in Rust");
    let _ = io::stdout().flush(); //TODO: is this okay?
    loop {
        print!("> ");
        let _ = io::stdout().flush();
        let mut source = String::new();
        let _ = io::stdin().read_line(&mut source);
        // TODO: add a way to exit
        try!(run(&source))
        // TODO: report syntax errors to the user
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let result = match args.len() {
        // The first argument is the program name
        1 => run_prompt(),
        2 => run_file(&args[1]),
        _ => {
            println!("Usage: rulox [script]");
            Ok(())
        }
    };
    let exit_code = match result {
        Ok(_) => 0,
        Err(errors) => {
            for error in errors {
                println!("{:?}", error);
            }
            1
        }
    };
    std::process::exit(exit_code)
}
<commit_msg>Preparation for runtime errors<commit_after>mod scanner;
mod ast;
mod pretty_printer;
mod parser;

extern crate itertools;

use std::env;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use pretty_printer::PrettyPrint;

#[derive(Debug)]
enum RunResult {
    Ok,
    IoError(String),
    InputError(Vec<InputError>),
    RuntimeError,
}

#[derive(Debug)]
enum InputError {
    ScannerError(scanner::ScannerError),
    ParserError(parser::ParseError),
}

fn run(source: &String) -> RunResult {
    // TODO: change scan and parse to return both what they managed
    // to do and a list of the errors they encountered.
    // This way we can report all the issues at once instead of
    // requiring lots of attempts
    let (tokens, scanner_errors) = scanner::scan(source);
    let mut errors: Vec<InputError> =
        scanner_errors.iter().map(|e| InputError::ScannerError(e.clone())).collect();
    match parser::parse(tokens) {
        Ok(expr) => {
            println!("{:?}", expr.pretty_print());
        }
        Err(parse_errors) => {
            for error in parse_errors {
                errors.push(InputError::ParserError(error))
            }
        }
    }
    if errors.is_empty() {
        RunResult::Ok
    } else {
        RunResult::InputError(errors)
    }
}

fn run_file(file_name: &String) -> RunResult {
    match File::open(file_name) {
        Err(_) => {
            RunResult::IoError("Error opening file".into()) // TODO: add context
        }
        Ok(mut file) => {
            let mut source = String::new();
            match file.read_to_string(&mut source) {
                Err(_) => {
                    RunResult::IoError("Error reading file".into()) // TODO: add context
                }
                Ok(_) => run(&source),
            }
        }
    }
}

fn run_prompt() -> RunResult {
    println!("Rulox - A lox interpreter written in Rust");
    let _ = io::stdout().flush(); //TODO: is this okay?
    loop {
        print!("> ");
        let _ = io::stdout().flush();
        let mut source = String::new();
        let _ = io::stdin().read_line(&mut source);
        // TODO: add a way to exit
        let result = run(&source);
        match result {
            RunResult::Ok => (),
            _ => return result,
        }
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let result = match args.len() {
        // The first argument is the program name
        1 => run_prompt(),
        2 => run_file(&args[1]),
        _ => {
            println!("Usage: rulox [script]");
            RunResult::Ok
        }
    };
    let exit_code = match result {
        RunResult::Ok => 0,
        _ => {
            println!("{:?}", result);
            1
        }
    };
    std::process::exit(exit_code)
}
<|endoftext|>


<commit_before>#![feature(phase)]
#[phase(plugin, link)] extern crate log;

const U4_LOW:  u8 = 0b00001111;
const U4_HIGH: u8 = 0b11110000;

enum CpuState {
	Continue,
	Halt,
}

struct P150Cpu {
	ip:  u8,
	ir: u16,

	reg: [u8, ..16],
	mem: [u8, ..256],
}

impl P150Cpu {
	fn new() -> P150Cpu {
		P150Cpu {
			ip:  0x00,
			ir:  0x0000,

			reg: [0u8, ..16],
			mem: [0u8, ..256],
		}
	}

	fn dump(&self) {
		println!("IP: 0x{:02X}, IR: 0x{:04X}", self.ip, self.ir);

		println!("Registers")
		for (addr, cell) in self.reg.iter().enumerate() {
			println!("{}: {}", addr, cell)
		}
	}

	// Read an array of instructions into memory
	fn init_mem(&mut self, memory: &[u16]) {
		let mut next_cell = 0x00;

		for op in memory.iter() {
			let byte_1 = (*op >> 8) as u8;
			let byte_2 = *op as u8;

			self.mem[next_cell]     = byte_1;
			self.mem[next_cell + 1] = byte_2;
			next_cell += 2
		}
	}

	fn tick(&mut self) -> CpuState {
		self.fetch();

		// decode
		let op = (self.ir >> 12) as u8;
		match op {
			0x0   => { // ADDB
				let rloc_i0 = ((self.ir >> 8) as u8) & U4_LOW;   // first input: lower nibble of first byte
				let rloc_i1 = ((self.ir as u8) & U4_HIGH) >> 4;  // second input: upper nibble of second byte
				let rloc_o0 = (self.ir as u8) & U4_LOW;          // output: lower nibble of second byte

				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint] + self.reg[rloc_i1 as uint];
				Continue
			},

			0x9   => { // RSET
				let rloc = ((self.ir >> 8) as u8) & U4_LOW;  // lower nibble of first byte
				let rval = self.ir as u8;                    // value is entire second byte
				self.reg[rloc as uint] = rval;               // store value in register

				Continue
			},

			0xB   => { Halt },
			_     => { debug!("read opcode: {}", op); Continue },
		}
	}

	fn fetch(&mut self) {
		// load PC -> IR
		let byte_1 = self.mem[(self.ip+0) as uint];
		let byte_2 = self.mem[(self.ip+1) as uint];

		self.ir  = (byte_1 as u16 << 8) | (byte_2 as u16);
		self.ip += 2;

		debug!("IR set to 0x{:04X} ({:02X},{:02X})", self.ir, byte_1, byte_2)
	}
}

fn main() {
	let mut cpu = P150Cpu::new();
	let program = [0x911E, 0x920C, 0x0123, 0xB000];
	cpu.init_mem(program);

	// 0x911E => 0x9 (rset), 0x1 (reg), 0x1E (val: 30)
	// 0x920C => 0x9 (rset), 0x2 (reg), 0x0C (val: 12)
	// 0x0123 => 0x0 (addb), 0x1 (in1), 0x2 (in2), 0x3 (out1)

	loop {
		match cpu.tick() {
			Continue => { continue; },
			Halt => { println!("CPU halted."); cpu.dump(); break; },
		}
	}
}

<commit_msg>Helper function for taking higher and lower nibbles.<commit_after>#![feature(phase)]
#[phase(plugin, link)] extern crate log;

const U4_LOW:  u8 = 0b00001111;
const U4_HIGH: u8 = 0b11110000;

enum CpuState {
	Continue,
	Halt,
}

struct P150Cpu {
	ip:  u8,
	ir: u16,

	reg: [u8, ..16],
	mem: [u8, ..256],
}

impl P150Cpu {
	fn new() -> P150Cpu {
		P150Cpu {
			ip:  0x00,
			ir:  0x0000,

			reg: [0u8, ..16],
			mem: [0u8, ..256],
		}
	}

	fn dump(&self) {
		println!("IP: 0x{:02X}, IR: 0x{:04X}", self.ip, self.ir);

		println!("Registers")
		for (addr, cell) in self.reg.iter().enumerate() {
			println!("{}: {}", addr, cell)
		}
	}

	// Read an array of instructions into memory
	fn init_mem(&mut self, memory: &[u16]) {
		let mut next_cell = 0x00;

		for op in memory.iter() {
			let byte_1 = (*op >> 8) as u8;
			let byte_2 = *op as u8;

			self.mem[next_cell]     = byte_1;
			self.mem[next_cell + 1] = byte_2;
			next_cell += 2
		}
	}

	fn tick(&mut self) -> CpuState {
		self.fetch();

		// decode
		let op = (self.ir >> 12) as u8;
		match op {
			0x0   => { // ADDB
				let rloc_i0 = l_nibble((self.ir >> 8) as u8);   // first input: lower nibble of first byte
				let rloc_i1 = h_nibble(self.ir as u8);          // second input: upper nibble of second byte
				let rloc_o0 = l_nibble(self.ir as u8);          // output: lower nibble of second byte

				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint] + self.reg[rloc_i1 as uint];
				Continue
			},

			0x9   => { // RSET
				let rloc = ((self.ir >> 8) as u8) & U4_LOW;  // lower nibble of first byte
				let rval = self.ir as u8;                    // value is entire second byte
				self.reg[rloc as uint] = rval;               // store value in register

				Continue
			},

			0xB   => { Halt },
			_     => { debug!("read opcode: {}", op); Continue },
		}
	}

	fn fetch(&mut self) {
		// load PC -> IR
		let byte_1 = self.mem[(self.ip+0) as uint];
		let byte_2 = self.mem[(self.ip+1) as uint];

		self.ir  = (byte_1 as u16 << 8) | (byte_2 as u16);
		self.ip += 2;

		debug!("IR set to 0x{:04X} ({:02X},{:02X})", self.ir, byte_1, byte_2)
	}
}

fn l_nibble(byte: u8) -> u8 {
	(byte & U4_LOW)
}

fn h_nibble(byte: u8) -> u8 {
	(byte & U4_HIGH) >> 4
}

fn main() {
	let mut cpu = P150Cpu::new();
	let program = [0x911E, 0x920C, 0x0123, 0xB000];
	cpu.init_mem(program);

	// 0x911E => 0x9 (rset), 0x1 (reg), 0x1E (val: 30)
	// 0x920C => 0x9 (rset), 0x2 (reg), 0x0C (val: 12)
	// 0x0123 => 0x0 (addb), 0x1 (in1), 0x2 (in2), 0x3 (out1)

	loop {
		match cpu.tick() {
			Continue => { continue; },
			Halt => { println!("CPU halted."); cpu.dump(); break; },
		}
	}
}

<|endoftext|>


<commit_before>extern crate bytes;
extern crate env_logger;
extern crate mio;
#[macro_use]
extern crate log;
#[macro_use]
extern crate clap;
extern crate failure;
extern crate slab;

use clap::{App, Arg};
use failure::Error;
use failure::ResultExt;
use mio::net::{TcpListener, TcpStream};
use slab::Slab;
use std::collections::VecDeque;
use std::io::{Read, Write};
use std::ops;

#[derive(Debug)]
enum MiChatCommand {
    Broadcast(String),
    NewConnection(TcpStream),
}

struct MiChat {
    connections: Slab<EventHandler>,
}

trait RuleHandler {
    fn handle_event(&mut self, _event_loop: &mut mio::Poll, events: mio::Ready);
    fn register(&self, event_loop: &mut mio::Poll, token: mio::Token);
    fn process_rules(
        &mut self,
        event_loop: &mut mio::Poll,
        to_parent: &mut FnMut(MiChatCommand),
    ) -> Result<(), Error>;
    fn is_closed(&self) -> bool;
}

impl MiChat {
    fn new() -> MiChat {
        MiChat {
            connections: Slab::new(),
        }
    }

    fn listen(&mut self, event_loop: &mut mio::Poll, listener: TcpListener) {
        let token = {
            let e = self.connections.vacant_entry();
            let token = mio::Token(e.key());
            let l = EventHandler::Listener(Listener::new(listener, token));
            e.insert(l);
            token
        };
        &self.connections[token.into()].register(event_loop, token);
    }

    fn process_action(&mut self, msg: MiChatCommand, event_loop: &mut mio::Poll) {
        trace!("{:p}; got {:?}", self, msg);
        match msg {
            MiChatCommand::Broadcast(s) => self.process_broadcast(s),
            MiChatCommand::NewConnection(socket) => self.process_new_connection(event_loop, socket),
        }
    }

    fn process_broadcast(&mut self, s: String) {
        for c in self.client_connections_mut() {
            c.enqueue(&s);
        }
    }

    fn process_new_connection(&mut self, event_loop: &mut mio::Poll, socket: mio::tcp::TcpStream) {
        let token = {
            let e = self.connections.vacant_entry();
            let token = mio::Token(e.key());
            let l = EventHandler::Conn(Connection::new(socket, token));
            e.insert(l);
            token
        };
        &self.connections[token.into()].register(event_loop, token);
    }

    fn client_connections_mut<'a>(&'a mut self) -> impl Iterator<Item = &'a mut Connection> + 'a {
        self.connections.iter_mut().filter_map(|(_, it)| match it {
            &mut EventHandler::Conn(ref mut c) => Some(c),
            _ => None,
        })
    }
}

#[derive(Debug)]
struct Connection {
    socket: TcpStream,
    sock_status: mio::Ready,
    token: mio::Token,
    read_buf: Vec<u8>,
    read_eof: bool,
    failed: bool,
    write_buf: Vec<u8>,
}

impl RuleHandler for Connection {
    fn register(&self, event_loop: &mut mio::Poll, token: mio::Token) {
        event_loop
            .register(
                &self.socket,
                token,
                mio::Ready::readable(),
                mio::PollOpt::edge() | mio::PollOpt::oneshot(),
            ).expect("event loop register");
    }

    // Event updates arrive here
    fn handle_event(&mut self, _event_loop: &mut mio::Poll, events: mio::Ready) {
        self.sock_status.insert(events);
        info!(
            "Connection::handle_event: {:?}; this time: {:?}; now: {:?}",
            self.socket.peer_addr(),
            events,
            self.sock_status
        );
    }

    // actions are processed here on down.

    fn process_rules(
        &mut self,
        event_loop: &mut mio::Poll,
        to_parent: &mut FnMut(MiChatCommand),
    ) -> Result<(), Error> {
        if self.sock_status.is_readable() {
            self.sock_status.remove(mio::Ready::readable());
            self.read()?;
        }

        self.process_buffer(to_parent);

        if self.sock_status.is_writable() {
            self.sock_status.remove(mio::Ready::writable());
            self.write()?;
        }

        if !self.is_closed() {
            self.reregister(event_loop)
        }

        Ok(())
    }

    fn is_closed(&self) -> bool {
        self.failed || (self.read_eof && self.write_buf.is_empty())
    }
}

impl Connection {
    fn new(socket: TcpStream, token: mio::Token) -> Connection {
        Connection {
            socket: socket,
            sock_status: mio::Ready::empty(),
            token: token,
            read_buf: Vec::with_capacity(1024),
            write_buf: Vec::new(),
            read_eof: false,
            failed: false,
        }
    }
    fn process_buffer(&mut self, to_parent: &mut FnMut(MiChatCommand)) {
        let mut prev = 0;
        info!(
            "{:?}: Read buffer: {:?}",
            self.socket.peer_addr(),
            self.read_buf
        );
        for n in self.read_buf.iter().enumerate().filter_map(|(i, e)| {
            if *e == '\n' as u8 {
                Some(i)
            } else {
                None
            }
        }) {
            info!(
                "{:?}: Pos: {:?}; chunk: {:?}",
                self.socket.peer_addr(),
                n,
                &self.read_buf[prev..n]
            );
            let s = String::from_utf8_lossy(&self.read_buf[prev..n]).to_string();
            let cmd = MiChatCommand::Broadcast(s);
            info!("Send! {:?}", cmd);
            to_parent(cmd);
            prev = n + 1;
        }
        let remainder = self.read_buf[prev..].to_vec();
        info!(
            "{:?}: read Remainder: {}",
            self.socket.peer_addr(),
            remainder.len()
        );
        self.read_buf = remainder;
    }

    fn read(&mut self) -> Result<(), Error> {
        let mut abuf = vec![0; 1024];
        match self.socket.read(&mut abuf).context("Reading socket")? {
            0 => {
                info!("{:?}: EOF!", self.socket.peer_addr());
                self.read_eof = true;
                Ok(())
            }
            n => {
                info!("{:?}: Read {}bytes", self.socket.peer_addr(), n);
                self.read_buf.extend(&abuf[0..n]);
                Ok(())
            }
        }
    }

    fn write(&mut self) -> Result<(), Error> {
        let n = self
            .socket
            .write(&mut self.write_buf)
            .context("writing buffer")?;
        info!(
            "{:?}: Wrote {} of {} in buffer",
            self.socket.peer_addr(),
            n,
            self.write_buf.len()
        );
        self.write_buf = self.write_buf[n..].to_vec();
        info!(
            "{:?}: Now {:?}b",
            self.socket.peer_addr(),
            self.write_buf.len()
        );
        Ok(())
    }

    fn reregister(&mut self, event_loop: &mut mio::Poll) {
        let mut flags = mio::Ready::readable();
        if !self.write_buf.is_empty() {
            flags.insert(mio::Ready::writable());
        }
        info!("Registering {:?} with {:?}", self, flags);

        event_loop
            .reregister(&self.socket, self.token, flags, mio::PollOpt::oneshot())
            .expect("EventLoop#reregister")
    }

    fn enqueue(&mut self, s: &str) {
        self.write_buf.extend(s.as_bytes());
        self.write_buf.push('\n' as u8);
    }
}

#[derive(Debug)]
struct Listener {
    listener: TcpListener,
    sock_status: mio::Ready,
    token: mio::Token,
}

impl Listener {
    fn new(listener: TcpListener, token: mio::Token) -> Listener {
        Listener {
            listener: listener,
            sock_status: mio::Ready::empty(),
            token: token,
        }
    }
    fn reregister(&self, event_loop: &mut mio::Poll, token: mio::Token) {
        event_loop
            .reregister(
                &self.listener,
                token,
                mio::Ready::readable(),
                mio::PollOpt::edge() | mio::PollOpt::oneshot(),
            ).expect("Register listener");
    }
}

impl RuleHandler for Listener {
    fn register(&self, event_loop: &mut mio::Poll, token: mio::Token) {
        event_loop
            .register(
                &self.listener,
                token,
                mio::Ready::readable(),
                mio::PollOpt::edge() | mio::PollOpt::oneshot(),
            ).expect("Register listener");
    }

    fn handle_event(&mut self, _event_loop: &mut mio::Poll, events: mio::Ready) {
        assert!(events.is_readable());
        self.sock_status.insert(events);
        info!(
            "Listener::handle_event: {:?}; this time: {:?}; now: {:?}",
            self.listener.local_addr(),
            events,
            self.sock_status
        );
    }
    fn process_rules(
        &mut self,
        event_loop: &mut mio::Poll,
        to_parent: &mut FnMut(MiChatCommand),
    ) -> Result<(), Error> {
        if self.sock_status.is_readable() {
            info!("the listener socket is ready to accept a connection");
            self.sock_status.remove(mio::Ready::readable());
            match self.listener.accept().context("Accept listening socket")? {
                (socket, _client) => {
                    let cmd = MiChatCommand::NewConnection(socket);
                    to_parent(cmd);
                }
            }

            self.reregister(event_loop, self.token);
        }
        Ok(())
    }

    fn is_closed(&self) -> bool {
        false
    }
}

#[derive(Debug)]
enum EventHandler {
    Listener(Listener),
    Conn(Connection),
}

impl ops::Deref for EventHandler {
    type Target = RuleHandler;
    fn deref(&self) -> &Self::Target {
        match self {
            &EventHandler::Conn(ref conn) => conn,
            &EventHandler::Listener(ref listener) => listener,
        }
    }
}
impl ops::DerefMut for EventHandler {
    fn deref_mut(&mut self) -> &mut Self::Target {
        match self {
            &mut EventHandler::Conn(ref mut conn) => conn,
            &mut EventHandler::Listener(ref mut listener) => listener,
        }
    }
}

impl MiChat {
    fn ready(&mut self, event_loop: &mut mio::Poll, token: mio::Token, events: mio::Ready) {
        info!("{:?}: {:?}", token, events);
        self.connections[token.into()].handle_event(event_loop, events);
        if self.connections[token.into()].is_closed() {
            info!("Removing; {:?}", token);
            self.connections.remove(token.into());
        }

        let mut parent_actions = VecDeque::new();
        let mut failed = Vec::new();
        loop {
            for (idx, conn) in self.connections.iter_mut() {
                if let Err(e) =
                    conn.process_rules(event_loop, &mut |action| parent_actions.push_back(action))
                {
                    failed.push(idx);
                    error!("Error on connection {:?}; Dropping: {:?}", idx, e);
                }
            }
            for idx in failed.drain(..) {
                self.connections.remove(idx);
            }
            // Anything left to process?
            if parent_actions.is_empty() {
                break;
            }

            for action in parent_actions.drain(..) {
                self.process_action(action, event_loop);
            }
        }
    }

    fn run(&mut self, event_loop: &mut mio::Poll) {
        loop {
            self.run_once(event_loop);
        }
    }
    fn run_once(&mut self, event_loop: &mut mio::Poll) {
        let mut events = mio::Events::with_capacity(1024);
        event_loop.poll(&mut events, None).expect("Poll");
        for ev in &events {
            self.ready(event_loop, ev.token(), ev.readiness())
        }
    }
}

fn main() {
    env_logger::init();
    let matches = App::new("michat")
        .arg(
            Arg::with_name("bind")
                .short("l")
                .takes_value(true)
                .required(true),
        ).get_matches();

    let address = value_t_or_exit!(matches.value_of("bind"), std::net::SocketAddr);
    let listener = TcpListener::bind(&address).expect("bind");

    let mut event_loop = mio::Poll::new().expect("Create event loop");
    let mut service = MiChat::new();

    service.listen(&mut event_loop, listener);
    info!("running michat listener at: {:?}", address);
    service.run(&mut event_loop);
}
<commit_msg>Errors on reregister.<commit_after>extern crate bytes;
extern crate env_logger;
extern crate mio;
#[macro_use]
extern crate log;
#[macro_use]
extern crate clap;
extern crate failure;
extern crate slab;

use clap::{App, Arg};
use failure::Error;
use failure::ResultExt;
use mio::net::{TcpListener, TcpStream};
use slab::Slab;
use std::collections::VecDeque;
use std::io::{Read, Write};
use std::ops;

#[derive(Debug)]
enum MiChatCommand {
    Broadcast(String),
    NewConnection(TcpStream),
}

struct MiChat {
    connections: Slab<EventHandler>,
}

trait RuleHandler {
    fn handle_event(&mut self, _event_loop: &mut mio::Poll, events: mio::Ready);
    fn register(&self, event_loop: &mut mio::Poll, token: mio::Token);
    fn process_rules(
        &mut self,
        event_loop: &mut mio::Poll,
        to_parent: &mut FnMut(MiChatCommand),
    ) -> Result<(), Error>;
    fn is_closed(&self) -> bool;
}

impl MiChat {
    fn new() -> MiChat {
        MiChat {
            connections: Slab::new(),
        }
    }

    fn listen(&mut self, event_loop: &mut mio::Poll, listener: TcpListener) {
        let token = {
            let e = self.connections.vacant_entry();
            let token = mio::Token(e.key());
            let l = EventHandler::Listener(Listener::new(listener, token));
            e.insert(l);
            token
        };
        &self.connections[token.into()].register(event_loop, token);
    }

    fn process_action(&mut self, msg: MiChatCommand, event_loop: &mut mio::Poll) {
        trace!("{:p}; got {:?}", self, msg);
        match msg {
            MiChatCommand::Broadcast(s) => self.process_broadcast(s),
            MiChatCommand::NewConnection(socket) => self.process_new_connection(event_loop, socket),
        }
    }

    fn process_broadcast(&mut self, s: String) {
        for c in self.client_connections_mut() {
            c.enqueue(&s);
        }
    }

    fn process_new_connection(&mut self, event_loop: &mut mio::Poll, socket: mio::tcp::TcpStream) {
        let token = {
            let e = self.connections.vacant_entry();
            let token = mio::Token(e.key());
            let l = EventHandler::Conn(Connection::new(socket, token));
            e.insert(l);
            token
        };
        &self.connections[token.into()].register(event_loop, token);
    }

    fn client_connections_mut<'a>(&'a mut self) -> impl Iterator<Item = &'a mut Connection> + 'a {
        self.connections.iter_mut().filter_map(|(_, it)| match it {
            &mut EventHandler::Conn(ref mut c) => Some(c),
            _ => None,
        })
    }
}

#[derive(Debug)]
struct Connection {
    socket: TcpStream,
    sock_status: mio::Ready,
    token: mio::Token,
    read_buf: Vec<u8>,
    read_eof: bool,
    failed: bool,
    write_buf: Vec<u8>,
}

impl RuleHandler for Connection {
    fn register(&self, event_loop: &mut mio::Poll, token: mio::Token) {
        event_loop
            .register(
                &self.socket,
                token,
                mio::Ready::readable(),
                mio::PollOpt::edge() | mio::PollOpt::oneshot(),
            ).expect("event loop register");
    }

    // Event updates arrive here
    fn handle_event(&mut self, _event_loop: &mut mio::Poll, events: mio::Ready) {
        self.sock_status.insert(events);
        info!(
            "Connection::handle_event: {:?}; this time: {:?}; now: {:?}",
            self.socket.peer_addr(),
            events,
            self.sock_status
        );
    }

    // actions are processed here on down.

    fn process_rules(
        &mut self,
        event_loop: &mut mio::Poll,
        to_parent: &mut FnMut(MiChatCommand),
    ) -> Result<(), Error> {
        if self.sock_status.is_readable() {
            self.sock_status.remove(mio::Ready::readable());
            self.read()?;
        }

        self.process_buffer(to_parent);

        if self.sock_status.is_writable() {
            self.sock_status.remove(mio::Ready::writable());
            self.write()?;
        }

        if !self.is_closed() {
            self.reregister(event_loop)?;
        }

        Ok(())
    }

    fn is_closed(&self) -> bool {
        self.failed || (self.read_eof && self.write_buf.is_empty())
    }
}

impl Connection {
    fn new(socket: TcpStream, token: mio::Token) -> Connection {
        Connection {
            socket: socket,
            sock_status: mio::Ready::empty(),
            token: token,
            read_buf: Vec::with_capacity(1024),
            write_buf: Vec::new(),
            read_eof: false,
            failed: false,
        }
    }
    fn process_buffer(&mut self, to_parent: &mut FnMut(MiChatCommand)) {
        let mut prev = 0;
        info!(
            "{:?}: Read buffer: {:?}",
            self.socket.peer_addr(),
            self.read_buf
        );
        for n in self.read_buf.iter().enumerate().filter_map(|(i, e)| {
            if *e == '\n' as u8 {
                Some(i)
            } else {
                None
            }
        }) {
            info!(
                "{:?}: Pos: {:?}; chunk: {:?}",
                self.socket.peer_addr(),
                n,
                &self.read_buf[prev..n]
            );
            let s = String::from_utf8_lossy(&self.read_buf[prev..n]).to_string();
            let cmd = MiChatCommand::Broadcast(s);
            info!("Send! {:?}", cmd);
            to_parent(cmd);
            prev = n + 1;
        }
        let remainder = self.read_buf[prev..].to_vec();
        info!(
            "{:?}: read Remainder: {}",
            self.socket.peer_addr(),
            remainder.len()
        );
        self.read_buf = remainder;
    }

    fn read(&mut self) -> Result<(), Error> {
        let mut abuf = vec![0; 1024];
        match self.socket.read(&mut abuf).context("Reading socket")? {
            0 => {
                info!("{:?}: EOF!", self.socket.peer_addr());
                self.read_eof = true;
                Ok(())
            }
            n => {
                info!("{:?}: Read {}bytes", self.socket.peer_addr(), n);
                self.read_buf.extend(&abuf[0..n]);
                Ok(())
            }
        }
    }

    fn write(&mut self) -> Result<(), Error> {
        let n = self
            .socket
            .write(&mut self.write_buf)
            .context("writing buffer")?;
        info!(
            "{:?}: Wrote {} of {} in buffer",
            self.socket.peer_addr(),
            n,
            self.write_buf.len()
        );
        self.write_buf = self.write_buf[n..].to_vec();
        info!(
            "{:?}: Now {:?}b",
            self.socket.peer_addr(),
            self.write_buf.len()
        );
        Ok(())
    }

    fn reregister(&mut self, event_loop: &mut mio::Poll) -> Result<(), Error> {
        let mut flags = mio::Ready::readable();
        if !self.write_buf.is_empty() {
            flags.insert(mio::Ready::writable());
        }
        info!("Registering {:?} with {:?}", self, flags);

        event_loop
            .reregister(&self.socket, self.token, flags, mio::PollOpt::oneshot())
            .context("EventLoop#reregister")?;

        Ok(())
    }

    fn enqueue(&mut self, s: &str) {
        self.write_buf.extend(s.as_bytes());
        self.write_buf.push('\n' as u8);
    }
}

#[derive(Debug)]
struct Listener {
    listener: TcpListener,
    sock_status: mio::Ready,
    token: mio::Token,
}

impl Listener {
    fn new(listener: TcpListener, token: mio::Token) -> Listener {
        Listener {
            listener: listener,
            sock_status: mio::Ready::empty(),
            token: token,
        }
    }
    fn reregister(&self, event_loop: &mut mio::Poll, token: mio::Token) {
        event_loop
            .reregister(
                &self.listener,
                token,
                mio::Ready::readable(),
                mio::PollOpt::edge() | mio::PollOpt::oneshot(),
            ).expect("Register listener");
    }
}

impl RuleHandler for Listener {
    fn register(&self, event_loop: &mut mio::Poll, token: mio::Token) {
        event_loop
            .register(
                &self.listener,
                token,
                mio::Ready::readable(),
                mio::PollOpt::edge() | mio::PollOpt::oneshot(),
            ).expect("Register listener");
    }

    fn handle_event(&mut self, _event_loop: &mut mio::Poll, events: mio::Ready) {
        assert!(events.is_readable());
        self.sock_status.insert(events);
        info!(
            "Listener::handle_event: {:?}; this time: {:?}; now: {:?}",
            self.listener.local_addr(),
            events,
            self.sock_status
        );
    }
    fn process_rules(
        &mut self,
        event_loop: &mut mio::Poll,
        to_parent: &mut FnMut(MiChatCommand),
    ) -> Result<(), Error> {
        if self.sock_status.is_readable() {
            info!("the listener socket is ready to accept a connection");
            self.sock_status.remove(mio::Ready::readable());
            match self.listener.accept().context("Accept listening socket")? {
                (socket, _client) => {
                    let cmd = MiChatCommand::NewConnection(socket);
                    to_parent(cmd);
                }
            }

            self.reregister(event_loop, self.token);
        }
        Ok(())
    }

    fn is_closed(&self) -> bool {
        false
    }
}

#[derive(Debug)]
enum EventHandler {
    Listener(Listener),
    Conn(Connection),
}

impl ops::Deref for EventHandler {
    type Target = RuleHandler;
    fn deref(&self) -> &Self::Target {
        match self {
            &EventHandler::Conn(ref conn) => conn,
            &EventHandler::Listener(ref listener) => listener,
        }
    }
}
impl ops::DerefMut for EventHandler {
    fn deref_mut(&mut self) -> &mut Self::Target {
        match self {
            &mut EventHandler::Conn(ref mut conn) => conn,
            &mut EventHandler::Listener(ref mut listener) => listener,
        }
    }
}

impl MiChat {
    fn ready(&mut self, event_loop: &mut mio::Poll, token: mio::Token, events: mio::Ready) {
        info!("{:?}: {:?}", token, events);
        self.connections[token.into()].handle_event(event_loop, events);
        if self.connections[token.into()].is_closed() {
            info!("Removing; {:?}", token);
            self.connections.remove(token.into());
        }

        let mut parent_actions = VecDeque::new();
        let mut failed = Vec::new();
        loop {
            for (idx, conn) in self.connections.iter_mut() {
                if let Err(e) =
                    conn.process_rules(event_loop, &mut |action| parent_actions.push_back(action))
                {
                    failed.push(idx);
                    error!("Error on connection {:?}; Dropping: {:?}", idx, e);
                }
            }
            for idx in failed.drain(..) {
                self.connections.remove(idx);
            }
            // Anything left to process?
            if parent_actions.is_empty() {
                break;
            }

            for action in parent_actions.drain(..) {
                self.process_action(action, event_loop);
            }
        }
    }

    fn run(&mut self, event_loop: &mut mio::Poll) {
        loop {
            self.run_once(event_loop);
        }
    }
    fn run_once(&mut self, event_loop: &mut mio::Poll) {
        let mut events = mio::Events::with_capacity(1024);
        event_loop.poll(&mut events, None).expect("Poll");
        for ev in &events {
            self.ready(event_loop, ev.token(), ev.readiness())
        }
    }
}

fn main() {
    env_logger::init();
    let matches = App::new("michat")
        .arg(
            Arg::with_name("bind")
                .short("l")
                .takes_value(true)
                .required(true),
        ).get_matches();

    let address = value_t_or_exit!(matches.value_of("bind"), std::net::SocketAddr);
    let listener = TcpListener::bind(&address).expect("bind");

    let mut event_loop = mio::Poll::new().expect("Create event loop");
    let mut service = MiChat::new();

    service.listen(&mut event_loop, listener);
    info!("running michat listener at: {:?}", address);
    service.run(&mut event_loop);
}
<|endoftext|>


<commit_before>mod system;
mod math;
mod renderer;

use renderer::context::*;
use renderer::mesh;
use renderer::shader;
use renderer::texture;

extern crate rand;
extern crate time;
extern crate gl;

use gl::types::*;
use std::mem;
use std::ptr;
use std::ffi::CString;
use rand::Rng;

// Vertex data
static VERTEX_DATA: [GLfloat; 9] = [
     0.0,  0.5, 0.0,
     0.5, -0.5, 0.0,
    -0.5, -0.5, 0.0
];

static VERTEX_TEX_DATA: [GLfloat; 6] = [
    0.5, 0.0,
    1.0, 1.0,
    0.0, 1.0
];

static INDEX_DATA: [u32; 3] = [
    0, 1, 2
];

// Shader sources
static VS_SRC: &'static str =
   "#version 400\n\
    in vec3 position;\n\
    in vec2 texcoord;\n\
    in vec4 color;\n\
    out vec2 vTexcoord;\n\
    out vec4 vColor;\n\
    void main() {\n\
        vTexcoord = texcoord;\n\
        vColor = color;\n\
        gl_Position = vec4(position, 1.0);\n\
    }";

static FS_SRC: &'static str =
   "#version 400\n\
    in vec2 vTexcoord;\n\
    in vec4 vColor;\n\
    uniform sampler2D diffuseTexture;\n\
    out vec4 out_color;\n\
    void main() {\n\
        vec4 diffuse = texture2D(diffuseTexture, vTexcoord);\n\
        out_color = diffuse * vColor;\n\
    }";

fn main() {
    let mut VERTEX_COL_DATA: [GLfloat; 12] = [
        1.0, 1.0, 1.0, 1.0,
        1.0, 0.0, 1.0, 1.0,
        0.0, 1.0, 1.0, 1.0
    ];

    let mut ctx = Context::new("data/config.json");

    let t = texture::Texture::from_image("data/rust.png");

    let mut program = shader::Program::new();
    let ref vs = shader::Shader::new(shader::ShaderType::VERTEX,"data/shaders/test.vs".to_string());
    let ref fs = shader::Shader::new(shader::ShaderType::FRAGMENT,"data/shaders/test.frag".to_string());
    program.attach(vs);
    program.attach(fs);
    program.link();
    // let

    // let vs = shader::compile_shader(VS_SRC, gl::VERTEX_SHADER);
    // let fs = shader::compile_shader(FS_SRC, gl::FRAGMENT_SHADER);
    // let program = shader::link_program(vs, fs);

    let mut m0 = mesh::Mesh::new(&VERTEX_DATA, &INDEX_DATA, Some(&VERTEX_TEX_DATA), Some(&VERTEX_COL_DATA));

    unsafe {
        program.bind();
        // gl::UseProgram(program.program_id);
        gl::BindFragDataLocation(program.program_id, 0,
            CString::new("out_color").unwrap().as_ptr());

        gl::ActiveTexture(gl::TEXTURE0);
        program.set_uniform_1i("diffuseTexture",0);
        // let diffuseTexLoc = gl::GetUniformLocation(program.program_id, CString::new("diffuseTexture").unwrap().as_ptr());
        // gl::Uniform1i(diffuseTexLoc, 0);
    }

    t.bind();

    let mut rng = rand::thread_rng();

    let mut start_time = time::now();
    let mut accum = 0.0;

    while ctx.is_running() {
        ctx.start_frame();

        let frame_time = time::now();
        let elapsed_duration = frame_time - start_time;
        start_time = frame_time;

        let mut elapsed = elapsed_duration.num_seconds() as f64;
        elapsed += (elapsed_duration.num_milliseconds() as f64) / 1_000.0;

        accum += elapsed;

        if accum >= 1.0 {
            accum -= 1.0;

            // try modifying tri color
            for i in 0..12 {
                if i % 4 != 0 {
                    VERTEX_COL_DATA[i] = rng.gen::<f32>();
                }
            }
            m0.update_buffer(mesh::MeshAttrib::Color, &VERTEX_COL_DATA);
        }

        m0.render();

        ctx.end_frame();
    }

    // free mem
    //TODO add memory cleaner for program and shader
    unsafe {
        // gl::DeleteProgram(program);
        // gl::DeleteShader(vs);
        // gl::DeleteShader(fs);
    }
}
<commit_msg>main.rs cleaning<commit_after>mod system;
mod math;
mod renderer;

use renderer::context::*;
use renderer::mesh;
use renderer::shader;
use renderer::texture;

extern crate rand;
extern crate time;
extern crate gl;

use gl::types::*;
use std::mem;
use std::ptr;
use std::ffi::CString;
use rand::Rng;

// Vertex data
static VERTEX_DATA: [GLfloat; 9] = [
     0.0,  0.5, 0.0,
     0.5, -0.5, 0.0,
    -0.5, -0.5, 0.0
];

static VERTEX_TEX_DATA: [GLfloat; 6] = [
    0.5, 0.0,
    1.0, 1.0,
    0.0, 1.0
];

static INDEX_DATA: [u32; 3] = [
    0, 1, 2
];

fn main() {
    let mut VERTEX_COL_DATA: [GLfloat; 12] = [
        1.0, 1.0, 1.0, 1.0,
        1.0, 0.0, 1.0, 1.0,
        0.0, 1.0, 1.0, 1.0
    ];

    let mut ctx = Context::new("data/config.json");

    let t = texture::Texture::from_image("data/rust.png");

    let mut program = shader::Program::new();
    let ref vs = shader::Shader::new(shader::ShaderType::VERTEX,"data/shaders/test.vs".to_string());
    let ref fs = shader::Shader::new(shader::ShaderType::FRAGMENT,"data/shaders/test.frag".to_string());
    program.attach(vs);
    program.attach(fs);
    program.link();
    // let

    // let vs = shader::compile_shader(VS_SRC, gl::VERTEX_SHADER);
    // let fs = shader::compile_shader(FS_SRC, gl::FRAGMENT_SHADER);
    // let program = shader::link_program(vs, fs);

    let mut m0 = mesh::Mesh::new(&VERTEX_DATA, &INDEX_DATA, Some(&VERTEX_TEX_DATA), Some(&VERTEX_COL_DATA));

    unsafe {
        program.bind();

        gl::BindFragDataLocation(program.program_id, 0,
            CString::new("out_color").unwrap().as_ptr());

        gl::ActiveTexture(gl::TEXTURE0);
        program.set_uniform_1i("diffuseTexture",0);
    }

    t.bind();

    let mut rng = rand::thread_rng();

    let mut start_time = time::now();
    let mut accum = 0.0;

    while ctx.is_running() {
        ctx.start_frame();

        let frame_time = time::now();
        let elapsed_duration = frame_time - start_time;
        start_time = frame_time;

        let mut elapsed = elapsed_duration.num_seconds() as f64;
        elapsed += (elapsed_duration.num_milliseconds() as f64) / 1_000.0;

        accum += elapsed;

        if accum >= 1.0 {
            accum -= 1.0;

            // try modifying tri color
            for i in 0..12 {
                if i % 4 != 0 {
                    VERTEX_COL_DATA[i] = rng.gen::<f32>();
                }
            }
            m0.update_buffer(mesh::MeshAttrib::Color, &VERTEX_COL_DATA);
        }

        m0.render();

        ctx.end_frame();
    }

    // free mem
    //TODO add memory cleaner for program and shader
    unsafe {
        // gl::DeleteProgram(program);
        // gl::DeleteShader(vs);
        // gl::DeleteShader(fs);
    }
}
<|endoftext|>