<commit_before>//! The wrapper around the information needed to meaningfully run this program
//!
//! NOTE: in the process of further abstracting IO logic with this --
//! expect things to break

use std;

use sdl2::*;
use sdl2::audio::AudioDevice;
use sdl2::keyboard::Keycode;
use log4rs;

use debugger::graphics::*;
use cpu;
use io::constants::*;
use io::input::*;
use io::graphics::*;
use io::memvis::MemVisState;
use io::vidram::{VidRamBGDisplay, VidRamTileDisplay};
use io::sound::*;

use log::LogLevelFilter;
use log4rs::append::console::ConsoleAppender;
use log4rs::encode::pattern::PatternEncoder;
use log4rs::config::{Appender, Config, Root};

use sdl2;
use sdl2::rect::{Point, Rect};

use std::num::Wrapping;

/// Holds all the data needed to use the emulator in meaningful ways
pub struct ApplicationState {
    pub gameboy: cpu::Cpu,
    sdl_context: Sdl, //  sdl_sound: sdl2::audio,
    sound_system: AudioDevice<Wave>,
    renderer: render::Renderer<'static>,
    cycle_count: u64,
    prev_time: u64,
    debugger: Option<Debugger>,
    prev_hsync_cycles: u64,
    clock_cycles: u64,
    initial_gameboy_state: cpu::Cpu,
    logger_handle: Option<log4rs::Handle>, // storing to keep alive
    controller: Option<sdl2::controller::GameController>, // storing to keep alive
    screenshot_frame_num: Wrapping<u64>,
    ui_scale: f32,
    ui_offset: Point, // TODO whole interface pan
    widgets: Vec<PositionedFrame>,
}

impl ApplicationState {
    //! Sets up the environment for running in memory visualization mode
    pub fn new(trace_mode: bool, debug_mode: bool, rom_file_name: &str) -> ApplicationState {
        // Set up logging
        let stdout = ConsoleAppender::builder()
            .encoder(Box::new(PatternEncoder::new("{h({l})} {m} {n}")))
            .build();

        let config = Config::builder()
            .appender(Appender::builder().build("stdout", Box::new(stdout)))
            .build(Root::builder().appender("stdout").build(if trace_mode {
                LogLevelFilter::Trace
            } else {
                LogLevelFilter::Debug
            }))
            .unwrap();

        // Set up debugging or command-line logging
        let (debugger, handle) = if debug_mode && cfg!(feature = "debugger") {
            info!("Running in debug mode");
            // Some(Debugger::new(&mut gameboy))
            (None, None)
        } else {
            let handle = log4rs::init_config(config).unwrap();
            (None, Some(handle))
        };

        // Set up gameboy and other state
        let mut gameboy = cpu::Cpu::new();

        trace!("loading ROM");
        gameboy.load_rom(rom_file_name);

        let sdl_context = sdl2::init().unwrap();
        let device = setup_audio(&sdl_context);
        let controller = setup_controller_subsystem(&sdl_context);

        // Set up graphics and window
        trace!("Opening window");
        let video_subsystem = sdl_context.video().unwrap();
        let window = video_subsystem.window(gameboy.get_game_name().as_str(),
                    RB_SCREEN_WIDTH,
                    RB_SCREEN_HEIGHT)
            .position_centered()
            .build()
            .unwrap();

        let renderer = window.renderer()
            .accelerated()
            .build()
            .unwrap();

        let gbcopy = gameboy.clone();

        let txt_format = sdl2::pixels::PixelFormatEnum::RGBA8888;
        let w = MEM_DISP_WIDTH as u32;
        let h = MEM_DISP_HEIGHT as u32;
        let memvis_texture = renderer.create_texture_streaming(txt_format, w, h).unwrap();

        // TODO function for widget creation and automaic layout
        let widget_memvis = {
            let vis = MemVisState::new(memvis_texture);
            let (w, h) = vis.get_initial_size();
            PositionedFrame {
                rect: Rect::new(1, 1, w, h),
                scale: 1.0,
                vis: Box::new(vis),
            }
        };

        let widget_vidram_bg = {
            let vis = VidRamBGDisplay { tile_data_select: TileDataSelect::Auto };
            let (w, h) = vis.get_initial_size();
            PositionedFrame {
                rect: Rect::new(MEM_DISP_WIDTH + 3, 1, w, h),
                scale: 1.0,
                vis: Box::new(vis),
            }
        };

        let widget_vidram_tiles = {
            let vis = VidRamTileDisplay { tile_data_select: TileDataSelect::Auto };
            let (w, h) = vis.get_initial_size();
            PositionedFrame {
                rect: Rect::new((MEM_DISP_WIDTH + SCREEN_BUFFER_SIZE_X as i32) as i32 + 5,
                                0,
                                w,
                                h),
                scale: 1.0,
                vis: Box::new(vis),
            }
        };

        let mut widgets = Vec::new();
        widgets.push(widget_memvis);
        widgets.push(widget_vidram_bg);
        widgets.push(widget_vidram_tiles);

        ApplicationState {
            gameboy: gameboy,
            sdl_context: sdl_context,
            sound_system: device,
            renderer: renderer,
            cycle_count: 0,
            prev_time: 0,
            debugger: debugger,
            prev_hsync_cycles: 0,
            clock_cycles: 0,
            initial_gameboy_state: gbcopy,
            logger_handle: handle,
            controller: controller,
            screenshot_frame_num: Wrapping(0),
            ui_scale: SCALE,
            ui_offset: Point::new(0, 0),
            widgets: widgets,
        }
    }

    pub fn display_coords_to_ui_point(&self, x: i32, y: i32) -> Point {
        let s_x = (x as f32 / self.ui_scale) as i32;
        let s_y = (y as f32 / self.ui_scale) as i32;
        Point::new(s_x, s_y)
    }

    /// Handles both controller input and keyboard/mouse debug input
    /// NOTE: does not handle input for ncurses debugger
    pub fn handle_events(&mut self) {
        for event in self.sdl_context.event_pump().unwrap().poll_iter() {
            use sdl2::event::Event;

            match event {
                Event::ControllerAxisMotion { axis, value: val, .. } => {
                    let dead_zone = 10000;
                    if val > dead_zone || val < -dead_zone {
                        debug!("Axis {:?} moved to {}", axis, val);
                        //                   match axis {
                        // controller::Axis::LeftX =>,
                        // controller::Axis::LeftY =>,
                        // _ => (),
                        // }
                        //
                    }
                }
                Event::ControllerButtonDown { button, .. } => {
                    debug!("Button {:?} down", button);
                    match button {
                        controller::Button::A => {
                            self.gameboy.press_a();
                            // TODO: sound
                            // device.resume();
                        }
                        controller::Button::B => self.gameboy.press_b(),
                        controller::Button::Back => self.gameboy.press_select(),
                        controller::Button::Start => self.gameboy.press_start(),
                        _ => (),
                    }
                }

                Event::ControllerButtonUp { button, .. } => {
                    debug!("Button {:?} up", button);
                    match button {
                        controller::Button::A => {
                            self.gameboy.unpress_a();
                            // TODO: sound
                            // device.pause();
                        }
                        controller::Button::B => self.gameboy.unpress_b(),
                        controller::Button::Back => self.gameboy.unpress_select(),
                        controller::Button::Start => self.gameboy.unpress_start(),
                        _ => (),
                    }
                }
                Event::Quit { .. } => {
                    info!("Program exiting!");
                    std::process::exit(0);
                }
                Event::KeyDown { keycode: Some(keycode), repeat, .. } => {
                    if !repeat {
                        match keycode {
                            Keycode::Escape => {
                                info!("Program exiting!");
                                std::process::exit(0);
                            }
                            Keycode::F3 => self.gameboy.toggle_logger(),
                            Keycode::R => {
                                // Reset/reload emu
                                // TODO Keep previous visualization settings
                                self.gameboy.reset();
                                let gbcopy = self.initial_gameboy_state.clone();
                                self.gameboy = gbcopy;
                                self.gameboy.reinit_logger();

                                // // This way makes it possible to edit rom
                                // // with external editor and see changes
                                // // instantly.
                                // gameboy = Cpu::new();
                            // gameboy.load_rom(rom_file);
                            }
                            Keycode::A => { self.gameboy.press_a() },
                            Keycode::S => { self.gameboy.press_b() },
                            Keycode::D => { self.gameboy.press_select() },
                            Keycode::F => { self.gameboy.press_start() },
                            Keycode::Up => { self.gameboy.press_up() },
                            Keycode::Down => { self.gameboy.press_down() },
                            Keycode::Left => { self.gameboy.press_left() },
                            Keycode::Right => { self.gameboy.press_right() },
                            _ => (),
                        }
                    }
                }
                Event::KeyUp { keycode: Some(keycode), repeat, .. } => {
                    if !repeat {
                        match keycode {
                            Keycode::A => { self.gameboy.unpress_a() },
                            Keycode::S => { self.gameboy.unpress_b() },
                            Keycode::D => { self.gameboy.unpress_select() },
                            Keycode::F => { self.gameboy.unpress_start() },
                            Keycode::Up => { self.gameboy.unpress_up() },
                            Keycode::Down => { self.gameboy.unpress_down() },
                            Keycode::Left => { self.gameboy.unpress_left() },
                            Keycode::Right => { self.gameboy.unpress_right() },

                            _ => (),
                        }
                    }
                }
                Event::MouseButtonDown { x, y, mouse_btn, .. } => {
                    // Transform screen coordinates in UI coordinates
                    let click_point = self.display_coords_to_ui_point(x, y);

                    // Find clicked widget
                    for widget in self.widgets.iter_mut() {
                        if widget.rect.contains(click_point) {
                            widget.click(mouse_btn, click_point, &mut self.gameboy);
                            break;
                        }
                    }
                }
                Event::MouseWheel { y, .. } => {
                    self.ui_scale += y as f32;
                    // self.widgets[0].scale += y as f32;
                }
                // // Event::MouseMotion { x, y, mousestate, xrel, yrel, .. } => {
                // Event::MouseMotion { x, y, .. } => {
                //     // Test widget position
                //     let mouse_pos = self.display_coords_to_ui_point(x+5, y+5);
                //     self.widgets[0].rect.reposition(mouse_pos);
                // }
                _ => (),
            }
        }
    }

