<commit_before>extern crate e2d2;
use e2d2::state::*;
use std::str;

/// Check rounding up to number of pages.
#[test]
fn round_pages_test() {
    assert!(ReorderedBuffer::round_to_pages(1) == 4096, "Rounding up 1 byte did not result in PAGE_SIZE");
    assert!(ReorderedBuffer::round_to_pages(0) == 0, "Rounding up 0 bytes did not result in 0");
    assert!(ReorderedBuffer::round_to_pages(8) == 4096, "Rounding up failure, expected 4096, got {}",
            ReorderedBuffer::round_to_pages(8));
    assert!(ReorderedBuffer::round_to_pages(512) == 4096, "Rounding up failure, expected 4096, got {}",
            ReorderedBuffer::round_to_pages(512));
    assert!(ReorderedBuffer::round_to_pages(4096) == 4096, "Rounding up exactly 1 page failed, expected 4096, got {}",
                    ReorderedBuffer::round_to_pages(4096));
    assert!(ReorderedBuffer::round_to_pages(4097) == 8192, "Rounding up > 1 page failed, expected 8192, got {}",
                    ReorderedBuffer::round_to_pages(4097));
}

/// Test rounding up to power of 2.
#[test]
fn round_to_power_of_2_test() {
    assert!(ReorderedBuffer::round_to_power_of_2(0) == 0, "Rounding to power of 2 failed, expected 0");
    assert!(ReorderedBuffer::round_to_power_of_2(1) == 1, "Rounding to power of 2 failed, expected 1");
    assert!(ReorderedBuffer::round_to_power_of_2(2) == 2, "Rounding to power of 2 failed, expected 2");
    assert!(ReorderedBuffer::round_to_power_of_2(3) == 4, "Rounding to power of 2 failed, expected 4");
    assert!(ReorderedBuffer::round_to_power_of_2(4) == 4, "Rounding to power of 2 failed, expected 4");
    assert!(ReorderedBuffer::round_to_power_of_2(5) == 8, "Rounding to power of 2 failed, expected 8");
}

/// Check that creation proceeds without a hitch.
#[test]
fn creation_test() {
    for i in 128..131072 {
        let ro = ReorderedBuffer::new(i);
        drop(ro);
    }
}

/// Check that in order insertion works correctly.
#[test]
fn in_order_insertion() {
    let mut ro = ReorderedBuffer::new(65536);
    let data0 = "food";
    let base_seq = 1232;
    if let InsertionResult::Inserted{ written, available } = ro.seq(base_seq, data0.as_bytes()) {
        assert!(written == data0.len(), "When writing with seq, not all data was written expected {} got {}",
                written, data0.len());
        assert!(available == data0.len(), "When writing in-order, not all data is available. Expected {} got {}",
                available, data0.len());
    } else {
        panic!("Seq failed");
    }

    let data1 = ": hamburger";
    if let InsertionResult::Inserted{ written, available } = ro.add_data(base_seq + data0.len(), data1.as_bytes()) {
        assert!(written == data1.len());
        assert!(available == data0.len() + data1.len());
    } else {
        panic!("Writing data1 failed");
    }

    let read_buf_len = data0.len() + data1.len() + 1;
    let mut read_buffer: Vec<_> = (0..read_buf_len).map(|_| 0).collect();
    let read = ro.read_data(&mut read_buffer[..]);
    assert!(read == data0.len() + data1.len(), "Read less than expected, read: {}, expected: {}",
            read, data0.len() + data1.len());
    let read_str = str::from_utf8(&read_buffer[..read]).unwrap();
    assert!(read_str == format!("{}{}", data0, data1),
            "Read does not match expected, read: {}, expected: {}", read_str, format!("{}{}", data0, data1));
}

/// Check that out of order insertion works correctly.
#[test]
fn out_of_order_insertion() {
    let mut ro = ReorderedBuffer::new(65536);
    let data0 = "food";
    let base_seq = 1232;
    if let InsertionResult::Inserted{ written, available } = ro.seq(base_seq, data0.as_bytes()) {
        assert!(written == data0.len());
        assert!(available == data0.len());
    } else {
        panic!("Seq failed");
    }

    let data1 = ": hamburger";
    let data2 = " american";
    if let InsertionResult::Inserted{ written, available } = ro.add_data(base_seq + data0.len() + data1.len(),
                                                                         data2.as_bytes()) {
        assert!(written == data2.len());
        assert!(available == data0.len());
    } else {
        panic!("Writing data2 failed");
    }

    if let InsertionResult::Inserted{ written, available } = ro.add_data(base_seq + data0.len(), data1.as_bytes()) {
        assert!(written == data1.len());
        assert!(available == data0.len() + data1.len() + data2.len());
    } else {
        panic!("Writing data1 failed");
    }

    let read_buf_len = ro.available();
    let mut read_buffer: Vec<_> = (0..read_buf_len).map(|_| 0).collect();
    let read = ro.read_data(&mut read_buffer[..]);
    assert!(read == read_buf_len, "Read less than what is available");
    assert!(ro.available() == 0, "Read everything but data is still available");
    let read = str::from_utf8(&read_buffer[..read]).unwrap();
    assert!(read == format!("{}{}{}", data0, data1, data2),
            "Read does not match expected, read: {}, expected: {}",
            read, format!("{}{}{}", data0, data1, data2));
}

/// Check that things OOM correctly when out of memory.
#[test]
fn check_oom() {
    let mut r0 = ReorderedBuffer::new(4096);
    let base_seq = 32;
    let data0 = "food";

    let iters = (4096 / data0.len()) - 1;
    if let InsertionResult::Inserted { written, .. } = r0.seq(base_seq, data0.as_bytes()) {
        assert!(written == data0.len());
    } else {
        panic!("Could not write");
    }

    for i in 1..iters {
        if let InsertionResult::Inserted{ written, .. } = r0.add_data(base_seq + (i * data0.len()),
                                                                             data0.as_bytes()) {
            assert!(written == data0.len());
        } else {
            panic!("Could not write");
        }
    }

    if let InsertionResult::OutOfMemory{ written, available } = r0.add_data(base_seq + (iters * data0.len()),
                                                                            data0.as_bytes()) {
        assert!(written != data0.len());
        assert!(available == 4096 - 1);
    } else {
        panic!("No OOM?");
    }
}

/// Check that reseting `ReorderedBuffer` works as expected.
#[test]
fn check_reset() {
    let mut r0 = ReorderedBuffer::new(4096);
    let base_seq = 155;
    let data0 = "food";

    let iters = (4096 / data0.len()) - 1;
    if let InsertionResult::Inserted { written, .. } = r0.seq(base_seq, data0.as_bytes()) {
        assert!(written == data0.len());
    } else {
        panic!("Could not write");
    }

    for i in 1..iters {
        if let InsertionResult::Inserted{ written, .. } = r0.add_data(base_seq + (i * data0.len()),
                                                                             data0.as_bytes()) {
            assert!(written == data0.len());
        } else {
            panic!("Could not write");
        }
    }

    if let InsertionResult::OutOfMemory{ written, available } = r0.add_data(base_seq + (iters * data0.len()),
                                                                            data0.as_bytes()) {
        assert!(written != data0.len());
        assert!(available == 4096 - 1);
    } else {
        panic!("No OOM?");
    }

    r0.reset();
    let base_seq = 72;

    if let InsertionResult::Inserted { written, .. } = r0.seq(base_seq, data0.as_bytes()) {
        assert!(written == data0.len());
    } else {
        panic!("Could not write");
    }

    for i in 1..iters {
        if let InsertionResult::Inserted{ written, .. } = r0.add_data(base_seq + (i * data0.len()),
                                                                             data0.as_bytes()) {
            assert!(written == data0.len());
        } else {
            panic!("Could not write");
        }
    }

    if let InsertionResult::OutOfMemory{ written, available } = r0.add_data(base_seq + (iters * data0.len()),
                                                                            data0.as_bytes()) {
        assert!(written != data0.len());
        assert!(available == 4096 - 1);
    } else {
        panic!("No OOM?");
    }
}

/// Check that reading after writing allows us to write infinitely
#[test]
fn check_read_after_write() {
    let mut r0 = ReorderedBuffer::new(4096);
    let mut base_seq = 255;
    let iters = 128000;
    let data = "testtest";

    if let InsertionResult::Inserted { written, .. } = r0.seq(base_seq, data.as_bytes()) {
        assert!(written == data.len(), "Could not write during seq");
        base_seq = base_seq.wrapping_add(written);
    } else {
        panic!("Could not seq");
    }

    let mut read_buf : Vec<_> = (0..data.len()).map(|_| 0).collect();

    for i in 0..iters {
        if let InsertionResult::Inserted { written, .. } = r0.add_data(base_seq, data.as_bytes()) {
            assert!(written == data.len());
            base_seq = base_seq.wrapping_add(written);
        } else {
            panic!("Could not write code, iter {} seq {}", i, base_seq);
        }

        let available_before_read = r0.available();

        let read = r0.read_data(&mut read_buf[..]);

        assert!(available_before_read == r0.available() + read, "Available bytes not adjusted by the right amount");
    }
}
<commit_msg>Test to make sure switching to fast path works<commit_after>extern crate e2d2;
use e2d2::state::*;
use std::str;

/// Check rounding up to number of pages.
#[test]
fn round_pages_test() {
    assert!(ReorderedBuffer::round_to_pages(1) == 4096, "Rounding up 1 byte did not result in PAGE_SIZE");
    assert!(ReorderedBuffer::round_to_pages(0) == 0, "Rounding up 0 bytes did not result in 0");
    assert!(ReorderedBuffer::round_to_pages(8) == 4096, "Rounding up failure, expected 4096, got {}",
            ReorderedBuffer::round_to_pages(8));
    assert!(ReorderedBuffer::round_to_pages(512) == 4096, "Rounding up failure, expected 4096, got {}",
            ReorderedBuffer::round_to_pages(512));
    assert!(ReorderedBuffer::round_to_pages(4096) == 4096, "Rounding up exactly 1 page failed, expected 4096, got {}",
                    ReorderedBuffer::round_to_pages(4096));
    assert!(ReorderedBuffer::round_to_pages(4097) == 8192, "Rounding up > 1 page failed, expected 8192, got {}",
                    ReorderedBuffer::round_to_pages(4097));
}

/// Test rounding up to power of 2.
#[test]
fn round_to_power_of_2_test() {
    assert!(ReorderedBuffer::round_to_power_of_2(0) == 0, "Rounding to power of 2 failed, expected 0");
    assert!(ReorderedBuffer::round_to_power_of_2(1) == 1, "Rounding to power of 2 failed, expected 1");
    assert!(ReorderedBuffer::round_to_power_of_2(2) == 2, "Rounding to power of 2 failed, expected 2");
    assert!(ReorderedBuffer::round_to_power_of_2(3) == 4, "Rounding to power of 2 failed, expected 4");
    assert!(ReorderedBuffer::round_to_power_of_2(4) == 4, "Rounding to power of 2 failed, expected 4");
    assert!(ReorderedBuffer::round_to_power_of_2(5) == 8, "Rounding to power of 2 failed, expected 8");
}

