<commit_before>extern crate roboime_next;
#[macro_use] extern crate glium;
extern crate clap;
extern crate clock_ticks;
//extern crate image;
extern crate env_logger;
#[macro_use] extern crate log;

use std::error::Error;

pub mod models;
pub mod colors;
mod utils;
mod draw;

fn main_loop() -> Result<(), Box<Error>> {
    use std::env;
    use std::thread;
    //use std::io::Cursor;
    use std::time::Duration;
    use std::process::Command;
    use roboime_next::prelude::*;
    use roboime_next::{game, sim, ai};
    use roboime_next::base::{TeamSide, Side, Color, Vec2d};
    use clap::{Arg, App, AppSettings};
    use glium::{glutin, DisplayBuild, Surface};
    use log::LogLevelFilter;
    use env_logger::LogBuilder;
    //use image::image::GenericImage;
    use ::utils::*;

    let matches = App::new("robime-next-cli")
        .setting(AppSettings::ColoredHelp)
        .setting(AppSettings::DeriveDisplayOrder)
        .setting(AppSettings::TrailingVarArg)
        .about("Connect an AI to a Robocup SSL game through an stdio interface (like codingame).")
        .arg(Arg::with_name("blue")
             .short("b")
             .long("blue")
             .help("Play as the blue team."))
        .arg(Arg::with_name("yellow")
             .conflicts_with("blue")
             .short("y")
             .long("yellow")
             .help("Play as the yellow team. (default)"))
        .arg(Arg::with_name("right")
             .short("r")
             .long("right")
             .help("Play on the right side."))
        .arg(Arg::with_name("left")
             .conflicts_with("right")
             .short("l")
             .long("left")
             .help("Play on the left side. (default)"))
        .arg(Arg::with_name("pause")
             .short("p")
             .long("pause")
             .help("Start the simulator paused."))
        .arg(Arg::with_name("v")
             .short("v")
             .multiple(true)
             .help("Sets the level of verbosity."))
        .arg(Arg::with_name("q")
             .conflicts_with("v")
             .long("quiet")
             .short("q")
             .help("Don't log warnings or errors."))
        //.arg(Arg::with_name("d")
        //     .long("debug")
        //     .short("d")
        //     .help("Enable debug logs."))
        .arg(Arg::with_name("AI")
             .required(true)
             .multiple(true)
             .value_name("COMMAND")
             .help("Command to start the AI, accepts arguments."))
        .get_matches();

    {
        let mut builder = LogBuilder::new();
        builder.format(|record| {
            format!("{} [{}] {}", record.level(), record.location().module_path(), record.args())
        });
        let verbosity = matches.occurrences_of("v");
        builder.filter(Some("roboime"), match verbosity {
            0 => LogLevelFilter::Warn,
            1 => LogLevelFilter::Info,
            2 => LogLevelFilter::Debug,
            _ => LogLevelFilter::Trace,
        });
        if matches.is_present("q") {
            builder.filter(Some("roboime"), LogLevelFilter::Off);
        }
        if let Ok(ref log) = env::var("RUST_LOG") {
           builder.parse(log);
        }
        try!(builder.init());
    }

    // building the display, ie. the main object
    let display = try!(glutin::WindowBuilder::new()
        .with_title(format!("RoboIME Next"))
        // 1 extra pixel to align the middle lines to the screen
        .with_dimensions(1041, 741)
        .with_depth_buffer(24)
        .with_gl(glutin::GlRequest::Latest)
        .with_multisampling(2)
        .with_vsync()
        .build_glium());

    let perspective = {
        let (width, height) = display.get_window().unwrap().get_inner_size_points().unwrap();
        perspective_matrix(width as f32, height as f32)
    };

    let is_yellow = {
        let mut yellow = true;
        if matches.is_present("blue")   { yellow = false; };
        if matches.is_present("yellow") { yellow = true; };
        yellow
    };

    let is_left = {
        let mut left = true;
        if matches.is_present("right") { left = false; };
        if matches.is_present("left")  { left = true; };
        left
    };

    let mut is_paused = {
        let mut pause = false;
        if matches.is_present("pause") { pause = true; };
        pause
    };

    let mut single_shot = false;

    let mut ai_cfg = {
        let ai_cmd: Vec<&str> = matches.values_of("AI").unwrap().collect();
        let (ai_program, ai_args) = (ai_cmd[0], &ai_cmd[1..]);
        let mut ai_command = Command::new(ai_program);
        ai_command.args(ai_args);
        let mut ai_cfg = ai::Interface::new(ai_command);
        ai_cfg.is_yellow(is_yellow);
        ai_cfg
    };

    let team_side = {
        use ::models::TeamSide::*;
        match (is_yellow, is_left) {
            (true,  true)  => YellowIsLeft,
            (true,  false) => BlueIsLeft,
            (false, false) => YellowIsLeft,
            (false, true)  => BlueIsLeft,
        }
    };

    let mut sim_state = sim::State::new(TeamSide(Color::yellow(is_yellow), Side::left(is_left)));
    let mut draw_game = try!(draw::Game::new(&display)); draw_game.team_side(&display, team_side);
    let mut game_state = game::State::new();
    let mut ai = try!(ai_cfg.spawn());

    let mut accumulator = 0;
    let mut previous_clock = clock_ticks::precise_time_ns();
    let mut step_clock = previous_clock;
    let mut step_counter = 0;

    // init the AI
    debug!("Wait for AI to start...");
    sim_state.update_game(&mut game_state);
    try!(ai.push_init(&game_state));

    //drop(try!(rx.recv()));
    debug!("AI started, going on...");

    // debugger thread
    let debug = ai.debug.take().unwrap();
    let debugger = thread::spawn(move || {
        for line in debug {
            println!("AI> {}", line.unwrap());
        }
    });

    // the main loop
    'main: loop {

        // render the game state
        let view = view_matrix(&[0.0, 0.0, 10.0], &[0.0, 0.0, -1.0], &[0.0, 1.0, 0.0]);
        //let view = view_matrix(&[-4.0, -4.0, 4.0], &[1.0, 1.0, -1.0], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[4.0, -4.0, 4.0], &[-1.0, 1.0, -1.0], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[-0.2, -0.2, 0.6], &[0.2, 0.2, -0.6], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[1.0, 2.0, 3.0], &[1.0, 1.0, -3.0], &[0.0, 1.0, 0.0]);
        //let view = view_matrix(&[-4.0, 0.7, 1.6], &[-0.2, -0.2, -0.6], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[-5.0, -0.7, 1.6], &[0.2, 0.2, -0.6], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[4.0, 0.7, 1.6], &[0.2, -0.2, -0.6], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[5.0, -0.7, 1.6], &[-0.2, 0.2, -0.6], &[0.0, 0.0, 1.0]);
        let mut target = display.draw();
        {
            //let state = try!(game_state.read());
            let state = &game_state;
            try!(draw_game.draw_to(&mut target, &state, perspective, view));
        }
        try!(target.finish());

        // polling and handling the events received by the window
        for event in display.poll_events() {
            use glium::glutin::Event::*;
            use glium::glutin::ElementState::*;
            use glium::glutin::VirtualKeyCode;

            match event {
                KeyboardInput(_, _, Some(VirtualKeyCode::Escape)) |
                Closed => {
                    break 'main;
                }
                KeyboardInput(Pressed, _, Some(VirtualKeyCode::P)) => {
                    is_paused = !is_paused;
                }
                KeyboardInput(Pressed, _, Some(VirtualKeyCode::RBracket)) => {
                    single_shot = true;
                }
                KeyboardInput(Pressed, _, Some(VirtualKeyCode::R)) => {
                    // reset ball position and speed
                    sim_state.ball.pos = Vec2d(0.0, 0.0);
                    sim_state.ball.vel = Vec2d(0.0, 0.0);
                }
                _ => ()
            }
        }

        const FIXED_TIME_STEP: u64 = 16666667;

        let now = clock_ticks::precise_time_ns();
        if !is_paused {
            accumulator += now - previous_clock;

            while accumulator >= FIXED_TIME_STEP {
                accumulator -= FIXED_TIME_STEP;
                let now = clock_ticks::precise_time_ns();
                let delta = now - step_clock;
                if delta >= 1_000_000_000 {
                    // expect ~60 steps per second
                    info!("{:2} steps in {:.03} seconds", step_counter, delta as f32 * 1.0e-9);
                    step_counter = 0;
                    step_clock = now;
                }

                // game step
                try!(ai.push_state(&game_state));
                let cmd = try!(ai.read_command(&game_state));
                sim_state.step(cmd, FIXED_TIME_STEP as f32 * 1.0e-9);
                sim_state.update_game(&mut game_state);
                step_counter += 1;
            }
        }
        previous_clock = now;

        if single_shot {
            // XXX: is there a simple way to no duplicade this?
            // game step
            try!(ai.push_state(&game_state));
            let cmd = try!(ai.read_command(&game_state));
            sim_state.step(cmd, FIXED_TIME_STEP as f32 * 1.0e-9);
            sim_state.update_game(&mut game_state);
            single_shot = false;
        }

        thread::sleep(Duration::from_millis(((FIXED_TIME_STEP - accumulator) / 1_000_000) as u64));
    }

    try!(ai.quit());
    debug!("Waiting for AI to exit");
    // FIXME: error after a quit is a bug, silence it for now
    let _ = ai.join();
    let _ = debugger.join();
    info!("Bye!");

    Ok(())
}

fn main() {
    use std::process::exit;

    if let Err(err) = main_loop() {
        println!("Error: {}.", err.description());

        let mut err: &Error = &*err;
        while let Some(cause) = err.cause() {
            println!("- caused by: {}", cause.description());
            err = cause;
        }

        exit(1);
    }
}
<commit_msg>Also update the game_state so it draws even if paused.<commit_after>extern crate roboime_next;
#[macro_use] extern crate glium;
extern crate clap;
extern crate clock_ticks;
//extern crate image;
extern crate env_logger;
#[macro_use] extern crate log;

use std::error::Error;

pub mod models;
pub mod colors;
mod utils;
mod draw;

