<commit_before>extern crate rand;

use types::*;

pub fn new_actions() -> Vec<Action> {
    let actions: Vec<Action> = Vec::new();
    actions
}

pub fn new_game() -> Game {
    let all_tiles = (0..TILES).map(|i| {
        let row = i / COLS;
        let col = i % ROWS;
        if let Some(tile) = Tile::new(row, col) {
            tile
        } else {
            panic!("Attempted to create invalid tile ({},{})", row, col)
        }
        }).collect();
    let (starting_tiles, remaining_tiles) = choose_tiles(all_tiles, PLAYERS);
    let players = new_players(remaining_tiles);
    let slots = initial_slots(starting_tiles);
    Game {
        board: Board { slots: slots },
        players: players,
        turn: PlayerId::One,
        merge_decision: None
    }
}

fn choose_tiles(tiles: Vec<Tile>, count: u8) -> (Vec<Tile>, Vec<Tile>) {
    let mut remaining_tiles = tiles;
    let mut random_tiles = Vec::new();
    for _ in 0..count {
        let random_index = rand::random::<usize>() % remaining_tiles.len();
        random_tiles.push(remaining_tiles.remove(random_index));
    }
    (random_tiles, remaining_tiles)
}

fn new_players(tiles: Vec<Tile>) -> Vec<Player>{
    let init_players: Vec<Player> = Vec::new();
    let (players, _) = (0..PLAYERS)
        .fold( (init_players, tiles), | (mut v, remaining), i | {
            let (player_tiles, new_remaining) = choose_tiles(remaining, 6);
            let player = new_player(PlayerId::new(i+1).unwrap(), player_tiles);
            v.push(player);
            (v, new_remaining)
        });
    players
}

pub fn new_player(id: PlayerId, tiles: Vec<Tile>) -> Player {
    Player { id: id, money: 6000, shares: empty_shares(), tiles: tiles }
}

fn empty_shares() -> PlayerShares {
    PlayerShares { luxor: 0, tower: 0, american: 0, festival: 0, worldwide: 0, continental: 0, imperial: 0 }
}

pub fn initial_slots(starting_tiles: Vec<Tile>) -> Vec<Slot> {
    (0..ROWS).flat_map(|row| -> Vec<Slot> {
        (0..COLS).map(|col| {
            Slot {
                row: row,
                col: col,
                hotel: None,
                has_tile: has_tile_on_slot(&starting_tiles, row, col)
            }
        }).collect()
    }).collect()
}

fn has_tile_on_slot(tiles: & Vec<Tile>, row: u8, col: u8) -> bool {
    tiles.iter().any(|t| t.row() == row && t.col() == col)
}

pub fn compute_state(last_state: &Game, actions: &Vec<Action>) -> Game {
    let mut state = Game {
        board: last_state.board.clone(),
        players: last_state.players.clone(),
        turn: last_state.turn,
        merge_decision: last_state.merge_decision
    };
    for action in actions {
    }
    state
}

pub fn play_turn(game: &Game, action: Action) -> Game {
    match action {
        Action::PlaceTile { player: player, tile: tile } => {
            place_tile(game, player, &tile)
        }
        _ => panic!(format!("I don't know how to play a turn with action {:?}", action))
    }
}

fn place_tile(game: &Game, player: PlayerId, tile: &Tile) -> Game {
    Game {
        board: place_tile_on_board(&game.board, &tile),
        players: game.players.clone(),
        turn: game.turn.clone(),
        merge_decision: game.merge_decision.clone()
    }
}

fn place_tile_on_board(board: &Board, tile: &Tile) -> Board {
    let slots = board.slots
        .iter()
        .map(|s| {
            if s.row == tile.row() && s.col == tile.col() {
                Slot { row: s.row, col: s.col, has_tile: true, hotel: s.hotel.clone() }
            } else {
                s.clone()
            }
        })
        .collect();
    Board { slots: slots }
}

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

    type BoardTiles = [[i32; COLS as usize]; ROWS as usize];
    type PlayerTiles = [[(i32,i32); 6]; PLAYERS as usize];

    #[test]
    fn players_start_with_six_tiles() {
        let game = new_game();
        for player in game.players {
            assert_eq!(player.tiles.len(), 6);
        }
    }

    #[test]
    fn players_start_with_6000_in_cash() {
        let game = new_game();
        for player in game.players {
            assert_eq!(player.money, 6000);
        }
    }

    #[test]
    fn players_start_with_zero_shares() {
        let game = new_game();
        for player in game.players {
            assert_eq!(player.shares.luxor, 0);
            assert_eq!(player.shares.tower, 0);
            assert_eq!(player.shares.american, 0);
            assert_eq!(player.shares.festival, 0);
            assert_eq!(player.shares.worldwide, 0);
            assert_eq!(player.shares.continental, 0);
            assert_eq!(player.shares.imperial, 0);
        }
    }

    #[test]
    fn game_starts_with_four_placed_tiles() {
        let game = new_game();
        let board_tiles = game.board.slots.iter().filter(|s| s.has_tile).count();
        assert_eq!(board_tiles, 4)
    }

    #[test]
    fn placing_a_tile_adds_tile_to_board() {
        let start_tiles = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]];
        let end_tiles =   [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]];
        let player_tiles = [[ (0,0), (0,1), (0,2), (0,3), (0,4), (0,5) ],
                            [ (1,0), (1,1), (1,2), (1,3), (1,4), (1,5) ],
                            [ (2,2), (2,1), (2,2), (2,3), (2,4), (2,5) ],
                            [ (3,3), (3,1), (3,2), (3,3), (3,4), (3,5) ]];
        let game = new_game_with_tiles(start_tiles, player_tiles);
        let tile_to_place = Tile::new(5,11).unwrap();
        let action = Action::PlaceTile { player: PlayerId::One, tile: tile_to_place };
        let game_after = play_turn(&game, action);
        assert_boards_equal(&tiles_to_board(&end_tiles), &game_after.board);
    }

    fn new_game_with_tiles(start_tiles: BoardTiles, player_tiles: PlayerTiles) -> Game {
        let (starting_tiles, remaining) = board_tiles_to_tiles(&start_tiles);
        let players = player_tiles
            .iter()
            .enumerate()
            .map(|(i, tiles)| {
                let _tiles = tiles
                    .iter()
                    .map(|&(r,c)| Tile::new(r as u8, c as u8).unwrap() )
                    .collect();
                new_player(PlayerId::new((i+1) as u8).unwrap(), _tiles)
            })
            .collect();
        let slots = initial_slots(starting_tiles);
        Game {
            board: Board { slots: slots },
            players: players,
            turn: PlayerId::One,
            merge_decision: None
        }
    }

    fn board_tiles_to_tiles(tiles: &BoardTiles) -> (Vec<Tile>, Vec<Tile>) {
        let mut chosen = Vec::new();
        let mut others = Vec::new();
        for row in 0..tiles.len() {
            for col in 0..tiles[0].len() {
                let tile = Tile::new(row as u8, col as u8).unwrap();
                if tiles[row][col] == 1 {
                    chosen.push(tile)
                } else {
                    others.push(tile)
                }
            }
        }
        (chosen, others)
    }

    fn assert_boards_equal(expected: &Board, actual: &Board) {
        let are_equal = expected.slots
            .iter()
            .zip(actual.slots.iter())
            .all(|(left, right)| *left == *right );
        let error_msg = format!("\n\nBoard did not have expected tiles.\n\nExpected tiles:\n{}\n\nActual tiles:\n{}\n\n", print_board(&expected), print_board(&actual));
        assert!(are_equal, error_msg);
    }

    fn tiles_to_board(tiles: &BoardTiles) -> Board {
        let board_tiles = tiles
            .iter()
            .enumerate()
            .flat_map(|(row, row_tiles)| {
                let slots: Vec<Slot> = row_tiles
                    .iter()
                    .enumerate()
                    .map(|(col, val): (usize, &i32)| {
                        let has_tile = *val == 1;
                        Slot { row: row as u8, col: col as u8, has_tile: has_tile, hotel: None }
                    })
                    .collect();
                slots
            }).collect();
        Board { slots: board_tiles }
    }

    fn row_to_char<'a>(row: u8) -> &'a str {
        let mapping = ["A", "B", "C", "D", "E", "F", "G", "H", "I"];
        mapping[row as usize]
    }

    fn print_tile(slot: &Slot) -> String{
        format!("{}{}", row_to_char(slot.row), slot.col + 1)
    }

    fn print_board(board: &Board) -> String {
        let mut string = String::new();
        string.push_str("   1  2  3  4  5  6  7  8  9  10 11 12\n");
        for row in board.slots.chunks(COLS as usize) {
            let row_char = row_to_char(row[0].row);
            string.push_str(&format!("{}  ", row_char));
            for slot in row {
                string.push_str(&format!("{:<2} ", if slot.has_tile { '\u{25FC}' } else { '\u{25FB}' }));
            }
            string.push_str(&format!("{}\n", row_char));
        }
        string.push_str("   1  2  3  4  5  6  7  8  9  10 11 12");
        string
    }
}
<commit_msg>Clone data to make it compile in action handler<commit_after>extern crate rand;

use types::*;

pub fn new_actions() -> Vec<Action> {
    let actions: Vec<Action> = Vec::new();
    actions
}

pub fn new_game() -> Game {
    let all_tiles = (0..TILES).map(|i| {
        let row = i / COLS;
        let col = i % ROWS;
        if let Some(tile) = Tile::new(row, col) {
            tile
        } else {
            panic!("Attempted to create invalid tile ({},{})", row, col)
        }
        }).collect();
    let (starting_tiles, remaining_tiles) = choose_tiles(all_tiles, PLAYERS);
    let players = new_players(remaining_tiles);
    let slots = initial_slots(starting_tiles);
    Game {
        board: Board { slots: slots },
        players: players,
        turn: PlayerId::One,
        merge_decision: None
    }
}

fn choose_tiles(tiles: Vec<Tile>, count: u8) -> (Vec<Tile>, Vec<Tile>) {
    let mut remaining_tiles = tiles;
    let mut random_tiles = Vec::new();
    for _ in 0..count {
        let random_index = rand::random::<usize>() % remaining_tiles.len();
        random_tiles.push(remaining_tiles.remove(random_index));
    }
    (random_tiles, remaining_tiles)
}

fn new_players(tiles: Vec<Tile>) -> Vec<Player>{
    let init_players: Vec<Player> = Vec::new();
    let (players, _) = (0..PLAYERS)
        .fold( (init_players, tiles), | (mut v, remaining), i | {
            let (player_tiles, new_remaining) = choose_tiles(remaining, 6);
            let player = new_player(PlayerId::new(i+1).unwrap(), player_tiles);
            v.push(player);
            (v, new_remaining)
        });
    players
}

pub fn new_player(id: PlayerId, tiles: Vec<Tile>) -> Player {
    Player { id: id, money: 6000, shares: empty_shares(), tiles: tiles }
}

fn empty_shares() -> PlayerShares {
    PlayerShares { luxor: 0, tower: 0, american: 0, festival: 0, worldwide: 0, continental: 0, imperial: 0 }
}

