<commit_before>use std::ops::{Index, IndexMut};

use turtle::random;

use cell::Cell;
use wall::Wall;

const GRID_SIZE: usize = 12;

/// A row or column of cells
pub type Cells = [Cell; GRID_SIZE];

/// Used to determine whether to iterate over rows or columns
#[derive(Clone, Copy)]
enum GridIterTarget {
    Rows,
    Columns,
}

pub struct GridIter<'a> {
    grid: &'a [Cells; GRID_SIZE],
    target: GridIterTarget,
    current: usize,
    end: usize,
}

impl<'a> GridIter<'a> {
    fn new(grid: &'a [Cells; GRID_SIZE], target: GridIterTarget) -> Self {
        Self {
            grid,
            target,
            current: 0,
            end: match target {
                GridIterTarget::Rows => grid.len(),
                GridIterTarget::Columns => grid[0].len(),
            },
        }
    }
}

impl<'a> Iterator for GridIter<'a> {
    type Item = GridCellIter<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.current >= self.end {
            return None;
        }

        let iter = GridCellIter::new(
            self.grid,
            self.target,
            self.current
        );

        self.current += 1;
        Some(iter)
    }
}

impl<'a> DoubleEndedIterator for GridIter<'a> {
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.current >= self.end {
            return None;
        }

        let iter = GridCellIter::new(
            self.grid,
            self.target,
            self.end - 1
        );

        self.end -= 1;
        Some(iter)
    }
}

pub struct GridCellIter<'a> {
    grid: &'a [Cells; GRID_SIZE],
    target: GridIterTarget,
    /// The row or column being iterated over
    index: usize,
    /// The current position in the row or column being iterated over
    current: usize,
    // Index of the item just after the last item in the row or column being iterated over
    end: usize,
}

impl<'a> GridCellIter<'a> {
    fn new(grid: &'a [Cells; GRID_SIZE], target: GridIterTarget, index: usize) -> Self {
        Self {
            grid,
            target,
            index,
            current: 0,
            end: match target {
                GridIterTarget::Rows => grid[0].len(),
                GridIterTarget::Columns => grid.len(),
            },
        }
    }

    fn get(&self, current: usize) -> &'a Cell {
        match self.target {
            GridIterTarget::Rows => {
                &self.grid[self.index][current]
            },
            GridIterTarget::Columns => {
                &self.grid[current][self.index]
            },
        }
    }
}

impl<'a> Iterator for GridCellIter<'a> {
    type Item = &'a Cell;

    fn next(&mut self) -> Option<Self::Item> {
        if self.current >= self.end {
            return None;
        }

        let cell = self.get(self.current);

        self.current += 1;
        Some(cell)
    }
}

impl<'a> DoubleEndedIterator for GridCellIter<'a> {
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.current >= self.end {
            return None;
        }

        let cell = self.get(self.end - 1);

        self.end -= 1;
        Some(cell)
    }
}

#[derive(Debug)]
pub struct Grid([Cells; GRID_SIZE]);

impl Index<usize> for Grid {
    type Output = Cells;

    fn index(&self, index: usize) -> &Self::Output {
        self.0.index(index)
    }
}

impl IndexMut<usize> for Grid {
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        self.0.index_mut(index)
    }
}

impl Grid {
    pub fn new() -> Grid {
        Grid([Cells::default(); GRID_SIZE])
    }

    pub fn random_walls() -> Grid {
        let mut grid = [Cells::default(); GRID_SIZE];
        for row in &mut grid {
            for cell in row {
                *cell = random();
            }
        }
        Grid(grid)
    }

    /// Removes the wall between two adjacent cells
    pub fn open_between(&mut self, (row1, col1): (usize, usize), (row2, col2): (usize, usize)) {
        match (row2 as isize - row1 as isize, col2 as isize - col1 as isize) {
            (-1, 0) => {
                self[row1][col1].north = Wall::Open;
                self[row2][col2].south = Wall::Open;
            },
            (0, 1) => {
                self[row1][col1].east = Wall::Open;
                self[row2][col2].west = Wall::Open;
            },
            (1, 0) => {
                self[row1][col1].south = Wall::Open;
                self[row2][col2].north = Wall::Open;
            },
            (0, -1) => {
                self[row1][col1].west = Wall::Open;
                self[row2][col2].east = Wall::Open;
            },
            _ => unreachable!("Cells were not adjacent"),
        }
    }

    /// Returns the cell positions adjacent in the four cardinal directions to the given cell
    /// position. Only returns valid cell positions.
    pub fn adjacent_cells(&self, (row, col): (usize, usize)) -> Vec<(usize, usize)> {
        let mut positions = Vec::new();
        if row > 0 {
            // north
            positions.push((row - 1, col));
        }
        if col < self.row_size()-1 {
            // east
            positions.push((row, col + 1));
        }
        if row < self.col_size()-1 {
            // south
            positions.push((row + 1, col));
        }
        if col > 0 {
            // west
            positions.push((row, col - 1));
        }
        positions
    }

    /// Gets the cell at the given position
    pub fn get(&self, (row, col): (usize, usize)) -> &Cell {
        &self[row][col]
    }

    /// Returns the size of each row
    pub fn row_size(&self) -> usize {
        self.0[0].len()
    }

    /// Returns the size of each column
    pub fn col_size(&self) -> usize {
        self.0.len()
    }

    /// Returns the first row
    pub fn first_row(&self) -> GridCellIter {
        self.rows().next().unwrap()
    }

    /// Returns the last row
    pub fn last_row(&self) -> GridCellIter {
        self.rows().next_back().unwrap()
    }

    /// Returns the first column
    pub fn first_col(&self) -> GridCellIter {
        self.cols().next().unwrap()
    }

    /// Returns the last column
    pub fn last_col(&self) -> GridCellIter {
        self.cols().next_back().unwrap()
    }

    /// Returns an iterator over each row
    pub fn rows(&self) -> GridIter {
        GridIter::new(&self.0, GridIterTarget::Rows)
    }

    /// Returns an iterator over each row
    pub fn cols(&self) -> GridIter {
        GridIter::new(&self.0, GridIterTarget::Columns)
    }
}
<commit_msg>Grid size is now 16<commit_after>use std::ops::{Index, IndexMut};

use turtle::random;

use cell::Cell;
use wall::Wall;

const GRID_SIZE: usize = 16;

/// A row or column of cells
pub type Cells = [Cell; GRID_SIZE];

/// Used to determine whether to iterate over rows or columns
#[derive(Clone, Copy)]
enum GridIterTarget {
    Rows,
    Columns,
}

pub struct GridIter<'a> {
    grid: &'a [Cells; GRID_SIZE],
    target: GridIterTarget,
    current: usize,
    end: usize,
}

impl<'a> GridIter<'a> {
    fn new(grid: &'a [Cells; GRID_SIZE], target: GridIterTarget) -> Self {
        Self {
            grid,
            target,
            current: 0,
            end: match target {
                GridIterTarget::Rows => grid.len(),
                GridIterTarget::Columns => grid[0].len(),
            },
        }
    }
}

impl<'a> Iterator for GridIter<'a> {
    type Item = GridCellIter<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.current >= self.end {
            return None;
        }

        let iter = GridCellIter::new(
            self.grid,
            self.target,
            self.current
        );

        self.current += 1;
        Some(iter)
    }
}

impl<'a> DoubleEndedIterator for GridIter<'a> {
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.current >= self.end {
            return None;
        }

        let iter = GridCellIter::new(
            self.grid,
            self.target,
            self.end - 1
        );

        self.end -= 1;
        Some(iter)
    }
}

pub struct GridCellIter<'a> {
    grid: &'a [Cells; GRID_SIZE],
    target: GridIterTarget,
    /// The row or column being iterated over
    index: usize,
    /// The current position in the row or column being iterated over
    current: usize,
    // Index of the item just after the last item in the row or column being iterated over
    end: usize,
}

impl<'a> GridCellIter<'a> {
    fn new(grid: &'a [Cells; GRID_SIZE], target: GridIterTarget, index: usize) -> Self {
        Self {
            grid,
            target,
            index,
            current: 0,
            end: match target {
                GridIterTarget::Rows => grid[0].len(),
                GridIterTarget::Columns => grid.len(),
            },
        }
    }

    fn get(&self, current: usize) -> &'a Cell {
        match self.target {
            GridIterTarget::Rows => {
                &self.grid[self.index][current]
            },
            GridIterTarget::Columns => {
                &self.grid[current][self.index]
            },
        }
    }
}

impl<'a> Iterator for GridCellIter<'a> {
    type Item = &'a Cell;

    fn next(&mut self) -> Option<Self::Item> {
        if self.current >= self.end {
            return None;
        }

        let cell = self.get(self.current);

        self.current += 1;
        Some(cell)
    }
}

impl<'a> DoubleEndedIterator for GridCellIter<'a> {
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.current >= self.end {
            return None;
        }

        let cell = self.get(self.end - 1);

        self.end -= 1;
        Some(cell)
    }
}

#[derive(Debug)]
pub struct Grid([Cells; GRID_SIZE]);

impl Index<usize> for Grid {
    type Output = Cells;

    fn index(&self, index: usize) -> &Self::Output {
        self.0.index(index)
    }
}

impl IndexMut<usize> for Grid {
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        self.0.index_mut(index)
    }
}

impl Grid {
    pub fn new() -> Grid {
        Grid([Cells::default(); GRID_SIZE])
    }

    pub fn random_walls() -> Grid {
        let mut grid = [Cells::default(); GRID_SIZE];
        for row in &mut grid {
            for cell in row {
                *cell = random();
            }
        }
        Grid(grid)
    }

    /// Removes the wall between two adjacent cells
    pub fn open_between(&mut self, (row1, col1): (usize, usize), (row2, col2): (usize, usize)) {
        match (row2 as isize - row1 as isize, col2 as isize - col1 as isize) {
            (-1, 0) => {
                self[row1][col1].north = Wall::Open;
                self[row2][col2].south = Wall::Open;
            },
            (0, 1) => {
                self[row1][col1].east = Wall::Open;
                self[row2][col2].west = Wall::Open;
            },
            (1, 0) => {
                self[row1][col1].south = Wall::Open;
                self[row2][col2].north = Wall::Open;
            },
            (0, -1) => {
                self[row1][col1].west = Wall::Open;
                self[row2][col2].east = Wall::Open;
            },
            _ => unreachable!("Cells were not adjacent"),
        }
    }

