<commit_before>use structs::{ Map, SnakeInfo };
use util;

#[derive(PartialEq, Debug)]
pub enum Tile<'a> {
    Food { coordinate: (i32,i32) },
    Obstacle { coordinate: (i32,i32) },
    Empty { coordinate: (i32,i32) },
    SnakeHead { coordinate: (i32,i32), snake: &'a SnakeInfo },
    SnakeBody { coordinate: (i32,i32), snake: &'a SnakeInfo }
}

#[derive(Debug)]
pub enum Direction {
    Down,
    Up,
    Left,
    Right
}

pub fn direction_as_string(direction: &Direction) -> String {
    let s = match direction {
        &Direction::Down => "DOWN",
        &Direction::Up => "UP",
        &Direction::Left => "LEFT",
        &Direction::Right => "RIGHT"
    };

    String::from(s)
}

pub fn direction_as_movement_delta(direction: &Direction) -> (i32,i32) {
    match direction {
        &Direction::Down => (0, 1),
        &Direction::Up => (0, -1),
        &Direction::Left => (-1, 0),
        &Direction::Right => (1, 0)
    }
}

impl Map {
    pub fn get_snake_by_id<'a>(&'a self, id: &String) -> Option<&'a SnakeInfo> {
        self.snakeInfos.iter().find(|s| &s.id == id)
    }

    pub fn get_tile_at(&self, coordinate: (i32,i32)) -> Tile {
        let position = util::translate_coordinate(coordinate, self.width);
        let snake_at_tile = self.snakeInfos.iter().find(|s| s.positions.contains(&position));

        if self.obstaclePositions.contains(&position) {
            Tile::Obstacle { coordinate: coordinate }
        } else if self.foodPositions.contains(&position) {
            Tile::Food { coordinate: coordinate }
        } else if snake_at_tile.is_some() {
            let s = snake_at_tile.unwrap();
            if s.positions[0] == position {
                Tile::SnakeHead { coordinate: coordinate, snake: s }
            } else {
                Tile::SnakeBody { coordinate: coordinate, snake: s }
            }
        } else {
            Tile::Empty { coordinate: coordinate }
        }
    }

    pub fn is_tile_available_for_movement(&self, coordinate: (i32,i32)) -> bool {
        let tile = self.get_tile_at(coordinate);
        match tile {
            Tile::Empty { coordinate: _ } => true,
            Tile::Food { coordinate: _ } => true,
            _ => false
        }
    }

    pub fn can_snake_move_in_direction(&self, snake: &SnakeInfo, direction: Direction) -> bool {
        let (xd,yd) = direction_as_movement_delta(&direction);
        let (x,y) = util::translate_position(snake.positions[0], self.width);

        self.is_tile_available_for_movement((x+xd,y+yd))
    }

    #[allow(dead_code)]
    pub fn is_coordinate_out_of_bounds(&self, coordinate: (i32,i32)) -> bool {
        let (x,y) = coordinate;
        x < 0 || x >= self.width || y < 0 || y >= self.height
    }
}

#[cfg(test)]
mod test {
    use util::{ translate_coordinate };
    use maputil::{ Direction, Tile };
    use messages::{ Map, SnakeInfo };

    const MAP_WIDTH: i32 = 3;

    fn get_snake_one() -> SnakeInfo {
        SnakeInfo {
            name: String::from("1"),
            points: 0,
            tailProtectedForGameTicks: 0,
            positions: vec![translate_coordinate((1,1), MAP_WIDTH),
                            translate_coordinate((0,1), MAP_WIDTH)],
            id: String::from("1")
        }
    }

    fn get_snake_two() -> SnakeInfo {
        SnakeInfo {
            name: String::from("2"),
            points: 0,
            tailProtectedForGameTicks: 0,
            positions: vec![translate_coordinate((1,2), MAP_WIDTH)],
            id: String::from("2")
        }
    }

    // The map used for testing, 1 and 2 represents the snakes
    //yx012
    //0  F
    //1 11#
    //2  2
    fn get_test_map() -> Map {
        Map {
            type_: String::from("type"),
            width: MAP_WIDTH,
            height: MAP_WIDTH,
            worldTick: 0,
            snakeInfos: vec![get_snake_one(), get_snake_two()],
            foodPositions: vec![translate_coordinate((1,0),  MAP_WIDTH)],
            obstaclePositions: vec![translate_coordinate((2,1), MAP_WIDTH)],
            receivingPlayerId: Some(String::from("1"))
        }
    }

    #[test]
    fn snake_can_be_found_by_id() {
        let map = get_test_map();
        let id = map.receivingPlayerId.as_ref().unwrap();
        let s = map.get_snake_by_id(id);
        let found_id = &s.unwrap().id;
        assert_eq!(id, found_id);
    }

    #[test]
    fn tile_is_correctly_found() {
        let map = get_test_map();
        let snake_one = get_snake_one();
        let snake_two = get_snake_two();
        let tiles =
            vec![
                vec![Tile::Empty{ coordinate: (0,0) },
                     Tile::Food{ coordinate: (1,0) },
                     Tile::Empty{ coordinate: (2,0) }],
                vec![Tile::SnakeBody{ coordinate: (0,1), snake: &snake_one },
                     Tile::SnakeHead{ coordinate: (1,1), snake: &snake_one },
                     Tile::Obstacle{ coordinate: (2,1)}],
                vec![Tile::Empty{ coordinate: (0,2) },
                     Tile::SnakeHead{ coordinate: (1,2), snake: &snake_two },
                     Tile::Empty{ coordinate:(2,2) }]];
        for y in 0..map.width {
            for x in 0..map.height {
                assert_eq!(tiles[y as usize][x as usize],
                           map.get_tile_at((x,y)));
            }
        }
    }

    #[test]
    fn tile_is_correctly_marked_as_movable() {
        let map = get_test_map();
        let tiles = vec![vec![true, true, true],
                         vec![false, false, false],
                         vec![true, false, true]];

        for y in 0..map.height {
            for x in 0..map.width {
                assert_eq!(tiles[y as usize][x as usize],
                           map.is_tile_available_for_movement((x,y)));
            }
        }
    }

    #[test]
    fn can_snake_move_identifies_correctly() {
        let map = get_test_map();
        let id = map.receivingPlayerId.as_ref().unwrap();
        let snake = map.get_snake_by_id(id).unwrap();

        assert_eq!(true, map.can_snake_move_in_direction(&snake, Direction::Up));
        assert_eq!(false, map.can_snake_move_in_direction(&snake, Direction::Down));
        assert_eq!(false, map.can_snake_move_in_direction(&snake, Direction::Left));
        assert_eq!(false, map.can_snake_move_in_direction(&snake, Direction::Right));
    }
}
<commit_msg>Resolve incorrect imports in tests<commit_after>use structs::{ Map, SnakeInfo };
use util;

#[derive(PartialEq, Debug)]
pub enum Tile<'a> {
    Food { coordinate: (i32,i32) },
    Obstacle { coordinate: (i32,i32) },
    Empty { coordinate: (i32,i32) },
    SnakeHead { coordinate: (i32,i32), snake: &'a SnakeInfo },
    SnakeBody { coordinate: (i32,i32), snake: &'a SnakeInfo }
}

#[derive(Debug)]
pub enum Direction {
    Down,
    Up,
    Left,
    Right
}

pub fn direction_as_string(direction: &Direction) -> String {
    let s = match direction {
        &Direction::Down => "DOWN",
        &Direction::Up => "UP",
        &Direction::Left => "LEFT",
        &Direction::Right => "RIGHT"
    };

    String::from(s)
}

pub fn direction_as_movement_delta(direction: &Direction) -> (i32,i32) {
    match direction {
        &Direction::Down => (0, 1),
        &Direction::Up => (0, -1),
        &Direction::Left => (-1, 0),
        &Direction::Right => (1, 0)
    }
}

impl Map {
    pub fn get_snake_by_id<'a>(&'a self, id: &String) -> Option<&'a SnakeInfo> {
        self.snakeInfos.iter().find(|s| &s.id == id)
    }

    pub fn get_tile_at(&self, coordinate: (i32,i32)) -> Tile {
        let position = util::translate_coordinate(coordinate, self.width);
        let snake_at_tile = self.snakeInfos.iter().find(|s| s.positions.contains(&position));

        if self.obstaclePositions.contains(&position) {
            Tile::Obstacle { coordinate: coordinate }
        } else if self.foodPositions.contains(&position) {
            Tile::Food { coordinate: coordinate }
        } else if snake_at_tile.is_some() {
            let s = snake_at_tile.unwrap();
            if s.positions[0] == position {
                Tile::SnakeHead { coordinate: coordinate, snake: s }
            } else {
                Tile::SnakeBody { coordinate: coordinate, snake: s }
            }
        } else {
            Tile::Empty { coordinate: coordinate }
        }
    }

    pub fn is_tile_available_for_movement(&self, coordinate: (i32,i32)) -> bool {
        let tile = self.get_tile_at(coordinate);
        match tile {
            Tile::Empty { coordinate: _ } => true,
            Tile::Food { coordinate: _ } => true,
            _ => false
        }
    }

    pub fn can_snake_move_in_direction(&self, snake: &SnakeInfo, direction: Direction) -> bool {
        let (xd,yd) = direction_as_movement_delta(&direction);
        let (x,y) = util::translate_position(snake.positions[0], self.width);

        self.is_tile_available_for_movement((x+xd,y+yd))
    }

    #[allow(dead_code)]
    pub fn is_coordinate_out_of_bounds(&self, coordinate: (i32,i32)) -> bool {
        let (x,y) = coordinate;
        x < 0 || x >= self.width || y < 0 || y >= self.height
    }
}

#[cfg(test)]
mod test {
    use util::{ translate_coordinate };
    use maputil::{ Direction, Tile };
    use structs::{ Map, SnakeInfo };

    const MAP_WIDTH: i32 = 3;

    fn get_snake_one() -> SnakeInfo {
        SnakeInfo {
            name: String::from("1"),
            points: 0,
            tailProtectedForGameTicks: 0,
            positions: vec![translate_coordinate((1,1), MAP_WIDTH),
                            translate_coordinate((0,1), MAP_WIDTH)],
            id: String::from("1")
        }
    }

    fn get_snake_two() -> SnakeInfo {
        SnakeInfo {
            name: String::from("2"),
            points: 0,
            tailProtectedForGameTicks: 0,
            positions: vec![translate_coordinate((1,2), MAP_WIDTH)],
            id: String::from("2")
        }
    }

    // The map used for testing, 1 and 2 represents the snakes
    //yx012
    //0  F
    //1 11#
    //2  2
    fn get_test_map() -> Map {
        Map {
            type_: String::from("type"),
            width: MAP_WIDTH,
            height: MAP_WIDTH,
            worldTick: 0,
            snakeInfos: vec![get_snake_one(), get_snake_two()],
            foodPositions: vec![translate_coordinate((1,0),  MAP_WIDTH)],
            obstaclePositions: vec![translate_coordinate((2,1), MAP_WIDTH)],
            receivingPlayerId: Some(String::from("1"))
        }
    }

    #[test]
    fn snake_can_be_found_by_id() {
        let map = get_test_map();
        let id = map.receivingPlayerId.as_ref().unwrap();
        let s = map.get_snake_by_id(id);
        let found_id = &s.unwrap().id;
        assert_eq!(id, found_id);
    }

    #[test]
    fn tile_is_correctly_found() {
        let map = get_test_map();
        let snake_one = get_snake_one();
        let snake_two = get_snake_two();
        let tiles =
            vec![
                vec![Tile::Empty{ coordinate: (0,0) },
                     Tile::Food{ coordinate: (1,0) },
                     Tile::Empty{ coordinate: (2,0) }],
                vec![Tile::SnakeBody{ coordinate: (0,1), snake: &snake_one },
                     Tile::SnakeHead{ coordinate: (1,1), snake: &snake_one },
                     Tile::Obstacle{ coordinate: (2,1)}],
                vec![Tile::Empty{ coordinate: (0,2) },
                     Tile::SnakeHead{ coordinate: (1,2), snake: &snake_two },
                     Tile::Empty{ coordinate:(2,2) }]];
        for y in 0..map.width {
            for x in 0..map.height {
                assert_eq!(tiles[y as usize][x as usize],
                           map.get_tile_at((x,y)));
            }
        }
    }