pub fn initial_slots(starting_tiles: Vec<Tile>) -> Vec<Slot> {
    (0..ROWS).flat_map(|row| -> Vec<Slot> {
        (0..COLS).map(|col| {
            Slot {
                row: row,
                col: col,
                hotel: None,
                has_tile: has_tile_on_slot(&starting_tiles, row, col)
            }
        }).collect()
    }).collect()
}

fn has_tile_on_slot(tiles: & Vec<Tile>, row: u8, col: u8) -> bool {
    tiles.iter().any(|t| t.row() == row && t.col() == col)
}

pub fn compute_state(last_state: &Game, actions: &Vec<Action>) -> Game {
    let mut state = Game {
        board: last_state.board.clone(),
        players: last_state.players.clone(),
        turn: last_state.turn.clone(),
        merge_decision: last_state.merge_decision.clone()
    };
    for action in actions {
    }
    state
}

pub fn play_turn(game: &Game, action: Action) -> Game {
    match action {
        Action::PlaceTile { player: player, tile: tile } => {
            place_tile(game, player, &tile)
        }
        _ => panic!(format!("I don't know how to play a turn with action {:?}", action))
    }
}

fn place_tile(game: &Game, player: PlayerId, tile: &Tile) -> Game {
    Game {
        board: place_tile_on_board(&game.board, &tile),
        players: game.players.clone(),
        turn: game.turn.clone(),
        merge_decision: game.merge_decision.clone()
    }
}

fn place_tile_on_board(board: &Board, tile: &Tile) -> Board {
    let slots = board.slots
        .iter()
        .map(|s| {
            if s.row == tile.row() && s.col == tile.col() {
                Slot { row: s.row, col: s.col, has_tile: true, hotel: s.hotel.clone() }
            } else {
                s.clone()
            }
        })
        .collect();
    Board { slots: slots }
}

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

    type BoardTiles = [[i32; COLS as usize]; ROWS as usize];
    type PlayerTiles = [[(i32,i32); 6]; PLAYERS as usize];

    #[test]
    fn players_start_with_six_tiles() {
        let game = new_game();
        for player in game.players {
            assert_eq!(player.tiles.len(), 6);
        }
    }

    #[test]
    fn players_start_with_6000_in_cash() {
        let game = new_game();
        for player in game.players {
            assert_eq!(player.money, 6000);
        }
    }

    #[test]
    fn players_start_with_zero_shares() {
        let game = new_game();
        for player in game.players {
            assert_eq!(player.shares.luxor, 0);
            assert_eq!(player.shares.tower, 0);
            assert_eq!(player.shares.american, 0);
            assert_eq!(player.shares.festival, 0);
            assert_eq!(player.shares.worldwide, 0);
            assert_eq!(player.shares.continental, 0);
            assert_eq!(player.shares.imperial, 0);
        }
    }

    #[test]
    fn game_starts_with_four_placed_tiles() {
        let game = new_game();
        let board_tiles = game.board.slots.iter().filter(|s| s.has_tile).count();
        assert_eq!(board_tiles, 4)
    }

    #[test]
    fn placing_a_tile_adds_tile_to_board() {
        let start_tiles = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]];
        let end_tiles =   [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]];
        let player_tiles = [[ (0,0), (0,1), (0,2), (0,3), (0,4), (0,5) ],
                            [ (1,0), (1,1), (1,2), (1,3), (1,4), (1,5) ],
                            [ (2,2), (2,1), (2,2), (2,3), (2,4), (2,5) ],
                            [ (3,3), (3,1), (3,2), (3,3), (3,4), (3,5) ]];
        let game = new_game_with_tiles(start_tiles, player_tiles);
        let tile_to_place = Tile::new(5,11).unwrap();
        let action = Action::PlaceTile { player: PlayerId::One, tile: tile_to_place };
        let game_after = play_turn(&game, action);
        assert_boards_equal(&tiles_to_board(&end_tiles), &game_after.board);
    }

    fn new_game_with_tiles(start_tiles: BoardTiles, player_tiles: PlayerTiles) -> Game {
        let (starting_tiles, remaining) = board_tiles_to_tiles(&start_tiles);
        let players = player_tiles
            .iter()
            .enumerate()
            .map(|(i, tiles)| {
                let _tiles = tiles
                    .iter()
                    .map(|&(r,c)| Tile::new(r as u8, c as u8).unwrap() )
                    .collect();
                new_player(PlayerId::new((i+1) as u8).unwrap(), _tiles)
            })
            .collect();
        let slots = initial_slots(starting_tiles);
        Game {
            board: Board { slots: slots },
            players: players,
            turn: PlayerId::One,
            merge_decision: None
        }
    }

    fn board_tiles_to_tiles(tiles: &BoardTiles) -> (Vec<Tile>, Vec<Tile>) {
        let mut chosen = Vec::new();
        let mut others = Vec::new();
        for row in 0..tiles.len() {
            for col in 0..tiles[0].len() {
                let tile = Tile::new(row as u8, col as u8).unwrap();
                if tiles[row][col] == 1 {
                    chosen.push(tile)
                } else {
                    others.push(tile)
                }
            }
        }
        (chosen, others)
    }

    fn assert_boards_equal(expected: &Board, actual: &Board) {
        let are_equal = expected.slots
            .iter()
            .zip(actual.slots.iter())
            .all(|(left, right)| *left == *right );
        let error_msg = format!("\n\nBoard did not have expected tiles.\n\nExpected tiles:\n{}\n\nActual tiles:\n{}\n\n", print_board(&expected), print_board(&actual));
        assert!(are_equal, error_msg);
    }

    fn tiles_to_board(tiles: &BoardTiles) -> Board {
        let board_tiles = tiles
            .iter()
            .enumerate()
            .flat_map(|(row, row_tiles)| {
                let slots: Vec<Slot> = row_tiles
                    .iter()
                    .enumerate()
                    .map(|(col, val): (usize, &i32)| {
                        let has_tile = *val == 1;
                        Slot { row: row as u8, col: col as u8, has_tile: has_tile, hotel: None }
                    })
                    .collect();
                slots
            }).collect();
        Board { slots: board_tiles }
    }

    fn row_to_char<'a>(row: u8) -> &'a str {
        let mapping = ["A", "B", "C", "D", "E", "F", "G", "H", "I"];
        mapping[row as usize]
    }

    fn print_tile(slot: &Slot) -> String{
        format!("{}{}", row_to_char(slot.row), slot.col + 1)
    }

    fn print_board(board: &Board) -> String {
        let mut string = String::new();
        string.push_str("   1  2  3  4  5  6  7  8  9  10 11 12\n");
        for row in board.slots.chunks(COLS as usize) {
            let row_char = row_to_char(row[0].row);
            string.push_str(&format!("{}  ", row_char));
            for slot in row {
                string.push_str(&format!("{:<2} ", if slot.has_tile { '\u{25FC}' } else { '\u{25FB}' }));
            }
            string.push_str(&format!("{}\n", row_char));
        }
        string.push_str("   1  2  3  4  5  6  7  8  9  10 11 12");
        string
    }
}
<|endoftext|>


<commit_before>use std::libc;
use std::str::raw;
use std::os::getenv;
use std::path::Path;
use std::libc::c_int;

struct Dataset {
    c_dataset: *(),
}

#[link(name = "gdal")]
extern {
    fn GDALVersionInfo(key: *libc::c_char) -> *libc::c_char;
    fn GDALOpen(pszFilename: *libc::c_char, eAccess: c_int) -> *();
    fn GDALAllRegister();
}
static GA_ReadOnly: c_int = 0;
static GA_Update: c_int = 1;

pub fn version_info(key: &str) -> ~str {
    let info = key.with_c_str(|c_key| {
        return unsafe { raw::from_c_str(GDALVersionInfo(c_key)) };
    });
    return info;
}

pub fn open(path: &Path) -> Option<Dataset> {
    unsafe { GDALAllRegister(); }  // TODO call once
    let filename = path.as_str().unwrap();
    let c_dataset = filename.with_c_str(|c_filename| {
        return unsafe { GDALOpen(c_filename, GA_ReadOnly) };
    });
    return match c_dataset.is_null() {
        true  => None,
        false => Some(Dataset{c_dataset: c_dataset}),
    };
}

#[test]
fn test_version_info() {
    let release_date = version_info("RELEASE_DATE");
    let release_name = version_info("RELEASE_NAME");
    let version_text = version_info("--version");

    let expected_text: ~str = "GDAL " + release_name + ", " +
        "released " + release_date.slice(0, 4) + "/" +
        release_date.slice(4, 6) + "/" + release_date.slice(6, 8);

    assert_eq!(version_text.into_owned(), expected_text);
}

fn fixture_path(name: &str) -> Path {
    let envvar = "RUSTILES_TEST_FIXTURES";
    let fixtures = match getenv(envvar) {
        Some(p) => Path::new(p),
        None => fail!("Environment variable {} not set", envvar)
    };
    let rv = fixtures.join(name);
    return rv;
}

#[test]
fn test_open() {
    let dataset = open(&fixture_path("tinymarble.jpeg"));
    assert!(dataset.is_some());

    let missing_dataset = open(&fixture_path("no_such_file.jpeg"));
    assert!(missing_dataset.is_none());
}
<commit_msg>simplify imports<commit_after>use std::str::raw;
use std::os::getenv;
use std::path::Path;
use std::libc::{c_int, c_char};

struct Dataset {
    c_dataset: *(),
}

#[link(name = "gdal")]
extern {
    fn GDALVersionInfo(key: *c_char) -> *c_char;
    fn GDALOpen(pszFilename: *c_char, eAccess: c_int) -> *();
    fn GDALAllRegister();
}
static GA_ReadOnly: c_int = 0;
static GA_Update: c_int = 1;

pub fn version_info(key: &str) -> ~str {
    let info = key.with_c_str(|c_key| {
        return unsafe { raw::from_c_str(GDALVersionInfo(c_key)) };
    });
    return info;
}

pub fn open(path: &Path) -> Option<Dataset> {
    unsafe { GDALAllRegister(); }  // TODO call once
    let filename = path.as_str().unwrap();
    let c_dataset = filename.with_c_str(|c_filename| {
        return unsafe { GDALOpen(c_filename, GA_ReadOnly) };
    });
    return match c_dataset.is_null() {
        true  => None,
        false => Some(Dataset{c_dataset: c_dataset}),
    };
}

#[test]
fn test_version_info() {
    let release_date = version_info("RELEASE_DATE");
    let release_name = version_info("RELEASE_NAME");
    let version_text = version_info("--version");

    let expected_text: ~str = "GDAL " + release_name + ", " +
        "released " + release_date.slice(0, 4) + "/" +
        release_date.slice(4, 6) + "/" + release_date.slice(6, 8);

    assert_eq!(version_text.into_owned(), expected_text);
}

fn fixture_path(name: &str) -> Path {
    let envvar = "RUSTILES_TEST_FIXTURES";
    let fixtures = match getenv(envvar) {
        Some(p) => Path::new(p),
        None => fail!("Environment variable {} not set", envvar)
    };
    let rv = fixtures.join(name);
    return rv;
}