    /// Runs the game application forward one "unit of time"
    /// TODO: elaborate
    pub fn step(&mut self) {

        // handle_events(&mut sdl_context, &mut gameboy);

        let current_op_time = if self.gameboy.state != cpu::constants::CpuState::Crashed {
            self.gameboy.dispatch_opcode() as u64
        } else {
            10 // FIXME think about what to return here or refactor code around this
        };

        self.cycle_count += current_op_time;
        self.clock_cycles += current_op_time;
        let timer_khz = self.gameboy.timer_frequency();
        let time_in_ms_per_cycle = (1000.0 / ((timer_khz as f64) * 1000.0)) as u64;
        self.clock_cycles += self.cycle_count;

        // TODO: remove prev_time
        let prev_time = self.prev_time;
        let ticks = self.cycle_count - prev_time;

        let time_in_cpu_cycle_per_cycle =
            ((time_in_ms_per_cycle as f64) / (1.0 / (4.19 * 1000.0 * 1000.0))) as u64;

        if self.clock_cycles >= time_in_cpu_cycle_per_cycle {
            //           std::thread::sleep_ms(16);
            // trace!("Incrementing the timer!");
            self.gameboy.timer_cycle();
            self.clock_cycles = 0;
        }

        let fake_display_hsync = true;
        if fake_display_hsync {
            // update LY respective to cycles spent execing instruction
            let cycle_count = self.cycle_count;
            loop {
                if cycle_count < self.prev_hsync_cycles {
                    break;
                }
                self.gameboy.inc_ly();
                self.prev_hsync_cycles += CYCLES_PER_HSYNC;
            }
        }

        // Gameboy screen is 256x256
        // only 160x144 are displayed at a time
        //
        // Background tile map is 32x32 of tiles. Scrollx and scrolly
        // determine how this is actually rendered (it wraps)
        // These numbers index the tile data table
        //

        // 16384hz, call inc_div
        // CPU is at 4.194304MHz (or 1.05MHz) 105000000hz
        // hsync at 9198KHz = 9198000hz
        // vsync at 59.73Hz

        let scale = self.ui_scale;
        match self.renderer.set_scale(scale, scale) {
            Ok(_) => (),
            Err(_) => error!("Could not set render scale"),
        }

        // 1ms before drawing in terms of CPU time we must throw a vblank interrupt
        // TODO make this variable based on whether it's GB, SGB, etc.

        if ticks >= CPU_CYCLES_PER_VBLANK {
            if let Some(ref mut dbg) = self.debugger {
                dbg.step(&mut self.gameboy);
            }

            let cycle_count = self.cycle_count;
            self.prev_time = cycle_count;
            self.renderer.set_draw_color(NICER_COLOR);
            self.renderer.clear();

            // Draw all widgets
            for ref mut widget in self.widgets.iter_mut() {
                widget.draw(&mut self.renderer, &mut self.gameboy);
            }

            //   00111100 1110001 00001000
            //   01111110 1110001 00010100
            //   11111111 1110001 00101010
            //

            // TODO add a way to enable/disable this while running
            let record_screen = false;
            if record_screen {
                save_screenshot(&self.renderer,
                                format!("screen{:010}.bmp", self.screenshot_frame_num.0));
                self.screenshot_frame_num += Wrapping(1);
            }

            if self.gameboy.get_sound1() {
                self.sound_system.resume();
            } else {
                self.sound_system.pause();
            }

            let mut sound_system = self.sound_system.lock();
            sound_system.wave_duty = self.gameboy.channel1_wave_pattern_duty();
            sound_system.phase_inc = 1.0 /
                                     (131072.0 / (2048 - self.gameboy.channel1_frequency()) as f32);
            sound_system.add = self.gameboy.channel1_sweep_increase();
            //            131072 / (2048 - gb)

            self.renderer.present();
        }
    }
}
<commit_msg>add directional input for controllers<commit_after>//! The wrapper around the information needed to meaningfully run this program
//!
//! NOTE: in the process of further abstracting IO logic with this --
//! expect things to break

use std;

use sdl2::*;
use sdl2::audio::AudioDevice;
use sdl2::keyboard::Keycode;
use log4rs;

use debugger::graphics::*;
use cpu;
use io::constants::*;
use io::input::*;
use io::graphics::*;
use io::memvis::MemVisState;
use io::vidram::{VidRamBGDisplay, VidRamTileDisplay};
use io::sound::*;

use log::LogLevelFilter;
use log4rs::append::console::ConsoleAppender;
use log4rs::encode::pattern::PatternEncoder;
use log4rs::config::{Appender, Config, Root};

use sdl2;
use sdl2::rect::{Point, Rect};

use std::num::Wrapping;

/// Holds all the data needed to use the emulator in meaningful ways
pub struct ApplicationState {
    pub gameboy: cpu::Cpu,
    sdl_context: Sdl, //  sdl_sound: sdl2::audio,
    sound_system: AudioDevice<Wave>,
    renderer: render::Renderer<'static>,
    cycle_count: u64,
    prev_time: u64,
    debugger: Option<Debugger>,
    prev_hsync_cycles: u64,
    clock_cycles: u64,
    initial_gameboy_state: cpu::Cpu,
    logger_handle: Option<log4rs::Handle>, // storing to keep alive
    controller: Option<sdl2::controller::GameController>, // storing to keep alive
    screenshot_frame_num: Wrapping<u64>,
    ui_scale: f32,
    ui_offset: Point, // TODO whole interface pan
    widgets: Vec<PositionedFrame>,
}

impl ApplicationState {
    //! Sets up the environment for running in memory visualization mode
    pub fn new(trace_mode: bool, debug_mode: bool, rom_file_name: &str) -> ApplicationState {
        // Set up logging
        let stdout = ConsoleAppender::builder()
            .encoder(Box::new(PatternEncoder::new("{h({l})} {m} {n}")))
            .build();

        let config = Config::builder()
            .appender(Appender::builder().build("stdout", Box::new(stdout)))
            .build(Root::builder().appender("stdout").build(if trace_mode {
                LogLevelFilter::Trace
            } else {
                LogLevelFilter::Debug
            }))
            .unwrap();

        // Set up debugging or command-line logging
        let (debugger, handle) = if debug_mode && cfg!(feature = "debugger") {
            info!("Running in debug mode");
            // Some(Debugger::new(&mut gameboy))
            (None, None)
        } else {
            let handle = log4rs::init_config(config).unwrap();
            (None, Some(handle))
        };

        // Set up gameboy and other state
        let mut gameboy = cpu::Cpu::new();

        trace!("loading ROM");
        gameboy.load_rom(rom_file_name);

        let sdl_context = sdl2::init().unwrap();
        let device = setup_audio(&sdl_context);
        let controller = setup_controller_subsystem(&sdl_context);

        // Set up graphics and window
        trace!("Opening window");
        let video_subsystem = sdl_context.video().unwrap();
        let window = video_subsystem.window(gameboy.get_game_name().as_str(),
                    RB_SCREEN_WIDTH,
                    RB_SCREEN_HEIGHT)
            .position_centered()
            .build()
            .unwrap();

        let renderer = window.renderer()
            .accelerated()
            .build()
            .unwrap();

        let gbcopy = gameboy.clone();

        let txt_format = sdl2::pixels::PixelFormatEnum::RGBA8888;
        let w = MEM_DISP_WIDTH as u32;
        let h = MEM_DISP_HEIGHT as u32;
        let memvis_texture = renderer.create_texture_streaming(txt_format, w, h).unwrap();

        // TODO function for widget creation and automaic layout
        let widget_memvis = {
            let vis = MemVisState::new(memvis_texture);
            let (w, h) = vis.get_initial_size();
            PositionedFrame {
                rect: Rect::new(1, 1, w, h),
                scale: 1.0,
                vis: Box::new(vis),
            }
        };

        let widget_vidram_bg = {
            let vis = VidRamBGDisplay { tile_data_select: TileDataSelect::Auto };
            let (w, h) = vis.get_initial_size();
            PositionedFrame {
                rect: Rect::new(MEM_DISP_WIDTH + 3, 1, w, h),
                scale: 1.0,
                vis: Box::new(vis),
            }
        };

        let widget_vidram_tiles = {
            let vis = VidRamTileDisplay { tile_data_select: TileDataSelect::Auto };
            let (w, h) = vis.get_initial_size();
            PositionedFrame {
                rect: Rect::new((MEM_DISP_WIDTH + SCREEN_BUFFER_SIZE_X as i32) as i32 + 5,
                                0,
                                w,
                                h),
                scale: 1.0,
                vis: Box::new(vis),
            }
        };

        let mut widgets = Vec::new();
        widgets.push(widget_memvis);
        widgets.push(widget_vidram_bg);
        widgets.push(widget_vidram_tiles);

        ApplicationState {
            gameboy: gameboy,
            sdl_context: sdl_context,
            sound_system: device,
            renderer: renderer,
            cycle_count: 0,
            prev_time: 0,
            debugger: debugger,
            prev_hsync_cycles: 0,
            clock_cycles: 0,
            initial_gameboy_state: gbcopy,
            logger_handle: handle,
            controller: controller,
            screenshot_frame_num: Wrapping(0),
            ui_scale: SCALE,
            ui_offset: Point::new(0, 0),
            widgets: widgets,
        }
    }

    pub fn display_coords_to_ui_point(&self, x: i32, y: i32) -> Point {
        let s_x = (x as f32 / self.ui_scale) as i32;
        let s_y = (y as f32 / self.ui_scale) as i32;
        Point::new(s_x, s_y)
    }

    /// Handles both controller input and keyboard/mouse debug input
    /// NOTE: does not handle input for ncurses debugger
    pub fn handle_events(&mut self) {
        for event in self.sdl_context.event_pump().unwrap().poll_iter() {
            use sdl2::event::Event;

            match event {
                Event::ControllerAxisMotion { axis, value: val, .. } => {
                    let deadzone = 10000;
                    debug!("Axis {:?} moved to {}", axis, val);
                    match axis {
                        controller::Axis::LeftX if deadzone < (val as i32).abs() => {
                            if val < 0 {
                                self.gameboy.press_left();
                                self.gameboy.unpress_right();
                            } else {
                                self.gameboy.press_right();
                                self.gameboy.unpress_left();
                            };
                        },
                        controller::Axis::LeftX => {
                            self.gameboy.unpress_left();
                            self.gameboy.unpress_right();
                        },
                        controller::Axis::LeftY if deadzone < (val as i32).abs() => {
                            if val < 0 {
                                self.gameboy.press_up();
                                self.gameboy.unpress_down();
                            } else {
                                self.gameboy.press_down();
                                self.gameboy.unpress_up();
                            }
                        },
                        controller::Axis::LeftY => {
                            self.gameboy.unpress_up();
                            self.gameboy.unpress_down();
                        },
                        _ => {},
                    }

                }
                Event::ControllerButtonDown { button, .. } => {
                    debug!("Button {:?} down", button);
                    match button {
                        controller::Button::A => {
                            self.gameboy.press_a();
                            // TODO: sound
                            // device.resume();
                        }
                        controller::Button::B => self.gameboy.press_b(),
                        controller::Button::Back => self.gameboy.press_select(),
                        controller::Button::Start => self.gameboy.press_start(),
                        _ => (),
                    }
                }

                Event::ControllerButtonUp { button, .. } => {
                    debug!("Button {:?} up", button);
                    match button {
                        controller::Button::A => {
                            self.gameboy.unpress_a();
                            // TODO: sound
                            // device.pause();
                        }
                        controller::Button::B => self.gameboy.unpress_b(),
                        controller::Button::Back => self.gameboy.unpress_select(),
                        controller::Button::Start => self.gameboy.unpress_start(),
                        _ => (),
                    }
                }
                Event::Quit { .. } => {
                    info!("Program exiting!");
                    std::process::exit(0);
                }
                Event::KeyDown { keycode: Some(keycode), repeat, .. } => {
                    if !repeat {
                        match keycode {
                            Keycode::Escape => {
                                info!("Program exiting!");
                                std::process::exit(0);
                            }
                            Keycode::F3 => self.gameboy.toggle_logger(),
                            Keycode::R => {
                                // Reset/reload emu
                                // TODO Keep previous visualization settings
                                self.gameboy.reset();
                                let gbcopy = self.initial_gameboy_state.clone();
                                self.gameboy = gbcopy;
                                self.gameboy.reinit_logger();

                                // // This way makes it possible to edit rom
                                // // with external editor and see changes
                                // // instantly.
                                // gameboy = Cpu::new();
                            // gameboy.load_rom(rom_file);
                            }
                            Keycode::A => { self.gameboy.press_a() },
                            Keycode::S => { self.gameboy.press_b() },
                            Keycode::D => { self.gameboy.press_select() },
                            Keycode::F => { self.gameboy.press_start() },
                            Keycode::Up => { self.gameboy.press_up() },
                            Keycode::Down => { self.gameboy.press_down() },
                            Keycode::Left => { self.gameboy.press_left() },
                            Keycode::Right => { self.gameboy.press_right() },
                            _ => (),
                        }
                    }
                }
                Event::KeyUp { keycode: Some(keycode), repeat, .. } => {
                    if !repeat {
                        match keycode {
                            Keycode::A => { self.gameboy.unpress_a() },
                            Keycode::S => { self.gameboy.unpress_b() },
                            Keycode::D => { self.gameboy.unpress_select() },
                            Keycode::F => { self.gameboy.unpress_start() },
                            Keycode::Up => { self.gameboy.unpress_up() },
                            Keycode::Down => { self.gameboy.unpress_down() },
                            Keycode::Left => { self.gameboy.unpress_left() },
                            Keycode::Right => { self.gameboy.unpress_right() },

                            _ => (),
                        }
                    }
                }
                Event::MouseButtonDown { x, y, mouse_btn, .. } => {
                    // Transform screen coordinates in UI coordinates
                    let click_point = self.display_coords_to_ui_point(x, y);

                    // Find clicked widget
                    for widget in self.widgets.iter_mut() {
                        if widget.rect.contains(click_point) {
                            widget.click(mouse_btn, click_point, &mut self.gameboy);
                            break;
                        }
                    }
                }
                Event::MouseWheel { y, .. } => {
                    self.ui_scale += y as f32;
                    // self.widgets[0].scale += y as f32;
                }
                // // Event::MouseMotion { x, y, mousestate, xrel, yrel, .. } => {
                // Event::MouseMotion { x, y, .. } => {
                //     // Test widget position
                //     let mouse_pos = self.display_coords_to_ui_point(x+5, y+5);
                //     self.widgets[0].rect.reposition(mouse_pos);
                // }
                _ => (),
            }
        }
    }