    #[test]
    fn tile_is_correctly_marked_as_movable() {
        let map = get_test_map();
        let tiles = vec![vec![true, true, true],
                         vec![false, false, false],
                         vec![true, false, true]];

        for y in 0..map.height {
            for x in 0..map.width {
                assert_eq!(tiles[y as usize][x as usize],
                           map.is_tile_available_for_movement((x,y)));
            }
        }
    }

    #[test]
    fn can_snake_move_identifies_correctly() {
        let map = get_test_map();
        let id = map.receivingPlayerId.as_ref().unwrap();
        let snake = map.get_snake_by_id(id).unwrap();

        assert_eq!(true, map.can_snake_move_in_direction(&snake, Direction::Up));
        assert_eq!(false, map.can_snake_move_in_direction(&snake, Direction::Down));
        assert_eq!(false, map.can_snake_move_in_direction(&snake, Direction::Left));
        assert_eq!(false, map.can_snake_move_in_direction(&snake, Direction::Right));
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 - 2016, Alberto Corona <ac@albertocorona.com>
// All rights reserved. This file is part of yabs, distributed under the BSD
// 3-Clause license. For full terms please see the LICENSE file.

extern crate toml;
extern crate rustc_serialize;
extern crate walkdir;
extern crate rpf;

use toml::decode;
use error::YabsError;
use rpf::*;
use ext::*;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, json};
use walkdir::{WalkDir,WalkDirIterator,DirEntry};

use std::ffi::OsStr;
use std::fs::File;
use std::io::Write;

#[derive(Debug,Default,RustcDecodable,RustcEncodable,Clone,PartialEq)]
pub struct Profile {
    name: String,
    proj_desc: Option<ProjDesc>,
    inst_desc: Option<InstallDesc>,
    doc_desc: Option<DocDesc>,
}

#[derive(Debug,Default,RustcDecodable,RustcEncodable,Clone)]
pub struct BuildFile {
    profiles: Vec<Profile>,
}

impl BuildFile {
    pub fn from_file(file: &str) -> Result<BuildFile, Vec<YabsError>> {
        let mut build_file: BuildFile = Default::default();
        parse_toml_file(file)
            .and_then(|toml| {
                for (key, table) in toml {
                    let mut profile: Profile = Default::default();
                    profile.name = key.clone();
                    match table {
                        toml::Value::Table(inner_table) => {
                            for (key, table) in inner_table {
                                match key.as_ref() {
                                    "project" => {
                                        profile.proj_desc = ProjDesc::from_toml_table(table).ok()
                                    }
                                    "install" => {
                                        profile.inst_desc = InstallDesc::from_toml_table(table).ok()
                                    }
                                    "doc" => {
                                        profile.doc_desc = DocDesc::from_toml_table(table).ok()
                                    }
                                    _ => (),
                                }
                            }
                        }
                        _ => (),
                    };
                    build_file.profiles.push(profile);
                }
                Ok(build_file)
            })
            .map_err(|err| err)
    }

    pub fn print_as_json(&self) {
        for profile in &self.profiles {
            profile.print_json();
        }
    }

    pub fn print_available_profiles(&self) {
        for profile in &self.profiles {
            print!("{} ", profile.name);
        }
        print!("\n");
    }

    pub fn print_profile_as_json(&self, name: String) {
        for profile in &self.profiles {
            if profile.name == name {
                profile.print_json();
            }
        }
    }

    pub fn gen_make(&self, name: String) -> Result<(), YabsError> {
        if let Some(index) = self.profiles.iter().position(|ref profile| profile.name == name) {
            try!(self.profiles[index.clone()].clone().proj_desc.unwrap_or(ProjDesc::new()).gen_file_list());
            try!(try!(File::create("Makefile")).write_all(try!(self.profiles[index.clone()]
                                                              .clone()
                                                              .proj_desc
                                                              .unwrap_or(ProjDesc::new())
                                                              .gen_make())
                                                              .as_bytes()));
            Ok(())
        } else {
            Err(YabsError::NoDesc(name))
        }
    }

    pub fn print_sources(&mut self) -> Result<(), YabsError> {
        for profile in &mut self.profiles {
            if let &mut Some(ref mut proj) = &mut profile.proj_desc {
                println!("{}", profile.name.bold());
                try!(proj.gen_file_list());
                if let Some(set_sources) = proj.src.as_ref() {
                    for src in set_sources {
                        println!("{}", src);
                    }
                }
            }
        }
        Ok(())
    }
}

#[derive(Debug,Default,RustcDecodable,RustcEncodable,Clone,PartialEq)]
pub struct ProjDesc {
    name: Option<String>,
    target: Option<String>,
    lang: Option<String>,
    os: Option<String>,
    version: Option<String>,
    compiler: Option<String>,
    src: Option<Vec<String>>,
    libs: Option<Vec<String>>,
    lib_dir: Option<Vec<String>>,
    inc: Option<Vec<String>>,
    inc_dir: Option<Vec<String>>,
    cflags: Option<Vec<String>>,
    explicit_cflags: Option<String>,
    lflags: Option<String>,
    ignore: Option<Vec<String>>,
    before_script: Option<Vec<String>>,
    after_script: Option<Vec<String>>,
    lib: Option<bool>,
    ar: Option<String>,
    clean: Option<Vec<String>>,
}

impl ProjDesc {
    fn concat_clean(&self) -> String {
        self.prepend_op_vec(&self.clean, "".to_string())
    }

    fn is_in_ignore(&self, entry: &DirEntry) -> bool {
        if let Some(ignore) = self.ignore.as_ref() {
            for path in ignore {
                let entry = entry.path().as_string();
                if entry.find(path).is_some() {
                    return true
                }
            }
        }
        false
    }

    fn gen_file_list(&mut self) -> Result<(), YabsError> {
        if self.src.is_some() {
            return Ok(())
        }
        let mut sources = Vec::new();
        let walk_dir = WalkDir::new(".").into_iter();
        for entry in walk_dir.filter_entry(|e| !&self.is_in_ignore(e)) {
            let entry = try!(entry);
            if entry.path().is_file() {
                let file_ext = entry.path().extension().unwrap_or(OsStr::new(""));
                if let Some(ext) = file_ext.to_str() {
                    if let Some(lang) = self.lang.as_ref() {
                        if ext == lang {
                            let mut entry = entry.path().as_string();
                            if entry.len() > 2 {
                                entry.remove(0);
                                entry.remove(0);
                            }
                            sources.push(entry);
                        }
                    }
                }
            }
        }
        self.src = Some(sources);
        Ok(())
    }

    fn prepend_op_vec(&self, list: &Option<Vec<String>>, prepend: String) -> String {
        let mut horrid_string = String::new();
        if let Some(items) = list.as_ref() {
            if let Some(split_last) = items.split_last() {
                for sub_item in split_last.1 {
                    if self.is_command(&sub_item) {
                        horrid_string.push_str(&format!("{} ", sub_item));
                    } else {
                        horrid_string.push_str(&format!("{}{} ", prepend, sub_item));
                    }
                }
                if self.is_command(&split_last.0) {
                        horrid_string.push_str(&format!("{} ", split_last.0));
                } else {
                    horrid_string.push_str(&format!("{}{}", prepend, split_last.0.clone()));
                }
            }
        }
        return horrid_string;
    }

    fn is_command(&self, string: &String) -> bool {
        if string.starts_with("`") {
            return true
        } else {
            return false
        }
    }

    fn gen_make_lib_list(&self) -> String {
        return self.prepend_op_vec(&self.libs, "-l".to_string());
    }

    fn gen_make_cflags_list(&self) -> String {
        return self.prepend_op_vec(&self.cflags, "-".to_string());
    }

    fn gen_make_src_list(&self) -> String {
        let mut horrid_string: String = "SRC\t= ".to_owned();
        let mut lang = self.lang.clone().unwrap_or("cpp".to_owned());
        lang.insert(0, '.');
        if let Some(source_list) = self.src.as_ref() {
            if let Some(split_first) = source_list.split_first() {
                horrid_string.push_str(&format!("{} \\\n", split_first.0));
                if let Some(split_last) = split_first.1.clone().split_last() {
                    for src in split_last.1 {
                        horrid_string.push_str(&format!("\t{} \\\n", src));
                    }
                    horrid_string.push_str(&format!("\t{}\n", split_last.0));
                }
            }
            let mut parsed_obj_list = Vec::new();
            for obj in source_list {
                parsed_obj_list.push(obj.replace(&lang, ".o"));
            }
            horrid_string.push_str("OBJ\t= ");
            if let Some(split_first) = parsed_obj_list.split_first() {
                horrid_string.push_str(&format!("{} \\\n", split_first.0));
                if let Some(split_last) = split_first.1.clone().split_last() {
                    for src in split_last.1 {
                        horrid_string.push_str(&format!("\t{} \\\n", src));
                    }
                    horrid_string.push_str(&format!("\t{}", split_last.0));
                }
            }
        }
        return horrid_string;
    }

    fn gen_make_src_deps(&self) -> String {
        let mut horrid_string = String::new();
        let mut lang = self.lang.clone().unwrap_or("cpp".to_owned());
        lang.insert(0, '.');
        if let Some(source_list) = self.src.as_ref() {
            for src in source_list {
                horrid_string.push_str(&format!("{0}: {1}\n\t$(CC) -c $(CFLAGS) $(INCDIR) -o \
                                                 {0} {1}\n\n",
                                                src.replace(&lang, ".o"),
                                                src));
            }
        }
        return horrid_string;
    }

    fn gen_make_inc_list(&self) -> String {
        return self.prepend_op_vec(&self.inc, "-I".to_string());
    }

    fn gen_make(&mut self) -> Result<String, YabsError> {
        try!(self.gen_file_list());
        Ok(format!(
            "INSTALL\t= /usr/bin/env install\n\
                AR\t= /usr/bin/env ar\n\
                DEST\t=\n\
                PREFIX\t=\n\
                CC\t= {compiler}\n\
                BINDIR\t=\n\
                LIBDIR\t=\n\
                TARGET\t= {target}\n\
                LINK\t=\n\
                CFLAGS\t= {cflags}\n\
                LFLAGS\t=\n\
                LIBS\t= {libs}\n\
                INCDIR\t= {incdir}\n\
                LIBDIR\t=\n\
                CLEAN\t=\n\
                DEL\t= rm -f\n\
                {srcs}\n\n\
                first: all\n\n\
                .PHONY: doc clean\n\n\
                .SUFFIXES: .o .c .cpp .cc .cxx .C\n\n\
                .cpp.o:\n\t$(CC) -c $(CFLAGS) $(INCDIR) -o \"$@\" \"$<\"\n\
                .cc.o:\n\t$(CC) -c $(CFLAGS) $(INCDIR) -o \"$@\" \"$<\"\n\n\
                .cxx.o:\n\t$(CC) -c $(CFLAGS) $(INCDIR) -o \"$@\" \"$<\"\n\n\
                .C.o:\n\t$(CC) -c $(CFLAGS) $(INCDIR) -o \"$@\" \"$<\"\n\n\
                .c.o:\n\t$(CC) -c $(CFLAGS) $(INCDIR) -o \"$@\" \"$<\"\n\n\
                all: $(TARGET)\n\n\
                $(TARGET): $(OBJ)\n\
                \t$(CC) $(LFLAGS) -o $(TARGET) $(OBJ) $(LIBS)\n\n\
                {dep_list}\n\
                clean:\n\
                \t$(DEL) $(OBJ)\n\
                \t$(DEL) {target}\n\
                \t$(DEL) {clean_list}\n\
                ",
                compiler = &self.compiler.clone().unwrap_or("gcc".to_owned()),
                target = &self.target.clone().unwrap_or("a".to_owned()),
                cflags = &self.gen_make_cflags_list(),
                libs = &self.gen_make_lib_list(),
                incdir = &self.gen_make_inc_list(),
                srcs = &self.gen_make_src_list(),
                dep_list = &self.gen_make_src_deps(),
                clean_list = &self.concat_clean()))
    }
}

// Descibe how to install this project
#[derive(Debug,Default,RustcDecodable,RustcEncodable,Clone,PartialEq)]
pub struct InstallDesc {
    prefix: Option<String>,
}

#[derive(Debug,Default,RustcDecodable,RustcEncodable,Clone,PartialEq)]
pub struct DocDesc {
    doc: Option<String>,
}

// General trait for any descriptions
pub trait Desc<T> {
    fn new() -> T;
    fn from_file(file: &str, name: &str) -> Result<T, Vec<YabsError>>;
    fn from_toml_table(table: toml::Value) -> Result<T, YabsError>;
    fn print_json(&self);
}

impl<T: Decodable + Encodable + Default> Desc<T> for T {
    fn new() -> T {
        Default::default()
    }

