<commit_before>

// local imports
use number::{Number, Zero};
use matrix::traits::{Shape, MatrixBuffer, Strided};
use matrix::matrix::Matrix;
use matrix::transpose::traits::Transpose;

impl <T:Number> Transpose<T> for Matrix<T> {
    /// Computes the transpose of a matrix.
    /// This doesn't involve complex conjugation.
    /// Returns a new matrix
    fn transpose(&self) -> Matrix <T>{
        let rows = self.num_rows();
        let cols = self.num_cols();
        let mut result : Matrix<T> = Matrix::new(cols, rows);
        let mut psrc_col = self.as_ptr();
        let mut pdst_row = result.as_mut_ptr();
        let src_stride = self.stride() as int;
        let dst_stride = result.stride() as int;
        for _ in range(0, cols){
            let mut psrc = psrc_col;
            let mut pdst = pdst_row;
            for _ in range(0, rows){
                unsafe {
                    *pdst = *psrc;
                    psrc = psrc.offset(1i);
                    pdst = pdst.offset(dst_stride);
                }
            }
            unsafe{
                // Move to next column in source
                psrc_col = psrc_col.offset(src_stride);
                // Move to next row in destination
                pdst_row = pdst_row.offset(1i);
            }
        }
        result
    }

    fn gram(&self) -> Matrix <T>{
        // simple implementation
        //let b = self.transpose();
        //b * *self
        let cols = self.num_cols();
        let rows = self.num_rows();
        let mut result = Matrix::new(cols, cols);
        let ps = self.as_ptr();
        let stride = self.stride() as int;
        let z : T = Zero::zero();
        // We take advantage of the fact that the gram matrix
        // is symmetric.
        // We only compute one half of it.
        for i in range(0, cols){
            for j in range(i, cols){
                unsafe{
                    let mut pi  = ps.offset((i as int)*stride);
                    let mut pj  = ps.offset((j as int)*stride);
                    let mut sum = z;
                    for _ in range(0, rows){
                        sum = sum + *pi * *pj;
                        // Move the pointer ahead
                        pi = pi.offset(1i);
                        pj = pj.offset(1i);
                    }
                    result.set(i, j, sum);
                    if i != j {
                        result.set(j, i, sum);
                    }
                }
            }
        }
        result

    }

}

/******************************************************
 *
 *   Unit tests
 *
 *******************************************************/

#[cfg(test)]
mod test{

    use matrix::matrix::*;
    use matrix::traits::*;
    use matrix::constructors::*;

    #[test]
    fn test_transpose(){
        let m  : MatrixI64 = Matrix::from_iter_cw(2, 2,  range(0, 4));
        assert_eq!(m.to_std_vec(), vec![0, 1, 2, 3]);
        assert_eq!(m.transpose().to_std_vec(), vec![0, 2, 1, 3]);
        assert_eq!(m.transpose().transpose().to_std_vec(), vec![0, 1, 2, 3]);
        let m  : MatrixI64 = Matrix::from_iter_cw(2, 3,  range(0, 10));
        assert_eq!(m.transpose().to_std_vec(), vec![
            0, 2, 4, 1, 3, 5]);
        let m4 :  MatrixI64 = Matrix::from_iter_cw(2, 5, range(9, 100));
        let m5 = m4.transpose();
        println!("m4: {}", m4);
        println!("m5: {}", m5);
        assert_eq!(m5.transpose(), m4);
    }

    #[test]
    fn test_gram(){
        let m = matrix_rw_f32(4, 3, &[
            1., 2., 3.,
            4., 5., 6.,
            4., 5., 6.,
            7., 8., 9.]);
        let g  = m.gram();
        assert_eq!(g, m.transpose() * m);
    }

}

/******************************************************
 *
 *   Bench marks.
 *
 *******************************************************/

#[cfg(test)]
mod bench {
    extern crate test;
    use self::test::Bencher;
    use matrix::constructors::*;
    use matrix::traits::*;

    #[bench]
    fn bench_transpose(b: &mut Bencher){
        let a = hadamard(1024).unwrap();
        b.iter(|| {
                    a.transpose();
                });
    }

    #[bench]
    fn bench_gram_simple(b: &mut Bencher){
        let m = hadamard(128).unwrap();
        let m = m.repeat_matrix(1, 2);
        b.iter(|| {
                    // computation of gram matrix
                    m.transpose() * m;
                });

    }

    #[bench]
    fn bench_gram_optimized(b: &mut Bencher){
        let m = hadamard(128).unwrap();
        let m = m.repeat_matrix(1, 2);
        b.iter(|| {
                    // computation of gram matrix
                    m.gram();
                });

    }
}
<commit_msg>block size 32 based transpose implementation seems much faster. Reaching MATLAB speeds.<commit_after>
// std imports
use std::iter::range_step;
use std::cmp::min;

// local imports
use number::{Number, Zero};
use matrix::traits::{Shape, MatrixBuffer, Strided};
use matrix::matrix::Matrix;
use matrix::transpose::traits::Transpose;

/// Checks if the matrices are transpose of each other
pub fn are_transpose<T:Number>(lhs: & Matrix<T>, rhs: & Matrix<T>) -> bool{
    if lhs.num_rows() != rhs.num_cols(){
        return false;
    }
    if lhs.num_cols() != rhs.num_rows(){
        return false;
    }
    for c in range(0, lhs.num_cols()){
        for r in range(0, lhs.num_rows()){
            if lhs.get(r, c) != rhs.get(c, r){
                return false;
            }
        }
    }
    // They are transpose of each other
    true
}

/// Simple implementation of transpose operation
pub fn transpose_simple<T:Number>(src: & Matrix<T>)->Matrix <T>{
    let rows = src.num_rows();
    let cols = src.num_cols();
    let mut result : Matrix<T> = Matrix::new(cols, rows);
    let mut psrc_col = src.as_ptr();
    let mut pdst_row = result.as_mut_ptr();
    let src_stride = src.stride() as int;
    let dst_stride = result.stride() as int;
    for _ in range(0, cols){
        let mut psrc = psrc_col;
        let mut pdst = pdst_row;
        for _ in range(0, rows){
            unsafe {
                *pdst = *psrc;
                psrc = psrc.offset(1i);
                pdst = pdst.offset(dst_stride);
            }
        }
        unsafe{
            // Move to next column in source
            psrc_col = psrc_col.offset(src_stride);
            // Move to next row in destination
            pdst_row = pdst_row.offset(1i);
        }
    }
    result
}

/// Block wise transpose
pub fn transpose_block<T:Number>(src: & Matrix<T>)->Matrix <T>{
    // Choose a block size
    let block_size = 32;
    // Construct the destination
    let rows = src.num_rows();
    let cols = src.num_cols();
    let mut result : Matrix<T> = Matrix::new(cols, rows);
    let psrc = src.as_ptr();
    let pdst = result.as_mut_ptr();
    let src_stride = src.stride() as int;
    let dst_stride = result.stride() as int;

    for cc in range_step(0, cols, block_size){
        for rr in range_step(0, rows, block_size){
            // We have to transpose a block of size blk x blk
            let blk_cols = min (block_size, cols - cc);
            let blk_rows = min (block_size, rows - rr);
            unsafe{
                // Get our pointers to the beginning of the block
                let mut psrc_col = psrc.offset(src.cell_to_offset(rr, cc));
                let mut pdst_row = pdst.offset(result.cell_to_offset(cc, rr));

                // Now run through the block
                // iterate over columns of source block
                // iterate over rows of destination block
                for _ in range(0, blk_cols){
                    let mut psrc_blk = psrc_col;
                    let mut pdst_blk = pdst_row;
                    // iterate over the rows of a column in source block
                    // iterate over the columns of a row in destination block
                    for _ in range(0, blk_rows){
                        *pdst_blk = *psrc_blk;
                        // next row in source
                        psrc_blk = psrc_blk.offset(1i);
                        // next column in destination
                        pdst_blk = pdst_blk.offset(dst_stride);
                    }
                    // Move to next column in source block
                    psrc_col = psrc_col.offset(src_stride);
                    // Move to next row in destination block
                    pdst_row = pdst_row.offset(1i);
                }
            }
        }
    }
    result
}

impl <T:Number> Transpose<T> for Matrix<T> {
    /// Computes the transpose of a matrix.
    /// This doesn't involve complex conjugation.
    /// Returns a new matrix
    #[inline]
    fn transpose(&self) -> Matrix <T>{
        transpose_block(self)
    }

    fn gram(&self) -> Matrix <T>{
        // simple implementation
        //let b = self.transpose();
        //b * *self
        let cols = self.num_cols();
        let rows = self.num_rows();
        let mut result = Matrix::new(cols, cols);
        let ps = self.as_ptr();
        let stride = self.stride() as int;
        let z : T = Zero::zero();
        // We take advantage of the fact that the gram matrix
        // is symmetric.
        // We only compute one half of it.
        for i in range(0, cols){
            for j in range(i, cols){
                unsafe{
                    let mut pi  = ps.offset((i as int)*stride);
                    let mut pj  = ps.offset((j as int)*stride);
                    let mut sum = z;
                    for _ in range(0, rows){
                        sum = sum + *pi * *pj;
                        // Move the pointer ahead
                        pi = pi.offset(1i);
                        pj = pj.offset(1i);
                    }
                    result.set(i, j, sum);
                    if i != j {
                        result.set(j, i, sum);
                    }
                }
            }
        }
        result

    }

}

/******************************************************
 *
 *   Unit tests
 *
 *******************************************************/

#[cfg(test)]
mod test{

    use std::iter::range_step;
    use matrix::matrix::*;
    use matrix::traits::*;
    use matrix::constructors::*;
    use super::*;

    #[test]
    fn test_transpose(){
        let m  : MatrixI64 = Matrix::from_iter_cw(2, 2,  range(0, 4));
        assert_eq!(m.to_std_vec(), vec![0, 1, 2, 3]);
        assert_eq!(m.transpose().to_std_vec(), vec![0, 2, 1, 3]);
        assert_eq!(m.transpose().transpose().to_std_vec(), vec![0, 1, 2, 3]);
        let m  : MatrixI64 = Matrix::from_iter_cw(2, 3,  range(0, 10));
        assert_eq!(m.transpose().to_std_vec(), vec![
            0, 2, 4, 1, 3, 5]);
        let m4 :  MatrixI64 = Matrix::from_iter_cw(2, 5, range(9, 100));
        let m5 = m4.transpose();
        println!("m4: {}", m4);
        println!("m5: {}", m5);
        assert_eq!(m5.transpose(), m4);
    }

    #[test]
    fn test_transpoe_simple_hilbert(){
        for n in range_step(100, 1024, 81){
            let h = hilbert(n);
            assert!(are_transpose(&h, &h.transpose()));
        }
    }