/// Check that creation proceeds without a hitch.
#[test]
fn creation_test() {
    for i in 128..131072 {
        let ro = ReorderedBuffer::new(i);
        drop(ro);
    }
}

/// Check that in order insertion works correctly.
#[test]
fn in_order_insertion() {
    let mut ro = ReorderedBuffer::new(65536);
    let data0 = "food";
    let base_seq = 1232;
    if let InsertionResult::Inserted{ written, available } = ro.seq(base_seq, data0.as_bytes()) {
        assert!(written == data0.len(), "When writing with seq, not all data was written expected {} got {}",
                written, data0.len());
        assert!(available == data0.len(), "When writing in-order, not all data is available. Expected {} got {}",
                available, data0.len());
    } else {
        panic!("Seq failed");
    }

    let data1 = ": hamburger";
    if let InsertionResult::Inserted{ written, available } = ro.add_data(base_seq + data0.len(), data1.as_bytes()) {
        assert!(written == data1.len());
        assert!(available == data0.len() + data1.len());
    } else {
        panic!("Writing data1 failed");
    }

    let read_buf_len = data0.len() + data1.len() + 1;
    let mut read_buffer: Vec<_> = (0..read_buf_len).map(|_| 0).collect();
    let read = ro.read_data(&mut read_buffer[..]);
    assert!(read == data0.len() + data1.len(), "Read less than expected, read: {}, expected: {}",
            read, data0.len() + data1.len());
    let read_str = str::from_utf8(&read_buffer[..read]).unwrap();
    assert!(read_str == format!("{}{}", data0, data1),
            "Read does not match expected, read: {}, expected: {}", read_str, format!("{}{}", data0, data1));
}

/// Check that out of order insertion works correctly.
#[test]
fn out_of_order_insertion() {
    let mut ro = ReorderedBuffer::new(65536);
    let data0 = "food";
    let base_seq = 1232;
    if let InsertionResult::Inserted{ written, available } = ro.seq(base_seq, data0.as_bytes()) {
        assert!(written == data0.len());
        assert!(available == data0.len());
    } else {
        panic!("Seq failed");
    }

    let data1 = ": hamburger";
    let data2 = " american";
    if let InsertionResult::Inserted{ written, available } = ro.add_data(base_seq + data0.len() + data1.len(),
                                                                         data2.as_bytes()) {
        assert!(written == data2.len());
        assert!(available == data0.len());
    } else {
        panic!("Writing data2 failed");
    }

    if let InsertionResult::Inserted{ written, available } = ro.add_data(base_seq + data0.len(), data1.as_bytes()) {
        assert!(written == data1.len());
        assert!(available == data0.len() + data1.len() + data2.len());
    } else {
        panic!("Writing data1 failed");
    }

    let read_buf_len = ro.available();
    let mut read_buffer: Vec<_> = (0..read_buf_len).map(|_| 0).collect();
    let read = ro.read_data(&mut read_buffer[..]);
    assert!(read == read_buf_len, "Read less than what is available");
    assert!(ro.available() == 0, "Read everything but data is still available");
    let read = str::from_utf8(&read_buffer[..read]).unwrap();
    assert!(read == format!("{}{}{}", data0, data1, data2),
            "Read does not match expected, read: {}, expected: {}",
            read, format!("{}{}{}", data0, data1, data2));
}

/// Check that things work fine once state is changed.
#[test]
fn check_state_change() {
    let mut ro = ReorderedBuffer::new(65536);
    let data0 = "food";
    let base_seq = 1232;
    if let InsertionResult::Inserted{ written, available } = ro.seq(base_seq, data0.as_bytes()) {
        assert!(written == data0.len());
        assert!(available == data0.len());
    } else {
        panic!("Seq failed");
    }

    let data1 = ": hamburger";
    let data2 = " american";
    let data3 = " (w/fries)";
    if let InsertionResult::Inserted{ written, available } = ro.add_data(base_seq + data0.len() + data1.len(),
                                                                         data2.as_bytes()) {
        assert!(written == data2.len());
        assert!(available == data0.len());
    } else {
        panic!("Writing data2 failed");
    }

    if let InsertionResult::Inserted{ written, available } = ro.add_data(base_seq + data0.len(), data1.as_bytes()) {
        assert!(written == data1.len());
        assert!(available == data0.len() + data1.len() + data2.len());
    } else {
        panic!("Writing data1 failed");
    }

    if let InsertionResult::Inserted { written, available } =
        ro.add_data(base_seq + data0.len() + data1.len() + data2.len(),
                    data3.as_bytes()) {
        assert!(written == data3.len());
        assert!(available == data0.len() + data1.len() + data2.len() + data3.len());
    } else {
        panic!("Writing data3 failed");
    }
    let read_buf_len = ro.available();
    let mut read_buffer: Vec<_> = (0..read_buf_len).map(|_| 0).collect();
    let read = ro.read_data(&mut read_buffer[..]);
    assert!(read == read_buf_len, "Read less than what is available");
    assert!(ro.available() == 0, "Read everything but data is still available");
    let read = str::from_utf8(&read_buffer[..read]).unwrap();
    assert!(read == format!("{}{}{}{}", data0, data1, data2, data3),
            "Read does not match expected, read: {}, expected: {}",
            read, format!("{}{}{}{}", data0, data1, data2, data3));
}

/// Check that things OOM correctly when out of memory.
#[test]
fn check_oom() {
    let mut r0 = ReorderedBuffer::new(4096);
    let base_seq = 32;
    let data0 = "food";

    let iters = (4096 / data0.len()) - 1;
    if let InsertionResult::Inserted { written, .. } = r0.seq(base_seq, data0.as_bytes()) {
        assert!(written == data0.len());
    } else {
        panic!("Could not write");
    }

    for i in 1..iters {
        if let InsertionResult::Inserted{ written, .. } = r0.add_data(base_seq + (i * data0.len()),
                                                                             data0.as_bytes()) {
            assert!(written == data0.len());
        } else {
            panic!("Could not write");
        }
    }

    if let InsertionResult::OutOfMemory{ written, available } = r0.add_data(base_seq + (iters * data0.len()),
                                                                            data0.as_bytes()) {
        assert!(written != data0.len());
        assert!(available == 4096 - 1);
    } else {
        panic!("No OOM?");
    }
}

/// Check that reseting `ReorderedBuffer` works as expected.
#[test]
fn check_reset() {
    let mut r0 = ReorderedBuffer::new(4096);
    let base_seq = 155;
    let data0 = "food";

    let iters = (4096 / data0.len()) - 1;
    if let InsertionResult::Inserted { written, .. } = r0.seq(base_seq, data0.as_bytes()) {
        assert!(written == data0.len());
    } else {
        panic!("Could not write");
    }

    for i in 1..iters {
        if let InsertionResult::Inserted{ written, .. } = r0.add_data(base_seq + (i * data0.len()),
                                                                             data0.as_bytes()) {
            assert!(written == data0.len());
        } else {
            panic!("Could not write");
        }
    }

    if let InsertionResult::OutOfMemory{ written, available } = r0.add_data(base_seq + (iters * data0.len()),
                                                                            data0.as_bytes()) {
        assert!(written != data0.len());
        assert!(available == 4096 - 1);
    } else {
        panic!("No OOM?");
    }

    r0.reset();
    let base_seq = 72;

    if let InsertionResult::Inserted { written, .. } = r0.seq(base_seq, data0.as_bytes()) {
        assert!(written == data0.len());
    } else {
        panic!("Could not write");
    }

    for i in 1..iters {
        if let InsertionResult::Inserted{ written, .. } = r0.add_data(base_seq + (i * data0.len()),
                                                                             data0.as_bytes()) {
            assert!(written == data0.len());
        } else {
            panic!("Could not write");
        }
    }

    if let InsertionResult::OutOfMemory{ written, available } = r0.add_data(base_seq + (iters * data0.len()),
                                                                            data0.as_bytes()) {
        assert!(written != data0.len());
        assert!(available == 4096 - 1);
    } else {
        panic!("No OOM?");
    }
}

/// Check that reading after writing allows us to write infinitely
#[test]
fn check_read_after_write() {
    let mut r0 = ReorderedBuffer::new(4096);
    let mut base_seq = 255;
    let iters = 128000;
    let data = "testtest";

    if let InsertionResult::Inserted { written, .. } = r0.seq(base_seq, data.as_bytes()) {
        assert!(written == data.len(), "Could not write during seq");
        base_seq = base_seq.wrapping_add(written);
    } else {
        panic!("Could not seq");
    }

    let mut read_buf : Vec<_> = (0..data.len()).map(|_| 0).collect();

    for i in 0..iters {
        if let InsertionResult::Inserted { written, .. } = r0.add_data(base_seq, data.as_bytes()) {
            assert!(written == data.len());
            base_seq = base_seq.wrapping_add(written);
        } else {
            panic!("Could not write code, iter {} seq {}", i, base_seq);
        }

        let available_before_read = r0.available();

        let read = r0.read_data(&mut read_buf[..]);

        assert!(available_before_read == r0.available() + read, "Available bytes not adjusted by the right amount");
    }
}
<|endoftext|>


<commit_before>///
/// Converts a vector of types that have the ToString trait into
/// a pretty string
///
/// # Arguments
///
/// * 'vec' - The vector you'd like a pretty string for
///
/// # Examples
///
/// ```rust
/// let v = vec![1,2,3]
/// string_for_vector(v) // prints "1,2,3"
/// ```
///
pub fn string_for_vector<T: ToString>(vec: Vec<T>) -> String {
    let mut s = String::new();
    for x in &vec {
        s.push_str(&x.to_string());
        s.push(',');
    }
    s.pop();
    s
}
<commit_msg>Changed doc to block style comments<commit_after>/**
 Converts a vector of types that have the ToString trait into
 a pretty string

 # Arguments

 * 'vec' - The vector you'd like a pretty string for

 # Examples

 ```rust
 let v = vec![1,2,3]
 string_for_vector(v) // prints "1,2,3"
 ```
*/
pub fn string_for_vector<T: ToString>(vec: Vec<T>) -> String {
    let mut s = String::new();
    for x in &vec {
        s.push_str(&x.to_string());
        s.push(',');
    }
    s.pop();
    s
}
<|endoftext|>


<commit_before>extern crate cards;
extern crate libthyme;
extern crate ncurses;

use super::{Action,UI};
use libthyme::board::{Position,HPosition,VPosition};
use libthyme::game::Game;

const CARD_WIDTH: i32 = 7;
const CARD_HEIGHT: i32 = 5;
const CARD_MARGIN: i32 = 2;
const BOARD_MARGIN: i32 = 1;
const STATUS_HEIGHT: i32 = 1;

const CARD_COLOR_BLACK: i16 = 1; // black on white
const CARD_COLOR_RED: i16 = 2; // red on white
const CARD_COLOR_EMPTY: i16 = 4; // white on black
const COLOR_SELECTED: i16 = 5; // yellow on black