    fn from_file(file: &str, name: &str) -> Result<T, Vec<YabsError>> {
        parse_toml_file(file).and_then(|toml| {
            toml.get(name)
                .ok_or(vec![YabsError::NoDesc(name.to_owned())])
                .and_then(|desc| {
                    Decodable::decode(&mut toml::Decoder::new(desc.clone()))
                        .map_err(|err| vec![YabsError::TomlDecode(err)])
                })
        })
    }

    fn from_toml_table(table: toml::Value) -> Result<T, YabsError> {
        Ok(try!(Decodable::decode(&mut toml::Decoder::new(table.clone()))))
    }

    fn print_json(&self) {
        println!("{}", json::as_pretty_json(&self));
    }
}
<commit_msg>build: whitespace changes via rustfmt<commit_after>// Copyright (c) 2015 - 2016, Alberto Corona <ac@albertocorona.com>
// All rights reserved. This file is part of yabs, distributed under the BSD
// 3-Clause license. For full terms please see the LICENSE file.

extern crate toml;
extern crate rustc_serialize;
extern crate walkdir;
extern crate rpf;

use toml::decode;
use error::YabsError;
use rpf::*;
use ext::*;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, json};
use walkdir::{WalkDir, WalkDirIterator, DirEntry};

use std::ffi::OsStr;
use std::fs::File;
use std::io::Write;

#[derive(Debug,Default,RustcDecodable,RustcEncodable,Clone,PartialEq)]
pub struct Profile {
    name: String,
    proj_desc: Option<ProjDesc>,
    inst_desc: Option<InstallDesc>,
    doc_desc: Option<DocDesc>,
}

#[derive(Debug,Default,RustcDecodable,RustcEncodable,Clone)]
pub struct BuildFile {
    profiles: Vec<Profile>,
}

impl BuildFile {
    pub fn from_file(file: &str) -> Result<BuildFile, Vec<YabsError>> {
        let mut build_file: BuildFile = Default::default();
        parse_toml_file(file)
            .and_then(|toml| {
                for (key, table) in toml {
                    let mut profile: Profile = Default::default();
                    profile.name = key.clone();
                    match table {
                        toml::Value::Table(inner_table) => {
                            for (key, table) in inner_table {
                                match key.as_ref() {
                                    "project" => {
                                        profile.proj_desc = ProjDesc::from_toml_table(table).ok()
                                    }
                                    "install" => {
                                        profile.inst_desc = InstallDesc::from_toml_table(table).ok()
                                    }
                                    "doc" => {
                                        profile.doc_desc = DocDesc::from_toml_table(table).ok()
                                    }
                                    _ => (),
                                }
                            }
                        }
                        _ => (),
                    };
                    build_file.profiles.push(profile);
                }
                Ok(build_file)
            })
            .map_err(|err| err)
    }

    pub fn print_as_json(&self) {
        for profile in &self.profiles {
            profile.print_json();
        }
    }

    pub fn print_available_profiles(&self) {
        for profile in &self.profiles {
            print!("{} ", profile.name);
        }
        print!("\n");
    }

    pub fn print_profile_as_json(&self, name: String) {
        for profile in &self.profiles {
            if profile.name == name {
                profile.print_json();
            }
        }
    }

    pub fn gen_make(&self, name: String) -> Result<(), YabsError> {
        if let Some(index) = self.profiles.iter().position(|ref profile| profile.name == name) {
            try!(self.profiles[index.clone()]
                     .clone()
                     .proj_desc
                     .unwrap_or(ProjDesc::new())
                     .gen_file_list());
            try!(try!(File::create("Makefile")).write_all(try!(self.profiles[index.clone()]
                                                                   .clone()
                                                                   .proj_desc
                                                                   .unwrap_or(ProjDesc::new())
                                                                   .gen_make())
                                                              .as_bytes()));
            Ok(())
        } else {
            Err(YabsError::NoDesc(name))
        }
    }

    pub fn print_sources(&mut self) -> Result<(), YabsError> {
        for profile in &mut self.profiles {
            if let &mut Some(ref mut proj) = &mut profile.proj_desc {
                println!("{}", profile.name.bold());
                try!(proj.gen_file_list());
                if let Some(set_sources) = proj.src.as_ref() {
                    for src in set_sources {
                        println!("{}", src);
                    }
                }
            }
        }
        Ok(())
    }
}

#[derive(Debug,Default,RustcDecodable,RustcEncodable,Clone,PartialEq)]
pub struct ProjDesc {
    name: Option<String>,
    target: Option<String>,
    lang: Option<String>,
    os: Option<String>,
    version: Option<String>,
    compiler: Option<String>,
    src: Option<Vec<String>>,
    libs: Option<Vec<String>>,
    lib_dir: Option<Vec<String>>,
    inc: Option<Vec<String>>,
    inc_dir: Option<Vec<String>>,
    cflags: Option<Vec<String>>,
    explicit_cflags: Option<String>,
    lflags: Option<String>,
    ignore: Option<Vec<String>>,
    before_script: Option<Vec<String>>,
    after_script: Option<Vec<String>>,
    lib: Option<bool>,
    ar: Option<String>,
    clean: Option<Vec<String>>,
}

impl ProjDesc {
    fn concat_clean(&self) -> String {
        self.prepend_op_vec(&self.clean, "".to_string())
    }

    fn is_in_ignore(&self, entry: &DirEntry) -> bool {
        if let Some(ignore) = self.ignore.as_ref() {
            for path in ignore {
                let entry = entry.path().as_string();
                if entry.find(path).is_some() {
                    return true;
                }
            }
        }
        false
    }

    fn gen_file_list(&mut self) -> Result<(), YabsError> {
        if self.src.is_some() {
            return Ok(());
        }
        let mut sources = Vec::new();
        let walk_dir = WalkDir::new(".").into_iter();
        for entry in walk_dir.filter_entry(|e| !&self.is_in_ignore(e)) {
            let entry = try!(entry);
            if entry.path().is_file() {
                let file_ext = entry.path().extension().unwrap_or(OsStr::new(""));
                if let Some(ext) = file_ext.to_str() {
                    if let Some(lang) = self.lang.as_ref() {
                        if ext == lang {
                            let mut entry = entry.path().as_string();
                            if entry.len() > 2 {
                                entry.remove(0);
                                entry.remove(0);
                            }
                            sources.push(entry);
                        }
                    }
                }
            }
        }
        self.src = Some(sources);
        Ok(())
    }

    fn prepend_op_vec(&self, list: &Option<Vec<String>>, prepend: String) -> String {
        let mut horrid_string = String::new();
        if let Some(items) = list.as_ref() {
            if let Some(split_last) = items.split_last() {
                for sub_item in split_last.1 {
                    if self.is_command(&sub_item) {
                        horrid_string.push_str(&format!("{} ", sub_item));
                    } else {
                        horrid_string.push_str(&format!("{}{} ", prepend, sub_item));
                    }
                }
                if self.is_command(&split_last.0) {
                    horrid_string.push_str(&format!("{} ", split_last.0));
                } else {
                    horrid_string.push_str(&format!("{}{}", prepend, split_last.0.clone()));
                }
            }
        }
        return horrid_string;
    }

    fn is_command(&self, string: &String) -> bool {
        if string.starts_with("`") {
            return true;
        } else {
            return false;
        }
    }

    fn gen_make_lib_list(&self) -> String {
        return self.prepend_op_vec(&self.libs, "-l".to_string());
    }

    fn gen_make_cflags_list(&self) -> String {
        return self.prepend_op_vec(&self.cflags, "-".to_string());
    }

    fn gen_make_src_list(&self) -> String {
        let mut horrid_string: String = "SRC\t= ".to_owned();
        let mut lang = self.lang.clone().unwrap_or("cpp".to_owned());
        lang.insert(0, '.');
        if let Some(source_list) = self.src.as_ref() {
            if let Some(split_first) = source_list.split_first() {
                horrid_string.push_str(&format!("{} \\\n", split_first.0));
                if let Some(split_last) = split_first.1.clone().split_last() {
                    for src in split_last.1 {
                        horrid_string.push_str(&format!("\t{} \\\n", src));
                    }
                    horrid_string.push_str(&format!("\t{}\n", split_last.0));
                }
            }
            let mut parsed_obj_list = Vec::new();
            for obj in source_list {
                parsed_obj_list.push(obj.replace(&lang, ".o"));
            }
            horrid_string.push_str("OBJ\t= ");
            if let Some(split_first) = parsed_obj_list.split_first() {
                horrid_string.push_str(&format!("{} \\\n", split_first.0));
                if let Some(split_last) = split_first.1.clone().split_last() {
                    for src in split_last.1 {
                        horrid_string.push_str(&format!("\t{} \\\n", src));
                    }
                    horrid_string.push_str(&format!("\t{}", split_last.0));
                }
            }
        }
        return horrid_string;
    }

    fn gen_make_src_deps(&self) -> String {
        let mut horrid_string = String::new();
        let mut lang = self.lang.clone().unwrap_or("cpp".to_owned());
        lang.insert(0, '.');
        if let Some(source_list) = self.src.as_ref() {
            for src in source_list {
                horrid_string.push_str(&format!("{0}: {1}\n\t$(CC) -c $(CFLAGS) $(INCDIR) -o \
                                                 {0} {1}\n\n",
                                                src.replace(&lang, ".o"),
                                                src));
            }
        }
        return horrid_string;
    }

    fn gen_make_inc_list(&self) -> String {
        return self.prepend_op_vec(&self.inc, "-I".to_string());
    }