    /// Runs the game application forward one "unit of time"
    /// TODO: elaborate
    pub fn step(&mut self) {

        // handle_events(&mut sdl_context, &mut gameboy);

        let current_op_time = if self.gameboy.state != cpu::constants::CpuState::Crashed {
            self.gameboy.dispatch_opcode() as u64
        } else {
            10 // FIXME think about what to return here or refactor code around this
        };

        self.cycle_count += current_op_time;
        self.clock_cycles += current_op_time;
        let timer_khz = self.gameboy.timer_frequency();
        let time_in_ms_per_cycle = (1000.0 / ((timer_khz as f64) * 1000.0)) as u64;
        self.clock_cycles += self.cycle_count;

        // TODO: remove prev_time
        let prev_time = self.prev_time;
        let ticks = self.cycle_count - prev_time;

        let time_in_cpu_cycle_per_cycle =
            ((time_in_ms_per_cycle as f64) / (1.0 / (4.19 * 1000.0 * 1000.0))) as u64;

        if self.clock_cycles >= time_in_cpu_cycle_per_cycle {
            //           std::thread::sleep_ms(16);
            // trace!("Incrementing the timer!");
            self.gameboy.timer_cycle();
            self.clock_cycles = 0;
        }

        let fake_display_hsync = true;
        if fake_display_hsync {
            // update LY respective to cycles spent execing instruction
            let cycle_count = self.cycle_count;
            loop {
                if cycle_count < self.prev_hsync_cycles {
                    break;
                }
                self.gameboy.inc_ly();
                self.prev_hsync_cycles += CYCLES_PER_HSYNC;
            }
        }

        // Gameboy screen is 256x256
        // only 160x144 are displayed at a time
        //
        // Background tile map is 32x32 of tiles. Scrollx and scrolly
        // determine how this is actually rendered (it wraps)
        // These numbers index the tile data table
        //

        // 16384hz, call inc_div
        // CPU is at 4.194304MHz (or 1.05MHz) 105000000hz
        // hsync at 9198KHz = 9198000hz
        // vsync at 59.73Hz

        let scale = self.ui_scale;
        match self.renderer.set_scale(scale, scale) {
            Ok(_) => (),
            Err(_) => error!("Could not set render scale"),
        }

        // 1ms before drawing in terms of CPU time we must throw a vblank interrupt
        // TODO make this variable based on whether it's GB, SGB, etc.

        if ticks >= CPU_CYCLES_PER_VBLANK {
            if let Some(ref mut dbg) = self.debugger {
                dbg.step(&mut self.gameboy);
            }

            let cycle_count = self.cycle_count;
            self.prev_time = cycle_count;
            self.renderer.set_draw_color(NICER_COLOR);
            self.renderer.clear();

            // Draw all widgets
            for ref mut widget in self.widgets.iter_mut() {
                widget.draw(&mut self.renderer, &mut self.gameboy);
            }

            //   00111100 1110001 00001000
            //   01111110 1110001 00010100
            //   11111111 1110001 00101010
            //

            // TODO add a way to enable/disable this while running
            let record_screen = false;
            if record_screen {
                save_screenshot(&self.renderer,
                                format!("screen{:010}.bmp", self.screenshot_frame_num.0));
                self.screenshot_frame_num += Wrapping(1);
            }

            if self.gameboy.get_sound1() {
                self.sound_system.resume();
            } else {
                self.sound_system.pause();
            }

            let mut sound_system = self.sound_system.lock();
            sound_system.wave_duty = self.gameboy.channel1_wave_pattern_duty();
            sound_system.phase_inc = 1.0 /
                                     (131072.0 / (2048 - self.gameboy.channel1_frequency()) as f32);
            sound_system.add = self.gameboy.channel1_sweep_increase();
            //            131072 / (2048 - gb)

            self.renderer.present();
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use libc::{c_void, c_char};
use ptr;
use ptr::RawPtr;
use vec;
use hashmap::HashSet;
use container::MutableSet;

extern {
    #[cfg(not(stage0))]
    #[weak_linkage]
    #[link_name = "_rust_crate_map_toplevel"]
    static CRATE_MAP: CrateMap;
}

pub struct ModEntry {
    name: *c_char,
    log_level: *mut u32
}
struct CrateMapV0 {
    entries: *ModEntry,
    children: [*CrateMap, ..1]
}

struct CrateMap {
    version: i32,
    annihilate_fn: *c_void,
    entries: *ModEntry,
    /// a dynamically sized struct, where all pointers to children are listed adjacent
    /// to the struct, terminated with NULL
    children: [*CrateMap, ..1]
}

#[cfg(not(stage0))]
pub fn get_crate_map() -> *CrateMap {
    &'static CRATE_MAP as *CrateMap
}

unsafe fn version(crate_map: *CrateMap) -> i32 {
    match (*crate_map).version {
        1 => return 1,
        _ => return 0
    }
}

/// Returns a pointer to the annihilate function of the CrateMap
pub unsafe fn annihilate_fn(crate_map: *CrateMap) -> *c_void {
    match version(crate_map) {
        0 => return ptr::null(),
        1 => return (*crate_map).annihilate_fn,
        _ => fail!("Unknown crate map version!")
    }
}

unsafe fn entries(crate_map: *CrateMap) -> *ModEntry {
    match version(crate_map) {
        0 => {
            let v0 = crate_map as (*CrateMapV0);
            return (*v0).entries;
        }
        1 => return (*crate_map).entries,
        _ => fail!("Unknown crate map version!")
    }
}

unsafe fn iterator(crate_map: *CrateMap) -> **CrateMap {
    match version(crate_map) {
        0 => {
            let v0 = crate_map as (*CrateMapV0);
            return vec::raw::to_ptr((*v0).children);
        }
        1 => return vec::raw::to_ptr((*crate_map).children),
        _ => fail!("Unknown crate map version!")
    }
}

unsafe fn iter_module_map(mod_entries: *ModEntry, f: &fn(*mut ModEntry)) {
    let mut curr = mod_entries;

    while !(*curr).name.is_null() {
        f(curr as *mut ModEntry);
        curr = curr.offset(1);
    }
}

unsafe fn do_iter_crate_map(crate_map: *CrateMap, f: &fn(*mut ModEntry),
                            visited: &mut HashSet<*CrateMap>) {
    if visited.insert(crate_map) {
        iter_module_map(entries(crate_map), |x| f(x));
        let child_crates = iterator(crate_map);
        do ptr::array_each(child_crates) |child| {
            do_iter_crate_map(child, |x| f(x), visited);
        }
    }
}

/// Iterates recursively over `crate_map` and all child crate maps
pub unsafe fn iter_crate_map(crate_map: *CrateMap, f: &fn(*mut ModEntry)) {
    // XXX: use random numbers as keys from the OS-level RNG when there is a nice
    //        way to do this
    let mut v: HashSet<*CrateMap> = HashSet::with_capacity_and_keys(0, 0, 32);
    do_iter_crate_map(crate_map, f, &mut v);
}

#[test]
fn iter_crate_map_duplicates() {
    use c_str::ToCStr;
    use cast::transmute;

    struct CrateMapT3 {
        version: i32,
        annihilate_fn: *c_void,
        entries: *ModEntry,
        children: [*CrateMap, ..3]
    }

    unsafe {
        let mod_name1 = "c::m1".to_c_str();
        let mut level3: u32 = 3;

        let entries: ~[ModEntry] = ~[
            ModEntry { name: mod_name1.with_ref(|buf| buf), log_level: &mut level3},
            ModEntry { name: ptr::null(), log_level: ptr::mut_null()}
        ];
        let child_crate = CrateMap {
            version: 1,
            annihilate_fn: ptr::null(),
            entries: vec::raw::to_ptr(entries),
            children: [ptr::null()]
        };

        let root_crate = CrateMapT3 {
            version: 1, annihilate_fn: ptr::null(),
            entries: vec::raw::to_ptr([ModEntry { name: ptr::null(), log_level: ptr::mut_null()}]),
            children: [&child_crate as *CrateMap, &child_crate as *CrateMap, ptr::null()]
        };

        let mut cnt = 0;
        do iter_crate_map(transmute(&root_crate)) |entry| {
            assert!(*(*entry).log_level == 3);
            cnt += 1;
        }
        assert!(cnt == 1);
    }
}

#[test]
fn iter_crate_map_follow_children() {
    use c_str::ToCStr;
    use cast::transmute;

    struct CrateMapT2 {
        version: i32,
        annihilate_fn: *c_void,
        entries: *ModEntry,
        children: [*CrateMap, ..2]
    }

    unsafe {
        let mod_name1 = "c::m1".to_c_str();
        let mod_name2 = "c::m2".to_c_str();
        let mut level2: u32 = 2;
        let mut level3: u32 = 3;
        let child_crate2 = CrateMap {
            version: 1,
            annihilate_fn: ptr::null(),
            entries: vec::raw::to_ptr([
                ModEntry { name: mod_name1.with_ref(|buf| buf), log_level: &mut level2},
                ModEntry { name: mod_name2.with_ref(|buf| buf), log_level: &mut level3},
                ModEntry { name: ptr::null(), log_level: ptr::mut_null()}
            ]),
            children: [ptr::null()]
        };

        let child_crate1 = CrateMapT2 {
            version: 1,
            annihilate_fn: ptr::null(),
            entries: vec::raw::to_ptr([
                ModEntry { name: "t::f1".to_c_str().with_ref(|buf| buf), log_level: &mut 1},
                ModEntry { name: ptr::null(), log_level: ptr::mut_null()}
            ]),
            children: [&child_crate2 as *CrateMap, ptr::null()]
        };

        let child_crate1_ptr: *CrateMap = transmute(&child_crate1);
        let root_crate = CrateMapT2 {
            version: 1, annihilate_fn: ptr::null(),
            entries: vec::raw::to_ptr([
                ModEntry { name: "t::f1".to_c_str().with_ref(|buf| buf), log_level: &mut 0},
                ModEntry { name: ptr::null(), log_level: ptr::mut_null()}
            ]),
            children: [child_crate1_ptr, ptr::null()]
        };

        let mut cnt = 0;
        do iter_crate_map(transmute(&root_crate)) |entry| {
            assert!(*(*entry).log_level == cnt);
            cnt += 1;
        }
        assert!(cnt == 4);
    }
}
<commit_msg>Fix unresolved symbol error for the crate_map in libstd on os x.<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use libc::{c_void, c_char};
use ptr;
use ptr::RawPtr;
use vec;
use hashmap::HashSet;
use container::MutableSet;

// Need to tell the linker on OS X to not barf on undefined symbols
// and instead look them up at runtime, which we need to resolve
// the crate_map properly.
#[cfg(target_os = "macos")]
#[link_args = "-undefined dynamic_lookup"]
extern {}

extern {
    #[cfg(not(stage0))]
    #[weak_linkage]
    #[link_name = "_rust_crate_map_toplevel"]
    static CRATE_MAP: CrateMap;
}

pub struct ModEntry {
    name: *c_char,
    log_level: *mut u32
}
struct CrateMapV0 {
    entries: *ModEntry,
    children: [*CrateMap, ..1]
}

struct CrateMap {
    version: i32,
    annihilate_fn: *c_void,
    entries: *ModEntry,
    /// a dynamically sized struct, where all pointers to children are listed adjacent
    /// to the struct, terminated with NULL
    children: [*CrateMap, ..1]
}

#[cfg(not(stage0))]
pub fn get_crate_map() -> *CrateMap {
    &'static CRATE_MAP as *CrateMap
}

unsafe fn version(crate_map: *CrateMap) -> i32 {
    match (*crate_map).version {
        1 => return 1,
        _ => return 0
    }
}

/// Returns a pointer to the annihilate function of the CrateMap
pub unsafe fn annihilate_fn(crate_map: *CrateMap) -> *c_void {
    match version(crate_map) {
        0 => return ptr::null(),
        1 => return (*crate_map).annihilate_fn,
        _ => fail!("Unknown crate map version!")
    }
}

unsafe fn entries(crate_map: *CrateMap) -> *ModEntry {
    match version(crate_map) {
        0 => {
            let v0 = crate_map as (*CrateMapV0);
            return (*v0).entries;
        }
        1 => return (*crate_map).entries,
        _ => fail!("Unknown crate map version!")
    }
}

unsafe fn iterator(crate_map: *CrateMap) -> **CrateMap {
    match version(crate_map) {
        0 => {
            let v0 = crate_map as (*CrateMapV0);
            return vec::raw::to_ptr((*v0).children);
        }
        1 => return vec::raw::to_ptr((*crate_map).children),
        _ => fail!("Unknown crate map version!")
    }
}

unsafe fn iter_module_map(mod_entries: *ModEntry, f: &fn(*mut ModEntry)) {
    let mut curr = mod_entries;

    while !(*curr).name.is_null() {
        f(curr as *mut ModEntry);
        curr = curr.offset(1);
    }
}

unsafe fn do_iter_crate_map(crate_map: *CrateMap, f: &fn(*mut ModEntry),
                            visited: &mut HashSet<*CrateMap>) {
    if visited.insert(crate_map) {
        iter_module_map(entries(crate_map), |x| f(x));
        let child_crates = iterator(crate_map);
        do ptr::array_each(child_crates) |child| {
            do_iter_crate_map(child, |x| f(x), visited);
        }
    }
}

/// Iterates recursively over `crate_map` and all child crate maps
pub unsafe fn iter_crate_map(crate_map: *CrateMap, f: &fn(*mut ModEntry)) {
    // XXX: use random numbers as keys from the OS-level RNG when there is a nice
    //        way to do this
    let mut v: HashSet<*CrateMap> = HashSet::with_capacity_and_keys(0, 0, 32);
    do_iter_crate_map(crate_map, f, &mut v);
}

#[test]
fn iter_crate_map_duplicates() {
    use c_str::ToCStr;
    use cast::transmute;

    struct CrateMapT3 {
        version: i32,
        annihilate_fn: *c_void,
        entries: *ModEntry,
        children: [*CrateMap, ..3]
    }

    unsafe {
        let mod_name1 = "c::m1".to_c_str();
        let mut level3: u32 = 3;

        let entries: ~[ModEntry] = ~[
            ModEntry { name: mod_name1.with_ref(|buf| buf), log_level: &mut level3},
            ModEntry { name: ptr::null(), log_level: ptr::mut_null()}
        ];
        let child_crate = CrateMap {
            version: 1,
            annihilate_fn: ptr::null(),
            entries: vec::raw::to_ptr(entries),
            children: [ptr::null()]
        };

        let root_crate = CrateMapT3 {
            version: 1, annihilate_fn: ptr::null(),
            entries: vec::raw::to_ptr([ModEntry { name: ptr::null(), log_level: ptr::mut_null()}]),
            children: [&child_crate as *CrateMap, &child_crate as *CrateMap, ptr::null()]
        };

        let mut cnt = 0;
        do iter_crate_map(transmute(&root_crate)) |entry| {
            assert!(*(*entry).log_level == 3);
            cnt += 1;
        }
        assert!(cnt == 1);
    }
}

#[test]
fn iter_crate_map_follow_children() {
    use c_str::ToCStr;
    use cast::transmute;

    struct CrateMapT2 {
        version: i32,
        annihilate_fn: *c_void,
        entries: *ModEntry,
        children: [*CrateMap, ..2]
    }

    unsafe {
        let mod_name1 = "c::m1".to_c_str();
        let mod_name2 = "c::m2".to_c_str();
        let mut level2: u32 = 2;
        let mut level3: u32 = 3;
        let child_crate2 = CrateMap {
            version: 1,
            annihilate_fn: ptr::null(),
            entries: vec::raw::to_ptr([
                ModEntry { name: mod_name1.with_ref(|buf| buf), log_level: &mut level2},
                ModEntry { name: mod_name2.with_ref(|buf| buf), log_level: &mut level3},
                ModEntry { name: ptr::null(), log_level: ptr::mut_null()}
            ]),
            children: [ptr::null()]
        };

        let child_crate1 = CrateMapT2 {
            version: 1,
            annihilate_fn: ptr::null(),
            entries: vec::raw::to_ptr([
                ModEntry { name: "t::f1".to_c_str().with_ref(|buf| buf), log_level: &mut 1},
                ModEntry { name: ptr::null(), log_level: ptr::mut_null()}
            ]),
            children: [&child_crate2 as *CrateMap, ptr::null()]
        };

        let child_crate1_ptr: *CrateMap = transmute(&child_crate1);
        let root_crate = CrateMapT2 {
            version: 1, annihilate_fn: ptr::null(),
            entries: vec::raw::to_ptr([
                ModEntry { name: "t::f1".to_c_str().with_ref(|buf| buf), log_level: &mut 0},
                ModEntry { name: ptr::null(), log_level: ptr::mut_null()}
            ]),
            children: [child_crate1_ptr, ptr::null()]
        };

        let mut cnt = 0;
        do iter_crate_map(transmute(&root_crate)) |entry| {
            assert!(*(*entry).log_level == cnt);
            cnt += 1;
        }
        assert!(cnt == 4);
    }
}
<|endoftext|>


<commit_before>use errors::*;
use multirust_dist::dist;
use multirust_utils::utils;
use multirust_dist::prefix::InstallPrefix;
use multirust_dist::dist::ToolchainDesc;
use multirust_dist::manifestation::{Manifestation, Changes};
use multirust_dist::manifest::Component;
use config::Cfg;
use env_var;
use install::{self, InstallMethod};

use std::process::Command;
use std::path::{Path, PathBuf};
use std::ffi::OsStr;
use std::env;

use hyper;

#[derive(Debug)]
pub struct Toolchain<'a> {
    cfg: &'a Cfg,
    name: String,
    path: PathBuf,
}

/// Used by the list_component function
pub struct ComponentStatus {
    pub component: Component,
    pub required: bool,
    pub installed: bool,
}

pub enum UpdateStatus {
    Installed,
    Updated,
    Unchanged,
}

impl<'a> Toolchain<'a> {
    pub fn from(cfg: &'a Cfg, name: &str) -> Self {
        let path = cfg.toolchains_dir.join(name);
        Toolchain {
            cfg: cfg,
            name: name.to_owned(),
            path: path.clone(),
        }
    }
    pub fn name(&self) -> &str {
        &self.name
    }
    pub fn path(&self) -> &Path {
        &self.path
    }
    pub fn exists(&self) -> bool {
        utils::is_directory(&self.path)
    }
    pub fn verify(&self) -> Result<()> {
        Ok(try!(utils::assert_is_directory(&self.path)))
    }
    pub fn remove(&self) -> Result<()> {
        if self.exists() {
            self.cfg.notify_handler.call(Notification::UninstallingToolchain(&self.name));
        } else {
            self.cfg.notify_handler.call(Notification::ToolchainNotInstalled(&self.name));
            return Ok(());
        }
        if let Some(update_hash) = try!(self.update_hash()) {
            try!(utils::remove_file("update hash", &update_hash));
        }
        let handler = self.cfg.notify_handler.as_ref();
        let result = install::uninstall(&self.path, ntfy!(&handler));
        if !self.exists() {
            self.cfg.notify_handler.call(Notification::UninstalledToolchain(&self.name));
        }
        Ok(try!(result))
    }
    fn install(&self, install_method: InstallMethod) -> Result<UpdateStatus> {
        assert!(self.is_valid_install_method(install_method));
        let exists = self.exists();
        if exists {
            self.cfg.notify_handler.call(Notification::UpdatingToolchain(&self.name));
        } else {
            self.cfg.notify_handler.call(Notification::InstallingToolchain(&self.name));
        }
        self.cfg
            .notify_handler
            .call(Notification::ToolchainDirectory(&self.path, &self.name));
        let handler = self.cfg.notify_handler.as_ref();
        let updated = try!(install_method.run(&self.path, ntfy!(&handler)));

        if !updated {
            self.cfg.notify_handler.call(Notification::UpdateHashMatches);
        } else {
            self.cfg.notify_handler.call(Notification::InstalledToolchain(&self.name));
        }

        let status = match (updated, exists) {
            (true, false) => UpdateStatus::Installed,
            (true, true) => UpdateStatus::Updated,
            (false, true) => UpdateStatus::Unchanged,
            (false, false) => unreachable!(),
        };

        Ok(status)
    }
    fn install_if_not_installed(&self, install_method: InstallMethod) -> Result<UpdateStatus> {
        assert!(self.is_valid_install_method(install_method));
        self.cfg.notify_handler.call(Notification::LookingForToolchain(&self.name));
        if !self.exists() {
            Ok(try!(self.install(install_method)))
        } else {
            self.cfg.notify_handler.call(Notification::UsingExistingToolchain(&self.name));
            Ok(UpdateStatus::Unchanged)
        }
    }
    fn is_valid_install_method(&self, install_method: InstallMethod) -> bool {
        match install_method {
            InstallMethod::Copy(_) |
            InstallMethod::Link(_) |
            InstallMethod::Installer(_, _) => self.is_custom(),
            InstallMethod::Dist(_, _, _) => !self.is_custom(),
        }
    }
    fn update_hash(&self) -> Result<Option<PathBuf>> {
        if self.is_custom() {
            Ok(None)
        } else {
            Ok(Some(try!(self.cfg.get_hash_file(&self.name, true))))
        }
    }

    fn download_cfg(&self) -> dist::DownloadCfg {
        dist::DownloadCfg {
            dist_root: &self.cfg.dist_root_url,
            temp_cfg: &self.cfg.temp_cfg,
            notify_handler: ntfy!(&self.cfg.notify_handler),
        }
    }

    pub fn install_from_dist(&self) -> Result<UpdateStatus> {
        let update_hash = try!(self.update_hash());
        self.install(InstallMethod::Dist(&self.name,
                                         update_hash.as_ref().map(|p| &**p),
                                         self.download_cfg()))
    }
    pub fn install_from_dist_if_not_installed(&self) -> Result<UpdateStatus> {
        let update_hash = try!(self.update_hash());
        self.install_if_not_installed(InstallMethod::Dist(&self.name,
                                                          update_hash.as_ref().map(|p| &**p),
                                                          self.download_cfg()))
    }
    pub fn is_custom(&self) -> bool {
        ToolchainDesc::from_str(&self.name).is_err()
    }
    pub fn is_tracking(&self) -> bool {
        ToolchainDesc::from_str(&self.name).ok().map(|d| d.is_tracking()) == Some(true)
    }

    fn ensure_custom(&self) -> Result<()> {
        if !self.is_custom() {
            Err(Error::Install(::multirust_dist::Error::InvalidCustomToolchainName(self.name.to_string())))
        } else {
            Ok(())
        }
    }

    pub fn install_from_installers(&self, installers: &[&OsStr]) -> Result<()> {
        try!(self.ensure_custom());

        try!(self.remove());

        // FIXME: This should do all downloads first, then do
        // installs, and do it all in a single transaction.
        for installer in installers {
            let installer_str = installer.to_str().unwrap_or("bogus");
            match installer_str.rfind(".") {
                Some(i) => {
                    let extension = &installer_str[i+1..];
                    if extension != "gz" {
                        return Err(Error::BadInstallerType(extension.to_string()));
                    }
                }
                None => return Err(Error::BadInstallerType(String::from("(none)")))
            }

            // FIXME: Pretty hacky
            let is_url = installer_str.starts_with("file://")
                || installer_str.starts_with("http://")
                || installer_str.starts_with("https://");
            let url = hyper::Url::parse(installer_str).ok();
            let url = if is_url { url } else { None };
            if let Some(url) = url {

                // Download to a local file
                let local_installer = try!(self.cfg.temp_cfg.new_file_with_ext("", ".tar.gz"));
                try!(utils::download_file(url,
                                          &local_installer,
                                          None,
                                          ntfy!(&self.cfg.notify_handler)));
                try!(self.install(InstallMethod::Installer(&local_installer, &self.cfg.temp_cfg)));
            } else {
                // If installer is a filename

                // No need to download
                let local_installer = Path::new(installer);

                // Install from file
                try!(self.install(InstallMethod::Installer(&local_installer, &self.cfg.temp_cfg)));
            }
        }

        Ok(())
    }

    pub fn install_from_dir(&self, src: &Path, link: bool) -> Result<()> {
        try!(self.ensure_custom());

        if link {
            try!(self.install(InstallMethod::Link(&try!(utils::to_absolute(src)))));
        } else {
            try!(self.install(InstallMethod::Copy(src)));
        }

        Ok(())
    }

    pub fn create_command<T: AsRef<OsStr>>(&self, binary: T) -> Result<Command> {
        if !self.exists() {
            return Err(Error::ToolchainNotInstalled(self.name.to_owned()));
        }

        let mut cmd = Command::new(binary);
        self.set_env(&mut cmd);
        Ok(cmd)
    }

    fn set_env(&self, cmd: &mut Command) {
        let ref bin_path = self.path.join("bin");

        self.set_ldpath(cmd);

        // Because multirust and cargo use slightly different
        // definitions of cargo home (multirust doesn't read HOME on
        // windows), we must set it here to ensure cargo and
        // multirust agree.
        if let Ok(cargo_home) = utils::cargo_home() {
            cmd.env("CARGO_HOME", &cargo_home);
        }

        env_var::set_path("PATH", bin_path, cmd);
        env_var::inc("RUST_RECURSION_COUNT", cmd);

        // FIXME: This should not be a path, but a toolchain name.
        // Not sure what's going on here.
        cmd.env("MULTIRUST_TOOLCHAIN", &self.path);
        cmd.env("MULTIRUST_HOME", &self.cfg.multirust_dir);
    }

    pub fn set_ldpath(&self, cmd: &mut Command) {
        let new_path = self.path.join("lib");

        env_var::set_path("LD_LIBRARY_PATH", &new_path, cmd);
        env_var::set_path("DYLD_LIBRARY_PATH", &new_path, cmd);
    }

    pub fn doc_path(&self, relative: &str) -> Result<PathBuf> {
        try!(self.verify());

        let parts = vec!["share", "doc", "rust", "html"];
        let mut doc_dir = self.path.clone();
        for part in parts {
            doc_dir.push(part);
        }
        doc_dir.push(relative);

        Ok(doc_dir)
    }
    pub fn open_docs(&self, relative: &str) -> Result<()> {
        try!(self.verify());

        Ok(try!(utils::open_browser(&try!(self.doc_path(relative)))))
    }

    pub fn make_default(&self) -> Result<()> {
        self.cfg.set_default(&self.name)
    }
    pub fn make_override(&self, path: &Path) -> Result<()> {
        Ok(try!(self.cfg.override_db.set(path,
                                         &self.name,
                                         &self.cfg.temp_cfg,
                                         self.cfg.notify_handler.as_ref())))
    }

    pub fn list_components(&self) -> Result<Vec<ComponentStatus>> {
        if !self.exists() {
            return Err(Error::ToolchainNotInstalled(self.name.to_owned()));
        }

        let ref toolchain = self.name;
        let ref toolchain = try!(ToolchainDesc::from_str(toolchain)
                                 .map_err(|_| Error::ComponentsUnsupported(self.name.to_string())));
        let trip = toolchain.target_triple();
        let prefix = InstallPrefix::from(self.path.to_owned());
        let manifestation = try!(Manifestation::open(prefix, &trip));

        if let Some(manifest) = try!(manifestation.load_manifest()) {
            let config = try!(manifestation.read_config());

            // Return all optional components of the "rust" package for the
            // toolchain's target triple.
            let mut res = Vec::new();

            let rust_pkg = manifest.packages.get("rust")
                .expect("manifest should cantain a rust package");
            let targ_pkg = rust_pkg.targets.get(&trip)
                .expect("installed manifest should have a known target");

            for component in &targ_pkg.components {
                let installed = config.as_ref()
                    .map(|c| c.components.contains(&component))
                    .unwrap_or(false);
                res.push(ComponentStatus {
                    component: component.clone(),
                    required: true,
                    installed: installed,
                });
            }

            for extension in &targ_pkg.extensions {
                let installed = config.as_ref()
                    .map(|c| c.components.contains(&extension))
                    .unwrap_or(false);
                res.push(ComponentStatus {
                    component: extension.clone(),
                    required: false,
                    installed: installed,
                });
            }

            res.sort_by(|a, b| a.component.cmp(&b.component));

            Ok(res)
        } else {
            Err(Error::ComponentsUnsupported(self.name.to_string()))
        }
    }

    pub fn add_component(&self, component: Component) -> Result<()> {
        if !self.exists() {
            return Err(Error::ToolchainNotInstalled(self.name.to_owned()));
        }

        let ref toolchain = self.name;
        let ref toolchain = try!(ToolchainDesc::from_str(toolchain)
                                 .map_err(|_| Error::ComponentsUnsupported(self.name.to_string())));
        let trip = toolchain.target_triple();
        let prefix = InstallPrefix::from(self.path.to_owned());
        let manifestation = try!(Manifestation::open(prefix, &trip));

        if let Some(manifest) = try!(manifestation.load_manifest()) {

            // Validate the component name
            let rust_pkg = manifest.packages.get("rust")
                .expect("manifest should cantain a rust package");
            let targ_pkg = rust_pkg.targets.get(&trip)
                .expect("installed manifest should have a known target");

            if targ_pkg.components.contains(&component) {
                return Err(Error::AddingRequiredComponent(self.name.to_string(), component));
            }

            if !targ_pkg.extensions.contains(&component) {
                return Err(Error::UnknownComponent(self.name.to_string(), component));
            }

            let changes = Changes {
                add_extensions: vec![component],
                remove_extensions: vec![]
            };

            try!(manifestation.update(&manifest,
                                      changes,
                                      self.download_cfg().temp_cfg,
                                      self.download_cfg().notify_handler.clone()));

            Ok(())
        } else {
            Err(Error::ComponentsUnsupported(self.name.to_string()))
        }
    }

    pub fn remove_component(&self, component: Component) -> Result<()> {
        if !self.exists() {
            return Err(Error::ToolchainNotInstalled(self.name.to_owned()));
        }

        let ref toolchain = self.name;
        let ref toolchain = try!(ToolchainDesc::from_str(toolchain)
                                 .map_err(|_| Error::ComponentsUnsupported(self.name.to_string())));
        let trip = toolchain.target_triple();
        let prefix = InstallPrefix::from(self.path.to_owned());
        let manifestation = try!(Manifestation::open(prefix, &trip));

        if let Some(manifest) = try!(manifestation.load_manifest()) {

            // Validate the component name
            let rust_pkg = manifest.packages.get("rust")
                .expect("manifest should cantain a rust package");
            let targ_pkg = rust_pkg.targets.get(&trip)
                .expect("installed manifest should have a known target");

            if targ_pkg.components.contains(&component) {
                return Err(Error::RemovingRequiredComponent(self.name.to_string(), component));
            }

            let dist_config = try!(manifestation.read_config()).unwrap();
            if !dist_config.components.contains(&component) {
                return Err(Error::UnknownComponent(self.name.to_string(), component));
            }

            let changes = Changes {
                add_extensions: vec![],
                remove_extensions: vec![component]
            };

            try!(manifestation.update(&manifest,
                                      changes,
                                      self.download_cfg().temp_cfg,
                                      self.download_cfg().notify_handler.clone()));

            Ok(())
        } else {
            Err(Error::ComponentsUnsupported(self.name.to_string()))
        }
    }

    pub fn binary_file(&self, name: &str) -> PathBuf {
        let mut path = self.path.clone();
        path.push("bin");
        path.push(name.to_owned() + env::consts::EXE_SUFFIX);
        path
    }
}
<commit_msg>Don't set the PATH environment variable when running proxies<commit_after>use errors::*;
use multirust_dist::dist;
use multirust_utils::utils;
use multirust_dist::prefix::InstallPrefix;
use multirust_dist::dist::ToolchainDesc;
use multirust_dist::manifestation::{Manifestation, Changes};
use multirust_dist::manifest::Component;
use config::Cfg;
use env_var;
use install::{self, InstallMethod};

use std::process::Command;
use std::path::{Path, PathBuf};
use std::ffi::OsStr;
use std::env;

use hyper;

#[derive(Debug)]
pub struct Toolchain<'a> {
    cfg: &'a Cfg,
    name: String,
    path: PathBuf,
}

/// Used by the list_component function
pub struct ComponentStatus {
    pub component: Component,
    pub required: bool,
    pub installed: bool,
}

pub enum UpdateStatus {
    Installed,
    Updated,
    Unchanged,
}

impl<'a> Toolchain<'a> {
    pub fn from(cfg: &'a Cfg, name: &str) -> Self {
        let path = cfg.toolchains_dir.join(name);
        Toolchain {
            cfg: cfg,
            name: name.to_owned(),
            path: path.clone(),
        }
    }
    pub fn name(&self) -> &str {
        &self.name
    }
    pub fn path(&self) -> &Path {
        &self.path
    }
    pub fn exists(&self) -> bool {
        utils::is_directory(&self.path)
    }
    pub fn verify(&self) -> Result<()> {
        Ok(try!(utils::assert_is_directory(&self.path)))
    }
    pub fn remove(&self) -> Result<()> {
        if self.exists() {
            self.cfg.notify_handler.call(Notification::UninstallingToolchain(&self.name));
        } else {
            self.cfg.notify_handler.call(Notification::ToolchainNotInstalled(&self.name));
            return Ok(());
        }
        if let Some(update_hash) = try!(self.update_hash()) {
            try!(utils::remove_file("update hash", &update_hash));
        }
        let handler = self.cfg.notify_handler.as_ref();
        let result = install::uninstall(&self.path, ntfy!(&handler));
        if !self.exists() {
            self.cfg.notify_handler.call(Notification::UninstalledToolchain(&self.name));
        }
        Ok(try!(result))
    }
    fn install(&self, install_method: InstallMethod) -> Result<UpdateStatus> {
        assert!(self.is_valid_install_method(install_method));
        let exists = self.exists();
        if exists {
            self.cfg.notify_handler.call(Notification::UpdatingToolchain(&self.name));
        } else {
            self.cfg.notify_handler.call(Notification::InstallingToolchain(&self.name));
        }
        self.cfg
            .notify_handler
            .call(Notification::ToolchainDirectory(&self.path, &self.name));
        let handler = self.cfg.notify_handler.as_ref();
        let updated = try!(install_method.run(&self.path, ntfy!(&handler)));

        if !updated {
            self.cfg.notify_handler.call(Notification::UpdateHashMatches);
        } else {
            self.cfg.notify_handler.call(Notification::InstalledToolchain(&self.name));
        }

        let status = match (updated, exists) {
            (true, false) => UpdateStatus::Installed,
            (true, true) => UpdateStatus::Updated,
            (false, true) => UpdateStatus::Unchanged,
            (false, false) => unreachable!(),
        };

        Ok(status)
    }
    fn install_if_not_installed(&self, install_method: InstallMethod) -> Result<UpdateStatus> {
        assert!(self.is_valid_install_method(install_method));
        self.cfg.notify_handler.call(Notification::LookingForToolchain(&self.name));
        if !self.exists() {
            Ok(try!(self.install(install_method)))
        } else {
            self.cfg.notify_handler.call(Notification::UsingExistingToolchain(&self.name));
            Ok(UpdateStatus::Unchanged)
        }
    }
    fn is_valid_install_method(&self, install_method: InstallMethod) -> bool {
        match install_method {
            InstallMethod::Copy(_) |
            InstallMethod::Link(_) |
            InstallMethod::Installer(_, _) => self.is_custom(),
            InstallMethod::Dist(_, _, _) => !self.is_custom(),
        }
    }
    fn update_hash(&self) -> Result<Option<PathBuf>> {
        if self.is_custom() {
            Ok(None)
        } else {
            Ok(Some(try!(self.cfg.get_hash_file(&self.name, true))))
        }
    }