/// Set up the UI
pub fn initialize_screen() {
    ncurses::setlocale(ncurses::LcCategory::ctype, "");
    ncurses::initscr();
    ncurses::noecho();
    ncurses::start_color();
    ncurses::keypad(ncurses::stdscr, true);
    ncurses::curs_set(ncurses::CURSOR_VISIBILITY::CURSOR_INVISIBLE);
    ncurses::init_pair(CARD_COLOR_BLACK, ncurses::COLOR_BLACK, ncurses::COLOR_WHITE);
    ncurses::init_pair(CARD_COLOR_RED, ncurses::COLOR_RED, ncurses::COLOR_WHITE);
    ncurses::init_pair(CARD_COLOR_EMPTY, ncurses::COLOR_WHITE, ncurses::COLOR_BLACK);
    ncurses::init_pair(COLOR_SELECTED, ncurses::COLOR_YELLOW, ncurses::COLOR_BLACK);
}

/// Redraw a UI in the current screen
pub fn redraw(ui: &UI, game: &mut Game, refresh: bool) {
    if refresh {
        ncurses::clear();
    }
    if validate_screen_size() {
        draw_cards(ui, game);
        write_message(&ui.message);
    }
    ncurses::refresh();
}

/// Tear down the UI
pub fn cleanup() {
    ncurses::endwin();
}

/// Process input from the user
///
/// Known inputs:
/// - Arrow keys: Move cursor between various positions on the board
/// - Q: Quit game
/// - H: Hint (unimplemented)
/// - ?: Help
/// - Space: Toggle position selection
/// - Return: Play move, clear selection
pub fn get_action() -> Action {
    return match ncurses::getch() {
        ncurses::KEY_LEFT => Action::CursorLeft,
        ncurses::KEY_RIGHT => Action::CursorRight,
        ncurses::KEY_UP => Action::CursorUp,
        ncurses::KEY_DOWN => Action::CursorDown,
        ncurses::KEY_RESIZE => Action::Resize,
        ncurses::KEY_ENTER | 13 | 10 => Action::Play,
        32 =>  Action::ToggleSelection, // Space
        113 => Action::Quit, // Q
        104 => Action::Hint, // H
        63 =>  Action::Help, // ?
        _ =>   Action::Unknown
    }
}

/// Check that the content can fit
fn validate_screen_size() -> bool {
    let min_height = BOARD_MARGIN*2 + CARD_MARGIN*6 + STATUS_HEIGHT + CARD_HEIGHT*3;
    if ncurses::LINES < min_height || ncurses::COLS < 50 {
        write_message(&format!("Please resize your terminal to be at least 50x{}", min_height));
        return false
    }
    return true
}

/// Print the message at the bottom of the window
fn write_message(message: &str) {
    ncurses::mvprintw(ncurses::LINES - 1, 0, message);
    ncurses::clrtoeol();
}

fn draw_cards(ui: &UI, game: &mut Game) {
    for position in game.board.positions() {
        let card = game.board.top(position);
        if card.is_some() {
            draw_card(position, card.unwrap());
        } else {
            draw_empty(position);
        }
        let (x, y) = card_location(position);
        toggle_highlight_card(x, y, ui.selection.contains(&position));
        if position == ui.cursor_position {
            let offset = (CARD_WIDTH as f32 /2.0).floor() as i32;
            ncurses::mvprintw(y + CARD_HEIGHT, x + offset, "*");
        }
    }
}

/// Draw a card on the board at a position
fn draw_card(position: Position, card: cards::card::Card) {
    let (x, y) = card_location(position);
    let (color, suit) = layout_suit(card);
    let value = layout_value(card);
    let black = ncurses::COLOR_PAIR(CARD_COLOR_BLACK);
    ncurses::attron(black);
    ncurses::mvprintw(y, x, &value);
    ncurses::attroff(black);
    ncurses::attron(color);
    ncurses::mvprintw(y, x + value.len() as i32, &suit);
    ncurses::attroff(color);
    let spacing = CARD_WIDTH - value.len() as i32 - 1;
    printw_repeat(" ", spacing, black);
    for i in 1..CARD_HEIGHT - 1 {
        ncurses::mv(y + i, x);
        printw_repeat(" ", CARD_WIDTH, black);
    }
    ncurses::mv(y + CARD_HEIGHT - 1, x);
    printw_repeat(" ", spacing, black);
    ncurses::attron(black);
    ncurses::printw(&value);
    ncurses::attroff(black);
    ncurses::attron(color);
    ncurses::printw(&suit);
    ncurses::attroff(color);
}

/// Draw empty slot for a card
fn draw_empty(position: Position) {
    let color = ncurses::COLOR_PAIR(CARD_COLOR_EMPTY);
    let (x, y) = card_location(position);
    ncurses::attron(color);
    ncurses::mvprintw(y, x, "┌");
    printw_repeat("─", CARD_WIDTH - 2, color);
    ncurses::mvprintw(y, x + CARD_WIDTH - 1, "┐");
    ncurses::attroff(color);
    for i in 1..CARD_HEIGHT - 1 {
        ncurses::attron(color);
        ncurses::mvprintw(y + i, x , "│");
        printw_repeat(" ", CARD_WIDTH - 2, color);
        ncurses::attroff(color);
        ncurses::attron(color);
        ncurses::mvprintw(y + i, x + CARD_WIDTH - 1, "│");
        ncurses::attroff(color);
    }
    ncurses::attron(color);
    ncurses::mvprintw(y + CARD_HEIGHT - 1, x, "└");
    printw_repeat("─", CARD_WIDTH - 2, color);
    ncurses::mvprintw(y + CARD_HEIGHT - 1, x + CARD_WIDTH - 1, "┘");
    ncurses::attroff(color);
}

fn printw_repeat(content: &str, len: i32, color: u64) {
    ncurses::attron(color);
    for _ in 0..len {
       ncurses::printw(content);
    }
    ncurses::attroff(color);
}

fn toggle_highlight_card(x: i32, y: i32, on: bool) {
    let color = ncurses::COLOR_PAIR(COLOR_SELECTED);
    ncurses::attron(color);
    ncurses::mvprintw(y - 1, x - 1, if on {"┌"} else {" "});
    ncurses::attroff(color);
    ncurses::mv(y - 1, x);
    printw_repeat(if on {"─"} else {" "}, CARD_WIDTH, color);
    ncurses::mv(y + CARD_HEIGHT, x);
    printw_repeat(if on {"─"} else {" "}, CARD_WIDTH, color);
    ncurses::attron(color);
    ncurses::mvprintw(y - 1, x + CARD_WIDTH, if on {"┐"} else {" "});
    for i in 0..CARD_HEIGHT {
        ncurses::mvprintw(y + i, x - 1, if on {"│"} else {" "});
        ncurses::mvprintw(y + i, x + CARD_WIDTH, if on {"│"} else {" "});
    }
    ncurses::mvprintw(y + CARD_HEIGHT, x - 1, if on {"└"} else {" "});
    ncurses::mvprintw(y + CARD_HEIGHT, x + CARD_WIDTH, if on {"┘"} else {" "});
    ncurses::attroff(color);
}

fn layout_suit(card: cards::card::Card) -> (u64, String) {
    let black = ncurses::COLOR_PAIR(CARD_COLOR_BLACK);
    let red = ncurses::COLOR_PAIR(CARD_COLOR_RED);
    return match card.suit {
        cards::card::Suit::Diamonds => (red, "\u{2666}".to_string()),
        cards::card::Suit::Clubs => (black, "\u{2663}".to_string()),
        cards::card::Suit::Spades => (black, "\u{2660}".to_string()),
        cards::card::Suit::Hearts => (red, "\u{2665}".to_string()),
    }
}

fn layout_value(card: cards::card::Card) -> String {
    return match card.value {
        cards::card::Value::Ace => "A",
        cards::card::Value::Two => "2",
        cards::card::Value::Three => "3",
        cards::card::Value::Four => "4",
        cards::card::Value::Five => "5",
        cards::card::Value::Six => "6",
        cards::card::Value::Seven => "7",
        cards::card::Value::Eight => "8",
        cards::card::Value::Nine => "9",
        cards::card::Value::Ten => "10",
        cards::card::Value::Jack => "J",
        cards::card::Value::Queen => "Q",
        cards::card::Value::King => "K",
    }.to_string()
}

/// Location (x, y) for a card position
fn card_location(position: Position) -> (i32, i32) {
    let left = BOARD_MARGIN + CARD_MARGIN;
    let center = BOARD_MARGIN + CARD_MARGIN*3 + CARD_WIDTH;
    let right = BOARD_MARGIN + CARD_MARGIN*5 + CARD_WIDTH*2;
    let top = BOARD_MARGIN + CARD_MARGIN;
    let middle = BOARD_MARGIN + CARD_MARGIN*3 + CARD_HEIGHT;
    let bottom = BOARD_MARGIN + CARD_MARGIN*5 + CARD_HEIGHT*2;
    match position {
        Position { x: HPosition::Left, y: VPosition::Top } => (left, top),
        Position { x: HPosition::Left, y: VPosition::Middle } => (left, middle),
        Position { x: HPosition::Left, y: VPosition::Bottom } => (left, bottom),
        Position { x: HPosition::Center, y: VPosition::Top } => (center, top),
        Position { x: HPosition::Center, y: VPosition::Middle } => (center, middle),
        Position { x: HPosition::Center, y: VPosition::Bottom } => (center, bottom),
        Position { x: HPosition::Right, y: VPosition::Top } => (right, top),
        Position { x: HPosition::Right, y: VPosition::Middle } => (right, middle),
        Position { x: HPosition::Right, y: VPosition::Bottom } => (right, bottom),
    }
}
<commit_msg>Print the game title and status info onscreen<commit_after>extern crate cards;
extern crate libthyme;
extern crate ncurses;

use super::{Action,UI};
use libthyme::board::{Position,HPosition,VPosition};
use libthyme::game::Game;

const CARD_WIDTH: i32 = 7;
const CARD_HEIGHT: i32 = 5;
const CARD_MARGIN: i32 = 2;
const BOARD_MARGIN: i32 = 1;
const STATUS_HEIGHT: i32 = 1;

const CARD_COLOR_BLACK: i16 = 1; // black on white
const CARD_COLOR_RED: i16 = 2; // red on white
const CARD_COLOR_EMPTY: i16 = 4; // white on black
const COLOR_SELECTED: i16 = 5; // yellow on black

/// Set up the UI
pub fn initialize_screen() {
    ncurses::setlocale(ncurses::LcCategory::ctype, "");
    ncurses::initscr();
    ncurses::noecho();
    ncurses::start_color();
    ncurses::keypad(ncurses::stdscr, true);
    ncurses::curs_set(ncurses::CURSOR_VISIBILITY::CURSOR_INVISIBLE);
    ncurses::init_pair(CARD_COLOR_BLACK, ncurses::COLOR_BLACK, ncurses::COLOR_WHITE);
    ncurses::init_pair(CARD_COLOR_RED, ncurses::COLOR_RED, ncurses::COLOR_WHITE);
    ncurses::init_pair(CARD_COLOR_EMPTY, ncurses::COLOR_WHITE, ncurses::COLOR_BLACK);
    ncurses::init_pair(COLOR_SELECTED, ncurses::COLOR_YELLOW, ncurses::COLOR_BLACK);
}