    fn gen_make(&mut self) -> Result<String, YabsError> {
        try!(self.gen_file_list());
        Ok(format!(
            "INSTALL\t= /usr/bin/env install\n\
                AR\t= /usr/bin/env ar\n\
                DEST\t=\n\
                PREFIX\t=\n\
                CC\t= {compiler}\n\
                BINDIR\t=\n\
                LIBDIR\t=\n\
                TARGET\t= {target}\n\
                LINK\t=\n\
                CFLAGS\t= {cflags}\n\
                LFLAGS\t=\n\
                LIBS\t= {libs}\n\
                INCDIR\t= {incdir}\n\
                LIBDIR\t=\n\
                CLEAN\t=\n\
                DEL\t= rm -f\n\
                {srcs}\n\n\
                first: all\n\n\
                .PHONY: doc clean\n\n\
                .SUFFIXES: .o .c .cpp .cc .cxx .C\n\n\
                .cpp.o:\n\t$(CC) -c $(CFLAGS) $(INCDIR) -o \"$@\" \"$<\"\n\
                .cc.o:\n\t$(CC) -c $(CFLAGS) $(INCDIR) -o \"$@\" \"$<\"\n\n\
                .cxx.o:\n\t$(CC) -c $(CFLAGS) $(INCDIR) -o \"$@\" \"$<\"\n\n\
                .C.o:\n\t$(CC) -c $(CFLAGS) $(INCDIR) -o \"$@\" \"$<\"\n\n\
                .c.o:\n\t$(CC) -c $(CFLAGS) $(INCDIR) -o \"$@\" \"$<\"\n\n\
                all: $(TARGET)\n\n\
                $(TARGET): $(OBJ)\n\
                \t$(CC) $(LFLAGS) -o $(TARGET) $(OBJ) $(LIBS)\n\n\
                {dep_list}\n\
                clean:\n\
                \t$(DEL) $(OBJ)\n\
                \t$(DEL) {target}\n\
                \t$(DEL) {clean_list}\n\
                ",
                compiler = &self.compiler.clone().unwrap_or("gcc".to_owned()),
                target = &self.target.clone().unwrap_or("a".to_owned()),
                cflags = &self.gen_make_cflags_list(),
                libs = &self.gen_make_lib_list(),
                incdir = &self.gen_make_inc_list(),
                srcs = &self.gen_make_src_list(),
                dep_list = &self.gen_make_src_deps(),
                clean_list = &self.concat_clean()))
    }
}

// Descibe how to install this project
#[derive(Debug,Default,RustcDecodable,RustcEncodable,Clone,PartialEq)]
pub struct InstallDesc {
    prefix: Option<String>,
}

#[derive(Debug,Default,RustcDecodable,RustcEncodable,Clone,PartialEq)]
pub struct DocDesc {
    doc: Option<String>,
}

// General trait for any descriptions
pub trait Desc<T> {
    fn new() -> T;
    fn from_file(file: &str, name: &str) -> Result<T, Vec<YabsError>>;
    fn from_toml_table(table: toml::Value) -> Result<T, YabsError>;
    fn print_json(&self);
}

impl<T: Decodable + Encodable + Default> Desc<T> for T {
    fn new() -> T {
        Default::default()
    }

    fn from_file(file: &str, name: &str) -> Result<T, Vec<YabsError>> {
        parse_toml_file(file).and_then(|toml| {
            toml.get(name)
                .ok_or(vec![YabsError::NoDesc(name.to_owned())])
                .and_then(|desc| {
                    Decodable::decode(&mut toml::Decoder::new(desc.clone()))
                        .map_err(|err| vec![YabsError::TomlDecode(err)])
                })
        })
    }

    fn from_toml_table(table: toml::Value) -> Result<T, YabsError> {
        Ok(try!(Decodable::decode(&mut toml::Decoder::new(table.clone()))))
    }

    fn print_json(&self) {
        println!("{}", json::as_pretty_json(&self));
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use bytes::{Buf, Bytes, IntoBuf};
use futures::{
    channel::mpsc::{self, UnboundedReceiver, UnboundedSender},
    io::{AsyncRead, AsyncWrite, Error, ErrorKind, Result},
    ready,
    stream::{FusedStream, Stream},
    task::{Context, Poll},
};
use lazy_static::lazy_static;
use std::{collections::HashMap, num::NonZeroU16, pin::Pin, sync::Mutex};

lazy_static! {
    static ref SWITCHBOARD: Mutex<SwitchBoard> = Mutex::new(SwitchBoard(HashMap::default(), 1));
}

struct SwitchBoard(HashMap<NonZeroU16, UnboundedSender<MemorySocket>>, u16);

/// An in-memory socket server, listening for connections.
///
/// After creating a `MemoryListener` by [`bind`]ing it to a socket address, it listens
/// for incoming connections. These can be accepted by awaiting elements from the
/// async stream of incoming connections, [`incoming`][`MemoryListener::incoming`].
///
/// The socket will be closed when the value is dropped.
///
/// [`bind`]: #method.bind
/// [`MemoryListener::incoming`]: #method.incoming
///
/// # Examples
///
/// ```rust,no_run
/// #![feature(async_await)]
/// use std::io::Result;
///
/// use memsocket::{MemoryListener, MemorySocket};
/// use futures::prelude::*;
///
/// async fn write_stormlight(mut stream: MemorySocket) -> Result<()> {
///     let msg = b"The most important step a person can take is always the next one.";
///     stream.write_all(msg).await?;
///     stream.flush().await
/// }
///
/// async fn listen() -> Result<()> {
///     let mut listener = MemoryListener::bind(16)?;
///     let mut incoming = listener.incoming();
///
///     // accept connections and process them serially
///     while let Some(stream) = incoming.next().await {
///         write_stormlight(stream?).await?;
///     }
///     Ok(())
/// }
/// ```
#[derive(Debug)]
pub struct MemoryListener {
    incoming: UnboundedReceiver<MemorySocket>,
    port: NonZeroU16,
}

impl Drop for MemoryListener {
    fn drop(&mut self) {
        let mut switchboard = (&*SWITCHBOARD).lock().unwrap();
        // Remove the Sending side of the channel in the switchboard when
        // MemoryListener is dropped
        switchboard.0.remove(&self.port);
    }
}

impl MemoryListener {
    /// Creates a new `MemoryListener` which will be bound to the specified
    /// port.
    ///
    /// The returned listener is ready for accepting connections.
    ///
    /// Binding with a port number of 0 will request that a port be assigned
    /// to this listener. The port allocated can be queried via the
    /// [`local_addr`] method.
    ///
    /// # Examples
    /// Create a MemoryListener bound to port 16:
    ///
    /// ```rust,no_run
    /// use memsocket::MemoryListener;
    ///
    /// # fn main () -> ::std::io::Result<()> {
    /// let listener = MemoryListener::bind(16)?;
    /// # Ok(())}
    /// ```
    ///
    /// [`local_addr`]: #method.local_addr
    pub fn bind(port: u16) -> Result<Self> {
        let mut switchboard = (&*SWITCHBOARD).lock().unwrap();

        // Get the port we should bind to.  If 0 was given, use a random port
        let port = if let Some(port) = NonZeroU16::new(port) {
            if switchboard.0.contains_key(&port) {
                return Err(ErrorKind::AddrInUse.into());
            }
            port
        } else {
            loop {
                let port = match NonZeroU16::new(switchboard.1) {
                    Some(p) => p,
                    None => unreachable!(),
                };
                switchboard.1 += 1;
                if !switchboard.0.contains_key(&port) {
                    break port;
                }
            }
        };

        let (sender, receiver) = mpsc::unbounded();
        switchboard.0.insert(port, sender);

        Ok(Self {
            incoming: receiver,
            port,
        })
    }

    /// Returns the local address that this listener is bound to.
    ///
    /// This can be useful, for example, when binding to port 0 to figure out
    /// which port was actually bound.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use memsocket::MemoryListener;
    ///
    /// # fn main () -> ::std::io::Result<()> {
    /// let listener = MemoryListener::bind(16)?;
    ///
    /// assert_eq!(listener.local_addr(), 16);
    /// # Ok(())}
    /// ```
    pub fn local_addr(&self) -> u16 {
        self.port.get()
    }

    /// Consumes this listener, returning a stream of the sockets this listener
    /// accepts.
    ///
    /// This method returns an implementation of the `Stream` trait which
    /// resolves to the sockets the are accepted on this listener.
    ///
    /// # Examples
    ///
    /// ```rust,no_run
    /// #![feature(async_await)]
    /// use futures::prelude::*;
    /// use memsocket::MemoryListener;
    ///
    /// # async fn work () -> ::std::io::Result<()> {
    /// let mut listener = MemoryListener::bind(16)?;
    /// let mut incoming = listener.incoming();
    ///
    /// // accept connections and process them serially
    /// while let Some(stream) = incoming.next().await {
    ///     match stream {
    ///         Ok(stream) => {
    ///             println!("new connection!");
    ///         },
    ///         Err(e) => { /* connection failed */ }
    ///     }
    /// }
    /// # Ok(())}
    /// ```
    pub fn incoming(&mut self) -> Incoming<'_> {
        Incoming { inner: self }
    }

    fn poll_accept(&mut self, context: &mut Context) -> Poll<Result<MemorySocket>> {
        match Pin::new(&mut self.incoming).poll_next(context) {
            Poll::Ready(Some(socket)) => Poll::Ready(Ok(socket)),
            Poll::Ready(None) => {
                let err = Error::new(ErrorKind::Other, "MemoryListener unknown error");
                Poll::Ready(Err(err))
            }
            Poll::Pending => Poll::Pending,
        }
    }
}

/// Stream returned by the `MemoryListener::incoming` function representing the
/// stream of sockets received from a listener.
#[must_use = "streams do nothing unless polled"]
#[derive(Debug)]
pub struct Incoming<'a> {
    inner: &'a mut MemoryListener,
}

impl<'a> Stream for Incoming<'a> {
    type Item = Result<MemorySocket>;

    fn poll_next(mut self: Pin<&mut Self>, context: &mut Context) -> Poll<Option<Self::Item>> {
        let socket = ready!(self.inner.poll_accept(context)?);
        Poll::Ready(Some(Ok(socket)))
    }
}

/// An in-memory stream between two local sockets.
///
/// A `MemorySocket` can either be created by connecting to an endpoint, via the
/// [`connect`] method, or by [accepting] a connection from a [listener].
/// It can be read or written to using the `AsyncRead`, `AsyncWrite`, and related
/// extension traits in `futures::io`.
///
/// # Examples
///
/// ```rust, no_run
/// #![feature(async_await)]
/// use futures::prelude::*;
/// use memsocket::MemorySocket;
///
/// # async fn run() -> ::std::io::Result<()> {
/// let (mut socket_a, mut socket_b) = MemorySocket::new_pair();
///
/// socket_a.write_all(b"stormlight").await?;
/// socket_a.flush().await?;
///
/// let mut buf = [0; 10];
/// socket_b.read_exact(&mut buf).await?;
/// assert_eq!(&buf, b"stormlight");
///
/// # Ok(())}
/// ```
///
/// [`connect`]: struct.MemorySocket.html#method.connect
/// [accepting]: struct.MemoryListener.html#method.accept
/// [listener]: struct.MemoryListener.html
#[derive(Debug)]
pub struct MemorySocket {
    incoming: UnboundedReceiver<Bytes>,
    outgoing: UnboundedSender<Bytes>,
    current_buffer: Option<<Bytes as IntoBuf>::Buf>,
    seen_eof: bool,
}

impl MemorySocket {
    /// Construct both sides of an in-memory socket.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use memsocket::MemorySocket;
    ///
    /// # fn main() {
    /// let (socket_a, socket_b) = MemorySocket::new_pair();
    /// # }
    /// ```
    pub fn new_pair() -> (Self, Self) {
        let (a_tx, a_rx) = mpsc::unbounded();
        let (b_tx, b_rx) = mpsc::unbounded();
        let a = Self {
            incoming: a_rx,
            outgoing: b_tx,
            current_buffer: None,
            seen_eof: false,
        };
        let b = Self {
            incoming: b_rx,
            outgoing: a_tx,
            current_buffer: None,
            seen_eof: false,
        };

        (a, b)
    }

    /// Create a new in-memory Socket connected to the specified port.
    ///
    /// This function will create a new MemorySocket socket and attempt to connect it to
    /// the `port` provided.
    ///
    /// # Examples
    ///
    /// ```rust,no_run
    /// use memsocket::MemorySocket;
    ///
    /// # fn main () -> ::std::io::Result<()> {
    /// let socket = MemorySocket::connect(16)?;
    /// # Ok(())}
    /// ```
    pub fn connect(port: u16) -> Result<MemorySocket> {
        let mut switchboard = (&*SWITCHBOARD).lock().unwrap();

        // Find port to connect to
        let port = if let Some(port) = NonZeroU16::new(port) {
            port
        } else {
            return Err(ErrorKind::AddrNotAvailable.into());
        };

        let sender = if let Some(s) = switchboard.0.get_mut(&port) {
            s
        } else {
            return Err(ErrorKind::AddrNotAvailable.into());
        };

        let (socket_a, socket_b) = Self::new_pair();
        // Send the socket to the listener
        if let Err(e) = sender.unbounded_send(socket_a) {
            if e.is_disconnected() {
                return Err(ErrorKind::AddrNotAvailable.into());
            }

            unreachable!();
        }

        Ok(socket_b)
    }
}