    fn download_cfg(&self) -> dist::DownloadCfg {
        dist::DownloadCfg {
            dist_root: &self.cfg.dist_root_url,
            temp_cfg: &self.cfg.temp_cfg,
            notify_handler: ntfy!(&self.cfg.notify_handler),
        }
    }

    pub fn install_from_dist(&self) -> Result<UpdateStatus> {
        let update_hash = try!(self.update_hash());
        self.install(InstallMethod::Dist(&self.name,
                                         update_hash.as_ref().map(|p| &**p),
                                         self.download_cfg()))
    }
    pub fn install_from_dist_if_not_installed(&self) -> Result<UpdateStatus> {
        let update_hash = try!(self.update_hash());
        self.install_if_not_installed(InstallMethod::Dist(&self.name,
                                                          update_hash.as_ref().map(|p| &**p),
                                                          self.download_cfg()))
    }
    pub fn is_custom(&self) -> bool {
        ToolchainDesc::from_str(&self.name).is_err()
    }
    pub fn is_tracking(&self) -> bool {
        ToolchainDesc::from_str(&self.name).ok().map(|d| d.is_tracking()) == Some(true)
    }

    fn ensure_custom(&self) -> Result<()> {
        if !self.is_custom() {
            Err(Error::Install(::multirust_dist::Error::InvalidCustomToolchainName(self.name.to_string())))
        } else {
            Ok(())
        }
    }