    #[test]
    fn test_transpoe_block_hilbert(){
        for n in range_step(100, 1024, 81){
            let h = hilbert(n);
            assert!(are_transpose(&h, & transpose_block(&h)));
        }
    }

    #[test]
    fn test_gram(){
        let m = matrix_rw_f32(4, 3, &[
            1., 2., 3.,
            4., 5., 6.,
            4., 5., 6.,
            7., 8., 9.]);
        let g  = m.gram();
        assert_eq!(g, m.transpose() * m);
    }

}

/******************************************************
 *
 *   Bench marks.
 *
 *******************************************************/

#[cfg(test)]
mod bench {
    extern crate test;
    use self::test::Bencher;
    use matrix::constructors::*;
    use matrix::traits::*;
    use super::*;

    #[bench]
    fn bench_transpose_simple(b: &mut Bencher){
        let a = hadamard(4096).unwrap();
        b.iter(|| {
                    transpose_simple(&a);
                });
    }

    #[bench]
    fn bench_transpose_block(b: &mut Bencher){
        let a = hadamard(4096).unwrap();
        b.iter(|| {
                    transpose_block(&a);
                });
    }

    #[bench]
    fn bench_gram_simple(b: &mut Bencher){
        let m = hadamard(128).unwrap();
        let m = m.repeat_matrix(1, 2);
        b.iter(|| {
                    // computation of gram matrix
                    m.transpose() * m;
                });

    }

    #[bench]
    fn bench_gram_optimized(b: &mut Bencher){
        let m = hadamard(128).unwrap();
        let m = m.repeat_matrix(1, 2);
        b.iter(|| {
                    // computation of gram matrix
                    m.gram();
                });

    }
}
<|endoftext|>


<commit_before>//! Video RAM display

use sdl2;
use io::constants::*;
use cpu;
use cpu::*;

use sdl2::rect::Point;
use sdl2::rect::Rect;
use sdl2::pixels::*;

use io::graphics::Drawable;

pub struct VidRamBGDisplay {
    pub tile_data_select: TileDataSelect,
}

/// Display for backround screen buffer
impl Drawable for VidRamBGDisplay {
    fn get_initial_size(&self) -> (u32, u32) {
        (SCREEN_BUFFER_SIZE_X, SCREEN_BUFFER_SIZE_Y)
    }

    fn draw(&mut self, renderer: &mut sdl2::render::Renderer, cpu: &mut Cpu) {
        // TODO add toggle for this also?
        let tile_map_offset = TILE_MAP_1_START;

        let ref bg_select = self.tile_data_select;

        let tile_patterns_offset = match *bg_select {
            TileDataSelect::Auto => {
                if cpu.lcdc_bg_win_tile_data() {
                    TILE_PATTERN_TABLE_1_ORIGIN
                } else {
                    TILE_PATTERN_TABLE_2_ORIGIN
                }
            }
            TileDataSelect::Mode1 => TILE_PATTERN_TABLE_1_ORIGIN,
            TileDataSelect::Mode2 => TILE_PATTERN_TABLE_2_ORIGIN,
        };

        draw_background_buffer(renderer, cpu,
                               tile_map_offset,
                               tile_patterns_offset,
                               0);
        draw_objects(renderer, cpu, 0, 0);
    }

    fn click(&mut self, _: sdl2::mouse::MouseButton, _: Point, _: &mut Cpu) {
        self.tile_data_select = match self.tile_data_select {
            TileDataSelect::Auto => TileDataSelect::Mode1,
            TileDataSelect::Mode1 => TileDataSelect::Mode2,
            TileDataSelect::Mode2 => TileDataSelect::Auto,
        };
        debug!("BG buffer tile data: {:?}", self.tile_data_select);
    }
}

pub struct VidRamTileDisplay {
    pub tile_data_select: TileDataSelect,
}

/// Display for tile data. Display tiles in `TILE_COLUMNS` with
/// `BORDER_PX` spacing.
impl Drawable for VidRamTileDisplay {
    fn get_initial_size(&self) -> (u32, u32) {
        let cell_size = TILE_SIZE_PX + BORDER_PX;
        let tile_num = TILE_PATTERN_TABLES_SIZE / TILE_SIZE_BYTES;
        ((TILE_COLUMNS * cell_size) as u32,
         ((tile_num / TILE_COLUMNS) * cell_size) as u32)
    }

    fn draw(&mut self, renderer: &mut sdl2::render::Renderer, cpu: &mut Cpu) {
        draw_tile_patterns(renderer, cpu);
    }

    fn click(&mut self, button: sdl2::mouse::MouseButton, position: Point, _: &mut Cpu) {
        debug!("Clicked tile display @ {:?} with {:?}", position, button);
    }
}

/// Draw single tile at given screen position
pub fn draw_tile(renderer: &mut sdl2::render::Renderer,
                 gameboy: &Cpu,
                 mem_offset: u16,
                 tile_idx: u16, // technically when used by GB it's only 8bit
                 screen_offset_x: i32,
                 screen_offset_y: i32) {
    #[inline]
    fn get_bit(n: u8, offset: u8) -> u8 {
        (n >> (7 - offset)) & 1u8
    }

    for px in 0..TILE_SIZE_PX {
        for py in 0..TILE_SIZE_PX {
            let col_byte_off = py * 2;
            let offset = mem_offset + (tile_idx * TILE_SIZE_BYTES);
            let col_byte1_v = gameboy.mem[(offset + col_byte_off) as usize];
            let col_byte2_v = gameboy.mem[(offset + col_byte_off + 1) as usize];
            let col_bit_1 = get_bit(col_byte1_v, px as u8);
            let col_bit_2 = get_bit(col_byte2_v, px as u8);
            let px_color = (col_bit_2 << 1) | col_bit_1;

            // let d = 255/4;
            // let px_val = px_color*d;
            // renderer.set_draw_color(Color::RGB(px_val, px_val, px_val));

            let px_pal_col = TILE_PALETTE[px_color as usize];
            renderer.set_draw_color(px_pal_col);

            let point = Point::new(screen_offset_x + px as i32,
                                   screen_offset_y + py as i32);
            match renderer.draw_point(point) {
                Ok(_) => (),
                Err(_) => error!("Could not draw point at {:?}", point),
            };
        }
    }
}

// TODO cache tiles into texture and use blending options (?) to make
// desired color "trasnparent".
/// Draw single tile at given screen position without drawing "0" color.
pub fn draw_tile_transparent(renderer: &mut sdl2::render::Renderer,
                             gameboy: &Cpu,
                             mem_offset: u16,
                             tile_idx: u16, // technically when used by GB it's only 8bit
                             screen_offset_x: i32,
                             screen_offset_y: i32) {

    #[inline]
    fn get_bit(n: u8, offset: u8) -> u8 {
        (n >> (7 - offset)) & 1u8
    }

    for px in 0..TILE_SIZE_PX {
        for py in 0..TILE_SIZE_PX {
            let col_byte_off = py * 2;
            let offset = mem_offset + (tile_idx * TILE_SIZE_BYTES);
            let col_byte1_v = gameboy.mem[(offset + col_byte_off) as usize];
            let col_byte2_v = gameboy.mem[(offset + col_byte_off + 1) as usize];
            let col_bit_1 = get_bit(col_byte1_v, px as u8);
            let col_bit_2 = get_bit(col_byte2_v, px as u8);
            let px_color = (col_bit_2 << 1) | col_bit_1;

            // let d = 255/4;
            // let px_val = px_color*d;
            // renderer.set_draw_color(Color::RGB(px_val, px_val, px_val));

            if true || px_color != 0 {
                let px_pal_col = OBJECT_PALETTE[px_color as usize];
                renderer.set_draw_color(px_pal_col);

                let point = Point::new((screen_offset_x as u8).wrapping_add(px as u8) as i32,
                                       (screen_offset_y as u8).wrapping_add(py as u8) as i32);
                renderer.draw_point(point).unwrap();
            }
        }
    }
}

/// This is the dumbest and straightforward code for displaying Tile
/// Patterns. It displays both background and sprite "tiles" as they
/// overlap in memory.
pub fn draw_tile_patterns(renderer: &mut sdl2::render::Renderer,
                          gameboy: &Cpu) {

    for tile_idx in 0..(TILE_PATTERN_TABLES_SIZE / TILE_SIZE_BYTES) + 1 {

        let tile_start_x = (tile_idx % TILE_COLUMNS) * (TILE_SIZE_PX + BORDER_PX);
        let y_pos = tile_idx / TILE_COLUMNS;
        let tile_start_y = (TILE_SIZE_PX + BORDER_PX) * y_pos;

        draw_tile(renderer,
                  gameboy,
                  TILE_PATTERN_TABLE_1_START,
                  tile_idx,
                  tile_start_x as i32,
                  tile_start_y as i32);
    }
}

/// Draw whole background buffer (256x256 px)
pub fn draw_background_buffer(renderer: &mut sdl2::render::Renderer,
                              gameboy: &Cpu,
                              tile_map_offset: cpu::constants::MemAddr,
                              tile_patterns_offset: cpu::constants::MemAddr,
                              screen_offset_x: i32) {

    // TODO implement proper windows/widgets
    const TOP_Y: i32 = 1;
    let screen_offset_y = TOP_Y;

    // FIXME rethink how to do this better
    match tile_patterns_offset {
        TILE_PATTERN_TABLE_1_ORIGIN => {
            for tile in 0..(SCREEN_BUFFER_TILES_X * SCREEN_BUFFER_TILES_Y) {
                let tile_index = gameboy.mem[(tile_map_offset + tile as u16) as usize];

                let tile_x = tile % SCREEN_BUFFER_TILES_X;
                let tile_y = tile / SCREEN_BUFFER_TILES_Y;

                draw_tile(renderer,
                          gameboy,
                          TILE_PATTERN_TABLE_1_START,
                          tile_index as u16, // use index as unsigned 8bit
                          screen_offset_x + (tile_x * TILE_SIZE_PX as u32) as i32,
                          screen_offset_y + (tile_y * TILE_SIZE_PX as u32) as i32);

            }
        },
        TILE_PATTERN_TABLE_2_ORIGIN => {
            for tile in 0..(SCREEN_BUFFER_TILES_X * SCREEN_BUFFER_TILES_Y) {
                let tile_index = gameboy.mem[(tile_map_offset + tile as u16) as usize];

                let tile_x = tile % SCREEN_BUFFER_TILES_X;
                let tile_y = tile / SCREEN_BUFFER_TILES_Y;

                draw_tile(renderer,
                          gameboy,
                          TILE_PATTERN_TABLE_2_START,             // reposition origin
                          add_u16_i8(128u16, (tile_index as i8)), // index is signed 8bit
                          screen_offset_x + (tile_x * TILE_SIZE_PX as u32) as i32,
                          screen_offset_y + (tile_y * TILE_SIZE_PX as u32) as i32);

            }

        },
        _ => panic!("Wrong tile data select"),
    };

    draw_screen_border(renderer, gameboy, screen_offset_x, TOP_Y);
}