/// Redraw a UI in the current screen
pub fn redraw(ui: &UI, game: &mut Game, refresh: bool) {
    if refresh {
        ncurses::clear();
    }
    if validate_screen_size() {
        write_title(game);
        draw_cards(ui, game);
        write_message(&ui.message);
    }
    ncurses::refresh();
}

/// Tear down the UI
pub fn cleanup() {
    ncurses::endwin();
}

/// Process input from the user
///
/// Known inputs:
/// - Arrow keys: Move cursor between various positions on the board
/// - Q: Quit game
/// - H: Hint (unimplemented)
/// - ?: Help
/// - Space: Toggle position selection
/// - Return: Play move, clear selection
pub fn get_action() -> Action {
    return match ncurses::getch() {
        ncurses::KEY_LEFT => Action::CursorLeft,
        ncurses::KEY_RIGHT => Action::CursorRight,
        ncurses::KEY_UP => Action::CursorUp,
        ncurses::KEY_DOWN => Action::CursorDown,
        ncurses::KEY_RESIZE => Action::Resize,
        ncurses::KEY_ENTER | 13 | 10 => Action::Play,
        32 =>  Action::ToggleSelection, // Space
        113 => Action::Quit, // Q
        104 => Action::Hint, // H
        63 =>  Action::Help, // ?
        _ =>   Action::Unknown
    }
}

/// Check that the content can fit
fn validate_screen_size() -> bool {
    let min_height = BOARD_MARGIN*2 + CARD_MARGIN*6 + STATUS_HEIGHT + CARD_HEIGHT*3;
    if ncurses::LINES < min_height || ncurses::COLS < 50 {
        write_message(&format!("Please resize your terminal to be at least 50x{}", min_height));
        return false
    }
    return true
}

/// Print the game title and status info
fn write_title(game: &Game) {
    ncurses::attron(ncurses::A_BOLD());
    ncurses::mvprintw(0, 0, "Thyme");
    ncurses::attroff(ncurses::A_BOLD());
    let (_, suit) = layout_suit(game.board.lucky_card);
    ncurses::printw(&format!(" - Lucky Suit: {}", suit));
    ncurses::clrtoeol();
}

/// Print the message at the bottom of the window
fn write_message(message: &str) {
    ncurses::mvprintw(ncurses::LINES - 1, 0, message);
    ncurses::clrtoeol();
}

fn draw_cards(ui: &UI, game: &mut Game) {
    for position in game.board.positions() {
        let card = game.board.top(position);
        if card.is_some() {
            draw_card(position, card.unwrap());
        } else {
            draw_empty(position);
        }
        let (x, y) = card_location(position);
        toggle_highlight_card(x, y, ui.selection.contains(&position));
        if position == ui.cursor_position {
            let offset = (CARD_WIDTH as f32 /2.0).floor() as i32;
            ncurses::mvprintw(y + CARD_HEIGHT, x + offset, "*");
        }
    }
}

/// Draw a card on the board at a position
fn draw_card(position: Position, card: cards::card::Card) {
    let (x, y) = card_location(position);
    let (color, suit) = layout_suit(card);
    let value = layout_value(card);
    let black = ncurses::COLOR_PAIR(CARD_COLOR_BLACK);
    ncurses::attron(black);
    ncurses::mvprintw(y, x, &value);
    ncurses::attroff(black);
    ncurses::attron(color);
    ncurses::mvprintw(y, x + value.len() as i32, &suit);
    ncurses::attroff(color);
    let spacing = CARD_WIDTH - value.len() as i32 - 1;
    printw_repeat(" ", spacing, black);
    for i in 1..CARD_HEIGHT - 1 {
        ncurses::mv(y + i, x);
        printw_repeat(" ", CARD_WIDTH, black);
    }
    ncurses::mv(y + CARD_HEIGHT - 1, x);
    printw_repeat(" ", spacing, black);
    ncurses::attron(black);
    ncurses::printw(&value);
    ncurses::attroff(black);
    ncurses::attron(color);
    ncurses::printw(&suit);
    ncurses::attroff(color);
}

/// Draw empty slot for a card
fn draw_empty(position: Position) {
    let color = ncurses::COLOR_PAIR(CARD_COLOR_EMPTY);
    let (x, y) = card_location(position);
    ncurses::attron(color);
    ncurses::mvprintw(y, x, "┌");
    printw_repeat("─", CARD_WIDTH - 2, color);
    ncurses::mvprintw(y, x + CARD_WIDTH - 1, "┐");
    ncurses::attroff(color);
    for i in 1..CARD_HEIGHT - 1 {
        ncurses::attron(color);
        ncurses::mvprintw(y + i, x , "│");
        printw_repeat(" ", CARD_WIDTH - 2, color);
        ncurses::attroff(color);
        ncurses::attron(color);
        ncurses::mvprintw(y + i, x + CARD_WIDTH - 1, "│");
        ncurses::attroff(color);
    }
    ncurses::attron(color);
    ncurses::mvprintw(y + CARD_HEIGHT - 1, x, "└");
    printw_repeat("─", CARD_WIDTH - 2, color);
    ncurses::mvprintw(y + CARD_HEIGHT - 1, x + CARD_WIDTH - 1, "┘");
    ncurses::attroff(color);
}

fn printw_repeat(content: &str, len: i32, color: u64) {
    ncurses::attron(color);
    for _ in 0..len {
       ncurses::printw(content);
    }
    ncurses::attroff(color);
}

fn toggle_highlight_card(x: i32, y: i32, on: bool) {
    let color = ncurses::COLOR_PAIR(COLOR_SELECTED);
    ncurses::attron(color);
    ncurses::mvprintw(y - 1, x - 1, if on {"┌"} else {" "});
    ncurses::attroff(color);
    ncurses::mv(y - 1, x);
    printw_repeat(if on {"─"} else {" "}, CARD_WIDTH, color);
    ncurses::mv(y + CARD_HEIGHT, x);
    printw_repeat(if on {"─"} else {" "}, CARD_WIDTH, color);
    ncurses::attron(color);
    ncurses::mvprintw(y - 1, x + CARD_WIDTH, if on {"┐"} else {" "});
    for i in 0..CARD_HEIGHT {
        ncurses::mvprintw(y + i, x - 1, if on {"│"} else {" "});
        ncurses::mvprintw(y + i, x + CARD_WIDTH, if on {"│"} else {" "});
    }
    ncurses::mvprintw(y + CARD_HEIGHT, x - 1, if on {"└"} else {" "});
    ncurses::mvprintw(y + CARD_HEIGHT, x + CARD_WIDTH, if on {"┘"} else {" "});
    ncurses::attroff(color);
}

fn layout_suit(card: cards::card::Card) -> (u64, String) {
    let black = ncurses::COLOR_PAIR(CARD_COLOR_BLACK);
    let red = ncurses::COLOR_PAIR(CARD_COLOR_RED);
    return match card.suit {
        cards::card::Suit::Diamonds => (red, "\u{2666}".to_string()),
        cards::card::Suit::Clubs => (black, "\u{2663}".to_string()),
        cards::card::Suit::Spades => (black, "\u{2660}".to_string()),
        cards::card::Suit::Hearts => (red, "\u{2665}".to_string()),
    }
}

fn layout_value(card: cards::card::Card) -> String {
    return match card.value {
        cards::card::Value::Ace => "A",
        cards::card::Value::Two => "2",
        cards::card::Value::Three => "3",
        cards::card::Value::Four => "4",
        cards::card::Value::Five => "5",
        cards::card::Value::Six => "6",
        cards::card::Value::Seven => "7",
        cards::card::Value::Eight => "8",
        cards::card::Value::Nine => "9",
        cards::card::Value::Ten => "10",
        cards::card::Value::Jack => "J",
        cards::card::Value::Queen => "Q",
        cards::card::Value::King => "K",
    }.to_string()
}

/// Location (x, y) for a card position
fn card_location(position: Position) -> (i32, i32) {
    let left = BOARD_MARGIN + CARD_MARGIN;
    let center = BOARD_MARGIN + CARD_MARGIN*3 + CARD_WIDTH;
    let right = BOARD_MARGIN + CARD_MARGIN*5 + CARD_WIDTH*2;
    let top = BOARD_MARGIN + CARD_MARGIN;
    let middle = BOARD_MARGIN + CARD_MARGIN*3 + CARD_HEIGHT;
    let bottom = BOARD_MARGIN + CARD_MARGIN*5 + CARD_HEIGHT*2;
    match position {
        Position { x: HPosition::Left, y: VPosition::Top } => (left, top),
        Position { x: HPosition::Left, y: VPosition::Middle } => (left, middle),
        Position { x: HPosition::Left, y: VPosition::Bottom } => (left, bottom),
        Position { x: HPosition::Center, y: VPosition::Top } => (center, top),
        Position { x: HPosition::Center, y: VPosition::Middle } => (center, middle),
        Position { x: HPosition::Center, y: VPosition::Bottom } => (center, bottom),
        Position { x: HPosition::Right, y: VPosition::Top } => (right, top),
        Position { x: HPosition::Right, y: VPosition::Middle } => (right, middle),
        Position { x: HPosition::Right, y: VPosition::Bottom } => (right, bottom),
    }
}
<|endoftext|>


<commit_before>use libc::{self, pid_t, c_int};
use {Errno, Result};

use sys::signal::Signal;

mod ffi {
    use libc::{pid_t, c_int};

    extern {
        pub fn waitpid(pid: pid_t, status: *mut c_int, options: c_int) -> pid_t;
    }
}

#[cfg(not(any(target_os = "linux",
              target_os = "android")))]
bitflags!(
    flags WaitPidFlag: c_int {
        const WNOHANG     = libc::WNOHANG,
        const WUNTRACED   = libc::WUNTRACED,
    }
);

#[cfg(any(target_os = "linux",
          target_os = "android"))]
bitflags!(
    flags WaitPidFlag: c_int {
        const WNOHANG     = libc::WNOHANG,
        const WUNTRACED   = libc::WUNTRACED,
        const WEXITED     = libc::WEXITED,
        const WCONTINUED  = libc::WCONTINUED,
        const WNOWAIT     = libc::WNOWAIT, // Don't reap, just poll status.
        const __WNOTHREAD = libc::__WNOTHREAD, // Don't wait on children of other threads in this group
        const __WALL      = libc::__WALL, // Wait on all children, regardless of type
        const __WCLONE    = libc::__WCLONE,
    }
);

#[cfg(any(target_os = "linux",
          target_os = "android"))]
const WSTOPPED: WaitPidFlag = WUNTRACED;

#[derive(Eq, PartialEq, Clone, Copy, Debug)]
pub enum WaitStatus {
    Exited(pid_t, i8),
    Signaled(pid_t, Signal, bool),
    Stopped(pid_t, Signal),
    #[cfg(any(target_os = "linux", target_os = "android"))]
    PtraceEvent(pid_t, Signal, c_int),
    Continued(pid_t),
    StillAlive
}