    pub fn install_from_installers(&self, installers: &[&OsStr]) -> Result<()> {
        try!(self.ensure_custom());

        try!(self.remove());

        // FIXME: This should do all downloads first, then do
        // installs, and do it all in a single transaction.
        for installer in installers {
            let installer_str = installer.to_str().unwrap_or("bogus");
            match installer_str.rfind(".") {
                Some(i) => {
                    let extension = &installer_str[i+1..];
                    if extension != "gz" {
                        return Err(Error::BadInstallerType(extension.to_string()));
                    }
                }
                None => return Err(Error::BadInstallerType(String::from("(none)")))
            }

            // FIXME: Pretty hacky
            let is_url = installer_str.starts_with("file://")
                || installer_str.starts_with("http://")
                || installer_str.starts_with("https://");
            let url = hyper::Url::parse(installer_str).ok();
            let url = if is_url { url } else { None };
            if let Some(url) = url {

                // Download to a local file
                let local_installer = try!(self.cfg.temp_cfg.new_file_with_ext("", ".tar.gz"));
                try!(utils::download_file(url,
                                          &local_installer,
                                          None,
                                          ntfy!(&self.cfg.notify_handler)));
                try!(self.install(InstallMethod::Installer(&local_installer, &self.cfg.temp_cfg)));
            } else {
                // If installer is a filename

                // No need to download
                let local_installer = Path::new(installer);

                // Install from file
                try!(self.install(InstallMethod::Installer(&local_installer, &self.cfg.temp_cfg)));
            }
        }

        Ok(())
    }