/// Draw rectangle showing values of SCX and SCY registers,
/// i.e. visible screen area.
fn draw_screen_border(renderer: &mut sdl2::render::Renderer,
                      gameboy: &Cpu,
                      screen_offset_x: i32,
                      screen_offset_y: i32) {
    renderer.set_draw_color(Color::RGB(255, 255, 255));
    let scx: u8 = gameboy.scx();
    let scy: u8 = gameboy.scy();

    renderer.set_clip_rect(Some(Rect::new(screen_offset_x,
                                          screen_offset_y,
                                          SCREEN_BUFFER_SIZE_X,
                                          SCREEN_BUFFER_SIZE_Y)));
    // Draw 9 versions to do wrap around
    // FIXME is this inefficient/dumb and there is a better way? probably.
    for x in -1..2 {
        for y in -1..2 {
            let offset_x = screen_offset_x.wrapping_add(x*SCREEN_BUFFER_SIZE_X as i32);
            let offset_y = screen_offset_y.wrapping_add(y*SCREEN_BUFFER_SIZE_X as i32);
            renderer.draw_rect(Rect::new(offset_x + scx as i32 - 1,
                                         offset_y + scy as i32 - 1,
                                         GB_SCREEN_WIDTH as u32 + 2,
                                         GB_SCREEN_HEIGHT as u32 + 2)).unwrap();
        }
    }
    renderer.set_clip_rect(None);
}

/// Draw "sprites" (something gameboy calls "Objects").
pub fn draw_objects(renderer: &mut sdl2::render::Renderer,
                    gameboy: &Cpu,
                    screen_offset_x: i32,
                    screen_offset_y: i32) {

    // TODO sprites should use palletes
    // TODO sprites can have transparent color
    // TODO sprites are sorted by x/y/idx

    for obj_idx in 0..40+1 {
        let offset = OBJECT_ATTRIBUTE_START + obj_idx * OBJECT_ATTRIBUTE_BLOCK_SIZE;
        let sprite_y: u8 = gameboy.mem[offset as usize];
        let sprite_x: u8 = gameboy.mem[offset as usize + 1];
        let tile_index: i8 = gameboy.mem[offset as usize + 2] as i8;
        // TODO implement flag handling (priority, flips...)
        let flags: u8 = gameboy.mem[offset as usize + 3];
        if sprite_x == 0 && sprite_y == 0 {
            // sprite is "hidden"
            continue
        }
        let screen_x = sprite_x.wrapping_sub(8);
        let screen_y = sprite_y.wrapping_sub(16);

        if gameboy.lcdc_sprite_size() {
            // "Tall 8x16 sprites" mode
            // FIXME Not sure this is how 8x16 sprites work
            let tile_16 = tile_index & !1;
            draw_tile_transparent(renderer,
                                  gameboy,
                                  TILE_PATTERN_TABLE_2_START,
                                  add_u16_i8(128u16, tile_16), // index is signed 8bit
                                  screen_offset_x + screen_x as i32,
                                  screen_offset_y + screen_y as i32);
            draw_tile_transparent(renderer,
                                  gameboy,
                                  TILE_PATTERN_TABLE_2_START,
                                  add_u16_i8(128u16, (tile_16 + 1)), // index is signed 8bit
                                  screen_offset_x + screen_x as i32,
                                  screen_offset_y + screen_y as i32);
        } else {
            // 8x8 sprites mode
            draw_tile_transparent(renderer,
                                  gameboy,
                                  TILE_PATTERN_TABLE_2_START,
                                  add_u16_i8(128u16, (tile_index as i8)), // index is signed 8bit
                                  screen_offset_x + screen_x as i32,
                                  screen_offset_y + screen_y as i32);

        }

    }

}
<commit_msg>vidram: Tile drawing is slightly more correct<commit_after>//! Video RAM display

use sdl2;
use io::constants::*;
use cpu;
use cpu::*;

use sdl2::rect::Point;
use sdl2::rect::Rect;
use sdl2::pixels::*;

use io::graphics::Drawable;

pub struct VidRamBGDisplay {
    pub tile_data_select: TileDataSelect,
}

/// Display for backround screen buffer
impl Drawable for VidRamBGDisplay {
    fn get_initial_size(&self) -> (u32, u32) {
        (SCREEN_BUFFER_SIZE_X, SCREEN_BUFFER_SIZE_Y)
    }

    fn draw(&mut self, renderer: &mut sdl2::render::Renderer, cpu: &mut Cpu) {
        // TODO add toggle for this also?
        // FIXME pretty sure this is swapped, but for some reason works better
        let tile_map_offset = if cpu.lcdc_bg_tile_map() {
            TILE_MAP_2_START
        } else {
            TILE_MAP_1_START
        };

        let ref bg_select = self.tile_data_select;

        let tile_patterns_offset = match *bg_select {
            TileDataSelect::Auto => {
                if cpu.lcdc_bg_win_tile_data() {
                    TILE_PATTERN_TABLE_1_ORIGIN
                } else {
                    TILE_PATTERN_TABLE_2_ORIGIN
                }
            }
            TileDataSelect::Mode1 => TILE_PATTERN_TABLE_1_ORIGIN,
            TileDataSelect::Mode2 => TILE_PATTERN_TABLE_2_ORIGIN,
        };

        draw_background_buffer(renderer, cpu,
                               tile_map_offset,
                               tile_patterns_offset,
                               0);
        draw_objects(renderer, cpu, cpu.scx() as i32, cpu.scy() as i32);
    }

    fn click(&mut self, _: sdl2::mouse::MouseButton, _: Point, _: &mut Cpu) {
        self.tile_data_select = match self.tile_data_select {
            TileDataSelect::Auto => TileDataSelect::Mode1,
            TileDataSelect::Mode1 => TileDataSelect::Mode2,
            TileDataSelect::Mode2 => TileDataSelect::Auto,
        };
        debug!("BG buffer tile data: {:?}", self.tile_data_select);
    }
}

pub struct VidRamTileDisplay {
    pub tile_data_select: TileDataSelect,
}

/// Display for tile data. Display tiles in `TILE_COLUMNS` with
/// `BORDER_PX` spacing.
impl Drawable for VidRamTileDisplay {
    fn get_initial_size(&self) -> (u32, u32) {
        let cell_size = TILE_SIZE_PX + BORDER_PX;
        let tile_num = TILE_PATTERN_TABLES_SIZE / TILE_SIZE_BYTES;
        ((TILE_COLUMNS * cell_size) as u32,
         ((tile_num / TILE_COLUMNS) * cell_size) as u32)
    }

    fn draw(&mut self, renderer: &mut sdl2::render::Renderer, cpu: &mut Cpu) {
        draw_tile_patterns(renderer, cpu);
    }

    fn click(&mut self, button: sdl2::mouse::MouseButton, position: Point, _: &mut Cpu) {
        debug!("Clicked tile display @ {:?} with {:?}", position, button);
    }
}

/// Draw single tile at given screen position
pub fn draw_tile(renderer: &mut sdl2::render::Renderer,
                 gameboy: &Cpu,
                 mem_offset: u16,
                 tile_idx: u16, // technically when used by GB it's only 8bit
                 screen_offset_x: i32,
                 screen_offset_y: i32) {
    #[inline]
    fn get_bit(n: u8, offset: u8) -> u8 {
        (n >> (7 - offset)) & 1u8
    }

    for px in 0..TILE_SIZE_PX {
        for py in 0..TILE_SIZE_PX {
            let col_byte_off = py * 2;
            let offset = mem_offset + (tile_idx * TILE_SIZE_BYTES);
            let col_byte1_v = gameboy.mem[(offset + col_byte_off) as usize];
            let col_byte2_v = gameboy.mem[(offset + col_byte_off + 1) as usize];
            let col_bit_1 = get_bit(col_byte1_v, px as u8);
            let col_bit_2 = get_bit(col_byte2_v, px as u8);
            let px_color = (col_bit_2 << 1) | col_bit_1;

            // let d = 255/4;
            // let px_val = px_color*d;
            // renderer.set_draw_color(Color::RGB(px_val, px_val, px_val));

            let px_pal_col = TILE_PALETTE[px_color as usize];
            renderer.set_draw_color(px_pal_col);

            let point = Point::new(screen_offset_x + px as i32,
                                   screen_offset_y + py as i32);
            match renderer.draw_point(point) {
                Ok(_) => (),
                Err(_) => error!("Could not draw point at {:?}", point),
            };
        }
    }
}

// TODO cache tiles into texture and use blending options (?) to make
// desired color "trasnparent".
/// Draw single tile at given screen position without drawing "0" color.
pub fn draw_tile_transparent(renderer: &mut sdl2::render::Renderer,
                             gameboy: &Cpu,
                             mem_offset: u16,
                             tile_idx: u16, // technically when used by GB it's only 8bit
                             screen_offset_x: i32,
                             screen_offset_y: i32) {

    #[inline]
    fn get_bit(n: u8, offset: u8) -> u8 {
        (n >> (7 - offset)) & 1u8
    }

    for px in 0..TILE_SIZE_PX {
        for py in 0..TILE_SIZE_PX {
            let col_byte_off = py * 2;
            let offset = mem_offset + (tile_idx * TILE_SIZE_BYTES);
            let col_byte1_v = gameboy.mem[(offset + col_byte_off) as usize];
            let col_byte2_v = gameboy.mem[(offset + col_byte_off + 1) as usize];
            let col_bit_1 = get_bit(col_byte1_v, px as u8);
            let col_bit_2 = get_bit(col_byte2_v, px as u8);
            let px_color = (col_bit_2 << 1) | col_bit_1;

            // let d = 255/4;
            // let px_val = px_color*d;
            // renderer.set_draw_color(Color::RGB(px_val, px_val, px_val));

            // TODO add toggle for this or remove it
            const DEBUG_OAM_BG: bool = false;

            if DEBUG_OAM_BG || px_color != 0 {
                let px_pal_col = OBJECT_PALETTE[px_color as usize];
                renderer.set_draw_color(px_pal_col);

                let point = Point::new((screen_offset_x as u8).wrapping_add(px as u8) as i32,
                                       (screen_offset_y as u8).wrapping_add(py as u8) as i32);
                renderer.draw_point(point).unwrap();
            }
        }
    }
}