    /// Returns the cell positions adjacent in the four cardinal directions to the given cell
    /// position. Only returns valid cell positions.
    pub fn adjacent_cells(&self, (row, col): (usize, usize)) -> Vec<(usize, usize)> {
        let mut positions = Vec::new();
        if row > 0 {
            // north
            positions.push((row - 1, col));
        }
        if col < self.row_size()-1 {
            // east
            positions.push((row, col + 1));
        }
        if row < self.col_size()-1 {
            // south
            positions.push((row + 1, col));
        }
        if col > 0 {
            // west
            positions.push((row, col - 1));
        }
        positions
    }

    /// Gets the cell at the given position
    pub fn get(&self, (row, col): (usize, usize)) -> &Cell {
        &self[row][col]
    }

    /// Returns the size of each row
    pub fn row_size(&self) -> usize {
        self.0[0].len()
    }

    /// Returns the size of each column
    pub fn col_size(&self) -> usize {
        self.0.len()
    }

    /// Returns the first row
    pub fn first_row(&self) -> GridCellIter {
        self.rows().next().unwrap()
    }

    /// Returns the last row
    pub fn last_row(&self) -> GridCellIter {
        self.rows().next_back().unwrap()
    }

    /// Returns the first column
    pub fn first_col(&self) -> GridCellIter {
        self.cols().next().unwrap()
    }

    /// Returns the last column
    pub fn last_col(&self) -> GridCellIter {
        self.cols().next_back().unwrap()
    }

    /// Returns an iterator over each row
    pub fn rows(&self) -> GridIter {
        GridIter::new(&self.0, GridIterTarget::Rows)
    }

    /// Returns an iterator over each row
    pub fn cols(&self) -> GridIter {
        GridIter::new(&self.0, GridIterTarget::Columns)
    }
}
<|endoftext|>


<commit_before>use std::any::Any;

use super::Mode;

use crate::core::editor::Editor;
use crate::core::editor::EditorEnv;
use crate::core::editor::InputStageActionMap;
use crate::core::modes::text_mode::RawDataFilter;
use crate::core::modes::text_mode::ScreenFilter;
use crate::core::modes::text_mode::TabFilter;
use crate::core::modes::text_mode::TextCodecFilter;
use crate::core::modes::text_mode::UnicodeToTextFilter;
use crate::core::modes::text_mode::Utf8Filter;
use crate::core::modes::text_mode::WordWrapFilter;
use crate::core::view::View;

use crate::core::screen::screen_apply;

use crate::dbg_println;

use crate::core::view::ContentFilter;

use crate::core::view::LayoutEnv;

use crate::core::codepointinfo::TextStyle;

pub struct StatusModeContext {}

pub struct StatusMode {}

impl StatusMode {
    pub fn new() -> Self {
        dbg_println!("StatusMode");
        StatusMode {}
    }

    pub fn register_input_stage_actions<'a>(_map: &'a mut InputStageActionMap<'a>) {}
}

impl<'a> Mode for StatusMode {
    fn name(&self) -> &'static str {
        &"status-mode"
    }

    fn alloc_ctx(&self) -> Box<dyn Any> {
        let ctx = StatusModeContext {};
        Box::new(ctx)
    }

    fn build_action_map(&self) -> InputStageActionMap<'static> {
        let mut map = InputStageActionMap::new();
        Self::register_input_stage_actions(&mut map);
        map
    }

    fn configure_view(
        &mut self,
        _editor: &mut Editor<'static>,
        _env: &mut EditorEnv<'static>,
        view: &mut View<'static>,
    ) {
        // let ctx = view.mode_ctx_mut::<StatusModeContext>("status-mode");

        //
        let use_utf8_codec = true;
        let use_tabulation_exp = true;
        let use_word_wrap = true;

        // mandatory data reader
        view.compose_content_filters
            .borrow_mut()
            .push(Box::new(RawDataFilter::new()));
        //

        if use_utf8_codec {
            //
            // DEBUG codec error
            view.compose_content_filters
                .borrow_mut()
                .push(Box::new(Utf8Filter::new()));
        } else {
            view.compose_content_filters
                .borrow_mut()
                .push(Box::new(TextCodecFilter::new()));
        }
        //
        view.compose_content_filters
            .borrow_mut()
            .push(Box::new(UnicodeToTextFilter::new()));

        //

        if use_tabulation_exp {
            view.compose_content_filters
                .borrow_mut()
                .push(Box::new(TabFilter::new()));
        }

        if use_word_wrap {
            // NB: Word Wrap after tab expansion
            view.compose_content_filters
                .borrow_mut()
                .push(Box::new(WordWrapFilter::new()));
        }

        let mut screen_filter = ScreenFilter::new();
        screen_filter.display_eof = false;

        view.compose_content_filters
            .borrow_mut()
            .push(Box::new(screen_filter));

        view.compose_content_filters
            .borrow_mut()
            .push(Box::new(StatusModeCompose::new()));
    }
}

pub struct StatusModeCompose {
    // add common fields
}

impl StatusModeCompose {
    pub fn new() -> Self {
        dbg_println!("StatusMode");
        StatusModeCompose {}
    }

    pub fn register_input_stage_actions<'a>(_map: &'a mut InputStageActionMap<'a>) {}
}

impl ContentFilter<'_> for StatusModeCompose {
    fn name(&self) -> &'static str {
        &"StatusModeCompose"
    }

    fn finish(&mut self, _view: &View, env: &mut LayoutEnv) {
        // fill the whole status bar
        screen_apply(&mut env.screen, |_, _, cpi| {
            cpi.style.color = TextStyle::title_color();
            cpi.style.bg_color = TextStyle::title_bg_color();

            true
        });
    }
}
<commit_msg>status mode : remove word wrap filter<commit_after>use std::any::Any;

use super::Mode;

use crate::core::editor::Editor;
use crate::core::editor::EditorEnv;
use crate::core::editor::InputStageActionMap;
use crate::core::modes::text_mode::RawDataFilter;
use crate::core::modes::text_mode::ScreenFilter;
use crate::core::modes::text_mode::TabFilter;
use crate::core::modes::text_mode::TextCodecFilter;
use crate::core::modes::text_mode::UnicodeToTextFilter;
use crate::core::modes::text_mode::Utf8Filter;
use crate::core::view::View;

use crate::core::screen::screen_apply;

use crate::dbg_println;

use crate::core::view::ContentFilter;

use crate::core::view::LayoutEnv;

use crate::core::codepointinfo::TextStyle;

pub struct StatusModeContext {}

pub struct StatusMode {}

impl StatusMode {
    pub fn new() -> Self {
        dbg_println!("StatusMode");
        StatusMode {}
    }

    pub fn register_input_stage_actions<'a>(_map: &'a mut InputStageActionMap<'a>) {}
}

impl<'a> Mode for StatusMode {
    fn name(&self) -> &'static str {
        &"status-mode"
    }

    fn alloc_ctx(&self) -> Box<dyn Any> {
        let ctx = StatusModeContext {};
        Box::new(ctx)
    }

    fn build_action_map(&self) -> InputStageActionMap<'static> {
        let mut map = InputStageActionMap::new();
        Self::register_input_stage_actions(&mut map);
        map
    }

    fn configure_view(
        &mut self,
        _editor: &mut Editor<'static>,
        _env: &mut EditorEnv<'static>,
        view: &mut View<'static>,
    ) {
        // let ctx = view.mode_ctx_mut::<StatusModeContext>("status-mode");

        //
        let use_utf8_codec = true;
        let use_tabulation_exp = true;

        // mandatory data reader
        view.compose_content_filters
            .borrow_mut()
            .push(Box::new(RawDataFilter::new()));
        //

        if use_utf8_codec {
            //
            // DEBUG codec error
            view.compose_content_filters
                .borrow_mut()
                .push(Box::new(Utf8Filter::new()));
        } else {
            view.compose_content_filters
                .borrow_mut()
                .push(Box::new(TextCodecFilter::new()));
        }
        //
        view.compose_content_filters
            .borrow_mut()
            .push(Box::new(UnicodeToTextFilter::new()));

        // TODO: char map 0x9 -> "\t"
        if use_tabulation_exp {
            view.compose_content_filters
                .borrow_mut()
                .push(Box::new(TabFilter::new()));
        }

        let mut screen_filter = ScreenFilter::new();
        screen_filter.display_eof = false;

        view.compose_content_filters
            .borrow_mut()
            .push(Box::new(screen_filter));

        view.compose_content_filters
            .borrow_mut()
            .push(Box::new(StatusModeCompose::new()));
    }
}

pub struct StatusModeCompose {
    // add common fields
}

impl StatusModeCompose {
    pub fn new() -> Self {
        dbg_println!("StatusMode");
        StatusModeCompose {}
    }

    pub fn register_input_stage_actions<'a>(_map: &'a mut InputStageActionMap<'a>) {}
}

impl ContentFilter<'_> for StatusModeCompose {
    fn name(&self) -> &'static str {
        &"StatusModeCompose"
    }

    fn finish(&mut self, _view: &View, env: &mut LayoutEnv) {
        // fill the whole status bar
        screen_apply(&mut env.screen, |_, _, cpi| {
            cpi.style.color = TextStyle::title_color();
            cpi.style.bg_color = TextStyle::title_bg_color();

            true
        });
    }
}
<|endoftext|>


<commit_before>use time::now_utc;

use crypto::{HashDigest, PublicKey, SecretKey, gen_keypair, hash_message,
             sign_message};
use error::{SimplesError, SimplesResult};
use simples_pb::{Block, BlockWithDiff, HashedBlock, SignedBlock, Transaction};
use tx::{TransactionBuilder, TransactionExt};

fn create_genesis_block(tx: Transaction) -> SimplesResult<HashedBlock> {
    if tx.get_commit().get_bounty() != 0 || tx.get_commit().has_bounty_pk() {
        return Err(SimplesError::new(
            "Transactions must not have a bounty set in a genesis block."));
    }
    try!(tx.verify_signatures());
    let mut genesis = HashedBlock::new();
    genesis.mut_signed_block().mut_block().mut_transactions().push(tx);
    genesis.mut_signed_block().mut_block().set_previous(
        HashDigest::from_u64(0).0.to_vec());
    genesis.mut_signed_block().mut_block().set_height(0);
    genesis.mut_signed_block().mut_block().set_timestamp(
        now_utc().to_timespec().sec);
    genesis.compute_hash();
    Ok(genesis)
}

pub struct GenesisBuilder {
    transfers: Vec<(PublicKey, u64)>
}

impl GenesisBuilder {
    pub fn new() -> GenesisBuilder {
        GenesisBuilder {
            transfers: vec![]
        }
    }

    pub fn add_transfer(&mut self, destination: PublicKey, tokens: u64) {
        self.transfers.push((destination, tokens));
    }