fn main_loop() -> Result<(), Box<Error>> {
    use std::env;
    use std::thread;
    //use std::io::Cursor;
    use std::time::Duration;
    use std::process::Command;
    use roboime_next::prelude::*;
    use roboime_next::{game, sim, ai};
    use roboime_next::base::{TeamSide, Side, Color, Vec2d};
    use clap::{Arg, App, AppSettings};
    use glium::{glutin, DisplayBuild, Surface};
    use log::LogLevelFilter;
    use env_logger::LogBuilder;
    //use image::image::GenericImage;
    use ::utils::*;

    let matches = App::new("robime-next-cli")
        .setting(AppSettings::ColoredHelp)
        .setting(AppSettings::DeriveDisplayOrder)
        .setting(AppSettings::TrailingVarArg)
        .about("Connect an AI to a Robocup SSL game through an stdio interface (like codingame).")
        .arg(Arg::with_name("blue")
             .short("b")
             .long("blue")
             .help("Play as the blue team."))
        .arg(Arg::with_name("yellow")
             .conflicts_with("blue")
             .short("y")
             .long("yellow")
             .help("Play as the yellow team. (default)"))
        .arg(Arg::with_name("right")
             .short("r")
             .long("right")
             .help("Play on the right side."))
        .arg(Arg::with_name("left")
             .conflicts_with("right")
             .short("l")
             .long("left")
             .help("Play on the left side. (default)"))
        .arg(Arg::with_name("pause")
             .short("p")
             .long("pause")
             .help("Start the simulator paused."))
        .arg(Arg::with_name("v")
             .short("v")
             .multiple(true)
             .help("Sets the level of verbosity."))
        .arg(Arg::with_name("q")
             .conflicts_with("v")
             .long("quiet")
             .short("q")
             .help("Don't log warnings or errors."))
        //.arg(Arg::with_name("d")
        //     .long("debug")
        //     .short("d")
        //     .help("Enable debug logs."))
        .arg(Arg::with_name("AI")
             .required(true)
             .multiple(true)
             .value_name("COMMAND")
             .help("Command to start the AI, accepts arguments."))
        .get_matches();

    {
        let mut builder = LogBuilder::new();
        builder.format(|record| {
            format!("{} [{}] {}", record.level(), record.location().module_path(), record.args())
        });
        let verbosity = matches.occurrences_of("v");
        builder.filter(Some("roboime"), match verbosity {
            0 => LogLevelFilter::Warn,
            1 => LogLevelFilter::Info,
            2 => LogLevelFilter::Debug,
            _ => LogLevelFilter::Trace,
        });
        if matches.is_present("q") {
            builder.filter(Some("roboime"), LogLevelFilter::Off);
        }
        if let Ok(ref log) = env::var("RUST_LOG") {
           builder.parse(log);
        }
        try!(builder.init());
    }

    // building the display, ie. the main object
    let display = try!(glutin::WindowBuilder::new()
        .with_title(format!("RoboIME Next"))
        // 1 extra pixel to align the middle lines to the screen
        .with_dimensions(1041, 741)
        .with_depth_buffer(24)
        .with_gl(glutin::GlRequest::Latest)
        .with_multisampling(2)
        .with_vsync()
        .build_glium());

    let perspective = {
        let (width, height) = display.get_window().unwrap().get_inner_size_points().unwrap();
        perspective_matrix(width as f32, height as f32)
    };

    let is_yellow = {
        let mut yellow = true;
        if matches.is_present("blue")   { yellow = false; };
        if matches.is_present("yellow") { yellow = true; };
        yellow
    };

    let is_left = {
        let mut left = true;
        if matches.is_present("right") { left = false; };
        if matches.is_present("left")  { left = true; };
        left
    };

    let mut is_paused = {
        let mut pause = false;
        if matches.is_present("pause") { pause = true; };
        pause
    };

    let mut single_shot = false;

    let mut ai_cfg = {
        let ai_cmd: Vec<&str> = matches.values_of("AI").unwrap().collect();
        let (ai_program, ai_args) = (ai_cmd[0], &ai_cmd[1..]);
        let mut ai_command = Command::new(ai_program);
        ai_command.args(ai_args);
        let mut ai_cfg = ai::Interface::new(ai_command);
        ai_cfg.is_yellow(is_yellow);
        ai_cfg
    };

    let team_side = {
        use ::models::TeamSide::*;
        match (is_yellow, is_left) {
            (true,  true)  => YellowIsLeft,
            (true,  false) => BlueIsLeft,
            (false, false) => YellowIsLeft,
            (false, true)  => BlueIsLeft,
        }
    };

    let mut sim_state = sim::State::new(TeamSide(Color::yellow(is_yellow), Side::left(is_left)));
    let mut draw_game = try!(draw::Game::new(&display)); draw_game.team_side(&display, team_side);
    let mut game_state = game::State::new();
    let mut ai = try!(ai_cfg.spawn());

    let mut accumulator = 0;
    let mut previous_clock = clock_ticks::precise_time_ns();
    let mut step_clock = previous_clock;
    let mut step_counter = 0;

    // init the AI
    debug!("Wait for AI to start...");
    sim_state.update_game(&mut game_state);
    try!(ai.push_init(&game_state));

    //drop(try!(rx.recv()));
    debug!("AI started, going on...");

    // debugger thread
    let debug = ai.debug.take().unwrap();
    let debugger = thread::spawn(move || {
        for line in debug {
            println!("AI> {}", line.unwrap());
        }
    });

    // the main loop
    'main: loop {

        // render the game state
        let view = view_matrix(&[0.0, 0.0, 10.0], &[0.0, 0.0, -1.0], &[0.0, 1.0, 0.0]);
        //let view = view_matrix(&[-4.0, -4.0, 4.0], &[1.0, 1.0, -1.0], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[4.0, -4.0, 4.0], &[-1.0, 1.0, -1.0], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[-0.2, -0.2, 0.6], &[0.2, 0.2, -0.6], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[1.0, 2.0, 3.0], &[1.0, 1.0, -3.0], &[0.0, 1.0, 0.0]);
        //let view = view_matrix(&[-4.0, 0.7, 1.6], &[-0.2, -0.2, -0.6], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[-5.0, -0.7, 1.6], &[0.2, 0.2, -0.6], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[4.0, 0.7, 1.6], &[0.2, -0.2, -0.6], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[5.0, -0.7, 1.6], &[-0.2, 0.2, -0.6], &[0.0, 0.0, 1.0]);
        let mut target = display.draw();
        {
            //let state = try!(game_state.read());
            let state = &game_state;
            try!(draw_game.draw_to(&mut target, &state, perspective, view));
        }
        try!(target.finish());

        // polling and handling the events received by the window
        for event in display.poll_events() {
            use glium::glutin::Event::*;
            use glium::glutin::ElementState::*;
            use glium::glutin::VirtualKeyCode;

            match event {
                KeyboardInput(_, _, Some(VirtualKeyCode::Escape)) |
                Closed => {
                    break 'main;
                }
                KeyboardInput(Pressed, _, Some(VirtualKeyCode::P)) => {
                    is_paused = !is_paused;
                }
                KeyboardInput(Pressed, _, Some(VirtualKeyCode::RBracket)) => {
                    single_shot = true;
                }
                KeyboardInput(Pressed, _, Some(VirtualKeyCode::R)) => {
                    // reset ball position and speed
                    sim_state.ball.pos = Vec2d(0.0, 0.0);
                    sim_state.ball.vel = Vec2d(0.0, 0.0);
                    sim_state.update_game(&mut game_state);
                }
                _ => ()
            }
        }

        const FIXED_TIME_STEP: u64 = 16666667;

        let now = clock_ticks::precise_time_ns();
        if !is_paused {
            accumulator += now - previous_clock;

            while accumulator >= FIXED_TIME_STEP {
                accumulator -= FIXED_TIME_STEP;
                let now = clock_ticks::precise_time_ns();
                let delta = now - step_clock;
                if delta >= 1_000_000_000 {
                    // expect ~60 steps per second
                    info!("{:2} steps in {:.03} seconds", step_counter, delta as f32 * 1.0e-9);
                    step_counter = 0;
                    step_clock = now;
                }

                // game step
                try!(ai.push_state(&game_state));
                let cmd = try!(ai.read_command(&game_state));
                sim_state.step(cmd, FIXED_TIME_STEP as f32 * 1.0e-9);
                sim_state.update_game(&mut game_state);
                step_counter += 1;
            }
        }
        previous_clock = now;

        if single_shot {
            // XXX: is there a simple way to no duplicade this?
            // game step
            try!(ai.push_state(&game_state));
            let cmd = try!(ai.read_command(&game_state));
            sim_state.step(cmd, FIXED_TIME_STEP as f32 * 1.0e-9);
            sim_state.update_game(&mut game_state);
            single_shot = false;
        }

        thread::sleep(Duration::from_millis(((FIXED_TIME_STEP - accumulator) / 1_000_000) as u64));
    }

    try!(ai.quit());
    debug!("Waiting for AI to exit");
    // FIXME: error after a quit is a bug, silence it for now
    let _ = ai.join();
    let _ = debugger.join();
    info!("Bye!");

    Ok(())
}

fn main() {
    use std::process::exit;

    if let Err(err) = main_loop() {
        println!("Error: {}.", err.description());

        let mut err: &Error = &*err;
        while let Some(cause) = err.cause() {
            println!("- caused by: {}", cause.description());
            err = cause;
        }

        exit(1);
    }
}
<|endoftext|>


<commit_before>use CHIP8_HEIGHT;
use CHIP8_WIDTH;
use CHIP8_RAM;

pub struct OutputState<'a> {
    pub vram: &'a [[u8; CHIP8_WIDTH]; CHIP8_HEIGHT],
    pub vram_changed: bool,
    pub beep: bool,
}

pub struct Processor {
    vram: [[u8; CHIP8_WIDTH]; CHIP8_HEIGHT],
    vram_changed: bool,
    ram: [u8; CHIP8_RAM],
    stack: [usize; 16],
    v: [u8; 16],
    i: usize,
    pc: usize,
    sp: usize,
    delay_timer: u8,
    sound_timer: u8,
}

impl Processor {
    pub fn new() -> Self {
        Processor {
            vram: [[0; CHIP8_WIDTH]; CHIP8_HEIGHT],
            vram_changed: false,
            ram: [0; CHIP8_RAM],
            stack: [0; 16],
            v: [0; 16],
            i: 0,
            pc: 0x200,
            sp: 0,
            delay_timer: 0,
            sound_timer: 0,
        }
    }

    pub fn tick(&mut self, keypad: &[bool; 16]) -> OutputState {
        println!("tick: {:?}", keypad);
        self.vram_changed = false;
        let opcode = self.get_opcode();
        self.run_opcode(opcode);
        OutputState {
            vram: &self.vram,
            vram_changed: self.vram_changed,
            beep: self.sound_timer > 0,
        }
    }

    fn get_opcode(&self) -> u16 {
        (self.ram[self.pc] as u16) << 8 | (self.ram[self.pc + 1] as u16)
    }