impl AsyncRead for MemorySocket {
    /// Attempt to read from the `AsyncRead` into `buf`.
    fn poll_read(
        mut self: Pin<&mut Self>,
        mut context: &mut Context,
        buf: &mut [u8],
    ) -> Poll<Result<usize>> {
        if self.incoming.is_terminated() {
            if self.seen_eof {
                return Poll::Ready(Err(ErrorKind::UnexpectedEof.into()));
            } else {
                self.seen_eof = true;
                return Poll::Ready(Ok(0));
            }
        }

        let mut bytes_read = 0;

        loop {
            // If we're already filled up the buffer then we can return
            if bytes_read == buf.len() {
                return Poll::Ready(Ok(bytes_read));
            }

            match self.current_buffer {
                // We have data to copy to buf
                Some(ref mut current_buffer) if current_buffer.has_remaining() => {
                    let bytes_to_read =
                        ::std::cmp::min(buf.len() - bytes_read, current_buffer.remaining());
                    debug_assert!(bytes_to_read > 0);

                    current_buffer
                        .take(bytes_to_read)
                        .copy_to_slice(&mut buf[bytes_read..(bytes_read + bytes_to_read)]);
                    bytes_read += bytes_to_read;
                }

                // Either we've exhausted our current buffer or don't have one
                _ => {
                    self.current_buffer = {
                        match Pin::new(&mut self.incoming).poll_next(&mut context) {
                            Poll::Pending => {
                                // If we've read anything up to this point return the bytes read
                                if bytes_read > 0 {
                                    return Poll::Ready(Ok(bytes_read));
                                } else {
                                    return Poll::Pending;
                                }
                            }
                            Poll::Ready(Some(buf)) => Some(buf.into_buf()),
                            Poll::Ready(None) => return Poll::Ready(Ok(bytes_read)),
                        }
                    };
                }
            }
        }
    }
}

impl AsyncWrite for MemorySocket {
    /// Attempt to write bytes from `buf` into the outgoing channel.
    fn poll_write(
        mut self: Pin<&mut Self>,
        context: &mut Context,
        buf: &[u8],
    ) -> Poll<Result<usize>> {
        let len = buf.len();

        match self.outgoing.poll_ready(context) {
            Poll::Ready(Ok(())) => {
                if let Err(e) = self.outgoing.start_send(buf.into()) {
                    if e.is_disconnected() {
                        return Poll::Ready(Err(Error::new(ErrorKind::BrokenPipe, e)));
                    }

                    // Unbounded channels should only ever have "Disconnected" errors
                    unreachable!();
                }
            }
            Poll::Ready(Err(e)) => {
                if e.is_disconnected() {
                    return Poll::Ready(Err(Error::new(ErrorKind::BrokenPipe, e)));
                }

                // Unbounded channels should only ever have "Disconnected" errors
                unreachable!();
            }
            Poll::Pending => return Poll::Pending,
        }

        Poll::Ready(Ok(len))
    }

    /// Attempt to flush the channel. Cannot Fail.
    fn poll_flush(self: Pin<&mut Self>, _context: &mut Context) -> Poll<Result<()>> {
        Poll::Ready(Ok(()))
    }

    /// Attempt to close the channel. Cannot Fail.
    fn poll_close(self: Pin<&mut Self>, _context: &mut Context) -> Poll<Result<()>> {
        self.outgoing.close_channel();

        Poll::Ready(Ok(()))
    }
}
<commit_msg>[memsocket] fix overflow bug<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use bytes::{Buf, Bytes, IntoBuf};
use futures::{
    channel::mpsc::{self, UnboundedReceiver, UnboundedSender},
    io::{AsyncRead, AsyncWrite, Error, ErrorKind, Result},
    ready,
    stream::{FusedStream, Stream},
    task::{Context, Poll},
};
use lazy_static::lazy_static;
use std::{collections::HashMap, num::NonZeroU16, pin::Pin, sync::Mutex};

lazy_static! {
    static ref SWITCHBOARD: Mutex<SwitchBoard> = Mutex::new(SwitchBoard(HashMap::default(), 1));
}

struct SwitchBoard(HashMap<NonZeroU16, UnboundedSender<MemorySocket>>, u16);

/// An in-memory socket server, listening for connections.
///
/// After creating a `MemoryListener` by [`bind`]ing it to a socket address, it listens
/// for incoming connections. These can be accepted by awaiting elements from the
/// async stream of incoming connections, [`incoming`][`MemoryListener::incoming`].
///
/// The socket will be closed when the value is dropped.
///
/// [`bind`]: #method.bind
/// [`MemoryListener::incoming`]: #method.incoming
///
/// # Examples
///
/// ```rust,no_run
/// #![feature(async_await)]
/// use std::io::Result;
///
/// use memsocket::{MemoryListener, MemorySocket};
/// use futures::prelude::*;
///
/// async fn write_stormlight(mut stream: MemorySocket) -> Result<()> {
///     let msg = b"The most important step a person can take is always the next one.";
///     stream.write_all(msg).await?;
///     stream.flush().await
/// }
///
/// async fn listen() -> Result<()> {
///     let mut listener = MemoryListener::bind(16)?;
///     let mut incoming = listener.incoming();
///
///     // accept connections and process them serially
///     while let Some(stream) = incoming.next().await {
///         write_stormlight(stream?).await?;
///     }
///     Ok(())
/// }
/// ```
#[derive(Debug)]
pub struct MemoryListener {
    incoming: UnboundedReceiver<MemorySocket>,
    port: NonZeroU16,
}

impl Drop for MemoryListener {
    fn drop(&mut self) {
        let mut switchboard = (&*SWITCHBOARD).lock().unwrap();
        // Remove the Sending side of the channel in the switchboard when
        // MemoryListener is dropped
        switchboard.0.remove(&self.port);
    }
}

impl MemoryListener {
    /// Creates a new `MemoryListener` which will be bound to the specified
    /// port.
    ///
    /// The returned listener is ready for accepting connections.
    ///
    /// Binding with a port number of 0 will request that a port be assigned
    /// to this listener. The port allocated can be queried via the
    /// [`local_addr`] method.
    ///
    /// # Examples
    /// Create a MemoryListener bound to port 16:
    ///
    /// ```rust,no_run
    /// use memsocket::MemoryListener;
    ///
    /// # fn main () -> ::std::io::Result<()> {
    /// let listener = MemoryListener::bind(16)?;
    /// # Ok(())}
    /// ```
    ///
    /// [`local_addr`]: #method.local_addr
    pub fn bind(port: u16) -> Result<Self> {
        let mut switchboard = (&*SWITCHBOARD).lock().unwrap();

        // Get the port we should bind to.  If 0 was given, use a random port
        let port = if let Some(port) = NonZeroU16::new(port) {
            if switchboard.0.contains_key(&port) {
                return Err(ErrorKind::AddrInUse.into());
            }
            port
        } else {
            loop {
                let port = match NonZeroU16::new(switchboard.1) {
                    Some(p) => p,
                    None => unreachable!(),
                };

                // The switchboard is full and all ports are in use
                if switchboard.0.len() == (std::u16::MAX - 1) as usize {
                    return Err(ErrorKind::AddrInUse.into());
                }

                // Instead of overflowing to 0, resume searching at port 1 since port 0 isn't a
                // valid port to bind to.
                if switchboard.1 == std::u16::MAX {
                    switchboard.1 = 1;
                } else {
                    switchboard.1 += 1;
                }

                if !switchboard.0.contains_key(&port) {
                    break port;
                }
            }
        };

        let (sender, receiver) = mpsc::unbounded();
        switchboard.0.insert(port, sender);

        Ok(Self {
            incoming: receiver,
            port,
        })
    }

    /// Returns the local address that this listener is bound to.
    ///
    /// This can be useful, for example, when binding to port 0 to figure out
    /// which port was actually bound.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use memsocket::MemoryListener;
    ///
    /// # fn main () -> ::std::io::Result<()> {
    /// let listener = MemoryListener::bind(16)?;
    ///
    /// assert_eq!(listener.local_addr(), 16);
    /// # Ok(())}
    /// ```
    pub fn local_addr(&self) -> u16 {
        self.port.get()
    }

    /// Consumes this listener, returning a stream of the sockets this listener
    /// accepts.
    ///
    /// This method returns an implementation of the `Stream` trait which
    /// resolves to the sockets the are accepted on this listener.
    ///
    /// # Examples
    ///
    /// ```rust,no_run
    /// #![feature(async_await)]
    /// use futures::prelude::*;
    /// use memsocket::MemoryListener;
    ///
    /// # async fn work () -> ::std::io::Result<()> {
    /// let mut listener = MemoryListener::bind(16)?;
    /// let mut incoming = listener.incoming();
    ///
    /// // accept connections and process them serially
    /// while let Some(stream) = incoming.next().await {
    ///     match stream {
    ///         Ok(stream) => {
    ///             println!("new connection!");
    ///         },
    ///         Err(e) => { /* connection failed */ }
    ///     }
    /// }
    /// # Ok(())}
    /// ```
    pub fn incoming(&mut self) -> Incoming<'_> {
        Incoming { inner: self }
    }

    fn poll_accept(&mut self, context: &mut Context) -> Poll<Result<MemorySocket>> {
        match Pin::new(&mut self.incoming).poll_next(context) {
            Poll::Ready(Some(socket)) => Poll::Ready(Ok(socket)),
            Poll::Ready(None) => {
                let err = Error::new(ErrorKind::Other, "MemoryListener unknown error");
                Poll::Ready(Err(err))
            }
            Poll::Pending => Poll::Pending,
        }
    }
}

/// Stream returned by the `MemoryListener::incoming` function representing the
/// stream of sockets received from a listener.
#[must_use = "streams do nothing unless polled"]
#[derive(Debug)]
pub struct Incoming<'a> {
    inner: &'a mut MemoryListener,
}

impl<'a> Stream for Incoming<'a> {
    type Item = Result<MemorySocket>;

    fn poll_next(mut self: Pin<&mut Self>, context: &mut Context) -> Poll<Option<Self::Item>> {
        let socket = ready!(self.inner.poll_accept(context)?);
        Poll::Ready(Some(Ok(socket)))
    }
}

/// An in-memory stream between two local sockets.
///
/// A `MemorySocket` can either be created by connecting to an endpoint, via the
/// [`connect`] method, or by [accepting] a connection from a [listener].
/// It can be read or written to using the `AsyncRead`, `AsyncWrite`, and related
/// extension traits in `futures::io`.
///
/// # Examples
///
/// ```rust, no_run
/// #![feature(async_await)]
/// use futures::prelude::*;
/// use memsocket::MemorySocket;
///
/// # async fn run() -> ::std::io::Result<()> {
/// let (mut socket_a, mut socket_b) = MemorySocket::new_pair();
///
/// socket_a.write_all(b"stormlight").await?;
/// socket_a.flush().await?;
///
/// let mut buf = [0; 10];
/// socket_b.read_exact(&mut buf).await?;
/// assert_eq!(&buf, b"stormlight");
///
/// # Ok(())}
/// ```
///
/// [`connect`]: struct.MemorySocket.html#method.connect
/// [accepting]: struct.MemoryListener.html#method.accept
/// [listener]: struct.MemoryListener.html
#[derive(Debug)]
pub struct MemorySocket {
    incoming: UnboundedReceiver<Bytes>,
    outgoing: UnboundedSender<Bytes>,
    current_buffer: Option<<Bytes as IntoBuf>::Buf>,
    seen_eof: bool,
}