    pub fn install_from_dir(&self, src: &Path, link: bool) -> Result<()> {
        try!(self.ensure_custom());

        if link {
            try!(self.install(InstallMethod::Link(&try!(utils::to_absolute(src)))));
        } else {
            try!(self.install(InstallMethod::Copy(src)));
        }

        Ok(())
    }

    pub fn create_command<T: AsRef<OsStr>>(&self, binary: T) -> Result<Command> {
        if !self.exists() {
            return Err(Error::ToolchainNotInstalled(self.name.to_owned()));
        }

        let ref bin_path = self.path.join("bin").join(binary.as_ref());
        let mut cmd = Command::new(bin_path);
        self.set_env(&mut cmd);
        Ok(cmd)
    }

    fn set_env(&self, cmd: &mut Command) {
        self.set_ldpath(cmd);

        // Because multirust and cargo use slightly different
        // definitions of cargo home (multirust doesn't read HOME on
        // windows), we must set it here to ensure cargo and
        // multirust agree.
        if let Ok(cargo_home) = utils::cargo_home() {
            cmd.env("CARGO_HOME", &cargo_home);
        }

        env_var::inc("RUST_RECURSION_COUNT", cmd);

        cmd.env("MULTIRUST_TOOLCHAIN", &self.name);
        cmd.env("MULTIRUST_HOME", &self.cfg.multirust_dir);
    }

    pub fn set_ldpath(&self, cmd: &mut Command) {
        let new_path = self.path.join("lib");

        env_var::set_path("LD_LIBRARY_PATH", &new_path, cmd);
        env_var::set_path("DYLD_LIBRARY_PATH", &new_path, cmd);
    }

    pub fn doc_path(&self, relative: &str) -> Result<PathBuf> {
        try!(self.verify());

        let parts = vec!["share", "doc", "rust", "html"];
        let mut doc_dir = self.path.clone();
        for part in parts {
            doc_dir.push(part);
        }
        doc_dir.push(relative);

        Ok(doc_dir)
    }
    pub fn open_docs(&self, relative: &str) -> Result<()> {
        try!(self.verify());

        Ok(try!(utils::open_browser(&try!(self.doc_path(relative)))))
    }

    pub fn make_default(&self) -> Result<()> {
        self.cfg.set_default(&self.name)
    }
    pub fn make_override(&self, path: &Path) -> Result<()> {
        Ok(try!(self.cfg.override_db.set(path,
                                         &self.name,
                                         &self.cfg.temp_cfg,
                                         self.cfg.notify_handler.as_ref())))
    }

    pub fn list_components(&self) -> Result<Vec<ComponentStatus>> {
        if !self.exists() {
            return Err(Error::ToolchainNotInstalled(self.name.to_owned()));
        }

        let ref toolchain = self.name;
        let ref toolchain = try!(ToolchainDesc::from_str(toolchain)
                                 .map_err(|_| Error::ComponentsUnsupported(self.name.to_string())));
        let trip = toolchain.target_triple();
        let prefix = InstallPrefix::from(self.path.to_owned());
        let manifestation = try!(Manifestation::open(prefix, &trip));

        if let Some(manifest) = try!(manifestation.load_manifest()) {
            let config = try!(manifestation.read_config());

            // Return all optional components of the "rust" package for the
            // toolchain's target triple.
            let mut res = Vec::new();

            let rust_pkg = manifest.packages.get("rust")
                .expect("manifest should cantain a rust package");
            let targ_pkg = rust_pkg.targets.get(&trip)
                .expect("installed manifest should have a known target");

            for component in &targ_pkg.components {
                let installed = config.as_ref()
                    .map(|c| c.components.contains(&component))
                    .unwrap_or(false);
                res.push(ComponentStatus {
                    component: component.clone(),
                    required: true,
                    installed: installed,
                });
            }

            for extension in &targ_pkg.extensions {
                let installed = config.as_ref()
                    .map(|c| c.components.contains(&extension))
                    .unwrap_or(false);
                res.push(ComponentStatus {
                    component: extension.clone(),
                    required: false,
                    installed: installed,
                });
            }

            res.sort_by(|a, b| a.component.cmp(&b.component));

            Ok(res)
        } else {
            Err(Error::ComponentsUnsupported(self.name.to_string()))
        }
    }

    pub fn add_component(&self, component: Component) -> Result<()> {
        if !self.exists() {
            return Err(Error::ToolchainNotInstalled(self.name.to_owned()));
        }

        let ref toolchain = self.name;
        let ref toolchain = try!(ToolchainDesc::from_str(toolchain)
                                 .map_err(|_| Error::ComponentsUnsupported(self.name.to_string())));
        let trip = toolchain.target_triple();
        let prefix = InstallPrefix::from(self.path.to_owned());
        let manifestation = try!(Manifestation::open(prefix, &trip));

        if let Some(manifest) = try!(manifestation.load_manifest()) {

            // Validate the component name
            let rust_pkg = manifest.packages.get("rust")
                .expect("manifest should cantain a rust package");
            let targ_pkg = rust_pkg.targets.get(&trip)
                .expect("installed manifest should have a known target");

            if targ_pkg.components.contains(&component) {
                return Err(Error::AddingRequiredComponent(self.name.to_string(), component));
            }

            if !targ_pkg.extensions.contains(&component) {
                return Err(Error::UnknownComponent(self.name.to_string(), component));
            }

            let changes = Changes {
                add_extensions: vec![component],
                remove_extensions: vec![]
            };

            try!(manifestation.update(&manifest,
                                      changes,
                                      self.download_cfg().temp_cfg,
                                      self.download_cfg().notify_handler.clone()));

            Ok(())
        } else {
            Err(Error::ComponentsUnsupported(self.name.to_string()))
        }
    }

    pub fn remove_component(&self, component: Component) -> Result<()> {
        if !self.exists() {
            return Err(Error::ToolchainNotInstalled(self.name.to_owned()));
        }

        let ref toolchain = self.name;
        let ref toolchain = try!(ToolchainDesc::from_str(toolchain)
                                 .map_err(|_| Error::ComponentsUnsupported(self.name.to_string())));
        let trip = toolchain.target_triple();
        let prefix = InstallPrefix::from(self.path.to_owned());
        let manifestation = try!(Manifestation::open(prefix, &trip));

        if let Some(manifest) = try!(manifestation.load_manifest()) {

            // Validate the component name
            let rust_pkg = manifest.packages.get("rust")
                .expect("manifest should cantain a rust package");
            let targ_pkg = rust_pkg.targets.get(&trip)
                .expect("installed manifest should have a known target");

            if targ_pkg.components.contains(&component) {
                return Err(Error::RemovingRequiredComponent(self.name.to_string(), component));
            }

            let dist_config = try!(manifestation.read_config()).unwrap();
            if !dist_config.components.contains(&component) {
                return Err(Error::UnknownComponent(self.name.to_string(), component));
            }

            let changes = Changes {
                add_extensions: vec![],
                remove_extensions: vec![component]
            };

            try!(manifestation.update(&manifest,
                                      changes,
                                      self.download_cfg().temp_cfg,
                                      self.download_cfg().notify_handler.clone()));

            Ok(())
        } else {
            Err(Error::ComponentsUnsupported(self.name.to_string()))
        }
    }