/// This is the dumbest and straightforward code for displaying Tile
/// Patterns. It displays both background and sprite "tiles" as they
/// overlap in memory.
pub fn draw_tile_patterns(renderer: &mut sdl2::render::Renderer,
                          gameboy: &Cpu) {

    for tile_idx in 0..(TILE_PATTERN_TABLES_SIZE / TILE_SIZE_BYTES) + 1 {

        let tile_start_x = (tile_idx % TILE_COLUMNS) * (TILE_SIZE_PX + BORDER_PX);
        let y_pos = tile_idx / TILE_COLUMNS;
        let tile_start_y = (TILE_SIZE_PX + BORDER_PX) * y_pos;

        draw_tile(renderer,
                  gameboy,
                  TILE_PATTERN_TABLE_1_START,
                  tile_idx,
                  tile_start_x as i32,
                  tile_start_y as i32);
    }
}

/// Draw whole background buffer (256x256 px)
pub fn draw_background_buffer(renderer: &mut sdl2::render::Renderer,
                              gameboy: &Cpu,
                              tile_map_offset: cpu::constants::MemAddr,
                              tile_patterns_offset: cpu::constants::MemAddr,
                              screen_offset_x: i32) {

    // TODO implement proper windows/widgets
    const TOP_Y: i32 = 1;
    let screen_offset_y = TOP_Y;

    // FIXME rethink how to do this better
    match tile_patterns_offset {
        TILE_PATTERN_TABLE_1_ORIGIN => {
            for tile in 0..(SCREEN_BUFFER_TILES_X * SCREEN_BUFFER_TILES_Y) {
                let tile_index = gameboy.mem[(tile_map_offset + tile as u16) as usize];

                let tile_x = tile % SCREEN_BUFFER_TILES_X;
                let tile_y = tile / SCREEN_BUFFER_TILES_Y;

                draw_tile(renderer,
                          gameboy,
                          TILE_PATTERN_TABLE_1_START,
                          tile_index as u16, // use index as unsigned 8bit
                          screen_offset_x + (tile_x * TILE_SIZE_PX as u32) as i32,
                          screen_offset_y + (tile_y * TILE_SIZE_PX as u32) as i32);

            }
        },
        TILE_PATTERN_TABLE_2_ORIGIN => {
            for tile in 0..(SCREEN_BUFFER_TILES_X * SCREEN_BUFFER_TILES_Y) {
                let tile_index = gameboy.mem[(tile_map_offset + tile as u16) as usize];

                let tile_x = tile % SCREEN_BUFFER_TILES_X;
                let tile_y = tile / SCREEN_BUFFER_TILES_Y;

                draw_tile(renderer,
                          gameboy,
                          TILE_PATTERN_TABLE_2_START,             // reposition origin
                          add_u16_i8(128u16, (tile_index as i8)), // index is signed 8bit
                          screen_offset_x + (tile_x * TILE_SIZE_PX as u32) as i32,
                          screen_offset_y + (tile_y * TILE_SIZE_PX as u32) as i32);

            }

        },
        _ => panic!("Wrong tile data select"),
    };

    draw_screen_border(renderer, gameboy, screen_offset_x, TOP_Y);
}

/// Draw rectangle showing values of SCX and SCY registers,
/// i.e. visible screen area.
fn draw_screen_border(renderer: &mut sdl2::render::Renderer,
                      gameboy: &Cpu,
                      screen_offset_x: i32,
                      screen_offset_y: i32) {
    renderer.set_draw_color(Color::RGB(255, 255, 255));
    let scx: u8 = gameboy.scx();
    let scy: u8 = gameboy.scy();

    renderer.set_clip_rect(Some(Rect::new(screen_offset_x,
                                          screen_offset_y,
                                          SCREEN_BUFFER_SIZE_X,
                                          SCREEN_BUFFER_SIZE_Y)));
    // Draw 9 versions to do wrap around
    // FIXME is this inefficient/dumb and there is a better way? probably.
    for x in -1..2 {
        for y in -1..2 {
            let offset_x = screen_offset_x.wrapping_add(x*SCREEN_BUFFER_SIZE_X as i32);
            let offset_y = screen_offset_y.wrapping_add(y*SCREEN_BUFFER_SIZE_X as i32);
            renderer.draw_rect(Rect::new(offset_x + scx as i32 - 1,
                                         offset_y + scy as i32 - 1,
                                         GB_SCREEN_WIDTH as u32 + 2,
                                         GB_SCREEN_HEIGHT as u32 + 2)).unwrap();
        }
    }
    renderer.set_clip_rect(None);
}

/// Draw "sprites" (something gameboy calls "Objects").
pub fn draw_objects(renderer: &mut sdl2::render::Renderer,
                    gameboy: &Cpu,
                    screen_offset_x: i32,
                    screen_offset_y: i32) {

    // TODO sprites should use palletes
    // TODO sprites can have transparent color
    // TODO sprites are sorted by x/y/idx

    for obj_idx in 0..40+1 {
        let offset = OBJECT_ATTRIBUTE_START + obj_idx * OBJECT_ATTRIBUTE_BLOCK_SIZE;
        let sprite_y: u8 = gameboy.mem[offset as usize];
        let sprite_x: u8 = gameboy.mem[offset as usize + 1];
        let tile_index: u8 = gameboy.mem[offset as usize + 2];
        // TODO implement flag handling (priority, flips...)
        let flags: u8 = gameboy.mem[offset as usize + 3];
        if sprite_x == 0 && sprite_y == 0 {
            // sprite is "hidden"
            continue
        }
        let screen_x = sprite_x.wrapping_sub(8);
        let screen_y = sprite_y.wrapping_sub(16);

        // This table is fixed for OAM
        let pattern_table = TILE_PATTERN_TABLE_1_START;

        if gameboy.lcdc_sprite_size() {
            // "Tall 8x16 sprites" mode
            // FIXME Not sure this is how 8x16 sprites work
            let tile_16 = tile_index & !1;
            draw_tile_transparent(renderer,
                                  gameboy,
                                  pattern_table,
                                  tile_16 as u16,
                                  screen_offset_x + screen_x as i32,
                                  screen_offset_y + screen_y as i32);
            // Draw second sprite below the first one
            draw_tile_transparent(renderer,
                                  gameboy,
                                  pattern_table,
                                  tile_16 as u16 + 1,
                                  screen_offset_x + screen_x as i32,
                                  screen_offset_y + screen_y.wrapping_add(8) as i32);
        } else {
            // 8x8 sprites mode
            draw_tile_transparent(renderer,
                                  gameboy,
                                  pattern_table,
                                  tile_index as u16,
                                  screen_offset_x + screen_x as i32,
                                  screen_offset_y + screen_y as i32);

        }

    }

}
<|endoftext|>


<commit_before>//! Weave parsing

use crate::{header::Header, NamingConvention, Result};
use failure::err_msg;
use flate2::read::GzDecoder;
use log::info;
use std::{
    cell::RefCell,
    fs::File,
    io::{BufRead, BufReader, Lines, Read},
    mem,
    rc::Rc,
};

/// A Sink is a place that a parsed weave can be sent to.  The insert/delete/end commands match
/// those in the weave file, and `plain` are the lines of data.  With each plain is a flag
/// indicating if that line should be included in the output (all lines are called, so that updates
/// can use this same code).  All methods return a result, with the Err value stopping the parse.
/// Note that the default implementations just return success, and ignore the result.
pub trait Sink {
    /// Begin an insert sequence for the given delta.
    fn insert(&mut self, _delta: usize) -> Result<()> {
        Ok(())
    }

    /// Begin a delete sequence.
    fn delete(&mut self, _delta: usize) -> Result<()> {
        Ok(())
    }

    /// End a previous insert or delete.
    fn end(&mut self, _delta: usize) -> Result<()> {
        Ok(())
    }

    /// A single line of plain text from the weave.  `keep` indicates if the line should be
    /// included in the requested delta.
    fn plain(&mut self, _text: &str, _keep: bool) -> Result<()> {
        Ok(())
    }
}

/// The PullParser returns the entries as nodes.  These are equivalent to
/// the values in Sink.
#[derive(Debug)]
pub enum Entry {
    /// Begin an insert sequence for the given delta.
    Insert {
        delta: usize,
    },

    /// Begin a delete sequence.
    Delete {
        delta: usize,
    },

    /// End a previous insert or delete.
    End {
        delta: usize,
    },

    /// A single line of plaintext from the weave.  `keep` indicates if the
    /// line should be included in the requested delta.
    Plain {
        text: String,
        keep: bool,
    },
}

/// A Parser is used to process a weave file, extracting either everything, or only a specific
/// delta.
pub struct Parser<S: Sink, B> {
    /// The lines of the input.
    source: Lines<B>,

    /// The sink to be given each line record in the weave file.
    sink: Rc<RefCell<S>>,

    /// The desired delta to retrieve, which affects the parse_to call as well as the `keep`
    /// argument passed to the sink's `plain` call.
    delta: usize,

    /// The delta state is kept sorted with the newest (largest) delta at element 0.
    delta_state: Vec<OneDelta>,

    /// A pending input line kept from the last invocation.
    pending: Option<String>,

    /// Indicates that we are currently "keeping" lines.
    keeping: bool,

    /// The line number indicator.
    lineno: usize,

    /// The header extracted from the file.
    header: Header,
}

impl<S: Sink> Parser<S, BufReader<Box<dyn Read>>> {
    /// Construct a parser, based on the main file of the naming convention.
    pub fn new(
        naming: &dyn NamingConvention,
        sink: S,
        delta: usize,
    ) -> Result<Parser<S, BufReader<Box<dyn Read>>>> {
        let rd = if naming.is_compressed() {
            let fd = File::open(naming.main_file())?;
            Box::new(GzDecoder::new(fd)) as Box<dyn Read>
        } else {
            Box::new(File::open(naming.main_file())?) as Box<dyn Read>
        };
        let lines = BufReader::new(rd).lines();
        Parser::new_raw(lines, Rc::new(RefCell::new(sink)), delta)
    }
}

impl<S: Sink, B: BufRead> Parser<S, B> {
    /// Construct a new Parser, reading from the given Reader, giving records to the given Sink,
    /// and aiming for the specified `delta`.  This is not the intended constructor, normal users
    /// should use `new`.  (This is public, for testing).
    pub fn new_raw(
        mut source: Lines<B>,
        sink: Rc<RefCell<S>>,
        delta: usize,
    ) -> Result<Parser<S, B>> {
        if let Some(line) = source.next() {
            let line = line?;
            let header = Header::decode(&line)?;

            Ok(Parser {
                source,
                sink,
                delta,
                delta_state: vec![],
                pending: None,
                keeping: false,
                lineno: 0,
                header,
            })
        } else {
            Err(err_msg("Weave file appears empty"))
        }
    }