impl MemorySocket {
    /// Construct both sides of an in-memory socket.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use memsocket::MemorySocket;
    ///
    /// # fn main() {
    /// let (socket_a, socket_b) = MemorySocket::new_pair();
    /// # }
    /// ```
    pub fn new_pair() -> (Self, Self) {
        let (a_tx, a_rx) = mpsc::unbounded();
        let (b_tx, b_rx) = mpsc::unbounded();
        let a = Self {
            incoming: a_rx,
            outgoing: b_tx,
            current_buffer: None,
            seen_eof: false,
        };
        let b = Self {
            incoming: b_rx,
            outgoing: a_tx,
            current_buffer: None,
            seen_eof: false,
        };

        (a, b)
    }

    /// Create a new in-memory Socket connected to the specified port.
    ///
    /// This function will create a new MemorySocket socket and attempt to connect it to
    /// the `port` provided.
    ///
    /// # Examples
    ///
    /// ```rust,no_run
    /// use memsocket::MemorySocket;
    ///
    /// # fn main () -> ::std::io::Result<()> {
    /// let socket = MemorySocket::connect(16)?;
    /// # Ok(())}
    /// ```
    pub fn connect(port: u16) -> Result<MemorySocket> {
        let mut switchboard = (&*SWITCHBOARD).lock().unwrap();

        // Find port to connect to
        let port = if let Some(port) = NonZeroU16::new(port) {
            port
        } else {
            return Err(ErrorKind::AddrNotAvailable.into());
        };

        let sender = if let Some(s) = switchboard.0.get_mut(&port) {
            s
        } else {
            return Err(ErrorKind::AddrNotAvailable.into());
        };

        let (socket_a, socket_b) = Self::new_pair();
        // Send the socket to the listener
        if let Err(e) = sender.unbounded_send(socket_a) {
            if e.is_disconnected() {
                return Err(ErrorKind::AddrNotAvailable.into());
            }

            unreachable!();
        }

        Ok(socket_b)
    }
}

impl AsyncRead for MemorySocket {
    /// Attempt to read from the `AsyncRead` into `buf`.
    fn poll_read(
        mut self: Pin<&mut Self>,
        mut context: &mut Context,
        buf: &mut [u8],
    ) -> Poll<Result<usize>> {
        if self.incoming.is_terminated() {
            if self.seen_eof {
                return Poll::Ready(Err(ErrorKind::UnexpectedEof.into()));
            } else {
                self.seen_eof = true;
                return Poll::Ready(Ok(0));
            }
        }

        let mut bytes_read = 0;

        loop {
            // If we're already filled up the buffer then we can return
            if bytes_read == buf.len() {
                return Poll::Ready(Ok(bytes_read));
            }

            match self.current_buffer {
                // We have data to copy to buf
                Some(ref mut current_buffer) if current_buffer.has_remaining() => {
                    let bytes_to_read =
                        ::std::cmp::min(buf.len() - bytes_read, current_buffer.remaining());
                    debug_assert!(bytes_to_read > 0);

                    current_buffer
                        .take(bytes_to_read)
                        .copy_to_slice(&mut buf[bytes_read..(bytes_read + bytes_to_read)]);
                    bytes_read += bytes_to_read;
                }

                // Either we've exhausted our current buffer or don't have one
                _ => {
                    self.current_buffer = {
                        match Pin::new(&mut self.incoming).poll_next(&mut context) {
                            Poll::Pending => {
                                // If we've read anything up to this point return the bytes read
                                if bytes_read > 0 {
                                    return Poll::Ready(Ok(bytes_read));
                                } else {
                                    return Poll::Pending;
                                }
                            }
                            Poll::Ready(Some(buf)) => Some(buf.into_buf()),
                            Poll::Ready(None) => return Poll::Ready(Ok(bytes_read)),
                        }
                    };
                }
            }
        }
    }
}

impl AsyncWrite for MemorySocket {
    /// Attempt to write bytes from `buf` into the outgoing channel.
    fn poll_write(
        mut self: Pin<&mut Self>,
        context: &mut Context,
        buf: &[u8],
    ) -> Poll<Result<usize>> {
        let len = buf.len();

        match self.outgoing.poll_ready(context) {
            Poll::Ready(Ok(())) => {
                if let Err(e) = self.outgoing.start_send(buf.into()) {
                    if e.is_disconnected() {
                        return Poll::Ready(Err(Error::new(ErrorKind::BrokenPipe, e)));
                    }

                    // Unbounded channels should only ever have "Disconnected" errors
                    unreachable!();
                }
            }
            Poll::Ready(Err(e)) => {
                if e.is_disconnected() {
                    return Poll::Ready(Err(Error::new(ErrorKind::BrokenPipe, e)));
                }

                // Unbounded channels should only ever have "Disconnected" errors
                unreachable!();
            }
            Poll::Pending => return Poll::Pending,
        }

        Poll::Ready(Ok(len))
    }

    /// Attempt to flush the channel. Cannot Fail.
    fn poll_flush(self: Pin<&mut Self>, _context: &mut Context) -> Poll<Result<()>> {
        Poll::Ready(Ok(()))
    }

    /// Attempt to close the channel. Cannot Fail.
    fn poll_close(self: Pin<&mut Self>, _context: &mut Context) -> Poll<Result<()>> {
        self.outgoing.close_channel();

        Poll::Ready(Ok(()))
    }
}
<|endoftext|>


<commit_before>//! method combinators

/// do not use: method combinators moved to the nom-methods crate
#[macro_export]
macro_rules! method (
  ($($args:tt)*) => (compile_error!("method combinators moved to the nom-methods crate"));
);

/// do not use: method combinators moved to the nom-methods crate
#[macro_export]
macro_rules! call_m (
  ($($args:tt)*) => (compile_error!("method combinators moved to the nom-methods crate"));
);

/// do not use: method combinators moved to the nom-methods crate
#[macro_export]
macro_rules! apply_m (
  ($($args:tt)*) => (compile_error!("method combinators moved to the nom-methods crate"));
);

<commit_msg>fix compile_error macro usage<commit_after>//! method combinators

/// do not use: method combinators moved to the nom-methods crate
#[macro_export]
macro_rules! method (
  ($($args:tt)*) => (compile_error!("method combinators moved to the nom-methods crate"););
);

/// do not use: method combinators moved to the nom-methods crate
#[macro_export]
macro_rules! call_m (
  ($($args:tt)*) => (compile_error!("method combinators moved to the nom-methods crate"););
);

/// do not use: method combinators moved to the nom-methods crate
#[macro_export]
macro_rules! apply_m (
  ($($args:tt)*) => (compile_error!("method combinators moved to the nom-methods crate"););
);

<|endoftext|>


<commit_before>// Copyright 2017 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate grin_core as core;
extern crate grin_chain as chain;
extern crate grin_keychain as keychain;
extern crate grin_pow as pow;
extern crate env_logger;
extern crate time;
extern crate rand;

use std::fs;
use std::sync::Arc;

use chain::types::*;
use core::core::build;
use core::core::transaction;
use core::consensus;
use core::global;
use core::global::MiningParameterMode;

use keychain::Keychain;

use pow::{types, cuckoo, MiningWorker};

fn clean_output_dir(dir_name: &str) {
	let _ = fs::remove_dir_all(dir_name);
}

#[test]
fn test_coinbase_maturity() {
	let _ = env_logger::init();
	clean_output_dir(".grin");
	global::set_mining_mode(MiningParameterMode::AutomatedTesting);

	let mut genesis_block = None;
	if !chain::Chain::chain_exists(".grin".to_string()) {
		genesis_block = pow::mine_genesis_block(None);
	}
	let chain = chain::Chain::init(
		".grin".to_string(),
		Arc::new(NoopAdapter {}),
		genesis_block,
		pow::verify_size,
	).unwrap();

	let mut miner_config = types::MinerConfig {
		enable_mining: true,
		burn_reward: true,
		..Default::default()
	};
	miner_config.cuckoo_miner_plugin_dir = Some(String::from("../target/debug/deps"));

	let mut cuckoo_miner = cuckoo::Miner::new(
		consensus::EASINESS,
		global::sizeshift() as u32,
		global::proofsize(),
	);

	let prev = chain.head_header().unwrap();

	let keychain = Keychain::from_random_seed().unwrap();
	let pk1 = keychain.derive_pubkey(1).unwrap();
	let pk2 = keychain.derive_pubkey(2).unwrap();
	let pk3 = keychain.derive_pubkey(3).unwrap();
	let pk4 = keychain.derive_pubkey(4).unwrap();

	let mut block = core::core::Block::new(&prev, vec![], &keychain, pk1.clone()).unwrap();
	block.header.timestamp = prev.timestamp + time::Duration::seconds(60);

	let difficulty = consensus::next_difficulty(chain.difficulty_iter()).unwrap();
	block.header.difficulty = difficulty.clone();
	chain.set_sumtree_roots(&mut block).unwrap();

	pow::pow_size(
		&mut cuckoo_miner,
		&mut block.header,
		difficulty,
		global::sizeshift() as u32,
	).unwrap();

	assert_eq!(block.outputs.len(), 1);
	assert!(block.outputs[0].features.contains(
		transaction::COINBASE_OUTPUT,
	));

	chain.process_block(block, chain::EASY_POW).unwrap();

	let prev = chain.head_header().unwrap();

	let amount = consensus::REWARD;
	let (coinbase_txn, _) = build::transaction(
		vec![
			build::input(amount, pk1.clone()),
			build::output(amount - 1, pk2),
			build::with_fee(1),
		],
		&keychain,
	).unwrap();

	let mut block = core::core::Block::new(&prev, vec![&coinbase_txn], &keychain, pk3.clone())
		.unwrap();
	block.header.timestamp = prev.timestamp + time::Duration::seconds(60);

	let difficulty = consensus::next_difficulty(chain.difficulty_iter()).unwrap();
	block.header.difficulty = difficulty.clone();
	chain.set_sumtree_roots(&mut block).unwrap();

	pow::pow_size(
		&mut cuckoo_miner,
		&mut block.header,
		difficulty,
		global::sizeshift() as u32,
	).unwrap();

	let result = chain.process_block(block, chain::EASY_POW);
	match result {
		Err(Error::ImmatureCoinbase) => (),
		_ => panic!("expected ImmatureCoinbase error here"),
	};

	// mine enough blocks to increase the height sufficiently for
	// coinbase to reach maturity and be spendable in the next block
	for _ in 0..3 {
		let prev = chain.head_header().unwrap();

		let keychain = Keychain::from_random_seed().unwrap();
		let pk = keychain.derive_pubkey(1).unwrap();

		let mut block = core::core::Block::new(&prev, vec![], &keychain, pk).unwrap();
		block.header.timestamp = prev.timestamp + time::Duration::seconds(60);

		let difficulty = consensus::next_difficulty(chain.difficulty_iter()).unwrap();
		block.header.difficulty = difficulty.clone();
		chain.set_sumtree_roots(&mut block).unwrap();

		pow::pow_size(
			&mut cuckoo_miner,
			&mut block.header,
			difficulty,
			global::sizeshift() as u32,
		).unwrap();

		chain.process_block(block, chain::EASY_POW).unwrap();
	}

	let prev = chain.head_header().unwrap();

	let mut block = core::core::Block::new(&prev, vec![&coinbase_txn], &keychain, pk4).unwrap();

	block.header.timestamp = prev.timestamp + time::Duration::seconds(60);

	let difficulty = consensus::next_difficulty(chain.difficulty_iter()).unwrap();
	block.header.difficulty = difficulty.clone();
	chain.set_sumtree_roots(&mut block).unwrap();

	pow::pow_size(
		&mut cuckoo_miner,
		&mut block.header,
		difficulty,
		global::sizeshift() as u32,
	).unwrap();

	let result = chain.process_block(block, chain::EASY_POW);
	match result {
		Ok(_) => (),
		Err(Error::ImmatureCoinbase) => panic!("we should not get an ImmatureCoinbase here"),
		Err(_) => panic!("we did not expect an error here"),
	};
}
<commit_msg>Fix odd fee in coinbase maturity test<commit_after>// Copyright 2017 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate grin_core as core;
extern crate grin_chain as chain;
extern crate grin_keychain as keychain;
extern crate grin_pow as pow;
extern crate env_logger;
extern crate time;
extern crate rand;