#[test]
fn test_open() {
    let dataset = open(&fixture_path("tinymarble.jpeg"));
    assert!(dataset.is_some());

    let missing_dataset = open(&fixture_path("no_such_file.jpeg"));
    assert!(missing_dataset.is_none());
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#[macro_use]
extern crate gj;
use gj::{EventLoop, Promise};
use gj::io::{AsyncRead, AsyncWrite, tcp, unix};

#[test]
fn hello() {
    EventLoop::top_level(|wait_scope| {

        let addr = ::std::str::FromStr::from_str("127.0.0.1:10000").unwrap();
        let listener = tcp::Listener::bind(addr).unwrap();

        let _write_promise = listener.accept().lift::<::std::io::Error>().then(move |(_, stream)| {
            stream.write(vec![0,1,2,3,4,5]).lift()
        });

        let read_promise = tcp::Stream::connect(addr).lift::<::std::io::Error>().then(move |stream| {
            stream.read(vec![0u8; 6], 6).lift()
        });

        let (_, buf, _) = read_promise.wait(wait_scope).unwrap();

        assert_eq!(&buf[..], [0,1,2,3,4,5]);
        Ok(())
    }).unwrap();
}

#[test]
fn echo() {
    EventLoop::top_level(|wait_scope| {

        let addr = ::std::str::FromStr::from_str("127.0.0.1:10001").unwrap();
        let listener = tcp::Listener::bind(addr).unwrap();

        let _server_promise = listener.accept().lift::<::std::io::Error>().then(move |(_, stream)| {
            stream.read(vec![0u8; 6], 6).lift().then(move |(stream, mut v, _)| {
                assert_eq!(&v[..], [7,6,5,4,3,2]);
                for x in &mut v {
                    *x += 1;
                }
                stream.write(v).lift()
            })
        });

        let client_promise = tcp::Stream::connect(addr).lift::<::std::io::Error>().then(move |stream| {
            stream.write(vec![7,6,5,4,3,2]).lift().then(move |(stream, v)| {
                stream.read(v, 6).lift()
            })
        });

        let (_, buf, _) = client_promise.wait(wait_scope).unwrap();
        assert_eq!(&buf[..], [8,7,6,5,4,3]);
        Ok(())
    }).unwrap();
}

#[test]
fn deregister_dupped() {
    EventLoop::top_level(|wait_scope| {
        let (stream1, stream2) = try!(unix::Stream::new_pair());
        let stream1_dupped = try!(stream1.try_clone());
        drop(stream1);

        let promise1 = stream1_dupped.read(vec![0u8; 6], 6).then(|(stream, v, _)| {
            Promise::ok(())
        });
        let promise2 = stream2.write(vec![1,2,3,4,5,6]);

        promise1.wait(wait_scope);

        Ok(())
    }).unwrap();
}
<commit_msg>cleanup<commit_after>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#[macro_use]
extern crate gj;
use gj::{EventLoop};
use gj::io::{AsyncRead, AsyncWrite, tcp, unix};

#[test]
fn hello() {
    EventLoop::top_level(|wait_scope| {

        let addr = ::std::str::FromStr::from_str("127.0.0.1:10000").unwrap();
        let listener = tcp::Listener::bind(addr).unwrap();

        let _write_promise = listener.accept().lift::<::std::io::Error>().then(move |(_, stream)| {
            stream.write(vec![0,1,2,3,4,5]).lift()
        });

        let read_promise = tcp::Stream::connect(addr).lift::<::std::io::Error>().then(move |stream| {
            stream.read(vec![0u8; 6], 6).lift()
        });

        let (_, buf, _) = read_promise.wait(wait_scope).unwrap();

        assert_eq!(&buf[..], [0,1,2,3,4,5]);
        Ok(())
    }).unwrap();
}

#[test]
fn echo() {
    EventLoop::top_level(|wait_scope| {

        let addr = ::std::str::FromStr::from_str("127.0.0.1:10001").unwrap();
        let listener = tcp::Listener::bind(addr).unwrap();

        let _server_promise = listener.accept().lift::<::std::io::Error>().then(move |(_, stream)| {
            stream.read(vec![0u8; 6], 6).lift().then(move |(stream, mut v, _)| {
                assert_eq!(&v[..], [7,6,5,4,3,2]);
                for x in &mut v {
                    *x += 1;
                }
                stream.write(v).lift()
            })
        });

        let client_promise = tcp::Stream::connect(addr).lift::<::std::io::Error>().then(move |stream| {
            stream.write(vec![7,6,5,4,3,2]).lift().then(move |(stream, v)| {
                stream.read(v, 6).lift()
            })
        });

        let (_, buf, _) = client_promise.wait(wait_scope).unwrap();
        assert_eq!(&buf[..], [8,7,6,5,4,3]);
        Ok(())
    }).unwrap();
}

#[test]
fn deregister_dupped() {
    // At one point, this panicked on Linux with "invalid handle idx".
    EventLoop::top_level(|wait_scope| {
        let (stream1, stream2) = try!(unix::Stream::new_pair());
        let stream1_dupped = try!(stream1.try_clone());
        drop(stream1);

        let promise1 = stream1_dupped.read(vec![0u8; 6], 6);
        let _promise2 = stream2.write(vec![1,2,3,4,5,6]);

        let _ = promise1.wait(wait_scope);
        Ok(())
    }).unwrap();
}
<|endoftext|>


<commit_before>// Rx -- Reactive programming for Rust
// Copyright 2016 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

extern crate rx;

use rx::{Never, Observable, Observer, Subject};
use std::cell::RefCell;
use std::rc::Rc;

// Generator tests

#[test]
fn never() {
    let mut never = Never::new();
    let _subscription = never.subscribe_error(
        |_x: u8| panic!("never observable should not produce a value"),
        || panic!("never observable should not complete"),
        |_err: ()| panic!("never observable should not fail")
    );

    // Without something like a message loop, the observable cannot suddenly
    // start pushing values, so if it did not produce anything here, it never
    // will.
}

// Option tests

#[test]
fn option_subscribe_next() {
    let mut received = None;

    // Subscribing to `Some` should push the value.
    Some(19).subscribe_next(|x| received = Some(x));
    assert_eq!(Some(19), received);

    None.subscribe_next(|_x: u32| panic!("none should not push a value"));
}

#[test]
fn option_subscribe_completed() {
    let mut received = None;
    let mut completed = false;

    // Subscribing to `Some` should complete after pushing the value.
    Some(19).subscribe_completed(|x| received = Some(x), || completed = true);
    assert_eq!(Some(19), received);
    assert!(completed);

    // Subscribing to `None` should complete without pushing a value.
    completed = false;
    None.subscribe_completed(
        |_x: u32| panic!("none should not push a value"),
        || completed = true
    );
    assert!(completed);
}

#[test]
fn option_subscribe_error() {
    let mut received = None;
    let mut completed = false;

    Some(23).subscribe_error(
        |x| received = Some(x),
        || completed = true,
        |_err| panic!("some observable should not fail")
    );
    assert_eq!(Some(23), received);
    assert!(completed);

    completed = false;
    None.subscribe_error(
        |_x: u32| panic!("none should not push a value"),
        || completed = true,
        |_err| panic!("none observable should not fail")
    );
    assert!(completed);
}

// Result tests

#[test]
fn result_subscribe_next_ok() {
    let mut result: Result<u32, ()> = Ok(13);
    let mut received = None;
    result.subscribe_next(|x| received = Some(x));
    assert_eq!(Some(13), received);
}

#[test]
#[should_panic]
fn result_subscribe_next_err() {
    let mut result: Result<u32, ()> = Err(());
    let mut received = None;

    // This should panic, because we did not provide an error handler.
    result.subscribe_next(|x| received = Some(x));
}

#[test]
fn result_subscribe_completed_ok() {
    let mut result: Result<u32, ()> = Ok(13);
    let mut received = None;
    let mut completed = false;
    result.subscribe_completed(|x| received = Some(x), || completed = true);
    assert_eq!(Some(13), received);
    assert!(completed);
}

#[test]
fn result_subscribe_error_ok() {
    let mut result: Result<u32, ()> = Ok(13);
    let mut received = None;
    let mut completed = false;
    result.subscribe_error(
        |x| received = Some(x),
        || completed = true,
        |_err| panic!("ok result should not be a failing observable")
    );
    assert_eq!(Some(13), received);
    assert!(completed);
}

#[test]
fn result_subscribe_error_err() {
    let mut result: Result<(), u32> = Err(17);
    let mut error = None;
    result.subscribe_error(
        |_x| panic!("err result should not push a value"),
        || panic!("err result should not complete"),
        |err| error = Some(err)
    );
    assert_eq!(Some(17), error);
}

// Slice tests

#[test]
fn slice_subscribe_next() {
    let mut values = &[2u8, 3, 5, 7, 11, 13];
    let mut received = Vec::new();
    values.subscribe_next(|&x| received.push(x));
    assert_eq!(&values[..], &received[..]);
}

#[test]
fn slice_subscribe_completed() {
    let mut values = &[2u8, 3, 5, 7, 11, 13];
    let mut received = Vec::new();
    let mut completed = false;
    values.subscribe_completed(|&x| received.push(x), || completed = true);
    assert_eq!(&values[..], &received[..]);
    assert!(completed);
}

#[test]
fn slice_subscribe_error() {
    let mut values = &[2u8, 3, 5, 7, 11, 13];
    let mut received = Vec::new();
    let mut completed = false;
    let mut failed = false;
    values.subscribe_error(|&x| received.push(x), || completed = true, |_err| failed = true);
    assert_eq!(&values[..], &received[..]);
    assert!(completed);
    assert!(!failed);
}

#[test]
fn slice_subscribe_option() {
    let mut values = &[2u8, 3, 5, 7, 11, 13];
    let expected = &[Some(2u8), Some(3), Some(5), Some(7), Some(11), Some(13), None];
    let mut received = Vec::new();
    values.subscribe_option(|x| received.push(x.cloned()));
    assert_eq!(&received[..], &expected[..]);
}

#[test]
fn slice_subscribe_result() {
    let mut values = &[2u8, 3, 5, 7];
    let expected = &[Ok(Some(2u8)), Ok(Some(3)), Ok(Some(5)), Ok(Some(7)), Ok(None)];
    let mut received = Vec::new();
    values.subscribe_result(|x| received.push(x.map(|y| y.cloned())));
    assert_eq!(&received[..], &expected[..]);
}

// Subject tests

#[test]
fn subject_on_next() {
    let mut subject = Subject::<u8, ()>::new();
    let mut received = Vec::new();
    let _subscription = subject.observable().subscribe_next(|x| received.push(x));

    // Subject should not push anything upon subscription.
    assert_eq!(0, received.len());

    let values = &[2u8, 3, 5, 7, 11, 13];
    for i in 0..values.len() {
        subject.on_next(values[i]);
        assert_eq!(&values[..i + 1], &received[..]);
    }
}

#[test]
fn subject_on_completed() {
    let mut subject = Subject::<u8, ()>::new();
    let mut completed = false;
    let _subscription = subject.observable().subscribe_completed(
        |_x| panic!("no value should be pushed"),
        || completed = true
    );

    // Subject should not push anything upon subscription.
    assert!(!completed);

    subject.on_completed();
    assert!(completed);
}

#[test]
fn subject_on_error() {
    let mut subject = Subject::<u8, u8>::new();
    let mut error = 0;
    let _subscription = subject.observable().subscribe_error(
        |_x| panic!("no value should be pushed"),
        || panic!("subject should not complete"),
        |err| error = err
    );

    // Subject should not fail upon subscription.
    assert_eq!(0, error);

    subject.on_error(41);
    assert_eq!(41, error);
}

/// Helper for the `subject_clones_once_per_observer()` test.
struct CloneCounter {
    counter: Rc<RefCell<u32>>,
}

impl Clone for CloneCounter {
    fn clone(&self) -> CloneCounter {
        let count: u32 = *self.counter.borrow();
        *self.counter.borrow_mut() = count + 1;
        CloneCounter {
            counter: self.counter.clone(),
        }
    }
}

#[test]
fn subject_clones_once_per_observer() {
    let mut subject = Subject::<CloneCounter, ()>::new();
    let mut first_called = false;
    let mut second_called = false;
    let counter = CloneCounter {
        counter: Rc::new(RefCell::new(0)),
    };

    // Subscribe twice.
    let _s1 = subject.observable().subscribe_next(|_x| first_called = true);
    let _s2 = subject.observable().subscribe_next(|_x| second_called = true);

    // Nothing should have been cloned yet.
    assert_eq!(0, *counter.counter.borrow());

    subject.on_next(counter.clone());

    // We cloned once, and the subject should have cloned once per subscription.
    assert_eq!(3, *counter.counter.borrow());
    assert!(first_called);
    assert!(second_called);
}

#[test]
fn subject_drop_subscription() {
    let mut subject = Subject::<u8, ()>::new();
    let mut received = Vec::new();
    let subscription = subject.observable().subscribe_next(|x| received.push(x));

    subject.on_next(2);
    subject.on_next(3);
    subject.on_next(5);

    assert_eq!(&[2u8, 3, 5], &received[..]);

    drop(subscription);

    subject.on_next(7);
    subject.on_next(11);

    // Values pushed after drop should not have been invoked.
    assert_eq!(&[2u8, 3, 5], &received[..]);
}

#[test]
fn subject_drop_subscription_multi() {
    let mut subject = Subject::<u8, ()>::new();
    let mut received = Vec::new();
    let _s1 = subject.observable().subscribe_next(|x| received.push(x));
    let s2 = subject.observable().subscribe_error(
        |_x| panic!("no value should be pushed after dropping subscription"),
        || panic!("completion should not be signalled after dropping subscription"),
        |_err| panic!("failure should not be signalled after dropping subscription")
    );

    drop(s2);

    subject.on_next(2);
    subject.on_next(3);
    subject.on_next(5);
    subject.on_completed();

    assert_eq!(&[2u8, 3, 5], &received[..]);
}

// TODO: Test multiple subscriptions and combinations of values and completed/error.
// TODO: Add better tests for dropping the subject subscription.

// Transform tests

#[test]
fn map() {
    let mut values = &[2u8, 3, 5, 7, 11, 13];
    let expected = &[4u8, 6, 10, 14, 22, 26];
    let mut received = Vec::new();
    let mut mapped = values.map(|x| x * 2);
    mapped.subscribe_next(|x| received.push(x));
    assert_eq!(&expected[..], &received[..]);
}

#[test]
fn map_does_not_change_error() {
    let mut error = None;
    let mut mapped = Err(23_u32).map(|x: u32| format!("{}", x));
    mapped.subscribe_error(
        |_x: String| panic!("mapped error should not produce a value"),
        || panic!("mapped error should not complete"),
        |err| error = Some(err)
    );
    assert_eq!(Some(23), error);
}

#[test]
fn map_error() {
    let mut error = None;
    let mut observable = Err(23_u32);
    let mut mapped = observable.map_error(|x| x * 2);
    mapped.subscribe_error(
        |_x: u32| panic!("mapped error should not produce a value"),
        || panic!("mapped error should not complete"),
        |err| error = Some(err)
    );
    assert_eq!(Some(46), error);
}

#[test]
fn map_error_does_not_change_values() {
    let mut values = &[2u8, 3, 5, 7, 11, 13];
    let mut received = Vec::new();
    let mut mapped = values.map_error(|_unit| 17u8);
    mapped.subscribe_next(|&x| received.push(x));
    assert_eq!(&values[..], &received[..]);
}

#[test]
fn continue_with() {
    let (mut first, mut second) = (&[2u8, 3, 5, 7], &[11u8, 13, 17, 19]);
    let expected = &[2u8, 3, 5, 7, 11, 13, 17, 19];
    let mut received = Vec::new();
    let mut continued = first.continue_with(&mut second);
    continued.subscribe_next(|&x| received.push(x));
    assert_eq!(&expected[..], &received[..]);
}
<commit_msg>Test continue_with() with subjects<commit_after>// Rx -- Reactive programming for Rust
// Copyright 2016 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

extern crate rx;

use rx::{Never, Observable, Observer, Subject};
use std::cell::RefCell;
use std::rc::Rc;

// Generator tests

#[test]
fn never() {
    let mut never = Never::new();
    let _subscription = never.subscribe_error(
        |_x: u8| panic!("never observable should not produce a value"),
        || panic!("never observable should not complete"),
        |_err: ()| panic!("never observable should not fail")
    );

    // Without something like a message loop, the observable cannot suddenly
    // start pushing values, so if it did not produce anything here, it never
    // will.
}

// Option tests

#[test]
fn option_subscribe_next() {
    let mut received = None;

    // Subscribing to `Some` should push the value.
    Some(19).subscribe_next(|x| received = Some(x));
    assert_eq!(Some(19), received);

    None.subscribe_next(|_x: u32| panic!("none should not push a value"));
}

#[test]
fn option_subscribe_completed() {
    let mut received = None;
    let mut completed = false;

    // Subscribing to `Some` should complete after pushing the value.
    Some(19).subscribe_completed(|x| received = Some(x), || completed = true);
    assert_eq!(Some(19), received);
    assert!(completed);

    // Subscribing to `None` should complete without pushing a value.
    completed = false;
    None.subscribe_completed(
        |_x: u32| panic!("none should not push a value"),
        || completed = true
    );
    assert!(completed);
}

#[test]
fn option_subscribe_error() {
    let mut received = None;
    let mut completed = false;

    Some(23).subscribe_error(
        |x| received = Some(x),
        || completed = true,
        |_err| panic!("some observable should not fail")
    );
    assert_eq!(Some(23), received);
    assert!(completed);

    completed = false;
    None.subscribe_error(
        |_x: u32| panic!("none should not push a value"),
        || completed = true,
        |_err| panic!("none observable should not fail")
    );
    assert!(completed);
}

// Result tests

#[test]
fn result_subscribe_next_ok() {
    let mut result: Result<u32, ()> = Ok(13);
    let mut received = None;
    result.subscribe_next(|x| received = Some(x));
    assert_eq!(Some(13), received);
}

#[test]
#[should_panic]
fn result_subscribe_next_err() {
    let mut result: Result<u32, ()> = Err(());
    let mut received = None;

    // This should panic, because we did not provide an error handler.
    result.subscribe_next(|x| received = Some(x));
}

#[test]
fn result_subscribe_completed_ok() {
    let mut result: Result<u32, ()> = Ok(13);
    let mut received = None;
    let mut completed = false;
    result.subscribe_completed(|x| received = Some(x), || completed = true);
    assert_eq!(Some(13), received);
    assert!(completed);
}

#[test]
fn result_subscribe_error_ok() {
    let mut result: Result<u32, ()> = Ok(13);
    let mut received = None;
    let mut completed = false;
    result.subscribe_error(
        |x| received = Some(x),
        || completed = true,
        |_err| panic!("ok result should not be a failing observable")
    );
    assert_eq!(Some(13), received);
    assert!(completed);
}

#[test]
fn result_subscribe_error_err() {
    let mut result: Result<(), u32> = Err(17);
    let mut error = None;
    result.subscribe_error(
        |_x| panic!("err result should not push a value"),
        || panic!("err result should not complete"),
        |err| error = Some(err)
    );
    assert_eq!(Some(17), error);
}

// Slice tests

#[test]
fn slice_subscribe_next() {
    let mut values = &[2u8, 3, 5, 7, 11, 13];
    let mut received = Vec::new();
    values.subscribe_next(|&x| received.push(x));
    assert_eq!(&values[..], &received[..]);
}

#[test]
fn slice_subscribe_completed() {
    let mut values = &[2u8, 3, 5, 7, 11, 13];
    let mut received = Vec::new();
    let mut completed = false;
    values.subscribe_completed(|&x| received.push(x), || completed = true);
    assert_eq!(&values[..], &received[..]);
    assert!(completed);
}

#[test]
fn slice_subscribe_error() {
    let mut values = &[2u8, 3, 5, 7, 11, 13];
    let mut received = Vec::new();
    let mut completed = false;
    let mut failed = false;
    values.subscribe_error(|&x| received.push(x), || completed = true, |_err| failed = true);
    assert_eq!(&values[..], &received[..]);
    assert!(completed);
    assert!(!failed);
}

#[test]
fn slice_subscribe_option() {
    let mut values = &[2u8, 3, 5, 7, 11, 13];
    let expected = &[Some(2u8), Some(3), Some(5), Some(7), Some(11), Some(13), None];
    let mut received = Vec::new();
    values.subscribe_option(|x| received.push(x.cloned()));
    assert_eq!(&received[..], &expected[..]);
}

#[test]
fn slice_subscribe_result() {
    let mut values = &[2u8, 3, 5, 7];
    let expected = &[Ok(Some(2u8)), Ok(Some(3)), Ok(Some(5)), Ok(Some(7)), Ok(None)];
    let mut received = Vec::new();
    values.subscribe_result(|x| received.push(x.map(|y| y.cloned())));
    assert_eq!(&received[..], &expected[..]);
}

// Subject tests

#[test]
fn subject_on_next() {
    let mut subject = Subject::<u8, ()>::new();
    let mut received = Vec::new();
    let _subscription = subject.observable().subscribe_next(|x| received.push(x));

    // Subject should not push anything upon subscription.
    assert_eq!(0, received.len());

    let values = &[2u8, 3, 5, 7, 11, 13];
    for i in 0..values.len() {
        subject.on_next(values[i]);
        assert_eq!(&values[..i + 1], &received[..]);
    }
}

#[test]
fn subject_on_completed() {
    let mut subject = Subject::<u8, ()>::new();
    let mut completed = false;
    let _subscription = subject.observable().subscribe_completed(
        |_x| panic!("no value should be pushed"),
        || completed = true
    );

    // Subject should not push anything upon subscription.
    assert!(!completed);

    subject.on_completed();
    assert!(completed);
}

#[test]
fn subject_on_error() {
    let mut subject = Subject::<u8, u8>::new();
    let mut error = 0;
    let _subscription = subject.observable().subscribe_error(
        |_x| panic!("no value should be pushed"),
        || panic!("subject should not complete"),
        |err| error = err
    );

    // Subject should not fail upon subscription.
    assert_eq!(0, error);

    subject.on_error(41);
    assert_eq!(41, error);
}

/// Helper for the `subject_clones_once_per_observer()` test.
struct CloneCounter {
    counter: Rc<RefCell<u32>>,
}

impl Clone for CloneCounter {
    fn clone(&self) -> CloneCounter {
        let count: u32 = *self.counter.borrow();
        *self.counter.borrow_mut() = count + 1;
        CloneCounter {
            counter: self.counter.clone(),
        }
    }
}

#[test]
fn subject_clones_once_per_observer() {
    let mut subject = Subject::<CloneCounter, ()>::new();
    let mut first_called = false;
    let mut second_called = false;
    let counter = CloneCounter {
        counter: Rc::new(RefCell::new(0)),
    };

    // Subscribe twice.
    let _s1 = subject.observable().subscribe_next(|_x| first_called = true);
    let _s2 = subject.observable().subscribe_next(|_x| second_called = true);

    // Nothing should have been cloned yet.
    assert_eq!(0, *counter.counter.borrow());

    subject.on_next(counter.clone());

    // We cloned once, and the subject should have cloned once per subscription.
    assert_eq!(3, *counter.counter.borrow());
    assert!(first_called);
    assert!(second_called);
}

#[test]
fn subject_drop_subscription() {
    let mut subject = Subject::<u8, ()>::new();
    let mut received = Vec::new();
    let subscription = subject.observable().subscribe_next(|x| received.push(x));

    subject.on_next(2);
    subject.on_next(3);
    subject.on_next(5);

    assert_eq!(&[2u8, 3, 5], &received[..]);

    drop(subscription);

    subject.on_next(7);
    subject.on_next(11);

    // Values pushed after drop should not have been invoked.
    assert_eq!(&[2u8, 3, 5], &received[..]);
}

#[test]
fn subject_drop_subscription_multi() {
    let mut subject = Subject::<u8, ()>::new();
    let mut received = Vec::new();
    let _s1 = subject.observable().subscribe_next(|x| received.push(x));
    let s2 = subject.observable().subscribe_error(
        |_x| panic!("no value should be pushed after dropping subscription"),
        || panic!("completion should not be signalled after dropping subscription"),
        |_err| panic!("failure should not be signalled after dropping subscription")
    );

    drop(s2);

    subject.on_next(2);
    subject.on_next(3);
    subject.on_next(5);
    subject.on_completed();

    assert_eq!(&[2u8, 3, 5], &received[..]);
}

#[test]
fn subject_continue_with() {
    let mut first = Subject::<u8, ()>::new();
    let mut second = Subject::<u8, ()>::new();
    let mut received = Vec::new();
    let mut completed = false;
    let _subscription = {
        let (mut ofirst, mut osecond) = (first.observable(), second.observable());
        let mut continued = ofirst.continue_with(&mut osecond);
            continued.subscribe_completed(
            |x| received.push(x),
            || completed = true,
        )
    };

    first.on_next(2);
    assert_eq!(&[2u8][..], &received[..]);

    // If `second` produces a value, it should not be pushed,
    // because `first` has not yet completed.
    second.on_next(3);
    assert_eq!(&[2u8][..], &received[..]);

    first.on_next(5);
    assert_eq!(&[2u8, 5][..], &received[..]);

    // Completing `first` should not complete the continuation,
    // nor should it push a value.
    first.on_completed();
    assert_eq!(&[2u8, 5][..], &received[..]);
    assert!(!completed);

    // Now pushing to `second` should have an effect, because `first` completed.
    second.on_next(7);
    assert_eq!(&[2u8, 5, 7][..], &received[..]);

    second.on_completed();
    assert!(completed);
}

// TODO: Test multiple subscriptions and combinations of values and completed/error.
// TODO: Add better tests for dropping the subject subscription.

// Transform tests

#[test]
fn map() {
    let mut values = &[2u8, 3, 5, 7, 11, 13];
    let expected = &[4u8, 6, 10, 14, 22, 26];
    let mut received = Vec::new();
    let mut mapped = values.map(|x| x * 2);
    mapped.subscribe_next(|x| received.push(x));
    assert_eq!(&expected[..], &received[..]);
}

#[test]
fn map_does_not_change_error() {
    let mut error = None;
    let mut mapped = Err(23_u32).map(|x: u32| format!("{}", x));
    mapped.subscribe_error(
        |_x: String| panic!("mapped error should not produce a value"),
        || panic!("mapped error should not complete"),
        |err| error = Some(err)
    );
    assert_eq!(Some(23), error);
}

#[test]
fn map_error() {
    let mut error = None;
    let mut observable = Err(23_u32);
    let mut mapped = observable.map_error(|x| x * 2);
    mapped.subscribe_error(
        |_x: u32| panic!("mapped error should not produce a value"),
        || panic!("mapped error should not complete"),
        |err| error = Some(err)
    );
    assert_eq!(Some(46), error);
}

#[test]
fn map_error_does_not_change_values() {
    let mut values = &[2u8, 3, 5, 7, 11, 13];
    let mut received = Vec::new();
    let mut mapped = values.map_error(|_unit| 17u8);
    mapped.subscribe_next(|&x| received.push(x));
    assert_eq!(&values[..], &received[..]);
}

#[test]
fn continue_with() {
    let (mut first, mut second) = (&[2u8, 3, 5, 7], &[11u8, 13, 17, 19]);
    let expected = &[2u8, 3, 5, 7, 11, 13, 17, 19];
    let mut received = Vec::new();
    let mut continued = first.continue_with(&mut second);
    continued.subscribe_next(|&x| received.push(x));
    assert_eq!(&expected[..], &received[..]);
}
<|endoftext|>


<commit_before>use crate::prolog_parser::ast::*;
use crate::prolog_parser::parser::*;
use crate::prolog_parser::tabled_rc::TabledData;

use crate::forms::*;
use crate::iterators::*;
use crate::machine::machine_indices::*;
use crate::machine::machine_state::MachineState;
use crate::machine::streams::Stream;

use std::collections::VecDeque;

type SubtermDeque = VecDeque<(usize, usize)>;

pub type PrologStream = ParsingStream<Stream>;

pub mod readline {
    use crate::machine::streams::Stream;
    use crate::rustyline::error::ReadlineError;
    use crate::rustyline::{Cmd, Editor, KeyPress};
    use std::io::{Cursor, Error, ErrorKind, Read};

    static mut PROMPT: bool = false;

    pub fn set_prompt(value: bool) {
        unsafe {
            PROMPT = value;
        }
    }

    #[inline]
    fn get_prompt() -> &'static str {
        unsafe {
            if PROMPT { "?- " } else { "" }
        }
    }

    #[derive(Debug)]
    pub struct ReadlineStream {
        rl: Editor<()>,
        pending_input: Cursor<String>,
    }

    impl ReadlineStream {
        #[inline]
        pub fn new(pending_input: String) -> Self {
            let mut rl = Editor::<()>::new();
            rl.bind_sequence(KeyPress::Tab, Cmd::Insert(1, "\t".to_string()));
            ReadlineStream { rl, pending_input: Cursor::new(pending_input) }
        }

        #[inline]
        pub fn input_stream(pending_input: String) -> Stream {
            Stream::from(Self::new(pending_input))
        }

        fn call_readline(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
            match self.rl.readline(get_prompt()) {
                Ok(text) => {
                    *self.pending_input.get_mut() = text;
                    self.pending_input.set_position(0);

                    unsafe {
                        if PROMPT {
                            self.rl.history_mut().add(self.pending_input.get_ref());
                            PROMPT = false;
                        }
                    }

                    *self.pending_input.get_mut() += "\n";
                    self.pending_input.read(buf)
                }
                Err(ReadlineError::Eof) => {
                    Ok(0)
                }
                Err(e) => {
                    Err(Error::new(ErrorKind::InvalidInput, e))
                }
            }
        }

        pub fn peek_byte(&mut self) -> std::io::Result<u8> {
            set_prompt(false);

            loop {
                match self.pending_input.get_ref().bytes().next() {
                    Some(b) => {
                        return Ok(b);
                    }
                    None => {
                        match self.call_readline(&mut []) {
                            Err(e) => {
                                return Err(e);
                            }
                            Ok(0) => {
                                return Err(Error::new(
                                    ErrorKind::UnexpectedEof,
                                    "end of file",
                                ));
                            }
                            _ => {
                            }
                        }
                    }
                }
            }
        }

        pub fn peek_char(&mut self) -> std::io::Result<char> {
            set_prompt(false);

            loop {
                match self.pending_input.get_ref().chars().next() {
                    Some(c) => {
                        return Ok(c);
                    }
                    None => {
                        match self.call_readline(&mut []) {
                            Err(e) => {
                                return Err(e);
                            }
                            Ok(0) => {
                                return Err(Error::new(
                                    ErrorKind::UnexpectedEof,
                                    "end of file",
                                ));
                            }
                            _ => {
                            }
                        }
                    }
                }
            }
        }
    }

    impl Read for ReadlineStream {
        fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
            match self.pending_input.read(buf) {
                Ok(0) => {
                    self.call_readline(buf)
                }
                result => {
                    result
                }
            }
        }
    }

    #[inline]
    pub fn input_stream() -> Stream {
        let input_stream = ReadlineStream::input_stream(String::from(""));
        Stream::from(input_stream)
    }
}