    fn run_opcode(&mut self, opcode: u16) {

        let nibbles = (
            (opcode & 0x000F) as u8,
            (opcode & 0x00F0) >> 4 as u8,
            (opcode & 0x0F00) >> 8 as u8,
            (opcode & 0xF000) >> 12 as u8,
        );

        let nnn = opcode & 0x0FFF;
        let kk = (opcode & 0x00FF) as u8;
        let x = nibbles.2 as usize;
        let y = nibbles.1 as usize;
        let n = nibbles.0 as u8;

        match nibbles {
            (0x00, 0x00, 0x0e, 0x00) => self.op_00e0(),
            (0x00, 0x00, 0x0e, 0x0e) => self.op_00ee(),
            (0x00, _, _, _) => self.op_0nnn(nnn),
            (0x01, _, _, _) => self.op_1nnn(nnn),
            (0x02, _, _, _) => self.op_2nnn(nnn),
            (0x03, _, _, _) => self.op_3xkk(x, kk),
            (0x04, _, _, _) => self.op_4xkk(x, kk),
            (0x05, _, _, 0x00) => self.op_5xy0(x, y),
            (0x06, _, _, _) => self.op_6xkk(x, kk),
            (0x07, _, _, _) => self.op_7xkk(x, kk),
            (0x08, _, _, 0x00) => self.op_8xy0(x, y),
            (0x08, _, _, 0x01) => self.op_8xy1(x, y),
            (0x08, _, _, 0x02) => self.op_8xy2(x, y),
            (0x08, _, _, 0x03) => self.op_8xy3(x, y),
            (0x08, _, _, 0x04) => self.op_8xy4(x, y),
            (0x08, _, _, 0x05) => self.op_8xy5(x, y),
            (0x08, _, _, 0x06) => self.op_8xy6(x, y),
            (0x08, _, _, 0x07) => self.op_8xy7(x, y),
            (0x08, _, _, 0x0e) => self.op_8xye(x, y),
            (0x09, _, _, 0x00) => self.op_9xy0(x, y),
            (0x0a, _, _, _) => self.op_annn(nnn),
            (0x0b, _, _, _) => self.op_bnnn(nnn),
            (0x0c, _, _, _) => self.op_cxkk(x, kk),
            (0x0d, _, _, _) => self.op_dxyn(x, y, n),
            (0x0e, _, 0x09, 0x0e) => self.op_ex9e(x),
            (0x0e, _, 0x0a, 0x01) => self.op_exa1(x),
            (0x0f, _, 0x00, 0x07) => self.op_fx07(x),
            (0x0f, _, 0x00, 0x0a) => self.op_fx0a(x),
            (0x0f, _, 0x01, 0x05) => self.op_fx15(x),
            (0x0f, _, 0x01, 0x08) => self.op_fx18(x),
            (0x0f, _, 0x01, 0x0e) => self.op_fx1e(x),
            (0x0f, _, 0x02, 0x09) => self.op_fx29(x),
            (0x0f, _, 0x03, 0x03) => self.op_fx33(x),
            (0x0f, _, 0x05, 0x05) => self.op_fx55(x),
            (0x0f, _, 0x06, 0x05) => self.op_fx65(x),
            _ => return,
        }

    }
    // CLS
    fn op_00e0(&mut self) {}
    // RET
    fn op_00ee(&mut self) {}
    // SYS addr
    fn op_0nnn(&mut self, nnn: u16) {}
    // JP addr
    fn op_1nnn(&mut self, nnn: u16) {}
    // CALL addr
    fn op_2nnn(&mut self, nnn: u16) {}
    // SE Vx, byte
    fn op_3xkk(&mut self, x: usize, kk: u8) {}
    // SNE Vx, byte
    fn op_4xkk(&mut self, x: usize, kk: u8) {}
    // SE Vx, Vy
    fn op_5xy0(&mut self, x: usize, y: usize) {}
    // LD Vx, byte
    fn op_6xkk(&mut self, x: usize, kk: u8) {}
    // ADD Vx, byte
    fn op_7xkk(&mut self, x: usize, kk: u8) {}
    // LD Vx, Vy
    fn op_8xy0(&mut self, x: usize, y: usize) {}
    // OR Vx, Vy
    fn op_8xy1(&mut self, x: usize, y: usize) {}
    // AND Vx, Vy
    fn op_8xy2(&mut self, x: usize, y: usize) {}
    // XOR Vx, Vy
    fn op_8xy3(&mut self, x: usize, y: usize) {}
    // ADD Vx, Vy
    fn op_8xy4(&mut self, x: usize, y: usize) {}
    // SUB Vx, Vy
    fn op_8xy5(&mut self, x: usize, y: usize) {}
    // SHR Vx {, Vy}
    fn op_8xy6(&mut self, x: usize, y: usize) {}
    // SUBN Vx, Vy
    fn op_8xy7(&mut self, x: usize, y: usize) {}
    // SHL Vx {, Vy}
    fn op_8xye(&mut self, x: usize, y: usize) {}
    // SNE Vx, Vy
    fn op_9xy0(&mut self, x: usize, y: usize) {}
    // LD I, addr
    fn op_annn(&mut self, nnn: u16) {}
    // JP V0, addr
    fn op_bnnn(&mut self, nnn: u16) {}
    // RND Vx, byte
    fn op_cxkk(&mut self, x: usize, kk: u8) {}
    // DRW Vx, Vy, nibble
    fn op_dxyn(&mut self, x: usize, y: usize, n: u8) {}
    // SKP Vx
    fn op_ex9e(&mut self, x: usize) {}
    // SKNP Vx
    fn op_exa1(&mut self, x: usize) {}
    // LD Vx, DT
    fn op_fx07(&mut self, x: usize) {}
    // LD Vx, K
    fn op_fx0a(&mut self, x: usize) {}
    // LD DT, Vx
    fn op_fx15(&mut self, x: usize) {}
    // LD ST, Vx
    fn op_fx18(&mut self, x: usize) {}
    // ADD I, Vx
    fn op_fx1e(&mut self, x: usize) {}
    // LD F, Vx
    fn op_fx29(&mut self, x: usize) {}
    // LD B, Vx
    fn op_fx33(&mut self, x: usize) {}
    // LD [I], Vx
    fn op_fx55(&mut self, x: usize) {}
    // LD Vx, [I]
    fn op_fx65(&mut self, x: usize) {}
}

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

    #[test]
    fn test_initial_state() {
        let processor = Processor::new();
        assert_eq!(processor.sp, 0);
        assert_eq!(processor.stack, [0; 16]);
    }
}
<commit_msg>implement CLS<commit_after>use CHIP8_HEIGHT;
use CHIP8_WIDTH;
use CHIP8_RAM;

pub struct OutputState<'a> {
    pub vram: &'a [[u8; CHIP8_WIDTH]; CHIP8_HEIGHT],
    pub vram_changed: bool,
    pub beep: bool,
}

pub struct Processor {
    vram: [[u8; CHIP8_WIDTH]; CHIP8_HEIGHT],
    vram_changed: bool,
    ram: [u8; CHIP8_RAM],
    stack: [usize; 16],
    v: [u8; 16],
    i: usize,
    pc: usize,
    sp: usize,
    delay_timer: u8,
    sound_timer: u8,
}

impl Processor {
    pub fn new() -> Self {
        Processor {
            vram: [[0; CHIP8_WIDTH]; CHIP8_HEIGHT],
            vram_changed: false,
            ram: [0; CHIP8_RAM],
            stack: [0; 16],
            v: [0; 16],
            i: 0,
            pc: 0x200,
            sp: 0,
            delay_timer: 0,
            sound_timer: 0,
        }
    }

    pub fn tick(&mut self, keypad: &[bool; 16]) -> OutputState {
        println!("tick: {:?}", keypad);
        self.vram_changed = false;
        let opcode = self.get_opcode();
        self.run_opcode(opcode);
        OutputState {
            vram: &self.vram,
            vram_changed: self.vram_changed,
            beep: self.sound_timer > 0,
        }
    }

    fn get_opcode(&self) -> u16 {
        (self.ram[self.pc] as u16) << 8 | (self.ram[self.pc + 1] as u16)
    }

    fn run_opcode(&mut self, opcode: u16) {

        let nibbles = (
            (opcode & 0x000F) as u8,
            (opcode & 0x00F0) >> 4 as u8,
            (opcode & 0x0F00) >> 8 as u8,
            (opcode & 0xF000) >> 12 as u8,
        );

        let nnn = opcode & 0x0FFF;
        let kk = (opcode & 0x00FF) as u8;
        let x = nibbles.2 as usize;
        let y = nibbles.1 as usize;
        let n = nibbles.0 as u8;

        match nibbles {
            (0x00, 0x00, 0x0e, 0x00) => self.op_00e0(),
            (0x00, 0x00, 0x0e, 0x0e) => self.op_00ee(),
            (0x00, _, _, _) => self.op_0nnn(nnn),
            (0x01, _, _, _) => self.op_1nnn(nnn),
            (0x02, _, _, _) => self.op_2nnn(nnn),
            (0x03, _, _, _) => self.op_3xkk(x, kk),
            (0x04, _, _, _) => self.op_4xkk(x, kk),
            (0x05, _, _, 0x00) => self.op_5xy0(x, y),
            (0x06, _, _, _) => self.op_6xkk(x, kk),
            (0x07, _, _, _) => self.op_7xkk(x, kk),
            (0x08, _, _, 0x00) => self.op_8xy0(x, y),
            (0x08, _, _, 0x01) => self.op_8xy1(x, y),
            (0x08, _, _, 0x02) => self.op_8xy2(x, y),
            (0x08, _, _, 0x03) => self.op_8xy3(x, y),
            (0x08, _, _, 0x04) => self.op_8xy4(x, y),
            (0x08, _, _, 0x05) => self.op_8xy5(x, y),
            (0x08, _, _, 0x06) => self.op_8xy6(x, y),
            (0x08, _, _, 0x07) => self.op_8xy7(x, y),
            (0x08, _, _, 0x0e) => self.op_8xye(x, y),
            (0x09, _, _, 0x00) => self.op_9xy0(x, y),
            (0x0a, _, _, _) => self.op_annn(nnn),
            (0x0b, _, _, _) => self.op_bnnn(nnn),
            (0x0c, _, _, _) => self.op_cxkk(x, kk),
            (0x0d, _, _, _) => self.op_dxyn(x, y, n),
            (0x0e, _, 0x09, 0x0e) => self.op_ex9e(x),
            (0x0e, _, 0x0a, 0x01) => self.op_exa1(x),
            (0x0f, _, 0x00, 0x07) => self.op_fx07(x),
            (0x0f, _, 0x00, 0x0a) => self.op_fx0a(x),
            (0x0f, _, 0x01, 0x05) => self.op_fx15(x),
            (0x0f, _, 0x01, 0x08) => self.op_fx18(x),
            (0x0f, _, 0x01, 0x0e) => self.op_fx1e(x),
            (0x0f, _, 0x02, 0x09) => self.op_fx29(x),
            (0x0f, _, 0x03, 0x03) => self.op_fx33(x),
            (0x0f, _, 0x05, 0x05) => self.op_fx55(x),
            (0x0f, _, 0x06, 0x05) => self.op_fx65(x),
            _ => return,
        }

    }
    // CLS
    fn op_00e0(&mut self) {
        for y in 0..CHIP8_HEIGHT {
            for x in 0..CHIP8_WIDTH {
                self.vram[y][x] = 0;
            }
        }
        self.vram_changed = true;
    }