    pub fn build(self) -> HashedBlock {
        let (public_key, secret_key) = gen_keypair();
        let mut tx_builder = TransactionBuilder::new();
        let mut op_num = 0u32;
        for (destination, tokens) in self.transfers.into_iter() {
            tx_builder.add_transfer(
                &secret_key, &public_key, &destination, tokens, op_num);
            op_num += 1;
        }
        let genesis_tx = tx_builder.build().unwrap();
        assert!(genesis_tx.verify_signatures().is_ok());
        create_genesis_block(genesis_tx).unwrap()
    }
}

pub trait HashedBlockExt {
    fn compute_hash(&mut self) -> HashDigest;
    fn decode_hash(&self) -> SimplesResult<HashDigest>;
    fn decode_previous(&self) -> SimplesResult<HashDigest>;
    fn get_block<'a>(&'a self) -> &'a Block;
    fn get_height(&self) -> u32;
    fn set_previous_block(&mut self, block_hash: &HashDigest);
    fn verify_hash(&self) -> SimplesResult<()>;
    fn verify(&self) -> SimplesResult<()>;
}

impl HashedBlockExt for HashedBlock {
    fn compute_hash(&mut self) -> HashDigest {
        let hash_digest = hash_message(self.get_signed_block());
        self.set_hash(hash_digest.0.to_vec());
        hash_digest
    }

    fn decode_hash(&self) -> SimplesResult<HashDigest> {
        HashDigest::from_bytes(self.get_hash())
    }

    fn decode_previous(&self) -> SimplesResult<HashDigest> {
        HashDigest::from_bytes(self.get_block().get_previous())
    }

    fn get_block<'a>(&'a self) -> &'a Block {
        self.get_signed_block().get_block()
    }

    fn get_height(&self) -> u32 { self.get_block().get_height() }

    fn set_previous_block(&mut self, block_hash: &HashDigest) {
        self.mut_signed_block().mut_block().set_previous(block_hash.0.to_vec())
    }

    fn verify_hash(&self) -> SimplesResult<()> {
        let block_hash = try!(HashDigest::from_bytes(&self.get_hash()));
        try!(HashDigest::from_bytes(self.get_block().get_previous()));

        let computed_hash = hash_message(self.get_signed_block());
        if computed_hash == block_hash { Ok(()) }
        else { Err(SimplesError::new(&format!(
            "Block has invalid hash: {} != {} (actual)",
            block_hash, computed_hash)))
        }
    }

    fn verify(&self) -> SimplesResult<()> {
        try!(self.verify_hash());
        try!(self.get_signed_block().verify_signature());
        let txes = self.get_block().get_transactions();
        for tx in txes { try!(tx.verify_signatures()); }
        Ok(())
    }
}

pub trait SignedBlockExt {
    fn sign(&mut self, secret_key: &SecretKey);
    fn verify_signature(&self) -> SimplesResult<()>;
}

impl SignedBlockExt for SignedBlock {
    fn sign(&mut self, secret_key: &SecretKey) {
        let signature = sign_message(secret_key, self.get_block());
        self.set_signature(signature.0.to_vec());
    }

    fn verify_signature(&self) -> SimplesResult<()> {
        Ok(())
    }
}

pub trait BlockWithDiffExt {
    fn decode_hash(&self) -> SimplesResult<HashDigest>;
    fn decode_previous(&self) -> SimplesResult<HashDigest>;
    fn get_height(&self) -> u32;
}

impl BlockWithDiffExt for BlockWithDiff {
    fn decode_hash(&self) -> SimplesResult<HashDigest> {
        self.get_hashed_block().decode_hash()
    }

    fn decode_previous(&self) -> SimplesResult<HashDigest> {
        self.get_hashed_block().decode_previous()
    }

    fn get_height(&self) -> u32 {
        self.get_hashed_block().get_height()
    }
}

/*****  Tests  *****/

#[test]
fn test_create_genesis_empty() {
    let tx = Transaction::new();
    let maybe_genesis = create_genesis_block(tx);
    assert!(maybe_genesis.is_ok());
    assert!(0 == maybe_genesis.unwrap().get_block().get_height());
}

#[test]
fn test_create_genesis_with_invalid_tx() {
    let (pk1, sk1) = gen_keypair();
    let (pk2, sk2) = gen_keypair();

    let mut tx_builder = TransactionBuilder::new();
    tx_builder.add_transfer(&sk1, &pk1, &pk2, 10, 0);
    let maybe_tx = tx_builder.build();
    assert!(maybe_tx.is_ok());
    let mut tx = maybe_tx.unwrap();
    assert!(create_genesis_block(tx.clone()).is_ok());
    tx.clear_signatures();
    assert!(create_genesis_block(tx).is_err());
}

#[test]
fn test_hashed_block_get_block() {
    let mut hashed_block = HashedBlock::new();
    hashed_block.mut_signed_block().mut_block()
        .set_previous(hash(b"test1").0.to_vec());
    assert!(hashed_block.get_signed_block().get_block() == hashed_block.get_block());
}

#[test]
fn test_hashed_block_hash_integrity() {
    let mut hashed_block = HashedBlock::new();
    hashed_block.mut_signed_block().mut_block()
        .set_previous(hash(b"test123").0.to_vec());
    assert!(hashed_block.verify_hash().is_err());
    hashed_block.compute_hash();
    assert!(hashed_block.verify_hash().is_ok());

    hashed_block.mut_signed_block().mut_block()
        .set_previous(hash(b"test123.").0.to_vec());
    assert!(hashed_block.verify_hash().is_err());
    hashed_block.compute_hash();
    assert!(hashed_block.verify_hash().is_ok());
}

// #[test]
// fn test_hashed_block_sign_integrity() {
//     let mut hashed_block = HashedBlock::new();
//     hashed_block.mut_signed_block().mut_mut_block().set_hash(hash("test1"));

//     assert!(hashed_block.verify_hash().is_err());
//     hashed_block.compute_hash();
//     assert!(hashed_block.verify_hash().is_ok());
//     println!("Block hash: {}",
//             &hashed_block.get_hash().to_base64(base64::STANDARD));
// }
<commit_msg>Sign genesis blocks.<commit_after>use time::now_utc;

use crypto::{HashDigest, PublicKey, SecretKey, gen_keypair, hash_message,
             sign_message, Signature, slice_to_signature, verify_signed_message};
use error::{SimplesError, SimplesResult};
use simples_pb::{Block, BlockWithDiff, HashedBlock, SignedBlock, Transaction};
use tx::{TransactionBuilder, TransactionExt};

fn create_genesis_block(staker_pk: &PublicKey, staker_sk: &SecretKey,
                        tx: Transaction) -> SimplesResult<HashedBlock> {
    if tx.get_commit().get_bounty() != 0 || tx.get_commit().has_bounty_pk() {
        return Err(SimplesError::new(
            "Transactions must not have a bounty set in a genesis block."));
    }
    try!(tx.verify_signatures());
    let mut genesis = HashedBlock::new();
    genesis.mut_signed_block().mut_block().set_staker_pk(staker_pk.0.to_vec());
    genesis.mut_signed_block().mut_block().set_previous(
        HashDigest::from_u64(0).0.to_vec());
    genesis.mut_signed_block().mut_block().set_height(0);
    genesis.mut_signed_block().mut_block().set_timestamp(
        now_utc().to_timespec().sec);
    genesis.mut_signed_block().mut_block().mut_transactions().push(tx);

    genesis.mut_signed_block().sign(staker_sk);
    genesis.compute_hash();
    Ok(genesis)
}

pub struct GenesisBuilder {
    transfers: Vec<(PublicKey, u64)>
}

impl GenesisBuilder {
    pub fn new() -> GenesisBuilder {
        GenesisBuilder {
            transfers: vec![]
        }
    }

    pub fn add_transfer(&mut self, destination: PublicKey, tokens: u64) {
        self.transfers.push((destination, tokens));
    }

    pub fn build(self) -> HashedBlock {
        let (public_key, secret_key) = gen_keypair();
        let mut tx_builder = TransactionBuilder::new();
        let mut op_num = 0u32;
        for (destination, tokens) in self.transfers.into_iter() {
            tx_builder.add_transfer(
                &secret_key, &public_key, &destination, tokens, op_num);
            op_num += 1;
        }
        let genesis_tx = tx_builder.build().unwrap();
        assert!(genesis_tx.verify_signatures().is_ok());
        create_genesis_block(&public_key, &secret_key, genesis_tx).unwrap()
    }
}

pub trait HashedBlockExt {
    fn compute_hash(&mut self) -> HashDigest;
    fn decode_hash(&self) -> SimplesResult<HashDigest>;
    fn decode_previous(&self) -> SimplesResult<HashDigest>;
    fn get_block<'a>(&'a self) -> &'a Block;
    fn get_height(&self) -> u32;
    fn set_previous_block(&mut self, block_hash: &HashDigest);
    fn verify_hash(&self) -> SimplesResult<()>;
    fn verify(&self) -> SimplesResult<()>;
}

impl HashedBlockExt for HashedBlock {
    fn compute_hash(&mut self) -> HashDigest {
        let hash_digest = hash_message(self.get_signed_block());
        self.set_hash(hash_digest.0.to_vec());
        hash_digest
    }

    fn decode_hash(&self) -> SimplesResult<HashDigest> {
        HashDigest::from_bytes(self.get_hash())
    }

    fn decode_previous(&self) -> SimplesResult<HashDigest> {
        HashDigest::from_bytes(self.get_block().get_previous())
    }

    fn get_block<'a>(&'a self) -> &'a Block {
        self.get_signed_block().get_block()
    }

    fn get_height(&self) -> u32 { self.get_block().get_height() }

    fn set_previous_block(&mut self, block_hash: &HashDigest) {
        self.mut_signed_block().mut_block().set_previous(block_hash.0.to_vec())
    }

    fn verify_hash(&self) -> SimplesResult<()> {
        let block_hash = try!(HashDigest::from_bytes(&self.get_hash()));
        try!(HashDigest::from_bytes(self.get_block().get_previous()));

        let computed_hash = hash_message(self.get_signed_block());
        if computed_hash == block_hash { Ok(()) }
        else { Err(SimplesError::new(&format!(
            "Block has invalid hash: {} != {} (actual)",
            block_hash, computed_hash)))
        }
    }

    fn verify(&self) -> SimplesResult<()> {
        try!(self.verify_hash());
        try!(self.get_signed_block().verify_signature());
        let txes = self.get_block().get_transactions();
        for tx in txes { try!(tx.verify_signatures()); }
        Ok(())
    }
}