    /// Run the parser until we either reach the given line number, or the end of the weave.  Lines
    /// are numbered from 1, so calling with a lineno of zero will run the parser until the end of
    /// the input.  Returns Ok(0) for the end of input, Ok(n) for stopping at line n (which should
    /// always be the same as the passed in lineno, or Err if there is an error.
    pub fn parse_to(&mut self, lineno: usize) -> Result<usize> {
        // Handle any pending input line.
        if let Some(pending) = mem::replace(&mut self.pending, None) {
            self.sink.borrow_mut().plain(&pending, self.keeping)?;
        }

        loop {
            // Get the next input line, finishing if we are done.
            let line = match self.source.next() {
                None => return Ok(0),
                Some(line) => line?,
            };

            info!("line: {:?}", line);

            // Detect the first character, without borrowing.
            let textual = match line.bytes().next() {
                None => true,
                Some(ch) if ch != b'\x01' => true,
                _ => false,
            };

            if textual {
                // Textual line.  Count line numbers for the lines we're keeping.
                if self.keeping {
                    self.lineno += 1;
                    if self.lineno == lineno {
                        // This is the desired stopping point, hold onto this line, and return to
                        // the caller.
                        self.pending = Some(line);
                        return Ok(lineno);
                    }
                }

                // Otherwise, call the Sink, and continue.
                info!("textual: keeping={}", self.keeping);
                self.sink.borrow_mut().plain(&line, self.keeping)?;
                continue;
            }

            let linebytes = line.as_bytes();

            // At this point, all should be control lines.  Skip any that are too short.
            if linebytes.len() < 4 {
                continue;
            }

            // Ignore control lines other than the insert/delete/end lines.
            if linebytes[1] != b'I' && linebytes[1] != b'D' && linebytes[1] != b'E' {
                continue;
            }

            let this_delta: usize = line[3..].parse()?;

            match linebytes[1] {
                b'E' => {
                    self.sink.borrow_mut().end(this_delta)?;
                    self.pop(this_delta);
                }
                b'I' => {
                    self.sink.borrow_mut().insert(this_delta)?;

                    // Do this insert if this insert is at least as old as the requested delta.
                    if self.delta >= this_delta {
                        self.push(this_delta, StateMode::Keep);
                    } else {
                        self.push(this_delta, StateMode::Skip);
                    }
                }
                b'D' => {
                    self.sink.borrow_mut().delete(this_delta)?;

                    // Do this delete if this delete is newer than current.  If not, don't account
                    // for it.
                    if self.delta >= this_delta {
                        self.push(this_delta, StateMode::Skip);
                    } else {
                        self.push(this_delta, StateMode::Next);
                    }
                }
                _ => unreachable!(),
            }

            self.update_keep();
        }
    }

    /// Remove the given numbered state.
    fn pop(&mut self, delta: usize) {
        // The binary search is reversed, so the largest are first.
        let pos = match self
            .delta_state
            .binary_search_by(|ent| delta.cmp(&ent.delta))
        {
            Ok(pos) => pos,
            Err(_) => unreachable!(),
        };

        self.delta_state.remove(pos);
    }

    /// Add a new state.  It will be inserted in the proper place in the array, based on the delta
    /// number.
    fn push(&mut self, delta: usize, mode: StateMode) {
        match self
            .delta_state
            .binary_search_by(|ent| delta.cmp(&ent.delta))
        {
            Ok(_) => panic!("Duplicate state in push"),
            Err(pos) => self.delta_state.insert(
                pos,
                OneDelta {
                    delta,
                    mode,
                },
            ),
        }
    }

    /// Update the keep field, based on the current state.
    fn update_keep(&mut self) {
        info!("Update: {:?}", self.delta_state);
        for st in &self.delta_state {
            match st.mode {
                StateMode::Keep => {
                    self.keeping = true;
                    return;
                }
                StateMode::Skip => {
                    self.keeping = false;
                    return;
                }
                _ => (),
            }
        }

        // This shouldn't be reached if there are any more context lines, but we may get here when
        // we reach the end of the input.
        self.keeping = false;
    }

    /// Get the header read from this weave file.
    pub fn get_header(&self) -> &Header {
        &self.header
    }

    /// Consume the parser, returning the header.
    pub fn into_header(self) -> Header {
        self.header
    }

    /// Get a copy of the sink.
    pub fn get_sink(&self) -> Rc<RefCell<S>> {
        self.sink.clone()
    }
}

/*
/// A PullIterator returns entities in a weave file, extracting either
/// everything, or only a specific delta.
pub struct PullIterator<B> {
    /// The lines of the input.
    source: Lines<B>,

    /// The desired delta to retrieve.
    delta: usize,

    /// The delta state is kept sorted with the newest (largest) delta at
    /// element 0.
    delta_state: Vec<OneDelta>,

    /// Indicates we are currently keeping lines.
    keeping: bool,

    /// The current line number.
    lineno: usize,

    /// The header extracted from the file.
    header: Header,
}
*/

pub struct PullParser<B> {
    /// The lines of the input.
    source: Lines<B>,

    /// The desired delta to retrieve.
    delta: usize,

    /// The delta state is kept sorted with the newest (largest) delta at element 0.
    delta_state: Vec<OneDelta>,

    /// Indicates that we are currently "keeping" lines.
    keeping: bool,

    /// The header extracted from the file.
    header: Header,
}

impl<B: BufRead> PullParser<B> {
    /// Construct a new Parser, reading from the given Reader.  The parser
    /// will act as an iterator.  This is the intended constructor, normal
    /// users should use `new`.  (This is public for testing).
    pub fn new_raw(
        mut source: Lines<B>,
        delta: usize,
    ) -> Result<PullParser<B>> {
        if let Some(line) = source.next() {
            let line = line?;
            let header = Header::decode(&line)?;

            Ok(PullParser {
                source,
                delta,
                delta_state: vec![],
                keeping: false,
                header,
            })
        } else {
            Err(err_msg("Weave file appears empty"))
        }
    }

    /// Remove the given numbered state.
    fn pop(&mut self, delta: usize) {
        // The binary search is reversed, so the largest are first.
        let pos = match self
            .delta_state
            .binary_search_by(|ent| delta.cmp(&ent.delta))
        {
            Ok(pos) => pos,
            Err(_) => unreachable!(),
        };

        self.delta_state.remove(pos);
    }

    /// Add a new state.  It will be inserted in the proper place in the array, based on the delta
    /// number.
    fn push(&mut self, delta: usize, mode: StateMode) {
        match self
            .delta_state
            .binary_search_by(|ent| delta.cmp(&ent.delta))
        {
            Ok(_) => panic!("Duplicate state in push"),
            Err(pos) => self.delta_state.insert(
                pos,
                OneDelta {
                    delta,
                    mode,
                },
            ),
        }
    }

    /// Update the keep field, based on the current state.
    fn update_keep(&mut self) {
        info!("Update: {:?}", self.delta_state);
        for st in &self.delta_state {
            match st.mode {
                StateMode::Keep => {
                    self.keeping = true;
                    return;
                }
                StateMode::Skip => {
                    self.keeping = false;
                    return;
                }
                _ => (),
            }
        }

        // This shouldn't be reached if there are any more context lines, but we may get here when
        // we reach the end of the input.
        self.keeping = false;
    }

    /// Get the header read from this weave file.
    pub fn get_header(&self) -> &Header {
        &self.header
    }

    /// Consume the parser, returning the header.
    pub fn into_header(self) -> Header {
        self.header
    }

}

impl<B: BufRead> Iterator for PullParser<B> {
    type Item = Result<Entry>;

    fn next(&mut self) -> Option<Result<Entry>> {
        // At this level, there is a 1:1 correspondence between weave input
        // lines and those returned.
        let line = match self.source.next() {
            None => return None,
            Some(Ok(line)) => line,
            Some(Err(e)) => return Some(Err(From::from(e))),
        };

        info!("line: {:?}", line);

        // Detect the first character, without borrowing.
        let textual = match line.bytes().next() {
            None => true,
            Some(ch) if ch != b'\x01' => true,
            _ => false,
        };

        if textual {
            return Some(Ok(Entry::Plain {
                text: line,
                keep: self.keeping,
            }));
        }

        let linebytes = line.as_bytes();

        if linebytes.len() < 4 {
            panic!("TODO: Handle short control lines");
        }

        if linebytes[1] != b'I' && linebytes[1] != b'D' && linebytes[1] != b'E' {
            panic!("TODO: Handle unrecognized control lines");
        };

        // TODO: Don't panic, but fail.
        let this_delta: usize = line[3..].parse().unwrap();

        match linebytes[1] {
            b'E' => {
                self.pop(this_delta);
                self.update_keep();
                return Some(Ok(Entry::End{ delta: this_delta }));
            }
            b'I' => {
                if self.delta >= this_delta {
                    self.push(this_delta, StateMode::Keep);
                } else {
                    self.push(this_delta, StateMode::Skip);
                }
                self.update_keep();

                return Some(Ok(Entry::Insert{ delta: this_delta }));
            }
            b'D' => {
                if self.delta >= this_delta {
                    self.push(this_delta, StateMode::Skip);
                } else {
                    self.push(this_delta, StateMode::Next);
                }
                self.update_keep();

                return Some(Ok(Entry::Delete{ delta: this_delta }));
            }
            _ => unreachable!(),
        }
    }
}

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
enum StateMode {
    Keep,
    Skip,
    Next,
}

#[derive(Debug)]
struct OneDelta {
    delta: usize,
    mode: StateMode,
}
<commit_msg>weave: Create a constructor for the pull parser<commit_after>//! Weave parsing

use crate::{header::Header, NamingConvention, Result};
use failure::err_msg;
use flate2::read::GzDecoder;
use log::info;
use std::{
    cell::RefCell,
    fs::File,
    io::{BufRead, BufReader, Lines, Read},
    mem,
    rc::Rc,
};

/// A Sink is a place that a parsed weave can be sent to.  The insert/delete/end commands match
/// those in the weave file, and `plain` are the lines of data.  With each plain is a flag
/// indicating if that line should be included in the output (all lines are called, so that updates
/// can use this same code).  All methods return a result, with the Err value stopping the parse.
/// Note that the default implementations just return success, and ignore the result.
pub trait Sink {
    /// Begin an insert sequence for the given delta.
    fn insert(&mut self, _delta: usize) -> Result<()> {
        Ok(())
    }

    /// Begin a delete sequence.
    fn delete(&mut self, _delta: usize) -> Result<()> {
        Ok(())
    }

    /// End a previous insert or delete.
    fn end(&mut self, _delta: usize) -> Result<()> {
        Ok(())
    }