    // RET
    fn op_00ee(&mut self) {}
    // SYS addr
    fn op_0nnn(&mut self, nnn: u16) {}
    // JP addr
    fn op_1nnn(&mut self, nnn: u16) {}
    // CALL addr
    fn op_2nnn(&mut self, nnn: u16) {}
    // SE Vx, byte
    fn op_3xkk(&mut self, x: usize, kk: u8) {}
    // SNE Vx, byte
    fn op_4xkk(&mut self, x: usize, kk: u8) {}
    // SE Vx, Vy
    fn op_5xy0(&mut self, x: usize, y: usize) {}
    // LD Vx, byte
    fn op_6xkk(&mut self, x: usize, kk: u8) {}
    // ADD Vx, byte
    fn op_7xkk(&mut self, x: usize, kk: u8) {}
    // LD Vx, Vy
    fn op_8xy0(&mut self, x: usize, y: usize) {}
    // OR Vx, Vy
    fn op_8xy1(&mut self, x: usize, y: usize) {}
    // AND Vx, Vy
    fn op_8xy2(&mut self, x: usize, y: usize) {}
    // XOR Vx, Vy
    fn op_8xy3(&mut self, x: usize, y: usize) {}
    // ADD Vx, Vy
    fn op_8xy4(&mut self, x: usize, y: usize) {}
    // SUB Vx, Vy
    fn op_8xy5(&mut self, x: usize, y: usize) {}
    // SHR Vx {, Vy}
    fn op_8xy6(&mut self, x: usize, y: usize) {}
    // SUBN Vx, Vy
    fn op_8xy7(&mut self, x: usize, y: usize) {}
    // SHL Vx {, Vy}
    fn op_8xye(&mut self, x: usize, y: usize) {}
    // SNE Vx, Vy
    fn op_9xy0(&mut self, x: usize, y: usize) {}
    // LD I, addr
    fn op_annn(&mut self, nnn: u16) {}
    // JP V0, addr
    fn op_bnnn(&mut self, nnn: u16) {}
    // RND Vx, byte
    fn op_cxkk(&mut self, x: usize, kk: u8) {}
    // DRW Vx, Vy, nibble
    fn op_dxyn(&mut self, x: usize, y: usize, n: u8) {}
    // SKP Vx
    fn op_ex9e(&mut self, x: usize) {}
    // SKNP Vx
    fn op_exa1(&mut self, x: usize) {}
    // LD Vx, DT
    fn op_fx07(&mut self, x: usize) {}
    // LD Vx, K
    fn op_fx0a(&mut self, x: usize) {}
    // LD DT, Vx
    fn op_fx15(&mut self, x: usize) {}
    // LD ST, Vx
    fn op_fx18(&mut self, x: usize) {}
    // ADD I, Vx
    fn op_fx1e(&mut self, x: usize) {}
    // LD F, Vx
    fn op_fx29(&mut self, x: usize) {}
    // LD B, Vx
    fn op_fx33(&mut self, x: usize) {}
    // LD [I], Vx
    fn op_fx55(&mut self, x: usize) {}
    // LD Vx, [I]
    fn op_fx65(&mut self, x: usize) {}
}

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

    #[test]
    fn test_initial_state() {
        let processor = Processor::new();
        assert_eq!(processor.sp, 0);
        assert_eq!(processor.stack, [0; 16]);
    }

    // CLS
    fn test_op_00e0() {
        let mut processor = Processor::new();
        processor.vram = [[128; CHIP8_WIDTH]; CHIP8_HEIGHT];
        processor.run_opcode(0x00e0);
        for y in 0..CHIP8_HEIGHT {
            for x in 0..CHIP8_WIDTH {
                assert_eq!(processor.vram[y][x], 0);
            }
        }
    }

}
<|endoftext|>


<commit_before>#![allow(dead_code)]

//! A set library to aid character set manipulation.
//!
//! `range_set` aims to make it easier to handle set manipulation for characters
//! over ranges. For example, a unicode library may expose character ranges such
//! as `('0', '9')` as a sequence of digits. If I was already later state I would
//! like to add the sequence of digits: `('1', '3')`, it would consider them as
//! distinct and store both. This is a nuisance. It should recognize that `1-3`
//! is encased inside `0-9` and leave it as is.
//!
//! It provides the standard set operations: union, intersection, difference,
//! and symmetric difference.

use std::collections::BTreeSet;
use std::fmt::{self, Display};
use parse::NextPrev;

#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Range(pub char, pub char);

impl fmt::Display for Range {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.0, self.1)
    }
}

#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Set(BTreeSet<Range>);

impl fmt::Display for Set {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let Set(ref set) = *self;
        let len = BTreeSet::len(set);

        for (count, s) in set.iter().enumerate() {
            if count < len - 1 { try!(write!(f, "{}, ", s)) }
            else { return write!(f, "{}", s) }
        }

        Ok(())
    }
}

impl Set {
    pub fn new() -> Self { Set(BTreeSet::new()) }
    pub fn insert(&mut self, value: Range) {
        let mut ret = BTreeSet::new();
        // value is a complete subset of one of the other ranges.
        let mut subset = false;

        // Borrowing self blocks later operation. Add a new scope.
        {   let Set(ref set) = *self;

            let Range(mut min_val, mut max_val) = value;
            if min_val > max_val { panic!("First value cannot be greater than the second.") }

            // Loop over set adding old disjoint pieces and supersets back. When partially
            // overlapped or disjoint without a gap, expand value to the union. At the
            // end, insert union after it has been fully expanded.
            for &Range(min, max) in &*set {
                // value overlaps at the beginning or disjoint w/o gap on the low side.
                if min_val < min && max_val >= min.prev() && max_val <= max { max_val = max }
                // value overlaps at the end or disjoin w/o gap on the high side.
                else if min_val >= min && min_val <= max.next() && max_val > max { min_val = min }
                // value is entirely contained between min and max. Insert original
                // into new array because new is a subset.
                else if min_val >= min && max_val <= max {
                    ret.insert(Range(min, max));
                    subset = true;
                }
                // value is a superset to the current so don't add current.
                else if min_val < min && max_val > max {}
                // value is disjoint with current and has a gap. Add current.
                else { ret.insert(Range(min, max)); }
            }

            // Insert value only when it's not a subset.
            if !subset { ret.insert(Range(min_val, max_val)); }
        }

        *self = Set(ret);
    }
    pub fn is_empty(&self) -> bool { self.0.is_empty() }
    pub fn remove(&mut self, value: Range) {
        let mut ret = BTreeSet::new();

        // Borrowing self blocks later modification. Make a new scope to contain it.
        {   let Set(ref set) = *self;

            let Range(min_val, max_val) = value;
            if min_val > max_val { panic!("First value cannot be greater than the second.") }

            // Loop over set inserting whatever doesn't intersect.
            for &Range(min, max) in &*set {
                // value overlaps at the beginning.
                if min_val <= min && max_val >= min && max_val < max { ret.insert(Range(max_val.next(), max)); }
                // value overlaps at the end.
                else if min_val > min && min_val <= max && max_val >= max { ret.insert(Range(min, min_val.prev())); }
                // value is entirely contained between min and max. Split set
                // into two pieces.
                else if min_val > min && max_val < max {
                    ret.insert(Range(min, min_val.prev()));
                    ret.insert(Range(max_val.next(), max));

                    // Current piece was a superset so value cannot be anywhere else.
                    break;
                // value is a superset to the current so don't add current.
                } else if min_val <= min && max_val >= max {}
                // value is disjoint with current so add current.
                else { ret.insert(Range(min, max)); }
            }
        }

        *self = Set(ret)
    }
    // 123 + 345 = 12345.
    pub fn union(&self, value: &Self) -> Self {
        let mut ret = self.clone();

        // Loop over the btreeset of Range(char, char).
        for &x in &value.0 { ret.insert(x) }

        ret
    }
    // Intersection of `A` & `B` is `A - (A - B)`: 123 & 345 = 3.
    pub fn intersection(&self, value: &Self) -> Self {
        let diff = self.difference(value);

        self.difference(&diff)
    }
    // 123 - 345 = 12.
    pub fn difference(&self, value: &Self) -> Self {
        let mut ret = self.clone();

        for &x in &value.0 { ret.remove(x) }

        ret
    }
    // `A` ^ `B` is `(A + B) - (A & B)`: 123 ^ 345 = 1245.
    pub fn symmetric_difference(&self, value: &Self) -> Self {
        let union = self.union(value);
        let intersection = self.intersection(value);

        union.difference(&intersection)
    }
}
<commit_msg>Clarify range_set comment for `insert()`<commit_after>#![allow(dead_code)]

//! A set library to aid character set manipulation.
//!
//! `range_set` aims to make it easier to handle set manipulation for characters
//! over ranges. For example, a unicode library may expose character ranges such
//! as `('0', '9')` as a sequence of digits. If I was already later state I would
//! like to add the sequence of digits: `('1', '3')`, it would consider them as
//! distinct and store both. This is a nuisance. It should recognize that `1-3`
//! is encased inside `0-9` and leave it as is.
//!
//! It provides the standard set operations: union, intersection, difference,
//! and symmetric difference.

use std::collections::BTreeSet;
use std::fmt::{self, Display};
use parse::NextPrev;

#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Range(pub char, pub char);

impl fmt::Display for Range {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.0, self.1)
    }
}

#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Set(BTreeSet<Range>);

impl fmt::Display for Set {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let Set(ref set) = *self;
        let len = BTreeSet::len(set);