#[cfg(any(target_os = "linux",
          target_os = "android"))]
mod status {
    use sys::signal::Signal;
    use libc::c_int;

    pub fn exited(status: i32) -> bool {
        (status & 0x7F) == 0
    }

    pub fn exit_status(status: i32) -> i8 {
        ((status & 0xFF00) >> 8) as i8
    }

    pub fn signaled(status: i32) -> bool {
        ((((status & 0x7f) + 1) as i8) >> 1) > 0
    }

    pub fn term_signal(status: i32) -> Signal {
        Signal::from_c_int(status & 0x7f).unwrap()
    }

    pub fn dumped_core(status: i32) -> bool {
        (status & 0x80) != 0
    }

    pub fn stopped(status: i32) -> bool {
        (status & 0xff) == 0x7f
    }

    pub fn stop_signal(status: i32) -> Signal {
        Signal::from_c_int((status & 0xFF00) >> 8).unwrap()
    }

    pub fn stop_additional(status: i32) -> c_int {
        (status >> 16) as c_int
    }

    pub fn continued(status: i32) -> bool {
        status == 0xFFFF
    }
}

#[cfg(any(target_os = "macos",
          target_os = "ios"))]
mod status {
    use sys::signal::{Signal,SIGCONT};

    const WCOREFLAG: i32 = 0x80;
    const WSTOPPED: i32 = 0x7f;

    fn wstatus(status: i32) -> i32 {
        status & 0x7F
    }

    pub fn exit_status(status: i32) -> i8 {
        ((status >> 8) & 0xFF) as i8
    }

    pub fn stop_signal(status: i32) -> Signal {
        Signal::from_c_int(status >> 8).unwrap()
    }

    pub fn continued(status: i32) -> bool {
        wstatus(status) == WSTOPPED && stop_signal(status) == SIGCONT
    }

    pub fn stopped(status: i32) -> bool {
        wstatus(status) == WSTOPPED && stop_signal(status) != SIGCONT
    }

    pub fn exited(status: i32) -> bool {
        wstatus(status) == 0
    }

    pub fn signaled(status: i32) -> bool {
        wstatus(status) != WSTOPPED && wstatus(status) != 0
    }

    pub fn term_signal(status: i32) -> Signal {
        Signal::from_c_int(wstatus(status)).unwrap()
    }

    pub fn dumped_core(status: i32) -> bool {
        (status & WCOREFLAG) != 0
    }
}

#[cfg(any(target_os = "freebsd",
          target_os = "openbsd",
          target_os = "dragonfly",
          target_os = "netbsd"))]
mod status {
    use sys::signal::Signal;

    const WCOREFLAG: i32 = 0x80;
    const WSTOPPED: i32 = 0x7f;

    fn wstatus(status: i32) -> i32 {
        status & 0x7F
    }

    pub fn stopped(status: i32) -> bool {
        wstatus(status) == WSTOPPED
    }

    pub fn stop_signal(status: i32) -> Signal {
        Signal::from_c_int(status >> 8).unwrap()
    }

    pub fn signaled(status: i32) -> bool {
        wstatus(status) != WSTOPPED && wstatus(status) != 0 && status != 0x13
    }

    pub fn term_signal(status: i32) -> Signal {
        Signal::from_c_int(wstatus(status)).unwrap()
    }

    pub fn exited(status: i32) -> bool {
        wstatus(status) == 0
    }

    pub fn exit_status(status: i32) -> i8 {
        (status >> 8) as i8
    }

    pub fn continued(status: i32) -> bool {
        status == 0x13
    }

    pub fn dumped_core(status: i32) -> bool {
        (status & WCOREFLAG) != 0
    }
}

fn decode(pid : pid_t, status: i32) -> WaitStatus {
    if status::exited(status) {
        WaitStatus::Exited(pid, status::exit_status(status))
    } else if status::signaled(status) {
        WaitStatus::Signaled(pid, status::term_signal(status), status::dumped_core(status))
    } else if status::stopped(status) {
        if cfg!(any(target_os = "linux", target_os = "android")) {
            let status_additional = status::stop_additional(status);
            if status_additional != 0 {
                return WaitStatus::PtraceEvent(pid, status::stop_signal(status), status::stop_additional(status))
            }
        }
        WaitStatus::Stopped(pid, status::stop_signal(status))
    } else {
        assert!(status::continued(status));
        WaitStatus::Continued(pid)
    }
}

pub fn waitpid(pid: pid_t, options: Option<WaitPidFlag>) -> Result<WaitStatus> {
    use self::WaitStatus::*;

    let mut status: i32 = 0;

    let option_bits = match options {
        Some(bits) => bits.bits(),
        None => 0
    };

    let res = unsafe { ffi::waitpid(pid as pid_t, &mut status as *mut c_int, option_bits) };

    Ok(match try!(Errno::result(res)) {
        0 => StillAlive,
        res => decode(res, status),
    })
}

pub fn wait() -> Result<WaitStatus> {
    waitpid(-1, None)
}
<commit_msg>Attempt to fix build for non-{android,linux} platforms<commit_after>use libc::{self, pid_t, c_int};
use {Errno, Result};

use sys::signal::Signal;

mod ffi {
    use libc::{pid_t, c_int};

    extern {
        pub fn waitpid(pid: pid_t, status: *mut c_int, options: c_int) -> pid_t;
    }
}

#[cfg(not(any(target_os = "linux",
              target_os = "android")))]
bitflags!(
    flags WaitPidFlag: c_int {
        const WNOHANG     = libc::WNOHANG,
        const WUNTRACED   = libc::WUNTRACED,
    }
);

#[cfg(any(target_os = "linux",
          target_os = "android"))]
bitflags!(
    flags WaitPidFlag: c_int {
        const WNOHANG     = libc::WNOHANG,
        const WUNTRACED   = libc::WUNTRACED,
        const WEXITED     = libc::WEXITED,
        const WCONTINUED  = libc::WCONTINUED,
        const WNOWAIT     = libc::WNOWAIT, // Don't reap, just poll status.
        const __WNOTHREAD = libc::__WNOTHREAD, // Don't wait on children of other threads in this group
        const __WALL      = libc::__WALL, // Wait on all children, regardless of type
        const __WCLONE    = libc::__WCLONE,
    }
);

#[cfg(any(target_os = "linux",
          target_os = "android"))]
const WSTOPPED: WaitPidFlag = WUNTRACED;

#[derive(Eq, PartialEq, Clone, Copy, Debug)]
pub enum WaitStatus {
    Exited(pid_t, i8),
    Signaled(pid_t, Signal, bool),
    Stopped(pid_t, Signal),
    #[cfg(any(target_os = "linux", target_os = "android"))]
    PtraceEvent(pid_t, Signal, c_int),
    Continued(pid_t),
    StillAlive
}

#[cfg(any(target_os = "linux",
          target_os = "android"))]
mod status {
    use sys::signal::Signal;
    use libc::c_int;

    pub fn exited(status: i32) -> bool {
        (status & 0x7F) == 0
    }

    pub fn exit_status(status: i32) -> i8 {
        ((status & 0xFF00) >> 8) as i8
    }

    pub fn signaled(status: i32) -> bool {
        ((((status & 0x7f) + 1) as i8) >> 1) > 0
    }

    pub fn term_signal(status: i32) -> Signal {
        Signal::from_c_int(status & 0x7f).unwrap()
    }

    pub fn dumped_core(status: i32) -> bool {
        (status & 0x80) != 0
    }

    pub fn stopped(status: i32) -> bool {
        (status & 0xff) == 0x7f
    }

    pub fn stop_signal(status: i32) -> Signal {
        Signal::from_c_int((status & 0xFF00) >> 8).unwrap()
    }

    pub fn stop_additional(status: i32) -> c_int {
        (status >> 16) as c_int
    }

    pub fn continued(status: i32) -> bool {
        status == 0xFFFF
    }
}

#[cfg(any(target_os = "macos",
          target_os = "ios"))]
mod status {
    use sys::signal::{Signal,SIGCONT};

    const WCOREFLAG: i32 = 0x80;
    const WSTOPPED: i32 = 0x7f;

    fn wstatus(status: i32) -> i32 {
        status & 0x7F
    }

    pub fn exit_status(status: i32) -> i8 {
        ((status >> 8) & 0xFF) as i8
    }

    pub fn stop_signal(status: i32) -> Signal {
        Signal::from_c_int(status >> 8).unwrap()
    }

    pub fn continued(status: i32) -> bool {
        wstatus(status) == WSTOPPED && stop_signal(status) == SIGCONT
    }

    pub fn stopped(status: i32) -> bool {
        wstatus(status) == WSTOPPED && stop_signal(status) != SIGCONT
    }

    pub fn exited(status: i32) -> bool {
        wstatus(status) == 0
    }

    pub fn signaled(status: i32) -> bool {
        wstatus(status) != WSTOPPED && wstatus(status) != 0
    }

    pub fn term_signal(status: i32) -> Signal {
        Signal::from_c_int(wstatus(status)).unwrap()
    }

    pub fn dumped_core(status: i32) -> bool {
        (status & WCOREFLAG) != 0
    }
}

#[cfg(any(target_os = "freebsd",
          target_os = "openbsd",
          target_os = "dragonfly",
          target_os = "netbsd"))]
mod status {
    use sys::signal::Signal;

    const WCOREFLAG: i32 = 0x80;
    const WSTOPPED: i32 = 0x7f;

    fn wstatus(status: i32) -> i32 {
        status & 0x7F
    }

    pub fn stopped(status: i32) -> bool {
        wstatus(status) == WSTOPPED
    }

    pub fn stop_signal(status: i32) -> Signal {
        Signal::from_c_int(status >> 8).unwrap()
    }

    pub fn signaled(status: i32) -> bool {
        wstatus(status) != WSTOPPED && wstatus(status) != 0 && status != 0x13
    }

    pub fn term_signal(status: i32) -> Signal {
        Signal::from_c_int(wstatus(status)).unwrap()
    }

    pub fn exited(status: i32) -> bool {
        wstatus(status) == 0
    }

    pub fn exit_status(status: i32) -> i8 {
        (status >> 8) as i8
    }

    pub fn continued(status: i32) -> bool {
        status == 0x13
    }

    pub fn dumped_core(status: i32) -> bool {
        (status & WCOREFLAG) != 0
    }
}

fn decode(pid : pid_t, status: i32) -> WaitStatus {
    if status::exited(status) {
        WaitStatus::Exited(pid, status::exit_status(status))
    } else if status::signaled(status) {
        WaitStatus::Signaled(pid, status::term_signal(status), status::dumped_core(status))
    } else if status::stopped(status) {
        #[cfg(any(target_os = "linux", target_os = "android"))] {
            let status_additional = status::stop_additional(status);
            if status_additional != 0 {
                return WaitStatus::PtraceEvent(pid, status::stop_signal(status), status::stop_additional(status))
            }
        }
        WaitStatus::Stopped(pid, status::stop_signal(status))
    } else {
        assert!(status::continued(status));
        WaitStatus::Continued(pid)
    }
}