    /// A single line of plain text from the weave.  `keep` indicates if the line should be
    /// included in the requested delta.
    fn plain(&mut self, _text: &str, _keep: bool) -> Result<()> {
        Ok(())
    }
}

/// The PullParser returns the entries as nodes.  These are equivalent to
/// the values in Sink.
#[derive(Debug)]
pub enum Entry {
    /// Begin an insert sequence for the given delta.
    Insert {
        delta: usize,
    },

    /// Begin a delete sequence.
    Delete {
        delta: usize,
    },

    /// End a previous insert or delete.
    End {
        delta: usize,
    },

    /// A single line of plaintext from the weave.  `keep` indicates if the
    /// line should be included in the requested delta.
    Plain {
        text: String,
        keep: bool,
    },
}

/// A Parser is used to process a weave file, extracting either everything, or only a specific
/// delta.
pub struct Parser<S: Sink, B> {
    /// The lines of the input.
    source: Lines<B>,

    /// The sink to be given each line record in the weave file.
    sink: Rc<RefCell<S>>,

    /// The desired delta to retrieve, which affects the parse_to call as well as the `keep`
    /// argument passed to the sink's `plain` call.
    delta: usize,

    /// The delta state is kept sorted with the newest (largest) delta at element 0.
    delta_state: Vec<OneDelta>,

    /// A pending input line kept from the last invocation.
    pending: Option<String>,

    /// Indicates that we are currently "keeping" lines.
    keeping: bool,

    /// The line number indicator.
    lineno: usize,

    /// The header extracted from the file.
    header: Header,
}

impl<S: Sink> Parser<S, BufReader<Box<dyn Read>>> {
    /// Construct a parser, based on the main file of the naming convention.
    pub fn new(
        naming: &dyn NamingConvention,
        sink: S,
        delta: usize,
    ) -> Result<Parser<S, BufReader<Box<dyn Read>>>> {
        let rd = if naming.is_compressed() {
            let fd = File::open(naming.main_file())?;
            Box::new(GzDecoder::new(fd)) as Box<dyn Read>
        } else {
            Box::new(File::open(naming.main_file())?) as Box<dyn Read>
        };
        let lines = BufReader::new(rd).lines();
        Parser::new_raw(lines, Rc::new(RefCell::new(sink)), delta)
    }
}

impl<S: Sink, B: BufRead> Parser<S, B> {
    /// Construct a new Parser, reading from the given Reader, giving records to the given Sink,
    /// and aiming for the specified `delta`.  This is not the intended constructor, normal users
    /// should use `new`.  (This is public, for testing).
    pub fn new_raw(
        mut source: Lines<B>,
        sink: Rc<RefCell<S>>,
        delta: usize,
    ) -> Result<Parser<S, B>> {
        if let Some(line) = source.next() {
            let line = line?;
            let header = Header::decode(&line)?;

            Ok(Parser {
                source,
                sink,
                delta,
                delta_state: vec![],
                pending: None,
                keeping: false,
                lineno: 0,
                header,
            })
        } else {
            Err(err_msg("Weave file appears empty"))
        }
    }

    /// Run the parser until we either reach the given line number, or the end of the weave.  Lines
    /// are numbered from 1, so calling with a lineno of zero will run the parser until the end of
    /// the input.  Returns Ok(0) for the end of input, Ok(n) for stopping at line n (which should
    /// always be the same as the passed in lineno, or Err if there is an error.
    pub fn parse_to(&mut self, lineno: usize) -> Result<usize> {
        // Handle any pending input line.
        if let Some(pending) = mem::replace(&mut self.pending, None) {
            self.sink.borrow_mut().plain(&pending, self.keeping)?;
        }

        loop {
            // Get the next input line, finishing if we are done.
            let line = match self.source.next() {
                None => return Ok(0),
                Some(line) => line?,
            };

            info!("line: {:?}", line);

            // Detect the first character, without borrowing.
            let textual = match line.bytes().next() {
                None => true,
                Some(ch) if ch != b'\x01' => true,
                _ => false,
            };

            if textual {
                // Textual line.  Count line numbers for the lines we're keeping.
                if self.keeping {
                    self.lineno += 1;
                    if self.lineno == lineno {
                        // This is the desired stopping point, hold onto this line, and return to
                        // the caller.
                        self.pending = Some(line);
                        return Ok(lineno);
                    }
                }

                // Otherwise, call the Sink, and continue.
                info!("textual: keeping={}", self.keeping);
                self.sink.borrow_mut().plain(&line, self.keeping)?;
                continue;
            }

            let linebytes = line.as_bytes();

            // At this point, all should be control lines.  Skip any that are too short.
            if linebytes.len() < 4 {
                continue;
            }

            // Ignore control lines other than the insert/delete/end lines.
            if linebytes[1] != b'I' && linebytes[1] != b'D' && linebytes[1] != b'E' {
                continue;
            }

            let this_delta: usize = line[3..].parse()?;

            match linebytes[1] {
                b'E' => {
                    self.sink.borrow_mut().end(this_delta)?;
                    self.pop(this_delta);
                }
                b'I' => {
                    self.sink.borrow_mut().insert(this_delta)?;

                    // Do this insert if this insert is at least as old as the requested delta.
                    if self.delta >= this_delta {
                        self.push(this_delta, StateMode::Keep);
                    } else {
                        self.push(this_delta, StateMode::Skip);
                    }
                }
                b'D' => {
                    self.sink.borrow_mut().delete(this_delta)?;

                    // Do this delete if this delete is newer than current.  If not, don't account
                    // for it.
                    if self.delta >= this_delta {
                        self.push(this_delta, StateMode::Skip);
                    } else {
                        self.push(this_delta, StateMode::Next);
                    }
                }
                _ => unreachable!(),
            }

            self.update_keep();
        }
    }

    /// Remove the given numbered state.
    fn pop(&mut self, delta: usize) {
        // The binary search is reversed, so the largest are first.
        let pos = match self
            .delta_state
            .binary_search_by(|ent| delta.cmp(&ent.delta))
        {
            Ok(pos) => pos,
            Err(_) => unreachable!(),
        };

        self.delta_state.remove(pos);
    }

    /// Add a new state.  It will be inserted in the proper place in the array, based on the delta
    /// number.
    fn push(&mut self, delta: usize, mode: StateMode) {
        match self
            .delta_state
            .binary_search_by(|ent| delta.cmp(&ent.delta))
        {
            Ok(_) => panic!("Duplicate state in push"),
            Err(pos) => self.delta_state.insert(
                pos,
                OneDelta {
                    delta,
                    mode,
                },
            ),
        }
    }

    /// Update the keep field, based on the current state.
    fn update_keep(&mut self) {
        info!("Update: {:?}", self.delta_state);
        for st in &self.delta_state {
            match st.mode {
                StateMode::Keep => {
                    self.keeping = true;
                    return;
                }
                StateMode::Skip => {
                    self.keeping = false;
                    return;
                }
                _ => (),
            }
        }

        // This shouldn't be reached if there are any more context lines, but we may get here when
        // we reach the end of the input.
        self.keeping = false;
    }

    /// Get the header read from this weave file.
    pub fn get_header(&self) -> &Header {
        &self.header
    }

    /// Consume the parser, returning the header.
    pub fn into_header(self) -> Header {
        self.header
    }

    /// Get a copy of the sink.
    pub fn get_sink(&self) -> Rc<RefCell<S>> {
        self.sink.clone()
    }
}

/*
/// A PullIterator returns entities in a weave file, extracting either
/// everything, or only a specific delta.
pub struct PullIterator<B> {
    /// The lines of the input.
    source: Lines<B>,

    /// The desired delta to retrieve.
    delta: usize,

    /// The delta state is kept sorted with the newest (largest) delta at
    /// element 0.
    delta_state: Vec<OneDelta>,

    /// Indicates we are currently keeping lines.
    keeping: bool,

    /// The current line number.
    lineno: usize,

    /// The header extracted from the file.
    header: Header,
}
*/

pub struct PullParser<B> {
    /// The lines of the input.
    source: Lines<B>,

    /// The desired delta to retrieve.
    delta: usize,

    /// The delta state is kept sorted with the newest (largest) delta at element 0.
    delta_state: Vec<OneDelta>,

    /// Indicates that we are currently "keeping" lines.
    keeping: bool,

    /// The header extracted from the file.
    header: Header,
}

impl PullParser<BufReader<Box<dyn Read>>> {
    /// Construct a parser, based on the main file of the naming
    /// convention.
    pub fn new(
        naming: &dyn NamingConvention,
        delta: usize,
    ) -> Result<PullParser<BufReader<Box<dyn Read>>>> {
        let rd = if naming.is_compressed() {
            let fd = File::open(naming.main_file())?;
            Box::new(GzDecoder::new(fd)) as Box<dyn Read>
        } else {
            Box::new(File::open(naming.main_file())?) as Box<dyn Read>
        };
        let lines = BufReader::new(rd).lines();
        PullParser::new_raw(lines, delta)
    }
}

impl<B: BufRead> PullParser<B> {
    /// Construct a new Parser, reading from the given Reader.  The parser
    /// will act as an iterator.  This is the intended constructor, normal
    /// users should use `new`.  (This is public for testing).
    pub fn new_raw(
        mut source: Lines<B>,
        delta: usize,
    ) -> Result<PullParser<B>> {
        if let Some(line) = source.next() {
            let line = line?;
            let header = Header::decode(&line)?;

            Ok(PullParser {
                source,
                delta,
                delta_state: vec![],
                keeping: false,
                header,
            })
        } else {
            Err(err_msg("Weave file appears empty"))
        }
    }

    /// Remove the given numbered state.
    fn pop(&mut self, delta: usize) {
        // The binary search is reversed, so the largest are first.
        let pos = match self
            .delta_state
            .binary_search_by(|ent| delta.cmp(&ent.delta))
        {
            Ok(pos) => pos,
            Err(_) => unreachable!(),
        };

        self.delta_state.remove(pos);
    }

    /// Add a new state.  It will be inserted in the proper place in the array, based on the delta
    /// number.
    fn push(&mut self, delta: usize, mode: StateMode) {
        match self
            .delta_state
            .binary_search_by(|ent| delta.cmp(&ent.delta))
        {
            Ok(_) => panic!("Duplicate state in push"),
            Err(pos) => self.delta_state.insert(
                pos,
                OneDelta {
                    delta,
                    mode,
                },
            ),
        }
    }