pub trait SignedBlockExt {
    fn sign(&mut self, secret_key: &SecretKey);
    fn verify_signature(&self) -> SimplesResult<()>;
}

impl SignedBlockExt for SignedBlock {
    fn sign(&mut self, secret_key: &SecretKey) {
        let signature = sign_message(secret_key, self.get_block());
        self.set_signature(signature.0.to_vec());
    }

    fn verify_signature(&self) -> SimplesResult<()> {
        Ok(())
    }
}

pub trait BlockWithDiffExt {
    fn decode_hash(&self) -> SimplesResult<HashDigest>;
    fn decode_previous(&self) -> SimplesResult<HashDigest>;
    fn get_height(&self) -> u32;
}

impl BlockWithDiffExt for BlockWithDiff {
    fn decode_hash(&self) -> SimplesResult<HashDigest> {
        self.get_hashed_block().decode_hash()
    }

    fn decode_previous(&self) -> SimplesResult<HashDigest> {
        self.get_hashed_block().decode_previous()
    }

    fn get_height(&self) -> u32 {
        self.get_hashed_block().get_height()
    }
}

/*****  Tests  *****/

#[test]
fn test_create_genesis_empty() {
    let tx = Transaction::new();
    let maybe_genesis = create_genesis_block(tx);
    assert!(maybe_genesis.is_ok());
    assert!(0 == maybe_genesis.unwrap().get_block().get_height());
}

#[test]
fn test_create_genesis_with_invalid_tx() {
    let (pk1, sk1) = gen_keypair();
    let (pk2, sk2) = gen_keypair();

    let mut tx_builder = TransactionBuilder::new();
    tx_builder.add_transfer(&sk1, &pk1, &pk2, 10, 0);
    let maybe_tx = tx_builder.build();
    assert!(maybe_tx.is_ok());
    let mut tx = maybe_tx.unwrap();
    assert!(create_genesis_block(tx.clone()).is_ok());
    tx.clear_signatures();
    assert!(create_genesis_block(tx).is_err());
}

#[test]
fn test_hashed_block_get_block() {
    let mut hashed_block = HashedBlock::new();
    hashed_block.mut_signed_block().mut_block()
        .set_previous(hash(b"test1").0.to_vec());
    assert!(hashed_block.get_signed_block().get_block() == hashed_block.get_block());
}

#[test]
fn test_hashed_block_hash_integrity() {
    let mut hashed_block = HashedBlock::new();
    hashed_block.mut_signed_block().mut_block()
        .set_previous(hash(b"test123").0.to_vec());
    assert!(hashed_block.verify_hash().is_err());
    hashed_block.compute_hash();
    assert!(hashed_block.verify_hash().is_ok());

    hashed_block.mut_signed_block().mut_block()
        .set_previous(hash(b"test123.").0.to_vec());
    assert!(hashed_block.verify_hash().is_err());
    hashed_block.compute_hash();
    assert!(hashed_block.verify_hash().is_ok());
}

// #[test]
// fn test_hashed_block_sign_integrity() {
//     let mut hashed_block = HashedBlock::new();
//     hashed_block.mut_signed_block().mut_mut_block().set_hash(hash("test1"));

//     assert!(hashed_block.verify_hash().is_err());
//     hashed_block.compute_hash();
//     assert!(hashed_block.verify_hash().is_ok());
//     println!("Block hash: {}",
//             &hashed_block.get_hash().to_base64(base64::STANDARD));
// }
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::io::{Error, ErrorKind, Read, Seek, SeekFrom};

use byteorder::{BigEndian, ReadBytesExt};

/// The usage information for an `IndexEntry`.
#[derive(Debug)]
pub enum Usage {
    /// Indentifier: 'Pict'.
    /// Indicates the resource is an image.
    Pict,

    /// Indentifier: 'Snd '.
    /// Indicates the resource is a sound.
    Snd,

    /// Indentifier: 'Data'.
    /// Indicates the resource is some data.
    Data,

    /// Indentifier: 'Exec'.
    /// Indicates the resource is an executable.
    Exec,
}

/// Contains the usage information for an entry, the resource number of
/// the entry, and where in the blob the entry starts.
#[derive(Debug)]
pub struct IndexEntry {
    pub usage: Usage,
    pub num: u32,
    start: u32,
}

/// Container for list of resource index entries.
#[derive(Debug)]
pub struct ResourceIndex {
    pub entries: HashMap<usize, IndexEntry>,
}

/// Container for chunk metadata. Used for identifying a chunk without
/// loading the full chunk into memory.
#[derive(Debug)]
pub struct ChunkData {
    pub id: String,
    len: u32,
}

/// Representation for loaded blorb chunks
pub enum Chunk {

    /// Chunk returned when the loaded chunk type is unable to be
    /// identified. Per Specification, the machine must ignore unknown
    /// chunks, and this type will be used to do so when necessary.
    Unknown{meta: ChunkData, data: Vec<u8>},

    /// Identifier: 'RIdx'.
    /// Contains a resource index for the IF.
    /// This chunk is mandatory and must be the first chunk in the form.
    ResourceIndex{index: ResourceIndex},

    /// Identifier: 'IFmd',
    /// Contains xml metadata content for the IF.
    Metadata{info: String},

    /// Identifier: 'Fspec',
    /// Contains a reference to a frontispiece image.
    /// This chunk is optional.
    Frontispiece{num: u32},

    /// Identifier: 'GLUL',
    /// Contains Glulx executable
    /// This is a executable resource chunk.
    Glulx{code: Vec<u8>},

    /// Identifier: 'PNG ',
    /// Contains a PNG image
    /// This is a picture resource chunk.
    Png{data: Vec<u8>},

    /// Identifier: 'JPEG',
    /// Contains a JPEG image
    /// This is a picture resource chunk.
    Jpeg{data: Vec<u8>},
}

pub struct Blorb<R: Read + Seek> {
    pub form: String,
    pub len: u32,
    index: ResourceIndex,
    file: R,
}

impl<R: Read + Seek> Blorb<R> {

    /// Creates a new Blorb from a file. The code goes through the
    /// given game file, validates the file type, and extracts the
    /// basic game objects for the blorb.
    pub fn from_file(file: R) -> Result<Blorb<R>, Error> {
        let mut file = file;

        // Check that the first byte is the word "FORM"
        let tag = try!(Blorb::load_4bw(&mut file));
        assert_eq!(&tag, "FORM");

        // Get the length of the blorb
        let len = try!(file.read_u32::<BigEndian>());

        // Check that the form type is IFRS
        let form = try!(Blorb::load_4bw(&mut file));
        assert_eq!(&form, "IFRS");

        let index = if let Chunk::ResourceIndex{index} =
                try!(Blorb::load_chunk(&mut file)) {
            index
        } else {
            return Err(Error::new(
                ErrorKind::InvalidInput,
                "could not locate index"
            ));
        };

        Ok(Blorb{
            form: form,
            len: len,
            index: index,
            file: file,
        })
    }

    /// loads a resource using the given index entry.
    pub fn load_resource(&mut self, num: usize) -> Result<Chunk, Error> {
        let entry = match self.index.entries.get(&num) {
            Some(entry) => entry,
            None => {
                return Err(Error::new(
                    ErrorKind::NotFound,
                    "resource not found"
                ))
            },
        };
        try!(self.file.seek(SeekFrom::Start(entry.start as u64)));

        Blorb::load_chunk(&mut self.file)
    }

    fn load_chunk(file: &mut R) -> Result<Chunk, Error> {
        let meta = try!(Blorb::load_chunk_data(file));

        match meta.id.as_ref() {
            "RIdx" => {
                let num = try!(file.read_u32::<BigEndian>());
                let mut entries = HashMap::with_capacity(num as usize);
                for _ in 0..num {
                    let entry = try!(Blorb::load_index_entry(file));
                    entries.insert(entry.num as usize, entry);
                }

                Ok(Chunk::ResourceIndex{index: ResourceIndex{entries:entries}})
            },
            "GLUL" => {
                let mut data = Vec::with_capacity(meta.len as usize);
                try!(file.take(meta.len as u64).read_to_end(&mut data));
                Ok(Chunk::Glulx{code: data})
            },
            _ => {
                let mut data = Vec::with_capacity(meta.len as usize);
                try!(file.take(meta.len as u64).read_to_end(&mut data));
                Ok(Chunk::Unknown{meta: meta, data: data})
            },
        }
    }

    fn load_index_entry(file: &mut R) -> Result<IndexEntry, Error> {
        let usage = try!(Blorb::load_4bw(file));
        let num = try!(file.read_u32::<BigEndian>());
        let start = try!(file.read_u32::<BigEndian>());

        let usage = match usage.as_ref() {
            "Pict" => Usage::Pict,
            "Snd " => Usage::Snd,
            "Data" => Usage::Data,
            "Exec" => Usage::Exec,
            _ => return Err(Error::new(
                ErrorKind::InvalidInput,
                "could not identify index entry usage"
            )),
        };

        Ok(IndexEntry{usage: usage, num: num, start: start})
    }

    fn load_chunk_data(file: &mut R) -> Result<ChunkData, Error> {
        let id = try!(Blorb::load_4bw(file));
        let len = try!(file.read_u32::<BigEndian>());
        Ok(ChunkData{id: id, len: len})
    }

    /// Load a 4 byte ASCII word from the file
    fn load_4bw(file: &mut R) -> Result<String, Error> {
        let mut id = String::with_capacity(0x4);
        try!(file.take(4).read_to_string(&mut id));
        Ok(id)
    }
}
<commit_msg>cleaned up top-level form a bit<commit_after>use std::collections::HashMap;
use std::io::{Error, ErrorKind, Read, Seek, SeekFrom};

use byteorder::{BigEndian, ReadBytesExt};

/// The usage information for an `IndexEntry`.
#[derive(Debug)]
pub enum Usage {
    /// Indentifier: 'Pict'.
    /// Indicates the resource is an image.
    Pict,

    /// Indentifier: 'Snd '.
    /// Indicates the resource is a sound.
    Snd,

    /// Indentifier: 'Data'.
    /// Indicates the resource is some data.
    Data,

    /// Indentifier: 'Exec'.
    /// Indicates the resource is an executable.
    Exec,
}

/// Contains the usage information for an entry, the resource number of
/// the entry, and where in the blob the entry starts.
#[derive(Debug)]
pub struct IndexEntry {
    pub usage: Usage,
    pub num: u32,
    start: u32,
}

/// Container for list of resource index entries.
#[derive(Debug)]
pub struct ResourceIndex {
    pub entries: HashMap<usize, IndexEntry>,
}