use std::fs;
use std::sync::Arc;

use chain::types::*;
use core::core::build;
use core::core::transaction;
use core::consensus;
use core::global;
use core::global::MiningParameterMode;

use keychain::Keychain;

use pow::{types, cuckoo, MiningWorker};

fn clean_output_dir(dir_name: &str) {
	let _ = fs::remove_dir_all(dir_name);
}

#[test]
fn test_coinbase_maturity() {
	let _ = env_logger::init();
	clean_output_dir(".grin");
	global::set_mining_mode(MiningParameterMode::AutomatedTesting);

	let mut genesis_block = None;
	if !chain::Chain::chain_exists(".grin".to_string()) {
		genesis_block = pow::mine_genesis_block(None);
	}
	let chain = chain::Chain::init(
		".grin".to_string(),
		Arc::new(NoopAdapter {}),
		genesis_block,
		pow::verify_size,
	).unwrap();

	let mut miner_config = types::MinerConfig {
		enable_mining: true,
		burn_reward: true,
		..Default::default()
	};
	miner_config.cuckoo_miner_plugin_dir = Some(String::from("../target/debug/deps"));

	let mut cuckoo_miner = cuckoo::Miner::new(
		consensus::EASINESS,
		global::sizeshift() as u32,
		global::proofsize(),
	);

	let prev = chain.head_header().unwrap();

	let keychain = Keychain::from_random_seed().unwrap();
	let pk1 = keychain.derive_pubkey(1).unwrap();
	let pk2 = keychain.derive_pubkey(2).unwrap();
	let pk3 = keychain.derive_pubkey(3).unwrap();
	let pk4 = keychain.derive_pubkey(4).unwrap();

	let mut block = core::core::Block::new(&prev, vec![], &keychain, pk1.clone()).unwrap();
	block.header.timestamp = prev.timestamp + time::Duration::seconds(60);

	let difficulty = consensus::next_difficulty(chain.difficulty_iter()).unwrap();
	block.header.difficulty = difficulty.clone();
	chain.set_sumtree_roots(&mut block).unwrap();

	pow::pow_size(
		&mut cuckoo_miner,
		&mut block.header,
		difficulty,
		global::sizeshift() as u32,
	).unwrap();

	assert_eq!(block.outputs.len(), 1);
	assert!(block.outputs[0].features.contains(
		transaction::COINBASE_OUTPUT,
	));

	chain.process_block(block, chain::EASY_POW).unwrap();

	let prev = chain.head_header().unwrap();

	let amount = consensus::REWARD;
	let (coinbase_txn, _) = build::transaction(
		vec![
			build::input(amount, pk1.clone()),
			build::output(amount - 2, pk2),
			build::with_fee(2),
		],
		&keychain,
	).unwrap();

	let mut block = core::core::Block::new(&prev, vec![&coinbase_txn], &keychain, pk3.clone())
		.unwrap();
	block.header.timestamp = prev.timestamp + time::Duration::seconds(60);

	let difficulty = consensus::next_difficulty(chain.difficulty_iter()).unwrap();
	block.header.difficulty = difficulty.clone();
	chain.set_sumtree_roots(&mut block).unwrap();

	pow::pow_size(
		&mut cuckoo_miner,
		&mut block.header,
		difficulty,
		global::sizeshift() as u32,
	).unwrap();

	let result = chain.process_block(block, chain::EASY_POW);
	match result {
		Err(Error::ImmatureCoinbase) => (),
		_ => panic!("expected ImmatureCoinbase error here"),
	};

	// mine enough blocks to increase the height sufficiently for
	// coinbase to reach maturity and be spendable in the next block
	for _ in 0..3 {
		let prev = chain.head_header().unwrap();

		let keychain = Keychain::from_random_seed().unwrap();
		let pk = keychain.derive_pubkey(1).unwrap();

		let mut block = core::core::Block::new(&prev, vec![], &keychain, pk).unwrap();
		block.header.timestamp = prev.timestamp + time::Duration::seconds(60);

		let difficulty = consensus::next_difficulty(chain.difficulty_iter()).unwrap();
		block.header.difficulty = difficulty.clone();
		chain.set_sumtree_roots(&mut block).unwrap();

		pow::pow_size(
			&mut cuckoo_miner,
			&mut block.header,
			difficulty,
			global::sizeshift() as u32,
		).unwrap();

		chain.process_block(block, chain::EASY_POW).unwrap();
	}

	let prev = chain.head_header().unwrap();

	let mut block = core::core::Block::new(&prev, vec![&coinbase_txn], &keychain, pk4).unwrap();

	block.header.timestamp = prev.timestamp + time::Duration::seconds(60);

	let difficulty = consensus::next_difficulty(chain.difficulty_iter()).unwrap();
	block.header.difficulty = difficulty.clone();
	chain.set_sumtree_roots(&mut block).unwrap();

	pow::pow_size(
		&mut cuckoo_miner,
		&mut block.header,
		difficulty,
		global::sizeshift() as u32,
	).unwrap();

	let result = chain.process_block(block, chain::EASY_POW);
	match result {
		Ok(_) => (),
		Err(Error::ImmatureCoinbase) => panic!("we should not get an ImmatureCoinbase here"),
		Err(_) => panic!("we did not expect an error here"),
	};
}
<|endoftext|>


<commit_before>use std::any::{Any, TypeId};
use std::cell::RefCell;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::mem::transmute;
use std::rc::Rc;

/// Trait for setting up mocks
///
/// The trait is implemented for all functions, so its methods can be called on any function.
///
/// Note: methods have any effect only if called on functions [annotated as mockable](https://docs.rs/mocktopus_macros).
pub trait Mockable<T, O> {

    /// Core function for setting up mocks
    ///
    /// The passed closure is called whenever the mocked function is called. Depending on variant of returned
    /// [MockResult](enum.MockResult.html) the mocked function continues to run or returns immediately.
    /// In case of continuation the function arguments can be modified or replaced.
    ///
    /// The mock closure is saved in a
    /// [thread local static storage](https://doc.rust-lang.org/std/macro.thread_local.html),
    /// so it has effect only in thread, where it was set.
    /// Each Rust test is executed in separate thread, so mocks do not leak between them.
    /// # Safety
    /// It is up to the user to make sure, that the closure is valid long enough to serve all calls to mocked function.
    /// If the mock closure uses any non-static values or references, it will silently become invalid at some point of
    /// host thread lifetime.
    ///
    /// ```
    /// #[mockable]
    /// fn get_string(context: &Context) -> &String {
    ///     context.get_string()
    /// }
    ///
    /// #[test]
    /// fn get_string_test() {
    ///     let mocked = "mocked".to_string();
    ///     unsafe {
    ///         get_string.mock_raw(|_| MockResult::Return(&mocked));
    ///     }
    ///
    ///     assert_eq!("mocked", get_string(&Context::default()));
    /// }
    /// ```
    unsafe fn mock_raw<M: FnMut<T, Output=MockResult<T, O>>>(&self, mock: M);

    /// A safe variant of [mock_raw](#tymethod.mock_raw) for static closures
    ///
    /// The safety is guaranteed by forcing passed closure to be static.
    /// This eliminates the problem of using non-static values, which may not live long enough.
    ///
    /// ```
    /// #[mockable]
    /// fn get_string() -> String {
    ///     "not mocked".to_string()
    /// }
    ///
    /// #[test]
    /// fn get_string_test() {
    ///     get_string.mock_safe(|| MockResult::Return("mocked".to_string()));
    ///
    ///     assert_eq!("mocked", get_string());
    /// }
    /// ```
    fn mock_safe<M: FnMut<T, Output=MockResult<T, O>> + 'static>(&self, mock: M);

    /// Stop mocking this function.
    ///
    /// All future invocations will be forwarded to the real implementation.
    fn clear_mock(&self);

    #[doc(hidden)]
    /// Called before every execution of a mockable function. Checks if mock is set and if it is, calls it.
    fn call_mock(&self, input: T) -> MockResult<T, O>;

    #[doc(hidden)]
    /// Returns a unique ID of the function, which is used to set and get its mock.
    unsafe fn get_mock_id(&self) -> TypeId;
}

/// Controls mocked function behavior when returned from [mock closure](trait.Mockable.html)
pub enum MockResult<T, O> {
    /// Function runs normally as if it was called with given arguments.
    /// The arguments are passed inside enum variant as a tuple.
    Continue(T),

    /// Function returns immediately with a given value. The returned value is passed inside enum variant.
    Return(O),
}

thread_local!{
    static MOCK_STORE: RefCell<HashMap<TypeId, Rc<RefCell<Box<FnMut<(), Output=()>>>>>> = RefCell::new(HashMap::new())
}

/// Clear all mocks in the ThreadLocal; only necessary if tests share threads
pub fn clear_mocks() {
    MOCK_STORE.with(|mock_ref_cell| {
        mock_ref_cell.borrow_mut().clear();
    });
}

struct ScopedMock<'a> {
    phantom: PhantomData<&'a ()>,
    id: TypeId,
}

impl<'a> ScopedMock<'a> {
    unsafe fn new<T, O, M: Mockable<T, O> + 'a, F: FnMut<T, Output=MockResult<T, O>>>(
        mockable: &M,
        mock: F,
    ) -> Self {
        mockable.mock_raw(mock);
        ScopedMock {
            phantom: PhantomData,
            id: mockable.get_mock_id(),
        }
    }
}

impl<'a> Drop for ScopedMock<'a> {
    fn drop(&mut self) {
        clear_id(self.id);
    }
}

fn clear_id(id: TypeId) {
    MOCK_STORE.with(|mock_ref_cell| {
        mock_ref_cell.borrow_mut().remove(&id);
    });
}

impl<T, O, F: FnOnce<T, Output=O>> Mockable<T, O> for F {
    unsafe fn mock_raw<M: FnMut<T, Output=MockResult<T, O>>>(&self, mock: M) {
        let id = self.get_mock_id();
        MOCK_STORE.with(|mock_ref_cell| {
            let real = Rc::new(RefCell::new(Box::new(mock) as Box<FnMut<_, Output=_>>));
            let stored = transmute(real);
            mock_ref_cell.borrow_mut()
                .insert(id, stored);
        })
    }

    fn mock_safe<M: FnMut<T, Output=MockResult<T, O>> + 'static>(&self, mock: M) {
        unsafe {
            self.mock_raw(mock)
        }
    }

    fn clear_mock(&self) {
        let id = unsafe { self.get_mock_id() };
        clear_id(id);
    }

    fn call_mock(&self, input: T) -> MockResult<T, O> {
        unsafe {
            let id = self.get_mock_id();
            let rc_opt = MOCK_STORE.with(|mock_ref_cell|
                mock_ref_cell.borrow()
                    .get(&id)
                    .cloned()
            );
            let stored_opt = rc_opt.as_ref()
                .and_then(|rc| rc.try_borrow_mut().ok());
            match stored_opt {
                Some(mut stored) => {
                    let real: &mut Box<FnMut<_, Output=_>> = transmute(&mut*stored);
                    real.call_mut(input)
                }
                None => MockResult::Continue(input),
            }
        }
    }

    unsafe fn get_mock_id(&self) -> TypeId {
        (||()).type_id()
    }
}