impl MachineState {
    pub fn read(
        &mut self,
        inner: &mut PrologStream,
        atom_tbl: TabledData<Atom>,
        op_dir: &OpDir,
    ) -> Result<TermWriteResult, ParserError> {
        let mut parser = Parser::new(inner, atom_tbl, self.flags);
        let term = parser.read_term(composite_op!(op_dir))?;

        Ok(write_term_to_heap(&term, self))
    }
}

#[inline]
pub(crate)
fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> TermWriteResult {
    let term_writer = TermWriter::new(machine_st);
    term_writer.write_term_to_heap(term)
}

#[derive(Debug)]
struct TermWriter<'a> {
    machine_st: &'a mut MachineState,
    queue: SubtermDeque,
    var_dict: HeapVarDict,
}

#[derive(Debug)]
pub struct TermWriteResult {
    pub(crate) heap_loc: usize,
    pub(crate) var_dict: HeapVarDict,
}

impl<'a> TermWriter<'a> {
    #[inline]
    fn new(machine_st: &'a mut MachineState) -> Self {
        TermWriter {
            machine_st,
            queue: SubtermDeque::new(),
            var_dict: HeapVarDict::new(),
        }
    }

    #[inline]
    fn modify_head_of_queue(&mut self, term: &TermRef<'a>, h: usize) {
        if let Some((arity, site_h)) = self.queue.pop_front() {
            self.machine_st.heap[site_h] =
                HeapCellValue::Addr(self.term_as_addr(term, h));

            if arity > 1 {
                self.queue.push_front((arity - 1, site_h + 1));
            }
        }
    }