/// Container for chunk metadata. Used for identifying a chunk without
/// loading the full chunk into memory.
#[derive(Debug)]
pub struct ChunkData {
    pub id: String,
    len: u32,
}

/// Representation for loaded blorb chunks
pub enum Chunk {

    /// Chunk returned when the loaded chunk type is unable to be
    /// identified. Per Specification, the machine must ignore unknown
    /// chunks, and this type will be used to do so when necessary.
    Unknown{meta: ChunkData, data: Vec<u8>},

    /// Identifier: 'RIdx'.
    /// Contains a resource index for the IF.
    /// This chunk is mandatory and must be the first chunk in the form.
    ResourceIndex{index: ResourceIndex},

    /// Identifier: 'IFmd',
    /// Contains xml metadata content for the IF.
    Metadata{info: String},

    /// Identifier: 'Fspec',
    /// Contains a reference to a frontispiece image.
    /// This chunk is optional.
    Frontispiece{num: u32},

    /// Identifier: 'GLUL',
    /// Contains Glulx executable
    /// This is a executable resource chunk.
    Glulx{code: Vec<u8>},

    /// Identifier: 'PNG ',
    /// Contains a PNG image
    /// This is a picture resource chunk.
    Png{data: Vec<u8>},

    /// Identifier: 'JPEG',
    /// Contains a JPEG image
    /// This is a picture resource chunk.
    Jpeg{data: Vec<u8>},
}

pub struct Blorb<R: Read + Seek> {
    pub len: u32,
    index: ResourceIndex,
    file: R,
}

impl<R: Read + Seek> Blorb<R> {

    /// Creates a new Blorb from a file. The code goes through the
    /// given game file, validates the file type, and extracts the
    /// basic game objects for the blorb.
    pub fn from_file(file: R) -> Result<Blorb<R>, Error> {
        let mut file = file;

        let form = try!(Blorb::load_chunk_data(&mut file));
        assert_eq!(&form.id, "FORM");

        // Check that the form type is IFRS
        let id = try!(Blorb::load_4bw(&mut file));
        assert_eq!(&id, "IFRS");

        let index = if let Chunk::ResourceIndex{index} =
                try!(Blorb::load_chunk(&mut file)) {
            index
        } else {
            return Err(Error::new(
                ErrorKind::InvalidInput,
                "could not locate index"
            ));
        };

        Ok(Blorb{
            len: form.len,
            index: index,
            file: file,
        })
    }

    /// loads a resource using the given index entry.
    pub fn load_resource(&mut self, num: usize) -> Result<Chunk, Error> {
        let entry = match self.index.entries.get(&num) {
            Some(entry) => entry,
            None => {
                return Err(Error::new(
                    ErrorKind::NotFound,
                    "resource not found"
                ))
            },
        };
        try!(self.file.seek(SeekFrom::Start(entry.start as u64)));

        Blorb::load_chunk(&mut self.file)
    }

    fn load_chunk(file: &mut R) -> Result<Chunk, Error> {
        let meta = try!(Blorb::load_chunk_data(file));

        match meta.id.as_ref() {
            "RIdx" => {
                let num = try!(file.read_u32::<BigEndian>());
                let mut entries = HashMap::with_capacity(num as usize);
                for _ in 0..num {
                    let entry = try!(Blorb::load_index_entry(file));
                    entries.insert(entry.num as usize, entry);
                }

                Ok(Chunk::ResourceIndex{index: ResourceIndex{entries:entries}})
            },
            "GLUL" => {
                let mut data = Vec::with_capacity(meta.len as usize);
                try!(file.take(meta.len as u64).read_to_end(&mut data));
                Ok(Chunk::Glulx{code: data})
            },
            _ => {
                let mut data = Vec::with_capacity(meta.len as usize);
                try!(file.take(meta.len as u64).read_to_end(&mut data));
                Ok(Chunk::Unknown{meta: meta, data: data})
            },
        }
    }

    fn load_index_entry(file: &mut R) -> Result<IndexEntry, Error> {
        let usage = try!(Blorb::load_4bw(file));
        let num = try!(file.read_u32::<BigEndian>());
        let start = try!(file.read_u32::<BigEndian>());

        let usage = match usage.as_ref() {
            "Pict" => Usage::Pict,
            "Snd " => Usage::Snd,
            "Data" => Usage::Data,
            "Exec" => Usage::Exec,
            _ => return Err(Error::new(
                ErrorKind::InvalidInput,
                "could not identify index entry usage"
            )),
        };

        Ok(IndexEntry{usage: usage, num: num, start: start})
    }

    fn load_chunk_data(file: &mut R) -> Result<ChunkData, Error> {
        let id = try!(Blorb::load_4bw(file));
        let len = try!(file.read_u32::<BigEndian>());
        Ok(ChunkData{id: id, len: len})
    }

    /// Load a 4 byte ASCII word from the file
    fn load_4bw(file: &mut R) -> Result<String, Error> {
        let mut id = String::with_capacity(0x4);
        try!(file.take(4).read_to_string(&mut id));
        Ok(id)
    }
}
<|endoftext|>


<commit_before>use std::result;

use piston::input::*;

use rand::Rng;

use super::block::Tetromino;
use super::block::TETROMINOES;

pub type Result<T> = result::Result<T, String>;

use super::BLOCK_SIZE;
use super::BOARD_WIDTH;
use super::BOARD_HEIGHT;

#[derive(PartialEq, Debug, Clone, Copy)]
pub enum GameState {
    Continue,
    PlayerLost,
    PlayerQuit
}

pub struct Board {
    pub cells: [[u8; BOARD_WIDTH as usize]; BOARD_HEIGHT as usize],
    pub current_piece: Tetromino, // current active Tetromino
    pub state: GameState,

    // line_counts[i] = # of filled blocks in row i
    line_counts: [i64; BOARD_HEIGHT as usize]
}

impl Board {
    pub fn init_board() -> Board {
        Board {
            cells: [[0; BOARD_WIDTH as usize]; BOARD_HEIGHT as usize],
            current_piece: *(::rand::thread_rng().choose(&TETROMINOES).unwrap()),
            state: GameState::Continue
            state: GameState::Continue,

            line_counts: [0; BOARD_HEIGHT as usize]
        }
    }

    pub fn handle_key_press(&mut self, inp: Input) {
        match inp {
            Input::Press(but) => {
                match but {
                    Button::Keyboard(Key::Up) => {
                        self.current_piece.rotate_right();

                        // undo rotation if it was invalid...lol
                        if self.current_piece_out_of_bounds() {
                            self.current_piece.rotate_left();
                        }
                    }
                    Button::Keyboard(Key::Down) => {
                        // TODO: drop piece to bottom?
                    }
                    Button::Keyboard(Key::Left) => {
                        if self.current_piece.leftmost() - 1.0 >= 0.0 {
                            self.current_piece.move_left();
                        }
                    }
                    Button::Keyboard(Key::Right) => {
                        if self.current_piece.rightmost() + 1.0 < BOARD_WIDTH as f64  {
                            self.current_piece.move_right();
                        }
                    }
                    _ => {}
                }
            }
            _ => {}
        }
    }

    // iterate thru board and clear the specified row
    fn clear_row(&mut self, row: usize) {
        for col in 0..BOARD_WIDTH {
            self.cells[row][col as usize] = 0;
        }
        self.line_counts[row] = 0;

        // move all cells above (and including) the cleared row down by one
        for r in (1..(row+1)).rev() {
            for col in 0..BOARD_WIDTH {
                self.cells[r as usize][col as usize] = self.cells[(r-1) as usize][col as usize];
            }
            self.line_counts[r as usize] = self.line_counts[(r-1) as usize];
        }
    }

    pub fn clear_line_if_needed(&mut self) {
        // iterate through rows affected by current piece
        let mut rows_affected = Vec::new();
        let current_x = self.current_piece.x_offset;
        let current_y = self.current_piece.y_offset;
        for (r, row) in self.current_piece.blocks.iter().enumerate() {
            for (col, colblock) in row.iter().enumerate() {
                if *colblock == 1 {
                    let board_y: usize = ((r as f64) + current_y) as usize;
                    rows_affected.push(board_y);
                }
            }
        }

        for row in rows_affected.iter() {
            if self.line_counts[*row] == BOARD_WIDTH as i64 {
                self.clear_row(*row);
            }
        }
    }

    pub fn advance_board(&mut self) -> Result<GameState> {
        if self.state != GameState::Continue {
            return Ok(self.state.clone())
        }
        // check if game is over or not
        // check top row of board and see if any of them are filled?
        for (col, colblock) in self.cells[0].iter().enumerate() {
            if *colblock == 1 {
                // TODO: clear current piece?
                return Ok(GameState::PlayerLost)
            }
        }

        // make the existing piece fall
        if self.can_move_current_piece_down() {
            self.current_piece.move_down();
        } else {
            // add piece to board cells
            self.set_piece_on_board();

            // clear line if necessary
            self.clear_line_if_needed();

            // get new piece
            self.current_piece = self.get_next_piece();
        }

        Ok(GameState::Continue)
    }

    fn can_move_current_piece_down(&self) -> bool {
        let above_bottom: bool = self.current_piece.bottommost() + 1.0 < BOARD_HEIGHT as f64;
        if !above_bottom {
            return false
        }

        // check if piece will intersect with a piece already on the board
        let current_x = self.current_piece.x_offset;
        let current_y = self.current_piece.y_offset;
        for (r, row) in self.current_piece.blocks.iter().enumerate() {
            for (col, colblock) in row.iter().enumerate() {
                if *colblock == 1 {
                    let board_x: i64 = (col as i64) + (current_x as i64);
                    let board_y: i64 = ((r as f64) + current_y + 1.0) as i64; // 1 down
                    if self.cells[board_y as usize][board_x as usize] == 1 {
                        return false;
                    }
                }
            }
        }

        above_bottom
    }

    fn current_piece_out_of_bounds(&self) -> bool {
        for (r, row) in self.current_piece.blocks.iter().enumerate() {
            for (col, colblock) in row.iter().enumerate() {
                if *colblock == 1 {
                    if self.current_piece.leftmost() < 0.0 || self.current_piece.rightmost() >= BOARD_WIDTH as f64 || self.current_piece.bottommost() >= BOARD_HEIGHT as f64 {
                        return true
                    }
                }
            }
        }
        false
    }

    pub fn set_piece_on_board(&mut self) {
        let current_x = self.current_piece.x_offset;
        let current_y = self.current_piece.y_offset;
        for (r, row) in self.current_piece.blocks.iter().enumerate() {
            for (col, colblock) in row.iter().enumerate() {
                if *colblock == 1 {
                    let x: i64 = (col as i64) + (current_x as i64);
                    let y: i64 = (r as i64) + (current_y as i64);
                    self.cells[y as usize][x as usize] = 1;
                    self.line_counts[y as usize] += 1;
                }
            }
        }
    }