    pub fn binary_file(&self, name: &str) -> PathBuf {
        let mut path = self.path.clone();
        path.push("bin");
        path.push(name.to_owned() + env::consts::EXE_SUFFIX);
        path
    }
}
<|endoftext|>


<commit_before>extern crate nalgebra as na;
extern crate ws;

use std::collections::HashMap;
use self::na::Matrix4;
use std::rc::Rc;
use std::cell::RefCell;
use server;
use std::thread;
use std::thread::{JoinHandle};
use renderers;
use std::sync::{Arc, RwLock};
use self::ws::{listen, Sender as WSSender, Handler, Message, CloseCode, Handshake};
use std::sync::mpsc;
// use serde_json::builder::{ArrayBuilder, ObjectBuilder};

#[derive(Clone)]
enum WSMessage {
    INITIAL_PAYLOAD = 0
}

struct WebsocketServer {
    out: WSSender,
    graphs: Arc<RwLock<server::Graphs>>
    // rx: mspc::Receiver<WSMessage>,
}

impl Handler for WebsocketServer {
    // fn on_open(&mut self, _: Handshake) -> Result<(), Error> {
    //     thread::spawn(move || {
    //         loop {
    //             let message = self.rx.recv().unwrap();
    //             self.out.send(message);
    //         }
    //     })
    //     self.out.send()
    // }

    fn on_message(&mut self, msg: Message) -> ws::Result<()> {
        let graphs = self.graphs.as_ref().read().unwrap();
        graphs.n;
        let data = msg.into_data();
        self.out.send("foo")
    }
}

pub struct WebGLRenderer {
    viewer: renderers::Viewer,
    options: HashMap<String, String>,
    handle: Option<JoinHandle<()>>
    // rx: Receiver<WSMessage>
}

impl WebGLRenderer {

    // fn get_payload_message(&self) -> Message {
        // MessageTypes::INITIAL_PAYLOAD;
        // self.viewer;
        // let value = ObjectBuilder::new()
        //     .insert("cameras", ArrayBuilder::new()
        //             .)
        //     pub cameras: HashMap<String, Camera>,
        // pub transform: Matrix4<f32>,
    // }

    pub fn new(
        graphs: Arc<RwLock<server::Graphs>>,
        viewer: renderers::Viewer,
        options: HashMap<String, String>
    ) -> WebGLRenderer {
        let mut renderer = WebGLRenderer{
            viewer: viewer,
            options: options,
            handle: None,
        };

        let addr = "127.0.0.1:12345";
        renderer.handle = Some(thread::spawn(move || {
            listen(addr, |out| {
                // add a listener tx to a shared list and rx to the server
                WebsocketServer{
                    out: out,
                    graphs: graphs.clone()
                    //rx: foo.clone()
                }
            }).unwrap();
        }));

        renderer
    }
}

impl renderers::Renderer for WebGLRenderer {

    fn viewer(&mut self) -> &mut renderers::Viewer {
        &mut self.viewer
    }

    fn set_viewer_transform(&mut self, transform: Matrix4<f32>) {
        // self.bus.unwrap().broadcast(WSMessage::INITIAL_PAYLOAD)
        // self.rx.send(Message{
        //     type: SET_VIEWER_TRANSFORM,
        //     transform: transform
        // });
    }

    fn add_camera(&mut self, camera: &renderers::Camera) {
        // self.rx.send(Message{
        //     type: ADD_CAMERA,
        //     camera: camera
        // });
    }

    fn delete_camera_with_name(&mut self, name: &str) {
        // self.rx.send(Message{
        //     type: DELETE_CAMERA_WITH_NAME,
        //     name: name
        // });
    }

    fn set_camera_transform(&mut self, camera_name: &str, transform: Matrix4<f32>) {
        // self.rx.send(Message{
        //     type: SET_CAMERA_TRANSFORM,
        //     name: camera_name,
        //     transform: transform
        // });
    }

    fn set_camera_projection(&mut self, camera_name: &str, projection: Matrix4<f32>) {
        // self.rx.send(Message{
        //     type: SET_CAMERA_PROJECTION,
        //     name: camera_name,
        //     projection: projection
        // });
    }
}
<commit_msg>Use channels<commit_after>extern crate nalgebra as na;
extern crate ws;

use std::collections::HashMap;
use self::na::Matrix4;
use server;
use std::thread;
use std::thread::{JoinHandle};
use renderers;
use std::sync::{Arc, RwLock};
use self::ws::{WebSocket, Sender as WSSender, Handler, Message};
use std::sync::mpsc;

#[derive(Clone)]
enum WSMessage {
    INITIAL_PAYLOAD = 0
}

struct WebsocketServer {
    out: WSSender,
    graphs: Arc<RwLock<server::Graphs>>
    // rx: mspc::Receiver<WSMessage>,
}

impl Handler for WebsocketServer {
    // fn on_open(&mut self, _: Handshake) -> Result<(), Error> {
    //     thread::spawn(move || {
    //         loop {
    //             let message = self.rx.recv().unwrap();
    //             self.out.send(message);
    //         }
    //     })
    //     self.out.send()
    // }

    fn on_message(&mut self, msg: Message) -> ws::Result<()> {
        let graphs = self.graphs.as_ref().read().unwrap();
        graphs.n;
        let data = msg.into_data();
        self.out.send("response")
    }
}

pub struct WebGLRenderer {
    viewer: renderers::Viewer,
    options: HashMap<String, String>,
    join_handle: Option<JoinHandle<()>>,
    tx: mpsc::Sender<Message>
}

impl WebGLRenderer {

    pub fn new(
        graphs: Arc<RwLock<server::Graphs>>,
        viewer: renderers::Viewer,
        options: HashMap<String, String>
    ) -> WebGLRenderer {
        let (tx, rx) = mpsc::channel();

        let mut renderer = WebGLRenderer{
            viewer: viewer,
            options: options,
            join_handle: None,
            tx: tx
        };

        let addr = "127.0.0.1:12345";
        renderer.join_handle = Some(thread::spawn(move || {
            let ws = WebSocket::new(|out| {
                WebsocketServer{
                    out: out,
                    graphs: graphs.clone()
                }
            }).unwrap();
            let broadcaster = ws.broadcaster();

            thread::spawn(move || {
                let msg = rx.recv().unwrap();
                let _ = broadcaster.send(msg);
            });

            ws.listen(addr).unwrap();
        }));

        renderer
    }
}

impl Drop for WebGLRenderer {

    fn drop(&mut self) {
        self.join_handle.take().unwrap().join();
    }
}

impl renderers::Renderer for WebGLRenderer {

    fn viewer(&mut self) -> &mut renderers::Viewer {
        &mut self.viewer
    }

    fn set_viewer_transform(&mut self, transform: Matrix4<f32>) {
        let msg = ws::Message::Text("hello world".to_string());
        let _ = self.tx.send(msg);
        // self.bus.unwrap().broadcast(WSMessage::INITIAL_PAYLOAD)
        // self.rx.send(Message{
        //     type: SET_VIEWER_TRANSFORM,
        //     transform: transform
        // });
    }

    fn add_camera(&mut self, camera: &renderers::Camera) {
        // self.rx.send(Message{
        //     type: ADD_CAMERA,
        //     camera: camera
        // });
    }

    fn delete_camera_with_name(&mut self, name: &str) {
        // self.rx.send(Message{
        //     type: DELETE_CAMERA_WITH_NAME,
        //     name: name
        // });
    }

    fn set_camera_transform(&mut self, camera_name: &str, transform: Matrix4<f32>) {
        // self.rx.send(Message{
        //     type: SET_CAMERA_TRANSFORM,
        //     name: camera_name,
        //     transform: transform
        // });
    }

    fn set_camera_projection(&mut self, camera_name: &str, projection: Matrix4<f32>) {
        // self.rx.send(Message{
        //     type: SET_CAMERA_PROJECTION,
        //     name: camera_name,
        //     projection: projection
        // });
    }
}
<|endoftext|>


<commit_before>extern crate imap;
extern crate openssl;

use openssl::ssl::{SslContext, SslMethod};
use imap::client::Client;
use imap::mailbox::Mailbox;

fn main() {
	let mut imap_socket = Client::secure_connect(("imap.gmail.com", 993), SslContext::new(SslMethod::Sslv23).unwrap()).unwrap();

	imap_socket.login("username", "password").unwrap();

	match imap_socket.capability() {
		Ok(capabilities) => {
			for capability in capabilities.iter() {
				println!("{}", capability);
			}
		},
		Err(e) => println!("Error parsing capability: {}", e)
	};

	match imap_socket.select("INBOX") {
		Ok(Mailbox{flags, exists, recent, unseen, permanent_flags, uid_next, uid_validity}) => {
			println!("flags: {}, exists: {}, recent: {}, unseen: {:?}, permanent_flags: {:?}, uid_next: {:?}, uid_validity: {:?}", flags, exists, recent, unseen, permanent_flags, uid_next, uid_validity);
		},
		Err(e) => println!("Error selecting INBOX: {}", e)
	};

	match imap_socket.fetch("2", "body[text]") {
		Ok(lines) => {
			for line in lines.iter() {
				print!("{}", line);
			}
		},
		Err(e) => println!("Error Fetching email 2: {}", e)
	};

	imap_socket.logout().unwrap();
}
<commit_msg>Removing complicated printing of mailbox<commit_after>extern crate imap;
extern crate openssl;

use openssl::ssl::{SslContext, SslMethod};
use imap::client::Client;

fn main() {
	let mut imap_socket = Client::secure_connect(("imap.gmail.com", 993), SslContext::new(SslMethod::Sslv23).unwrap()).unwrap();

	imap_socket.login("username", "password").unwrap();

	match imap_socket.capability() {
		Ok(capabilities) => {
			for capability in capabilities.iter() {
				println!("{}", capability);
			}
		},
		Err(e) => println!("Error parsing capability: {}", e)
	};

	match imap_socket.select("INBOX") {
		Ok(mailbox) => {
			println!("{}", mailbox);
		},
		Err(e) => println!("Error selecting INBOX: {}", e)
	};

	match imap_socket.fetch("2", "body[text]") {
		Ok(lines) => {
			for line in lines.iter() {
				print!("{}", line);
			}
		},
		Err(e) => println!("Error Fetching email 2: {}", e)
	};

	imap_socket.logout().unwrap();
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use extra::json;
use serialize::Decodable;
use glfw;
use gl;
use gl::types::{
  GLfloat,
  GLint,
  GLuint,
};
use cgmath::vector::{
  Vec3,
  Vec2,
};
use glh = gl_helpers;
use camera::Camera;
use map::TileIterator;
use geom::Geom;
use tile_picker::TilePicker;
use obj;
use mesh::Mesh;
use misc::read_file;

fn build_hex_mesh(&geom: &Geom) -> ~[Vec3<GLfloat>] {
  let mut vertex_data = ~[];
  for tile_pos in TileIterator::new() {
    let pos3d = geom.v2i_to_v2f(tile_pos).extend(0.0);
    for num in range(0, 6) {
      let vertex = geom.index_to_hex_vertex(num);
      let next_vertex = geom.index_to_hex_vertex(num + 1);
      let data = &mut vertex_data;
      data.push(pos3d + vertex.extend(0.0));
      data.push(pos3d + next_vertex.extend(0.0));
      data.push(pos3d + Vec3::zero());
    }
  }
  vertex_data
}

pub struct Visualizer {
  program: GLuint,
  map_mesh: Mesh,
  unit_mesh: Mesh,
  mat_id: GLint,
  win: Option<glfw::Window>,
  mouse_pos: Vec2<f32>,
  camera: Camera,
  picker: TilePicker,
  selected_tile_pos: Option<Vec2<i32>>,
  geom: Geom,
}

fn init_win(win_size: Vec2<int>) -> glfw::Window {
  glfw::set_error_callback(~glfw::LogErrorHandler);
  let init_status = glfw::init();
  if !init_status.is_ok() {
    fail!("Failed to initialize GLFW");
  }
  let win = glfw::Window::create(
    win_size.x as u32,
    win_size.y as u32,
    "OpenGL",
    glfw::Windowed,
  ).unwrap();
  win.make_context_current();
  win.set_all_polling(true);
  win
}

#[deriving(Decodable)]
struct Size2<T> {
  x: T,
  y: T,
}

fn read_win_size(config_path: &str) -> Vec2<int> {
  let path = Path::new(config_path);
  let json = json::from_str(read_file(&path)).unwrap();
  let mut decoder = json::Decoder::new(json);
  let size: Size2<int> = Decodable::decode(&mut decoder);
  Vec2{x: size.x, y: size.y}
}

impl Visualizer {
  pub fn new() -> ~Visualizer {
    let win_size = read_win_size("config.json");
    let win = init_win(win_size);
    let geom = Geom::new();
    let mut vis = ~Visualizer {
      program: 0,
      map_mesh: Mesh::new(),
      unit_mesh: Mesh::new(),
      mat_id: 0,
      win: Some(win),
      mouse_pos: Vec2::zero(),
      camera: Camera::new(),
      picker: TilePicker::new(),
      selected_tile_pos: None,
      geom: geom,
    };
    vis.init_opengl();
    vis.picker.init(&geom);
    vis.init_models();
    vis
  }

  fn win<'a>(&'a self) -> &'a glfw::Window {
    self.win.get_ref()
  }