    #[inline]
    fn push_stub_addr(&mut self) {
        let h = self.machine_st.heap.h();
        self.machine_st.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
    }

    fn term_as_addr(&mut self, term: &TermRef<'a>, h: usize) -> Addr {
        match term {
            &TermRef::AnonVar(_) | &TermRef::Var(..) => {
                Addr::HeapCell(h)
            }
            &TermRef::Cons(..) => {
                Addr::HeapCell(h)
            }
            &TermRef::Constant(_, _, c) => {
                self.machine_st.heap.put_constant(c.clone())
            }
            &TermRef::Clause(..) => {
                Addr::Str(h)
            }
            &TermRef::PartialString(..) => {
                Addr::PStrLocation(h, 0)
            }
        }
    }

    fn write_term_to_heap(mut self, term: &'a Term) -> TermWriteResult {
        let heap_loc = self.machine_st.heap.h();

        for term in breadth_first_iter(term, true) {
            let h = self.machine_st.heap.h();

            match &term {
                &TermRef::Cons(lvl, ..) => {
                    self.queue.push_back((2, h + 1));
                    self.machine_st.heap.push(HeapCellValue::Addr(Addr::Lis(h + 1)));

                    self.push_stub_addr();
                    self.push_stub_addr();

                    if let Level::Root = lvl {
                        continue;
                    }
                }
                &TermRef::Clause(lvl, _, ref ct, subterms) => {
                    self.queue.push_back((subterms.len(), h + 1));
                    let named = HeapCellValue::NamedStr(subterms.len(), ct.name(), ct.spec());

                    self.machine_st.heap.push(named);

                    for _ in 0..subterms.len() {
                        self.push_stub_addr();
                    }

                    if let Level::Root = lvl {
                        continue;
                    }
                }
                &TermRef::AnonVar(Level::Root) | &TermRef::Constant(Level::Root, ..) => {
                    let addr = self.term_as_addr(&term, h);
                    self.machine_st.heap.push(HeapCellValue::Addr(addr));
                }
                &TermRef::Var(Level::Root, _, ref var) => {
                    let addr = self.term_as_addr(&term, h);
                    self.var_dict.insert(var.clone(), Addr::HeapCell(h));
                    self.machine_st.heap.push(HeapCellValue::Addr(addr));
                }
                &TermRef::AnonVar(_) => {
                    if let Some((arity, site_h)) = self.queue.pop_front() {
                        if arity > 1 {
                            self.queue.push_front((arity - 1, site_h + 1));
                        }
                    }

                    continue;
                }
                &TermRef::PartialString(lvl, _, ref pstr, tail) => {
                    if tail.is_some() {
                        self.machine_st.heap.allocate_pstr(&pstr);
                    } else {
                        self.machine_st.heap.put_complete_string(&pstr);
                    }

                    if let Level::Root = lvl {
                    } else if tail.is_some() {
                        let h = self.machine_st.heap.h();
                        self.queue.push_back((1, h - 1));
                    }
                }
                &TermRef::Var(_, _, ref var) => {
                    if let Some((arity, site_h)) = self.queue.pop_front() {
                        if let Some(addr) = self.var_dict.get(var).cloned() {
                            self.machine_st.heap[site_h] = HeapCellValue::Addr(addr);
                        } else {
                            self.var_dict.insert(var.clone(), Addr::HeapCell(site_h));
                        }

                        if arity > 1 {
                            self.queue.push_front((arity - 1, site_h + 1));
                        }
                    }

                    continue;
                }
                _ => {
                }
            };

            self.modify_head_of_queue(&term, h);
        }

        TermWriteResult { heap_loc, var_dict: self.var_dict }
    }
}
<commit_msg>Improved readline<commit_after>use crate::prolog_parser::ast::*;
use crate::prolog_parser::parser::*;
use crate::prolog_parser::tabled_rc::TabledData;