    /// Update the keep field, based on the current state.
    fn update_keep(&mut self) {
        info!("Update: {:?}", self.delta_state);
        for st in &self.delta_state {
            match st.mode {
                StateMode::Keep => {
                    self.keeping = true;
                    return;
                }
                StateMode::Skip => {
                    self.keeping = false;
                    return;
                }
                _ => (),
            }
        }

        // This shouldn't be reached if there are any more context lines, but we may get here when
        // we reach the end of the input.
        self.keeping = false;
    }

    /// Get the header read from this weave file.
    pub fn get_header(&self) -> &Header {
        &self.header
    }

    /// Consume the parser, returning the header.
    pub fn into_header(self) -> Header {
        self.header
    }

}

impl<B: BufRead> Iterator for PullParser<B> {
    type Item = Result<Entry>;

    fn next(&mut self) -> Option<Result<Entry>> {
        // At this level, there is a 1:1 correspondence between weave input
        // lines and those returned.
        let line = match self.source.next() {
            None => return None,
            Some(Ok(line)) => line,
            Some(Err(e)) => return Some(Err(From::from(e))),
        };

        info!("line: {:?}", line);

        // Detect the first character, without borrowing.
        let textual = match line.bytes().next() {
            None => true,
            Some(ch) if ch != b'\x01' => true,
            _ => false,
        };

        if textual {
            return Some(Ok(Entry::Plain {
                text: line,
                keep: self.keeping,
            }));
        }

        let linebytes = line.as_bytes();

        if linebytes.len() < 4 {
            panic!("TODO: Handle short control lines");
        }

        if linebytes[1] != b'I' && linebytes[1] != b'D' && linebytes[1] != b'E' {
            panic!("TODO: Handle unrecognized control lines");
        };

        // TODO: Don't panic, but fail.
        let this_delta: usize = line[3..].parse().unwrap();

        match linebytes[1] {
            b'E' => {
                self.pop(this_delta);
                self.update_keep();
                return Some(Ok(Entry::End{ delta: this_delta }));
            }
            b'I' => {
                if self.delta >= this_delta {
                    self.push(this_delta, StateMode::Keep);
                } else {
                    self.push(this_delta, StateMode::Skip);
                }
                self.update_keep();

                return Some(Ok(Entry::Insert{ delta: this_delta }));
            }
            b'D' => {
                if self.delta >= this_delta {
                    self.push(this_delta, StateMode::Skip);
                } else {
                    self.push(this_delta, StateMode::Next);
                }
                self.update_keep();

                return Some(Ok(Entry::Delete{ delta: this_delta }));
            }
            _ => unreachable!(),
        }
    }
}

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
enum StateMode {
    Keep,
    Skip,
    Next,
}

#[derive(Debug)]
struct OneDelta {
    delta: usize,
    mode: StateMode,
}
<|endoftext|>


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

//! Helper functions for implementing `RngCore` functions.
//!
//! For cross-platform reproducibility, these functions all use Little Endian:
//! least-significant part first. For example, `next_u64_via_u32` takes `u32`
//! values `x, y`, then outputs `(y << 32) | x`. To implement `next_u32`
//! from `next_u64` in little-endian order, one should use `next_u64() as u32`.
//!
//! Byte-swapping (like the std `to_le` functions) is only needed to convert
//! to/from byte sequences, and since its purpose is reproducibility,
//! non-reproducible sources (e.g. `OsRng`) need not bother with it.

use core::intrinsics::transmute;
use core::ptr::copy_nonoverlapping;
use core::slice;
use core::cmp::min;
use core::mem::size_of;
use RngCore;

/// Implement `next_u64` via `next_u32`, little-endian order.
pub fn next_u64_via_u32<R: RngCore + ?Sized>(rng: &mut R) -> u64 {
    // Use LE; we explicitly generate one value before the next.
    let x = rng.next_u32() as u64;
    let y = rng.next_u32() as u64;
    (y << 32) | x
}

macro_rules! fill_bytes_via {
    ($rng:ident, $next_u:ident, $BYTES:expr, $dest:ident) => {{
        let mut left = $dest;
        while left.len() >= $BYTES {
            let (l, r) = {left}.split_at_mut($BYTES);
            left = r;
            let chunk: [u8; $BYTES] = unsafe {
                transmute($rng.$next_u().to_le())
            };
            l.copy_from_slice(&chunk);
        }
        let n = left.len();
        if n > 0 {
            let chunk: [u8; $BYTES] = unsafe {
                transmute($rng.$next_u().to_le())
            };
            left.copy_from_slice(&chunk[..n]);
        }
    }}
}

/// Implement `fill_bytes` via `next_u32`, little-endian order.
pub fn fill_bytes_via_u32<R: RngCore + ?Sized>(rng: &mut R, dest: &mut [u8]) {
    fill_bytes_via!(rng, next_u32, 4, dest)
}

/// Implement `fill_bytes` via `next_u64`, little-endian order.
pub fn fill_bytes_via_u64<R: RngCore + ?Sized>(rng: &mut R, dest: &mut [u8]) {
    fill_bytes_via!(rng, next_u64, 8, dest)
}

macro_rules! impl_uint_from_fill {
    ($rng:expr, $ty:ty, $N:expr) => ({
        debug_assert!($N == size_of::<$ty>());

        let mut int: $ty = 0;
        unsafe {
            let ptr = &mut int as *mut $ty as *mut u8;
            let slice = slice::from_raw_parts_mut(ptr, $N);
            $rng.fill_bytes(slice);
        }
        int
    });
}

macro_rules! fill_via_chunks {
    ($src:expr, $dst:expr, $ty:ty, $size:expr) => ({
        let chunk_size_u8 = min($src.len() * $size, $dst.len());
        let chunk_size = (chunk_size_u8 + $size - 1) / $size;
        if cfg!(target_endian="little") {
            unsafe {
                copy_nonoverlapping(
                    $src.as_ptr() as *const u8,
                    $dst.as_mut_ptr(),
                    chunk_size_u8);
            }
        } else {
            for (&n, chunk) in $src.iter().zip($dst.chunks_mut($size)) {
                let tmp = n.to_le();
                let src_ptr = &tmp as *const $ty as *const u8;
                unsafe {
                    copy_nonoverlapping(src_ptr,
                                        chunk.as_mut_ptr(),
                                        chunk.len());
                }
            }
        }

        (chunk_size, chunk_size_u8)
    });
}

/// Implement `fill_bytes` by reading chunks from the output buffer of a block
/// based RNG.
///
/// The return values are `(consumed_u32, filled_u8)`.
///
/// `filled_u8` is the number of filled bytes in `dest`, which may be less than
/// the length of `dest`.
/// `consumed_u32` is the number of words consumed from `src`, which is the same
/// as `filled_u8 / 4` rounded up.
///
/// # Example
/// (from `IsaacRng`)
///
/// ```rust,ignore
/// fn fill_bytes(&mut self, dest: &mut [u8]) {
///     let mut read_len = 0;
///     while read_len < dest.len() {
///         if self.index >= self.rsl.len() {
///             self.isaac();
///         }
///
///         let (consumed_u32, filled_u8) =
///             impls::fill_via_u32_chunks(&mut self.rsl[self.index..],
///                                        &mut dest[read_len..]);
///
///         self.index += consumed_u32;
///         read_len += filled_u8;
///     }
/// }
/// ```
pub fn fill_via_u32_chunks(src: &[u32], dest: &mut [u8]) -> (usize, usize) {
    fill_via_chunks!(src, dest, u32, 4)
}

/// Implement `fill_bytes` by reading chunks from the output buffer of a block
/// based RNG.
///
/// The return values are `(consumed_u64, filled_u8)`.
/// `filled_u8` is the number of filled bytes in `dest`, which may be less than
/// the length of `dest`.
/// `consumed_u64` is the number of words consumed from `src`, which is the same
/// as `filled_u8 / 8` rounded up.
///
/// See `fill_via_u32_chunks` for an example.
pub fn fill_via_u64_chunks(src: &[u64], dest: &mut [u8]) -> (usize, usize) {
    fill_via_chunks!(src, dest, u64, 8)
}

/// Implement `next_u32` via `fill_bytes`, little-endian order.
pub fn next_u32_via_fill<R: RngCore + ?Sized>(rng: &mut R) -> u32 {
    impl_uint_from_fill!(rng, u32, 4)
}

/// Implement `next_u64` via `fill_bytes`, little-endian order.
pub fn next_u64_via_fill<R: RngCore + ?Sized>(rng: &mut R) -> u64 {
    impl_uint_from_fill!(rng, u64, 8)
}

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

//! Helper functions for implementing `RngCore` functions.
//!
//! For cross-platform reproducibility, these functions all use Little Endian:
//! least-significant part first. For example, `next_u64_via_u32` takes `u32`
//! values `x, y`, then outputs `(y << 32) | x`. To implement `next_u32`
//! from `next_u64` in little-endian order, one should use `next_u64() as u32`.
//!
//! Byte-swapping (like the std `to_le` functions) is only needed to convert
//! to/from byte sequences, and since its purpose is reproducibility,
//! non-reproducible sources (e.g. `OsRng`) need not bother with it.

use core::intrinsics::transmute;
use core::ptr::copy_nonoverlapping;
use core::{fmt, slice};
use core::cmp::min;
use core::mem::size_of;
use {RngCore, BlockRngCore, CryptoRng, SeedableRng, Error};

/// Implement `next_u64` via `next_u32`, little-endian order.
pub fn next_u64_via_u32<R: RngCore + ?Sized>(rng: &mut R) -> u64 {
    // Use LE; we explicitly generate one value before the next.
    let x = rng.next_u32() as u64;
    let y = rng.next_u32() as u64;
    (y << 32) | x
}

macro_rules! fill_bytes_via {
    ($rng:ident, $next_u:ident, $BYTES:expr, $dest:ident) => {{
        let mut left = $dest;
        while left.len() >= $BYTES {
            let (l, r) = {left}.split_at_mut($BYTES);
            left = r;
            let chunk: [u8; $BYTES] = unsafe {
                transmute($rng.$next_u().to_le())
            };
            l.copy_from_slice(&chunk);
        }
        let n = left.len();
        if n > 0 {
            let chunk: [u8; $BYTES] = unsafe {
                transmute($rng.$next_u().to_le())
            };
            left.copy_from_slice(&chunk[..n]);
        }
    }}
}

/// Implement `fill_bytes` via `next_u32`, little-endian order.
pub fn fill_bytes_via_u32<R: RngCore + ?Sized>(rng: &mut R, dest: &mut [u8]) {
    fill_bytes_via!(rng, next_u32, 4, dest)
}

/// Implement `fill_bytes` via `next_u64`, little-endian order.
pub fn fill_bytes_via_u64<R: RngCore + ?Sized>(rng: &mut R, dest: &mut [u8]) {
    fill_bytes_via!(rng, next_u64, 8, dest)
}