  fn init_models(&mut self) {
    self.program = glh::compile_program(
      read_file(&Path::new("normal.vs.glsl")),
      read_file(&Path::new("normal.fs.glsl")),
    );
    gl::UseProgram(self.program);
    self.mat_id = glh::get_uniform(self.program, "mvp_mat");
    let pos_attr = glh::get_attr(self.program, "position");
    glh::vertex_attrib_pointer(pos_attr);
    let map_vertex_data = build_hex_mesh(&self.geom);
    self.map_mesh.init(map_vertex_data);
    let unit_obj = obj::Model::new("tank.obj");
    self.unit_mesh.init(unit_obj.build());
  }

  fn init_opengl(&mut self) {
    gl::load_with(glfw::get_proc_address);
  }

  fn cleanup_opengl(&self) {
    gl::DeleteProgram(self.program);
  }

  fn draw(&self) {
    gl::ClearColor(0.3, 0.3, 0.3, 1.0);
    gl::Clear(gl::COLOR_BUFFER_BIT);
    gl::UseProgram(self.program);
    glh::uniform_mat4f(self.mat_id, &self.camera.mat());
    self.map_mesh.draw(self.program);
    self.unit_mesh.draw(self.program);
    self.win().swap_buffers();
  }

  pub fn is_running(&self) -> bool {
    return !self.win().should_close()
  }

  fn handle_key_event(&mut self, key: glfw::Key) {
    match key {
      glfw::KeyEscape | glfw::KeyQ => {
        self.win().set_should_close(true);
      },
      glfw::KeySpace => println!("space"),
      glfw::KeyUp => self.camera.move(270.0),
      glfw::KeyDown => self.camera.move(90.0),
      glfw::KeyRight => self.camera.move(0.0),
      glfw::KeyLeft => self.camera.move(180.0),
      _ => {},
    }
  }

  fn handle_cursor_pos_event(&mut self, pos: Vec2<f32>) {
    let button = self.win().get_mouse_button(glfw::MouseButtonRight);
    if button == glfw::Press {
      self.camera.z_angle += self.mouse_pos.x - pos.x;
      self.camera.x_angle += self.mouse_pos.y - pos.y;
    }
    self.mouse_pos = pos;
  }

  fn get_events(&mut self) -> ~[glfw::WindowEvent]{
    glfw::poll_events();
    let mut events = ~[];
    for (_, event) in self.win().flush_events() {
      events.push(event);
    }
    events
  }

  fn handle_event(&mut self, event: glfw::WindowEvent) {
    match event {
      glfw::KeyEvent(key, _, glfw::Press, _) => {
        self.handle_key_event(key);
      },
      glfw::CursorPosEvent(x, y) => {
        let p = Vec2{x: x as f32, y: y as f32};
        self.handle_cursor_pos_event(p);
      },
      _ => {},
    }
  }

  fn handle_events(&mut self) {
    for event in self.get_events().iter() {
      self.handle_event(*event);
    }
  }

  fn close_window(&mut self) {
    // destroy glfw::Window before terminating glfw
    self.win = None;
  }

  fn pick_tile(&mut self) {
    let mouse_pos = Vec2 {
      x: self.mouse_pos.x as i32,
      y: self.mouse_pos.y as i32,
    };
    let win_size = self.win().get_size();
    self.selected_tile_pos = self.picker.pick_tile(
      win_size, &self.camera, mouse_pos);
    println!("selected: {:?}", self.selected_tile_pos);
  }

  pub fn tick(&mut self) {
    self.handle_events();
    self.pick_tile();
    self.draw();
  }
}

impl Drop for Visualizer {
  fn drop(&mut self) {
    self.cleanup_opengl();
    self.close_window();
    glfw::terminate();
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<commit_msg>Visualizer: draw_unit_at(self, pos)<commit_after>// See LICENSE file for copyright and license details.

use extra::json;
use serialize::Decodable;
use glfw;
use gl;
use gl::types::{
  GLfloat,
  GLint,
  GLuint,
};
use cgmath::vector::{
  Vec3,
  Vec2,
};
use glh = gl_helpers;
use camera::Camera;
use map::TileIterator;
use geom::Geom;
use tile_picker::TilePicker;
use obj;
use mesh::Mesh;
use misc::read_file;

fn build_hex_mesh(&geom: &Geom) -> ~[Vec3<GLfloat>] {
  let mut vertex_data = ~[];
  for tile_pos in TileIterator::new() {
    let pos3d = geom.v2i_to_v2f(tile_pos).extend(0.0);
    for num in range(0, 6) {
      let vertex = geom.index_to_hex_vertex(num);
      let next_vertex = geom.index_to_hex_vertex(num + 1);
      let data = &mut vertex_data;
      data.push(pos3d + vertex.extend(0.0));
      data.push(pos3d + next_vertex.extend(0.0));
      data.push(pos3d + Vec3::zero());
    }
  }
  vertex_data
}

pub struct Visualizer {
  program: GLuint,
  map_mesh: Mesh,
  unit_mesh: Mesh,
  mat_id: GLint,
  win: Option<glfw::Window>,
  mouse_pos: Vec2<f32>,
  camera: Camera,
  picker: TilePicker,
  selected_tile_pos: Option<Vec2<i32>>,
  geom: Geom,
}

fn init_win(win_size: Vec2<int>) -> glfw::Window {
  glfw::set_error_callback(~glfw::LogErrorHandler);
  let init_status = glfw::init();
  if !init_status.is_ok() {
    fail!("Failed to initialize GLFW");
  }
  let win = glfw::Window::create(
    win_size.x as u32,
    win_size.y as u32,
    "OpenGL",
    glfw::Windowed,
  ).unwrap();
  win.make_context_current();
  win.set_all_polling(true);
  win
}

#[deriving(Decodable)]
struct Size2<T> {
  x: T,
  y: T,
}

fn read_win_size(config_path: &str) -> Vec2<int> {
  let path = Path::new(config_path);
  let json = json::from_str(read_file(&path)).unwrap();
  let mut decoder = json::Decoder::new(json);
  let size: Size2<int> = Decodable::decode(&mut decoder);
  Vec2{x: size.x, y: size.y}
}

impl Visualizer {
  pub fn new() -> ~Visualizer {
    let win_size = read_win_size("config.json");
    let win = init_win(win_size);
    let geom = Geom::new();
    let mut vis = ~Visualizer {
      program: 0,
      map_mesh: Mesh::new(),
      unit_mesh: Mesh::new(),
      mat_id: 0,
      win: Some(win),
      mouse_pos: Vec2::zero(),
      camera: Camera::new(),
      picker: TilePicker::new(),
      selected_tile_pos: None,
      geom: geom,
    };
    vis.init_opengl();
    vis.picker.init(&geom);
    vis.init_models();
    vis
  }

  fn win<'a>(&'a self) -> &'a glfw::Window {
    self.win.get_ref()
  }

  fn init_models(&mut self) {
    self.program = glh::compile_program(
      read_file(&Path::new("normal.vs.glsl")),
      read_file(&Path::new("normal.fs.glsl")),
    );
    gl::UseProgram(self.program);
    self.mat_id = glh::get_uniform(self.program, "mvp_mat");
    let pos_attr = glh::get_attr(self.program, "position");
    glh::vertex_attrib_pointer(pos_attr);
    let map_vertex_data = build_hex_mesh(&self.geom);
    self.map_mesh.init(map_vertex_data);
    let unit_obj = obj::Model::new("tank.obj");
    self.unit_mesh.init(unit_obj.build());
  }

  fn init_opengl(&mut self) {
    gl::load_with(glfw::get_proc_address);
  }

  fn cleanup_opengl(&self) {
    gl::DeleteProgram(self.program);
  }

  fn draw_unit_at(&self, pos: Vec2<i32>) {
    let world_pos = self.geom.v2i_to_v2f(pos).extend(0.0);
    let m = glh::tr(self.camera.mat(), world_pos);
    glh::uniform_mat4f(self.mat_id, &m);
    self.unit_mesh.draw(self.program);
  }

  fn draw(&self) {
    gl::ClearColor(0.3, 0.3, 0.3, 1.0);
    gl::Clear(gl::COLOR_BUFFER_BIT);
    gl::UseProgram(self.program);
    self.draw_unit_at(Vec2{x: 0, y: 0});
    self.draw_unit_at(Vec2{x: 1, y: 0});
    self.draw_unit_at(Vec2{x: 2, y: 0});
    self.draw_unit_at(Vec2{x: 1, y: 1});
    glh::uniform_mat4f(self.mat_id, &self.camera.mat());
    self.map_mesh.draw(self.program);
    self.win().swap_buffers();
  }

  pub fn is_running(&self) -> bool {
    return !self.win().should_close()
  }

  fn handle_key_event(&mut self, key: glfw::Key) {
    match key {
      glfw::KeyEscape | glfw::KeyQ => {
        self.win().set_should_close(true);
      },
      glfw::KeySpace => println!("space"),
      glfw::KeyUp => self.camera.move(270.0),
      glfw::KeyDown => self.camera.move(90.0),
      glfw::KeyRight => self.camera.move(0.0),
      glfw::KeyLeft => self.camera.move(180.0),
      _ => {},
    }
  }

  fn handle_cursor_pos_event(&mut self, pos: Vec2<f32>) {
    let button = self.win().get_mouse_button(glfw::MouseButtonRight);
    if button == glfw::Press {
      self.camera.z_angle += self.mouse_pos.x - pos.x;
      self.camera.x_angle += self.mouse_pos.y - pos.y;
    }
    self.mouse_pos = pos;
  }

  fn get_events(&mut self) -> ~[glfw::WindowEvent]{
    glfw::poll_events();
    let mut events = ~[];
    for (_, event) in self.win().flush_events() {
      events.push(event);
    }
    events
  }

  fn handle_event(&mut self, event: glfw::WindowEvent) {
    match event {
      glfw::KeyEvent(key, _, glfw::Press, _) => {
        self.handle_key_event(key);
      },
      glfw::CursorPosEvent(x, y) => {
        let p = Vec2{x: x as f32, y: y as f32};
        self.handle_cursor_pos_event(p);
      },
      _ => {},
    }
  }

  fn handle_events(&mut self) {
    for event in self.get_events().iter() {
      self.handle_event(*event);
    }
  }

  fn close_window(&mut self) {
    // destroy glfw::Window before terminating glfw
    self.win = None;
  }

  fn pick_tile(&mut self) {
    let mouse_pos = Vec2 {
      x: self.mouse_pos.x as i32,
      y: self.mouse_pos.y as i32,
    };
    let win_size = self.win().get_size();
    self.selected_tile_pos = self.picker.pick_tile(
      win_size, &self.camera, mouse_pos);
    println!("selected: {:?}", self.selected_tile_pos);
  }

  pub fn tick(&mut self) {
    self.handle_events();
    self.pick_tile();
    self.draw();
  }
}

impl Drop for Visualizer {
  fn drop(&mut self) {
    self.cleanup_opengl();
    self.close_window();
    glfw::terminate();
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<|endoftext|>