use crate::forms::*;
use crate::iterators::*;
use crate::machine::machine_indices::*;
use crate::machine::machine_state::MachineState;
use crate::machine::streams::Stream;

use std::collections::VecDeque;

type SubtermDeque = VecDeque<(usize, usize)>;

pub type PrologStream = ParsingStream<Stream>;

pub mod readline {
    use crate::machine::streams::Stream;
    use crate::rustyline::error::ReadlineError;
    use crate::rustyline::{Cmd, Editor, KeyPress};
    use std::io::{Cursor, Error, ErrorKind, Read};

    static mut PROMPT: bool = false;

    pub fn set_prompt(value: bool) {
        unsafe {
            PROMPT = value;
        }
    }

    #[inline]
    fn get_prompt() -> &'static str {
        unsafe {
            if PROMPT { "?- " } else { "" }
        }
    }

    #[derive(Debug)]
    pub struct ReadlineStream {
        rl: Editor<()>,
        pending_input: Cursor<String>,
    }

    impl ReadlineStream {
        #[inline]
        pub fn new(pending_input: String) -> Self {
            let mut rl = Editor::<()>::new();
            rl.bind_sequence(KeyPress::Tab, Cmd::Insert(1, "\t".to_string()));
            ReadlineStream { rl, pending_input: Cursor::new(pending_input) }
        }

        #[inline]
        pub fn input_stream(pending_input: String) -> Stream {
            Stream::from(Self::new(pending_input))
        }

        fn call_readline(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
            match self.rl.readline(get_prompt()) {
                Ok(text) => {
                    *self.pending_input.get_mut() = text;
                    self.pending_input.set_position(0);

                    unsafe {
                        if PROMPT {
                            self.rl.history_mut().add(self.pending_input.get_ref());
                            PROMPT = false;
                        }
                    }

                    if self.pending_input.get_ref().chars().last() != Some('\n')
                    {
                        *self.pending_input.get_mut() += "\n";
                    }
                    self.pending_input.read(buf)
                }
                Err(ReadlineError::Eof) => {
                    Ok(0)
                }
                Err(e) => {
                    Err(Error::new(ErrorKind::InvalidInput, e))
                }
            }
        }

        pub fn peek_byte(&mut self) -> std::io::Result<u8> {
            set_prompt(false);

            loop {
                match self.pending_input.get_ref().bytes().next() {
                    Some(b) => {
                        return Ok(b);
                    }
                    None => {
                        match self.call_readline(&mut []) {
                            Err(e) => {
                                return Err(e);
                            }
                            Ok(0) => {
                                return Err(Error::new(
                                    ErrorKind::UnexpectedEof,
                                    "end of file",
                                ));
                            }
                            _ => {
                            }
                        }
                    }
                }
            }
        }

        pub fn peek_char(&mut self) -> std::io::Result<char> {
            set_prompt(false);

            loop {
                match self.pending_input.get_ref().chars().next() {
                    Some(c) => {
                        return Ok(c);
                    }
                    None => {
                        match self.call_readline(&mut []) {
                            Err(e) => {
                                return Err(e);
                            }
                            Ok(0) => {
                                return Err(Error::new(
                                    ErrorKind::UnexpectedEof,
                                    "end of file",
                                ));
                            }
                            _ => {
                            }
                        }
                    }
                }
            }
        }
    }

    impl Read for ReadlineStream {
        fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
            match self.pending_input.read(buf) {
                Ok(0) => {
                    self.call_readline(buf)
                }
                result => {
                    result
                }
            }
        }
    }

    #[inline]
    pub fn input_stream() -> Stream {
        let input_stream = ReadlineStream::input_stream(String::from(""));
        Stream::from(input_stream)
    }
}

impl MachineState {
    pub fn read(
        &mut self,
        inner: &mut PrologStream,
        atom_tbl: TabledData<Atom>,
        op_dir: &OpDir,
    ) -> Result<TermWriteResult, ParserError> {
        let mut parser = Parser::new(inner, atom_tbl, self.flags);
        let term = parser.read_term(composite_op!(op_dir))?;

        Ok(write_term_to_heap(&term, self))
    }
}

#[inline]
pub(crate)
fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> TermWriteResult {
    let term_writer = TermWriter::new(machine_st);
    term_writer.write_term_to_heap(term)
}

#[derive(Debug)]
struct TermWriter<'a> {
    machine_st: &'a mut MachineState,
    queue: SubtermDeque,
    var_dict: HeapVarDict,
}

#[derive(Debug)]
pub struct TermWriteResult {
    pub(crate) heap_loc: usize,
    pub(crate) var_dict: HeapVarDict,
}

impl<'a> TermWriter<'a> {
    #[inline]
    fn new(machine_st: &'a mut MachineState) -> Self {
        TermWriter {
            machine_st,
            queue: SubtermDeque::new(),
            var_dict: HeapVarDict::new(),
        }
    }

    #[inline]
    fn modify_head_of_queue(&mut self, term: &TermRef<'a>, h: usize) {
        if let Some((arity, site_h)) = self.queue.pop_front() {
            self.machine_st.heap[site_h] =
                HeapCellValue::Addr(self.term_as_addr(term, h));

            if arity > 1 {
                self.queue.push_front((arity - 1, site_h + 1));
            }
        }
    }

    #[inline]
    fn push_stub_addr(&mut self) {
        let h = self.machine_st.heap.h();
        self.machine_st.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
    }

    fn term_as_addr(&mut self, term: &TermRef<'a>, h: usize) -> Addr {
        match term {
            &TermRef::AnonVar(_) | &TermRef::Var(..) => {
                Addr::HeapCell(h)
            }
            &TermRef::Cons(..) => {
                Addr::HeapCell(h)
            }
            &TermRef::Constant(_, _, c) => {
                self.machine_st.heap.put_constant(c.clone())
            }
            &TermRef::Clause(..) => {
                Addr::Str(h)
            }
            &TermRef::PartialString(..) => {
                Addr::PStrLocation(h, 0)
            }
        }
    }