    pub fn get_next_piece(&self) -> Tetromino {
        // add new piece to the board (randomly chosen)
        *(::rand::thread_rng().choose(&TETROMINOES).unwrap())
    }

    pub fn draw_board(self) -> Result<()> {
        // draw the board ?
        Ok(())
    }
}<commit_msg>fix compile error<commit_after>use std::result;

use piston::input::*;

use rand::Rng;

use super::block::Tetromino;
use super::block::TETROMINOES;

pub type Result<T> = result::Result<T, String>;

use super::BLOCK_SIZE;
use super::BOARD_WIDTH;
use super::BOARD_HEIGHT;

#[derive(PartialEq, Debug, Clone, Copy)]
pub enum GameState {
    Continue,
    PlayerLost,
    PlayerQuit
}

pub struct Board {
    pub cells: [[u8; BOARD_WIDTH as usize]; BOARD_HEIGHT as usize],
    pub current_piece: Tetromino, // current active Tetromino
    pub state: GameState,

    // line_counts[i] = # of filled blocks in row i
    line_counts: [i64; BOARD_HEIGHT as usize]
}

impl Board {
    pub fn init_board() -> Board {
        Board {
            cells: [[0; BOARD_WIDTH as usize]; BOARD_HEIGHT as usize],
            current_piece: *(::rand::thread_rng().choose(&TETROMINOES).unwrap()),
            state: GameState::Continue,

            line_counts: [0; BOARD_HEIGHT as usize]
        }
    }

    pub fn handle_key_press(&mut self, inp: Input) {
        match inp {
            Input::Press(but) => {
                match but {
                    Button::Keyboard(Key::Up) => {
                        self.current_piece.rotate_right();

                        // undo rotation if it was invalid...lol
                        if self.current_piece_out_of_bounds() {
                            self.current_piece.rotate_left();
                        }
                    }
                    Button::Keyboard(Key::Down) => {
                        // TODO: drop piece to bottom?
                    }
                    Button::Keyboard(Key::Left) => {
                        if self.current_piece.leftmost() - 1.0 >= 0.0 {
                            self.current_piece.move_left();
                        }
                    }
                    Button::Keyboard(Key::Right) => {
                        if self.current_piece.rightmost() + 1.0 < BOARD_WIDTH as f64  {
                            self.current_piece.move_right();
                        }
                    }
                    _ => {}
                }
            }
            _ => {}
        }
    }

    // iterate thru board and clear the specified row
    fn clear_row(&mut self, row: usize) {
        for col in 0..BOARD_WIDTH {
            self.cells[row][col as usize] = 0;
        }
        self.line_counts[row] = 0;

        // move all cells above (and including) the cleared row down by one
        for r in (1..(row+1)).rev() {
            for col in 0..BOARD_WIDTH {
                self.cells[r as usize][col as usize] = self.cells[(r-1) as usize][col as usize];
            }
            self.line_counts[r as usize] = self.line_counts[(r-1) as usize];
        }
    }

    pub fn clear_line_if_needed(&mut self) {
        // iterate through rows affected by current piece
        let mut rows_affected = Vec::new();
        let current_x = self.current_piece.x_offset;
        let current_y = self.current_piece.y_offset;
        for (r, row) in self.current_piece.blocks.iter().enumerate() {
            for (col, colblock) in row.iter().enumerate() {
                if *colblock == 1 {
                    let board_y: usize = ((r as f64) + current_y) as usize;
                    rows_affected.push(board_y);
                }
            }
        }

        for row in rows_affected.iter() {
            if self.line_counts[*row] == BOARD_WIDTH as i64 {
                self.clear_row(*row);
            }
        }
    }

    pub fn advance_board(&mut self) -> Result<GameState> {
        if self.state != GameState::Continue {
            return Ok(self.state.clone())
        }
        // check if game is over or not
        // check top row of board and see if any of them are filled?
        for (col, colblock) in self.cells[0].iter().enumerate() {
            if *colblock == 1 {
                // TODO: clear current piece?
                return Ok(GameState::PlayerLost)
            }
        }

        // make the existing piece fall
        if self.can_move_current_piece_down() {
            self.current_piece.move_down();
        } else {
            // add piece to board cells
            self.set_piece_on_board();

            // clear line if necessary
            self.clear_line_if_needed();

            // get new piece
            self.current_piece = self.get_next_piece();
        }

        Ok(GameState::Continue)
    }

    fn can_move_current_piece_down(&self) -> bool {
        let above_bottom: bool = self.current_piece.bottommost() + 1.0 < BOARD_HEIGHT as f64;
        if !above_bottom {
            return false
        }

        // check if piece will intersect with a piece already on the board
        let current_x = self.current_piece.x_offset;
        let current_y = self.current_piece.y_offset;
        for (r, row) in self.current_piece.blocks.iter().enumerate() {
            for (col, colblock) in row.iter().enumerate() {
                if *colblock == 1 {
                    let board_x: i64 = (col as i64) + (current_x as i64);
                    let board_y: i64 = ((r as f64) + current_y + 1.0) as i64; // 1 down
                    if self.cells[board_y as usize][board_x as usize] == 1 {
                        return false;
                    }
                }
            }
        }

        above_bottom
    }

    fn current_piece_out_of_bounds(&self) -> bool {
        for (r, row) in self.current_piece.blocks.iter().enumerate() {
            for (col, colblock) in row.iter().enumerate() {
                if *colblock == 1 {
                    if self.current_piece.leftmost() < 0.0 || self.current_piece.rightmost() >= BOARD_WIDTH as f64 || self.current_piece.bottommost() >= BOARD_HEIGHT as f64 {
                        return true
                    }
                }
            }
        }
        false
    }

    pub fn set_piece_on_board(&mut self) {
        let current_x = self.current_piece.x_offset;
        let current_y = self.current_piece.y_offset;
        for (r, row) in self.current_piece.blocks.iter().enumerate() {
            for (col, colblock) in row.iter().enumerate() {
                if *colblock == 1 {
                    let x: i64 = (col as i64) + (current_x as i64);
                    let y: i64 = (r as i64) + (current_y as i64);
                    self.cells[y as usize][x as usize] = 1;
                    self.line_counts[y as usize] += 1;
                }
            }
        }
    }

    pub fn get_next_piece(&self) -> Tetromino {
        // add new piece to the board (randomly chosen)
        *(::rand::thread_rng().choose(&TETROMINOES).unwrap())
    }

    pub fn draw_board(self) -> Result<()> {
        // draw the board ?
        Ok(())
    }
}<|endoftext|>


<commit_before>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2015  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use gtype::GType;
use types::gpointer;

use gobject as ffi;

use std::boxed::into_raw as box_into_raw;
use std::ffi::CString;
use std::mem;

pub trait BoxedType {
    fn get_type() -> GType;
    unsafe fn from_ptr(ptr: gpointer) -> Self;
    unsafe fn into_ptr(self) -> gpointer;
}

pub fn type_of<T>() -> GType where T: BoxedType
{
    <T as BoxedType>::get_type()
}

extern "C" fn box_copy<T>(raw: gpointer) -> gpointer
    where T: Clone
{
    let boxed: Box<T> = unsafe { Box::from_raw(raw as *mut T) };
    let copy: Box<T> = boxed.clone();
    unsafe {
        // Prevent the original value from being dropped
        box_into_raw(boxed);
        box_into_raw(copy) as gpointer
    }
}

extern "C" fn box_free<T>(raw: gpointer) {
    let boxed: Box<T> = unsafe { Box::from_raw(raw as *mut T) };
    mem::drop(boxed);
}

pub fn register_box_type<T>(name: &str) -> GType where T: Clone + Send {
    let c_name = CString::new(name).unwrap();
    let raw = unsafe {
        ffi::g_boxed_type_register_static(c_name.as_ptr(),
                                          box_copy::<T>,
                                          box_free::<T>)
    };
    assert!(raw != 0, "failed to register type \"{}\"", name);
    unsafe { GType::from_raw(raw) }
}

pub unsafe trait BoxRegistered : Clone + Send {
    fn box_type() -> GType;
}

impl<T> BoxedType for Box<T> where T: BoxRegistered {

    fn get_type() -> GType {
        <T as BoxRegistered>::box_type()
    }

    unsafe fn from_ptr(raw: gpointer) -> Box<T> {
        Box::from_raw(raw as *mut T)
    }

    unsafe fn into_ptr(self) -> gpointer {
        box_into_raw(self) as gpointer
    }
}
<commit_msg>boxed: update to recent nightly Rust<commit_after>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2015  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use gtype::GType;
use types::gpointer;

use gobject as ffi;

use std::boxed::into_raw as box_into_raw;
use std::ffi::CString;
use std::mem;

pub trait BoxedType {
    fn get_type() -> GType;
    unsafe fn from_ptr(ptr: gpointer) -> Self;
    unsafe fn into_ptr(self) -> gpointer;
}

pub fn type_of<T>() -> GType where T: BoxedType
{
    <T as BoxedType>::get_type()
}

extern "C" fn box_copy<T>(raw: gpointer) -> gpointer
    where T: Clone
{
    let boxed: Box<T> = unsafe { Box::from_raw(raw as *mut T) };
    let copy: Box<T> = boxed.clone();
    // Prevent the original value from being dropped
    box_into_raw(boxed);
    box_into_raw(copy) as gpointer
}

extern "C" fn box_free<T>(raw: gpointer) {
    let boxed: Box<T> = unsafe { Box::from_raw(raw as *mut T) };
    mem::drop(boxed);
}

pub fn register_box_type<T>(name: &str) -> GType where T: Clone + Send {
    let c_name = CString::new(name).unwrap();
    let raw = unsafe {
        ffi::g_boxed_type_register_static(c_name.as_ptr(),
                                          box_copy::<T>,
                                          box_free::<T>)
    };
    assert!(raw != 0, "failed to register type \"{}\"", name);
    unsafe { GType::from_raw(raw) }
}

pub unsafe trait BoxRegistered : Clone + Send {
    fn box_type() -> GType;
}

impl<T> BoxedType for Box<T> where T: BoxRegistered {

    fn get_type() -> GType {
        <T as BoxRegistered>::box_type()
    }

    unsafe fn from_ptr(raw: gpointer) -> Box<T> {
        Box::from_raw(raw as *mut T)
    }

    unsafe fn into_ptr(self) -> gpointer {
        box_into_raw(self) as gpointer
    }
}
<|endoftext|>