        for (count, s) in set.iter().enumerate() {
            if count < len - 1 { try!(write!(f, "{}, ", s)) }
            else { return write!(f, "{}", s) }
        }

        Ok(())
    }
}

impl Set {
    pub fn new() -> Self { Set(BTreeSet::new()) }
    pub fn insert(&mut self, value: Range) {
        let mut ret = BTreeSet::new();
        // value is a complete subset of one of the other ranges.
        let mut subset = false;

        // Borrowing self blocks later operation. Add a new scope.
        {   let Set(ref set) = *self;

            let Range(mut min_val, mut max_val) = value;
            if min_val > max_val { panic!("First value cannot be greater than the second.") }

            // Loop over set adding old disjoint pieces and supersets back. When partially
            // overlapped or disjoint without a gap, expand value to the union. At the
            // end, insert union after it has been fully expanded.
            //
            // It is important that each branch consider all cases which lead to a specific
            // modification. For example, expanding the low side isn't checking for only
            // partial overlap, it's checking all cases which result in *only* the left
            // side expanding. Previous attempts, for example, checked for partial overlap
            // as distinct from subsets/supersets. The result was missing many edge cases.
            for &Range(min, max) in &*set {
                // value overlaps at the beginning or disjoint w/o gap on the low side.
                if min_val < min && max_val >= min.prev() && max_val <= max { max_val = max }
                // value overlaps at the end or disjoin w/o gap on the high side.
                else if min_val >= min && min_val <= max.next() && max_val > max { min_val = min }
                // value is entirely contained between min and max. Insert original
                // into new array because new is a subset.
                else if min_val >= min && max_val <= max {
                    ret.insert(Range(min, max));
                    subset = true;
                }
                // value is a superset to the current so don't add current.
                else if min_val < min && max_val > max {}
                // value is disjoint with current and has a gap. Add current.
                else { ret.insert(Range(min, max)); }
            }

            // Insert value only when it's not a subset.
            if !subset { ret.insert(Range(min_val, max_val)); }
        }

        *self = Set(ret);
    }
    pub fn is_empty(&self) -> bool { self.0.is_empty() }
    pub fn remove(&mut self, value: Range) {
        let mut ret = BTreeSet::new();

        // Borrowing self blocks later modification. Make a new scope to contain it.
        {   let Set(ref set) = *self;

            let Range(min_val, max_val) = value;
            if min_val > max_val { panic!("First value cannot be greater than the second.") }

            // Loop over set inserting whatever doesn't intersect.
            for &Range(min, max) in &*set {
                // value overlaps at the beginning.
                if min_val <= min && max_val >= min && max_val < max { ret.insert(Range(max_val.next(), max)); }
                // value overlaps at the end.
                else if min_val > min && min_val <= max && max_val >= max { ret.insert(Range(min, min_val.prev())); }
                // value is entirely contained between min and max. Split set
                // into two pieces.
                else if min_val > min && max_val < max {
                    ret.insert(Range(min, min_val.prev()));
                    ret.insert(Range(max_val.next(), max));

                    // Current piece was a superset so value cannot be anywhere else.
                    break;
                // value is a superset to the current so don't add current.
                } else if min_val <= min && max_val >= max {}
                // value is disjoint with current so add current.
                else { ret.insert(Range(min, max)); }
            }
        }

        *self = Set(ret)
    }
    // 123 + 345 = 12345.
    pub fn union(&self, value: &Self) -> Self {
        let mut ret = self.clone();

        // Loop over the btreeset of Range(char, char).
        for &x in &value.0 { ret.insert(x) }

        ret
    }
    // Intersection of `A` & `B` is `A - (A - B)`: 123 & 345 = 3.
    pub fn intersection(&self, value: &Self) -> Self {
        let diff = self.difference(value);

        self.difference(&diff)
    }
    // 123 - 345 = 12.
    pub fn difference(&self, value: &Self) -> Self {
        let mut ret = self.clone();

        for &x in &value.0 { ret.remove(x) }

        ret
    }
    // `A` ^ `B` is `(A + B) - (A & B)`: 123 ^ 345 = 1245.
    pub fn symmetric_difference(&self, value: &Self) -> Self {
        let union = self.union(value);
        let intersection = self.intersection(value);

        union.difference(&intersection)
    }
}
<|endoftext|>


<commit_before>//! [β-reduction](https://en.wikipedia.org/wiki/Beta_normal_form) for lambda `Term`s

use term::{Term, TermError};
use term::Term::*;
use std::fmt;
use std::mem;
pub use self::Order::*;

/// The [evaluation order](http://www.cs.cornell.edu/courses/cs6110/2014sp/Handouts/Sestoft.pdf) of
/// β-reductions.
///
/// - The `NOR`, `HNO`, `APP` and `HAP` orders reduce expressions to their normal forms
/// - The `APP` order will fail to fully reduce expressions containing functions without a normal
/// form, e.g. the `Y` combinator (they will expand forever)
/// - The `CBN` order reduces to weak head normal form
/// - The `CBV` order reduces to weak normal form
/// - The `HSP` order reduces to head normal form
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Order {
    /// Normal - leftmost outermost; the most popular reduction strategy
    NOR,
    /// Call-by-name - leftmost outermost; no reductions inside abstractions
    CBN,
    /// Head spine - leftmost outermost; abstractions reduced only in head position
    HSP,
    /// Hybrid normal - a mix between `HSP` (head spine) and `NOR` (normal) strategies
    HNO,
    /// Applicative - leftmost innermost; the most eager strategy; unfit for recursion combinators
    APP,
    /// Call-by-value - leftmost innermost, no reductions inside abstractions
    CBV,
    /// Hybrid applicative - a mix between `CBV` (call-by-value) and `APP` (applicative) strategies;
    /// usually the fastest-reducing normalizing strategy
    HAP
}

/// Applies two `Term`s with substitution and variable update, consuming the first one in the
/// process.
///
/// # Example
/// ```
/// use lambda_calculus::reduction::apply;
/// use lambda_calculus::*;
///
/// // these are valid terms, but be careful with unwraps in your code
/// let lhs    = parse(&"λλ42(λ13)", DeBruijn).unwrap();
/// let rhs    = parse(&"λ51", DeBruijn).unwrap();
/// let result = parse(&"λ3(λ61)(λ1(λ71))", DeBruijn).unwrap();
///
/// assert_eq!(apply(lhs, &rhs), Ok(result));
/// ```
/// # Errors
///
/// Returns a `TermError` if `lhs` is not an `Abs`traction.
pub fn apply(mut lhs: Term, rhs: &Term) -> Result<Term, TermError> {
    lhs.unabs_ref()?;

    _apply(&mut lhs, rhs, 0);

    lhs.unabs()
}

fn _apply(lhs: &mut Term, rhs: &Term, depth: usize) {
    match *lhs {
        Var(i) => if i == depth {
            *lhs = rhs.to_owned(); // substitute a top-level variable from lhs with rhs
            update_free_variables(lhs, depth - 1, 0); // update indices of free variables from rhs
        } else if i > depth {
            *lhs = Var(i - 1) // decrement a free variable's index
        },
        Abs(ref mut abstracted) => {
            _apply(abstracted, rhs, depth + 1)
        },
        App(ref mut lhs_lhs, ref mut lhs_rhs) => {
            _apply(lhs_lhs, rhs, depth);
            _apply(lhs_rhs, rhs, depth)
        }
    }
}

fn update_free_variables(term: &mut Term, added_depth: usize, own_depth: usize) {
    match *term {
        Var(ref mut i) => if *i > own_depth {
            *i += added_depth
        },
        Abs(ref mut abstracted) => {
            update_free_variables(abstracted, added_depth, own_depth + 1)
        },
        App(ref mut lhs, ref mut rhs) => {
            update_free_variables(lhs, added_depth, own_depth);
            update_free_variables(rhs, added_depth, own_depth)
        }
    }
}

/// Performs β-reduction on a `Term` with the specified evaluation `Order` and an optional limit on
/// the number of reductions (`0` means no limit) and returns the reduced `Term`.
///
/// # Example
///
/// ```
/// use lambda_calculus::*;
///
/// let expr    = parse(&"(λa.λb.λc.a (λd.λe.e (d b)) (λd.c) (λd.d)) (λa.λb.a b)", Classic).unwrap();
/// let reduced = parse(&"λa.λb.b", Classic).unwrap();
///
/// assert_eq!(beta(expr, NOR, 0), reduced);
/// ```
pub fn beta(mut term: Term, order: Order, limit: usize) -> Term {
    term.reduce(order, limit);
    term
}

impl Term {
    fn eval(&mut self, count: &mut usize) {
        let to_apply = mem::replace(self, Var(0)); // replace self with a dummy
        let (lhs, rhs) = to_apply.unapp().unwrap(); // safe; only called in reduction sites
        let applied = apply(lhs, &rhs).unwrap(); // ditto
        mem::replace(self, applied); // move self back to its place

        *count += 1;
    }

    fn is_reducible(&self, limit: usize, count: &usize) -> bool {
        self.lhs_ref().and_then(|t| t.unabs_ref()).is_ok() && (limit == 0 || *count < limit )
    }

    /// Performs β-reduction on a `Term` with the specified evaluation `Order` and an optional limit
    /// on the number of reductions (`0` means no limit) and returns the number of performed
    /// reductions.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::*;
    ///
    /// let mut expression = parse(&"(λa.λb.λc.b (a b c)) (λa.λb.b)", Classic).unwrap();
    /// let reduced        = parse(&"λa.λb.a b", Classic).unwrap();
    ///
    /// expression.reduce(NOR, 0);
    ///
    /// assert_eq!(expression, reduced);
    /// ```
    pub fn reduce(&mut self, order: Order, limit: usize) -> usize {
        let mut count = 0;

        match order {
            CBN => self.beta_cbn(limit, &mut count),
            NOR => self.beta_nor(limit, &mut count),
            CBV => self.beta_cbv(limit, &mut count),
            APP => self.beta_app(limit, &mut count),
            HSP => self.beta_hsp(limit, &mut count),
            HNO => self.beta_hno(limit, &mut count),
            HAP => self.beta_hap(limit, &mut count)
        }

        count
    }

    fn beta_cbn(&mut self, limit: usize, count: &mut usize) {
        if limit != 0 && *count == limit { return }

        if let App(_, _) = *self {
            self.lhs_mut().unwrap().beta_cbn(limit, count);

            if self.is_reducible(limit, count) {
                self.eval(count);
                self.beta_cbn(limit, count);
            }
        }
    }