    fn write_term_to_heap(mut self, term: &'a Term) -> TermWriteResult {
        let heap_loc = self.machine_st.heap.h();

        for term in breadth_first_iter(term, true) {
            let h = self.machine_st.heap.h();

            match &term {
                &TermRef::Cons(lvl, ..) => {
                    self.queue.push_back((2, h + 1));
                    self.machine_st.heap.push(HeapCellValue::Addr(Addr::Lis(h + 1)));

                    self.push_stub_addr();
                    self.push_stub_addr();

                    if let Level::Root = lvl {
                        continue;
                    }
                }
                &TermRef::Clause(lvl, _, ref ct, subterms) => {
                    self.queue.push_back((subterms.len(), h + 1));
                    let named = HeapCellValue::NamedStr(subterms.len(), ct.name(), ct.spec());

                    self.machine_st.heap.push(named);

                    for _ in 0..subterms.len() {
                        self.push_stub_addr();
                    }

                    if let Level::Root = lvl {
                        continue;
                    }
                }
                &TermRef::AnonVar(Level::Root) | &TermRef::Constant(Level::Root, ..) => {
                    let addr = self.term_as_addr(&term, h);
                    self.machine_st.heap.push(HeapCellValue::Addr(addr));
                }
                &TermRef::Var(Level::Root, _, ref var) => {
                    let addr = self.term_as_addr(&term, h);
                    self.var_dict.insert(var.clone(), Addr::HeapCell(h));
                    self.machine_st.heap.push(HeapCellValue::Addr(addr));
                }
                &TermRef::AnonVar(_) => {
                    if let Some((arity, site_h)) = self.queue.pop_front() {
                        if arity > 1 {
                            self.queue.push_front((arity - 1, site_h + 1));
                        }
                    }

                    continue;
                }
                &TermRef::PartialString(lvl, _, ref pstr, tail) => {
                    if tail.is_some() {
                        self.machine_st.heap.allocate_pstr(&pstr);
                    } else {
                        self.machine_st.heap.put_complete_string(&pstr);
                    }

                    if let Level::Root = lvl {
                    } else if tail.is_some() {
                        let h = self.machine_st.heap.h();
                        self.queue.push_back((1, h - 1));
                    }
                }
                &TermRef::Var(_, _, ref var) => {
                    if let Some((arity, site_h)) = self.queue.pop_front() {
                        if let Some(addr) = self.var_dict.get(var).cloned() {
                            self.machine_st.heap[site_h] = HeapCellValue::Addr(addr);
                        } else {
                            self.var_dict.insert(var.clone(), Addr::HeapCell(site_h));
                        }

                        if arity > 1 {
                            self.queue.push_front((arity - 1, site_h + 1));
                        }
                    }

                    continue;
                }
                _ => {
                }
            };

            self.modify_head_of_queue(&term, h);
        }

        TermWriteResult { heap_loc, var_dict: self.var_dict }
    }
}
<|endoftext|>


<commit_before>//! This module implements the todr REPL logic.

use dirs;
use rustyline::error::ReadlineError;
use rustyline::Editor;
use std::path::Path;

// Use our internal handlers module.
use completer::CustomCompletion;
use handlers;

// On unix platforms you can use ANSI escape sequences
#[cfg(unix)]
static PROMPT: &'static str = "\x1b[1;32m>>\x1b[0m ";

// Windows consoles typically don't support ANSI escape sequences out
// of the box
#[cfg(windows)]
static PROMPT: &'static str = ">> ";

// The default history file name.
static DEFAULT_HISTORY_FILE: &'static str = ".todr_history";

#[derive(Debug)]
pub struct Todr {
    /// The repl's readline editor.
    readline_editor: Editor<CustomCompletion>,

    // The configured history file.
    history_file: String,

    /// Flag that marks if we should exit or not.
    should_exit: bool,
}

impl Todr {
    /// Factory method.
    pub fn new() -> Self {
        let home = dirs::home_dir().expect("Home Dir couldn't be found");
        let history_file = Path::new(&home)
            .join(DEFAULT_HISTORY_FILE)
            .to_string_lossy()
            .to_string();

        let mut editor = Editor::<CustomCompletion>::new();

        let completer = CustomCompletion::new();
        editor.set_helper(Some(completer));

        Self {
            // `()` can be used when no completer is required
            readline_editor: editor,
            history_file,
            should_exit: false,
        }
    }

    /// Executes the main process loop.
    pub fn process_command_loop(&mut self) {
        if self
            .readline_editor
            .load_history(&self.history_file)
            .is_err()
        {
            println!("No previous history to load...");
        }

        loop {
            // Handle graceful exit request.
            if self.should_exit {
                break;
            }

            let readline = self.readline_editor.readline(PROMPT);
            match readline {
                Ok(line) => {
                    self.process_line(&line);
                }
                Err(ReadlineError::Interrupted) => {
                    println!("CTRL-C");
                    break;
                }
                Err(ReadlineError::Eof) => {
                    println!("CTRL-D");
                    break;
                }
                Err(err) => {
                    println!("Error: {:?}", err);
                    break;
                }
            }
        }

        self.readline_editor
            .save_history(&self.history_file)
            .expect("Failed to save repl history file");
    }

    /// Processes a single line for a command.
    fn process_line(&mut self, line: &str) {
        self.readline_editor.add_history_entry(line);

        match line {
            // Handle printing help message.
            "help" | "h" => handlers::help_command(),

            // Handle executing the items commands.
            "items" | "i" => handlers::items_command(),

            // Handle executing the items commands.
            "projs" | "p" => handlers::projects_command(),

            // Handle graceful exit.
            "quit" | "q" => self.should_exit = true,

            // Handle unknown commands.
            _ => handlers::unknown_command(line),
        }
    }
}
<commit_msg>Repl: Stop printing message when no repl history is available.<commit_after>//! This module implements the todr REPL logic.

use dirs;
use rustyline::error::ReadlineError;
use rustyline::Editor;
use std::path::Path;

// Use our internal handlers module.
use completer::CustomCompletion;
use handlers;

// On unix platforms you can use ANSI escape sequences
#[cfg(unix)]
static PROMPT: &'static str = "\x1b[1;32m>>\x1b[0m ";

// Windows consoles typically don't support ANSI escape sequences out
// of the box
#[cfg(windows)]
static PROMPT: &'static str = ">> ";

// The default history file name.
static DEFAULT_HISTORY_FILE: &'static str = ".todr_history";

#[derive(Debug)]
pub struct Todr {
    /// The repl's readline editor.
    readline_editor: Editor<CustomCompletion>,

    // The configured history file.
    history_file: String,

    /// Flag that marks if we should exit or not.
    should_exit: bool,
}

impl Todr {
    /// Factory method.
    pub fn new() -> Self {
        let home = dirs::home_dir().expect("Home Dir couldn't be found");
        let history_file = Path::new(&home)
            .join(DEFAULT_HISTORY_FILE)
            .to_string_lossy()
            .to_string();

        let mut editor = Editor::<CustomCompletion>::new();

        let completer = CustomCompletion::new();
        editor.set_helper(Some(completer));

        Self {
            // `()` can be used when no completer is required
            readline_editor: editor,
            history_file,
            should_exit: false,
        }
    }

    /// Executes the main process loop.
    pub fn process_command_loop(&mut self) {

        // If loading failed, that's fine, just ignore it.
        let _ = self .readline_editor
                    .load_history(&self.history_file);

        loop {
            // Handle graceful exit request.
            if self.should_exit {
                break;
            }

            let readline = self.readline_editor.readline(PROMPT);
            match readline {
                Ok(line) => {
                    self.process_line(&line);
                }
                Err(ReadlineError::Interrupted) => {
                    println!("CTRL-C");
                    break;
                }
                Err(ReadlineError::Eof) => {
                    println!("CTRL-D");
                    break;
                }
                Err(err) => {
                    println!("Error: {:?}", err);
                    break;
                }
            }
        }

        self.readline_editor
            .save_history(&self.history_file)
            .expect("Failed to save repl history file");
    }

    /// Processes a single line for a command.
    fn process_line(&mut self, line: &str) {
        self.readline_editor.add_history_entry(line);

        match line {
            // Handle printing help message.
            "help" | "h" => handlers::help_command(),

            // Handle executing the items commands.
            "items" | "i" => handlers::items_command(),

            // Handle executing the items commands.
            "projs" | "p" => handlers::projects_command(),

            // Handle graceful exit.
            "quit" | "q" => self.should_exit = true,

            // Handle unknown commands.
            _ => handlers::unknown_command(line),
        }
    }
}
<|endoftext|>


<commit_before>/*!

Suffix Array Construction

worst time: O(N)
worst space: N bytes (for input) + N words (for suffix array)

# Credit
Ge Nong and the team:
https://code.google.com/p/ge-nong/

*/

use std::{iter, vec};
use compress::bwt;

pub type Symbol = u8;
pub type Suffix = uint;

/// main entry point for SAC
pub fn construct_suffix_array(input: &[Symbol], suffixes: &mut [Suffix]) {
	assert_eq!(input.len(), suffixes.len());
	for (i,p) in suffixes.mut_iter().enumerate() {
		*p = i as Suffix;
	}

	suffixes.sort_by(|&a,&b| {
		iter::order::cmp(
			input.slice_from(a).iter(),
			input.slice_from(b).iter())
	});

	debug!("construct suf: {:?}", suffixes);
}

/// An iterator over BWT output
pub struct LastColumnIterator<'a> {
	priv input		: &'a [Symbol],
	priv suf_iter	: iter::Enumerate<vec::Items<'a,Suffix>>,
	priv origin		: Option<uint>,
}

impl<'a> LastColumnIterator<'a> {
	/// create a new BWT iterator from the suffix array
	pub fn new(input: &'a [Symbol], suffixes: &'a [Suffix]) -> LastColumnIterator<'a> {
		LastColumnIterator {
			input: input,
			suf_iter: suffixes.iter().enumerate(),
			origin: None,
		}
	}

	/// return the index of the original string
	pub fn get_origin(&self) -> uint {
		self.origin.unwrap()
	}
}

impl<'a> Iterator<Symbol> for LastColumnIterator<'a> {
	fn next(&mut self) -> Option<Symbol> {
		self.suf_iter.next().map(|(i,&p)| {
			if p == 0 {
				assert!( self.origin.is_none() );
				self.origin = Some(i);
				*self.input.last().unwrap()
			}else {
				self.input[p-1]
			}
		})
	}
}

/// A helper method to perform BWT on a given block and place the result into output
/// returns the original string index in the sorted matrix
pub fn BW_transform(input: &[Symbol], suf: &mut [Suffix], output: &mut [Symbol]) -> uint {
	construct_suffix_array(input, suf);
	let mut iter = LastColumnIterator::new(input, suf);
	for (out,s) in output.mut_iter().zip(iter.by_ref()) {
		*out = s;
	}
	iter.get_origin()
}

/// An iterator over inverse BWT
pub struct InverseIterator<'a> {
	priv input		: &'a [Symbol],
	priv suffixes	: &'a [Suffix],
	priv origin		: Suffix,
	priv current	: Suffix,
}

impl<'a> InverseIterator<'a> {
	/// create a new inverse BWT iterator
	pub fn new(input: &'a [Symbol], origin: uint, suffixes: &'a mut [Suffix]) -> InverseIterator<'a> {
		assert_eq!(input.len(), suffixes.len())
		debug!("decode origin={}, input: {:?}", origin, input)

		let mut radix = bwt::Radix::new();
		radix.gather(input);
		radix.accumulate();

		suffixes[radix.place(input[origin])] = 0;
		for (i,&ch) in input.slice_to(origin).iter().enumerate() {
			suffixes[radix.place(ch)] = i+1;
		}
		for (i,&ch) in input.slice_from(origin+1).iter().enumerate() {
			suffixes[radix.place(ch)] = origin+2+i;
		}
		//suffixes[-1] = origin;
		debug!("decode table: {:?}", suffixes)

		InverseIterator {
			input: input,
			suffixes: suffixes,
			origin: origin,
			current: origin as Suffix,
		}
	}
}

impl<'a> Iterator<Symbol> for InverseIterator<'a> {
	fn next(&mut self) -> Option<Symbol> {
		if self.current == -1 {
			None
		}else {
			self.current = self.suffixes[self.current] - 1;
			debug!("\tjumped to {}", self.current);
			let p = if self.current!=-1 {self.current} else {self.origin};
			Some(self.input[p])
		}
	}
}