/// `MockContext` allows for safe capture of local variables.
///
/// It does this by forcing only mocking the actual function while in the body
/// of [`run`].
///
/// # Examples
///
/// Simple function replacement:
///
/// ```
/// use mocktopus::macros::mockable;
/// use mocktopus::mocking::{MockContext, MockResult};
///
/// #[mockable]
/// fn f() -> i32 {
///     0
/// }
///
/// MockContext::new()
///     .mock_safe(f, || MockResult::Return(1))
///     .run(|| {
///         assert_eq!(f(), 1);
///     });
/// ```
///
/// Using local variables:
///
/// ```
/// use mocktopus::macros::mockable;
/// use mocktopus::mocking::{MockContext, MockResult};
///
/// #[mockable]
/// fn as_str(s: &String) -> &str {
///     &s
/// }
///
/// let mut count = 0;
/// MockContext::new()
///     .mock_safe(as_str, |s| { count += 1; MockResult::Return(&s) })
///     .run(|| {
///         assert_eq!(as_str(&"abc".to_string()), "abc");
///     });
/// assert_eq!(count, 1);
/// ```
#[derive(Default)]
pub struct MockContext<'a> {
    planned_mocks: HashMap<TypeId, Box<FnOnce() -> ScopedMock<'a> + 'a>>,
}

impl<'a> MockContext<'a> {
    /// Create a new MockContext object.
    pub fn new() -> Self {
        Self::default()
    }

    /// Set up a function to be mocked.
    ///
    /// This function doesn't actually mock the function.  It registers it as a
    /// function that will be mocked when [`run`](#method.run) is called.
    pub fn mock_safe<
        Args,
        Output,
        M: Mockable<Args, Output> + 'a,
        F: FnMut<Args, Output = MockResult<Args, Output>> + 'a,
    >(
        mut self,
        mock: M,
        body: F,
    ) -> Self {
        self.planned_mocks.insert(
            unsafe { mock.get_mock_id() },
            Box::new(move || unsafe { ScopedMock::new(&mock, body) }),
        );
        self
    }

    /// Run the function while mocking all the functions.
    ///
    /// This function will mock all functions registered for mocking, run the
    /// function passed in, then deregister those functions.  It does this in a
    /// panic-safe way.  Note that functions are only mocked in the current
    /// thread and other threads may invoke the real implementations.
    ///
    /// Register a function for mocking with [`mock_safe`](#method.mock_safe).
    pub fn run<T, F: FnOnce() -> T>(self, f: F) -> T {
        let _scoped_mocks = self
            .planned_mocks
            .into_iter()
            .map(|entry| entry.1())
            .collect::<Vec<_>>();
        f()
    }
}
<commit_msg>Create MockStore<commit_after>use std::any::{Any, TypeId};
use std::cell::RefCell;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::mem::transmute;
use std::rc::Rc;

/// Trait for setting up mocks
///
/// The trait is implemented for all functions, so its methods can be called on any function.
///
/// Note: methods have any effect only if called on functions [annotated as mockable](https://docs.rs/mocktopus_macros).
pub trait Mockable<T, O> {

    /// Core function for setting up mocks
    ///
    /// The passed closure is called whenever the mocked function is called. Depending on variant of returned
    /// [MockResult](enum.MockResult.html) the mocked function continues to run or returns immediately.
    /// In case of continuation the function arguments can be modified or replaced.
    ///
    /// The mock closure is saved in a
    /// [thread local static storage](https://doc.rust-lang.org/std/macro.thread_local.html),
    /// so it has effect only in thread, where it was set.
    /// Each Rust test is executed in separate thread, so mocks do not leak between them.
    /// # Safety
    /// It is up to the user to make sure, that the closure is valid long enough to serve all calls to mocked function.
    /// If the mock closure uses any non-static values or references, it will silently become invalid at some point of
    /// host thread lifetime.
    ///
    /// ```
    /// #[mockable]
    /// fn get_string(context: &Context) -> &String {
    ///     context.get_string()
    /// }
    ///
    /// #[test]
    /// fn get_string_test() {
    ///     let mocked = "mocked".to_string();
    ///     unsafe {
    ///         get_string.mock_raw(|_| MockResult::Return(&mocked));
    ///     }
    ///
    ///     assert_eq!("mocked", get_string(&Context::default()));
    /// }
    /// ```
    unsafe fn mock_raw<M: FnMut<T, Output=MockResult<T, O>>>(&self, mock: M);

    /// A safe variant of [mock_raw](#tymethod.mock_raw) for static closures
    ///
    /// The safety is guaranteed by forcing passed closure to be static.
    /// This eliminates the problem of using non-static values, which may not live long enough.
    ///
    /// ```
    /// #[mockable]
    /// fn get_string() -> String {
    ///     "not mocked".to_string()
    /// }
    ///
    /// #[test]
    /// fn get_string_test() {
    ///     get_string.mock_safe(|| MockResult::Return("mocked".to_string()));
    ///
    ///     assert_eq!("mocked", get_string());
    /// }
    /// ```
    fn mock_safe<M: FnMut<T, Output=MockResult<T, O>> + 'static>(&self, mock: M);

    /// Stop mocking this function.
    ///
    /// All future invocations will be forwarded to the real implementation.
    fn clear_mock(&self);

    #[doc(hidden)]
    /// Called before every execution of a mockable function. Checks if mock is set and if it is, calls it.
    fn call_mock(&self, input: T) -> MockResult<T, O>;

    #[doc(hidden)]
    /// Returns a unique ID of the function, which is used to set and get its mock.
    unsafe fn get_mock_id(&self) -> TypeId;
}

/// Controls mocked function behavior when returned from [mock closure](trait.Mockable.html)
pub enum MockResult<T, O> {
    /// Function runs normally as if it was called with given arguments.
    /// The arguments are passed inside enum variant as a tuple.
    Continue(T),

    /// Function returns immediately with a given value. The returned value is passed inside enum variant.
    Return(O),
}

thread_local!{
    // static MOCK_STORE: RefCell<HashMap<TypeId, Rc<RefCell<Box<FnMut<(), Output=()>>>>>> = RefCell::new(HashMap::new())
    static MOCK_STORE: MockStore = MockStore::default()
}

/// Clear all mocks in the ThreadLocal; only necessary if tests share threads
pub fn clear_mocks() {
    MOCK_STORE.with(|mock_store| mock_store.clear())
}

struct ScopedMock<'a> {
    phantom: PhantomData<&'a ()>,
    id: TypeId,
}

impl<'a> ScopedMock<'a> {
    unsafe fn new<T, O, M: Mockable<T, O> + 'a, F: FnMut<T, Output=MockResult<T, O>>>(
        mockable: &M,
        mock: F,
    ) -> Self {
        mockable.mock_raw(mock);
        ScopedMock {
            phantom: PhantomData,
            id: mockable.get_mock_id(),
        }
    }
}

impl<'a> Drop for ScopedMock<'a> {
    fn drop(&mut self) {
        clear_id(self.id);
    }
}

fn clear_id(id: TypeId) {
    MOCK_STORE.with(|mock_store| mock_store.clear_id(id))
}

impl<T, O, F: FnOnce<T, Output=O>> Mockable<T, O> for F {
    unsafe fn mock_raw<M: FnMut<T, Output=MockResult<T, O>>>(&self, mock: M) {
        let id = self.get_mock_id();
        MOCK_STORE.with(|mock_store| mock_store.add(id, mock))
    }

    fn mock_safe<M: FnMut<T, Output=MockResult<T, O>> + 'static>(&self, mock: M) {
        unsafe {
            self.mock_raw(mock)
        }
    }

    fn clear_mock(&self) {
        let id = unsafe { self.get_mock_id() };
        clear_id(id);
    }

    fn call_mock(&self, input: T) -> MockResult<T, O> {
        unsafe {
            let id = self.get_mock_id();
            let rc_opt = MOCK_STORE.with(|mock_store| mock_store.get(id));
            let mock_opt = rc_opt.as_ref().and_then(|rc| rc.try_borrow_mut().ok());
            match mock_opt {
                Some(mut mock) => mock.call_mut(input),
                None => MockResult::Continue(input),
            }
        }
    }

    unsafe fn get_mock_id(&self) -> TypeId {
        (||()).type_id()
    }
}

/// `MockContext` allows for safe capture of local variables.
///
/// It does this by forcing only mocking the actual function while in the body
/// of [`run`].
///
/// # Examples
///
/// Simple function replacement:
///
/// ```
/// use mocktopus::macros::mockable;
/// use mocktopus::mocking::{MockContext, MockResult};
///
/// #[mockable]
/// fn f() -> i32 {
///     0
/// }
///
/// MockContext::new()
///     .mock_safe(f, || MockResult::Return(1))
///     .run(|| {
///         assert_eq!(f(), 1);
///     });
/// ```
///
/// Using local variables:
///
/// ```
/// use mocktopus::macros::mockable;
/// use mocktopus::mocking::{MockContext, MockResult};
///
/// #[mockable]
/// fn as_str(s: &String) -> &str {
///     &s
/// }
///
/// let mut count = 0;
/// MockContext::new()
///     .mock_safe(as_str, |s| { count += 1; MockResult::Return(&s) })
///     .run(|| {
///         assert_eq!(as_str(&"abc".to_string()), "abc");
///     });
/// assert_eq!(count, 1);
/// ```
#[derive(Default)]
pub struct MockContext<'a> {
    planned_mocks: HashMap<TypeId, Box<FnOnce() -> ScopedMock<'a> + 'a>>,
}

impl<'a> MockContext<'a> {
    /// Create a new MockContext object.
    pub fn new() -> Self {
        Self::default()
    }

    /// Set up a function to be mocked.
    ///
    /// This function doesn't actually mock the function.  It registers it as a
    /// function that will be mocked when [`run`](#method.run) is called.
    pub fn mock_safe<
        Args,
        Output,
        M: Mockable<Args, Output> + 'a,
        F: FnMut<Args, Output = MockResult<Args, Output>> + 'a,
    >(
        mut self,
        mock: M,
        body: F,
    ) -> Self {
        self.planned_mocks.insert(
            unsafe { mock.get_mock_id() },
            Box::new(move || unsafe { ScopedMock::new(&mock, body) }),
        );
        self
    }

    /// Run the function while mocking all the functions.
    ///
    /// This function will mock all functions registered for mocking, run the
    /// function passed in, then deregister those functions.  It does this in a
    /// panic-safe way.  Note that functions are only mocked in the current
    /// thread and other threads may invoke the real implementations.
    ///
    /// Register a function for mocking with [`mock_safe`](#method.mock_safe).
    pub fn run<T, F: FnOnce() -> T>(self, f: F) -> T {
        let _scoped_mocks = self
            .planned_mocks
            .into_iter()
            .map(|entry| entry.1())
            .collect::<Vec<_>>();
        f()
    }
}

#[derive(Default)]
struct MockStore {
    mocks: RefCell<HashMap<TypeId, Rc<RefCell<Box<FnMut<(), Output=()>>>>>>,
}

impl MockStore {
    fn clear(&self) {
        self.mocks.borrow_mut().clear()
    }

    fn clear_id(&self, id: TypeId) {
        self.mocks.borrow_mut().remove(&id);
    }

    unsafe fn add<I, O, M: FnMut<I, Output=MockResult<I, O>>>(&self, id: TypeId, mock: M) {
        let boxed = Box::new(mock) as Box<FnMut<_, Output=_>>;
        let real = Rc::new(RefCell::new(boxed));
        let stored = transmute(real);
        self.mocks.borrow_mut().insert(id, stored);
    }

    unsafe fn get<I, O>(&self, id: TypeId)
            -> Option<Rc<RefCell<Box<FnMut<I, Output=MockResult<I, O>>>>>> {
        let mock = self.mocks.borrow().get(&id).cloned();
        transmute(mock)
    }
}
<|endoftext|>