    fn beta_nor(&mut self, limit: usize, count: &mut usize) {
        if limit != 0 && *count == limit { return }

        match *self {
            Abs(ref mut abstracted) => abstracted.beta_nor(limit, count),
            App(_, _) => {
                self.lhs_mut().unwrap().beta_cbn(limit, count);

                if self.is_reducible(limit, count) {
                    self.eval(count);
                    self.beta_nor(limit, count);
                } else {
                    self.lhs_mut().unwrap().beta_nor(limit, count);
                    self.rhs_mut().unwrap().beta_nor(limit, count);
                }
            },
            _ => ()
        }
    }

    fn beta_cbv(&mut self, limit: usize, count: &mut usize) {
        if limit != 0 && *count == limit { return }

        if let App(_, _) = *self {
            self.lhs_mut().unwrap().beta_cbv(limit, count);
            self.rhs_mut().unwrap().beta_cbv(limit, count);

            if self.is_reducible(limit, count) {
                self.eval(count);
                self.beta_cbv(limit, count);
            }
        }
    }

    fn beta_app(&mut self, limit: usize, count: &mut usize) {
        if limit != 0 && *count == limit { return }

        match *self {
            Abs(ref mut abstracted) => abstracted.beta_app(limit, count),
            App(_, _) => {
                self.lhs_mut().unwrap().beta_app(limit, count);
                self.rhs_mut().unwrap().beta_app(limit, count);

                if self.is_reducible(limit, count) {
                    self.eval(count);
                    self.beta_app(limit, count);
                }
            },
            _ => ()
        }
    }

    fn beta_hap(&mut self, limit: usize, count: &mut usize) {
        if limit != 0 && *count == limit { return }

        match *self {
            Abs(ref mut abstracted) => abstracted.beta_hap(limit, count),
            App(_, _) => {
                self.lhs_mut().unwrap().beta_cbv(limit, count);
                self.rhs_mut().unwrap().beta_hap(limit, count);

                if self.is_reducible(limit, count) {
                    self.eval(count);
                    self.beta_hap(limit, count);
                } else {
                    self.lhs_mut().unwrap().beta_hap(limit, count);
                }
            },
            _ => ()
        }
    }

    fn beta_hsp(&mut self, limit: usize, count: &mut usize) {
        if limit != 0 && *count == limit { return }

        match *self {
            Abs(ref mut abstracted) => abstracted.beta_hsp(limit, count),
            App(_, _) => {
                self.lhs_mut().unwrap().beta_hsp(limit, count);

                if self.is_reducible(limit, count) {
                    self.eval(count);
                    self.beta_hsp(limit, count)
                }
            },
            _ => ()
        }
    }

    fn beta_hno(&mut self, limit: usize, count: &mut usize) {
        if limit != 0 && *count == limit { return }

        match *self {
            Abs(ref mut abstracted) => abstracted.beta_hno(limit, count),
            App(_, _) => {
                self.lhs_mut().unwrap().beta_hsp(limit, count);

                if self.is_reducible(limit, count) {
                    self.eval(count);
                    self.beta_hno(limit, count)
                } else {
                    self.lhs_mut().unwrap().beta_hno(limit, count);
                    self.rhs_mut().unwrap().beta_hno(limit, count);
                }
            },
            _ => ()
        }
    }
}

impl fmt::Display for Order {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            NOR => "normal",
            CBN => "call-by-name",
            HSP => "head spine",
            HNO => "hybrid normal",
            APP => "applicative",
            CBV => "call-by-value",
            HAP => "hybrid applicative"
        })
    }
}
<commit_msg>minor doc improvement<commit_after>//! [β-reduction](https://en.wikipedia.org/wiki/Beta_normal_form) for lambda `Term`s

use term::{Term, TermError};
use term::Term::*;
use std::fmt;
use std::mem;
pub use self::Order::*;

/// The [evaluation order](http://www.cs.cornell.edu/courses/cs6110/2014sp/Handouts/Sestoft.pdf) of
/// β-reductions.
///
/// - The `NOR`, `HNO`, `APP` and `HAP` orders reduce expressions to their normal forms
/// - The `APP` order will fail to fully reduce expressions containing functions without a normal
/// form, e.g. the `Y` combinator (they will expand forever)
/// - The `CBN` order reduces to weak head normal form
/// - The `CBV` order reduces to weak normal form
/// - The `HSP` order reduces to head normal form
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Order {
    /// Normal - leftmost outermost; the most popular reduction strategy
    NOR,
    /// Call-by-name - leftmost outermost; no reductions inside abstractions
    CBN,
    /// Head spine - leftmost outermost; abstractions reduced only in head position
    HSP,
    /// Hybrid normal - a mix between `HSP` (head spine) and `NOR` (normal) strategies
    HNO,
    /// Applicative - leftmost innermost; the most eager strategy; unfit for recursion combinators
    APP,
    /// Call-by-value - leftmost innermost, no reductions inside abstractions
    CBV,
    /// Hybrid applicative - a mix between `CBV` (call-by-value) and `APP` (applicative) strategies;
    /// usually the fastest-reducing normalizing strategy
    HAP
}

/// Applies two `Term`s via substitution and variable update, consuming the first one in the process.
///
/// # Example
/// ```
/// use lambda_calculus::reduction::apply;
/// use lambda_calculus::*;
///
/// // these are valid terms, but be careful with unwraps in your code
/// let lhs    = parse(&"λλ42(λ13)", DeBruijn).unwrap();
/// let rhs    = parse(&"λ51", DeBruijn).unwrap();
/// let result = parse(&"λ3(λ61)(λ1(λ71))", DeBruijn).unwrap();
///
/// assert_eq!(apply(lhs, &rhs), Ok(result));
/// ```
/// # Errors
///
/// Returns a `TermError` if `lhs` is not an `Abs`traction.
pub fn apply(mut lhs: Term, rhs: &Term) -> Result<Term, TermError> {
    lhs.unabs_ref()?;

    _apply(&mut lhs, rhs, 0);

    lhs.unabs()
}

fn _apply(lhs: &mut Term, rhs: &Term, depth: usize) {
    match *lhs {
        Var(i) => if i == depth {
            *lhs = rhs.to_owned(); // substitute a top-level variable from lhs with rhs
            update_free_variables(lhs, depth - 1, 0); // update indices of free variables from rhs
        } else if i > depth {
            *lhs = Var(i - 1) // decrement a free variable's index
        },
        Abs(ref mut abstracted) => {
            _apply(abstracted, rhs, depth + 1)
        },
        App(ref mut lhs_lhs, ref mut lhs_rhs) => {
            _apply(lhs_lhs, rhs, depth);
            _apply(lhs_rhs, rhs, depth)
        }
    }
}

fn update_free_variables(term: &mut Term, added_depth: usize, own_depth: usize) {
    match *term {
        Var(ref mut i) => if *i > own_depth {
            *i += added_depth
        },
        Abs(ref mut abstracted) => {
            update_free_variables(abstracted, added_depth, own_depth + 1)
        },
        App(ref mut lhs, ref mut rhs) => {
            update_free_variables(lhs, added_depth, own_depth);
            update_free_variables(rhs, added_depth, own_depth)
        }
    }
}

/// Performs β-reduction on a `Term` with the specified evaluation `Order` and an optional limit on
/// the number of reductions (`0` means no limit) and returns the reduced `Term`.
///
/// # Example
///
/// ```
/// use lambda_calculus::*;
///
/// let expr    = parse(&"(λa.λb.λc.a (λd.λe.e (d b)) (λd.c) (λd.d)) (λa.λb.a b)", Classic).unwrap();
/// let reduced = parse(&"λa.λb.b", Classic).unwrap();
///
/// assert_eq!(beta(expr, NOR, 0), reduced);
/// ```
pub fn beta(mut term: Term, order: Order, limit: usize) -> Term {
    term.reduce(order, limit);
    term
}

impl Term {
    fn eval(&mut self, count: &mut usize) {
        let to_apply = mem::replace(self, Var(0)); // replace self with a dummy
        let (lhs, rhs) = to_apply.unapp().unwrap(); // safe; only called in reduction sites
        let applied = apply(lhs, &rhs).unwrap(); // ditto
        mem::replace(self, applied); // move self back to its place

        *count += 1;
    }

    fn is_reducible(&self, limit: usize, count: &usize) -> bool {
        self.lhs_ref().and_then(|t| t.unabs_ref()).is_ok() && (limit == 0 || *count < limit )
    }

    /// Performs β-reduction on a `Term` with the specified evaluation `Order` and an optional limit
    /// on the number of reductions (`0` means no limit) and returns the number of performed
    /// reductions.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::*;
    ///
    /// let mut expression = parse(&"(λa.λb.λc.b (a b c)) (λa.λb.b)", Classic).unwrap();
    /// let reduced        = parse(&"λa.λb.a b", Classic).unwrap();
    ///
    /// expression.reduce(NOR, 0);
    ///
    /// assert_eq!(expression, reduced);
    /// ```
    pub fn reduce(&mut self, order: Order, limit: usize) -> usize {
        let mut count = 0;

        match order {
            CBN => self.beta_cbn(limit, &mut count),
            NOR => self.beta_nor(limit, &mut count),
            CBV => self.beta_cbv(limit, &mut count),
            APP => self.beta_app(limit, &mut count),
            HSP => self.beta_hsp(limit, &mut count),
            HNO => self.beta_hno(limit, &mut count),
            HAP => self.beta_hap(limit, &mut count)
        }

        count
    }

    fn beta_cbn(&mut self, limit: usize, count: &mut usize) {
        if limit != 0 && *count == limit { return }

        if let App(_, _) = *self {
            self.lhs_mut().unwrap().beta_cbn(limit, count);

            if self.is_reducible(limit, count) {
                self.eval(count);
                self.beta_cbn(limit, count);
            }
        }
    }

    fn beta_nor(&mut self, limit: usize, count: &mut usize) {
        if limit != 0 && *count == limit { return }

        match *self {
            Abs(ref mut abstracted) => abstracted.beta_nor(limit, count),
            App(_, _) => {
                self.lhs_mut().unwrap().beta_cbn(limit, count);

                if self.is_reducible(limit, count) {
                    self.eval(count);
                    self.beta_nor(limit, count);
                } else {
                    self.lhs_mut().unwrap().beta_nor(limit, count);
                    self.rhs_mut().unwrap().beta_nor(limit, count);
                }
            },
            _ => ()
        }
    }