<commit_before>use super::*;

use std::iter;

/// Doc-comments are promoted to attributes that have `is_sugared_doc` = true
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Attribute {
    pub style: AttrStyle,
    pub name: Ident,
    pub tts: Vec<TokenTree>,
    pub is_sugared_doc: bool,
}

impl Attribute {
    pub fn meta_item(&self) -> Option<MetaItem> {
        if self.tts.is_empty() {
            return Some(MetaItem::Word);
        }

        if self.tts.len() == 1 {
            if let TokenTree::Delimited(Delimited { delim: DelimToken::Paren, ref tts }) = self.tts[0] {
                fn nested_meta_item_from_tokens(tts: &[TokenTree]) -> Option<(NestedMetaItem, &[TokenTree])> {
                    assert!(!tts.is_empty());

                    match tts[0] {
                        TokenTree::Token(Token::Literal(ref lit)) => {
                            Some((NestedMetaItem::Literal(lit.clone()), &tts[1..]))
                        }

                        TokenTree::Token(Token::Ident(ref ident)) => {
                            if tts.len() >= 3 {
                                match (&tts[1], &tts[2]) {
                                    (&TokenTree::Token(Token::Eq), &TokenTree::Token(Token::Literal(ref lit))) => {
                                        return Some((NestedMetaItem::MetaItem(ident.clone(), MetaItem::NameValue(lit.clone())), &tts[3..]));
                                    }

                                    _ => {}
                                }
                            }

                            if tts.len() >= 2 {
                                if let TokenTree::Delimited(Delimited { delim: DelimToken::Paren, tts: ref inner_tts }) = tts[1] {
                                    return match list_of_nested_meta_items_from_tokens(vec![], inner_tts) {
                                        Some(nested_meta_items) => {
                                            Some((NestedMetaItem::MetaItem(ident.clone(), MetaItem::List(nested_meta_items)), &tts[2..]))
                                        }

                                        None => None
                                    };
                                }
                            }

                            Some((NestedMetaItem::MetaItem(ident.clone(), MetaItem::Word), &tts[1..]))
                        }

                        _ => None
                    }
                }

                fn list_of_nested_meta_items_from_tokens(mut result: Vec<NestedMetaItem>, tts: &[TokenTree]) -> Option<Vec<NestedMetaItem>> {
                    if tts.is_empty() {
                        return Some(result);
                    }

                    match nested_meta_item_from_tokens(tts) {
                        Some((nested_meta_item, rest)) => {
                            result.push(nested_meta_item);
                            if rest.is_empty() {
                                list_of_nested_meta_items_from_tokens(result, rest)
                            }
                            else {
                                if let TokenTree::Token(Token::Comma) = rest[0] {
                                    list_of_nested_meta_items_from_tokens(result, &rest[1..])
                                }
                                else {
                                   None
                                }
                            }
                        }

                        None => None
                    }
                }

                if let Some(nested_meta_items) = list_of_nested_meta_items_from_tokens(vec![], tts) {
                    return Some(MetaItem::List(nested_meta_items));
                }
            }
        }

        if self.tts.len() == 2 {
            match (&self.tts[0], &self.tts[1]) {
                (&TokenTree::Token(Token::Eq), &TokenTree::Token(Token::Literal(ref lit))) => {
                    return Some(MetaItem::NameValue(lit.clone()));
                }

                _ => {}
            }
        }

        None
    }
}

/// Distinguishes between Attributes that decorate items and Attributes that
/// are contained as statements within items. These two cases need to be
/// distinguished for pretty-printing.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum AttrStyle {
    /// Attribute of the form `#![...]`.
    Outer,

    /// Attribute of the form `#[...]`.
    Inner,
}

/// A compile-time attribute item.
///
/// E.g. `#[test]`, `#[derive(..)]` or `#[feature = "foo"]`
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum MetaItem {
    /// Word meta item.
    ///
    /// E.g. `test` as in `#[test]`
    Word,

    /// List meta item.
    ///
    /// E.g. `derive(..)` as in `#[derive(..)]`
    List(Vec<NestedMetaItem>),

    /// Name-value meta item.
    ///
    /// E.g. `feature = "foo"` as in `#[feature = "foo"]`
    NameValue(Lit),
}

/// Possible values inside of compile-time attribute lists.
///
/// E.g. the '..' in `#[name(..)]`.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum NestedMetaItem {
    /// A full `MetaItem`.
    ///
    /// E.g. `Copy` in `#[derive(Copy)]` would be a `(Ident::from("Copy"), MetaItem::Word)`.
    MetaItem(Ident, MetaItem),

    /// A Rust literal.
    ///
    /// E.g. `"name"` in `#[rename("name")]`.
    Literal(Lit),
}

pub trait FilterAttrs<'a> {
    type Ret: Iterator<Item = &'a Attribute>;

    fn outer(self) -> Self::Ret;
    fn inner(self) -> Self::Ret;
}

impl<'a, T> FilterAttrs<'a> for T
    where T: IntoIterator<Item = &'a Attribute>
{
    type Ret = iter::Filter<T::IntoIter, fn(&&Attribute) -> bool>;

    fn outer(self) -> Self::Ret {
        fn is_outer(attr: &&Attribute) -> bool {
            attr.style == AttrStyle::Outer
        }
        self.into_iter().filter(is_outer)
    }

    fn inner(self) -> Self::Ret {
        fn is_inner(attr: &&Attribute) -> bool {
            attr.style == AttrStyle::Inner
        }
        self.into_iter().filter(is_inner)
    }
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;
    use ident::parsing::ident;
    use mac::parsing::token_trees;
    use synom::space::{block_comment, whitespace};

    #[cfg(feature = "full")]
    named!(pub inner_attr -> Attribute, alt!(
        do_parse!(
            punct!("#") >>
            punct!("!") >>
            name_and_tts: delimited!(
                punct!("["),
                tuple!(ident, token_trees),
                punct!("]")
            ) >>
            ({
                let (name, tts) = name_and_tts;

                Attribute {
                    style: AttrStyle::Inner,
                    name: name,
                    tts: tts,
                    is_sugared_doc: false,
                }
            })
        )
        |
        do_parse!(
            punct!("//!") >>
            content: take_until!("\n") >>
            (Attribute {
                style: AttrStyle::Inner,
                name: "doc".into(),
                tts: vec![
                    TokenTree::Token(Token::Eq),
                    TokenTree::Token(Token::Literal(Lit::Str(format!("//!{}", content).into(), StrStyle::Cooked))),
                ],
                is_sugared_doc: true,
            })
        )
        |
        do_parse!(
            option!(whitespace) >>
            peek!(tag!("/*!")) >>
            com: block_comment >>
            (Attribute {
                style: AttrStyle::Inner,
                name: "doc".into(),
                tts: vec![
                    TokenTree::Token(Token::Eq),
                    TokenTree::Token(Token::Literal(Lit::Str(com.into(), StrStyle::Cooked))),
                ],
                is_sugared_doc: true,
            })
        )
    ));

    named!(pub outer_attr -> Attribute, alt!(
        do_parse!(
            punct!("#") >>
            name_and_tts: delimited!(
                punct!("["),
                tuple!(ident, token_trees),
                punct!("]")
            ) >>
            ({
                let (name, tts) = name_and_tts;

                Attribute {
                    style: AttrStyle::Outer,
                    name: name,
                    tts: tts,
                    is_sugared_doc: false,
                }
            })
        )
        |
        do_parse!(
            punct!("///") >>
            not!(tag!("/")) >>
            content: take_until!("\n") >>
            (Attribute {
                style: AttrStyle::Outer,
                name: "doc".into(),
                tts: vec![
                    TokenTree::Token(Token::Eq),
                    TokenTree::Token(Token::Literal(Lit::Str(format!("///{}", content).into(), StrStyle::Cooked))),
                ],
                is_sugared_doc: true,
            })
        )
        |
        do_parse!(
            option!(whitespace) >>
            peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
            com: block_comment >>
            (Attribute {
                style: AttrStyle::Outer,
                name: "doc".into(),
                tts: vec![
                    TokenTree::Token(Token::Eq),
                    TokenTree::Token(Token::Literal(Lit::Str(com.into(), StrStyle::Cooked))),
                ],
                is_sugared_doc: true,
            })
        )
    ));
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use lit::{Lit, StrStyle};
    use quote::{Tokens, ToTokens};

    impl ToTokens for Attribute {
        fn to_tokens(&self, tokens: &mut Tokens) {
            if let Attribute { style, ref name, ref tts, is_sugared_doc: true } = *self {
                if name == "doc" && tts.len() == 2 {
                    match (&tts[0], &tts[1]) {
                        (&TokenTree::Token(Token::Eq),
                         &TokenTree::Token(Token::Literal(Lit::Str(ref value, StrStyle::Cooked)))) => {
                            match style {
                                AttrStyle::Inner if value.starts_with("//!") => {
                                    tokens.append(&format!("{}\n", value));
                                    return;
                                }
                                AttrStyle::Inner if value.starts_with("/*!") => {
                                    tokens.append(value);
                                    return;
                                }
                                AttrStyle::Outer if value.starts_with("///") => {
                                    tokens.append(&format!("{}\n", value));
                                    return;
                                }
                                AttrStyle::Outer if value.starts_with("/**") => {
                                    tokens.append(value);
                                    return;
                                }
                                _ => {}
                            }
                        }

                        _ => {}
                    }
                }
            }

            tokens.append("#");
            if let AttrStyle::Inner = self.style {
                tokens.append("!");
            }
            tokens.append("[");
            self.name.to_tokens(tokens);
            tokens.append_all(&self.tts);
            tokens.append("]");
        }
    }

    impl ToTokens for MetaItem {
        fn to_tokens(&self, tokens: &mut Tokens) {
            match *self {
                MetaItem::Word => {}
                MetaItem::List(ref inner) => {
                    tokens.append("(");
                    tokens.append_separated(inner, ",");
                    tokens.append(")");
                }
                MetaItem::NameValue(ref value) => {
                    tokens.append("=");
                    value.to_tokens(tokens);
                }
            }
        }
    }

    impl ToTokens for NestedMetaItem {
        fn to_tokens(&self, tokens: &mut Tokens) {
            match *self {
                NestedMetaItem::MetaItem(ref ident, ref nested) => {
                    ident.to_tokens(tokens);
                    nested.to_tokens(tokens);
                }
                NestedMetaItem::Literal(ref lit) => {
                    lit.to_tokens(tokens);
                }
            }
        }
    }
}
<commit_msg>fixup! Fixed build on 1.12.1 and 1.13.0<commit_after>use super::*;