#[cfg(test)]
pub mod test {
	use std::vec;
	use super::{Suffix, Symbol};

	#[test]
	fn some() {
		let input = bytes!("abracadabra");
		let mut suf = vec::from_elem(input.len(), 0 as Suffix);
		super::construct_suffix_array(input, suf);
		assert_eq!(suf.as_slice(), &[10,7,0,3,5,8,1,4,6,9,2]);
		let (output, origin) = {
			let mut iter = super::LastColumnIterator::new(input,suf);
			let out = iter.by_ref().take(input.len()).to_owned_vec();
			(out, iter.get_origin())
		};
		assert_eq!(origin, 2);
		let expected = bytes!("rdarcaaaabb");
		assert_eq!(output.as_slice(), expected.as_slice());
		let decoded = super::InverseIterator::new(output, origin, suf).to_owned_vec();
		assert_eq!(input.as_slice(), decoded.as_slice());
	}

	#[test]
	fn roundtrip() {
		let input = include_bin!("../LICENSE");
		let mut suf = vec::from_elem(input.len(), 0 as Suffix);
		let mut output = vec::from_elem(input.len(), 0 as Symbol);
		let origin = super::BW_transform(input, suf, output);
		let decoded = super::InverseIterator::new(output, origin, suf).
			take(input.len()).to_owned_vec();
		assert_eq!(input.as_slice(), decoded.as_slice());
	}
}
<commit_msg>A skeleton for SACA is implemented.<commit_after>/*!

Suffix Array Construction

worst time: O(N)
worst space: N bytes (for input) + N words (for suffix array)

# Credit
Ge Nong and the team:
https://code.google.com/p/ge-nong/

*/

use std::{iter, vec};
use compress::bwt;

pub type Symbol = u8;
pub type Suffix = uint;

static EMPTY: Suffix = 0x7FFFFFFF;

fn get_buckets(input: &[Symbol], buckets: &mut [uint], end: bool) {
	for buck in buckets.mut_iter() {
		*buck = 0;
	}
	for sym in input.iter() {
		buckets[*sym] += 1;
	}
	let mut sum = 0u;
	for buck in buckets.mut_iter() {
		sum += *buck;
		*buck = if end {sum} else {sum - *buck};
	}
}

fn put_substr0(_suffixes: &mut [Suffix], input: &[Symbol], buckets: &mut [uint]) {
	// Find the end of each bucket.
	get_buckets(input, buckets, true);

	//TODO
}

fn induce_l0(_suffixes: &mut [Suffix], _input: &[Symbol], _buckets: &mut [uint], _clean: bool) {
	//TODO
}

fn induce_s0(_suffixes: &mut [Suffix], _input: &[Symbol], _buckets: &mut [uint], _clean: bool) {
	//TODO
}

fn gather_lms(suffixes: &mut [Suffix], input: &[Suffix]) {
	//TODO

	for suf in suffixes.mut_iter() {
		*suf = input[*suf];
	}
}

fn put_suffix0(suffixes: &mut [Suffix], n1: uint, input: &[Symbol], buckets: &mut [uint]) {
	// Find the end of each bucket.
	get_buckets(input, buckets, true);

	for i in range(0,n1).rev() {
		let p = suffixes[i];
		suffixes[i] = 0;
		let sym = input[p];
		buckets[sym] -= 1;
		suffixes[buckets[sym]] = p;
	}

	// Set the single sentinel suffix.
	suffixes[0] = input.len()-1;
}

fn name_substr(_suffixes: &mut [Suffix], _input: &[Symbol], _new_input: &[Suffix], _level: uint) -> uint {
	0 //TODO
}

fn saca_kn(input: &[Suffix], suffixes: &mut [Suffix], _level: uint) {
	//TODO

	let n1 = 0u;

	assert!(n1+n1 <= input.len());
	let (sa_new, input_new) = suffixes.mut_split_at(n1);
	//TODO

	// Stage 3: induce SA(S) from SA(S1).
	gather_lms(sa_new, input_new);
	for s in input_new.mut_iter() {
		*s = EMPTY;
	}

	//TODO
}

fn saca_k0(input: &[Symbol], K: uint, suffixes: &mut [Suffix]) {
	let mut buckets = vec::from_elem(K, 0u);

	// Stage 1: reduce the problem by at least 1/2.
	put_substr0(suffixes, input, buckets.as_mut_slice());
	induce_l0(suffixes, input, buckets.as_mut_slice(), false);
	induce_s0(suffixes, input, buckets.as_mut_slice(), false);

	// Now, all the LMS-substrings are sorted and stored sparsely in SA.
	// Compact all the sorted substrings into the first n1 items of SA.
	let mut n1 = 0u;
	for i in range(0, suffixes.len()) {
		if suffixes[i]>0 {
			suffixes[n1] = suffixes[i];
			n1 += 1;
		}
	}

	// Stage 2: solve the reduced problem.
	{
		assert!(n1+n1 <= input.len());
		let (sa_new, input_new) = suffixes.mut_split_at(n1);
		let num_names = name_substr(sa_new, input, input_new, 0);

		if num_names < n1 {
			// Recurse if names are not yet unique.
			saca_kn(input_new, sa_new, 1);
		}else {
			// Get the suffix array of s1 directly.
			for (i,&sym) in input_new.iter().enumerate() {
				sa_new[sym] = i;
			}
		}

		// Stage 3: induce SA(S) from SA(S1).
		gather_lms(sa_new, input_new);
		for s in input_new.mut_iter() {
			*s = 0;
		}
	}

	put_suffix0(suffixes, n1, input, buckets.as_mut_slice());
	induce_l0(suffixes, input, buckets.as_mut_slice(), true);
	induce_s0(suffixes, input, buckets.as_mut_slice(), true);
}

/// main entry point for SAC
pub fn construct_suffix_array(input: &[Symbol], suffixes: &mut [Suffix]) {
	assert_eq!(input.len(), suffixes.len());
	for (i,p) in suffixes.mut_iter().enumerate() {
		*p = i as Suffix;
	}

	if true {
		saca_k0(input, 0x100, suffixes);
	}else {
		suffixes.sort_by(|&a,&b| {
			iter::order::cmp(
				input.slice_from(a).iter(),
				input.slice_from(b).iter())
		});
	}

	debug!("construct suf: {:?}", suffixes);
}

/// An iterator over BWT output
pub struct LastColumnIterator<'a> {
	priv input		: &'a [Symbol],
	priv suf_iter	: iter::Enumerate<vec::Items<'a,Suffix>>,
	priv origin		: Option<uint>,
}

impl<'a> LastColumnIterator<'a> {
	/// create a new BWT iterator from the suffix array
	pub fn new(input: &'a [Symbol], suffixes: &'a [Suffix]) -> LastColumnIterator<'a> {
		LastColumnIterator {
			input: input,
			suf_iter: suffixes.iter().enumerate(),
			origin: None,
		}
	}

	/// return the index of the original string
	pub fn get_origin(&self) -> uint {
		self.origin.unwrap()
	}
}

impl<'a> Iterator<Symbol> for LastColumnIterator<'a> {
	fn next(&mut self) -> Option<Symbol> {
		self.suf_iter.next().map(|(i,&p)| {
			if p == 0 {
				assert!( self.origin.is_none() );
				self.origin = Some(i);
				*self.input.last().unwrap()
			}else {
				self.input[p-1]
			}
		})
	}
}

/// A helper method to perform BWT on a given block and place the result into output
/// returns the original string index in the sorted matrix
pub fn BW_transform(input: &[Symbol], suf: &mut [Suffix], output: &mut [Symbol]) -> uint {
	construct_suffix_array(input, suf);
	let mut iter = LastColumnIterator::new(input, suf);
	for (out,s) in output.mut_iter().zip(iter.by_ref()) {
		*out = s;
	}
	iter.get_origin()
}

/// An iterator over inverse BWT
pub struct InverseIterator<'a> {
	priv input		: &'a [Symbol],
	priv suffixes	: &'a [Suffix],
	priv origin		: Suffix,
	priv current	: Suffix,
}

impl<'a> InverseIterator<'a> {
	/// create a new inverse BWT iterator
	pub fn new(input: &'a [Symbol], origin: uint, suffixes: &'a mut [Suffix]) -> InverseIterator<'a> {
		assert_eq!(input.len(), suffixes.len())
		debug!("decode origin={}, input: {:?}", origin, input)

		let mut radix = bwt::Radix::new();
		radix.gather(input);
		radix.accumulate();

		suffixes[radix.place(input[origin])] = 0;
		for (i,&ch) in input.slice_to(origin).iter().enumerate() {
			suffixes[radix.place(ch)] = i+1;
		}
		for (i,&ch) in input.slice_from(origin+1).iter().enumerate() {
			suffixes[radix.place(ch)] = origin+2+i;
		}
		//suffixes[-1] = origin;
		debug!("decode table: {:?}", suffixes)

		InverseIterator {
			input: input,
			suffixes: suffixes,
			origin: origin,
			current: origin as Suffix,
		}
	}
}

impl<'a> Iterator<Symbol> for InverseIterator<'a> {
	fn next(&mut self) -> Option<Symbol> {
		if self.current == -1 {
			None
		}else {
			self.current = self.suffixes[self.current] - 1;
			debug!("\tjumped to {}", self.current);
			let p = if self.current!=-1 {self.current} else {self.origin};
			Some(self.input[p])
		}
	}
}

#[cfg(test)]
pub mod test {
	use std::{mem, vec};
	use super::{EMPTY, Suffix, Symbol};

	#[test]
	fn consts() {
		assert_eq!(EMPTY, 1<<(mem::size_of::<Suffix>()*8-1));
	}

	#[test]
	fn abracadabra() {
		let input = bytes!("abracadabra");
		let mut suf = vec::from_elem(input.len(), 0 as Suffix);
		super::construct_suffix_array(input, suf);
		assert_eq!(suf.as_slice(), &[10,7,0,3,5,8,1,4,6,9,2]);
		let (output, origin) = {
			let mut iter = super::LastColumnIterator::new(input,suf);
			let out = iter.by_ref().take(input.len()).to_owned_vec();
			(out, iter.get_origin())
		};
		assert_eq!(origin, 2);
		let expected = bytes!("rdarcaaaabb");
		assert_eq!(output.as_slice(), expected.as_slice());
		let decoded = super::InverseIterator::new(output, origin, suf).to_owned_vec();
		assert_eq!(input.as_slice(), decoded.as_slice());
	}

	#[test]
	fn roundtrip() {
		let input = include_bin!("../LICENSE");
		let mut suf = vec::from_elem(input.len(), 0 as Suffix);
		let mut output = vec::from_elem(input.len(), 0 as Symbol);
		let origin = super::BW_transform(input, suf, output);
		let decoded = super::InverseIterator::new(output, origin, suf).
			take(input.len()).to_owned_vec();
		assert_eq!(input.as_slice(), decoded.as_slice());
	}
}
<|endoftext|>