    fn beta_cbv(&mut self, limit: usize, count: &mut usize) {
        if limit != 0 && *count == limit { return }

        if let App(_, _) = *self {
            self.lhs_mut().unwrap().beta_cbv(limit, count);
            self.rhs_mut().unwrap().beta_cbv(limit, count);

            if self.is_reducible(limit, count) {
                self.eval(count);
                self.beta_cbv(limit, count);
            }
        }
    }

    fn beta_app(&mut self, limit: usize, count: &mut usize) {
        if limit != 0 && *count == limit { return }

        match *self {
            Abs(ref mut abstracted) => abstracted.beta_app(limit, count),
            App(_, _) => {
                self.lhs_mut().unwrap().beta_app(limit, count);
                self.rhs_mut().unwrap().beta_app(limit, count);

                if self.is_reducible(limit, count) {
                    self.eval(count);
                    self.beta_app(limit, count);
                }
            },
            _ => ()
        }
    }

    fn beta_hap(&mut self, limit: usize, count: &mut usize) {
        if limit != 0 && *count == limit { return }

        match *self {
            Abs(ref mut abstracted) => abstracted.beta_hap(limit, count),
            App(_, _) => {
                self.lhs_mut().unwrap().beta_cbv(limit, count);
                self.rhs_mut().unwrap().beta_hap(limit, count);

                if self.is_reducible(limit, count) {
                    self.eval(count);
                    self.beta_hap(limit, count);
                } else {
                    self.lhs_mut().unwrap().beta_hap(limit, count);
                }
            },
            _ => ()
        }
    }

    fn beta_hsp(&mut self, limit: usize, count: &mut usize) {
        if limit != 0 && *count == limit { return }

        match *self {
            Abs(ref mut abstracted) => abstracted.beta_hsp(limit, count),
            App(_, _) => {
                self.lhs_mut().unwrap().beta_hsp(limit, count);

                if self.is_reducible(limit, count) {
                    self.eval(count);
                    self.beta_hsp(limit, count)
                }
            },
            _ => ()
        }
    }

    fn beta_hno(&mut self, limit: usize, count: &mut usize) {
        if limit != 0 && *count == limit { return }

        match *self {
            Abs(ref mut abstracted) => abstracted.beta_hno(limit, count),
            App(_, _) => {
                self.lhs_mut().unwrap().beta_hsp(limit, count);

                if self.is_reducible(limit, count) {
                    self.eval(count);
                    self.beta_hno(limit, count)
                } else {
                    self.lhs_mut().unwrap().beta_hno(limit, count);
                    self.rhs_mut().unwrap().beta_hno(limit, count);
                }
            },
            _ => ()
        }
    }
}

impl fmt::Display for Order {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            NOR => "normal",
            CBN => "call-by-name",
            HSP => "head spine",
            HNO => "hybrid normal",
            APP => "applicative",
            CBV => "call-by-value",
            HAP => "hybrid applicative"
        })
    }
}
<|endoftext|>


<commit_before>#[macro_escape]
macro_rules! wayland_protocol(
    ($name: expr, [$(($import: ident, $interface: ident)),*], [$(($prot_name:ident, $prot_import: ident, $prot_iface: ident)),*]) => {
        #[cfg(feature = "client")]
        pub use self::generated::client;

        #[cfg(feature = "server")]
        pub use self::generated::server;

        mod generated {
            #![allow(dead_code,non_camel_case_types,unused_unsafe,unused_variables)]
            #![allow(non_upper_case_globals,non_snake_case,unused_imports)]
            #![allow(missing_docs)]
            #![cfg_attr(feature = "cargo-clippy", allow(clippy))]

            #[cfg(feature = "client")]
            pub mod client {
                //! Client-side API of this protocol
                pub(crate) use wayland_client::{NewProxy, Proxy, ProxyMap, HandledBy, AnonymousObject};
                pub(crate) use wayland_commons::map::{Object, ObjectMetadata};
                pub(crate) use wayland_commons::{Interface, MessageGroup};
                pub(crate) use wayland_commons::wire::{Argument, MessageDesc, ArgumentType, Message};
                pub(crate) use wayland_client::protocol::{$($import),*};
                pub(crate) use wayland_client::sys;
                $(
                    pub(crate) use ::$prot_name::client::$prot_import;
                )*
                include!(concat!(env!("OUT_DIR"), "/", $name, "_client_api.rs"));
            }

            #[cfg(feature = "server")]
            pub mod server {
                //! Server-side API of this protocol
                pub(crate) use wayland_server::{AnonymousObject, NewResource, Resource, ResourceMap, HandledBy};
                pub(crate) use wayland_commons::map::{Object, ObjectMetadata};
                pub(crate) use wayland_commons::{Interface, MessageGroup};
                pub(crate) use wayland_commons::wire::{Argument, MessageDesc, ArgumentType, Message};
                pub(crate) use wayland_server::protocol::{$($import),*};
                pub(crate) use wayland_server::sys;
                $(
                    pub(crate) use ::$prot_name::server::$prot_import;
                )*
                include!(concat!(env!("OUT_DIR"), "/", $name, "_server_api.rs"));
            }
        }
    }
);

#[cfg(feature = "unstable_protocols")]
#[macro_escape]
macro_rules! wayland_protocol_versioned(
    ($name: expr, [$($version: ident),*], $std_imports:tt, $prot_imports:tt) => {
        $(
            #[allow(missing_docs)]
            pub mod $version {
                wayland_protocol!(concat!($name, "-", stringify!($version)), $std_imports, $prot_imports);
            }
        )*
    }
);
<commit_msg>protocols: migrate to new API<commit_after>#[macro_escape]
macro_rules! wayland_protocol(
    ($name: expr, [$(($import: ident, $interface: ident)),*], [$(($prot_name:ident, $prot_import: ident, $prot_iface: ident)),*]) => {
        #[cfg(feature = "client")]
        pub use self::generated::client;

        #[cfg(feature = "server")]
        pub use self::generated::server;

        mod generated {
            #![allow(dead_code,non_camel_case_types,unused_unsafe,unused_variables)]
            #![allow(non_upper_case_globals,non_snake_case,unused_imports)]
            #![allow(missing_docs)]
            #![cfg_attr(feature = "cargo-clippy", allow(clippy))]

            #[cfg(feature = "client")]
            pub mod client {
                //! Client-side API of this protocol
                pub(crate) use wayland_client::{Main, Attached, Proxy, ProxyMap, AnonymousObject};
                pub(crate) use wayland_commons::map::{Object, ObjectMetadata};
                pub(crate) use wayland_commons::{Interface, MessageGroup};
                pub(crate) use wayland_commons::wire::{Argument, MessageDesc, ArgumentType, Message};
                pub(crate) use wayland_client::protocol::{$($import),*};
                pub(crate) use wayland_client::sys;
                $(
                    pub(crate) use ::$prot_name::client::$prot_import;
                )*
                include!(concat!(env!("OUT_DIR"), "/", $name, "_client_api.rs"));
            }

            #[cfg(feature = "server")]
            pub mod server {
                //! Server-side API of this protocol
                pub(crate) use wayland_server::{AnonymousObject, Resource, ResourceMap};
                pub(crate) use wayland_commons::map::{Object, ObjectMetadata};
                pub(crate) use wayland_commons::{Interface, MessageGroup};
                pub(crate) use wayland_commons::wire::{Argument, MessageDesc, ArgumentType, Message};
                pub(crate) use wayland_server::protocol::{$($import),*};
                pub(crate) use wayland_server::sys;
                $(
                    pub(crate) use ::$prot_name::server::$prot_import;
                )*
                include!(concat!(env!("OUT_DIR"), "/", $name, "_server_api.rs"));
            }
        }
    }
);

#[cfg(feature = "unstable_protocols")]
#[macro_escape]
macro_rules! wayland_protocol_versioned(
    ($name: expr, [$($version: ident),*], $std_imports:tt, $prot_imports:tt) => {
        $(
            #[allow(missing_docs)]
            pub mod $version {
                wayland_protocol!(concat!($name, "-", stringify!($version)), $std_imports, $prot_imports);
            }
        )*
    }
);
<|endoftext|>


<commit_before>use std::u64;
use std::io::Read;
use url::Url;
use hyper::header::{ContentLength, ContentRange, ContentRangeSpec, Range, ByteRangeSpec, AcceptRanges, RangeUnit};
use hyper::client::Client;
use hyper::client::response::Response;

use std::io::Write;

use utils::*;
use rssource::*;

#[derive(Debug)]
pub struct HttpSrc {
    url: Option<Url>,
    client: Client,
    response: Option<Response>,
    seekable: bool,
    position: u64,
    size: u64,
    start: u64,
    stop: u64,
}

unsafe impl Sync for HttpSrc {}
unsafe impl Send for HttpSrc {}

impl HttpSrc {
    fn new() -> HttpSrc {
        HttpSrc { url: None, client: Client::new(), response: None, seekable: false, position: 0, size: u64::MAX, start: 0, stop: u64::MAX }
    }

    fn new_source() -> Box<Source> {
        Box::new(HttpSrc::new())
    }
    pub extern "C" fn new_ptr() -> *mut Box<Source> {
        let instance = Box::new(HttpSrc::new_source());
        return Box::into_raw(instance);
    }

    pub fn do_request(&mut self, start: u64, stop: u64) -> bool {
        self.response = None;
        self.seekable = false;
        self.position = 0;
        self.size = u64::MAX;

        match self.url {
            None => return false,
            Some(ref url) => {
                let mut req = self.client.get(url.clone());

                if start != 0 || stop != u64::MAX {
                    req = if stop == u64::MAX {
                            req.header(Range::Bytes(vec![ByteRangeSpec::AllFrom(start)]))
                        } else {
                            req.header(Range::Bytes(vec![ByteRangeSpec::FromTo(start, stop)]))
                        };
                }

                match req.send() {
                    Ok(response) => {
                        if response.status.is_success() {
                            self.size = if let Some(&ContentLength(content_length)) = response.headers.get() {
                                content_length + start
                            } else {
                                u64::MAX
                            };
                            let accept_byte_ranges = if let Some(&AcceptRanges(ref ranges)) = response.headers.get() {
                                ranges.iter().any(|u| *u == RangeUnit::Bytes)
                            } else {
                                false
                            };

                            self.seekable = self.size != u64::MAX && accept_byte_ranges;

                            self.start = start;
                            self.stop = stop;

                            self.position = if let Some(&ContentRange(ContentRangeSpec::Bytes{range: Some((range_start, _)), ..})) = response.headers.get() {
                                range_start
                            } else {
                                start
                            };

                            if self.position != start {
                                println_err!("Failed to seek to {}: Got {}", start, self.position);
                                return false;
                            }

                            self.response = Some(response);

                            return true;
                        } else {
                            println_err!("Failed to fetch {}: {}", url, response.status);
                            return false;
                        }
                    },
                    Err(err) => {
                        println_err!("Failed to fetch {}: {}", url, err.to_string());
                        return false;
                    }
                }
            },
        }
    }
}