pub fn waitpid(pid: pid_t, options: Option<WaitPidFlag>) -> Result<WaitStatus> {
    use self::WaitStatus::*;

    let mut status: i32 = 0;

    let option_bits = match options {
        Some(bits) => bits.bits(),
        None => 0
    };

    let res = unsafe { ffi::waitpid(pid as pid_t, &mut status as *mut c_int, option_bits) };

    Ok(match try!(Errno::result(res)) {
        0 => StillAlive,
        res => decode(res, status),
    })
}

pub fn wait() -> Result<WaitStatus> {
    waitpid(-1, None)
}
<|endoftext|>


<commit_before>use failure::{Backtrace, Context, Fail};
use lapin_async;
use tokio_timer;

use std::{fmt, io};

use crate::transport::CodecError;

/// The type of error that can be returned in this crate.
///
/// Instead of implementing the `Error` trait provided by the standard library,
/// it implemented the `Fail` trait provided by the `failure` crate. Doing so
/// means that this type guaranteed to be both sendable and usable across
/// threads, and that you'll be able to use the downcasting feature of the
/// `failure::Error` type.
#[derive(Debug)]
pub struct Error {
    inner: Context<ErrorKind>,
}

/// The different kinds of errors that can be reported.
///
/// Even though we expose the complete enumeration of possible error variants, it is not
/// considered stable to exhaustively match on this enumeration: do it at your own risk.
#[derive(Debug, Fail)]
pub enum ErrorKind {
    #[fail(display = "The maximum number of channels for this connection has been reached")]
    ChannelLimitReached,
    #[fail(display = "Failed to open channel")]
    ChannelOpenFailed,
    #[fail(display = "Couldn't decode incoming frame: {}", _0)]
    Decode(CodecError),
    #[fail(display = "The connection was closed by the remote peer")]
    ConnectionClosed,
    #[fail(display = "Failed to connect: {}", _0)]
    ConnectionFailed(#[fail(cause)] io::Error),
    #[fail(display = "Basic get returned empty")]
    EmptyBasicGet,
    #[fail(display = "Couldn't encode outcoming frame: {}", _0)]
    Encode(CodecError),
    #[fail(display = "The timer of the heartbeat encountered an error: {}", _0)]
    HeartbeatTimer(#[fail(cause)] tokio_timer::Error),
    #[fail(display = "Failed to handle incoming frame: {:?}", _0)]
    InvalidFrame(#[fail(cause)] lapin_async::error::Error),
    #[fail(display = "Couldn't parse URI: {}", _0)]
    InvalidUri(String),
    #[fail(display = "Transport mutex is poisoned")]
    PoisonedMutex,
    #[fail(display = "{}: {:?}", _0, _1)]
    ProtocolError(String, #[fail(cause)] lapin_async::error::Error),
    /// A hack to prevent developers from exhaustively match on the enum's variants
    ///
    /// The purpose of this variant is to let the `ErrorKind` enumeration grow more variants
    /// without it being a breaking change for users. It is planned for the language to provide
    /// this functionnality out of the box, though it has not been [stabilized] yet.
    ///
    /// [stabilized]: https://github.com/rust-lang/rust/issues/44109
    #[doc(hidden)]
    #[fail(display = "lapin_futures::error::ErrorKind::__Nonexhaustive: this should not be printed")]
    __Nonexhaustive,
}

impl Error {
    /// Return the underlying `ErrorKind`
    pub fn kind(&self) -> &ErrorKind {
        self.inner.get_context()
    }
}

impl Fail for Error {
    fn cause(&self) -> Option<&dyn Fail> {
        self.inner.cause()
    }

    fn backtrace(&self) -> Option<&Backtrace> {
        self.inner.backtrace()
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&self.inner, f)
    }
}

impl From<ErrorKind> for Error {
    fn from(kind: ErrorKind) -> Error {
        Error { inner: Context::new(kind) }
    }
}

impl From<Context<ErrorKind>> for Error {
    fn from(inner: Context<ErrorKind>) -> Error {
        Error { inner: inner }
    }
}
<commit_msg>futures: drop now unused error kind<commit_after>use failure::{Backtrace, Context, Fail};
use lapin_async;
use tokio_timer;

use std::{fmt, io};

use crate::transport::CodecError;

/// The type of error that can be returned in this crate.
///
/// Instead of implementing the `Error` trait provided by the standard library,
/// it implemented the `Fail` trait provided by the `failure` crate. Doing so
/// means that this type guaranteed to be both sendable and usable across
/// threads, and that you'll be able to use the downcasting feature of the
/// `failure::Error` type.
#[derive(Debug)]
pub struct Error {
    inner: Context<ErrorKind>,
}

/// The different kinds of errors that can be reported.
///
/// Even though we expose the complete enumeration of possible error variants, it is not
/// considered stable to exhaustively match on this enumeration: do it at your own risk.
#[derive(Debug, Fail)]
pub enum ErrorKind {
    #[fail(display = "The maximum number of channels for this connection has been reached")]
    ChannelLimitReached,
    #[fail(display = "Failed to open channel")]
    ChannelOpenFailed,
    #[fail(display = "Couldn't decode incoming frame: {}", _0)]
    Decode(CodecError),
    #[fail(display = "The connection was closed by the remote peer")]
    ConnectionClosed,
    #[fail(display = "Failed to connect: {}", _0)]
    ConnectionFailed(#[fail(cause)] io::Error),
    #[fail(display = "Basic get returned empty")]
    EmptyBasicGet,
    #[fail(display = "Couldn't encode outcoming frame: {}", _0)]
    Encode(CodecError),
    #[fail(display = "The timer of the heartbeat encountered an error: {}", _0)]
    HeartbeatTimer(#[fail(cause)] tokio_timer::Error),
    #[fail(display = "Failed to handle incoming frame: {:?}", _0)]
    InvalidFrame(#[fail(cause)] lapin_async::error::Error),
    #[fail(display = "Couldn't parse URI: {}", _0)]
    InvalidUri(String),
    #[fail(display = "{}: {:?}", _0, _1)]
    ProtocolError(String, #[fail(cause)] lapin_async::error::Error),
    /// A hack to prevent developers from exhaustively match on the enum's variants
    ///
    /// The purpose of this variant is to let the `ErrorKind` enumeration grow more variants
    /// without it being a breaking change for users. It is planned for the language to provide
    /// this functionnality out of the box, though it has not been [stabilized] yet.
    ///
    /// [stabilized]: https://github.com/rust-lang/rust/issues/44109
    #[doc(hidden)]
    #[fail(display = "lapin_futures::error::ErrorKind::__Nonexhaustive: this should not be printed")]
    __Nonexhaustive,
}

impl Error {
    /// Return the underlying `ErrorKind`
    pub fn kind(&self) -> &ErrorKind {
        self.inner.get_context()
    }
}

impl Fail for Error {
    fn cause(&self) -> Option<&dyn Fail> {
        self.inner.cause()
    }

    fn backtrace(&self) -> Option<&Backtrace> {
        self.inner.backtrace()
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&self.inner, f)
    }
}

impl From<ErrorKind> for Error {
    fn from(kind: ErrorKind) -> Error {
        Error { inner: Context::new(kind) }
    }
}

impl From<Context<ErrorKind>> for Error {
    fn from(inner: Context<ErrorKind>) -> Error {
        Error { inner: inner }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fmt;
use std::fmt::Formatter;

use crate::descriptor::FileDescriptorProto;
use crate::owning_ref::OwningRef;
use crate::reflect::enums::generated::GeneratedEnumDescriptor;
use crate::reflect::file::index::FileDescriptorCommon;
use crate::reflect::message::generated::GeneratedMessageDescriptor;
use crate::reflect::oneof::generated::GeneratedOneofDescriptor;
use crate::reflect::FileDescriptor;
use crate::reflect::GeneratedEnumDescriptorData;
use crate::reflect::GeneratedMessageDescriptorData;

/// Reflection for objects defined in `.proto` file (messages, enums, etc).
#[doc(hidden)]
pub struct GeneratedFileDescriptor {
    pub(crate) proto: &'static FileDescriptorProto,
    pub(crate) messages: Vec<GeneratedMessageDescriptor>,
    pub(crate) enums: Vec<GeneratedEnumDescriptor>,
    pub(crate) oneofs: Vec<GeneratedOneofDescriptor>,
    pub(crate) common: FileDescriptorCommon,
}

impl fmt::Debug for GeneratedFileDescriptor {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.debug_struct("GeneratedFileDescriptor")
            .field("proto.name", &self.proto.name())
            .finish_non_exhaustive()
    }
}

impl GeneratedFileDescriptor {
    /// This function is to be called from generated code.
    pub fn new_generated_2(
        file_descriptor_proto: &'static FileDescriptorProto,
        dependencies: Vec<&'static FileDescriptor>,
        messages: Vec<GeneratedMessageDescriptorData>,
        enums: Vec<GeneratedEnumDescriptorData>,
    ) -> GeneratedFileDescriptor {
        GeneratedFileDescriptor::new_generated(
            file_descriptor_proto,
            dependencies.into_iter().map(|f| f.clone()).collect(),
            messages,
            enums,
        )
    }

    /// This function is to be called from generated code.
    pub fn new_generated(
        file_descriptor_proto: &'static FileDescriptorProto,
        dependencies: Vec<FileDescriptor>,
        messages: Vec<GeneratedMessageDescriptorData>,
        enums: Vec<GeneratedEnumDescriptorData>,
    ) -> GeneratedFileDescriptor {
        let common =
            FileDescriptorCommon::new(OwningRef::new_static(file_descriptor_proto), dependencies)
                .unwrap();

        let mut messages: HashMap<&str, GeneratedMessageDescriptorData> = messages
            .into_iter()
            .map(|m| (m.protobuf_name_to_package, m))
            .collect();

        let mut enums: HashMap<&str, GeneratedEnumDescriptorData> =
            enums.into_iter().map(|e| (e.name_in_file, e)).collect();

        let mut oneofs = Vec::new();
        for oneof in &common.oneofs {
            let message = &common.messages[oneof.containing_message];
            let message_proto = &message.proto;
            let oneof_proto = &message_proto.oneof_decl[oneof.index_in_containing_message];
            let message = messages.get(message.name_to_package.as_str()).unwrap();
            let oneof_data = &message.oneofs.iter().find(|o| o.name == oneof_proto.name());
            if oneof.synthetic {
                assert!(oneof_data.is_none());
                oneofs.push(GeneratedOneofDescriptor::new_synthetic())
            } else {
                let oneof = GeneratedOneofDescriptor::new(oneof_data.unwrap());
                oneofs.push(oneof);
            }
        }

        let messages = common
            .messages
            .iter()
            .map(|message_index| {
                if message_index.proto.options.map_entry() {
                    GeneratedMessageDescriptor::new_map_entry()
                } else {
                    let message = messages
                        .remove(message_index.name_to_package.as_str())
                        .unwrap();
                    GeneratedMessageDescriptor::new(message, file_descriptor_proto, &common)
                }
            })
            .collect();

        let enums = common
            .enums
            .iter()
            .map(|enum_index| {
                let en = enums.remove(enum_index.name_to_package.as_str()).unwrap();
                GeneratedEnumDescriptor::new(en, file_descriptor_proto)
            })
            .collect();

        GeneratedFileDescriptor {
            proto: file_descriptor_proto,
            messages,
            enums,
            oneofs,
            common,
        }
    }
}
<commit_msg>Code cleanup<commit_after>use std::collections::HashMap;
use std::fmt;
use std::fmt::Formatter;

use crate::descriptor::FileDescriptorProto;
use crate::owning_ref::OwningRef;
use crate::reflect::enums::generated::GeneratedEnumDescriptor;
use crate::reflect::file::index::FileDescriptorCommon;
use crate::reflect::message::generated::GeneratedMessageDescriptor;
use crate::reflect::oneof::generated::GeneratedOneofDescriptor;
use crate::reflect::FileDescriptor;
use crate::reflect::GeneratedEnumDescriptorData;
use crate::reflect::GeneratedMessageDescriptorData;

/// Reflection for objects defined in `.proto` file (messages, enums, etc).
#[doc(hidden)]
pub struct GeneratedFileDescriptor {
    pub(crate) proto: &'static FileDescriptorProto,
    pub(crate) messages: Vec<GeneratedMessageDescriptor>,
    pub(crate) enums: Vec<GeneratedEnumDescriptor>,
    pub(crate) oneofs: Vec<GeneratedOneofDescriptor>,
    pub(crate) common: FileDescriptorCommon,
}

impl fmt::Debug for GeneratedFileDescriptor {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.debug_struct("GeneratedFileDescriptor")
            .field("proto.name", &self.proto.name())
            .finish_non_exhaustive()
    }
}

impl GeneratedFileDescriptor {
    /// This function is called from generated code.
    pub fn new_generated(
        file_descriptor_proto: &'static FileDescriptorProto,
        dependencies: Vec<FileDescriptor>,
        messages: Vec<GeneratedMessageDescriptorData>,
        enums: Vec<GeneratedEnumDescriptorData>,
    ) -> GeneratedFileDescriptor {
        let common =
            FileDescriptorCommon::new(OwningRef::new_static(file_descriptor_proto), dependencies)
                .unwrap();

        let mut messages: HashMap<&str, GeneratedMessageDescriptorData> = messages
            .into_iter()
            .map(|m| (m.protobuf_name_to_package, m))
            .collect();

        let mut enums: HashMap<&str, GeneratedEnumDescriptorData> =
            enums.into_iter().map(|e| (e.name_in_file, e)).collect();

        let mut oneofs = Vec::new();
        for oneof in &common.oneofs {
            let message = &common.messages[oneof.containing_message];
            let message_proto = &message.proto;
            let oneof_proto = &message_proto.oneof_decl[oneof.index_in_containing_message];
            let message = messages.get(message.name_to_package.as_str()).unwrap();
            let oneof_data = &message.oneofs.iter().find(|o| o.name == oneof_proto.name());
            if oneof.synthetic {
                assert!(oneof_data.is_none());
                oneofs.push(GeneratedOneofDescriptor::new_synthetic())
            } else {
                let oneof = GeneratedOneofDescriptor::new(oneof_data.unwrap());
                oneofs.push(oneof);
            }
        }

        let messages = common
            .messages
            .iter()
            .map(|message_index| {
                if message_index.proto.options.map_entry() {
                    GeneratedMessageDescriptor::new_map_entry()
                } else {
                    let message = messages
                        .remove(message_index.name_to_package.as_str())
                        .unwrap();
                    GeneratedMessageDescriptor::new(message, file_descriptor_proto, &common)
                }
            })
            .collect();

        let enums = common
            .enums
            .iter()
            .map(|enum_index| {
                let en = enums.remove(enum_index.name_to_package.as_str()).unwrap();
                GeneratedEnumDescriptor::new(en, file_descriptor_proto)
            })
            .collect();

        GeneratedFileDescriptor {
            proto: file_descriptor_proto,
            messages,
            enums,
            oneofs,
            common,
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::rc::Rc;
use std::cell::RefCell;

type WordCell = Rc<RefCell<Word>>;
type AuthorCell = Rc<RefCell<Author>>;
type SourceCell = Rc<RefCell<Source>>;
type MessageCell = Rc<RefCell<Message>>;
type CategoryCell = Rc<RefCell<Category>>;
type ConversationCell = Rc<RefCell<Conversation>>;

const RATIO_CONTAINED_BEFORE_COMBINATION: f64 = 0.8;

struct Lexicon {
    words: BTreeMap<String, WordCell>,
    authors: BTreeMap<String, AuthorCell>,
    sources: BTreeMap<String, SourceCell>,
    conversations: Vec<ConversationCell>,
}

struct Conversation {
    source: SourceCell,
    messages: Vec<MessageCell>,
}

struct Author {
    name: String,
}

struct Source {
    name: String,
    messages: u64,
}

struct MessageWord {
    word: WordCell,
    category: CategoryCell,
}

struct Message {
    author: AuthorCell,
    conversation: ConversationCell,
    index: usize,
    words: Vec<MessageWord>,
}

struct WordInstance {
    word: WordCell,
    message: MessageCell,
    index: usize,
}

struct Category {
    instances: Vec<WordInstance>,
    subcategories: Vec<CategoryCell>,
}

struct Word {
    name: String,
    instances: Vec<WordInstance>,
}
<commit_msg>add null implementation of tell function<commit_after>use std::collections::BTreeMap;
use std::rc::Rc;
use std::cell::RefCell;

type WordCell = Rc<RefCell<Word>>;
type AuthorCell = Rc<RefCell<Author>>;
type SourceCell = Rc<RefCell<Source>>;
type MessageCell = Rc<RefCell<Message>>;
type CategoryCell = Rc<RefCell<Category>>;
type ConversationCell = Rc<RefCell<Conversation>>;

const RATIO_CONTAINED_BEFORE_COMBINATION: f64 = 0.8;

struct Lexicon {
    words: BTreeMap<&'static str, WordCell>,
    authors: BTreeMap<&'static str, AuthorCell>,
    sources: BTreeMap<&'static str, SourceCell>,
    conversations: Vec<ConversationCell>,

    active_conversations: BTreeMap<*const Source, ConversationCell>,
}

impl Lexicon {
    fn tell(source: SourceCell, author: &str, message: &str) -> Option<String> {
        None
    }
}

struct Conversation {
    source: SourceCell,
    messages: Vec<MessageCell>,
}

struct Author {
    name: String,
}

struct Source {
    name: String,
    messages: u64,
}

struct MessageWord {
    word: WordCell,
    category: CategoryCell,
}

struct Message {
    author: AuthorCell,
    conversation: ConversationCell,
    index: usize,
    words: Vec<MessageWord>,
}

struct WordInstance {
    word: WordCell,
    message: MessageCell,
    index: usize,
}

struct Category {
    instances: Vec<WordInstance>,
    subcategories: Vec<CategoryCell>,
}

struct Word {
    name: String,
    instances: Vec<WordInstance>,
}
<|endoftext|>


<commit_before>#[allow(dead_code)]

#[deriving(Clone, PartialEq)]
pub enum ExprAst {
    Int(IntNode),
    Str(StrNode),
    Bool(BoolNode),
    Pair(PairNode),
    Symbol(SymbolNode),
    Char(CharNode),
    Proc(ProcNode),
    CompProc(CompProcNode),
    EmptyList(EmptyListNode),
}

pub trait Ast {
    fn print(&self);
}

impl Ast for ExprAst {
    fn print(&self) {
        match *self {
            ExprAst::Int(ref ast) => ast.print(),
            ExprAst::Str(ref ast) => ast.print(),
            ExprAst::Bool(ref ast) => ast.print(),
            ExprAst::Pair(ref ast) => ast.print(),
            ExprAst::Symbol(ref ast) => ast.print(),
            ExprAst::Char(ref ast) => ast.print(),
            ExprAst::Proc(ref ast) => ast.print(),
            ExprAst::CompProc(ref ast) => ast.print(),
            ExprAst::EmptyList(ref ast) => ast.print(),
        }
    }
}

impl ExprAst {
    fn as_bool(&self) -> bool {
        match *self {
            ExprAst::Bool(ref ast) => ast.value,
            _ => panic!("error type: expect BoolNode")
        }
    }

    fn as_int(&self) -> i32 {
        match *self {
            ExprAst::Int(ref ast) => ast.value,
            _ => panic!("error type: expect IntNode")
        }
    }

    fn as_str(&self) -> String {
        match *self {
            ExprAst::Str(ref ast) => ast.value.clone(),
            _ => panic!("error type: expect StrNode")
        }
    }

    fn as_char(&self) -> char {
        match *self {
            ExprAst::Char(ref ast) => ast.value,
            _ => panic!("error type: expect CharNode")
        }
    }
}

#[deriving(Clone, PartialEq)]
pub struct IntNode {
    pub value: i32
}

#[allow(dead_code)]
impl IntNode {
    pub fn new(val: i32) -> IntNode {
        IntNode{ value: val}
    }
}

impl Ast for IntNode {
    fn print(&self) {
        println!("IntNode: {}", self.value);
    }
}

#[deriving(Clone, PartialEq)]
pub struct StrNode {
    pub value: String
}

impl Ast for StrNode {
    fn print(&self) {
        println!("StrNode: {}", self.value);
    }
}

#[allow(dead_code)]
impl StrNode {
    pub fn new(val: String) -> StrNode {
        StrNode{ value: val}
    }
}

#[deriving(Clone, PartialEq)]
pub struct BoolNode {
    pub value: bool
}

#[allow(dead_code)]
impl BoolNode {
    pub fn new(val: bool) -> BoolNode {
        BoolNode{ value: val}
    }
}

impl Ast for BoolNode {
    fn print(&self) {
        println!("BoolNode: {}", self.value);
    }
}

#[deriving(Clone, PartialEq)]
pub struct PairNode{
    pub car: Box<ExprAst>,
    pub cdr: Box<ExprAst>
}

#[allow(dead_code)]
impl PairNode {
    pub fn new(_car: Box<ExprAst>, _cdr: Box<ExprAst>) -> PairNode {
        PairNode {
            car: _car,
            cdr: _cdr
        }
    }
}

impl Ast for PairNode {
    fn print(&self) {
        println!("PairNode (");
        self.car.print();
        self.cdr.print();
        //self.car.print();
        //self.cdr.print();
        println!(")");
    }
}

#[deriving(Clone, PartialEq)]
pub struct SymbolNode {
    pub value: String
}

impl Ast for SymbolNode {
    fn print(&self) {
        println!("SymbolNode: {}", self.value);
    }
}

#[allow(dead_code)]
impl SymbolNode {
    pub fn new(val: String) -> SymbolNode {
        SymbolNode {
            value: val
        }
    }
}

#[deriving(Clone, PartialEq)]
pub struct CharNode {
    pub value: char
}

impl Ast for CharNode {
    fn print(&self) {
        println!("CharNode: {}", self.value);
    }
}

#[allow(dead_code)]
impl CharNode {
    pub fn new(val: char) -> CharNode {
        CharNode {
            value: val
        }
    }
}

#[deriving(Clone, PartialEq)]
pub struct ProcNode {
    pub value: String
}

impl Ast for ProcNode {
    fn print(&self) {
        println!("ProcNode: {}", self.value);
    }
}

#[deriving(Clone, PartialEq)]
struct EmptyListNode;

impl Ast for EmptyListNode{
    fn print(&self) {
        println!("EmptyListNode: nil");
    }
}

#[deriving(Clone, PartialEq)]
pub struct CompProcNode {
    pub params: Box<ExprAst>,
    pub body:   Box<ExprAst>,
    pub env:    Box<ExprAst>
}

impl Ast for CompProcNode {
    fn print(&self) {
        println!("CompProcNode: ");
        self.params.print();
        self.body.print();
        self.env.print();
    }
}

#[test]
fn test_ast_int() {
    let int_node = ExprAst::Int(IntNode::new(3));
    assert!(int_node.as_int() == 3);
}

#[test]
#[should_fail]
fn test_ast_int_fail() {
    let str_node = ExprAst::Str(StrNode::new("hello".to_string()));
    assert!(str_node.as_int() == 3);
}

#[test]
fn test_ast_bool() {
    let bool_node = ExprAst::Bool(BoolNode::new(false));
    assert!(bool_node.as_bool() == false);
}

#[test]
#[should_fail]
fn test_ast_bool_fail() {
    let int_node = ExprAst::Int(IntNode::new(3));
    assert!(int_node.as_bool() == false);
}

#[test]
fn test_ast_char() {
    let char_node = ExprAst::Char(CharNode::new('a'));
    assert!(char_node.as_char() == 'a');
}

#[test]
#[should_fail]
fn test_ast_char_fail() {
    let int_node = ExprAst::Int(IntNode::new(1));
    assert!(int_node.as_char() == 'a');
}

#[test]
fn test_ast_str() {
    let str_node = ExprAst::Str(StrNode::new("hello".to_string()));
    assert!(str_node.as_str() == "hello".to_string());
}

#[test]
#[should_fail]
fn test_ast_str_fail() {
    let int_node = ExprAst::Int(IntNode::new(3));
    assert!(int_node.as_str() == "3".to_string());
}

#[test]
fn test_ast_pair() {
    let int_node = ExprAst::Int(IntNode::new(3));
    int_node.print();
    let str_node = ExprAst::Str(StrNode::new("hello".to_string()));
    str_node.print();
    let pair_node = ExprAst::Pair(PairNode::new(box int_node, box str_node));

    pair_node.print();
}
<commit_msg>more on ast<commit_after>#[allow(dead_code)]

#[deriving(Clone, PartialEq)]
pub enum ExprAst {
    Int(IntNode),
    Str(StrNode),
    Bool(BoolNode),
    Pair(PairNode),
    Symbol(SymbolNode),
    Char(CharNode),
    Proc(ProcNode),
    CompProc(CompProcNode),
    EmptyList(EmptyListNode),
}

pub trait Ast {
    fn print(&self);
}

impl Ast for ExprAst {
    fn print(&self) {
        match *self {
            ExprAst::Int(ref ast) => ast.print(),
            ExprAst::Str(ref ast) => ast.print(),
            ExprAst::Bool(ref ast) => ast.print(),
            ExprAst::Pair(ref ast) => ast.print(),
            ExprAst::Symbol(ref ast) => ast.print(),
            ExprAst::Char(ref ast) => ast.print(),
            ExprAst::Proc(ref ast) => ast.print(),
            ExprAst::CompProc(ref ast) => ast.print(),
            ExprAst::EmptyList(ref ast) => ast.print(),
        }
    }
}

impl ExprAst {
    fn as_bool(&self) -> bool {
        match *self {
            ExprAst::Bool(ref ast) => ast.value,
            _ => panic!("error type: expect BoolNode")
        }
    }

    fn as_int(&self) -> i32 {
        match *self {
            ExprAst::Int(ref ast) => ast.value,
            _ => panic!("error type: expect IntNode")
        }
    }

    fn as_str(&self) -> String {
        match *self {
            ExprAst::Str(ref ast) => ast.value.clone(),
            _ => panic!("error type: expect StrNode")
        }
    }

    fn as_char(&self) -> char {
        match *self {
            ExprAst::Char(ref ast) => ast.value,
            _ => panic!("error type: expect CharNode")
        }
    }

    fn car(&self) -> &Box<ExprAst> {
        match *self {
            ExprAst::Pair(ref ast) => &(ast.car),
            _ => panic!("error type: expect PairNode")
        }
    }

    fn cdr(&self) -> &Box<ExprAst> {
        match *self {
            ExprAst::Pair(ref ast) => &(ast.cdr),
            _ => panic!("error type: expect PairNode")
        }
    }

    fn is_empty_list(&self) -> bool {
        match *self {
            ExprAst::EmptyList(_) => true,
            _ => false
        }
    }
}

#[deriving(Clone, PartialEq)]
pub struct IntNode {
    pub value: i32
}

#[allow(dead_code)]
impl IntNode {
    pub fn new(val: i32) -> IntNode {
        IntNode{ value: val}
    }
}

impl Ast for IntNode {
    fn print(&self) {
        println!("IntNode: {}", self.value);
    }
}

#[deriving(Clone, PartialEq)]
pub struct StrNode {
    pub value: String
}

impl Ast for StrNode {
    fn print(&self) {
        println!("StrNode: {}", self.value);
    }
}

#[allow(dead_code)]
impl StrNode {
    pub fn new(val: String) -> StrNode {
        StrNode{ value: val}
    }
}

#[deriving(Clone, PartialEq)]
pub struct BoolNode {
    pub value: bool
}

#[allow(dead_code)]
impl BoolNode {
    pub fn new(val: bool) -> BoolNode {
        BoolNode{ value: val}
    }
}

impl Ast for BoolNode {
    fn print(&self) {
        println!("BoolNode: {}", self.value);
    }
}

#[deriving(Clone, PartialEq)]
pub struct PairNode{
    pub car: Box<ExprAst>,
    pub cdr: Box<ExprAst>
}

#[allow(dead_code)]
impl PairNode {
    pub fn new(car: Box<ExprAst>, cdr: Box<ExprAst>) -> PairNode {
        PairNode {
            car: car,
            cdr: cdr
        }
    }
}

impl Ast for PairNode {
    fn print(&self) {
        println!("PairNode (");
        self.car.print();
        self.cdr.print();
        //self.car.print();
        //self.cdr.print();
        println!(")");
    }
}

#[deriving(Clone, PartialEq)]
pub struct SymbolNode {
    pub value: String
}

impl Ast for SymbolNode {
    fn print(&self) {
        println!("SymbolNode: {}", self.value);
    }
}

#[allow(dead_code)]
impl SymbolNode {
    pub fn new(val: String) -> SymbolNode {
        SymbolNode {
            value: val
        }
    }
}

#[deriving(Clone, PartialEq)]
pub struct CharNode {
    pub value: char
}

impl Ast for CharNode {
    fn print(&self) {
        println!("CharNode: {}", self.value);
    }
}

#[allow(dead_code)]
impl CharNode {
    pub fn new(val: char) -> CharNode {
        CharNode {
            value: val
        }
    }
}

//FIXME, empty struct?
#[deriving(Clone, PartialEq)]
struct EmptyListNode {
    pub value: String
}

impl EmptyListNode {
    pub fn new() -> EmptyListNode {
        EmptyListNode {
            value: "EmptyListNode".to_string()
        }
    }
}

impl Ast for EmptyListNode{
    fn print(&self) {
        println!("EmptyListNode");
    }
}

//type AstFunc = |args: ExprAst| -> Option<ExprAst>;
#[deriving(Clone, PartialEq)]
pub struct ProcNode {
    pub value: String
}

impl Ast for ProcNode {
    fn print(&self) {
        println!("ProcNode: {}", self.value);
    }
}

#[deriving(Clone, PartialEq)]
pub struct CompProcNode {
    pub params: Box<ExprAst>,
    pub body:   Box<ExprAst>,
    pub env:    Box<ExprAst>
}

impl Ast for CompProcNode {
    fn print(&self) {
        println!("CompProcNode: ");
        self.params.print();
        self.body.print();
        self.env.print();
    }
}

#[test]
fn test_ast_int() {
    let int_node = ExprAst::Int(IntNode::new(3));
    assert!(int_node.as_int() == 3);
}

#[test]
#[should_fail]
fn test_ast_int_fail() {
    let str_node = ExprAst::Str(StrNode::new("hello".to_string()));
    assert!(str_node.as_int() == 3);
}

#[test]
fn test_ast_bool() {
    let bool_node = ExprAst::Bool(BoolNode::new(false));
    assert!(bool_node.as_bool() == false);
}

#[test]
#[should_fail]
fn test_ast_bool_fail() {
    let int_node = ExprAst::Int(IntNode::new(3));
    assert!(int_node.as_bool() == false);
}

#[test]
fn test_ast_char() {
    let char_node = ExprAst::Char(CharNode::new('a'));
    assert!(char_node.as_char() == 'a');
}

#[test]
#[should_fail]
fn test_ast_char_fail() {
    let int_node = ExprAst::Int(IntNode::new(1));
    assert!(int_node.as_char() == 'a');
}

#[test]
fn test_ast_str() {
    let str_node = ExprAst::Str(StrNode::new("hello".to_string()));
    assert!(str_node.as_str() == "hello".to_string());
}

#[test]
#[should_fail]
fn test_ast_str_fail() {
    let int_node = ExprAst::Int(IntNode::new(3));
    assert!(int_node.as_str() == "3".to_string());
}

#[test]
fn test_ast_pair() {
    let int_node = ExprAst::Int(IntNode::new(3));
    int_node.print();
    let str_node = ExprAst::Str(StrNode::new("hello".to_string()));
    str_node.print();
    let pair_node = ExprAst::Pair(PairNode::new(box int_node, box str_node));
    let car_node = pair_node.car();
    let cdr_node = pair_node.cdr();
    assert!(car_node.as_int() == 3);
    assert!(cdr_node.as_str() == "hello".to_string());
}

#[test]
#[should_fail]
fn test_ast_pair_fail() {
    let int_node = ExprAst::Int(IntNode::new(3));
    let car_node = int_node.car();
    assert!(car_node.as_int() == 3);
}

#[test]
fn test_ast_emptylist() {
    let empty_node = ExprAst::EmptyList(EmptyListNode::new());
    assert!(empty_node.is_empty_list());
}

#[test]
#[should_fail]
fn test_ast_emptylist_fail() {
    let empty_node = ExprAst::Int(IntNode::new(3));
    assert!(empty_node.is_empty_list());
}
<|endoftext|>


<commit_before><commit_msg>remove useless cast<commit_after><|endoftext|>