macro_rules! impl_uint_from_fill {
    ($rng:expr, $ty:ty, $N:expr) => ({
        debug_assert!($N == size_of::<$ty>());

        let mut int: $ty = 0;
        unsafe {
            let ptr = &mut int as *mut $ty as *mut u8;
            let slice = slice::from_raw_parts_mut(ptr, $N);
            $rng.fill_bytes(slice);
        }
        int
    });
}

macro_rules! fill_via_chunks {
    ($src:expr, $dst:expr, $ty:ty, $size:expr) => ({
        let chunk_size_u8 = min($src.len() * $size, $dst.len());
        let chunk_size = (chunk_size_u8 + $size - 1) / $size;
        if cfg!(target_endian="little") {
            unsafe {
                copy_nonoverlapping(
                    $src.as_ptr() as *const u8,
                    $dst.as_mut_ptr(),
                    chunk_size_u8);
            }
        } else {
            for (&n, chunk) in $src.iter().zip($dst.chunks_mut($size)) {
                let tmp = n.to_le();
                let src_ptr = &tmp as *const $ty as *const u8;
                unsafe {
                    copy_nonoverlapping(src_ptr,
                                        chunk.as_mut_ptr(),
                                        chunk.len());
                }
            }
        }

        (chunk_size, chunk_size_u8)
    });
}

/// Implement `fill_bytes` by reading chunks from the output buffer of a block
/// based RNG.
///
/// The return values are `(consumed_u32, filled_u8)`.
///
/// `filled_u8` is the number of filled bytes in `dest`, which may be less than
/// the length of `dest`.
/// `consumed_u32` is the number of words consumed from `src`, which is the same
/// as `filled_u8 / 4` rounded up.
///
/// # Example
/// (from `IsaacRng`)
///
/// ```rust,ignore
/// fn fill_bytes(&mut self, dest: &mut [u8]) {
///     let mut read_len = 0;
///     while read_len < dest.len() {
///         if self.index >= self.rsl.len() {
///             self.isaac();
///         }
///
///         let (consumed_u32, filled_u8) =
///             impls::fill_via_u32_chunks(&mut self.rsl[self.index..],
///                                        &mut dest[read_len..]);
///
///         self.index += consumed_u32;
///         read_len += filled_u8;
///     }
/// }
/// ```
pub fn fill_via_u32_chunks(src: &[u32], dest: &mut [u8]) -> (usize, usize) {
    fill_via_chunks!(src, dest, u32, 4)
}

/// Implement `fill_bytes` by reading chunks from the output buffer of a block
/// based RNG.
///
/// The return values are `(consumed_u64, filled_u8)`.
/// `filled_u8` is the number of filled bytes in `dest`, which may be less than
/// the length of `dest`.
/// `consumed_u64` is the number of words consumed from `src`, which is the same
/// as `filled_u8 / 8` rounded up.
///
/// See `fill_via_u32_chunks` for an example.
pub fn fill_via_u64_chunks(src: &[u64], dest: &mut [u8]) -> (usize, usize) {
    fill_via_chunks!(src, dest, u64, 8)
}

/// Implement `next_u32` via `fill_bytes`, little-endian order.
pub fn next_u32_via_fill<R: RngCore + ?Sized>(rng: &mut R) -> u32 {
    impl_uint_from_fill!(rng, u32, 4)
}

/// Implement `next_u64` via `fill_bytes`, little-endian order.
pub fn next_u64_via_fill<R: RngCore + ?Sized>(rng: &mut R) -> u64 {
    impl_uint_from_fill!(rng, u64, 8)
}

/// Wrapper around PRNGs that implement [`BlockRngCore`] to keep a results
/// buffer and offer the methods from [`RngCore`].
///
/// `BlockRng` has optimized methods to read from the output array that the
/// algorithm of many cryptograpic RNGs generates natively. Also they handle the
/// bookkeeping when to generate a new batch of values.
///
/// `next_u32` simply indexes the array. `next_u64` tries to read two `u32`
/// values at a time if possible, and handles edge cases like when only one
/// value is left. `try_fill_bytes` is optimized to even attempt to use the
/// [`BlockRngCore`] implementation to write the results directly to the
/// destination slice. No generated values are ever thown away.
///
/// Although `BlockCoreRng::generate` can return a `Result`, we assume all PRNGs
/// to be infallible, and for the `Result` to only have a signaling function.
/// Therefore, the error is only reported by `try_fill_bytes`, all other
/// functions squelch the error.
///
/// For easy initialization `BlockRng` also implements [`SeedableRng`].
///
/// [`BlockRngCore`]: ../BlockRngCore.t.html
/// [`RngCore`]: ../RngCore.t.html
/// [`SeedableRng`]: ../SeedableRng.t.html
#[derive(Clone)]
pub struct BlockRng<R: BlockRngCore<u32>> {
    pub core: R,
    pub results: R::Results,
    pub index: usize,
}

// Custom Debug implementation that does not expose the contents of `results`.
impl<R: BlockRngCore<u32>+fmt::Debug> fmt::Debug for BlockRng<R> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("BlockRng")
           .field("core", &self.core)
           .field("result_len", &self.results.as_ref().len())
           .field("index", &self.index)
           .finish()
    }
}

impl<R: BlockRngCore<u32>> RngCore for BlockRng<R> {
    #[inline(always)]
    fn next_u32(&mut self) -> u32 {
        if self.index >= self.results.as_ref().len() {
            let _ = self.core.generate(&mut self.results).unwrap();
            self.index = 0;
        }

        let value = self.results.as_ref()[self.index];
        self.index += 1;
        value
    }

    #[inline(always)]
    fn next_u64(&mut self) -> u64 {
        let len = self.results.as_ref().len();

        let index = self.index;
        if index < len-1 {
            self.index += 2;
            // Read an u64 from the current index
            if cfg!(any(target_arch = "x86", target_arch = "x86_64")) {
                unsafe { *(&self.results.as_ref()[index] as *const u32 as *const u64) }
            } else {
                let x = self.results.as_ref()[index] as u64;
                let y = self.results.as_ref()[index + 1] as u64;
                (y << 32) | x
            }
        } else if index >= len {
            let _ = self.core.generate(&mut self.results);
            self.index = 2;
            let x = self.results.as_ref()[0] as u64;
            let y = self.results.as_ref()[1] as u64;
            (y << 32) | x
        } else {
            let x = self.results.as_ref()[len-1] as u64;
            let _ = self.core.generate(&mut self.results);
            self.index = 1;
            let y = self.results.as_ref()[0] as u64;
            (y << 32) | x
        }
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        let _ = self.try_fill_bytes(dest);
    }

    // As an optimization we try to write directly into the output buffer.
    // This is only enabled for platforms where unaligned writes are known to
    // be safe and fast.
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
        let mut filled = 0;
        let mut res = Ok(());

        // Continue filling from the current set of results
        if self.index < self.results.as_ref().len() {
            let (consumed_u32, filled_u8) =
                fill_via_u32_chunks(&self.results.as_ref()[self.index..],
                                    dest);

            self.index += consumed_u32;
            filled += filled_u8;
        }

        let len_remainder =
            (dest.len() - filled) % (self.results.as_ref().len() * 4);
        let len_direct = dest.len() - len_remainder;

        while filled < len_direct {
            let dest_u32: &mut R::Results = unsafe {
                ::core::mem::transmute(dest[filled..].as_mut_ptr())
            };
            let res2 = self.core.generate(dest_u32);
            if res2.is_err() && res.is_ok() { res = res2 };
            filled += self.results.as_ref().len() * 4;
        }
        self.index = self.results.as_ref().len();

        if len_remainder > 0 {
            let res2 = self.core.generate(&mut self.results);
            if res2.is_err() && res.is_ok() { res = res2 };

            let (consumed_u32, _) =
                fill_via_u32_chunks(&mut self.results.as_ref(),
                                    &mut dest[filled..]);

            self.index = consumed_u32;
        }
        res
    }

    #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
        let mut res = Ok(());
        let mut read_len = 0;
        while read_len < dest.len() {
            if self.index >= self.results.as_ref().len() {
                let res2 = self.core.generate(&mut self.results);
                if res2.is_err() && res.is_ok() { res = res2 };
                self.index = 0;
            }
            let (consumed_u32, filled_u8) =
                fill_via_u32_chunks(&self.results.as_ref()[self.index..],
                                    &mut dest[read_len..]);

            self.index += consumed_u32;
            read_len += filled_u8;
        }
        res
    }
}

impl<R: BlockRngCore<u32> + SeedableRng> SeedableRng for BlockRng<R> {
    type Seed = R::Seed;

    fn from_seed(seed: Self::Seed) -> Self {
        let results_empty = R::Results::default();
        Self {
            core: R::from_seed(seed),
            index: results_empty.as_ref().len(), // generate on first use
            results: results_empty,
        }
    }

    fn from_rng<RNG: RngCore>(rng: &mut RNG) -> Result<Self, Error> {
        let results_empty = R::Results::default();
        Ok(Self {
            core: R::from_rng(rng)?,
            index: results_empty.as_ref().len(), // generate on first use
            results: results_empty,
        })
    }
}

impl<R: BlockRngCore<u32>+CryptoRng> CryptoRng for BlockRng<R> {}

// TODO: implement tests for the above
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate extra;

use std::env;
use std::fs;
use std::io;
use extra::io::fail;
use extra::option::OptionalExt;

fn main() {
    let mut stderr = io::stderr();

    if env::args().count() < 2 {
        fail("no arguments.", &mut stderr);
    }

    for ref path in env::args().skip(1) {
        fs::remove_file(path).try(&mut stderr);
    }
}
<commit_msg>Add man page to rm, -h and --help options.<commit_after>#![deny(warnings)]

extern crate extra;

use std::env;
use std::fs;
use std::io::{stdout, stderr, Write};
use extra::io::fail;
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = /* @MANSTART{rm} */ r#"
NAME
    rm - delete files

SYNOPSIS
    rm [ -h | --help ] FILE...

DESCRIPTION
    The rm utility deletes the file named by the FILE operand. Multiple file names can be passed.

OPTIONS
    --help, -h
        print this message
"#; /* @MANEND */

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();

    if env::args().count() == 2 {
        if let Some(arg) = env::args().nth(1) {
            if arg == "--help" || arg == "-h" {
                stdout.write_all(MAN_PAGE.as_bytes()).try(&mut stderr);
                stdout.flush().try(&mut stderr);
                return;
            }
        }
    }

    if env::args().count() < 2 {
        fail("No arguments. Use --help to see the usage.", &mut stderr);
    }

    for ref path in env::args().skip(1) {
        fs::remove_file(path).try(&mut stderr);
    }
}
<|endoftext|>