use std::iter;

/// Doc-comments are promoted to attributes that have `is_sugared_doc` = true
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Attribute {
    pub style: AttrStyle,
    pub name: Ident,
    pub tts: Vec<TokenTree>,
    pub is_sugared_doc: bool,
}

impl Attribute {
    pub fn meta_item(&self) -> Option<MetaItem> {
        if self.tts.is_empty() {
            return Some(MetaItem::Word);
        }

        if self.tts.len() == 1 {
            if let TokenTree::Delimited(Delimited { delim: DelimToken::Paren, ref tts }) = self.tts[0] {
                fn nested_meta_item_from_tokens(tts: &[TokenTree]) -> Option<(NestedMetaItem, &[TokenTree])> {
                    assert!(!tts.is_empty());

                    match tts[0] {
                        TokenTree::Token(Token::Literal(ref lit)) => {
                            Some((NestedMetaItem::Literal(lit.clone()), &tts[1..]))
                        }

                        TokenTree::Token(Token::Ident(ref ident)) => {
                            if tts.len() >= 3 {
                                match (&tts[1], &tts[2]) {
                                    (&TokenTree::Token(Token::Eq), &TokenTree::Token(Token::Literal(ref lit))) => {
                                        return Some((NestedMetaItem::MetaItem(ident.clone(), MetaItem::NameValue(lit.clone())), &tts[3..]));
                                    }

                                    _ => {}
                                }
                            }

                            if tts.len() >= 2 {
                                if let TokenTree::Delimited(Delimited { delim: DelimToken::Paren, tts: ref inner_tts }) = tts[1] {
                                    return match list_of_nested_meta_items_from_tokens(vec![], inner_tts) {
                                        Some(nested_meta_items) => {
                                            Some((NestedMetaItem::MetaItem(ident.clone(), MetaItem::List(nested_meta_items)), &tts[2..]))
                                        }

                                        None => None
                                    };
                                }
                            }

                            Some((NestedMetaItem::MetaItem(ident.clone(), MetaItem::Word), &tts[1..]))
                        }

                        _ => None
                    }
                }

                fn list_of_nested_meta_items_from_tokens(mut result: Vec<NestedMetaItem>, tts: &[TokenTree]) -> Option<Vec<NestedMetaItem>> {
                    if tts.is_empty() {
                        return Some(result);
                    }

                    match nested_meta_item_from_tokens(tts) {
                        Some((nested_meta_item, rest)) => {
                            result.push(nested_meta_item);
                            if rest.is_empty() {
                                list_of_nested_meta_items_from_tokens(result, rest)
                            }
                            else {
                                if let TokenTree::Token(Token::Comma) = rest[0] {
                                    list_of_nested_meta_items_from_tokens(result, &rest[1..])
                                }
                                else {
                                   None
                                }
                            }
                        }

                        None => None
                    }
                }

                if let Some(nested_meta_items) = list_of_nested_meta_items_from_tokens(vec![], tts) {
                    return Some(MetaItem::List(nested_meta_items));
                }
            }
        }

        if self.tts.len() == 2 {
            match (&self.tts[0], &self.tts[1]) {
                (&TokenTree::Token(Token::Eq), &TokenTree::Token(Token::Literal(ref lit))) => {
                    return Some(MetaItem::NameValue(lit.clone()));
                }

                _ => {}
            }
        }

        None
    }
}

/// Distinguishes between Attributes that decorate items and Attributes that
/// are contained as statements within items. These two cases need to be
/// distinguished for pretty-printing.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum AttrStyle {
    /// Attribute of the form `#![...]`.
    Outer,

    /// Attribute of the form `#[...]`.
    Inner,
}

/// A compile-time attribute item.
///
/// E.g. `#[test]`, `#[derive(..)]` or `#[feature = "foo"]`
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum MetaItem {
    /// Word meta item.
    ///
    /// E.g. `test` as in `#[test]`
    Word,

    /// List meta item.
    ///
    /// E.g. `derive(..)` as in `#[derive(..)]`
    List(Vec<NestedMetaItem>),

    /// Name-value meta item.
    ///
    /// E.g. `feature = "foo"` as in `#[feature = "foo"]`
    NameValue(Lit),
}

/// Possible values inside of compile-time attribute lists.
///
/// E.g. the '..' in `#[name(..)]`.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum NestedMetaItem {
    /// A full `MetaItem`.
    ///
    /// E.g. `Copy` in `#[derive(Copy)]` would be a `(Ident::from("Copy"), MetaItem::Word)`.
    MetaItem(Ident, MetaItem),

    /// A Rust literal.
    ///
    /// E.g. `"name"` in `#[rename("name")]`.
    Literal(Lit),
}

pub trait FilterAttrs<'a> {
    type Ret: Iterator<Item = &'a Attribute>;

    fn outer(self) -> Self::Ret;
    fn inner(self) -> Self::Ret;
}

impl<'a, T> FilterAttrs<'a> for T
    where T: IntoIterator<Item = &'a Attribute>
{
    type Ret = iter::Filter<T::IntoIter, fn(&&Attribute) -> bool>;

    fn outer(self) -> Self::Ret {
        fn is_outer(attr: &&Attribute) -> bool {
            attr.style == AttrStyle::Outer
        }
        self.into_iter().filter(is_outer)
    }

    fn inner(self) -> Self::Ret {
        fn is_inner(attr: &&Attribute) -> bool {
            attr.style == AttrStyle::Inner
        }
        self.into_iter().filter(is_inner)
    }
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;
    use ident::parsing::ident;
    use lit::{Lit, StrStyle};
    use mac::{Token, TokenTree};
    use mac::parsing::token_trees;
    use synom::space::{block_comment, whitespace};

    #[cfg(feature = "full")]
    named!(pub inner_attr -> Attribute, alt!(
        do_parse!(
            punct!("#") >>
            punct!("!") >>
            name_and_tts: delimited!(
                punct!("["),
                tuple!(ident, token_trees),
                punct!("]")
            ) >>
            ({
                let (name, tts) = name_and_tts;

                Attribute {
                    style: AttrStyle::Inner,
                    name: name,
                    tts: tts,
                    is_sugared_doc: false,
                }
            })
        )
        |
        do_parse!(
            punct!("//!") >>
            content: take_until!("\n") >>
            (Attribute {
                style: AttrStyle::Inner,
                name: "doc".into(),
                tts: vec![
                    TokenTree::Token(Token::Eq),
                    TokenTree::Token(Token::Literal(Lit::Str(format!("//!{}", content).into(), StrStyle::Cooked))),
                ],
                is_sugared_doc: true,
            })
        )
        |
        do_parse!(
            option!(whitespace) >>
            peek!(tag!("/*!")) >>
            com: block_comment >>
            (Attribute {
                style: AttrStyle::Inner,
                name: "doc".into(),
                tts: vec![
                    TokenTree::Token(Token::Eq),
                    TokenTree::Token(Token::Literal(Lit::Str(com.into(), StrStyle::Cooked))),
                ],
                is_sugared_doc: true,
            })
        )
    ));

    named!(pub outer_attr -> Attribute, alt!(
        do_parse!(
            punct!("#") >>
            name_and_tts: delimited!(
                punct!("["),
                tuple!(ident, token_trees),
                punct!("]")
            ) >>
            ({
                let (name, tts) = name_and_tts;

                Attribute {
                    style: AttrStyle::Outer,
                    name: name,
                    tts: tts,
                    is_sugared_doc: false,
                }
            })
        )
        |
        do_parse!(
            punct!("///") >>
            not!(tag!("/")) >>
            content: take_until!("\n") >>
            (Attribute {
                style: AttrStyle::Outer,
                name: "doc".into(),
                tts: vec![
                    TokenTree::Token(Token::Eq),
                    TokenTree::Token(Token::Literal(Lit::Str(format!("///{}", content).into(), StrStyle::Cooked))),
                ],
                is_sugared_doc: true,
            })
        )
        |
        do_parse!(
            option!(whitespace) >>
            peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
            com: block_comment >>
            (Attribute {
                style: AttrStyle::Outer,
                name: "doc".into(),
                tts: vec![
                    TokenTree::Token(Token::Eq),
                    TokenTree::Token(Token::Literal(Lit::Str(com.into(), StrStyle::Cooked))),
                ],
                is_sugared_doc: true,
            })
        )
    ));
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use lit::{Lit, StrStyle};
    use mac::{Token, TokenTree};
    use quote::{Tokens, ToTokens};

    impl ToTokens for Attribute {
        fn to_tokens(&self, tokens: &mut Tokens) {
            if let Attribute { style, ref name, ref tts, is_sugared_doc: true } = *self {
                if name == "doc" && tts.len() == 2 {
                    match (&tts[0], &tts[1]) {
                        (&TokenTree::Token(Token::Eq),
                         &TokenTree::Token(Token::Literal(Lit::Str(ref value, StrStyle::Cooked)))) => {
                            match style {
                                AttrStyle::Inner if value.starts_with("//!") => {
                                    tokens.append(&format!("{}\n", value));
                                    return;
                                }
                                AttrStyle::Inner if value.starts_with("/*!") => {
                                    tokens.append(value);
                                    return;
                                }
                                AttrStyle::Outer if value.starts_with("///") => {
                                    tokens.append(&format!("{}\n", value));
                                    return;
                                }
                                AttrStyle::Outer if value.starts_with("/**") => {
                                    tokens.append(value);
                                    return;
                                }
                                _ => {}
                            }
                        }

                        _ => {}
                    }
                }
            }

            tokens.append("#");
            if let AttrStyle::Inner = self.style {
                tokens.append("!");
            }
            tokens.append("[");
            self.name.to_tokens(tokens);
            tokens.append_all(&self.tts);
            tokens.append("]");
        }
    }

    impl ToTokens for MetaItem {
        fn to_tokens(&self, tokens: &mut Tokens) {
            match *self {
                MetaItem::Word => {}
                MetaItem::List(ref inner) => {
                    tokens.append("(");
                    tokens.append_separated(inner, ",");
                    tokens.append(")");
                }
                MetaItem::NameValue(ref value) => {
                    tokens.append("=");
                    value.to_tokens(tokens);
                }
            }
        }
    }

    impl ToTokens for NestedMetaItem {
        fn to_tokens(&self, tokens: &mut Tokens) {
            match *self {
                NestedMetaItem::MetaItem(ref ident, ref nested) => {
                    ident.to_tokens(tokens);
                    nested.to_tokens(tokens);
                }
                NestedMetaItem::Literal(ref lit) => {
                    lit.to_tokens(tokens);
                }
            }
        }
    }
}
<|endoftext|>