impl Source for HttpSrc {
    fn set_uri(&mut self, uri_str: &Option<String>) -> bool {
        if self.response.is_some() {
            println_err!("Can't set URI after starting");
            return false;
        }

        match *uri_str {
            None => {
                self.url = None;
                return true;
            },
            Some(ref uri_str) => {
                let uri_parsed = Url::parse(uri_str.as_str());
                match uri_parsed {
                    Ok(u) => {
                        if u.scheme() == "http" ||
                           u.scheme() == "https" {
                            self.url = Some(u);
                            return true;
                        } else {
                            self.url = None;
                            println_err!("Unsupported file URI '{}'", uri_str);
                            return false;
                        }
                    },
                    Err(err) => {
                        self.url = None;
                        println_err!("Failed to parse URI '{}': {}", uri_str, err);
                        return false;
                    }
                }
            }
        }
    }

    fn get_uri(&self) -> Option<String> {
        self.url.as_ref().map(|u| String::from(u.as_str()))
    }

    fn is_seekable(&self) -> bool {
        self.seekable
    }

    fn get_size(&self) -> u64 {
        self.size
    }

    fn start(&mut self) -> bool {
        self.seekable = false;
        return self.do_request(0, u64::MAX);
    }

    fn stop(&mut self) -> bool {
        self.seekable = false;
        self.position = 0;
        self.size = u64::MAX;
        match self.response {
            Some(ref mut response) => drop(response),
            None => ()
        }
        self.response = None;

        return true;
    }

    fn do_seek(&mut self, start: u64, stop: u64) -> bool {
        return self.do_request(start, stop);
    }

    fn fill(&mut self, offset: u64, data: &mut [u8]) -> Result<usize, GstFlowReturn> {
        if self.position != offset || self.response.is_none() {
            let stop = self.stop;
            if !self.do_request(offset, stop) {
                println_err!("Failed to seek to {}", offset);
                return Err(GstFlowReturn::Error);
            }
        }

        match self.response {
            None => return Err(GstFlowReturn::Error),
            Some(ref mut r) => {
                match r.read(data) {
                    Ok(size) => {
                        if size == 0 {
                            return Err(GstFlowReturn::Eos);
                        }

                        self.position += size as u64;
                        return Ok(size)
                    },
                    Err(err) => {
                        println_err!("Failed to read at {}: {}", offset, err.to_string());
                        return Err(GstFlowReturn::Error);
                    },
                }
            },
        }
    }
}

<commit_msg>Add FIXME comment<commit_after>use std::u64;
use std::io::Read;
use url::Url;
use hyper::header::{ContentLength, ContentRange, ContentRangeSpec, Range, ByteRangeSpec, AcceptRanges, RangeUnit};
use hyper::client::Client;
use hyper::client::response::Response;

use std::io::Write;

use utils::*;
use rssource::*;

#[derive(Debug)]
pub struct HttpSrc {
    url: Option<Url>,
    client: Client,
    response: Option<Response>,
    seekable: bool,
    position: u64,
    size: u64,
    start: u64,
    stop: u64,
}

unsafe impl Sync for HttpSrc {}
unsafe impl Send for HttpSrc {}

impl HttpSrc {
    fn new() -> HttpSrc {
        HttpSrc { url: None, client: Client::new(), response: None, seekable: false, position: 0, size: u64::MAX, start: 0, stop: u64::MAX }
    }

    fn new_source() -> Box<Source> {
        Box::new(HttpSrc::new())
    }
    pub extern "C" fn new_ptr() -> *mut Box<Source> {
        let instance = Box::new(HttpSrc::new_source());
        return Box::into_raw(instance);
    }

    pub fn do_request(&mut self, start: u64, stop: u64) -> bool {
        self.response = None;
        self.seekable = false;
        self.position = 0;
        self.size = u64::MAX;

        match self.url {
            None => return false,
            Some(ref url) => {
                let mut req = self.client.get(url.clone());

                if start != 0 || stop != u64::MAX {
                    req = if stop == u64::MAX {
                            req.header(Range::Bytes(vec![ByteRangeSpec::AllFrom(start)]))
                        } else {
                            req.header(Range::Bytes(vec![ByteRangeSpec::FromTo(start, stop)]))
                        };
                }

                match req.send() {
                    Ok(response) => {
                        if response.status.is_success() {
                            self.size = if let Some(&ContentLength(content_length)) = response.headers.get() {
                                content_length + start
                            } else {
                                u64::MAX
                            };
                            let accept_byte_ranges = if let Some(&AcceptRanges(ref ranges)) = response.headers.get() {
                                ranges.iter().any(|u| *u == RangeUnit::Bytes)
                            } else {
                                false
                            };

                            self.seekable = self.size != u64::MAX && accept_byte_ranges;

                            self.start = start;
                            self.stop = stop;

                            self.position = if let Some(&ContentRange(ContentRangeSpec::Bytes{range: Some((range_start, _)), ..})) = response.headers.get() {
                                range_start
                            } else {
                                start
                            };

                            if self.position != start {
                                println_err!("Failed to seek to {}: Got {}", start, self.position);
                                return false;
                            }

                            self.response = Some(response);

                            return true;
                        } else {
                            println_err!("Failed to fetch {}: {}", url, response.status);
                            return false;
                        }
                    },
                    Err(err) => {
                        println_err!("Failed to fetch {}: {}", url, err.to_string());
                        return false;
                    }
                }
            },
        }
    }
}

impl Source for HttpSrc {
    fn set_uri(&mut self, uri_str: &Option<String>) -> bool {
        if self.response.is_some() {
            println_err!("Can't set URI after starting");
            return false;
        }

        match *uri_str {
            None => {
                self.url = None;
                return true;
            },
            Some(ref uri_str) => {
                let uri_parsed = Url::parse(uri_str.as_str());
                match uri_parsed {
                    Ok(u) => {
                        if u.scheme() == "http" ||
                           u.scheme() == "https" {
                            self.url = Some(u);
                            return true;
                        } else {
                            self.url = None;
                            println_err!("Unsupported file URI '{}'", uri_str);
                            return false;
                        }
                    },
                    Err(err) => {
                        self.url = None;
                        println_err!("Failed to parse URI '{}': {}", uri_str, err);
                        return false;
                    }
                }
            }
        }
    }

    fn get_uri(&self) -> Option<String> {
        self.url.as_ref().map(|u| String::from(u.as_str()))
    }

    fn is_seekable(&self) -> bool {
        self.seekable
    }

    fn get_size(&self) -> u64 {
        self.size
    }

    fn start(&mut self) -> bool {
        self.seekable = false;
        return self.do_request(0, u64::MAX);
    }

    fn stop(&mut self) -> bool {
        self.seekable = false;
        self.position = 0;
        self.size = u64::MAX;
        match self.response {
            Some(ref mut response) => drop(response),
            None => ()
        }
        self.response = None;

        return true;
    }

    fn do_seek(&mut self, start: u64, stop: u64) -> bool {
        return self.do_request(start, stop);
    }

    fn fill(&mut self, offset: u64, data: &mut [u8]) -> Result<usize, GstFlowReturn> {
        if self.position != offset || self.response.is_none() {
            let stop = self.stop; // FIXME: Borrow checker fail
            if !self.do_request(offset, stop) {
                println_err!("Failed to seek to {}", offset);
                return Err(GstFlowReturn::Error);
            }
        }

        match self.response {
            None => return Err(GstFlowReturn::Error),
            Some(ref mut r) => {
                match r.read(data) {
                    Ok(size) => {
                        if size == 0 {
                            return Err(GstFlowReturn::Eos);
                        }

                        self.position += size as u64;
                        return Ok(size)
                    },
                    Err(err) => {
                        println_err!("Failed to read at {}: {}", offset, err.to_string());
                        return Err(GstFlowReturn::Error);
                    },
                }
            },
        }
    }
}

<|endoftext|>


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

use std::collections::HashMap;
use std::hash::Hash;
use std::iter::Iterator;

/// Return a `HashMap` of keys mapped to a list of their corresponding values.
///
/// See [`.into_group_map()`](../trait.Itertools.html#method.into_group_map)
/// for more information.
pub fn into_group_map<I, K, V>(iter: I) -> HashMap<K, Vec<V>>
    where I: Iterator<Item=(K, V)>,
          K: Hash + Eq,
{
    let mut lookup = HashMap::new();

    for (key, val) in iter {
        lookup.entry(key).or_insert(Vec::new()).push(val);
    }

    lookup
}<commit_msg>Added into_group_map_by, into_group_map_by_fold<commit_after>#![cfg(feature = "use_std")]

use std::collections::HashMap;
use std::hash::Hash;
use std::iter::Iterator;

/// Return a `HashMap` of keys mapped to a list of their corresponding values.
///
/// See [`.into_group_map()`](../trait.Itertools.html#method.into_group_map)
/// for more information.
pub fn into_group_map<I, K, V>(iter: I) -> HashMap<K, Vec<V>>
    where I: Iterator<Item=(K, V)>,
          K: Hash + Eq,
{
    let mut lookup = HashMap::new();

    for (key, val) in iter {
        lookup.entry(key).or_insert(Vec::new()).push(val);
    }

    lookup
}

pub fn into_group_map_by<I, K, V>(iter: I, f: impl Fn(&V) -> K) -> HashMap<K, Vec<V>>
    where I: Iterator<Item=V>,
          K: Hash + Eq,
{
    let mut lookup = HashMap::new();

    for val in iter {
        let key = f(&val);
        lookup.entry(key).or_insert(Vec::new()).push(val);
    }

    lookup
}

pub fn into_group_map_by_fold<I, K, V, Acc, Fold>(iter: I, f_key: impl Fn(&V) -> K,
                                             init: Acc,
                                             fold: Fold) -> HashMap<K, Acc>
    where I: Iterator<Item=V>,
          K: Hash + Eq,
          Acc: Clone,
          Fold : FnMut(Acc,V) -> Acc + Clone

{
    let mut lookup = HashMap::new();

    for val in iter {
        let key = f_key(&val);
        lookup.entry(key).or_insert(Vec::new()).push(val);
    }

    lookup
        .into_iter()
        .map(move |(key,value)| (key, value.into_iter().fold(init.clone(), fold.clone())))
        .collect()
}

<|endoftext|>