<commit_before>use std::cmp;

use rand::{self, Rng};

use tcod::colors;
use tcod::bsp::{Bsp, TraverseOrder};

use consts;
use object;
use object::actor;
use object::item::Item;
use ai::Ai;

pub const MAP_WIDTH: i32 = 80;
pub const MAP_HEIGHT: i32 = 43;

pub const FLOOR_WIDTH: i32 = 20;
pub const FLOOR_HEIGHT: i32 = 20;

pub const ROOM_MAX_SIZE: i32 = 10;
pub const ROOM_MIN_SIZE: i32 = 6;
pub const MAX_ROOMS: i32 = 30;

pub const MAX_ROOM_MONSTERS: i32 = 3;
pub const MAX_ROOM_ITEMS:i32 = 4;

#[derive(Clone, Copy, Debug, RustcEncodable, RustcDecodable)]
pub struct Tile {
    pub impassable: bool,
    pub blocks_sight: bool,
    pub explored: bool,
}

impl Tile {
    pub fn empty() -> Self {
        Tile{ blocks_sight: false, explored: false, impassable: false, }
    }

    pub fn wall() -> Self {
        Tile{ blocks_sight: true, explored: false, impassable: true,  }
    }
}

pub type Map = Vec<Vec<Tile>>;
pub type Floor = Vec<Vec<Tile>>;

#[derive(Clone, Copy, Debug)]
struct Rect {
    x1: i32,
    y1: i32,
    x2: i32,
    y2: i32,
}

impl Rect {
    pub fn new(x: i32, y: i32, w: i32, h: i32)
        -> Self {
        Rect { x1: x, y1: y, x2: x + w, y2: y + h }
    }

    pub fn center(&self) -> (i32, i32) {
        let center_x = (self.x1 + self.x2) / 2;
        let center_y = (self.y1 + self.y2) / 2;
        (center_x, center_y)
    }

    pub fn intersects_with(&self, other: &Rect) -> bool {
        (self.x1 <= other.x2) && (self.x2 >= other.x1) &&
            (self.y1 <= other.y2) && (self.y2 >= other.y1)
    }
}

pub fn is_blocked(x: i32, y: i32, map: &Map, objects: &[object::Object]) -> bool {
    // first test the map tile
    if map[x as usize][y as usize].impassable {
        return true;
    }
    // now check for any blocking objects
    objects.iter().any(|object| {
        object.blocks && object.pos() == (x, y)
    })
}

fn create_room(room: Rect, map: &mut Map) {
    for x in (room.x1 + 1)..room.x2 {
        for y in (room.y1 + 1)..room.y2 {
            map[x as usize][y as usize] = Tile::empty();
        }
    }
}

fn create_room2(room: &mut Bsp, floor: &mut Floor) {
    for x in (room.x + 1)..room.x + room.w {
        for y in (room.y + 1)..room.y + room.h {
            floor[x as usize][y as usize] = Tile::empty();
        }
    }
}

fn create_h_tunnel(x1: i32, x2: i32, y: i32, map: &mut Map) {
    for x in cmp::min(x1, x2)..(cmp::max(x1, x2) + 1) {
        map[x as usize][y as usize] = Tile::empty();
    }
}

fn create_v_tunnel(y1: i32, y2: i32, x: i32, map: &mut Map) {
    for y in cmp::min(y1, y2)..(cmp::max(y1, y2) + 1) {
        map[x as usize][y as usize] = Tile::empty();
    }
}

// fn vline(x: i32, y1: i32, y2: i32, floor: &mut Floor):
//     if y1 > y2:
//         y1,y2 = y2,y1

//     for y in range(y1,y2+1):
//         map[x][y].blocked = False
//         map[x][y].block_sight = False

fn vline_up(x: i32, y: i32, floor: &mut Floor){
    let mut new_y = y;
    while new_y >= 0 && floor[x as usize][new_y as usize].impassable == true {
        floor[x as usize][new_y as usize] = Tile::empty();
        new_y -= 1;
    }
}

fn vline_down(x: i32, y: i32, floor: &mut Floor){
    let mut new_y = y;
    while new_y < FLOOR_HEIGHT && floor[x as usize][new_y as usize].impassable == true{
        floor[x as usize][new_y as usize] = Tile::empty();
        new_y += 1;
    }
}
// fn hline(map, x1, y, x2):
//     if x1 > x2:
//         x1,x2 = x2,x1
//     for x in range(x1,x2+1):
//         map[x][y].blocked = False
//         map[x][y].block_sight = False

fn hline_left(x: i32, y: i32, floor: &mut Floor) {
    let mut new_x = x;
    while new_x >= 0 && floor[new_x as usize][y as usize].impassable == true {
        floor[new_x as usize][y as usize] = Tile::empty();
        new_x -= 1
    }
}

fn hline_right(x: i32, y: i32, floor: &mut Floor) {
    let mut new_x = x;
    while new_x < FLOOR_WIDTH && floor[new_x as usize][y as usize].impassable == true {
        floor[new_x as usize][y as usize] = Tile::empty();
        new_x += 1
    }
}

fn place_objects(room: Rect, map: &Map, objects: &mut Vec<object::Object>) {
    let num_monsters = rand::thread_rng().gen_range(0, MAX_ROOM_MONSTERS + 1);

    for _ in 0..num_monsters {
        let x = rand::thread_rng().gen_range(room.x1 + 1, room.x2);
        let y = rand::thread_rng().gen_range(room.y1 + 1, room.y2);
        if !is_blocked(x, y, map, objects) {
            let mut monster = if rand::random::<f32>() < 0.8 {
                let mut c_zombie = object::Object::new(x, y, 'Z', "Chrysalis zombie",
                                          colors::DESATURATED_GREEN, true);
                c_zombie.fighter = Some(actor::Fighter{
                    max_hp: 10, hp: 10, defense: 0, power: 3,
                    on_death: actor::DeathCallback::Monster,
                });
                c_zombie.ai = Some(Ai::Chrysalis);
                c_zombie
            } else {
                let mut zombie = object::Object::new(x, y, 'Z', "runner zombie",
                                            colors::DARKER_GREEN, true);
                zombie.fighter = Some(actor::Fighter{
                    max_hp: 16, hp: 16, defense: 1, power: 4,
                    on_death: actor::DeathCallback::Monster,
                });
                zombie.ai = Some(Ai::Basic);
                zombie
            };
            monster.alive = true;
            objects.push(monster);
        }
    }

    let num_items = rand::thread_rng().gen_range(0, MAX_ROOM_ITEMS + 1);

    for _ in 0..num_items {
        let x = rand::thread_rng().gen_range(room.x1 + 1, room.x2);
        let y = rand::thread_rng().gen_range(room.y1 + 1, room.y2);

        if !is_blocked(x, y, map, objects) {
            let dice = rand::random::<f32>();
            let item = if dice < 0.7 {
                let mut object = object::Object::new(x, y, '!', "First aid kit",
                                             colors::VIOLET, false);
                object.item = Some(Item::Heal);
                object
            } else if dice < 0.7 + 0.1 {
                let mut object = object::Object::new(x, y, '#',
                                             "scroll of lightning bolt",
                                             colors::LIGHT_YELLOW, false);
                object.item = Some(Item::Lightning);
                object
            } else if dice < 0.7 + 0.1 + 0.1 {
                let mut object = object::Object::new(x, y, '#', "molotov cocktail",
                                             colors::LIGHT_YELLOW, false);
                object.item = Some(Item::Fireball);
                object
            } else {
                let mut object = object::Object::new(x, y, '#', "scroll of confusion",
                                             colors::LIGHT_YELLOW, false);
                object.item = Some(Item::Confuse);
                object
            };
            objects.push(item);
        }
    }
}

fn traverse_node(node: &mut Bsp, mut floor: &mut Floor) -> bool {
    if node.is_leaf() {
        let mut minx = node.x + 1;
        let mut maxx = node.x + node.w - 1;
        let mut miny = node.y + 1;
        let mut maxy = node.y + node.h - 1;
        if maxx == FLOOR_WIDTH - 1 {
            maxx -= 1;
        }
        if maxy == FLOOR_HEIGHT - 1 {
            maxy -= 1;
        }
        node.x = minx;
        node.y = miny;
        node.w = maxx - minx + 1;
        node.h = maxy - miny + 1;

        create_room2(node, floor);
    } else {
        if node.left().is_some() && node.right().is_some() {
            let left = node.left().unwrap();
            let right = node.right().unwrap();
            println!("{:?}", left);
            node.x = cmp::min(left.x, right.x);
            node.y = cmp::min(left.y, right.y);
            node.w = cmp::max(left.x + left.w, right.x + right.w) - node.x;
            node.h = cmp::max(left.y + left.h, right.y + right.h) - node.y;
            if node.horizontal() {
                if left.x + left.w - 1 < right.x ||
                    right.x + right.w - 1 < left.x {
                        let x1 = rand::thread_rng()
                            .gen_range(left.x, left.x + left.w - 1);
                        let x2 = rand::thread_rng()
                            .gen_range(right.x, right.x + right.w - 1);
                        let y = rand::thread_rng()
                            .gen_range(left.y + left.h, right.y);
                        vline_up(x1, y - 1, &mut floor);
                        create_h_tunnel(x1, x2, y, &mut floor);
                        vline_down(x2, y + 1, &mut floor);
                    } else {
                        let minx = cmp::max(left.x, right.x);
                        let maxx = cmp::min(left.x + left.w - 1,
                                            right.x + right.w - 1);
                        let x = rand::thread_rng().gen_range(minx, maxx);
                        vline_down(x, right.y, &mut floor);
                        vline_up(x, right.y - 1, &mut floor);
                    }

            } else {
                if left.y + left.h - 1 < right.y ||
                    right.y + right.h - 1 < left.y {
                        let y1 = rand::thread_rng()
                            .gen_range(left.y, left.y + left.h - 1);
                        let y2 = rand::thread_rng()
                            .gen_range(right.y, right.y + right.h - 1);
                        let x = rand::thread_rng()
                            .gen_range(left.x + left.w, right.x);
                        hline_left(x - 1, y1, &mut floor);
                        create_v_tunnel(y1, y2, x, &mut floor);
                        hline_right(x + 1, y2, &mut floor);
                    } else {
                        let miny = cmp::max(left.y, right.y);
                        let maxy = cmp::min(left.y + left.h - 1,
                                            right.y + right.h - 1);
                        let y = rand::thread_rng().gen_range(miny, maxy);
                        hline_left(right.x - 1, y, &mut floor);
                        hline_right(right.x, y, &mut floor);
                    }
            }
        }
    }
    true
}

pub fn make_floor() -> Map {
    let mut floor = vec![vec![Tile::wall(); FLOOR_HEIGHT as usize];
                         FLOOR_WIDTH as usize];
    // let mut rooms = vec![];

    let mut bsp = Bsp::new_with_size(0, 0, FLOOR_WIDTH, FLOOR_HEIGHT);
    bsp.split_recursive(None, 10, 6, 6, 1.5, 1.5);
    let mut counter = 0;
    bsp.traverse(TraverseOrder::InvertedLevelOrder, |node| {
        traverse_node(node, &mut floor)
    });
    floor
}

pub fn make_map(objects: &mut Vec<object::Object>) -> Map {
    make_floor();
    let mut map = vec![vec![Tile::wall(); MAP_HEIGHT as usize];
                       MAP_WIDTH as usize];
    let mut rooms = vec![];
    assert_eq!(&objects[consts::PLAYER] as *const _, &objects[0] as *const _);
    objects.truncate(1);

    for _ in 0..MAX_ROOMS {
        let w = rand::thread_rng().gen_range(ROOM_MIN_SIZE,
                                             ROOM_MAX_SIZE + 1);
        let h = rand::thread_rng().gen_range(ROOM_MIN_SIZE,
                                             ROOM_MAX_SIZE + 1);
        let x = rand::thread_rng().gen_range(0, MAP_WIDTH - w);
        let y = rand::thread_rng().gen_range(0, MAP_HEIGHT - h);

        let new_room = Rect::new(x, y, w, h);

        let failed = rooms.iter().any(|other_room
                                      |new_room.intersects_with(
                                          other_room));

        if !failed {

            create_room(new_room, &mut map);
            place_objects(new_room, &map, objects);

            let (new_x, new_y) = new_room.center();

            if rooms.is_empty() {
                objects[consts::PLAYER].set_pos(new_x, new_y);
            } else {
                let (prev_x, prev_y) =
                    rooms[rooms.len() - 1].center();

                if rand::random() {
                    create_h_tunnel(prev_x, new_x,
                                    prev_y, &mut map);
                    create_v_tunnel(prev_y, new_y,
                                    prev_x, &mut map);
                } else {
                    create_v_tunnel(prev_y, new_y,
                                    prev_x, &mut map);
                    create_h_tunnel(prev_x, new_x,
                                    prev_y, &mut map);
                }
            }
            rooms.push(new_room);
        }

    }
    let (last_room_x, last_room_y) = rooms[rooms.len() - 1].center();
    let stairs = object::Object::new(last_room_x, last_room_y, '>', "stairs up",
                             colors::WHITE, false);
    objects.push(stairs);
    map
}
<commit_msg>Make "impassable" same as objects: "blocks" Use "if let" with variable decomposition!<commit_after>use std::cmp;

use rand::{self, Rng};

use tcod::colors;
use tcod::bsp::{Bsp, TraverseOrder};

use consts;
use object;
use object::actor;
use object::item::Item;
use ai::Ai;

pub const MAP_WIDTH: i32 = 80;
pub const MAP_HEIGHT: i32 = 43;

pub const FLOOR_WIDTH: i32 = 20;
pub const FLOOR_HEIGHT: i32 = 20;

pub const ROOM_MAX_SIZE: i32 = 10;
pub const ROOM_MIN_SIZE: i32 = 6;
pub const MAX_ROOMS: i32 = 30;

pub const MAX_ROOM_MONSTERS: i32 = 3;
pub const MAX_ROOM_ITEMS:i32 = 4;

#[derive(Clone, Copy, Debug, RustcEncodable, RustcDecodable)]
pub struct Tile {
    pub blocks: bool,
    pub blocks_sight: bool,
    pub explored: bool,
}

impl Tile {
    pub fn empty() -> Self {
        Tile{ blocks_sight: false, explored: false, blocks: false, }
    }

    pub fn wall() -> Self {
        Tile{ blocks_sight: true, explored: false, blocks: true,  }
    }
}

pub type Map = Vec<Vec<Vec<object::Object>>>;
//pub type Floor = Vec<Vec<Vec<object::Object>>>;

#[derive(Clone, Copy, Debug)]
struct Rect {
    x1: i32,
    y1: i32,
    x2: i32,
    y2: i32,
}

impl Rect {
    pub fn new(x: i32, y: i32, w: i32, h: i32)
        -> Self {
        Rect { x1: x, y1: y, x2: x + w, y2: y + h }
    }

    pub fn center(&self) -> (i32, i32) {
        let center_x = (self.x1 + self.x2) / 2;
        let center_y = (self.y1 + self.y2) / 2;
        (center_x, center_y)
    }

    pub fn intersects_with(&self, other: &Rect) -> bool {
        (self.x1 <= other.x2) && (self.x2 >= other.x1) &&
            (self.y1 <= other.y2) && (self.y2 >= other.y1)
    }
}

pub fn is_blocked(x: i32, y: i32, map: &Map, objects: &[object::Object]) -> bool {
    // first test the map tile
    if map[x as usize][y as usize].blocks {
        return true;
    }
    // now check for any blocking objects
    objects.iter().any(|object| {
        object.blocks && object.pos() == (x, y)
    })
}

fn create_room(room: Rect, map: &mut Map) {
    for x in (room.x1 + 1)..room.x2 {
        for y in (room.y1 + 1)..room.y2 {
            map[x as usize][y as usize] = Tile::empty();
        }
    }
}

fn create_room2(room: &mut Bsp, floor: &mut Map) {
    for x in (room.x + 1)..room.x + room.w {
        for y in (room.y + 1)..room.y + room.h {
            floor[x as usize][y as usize] = Tile::empty();
        }
    }
}

fn create_h_tunnel(x1: i32, x2: i32, y: i32, map: &mut Map) {
    for x in cmp::min(x1, x2)..(cmp::max(x1, x2) + 1) {
        map[x as usize][y as usize] = Tile::empty();
    }
}

fn create_v_tunnel(y1: i32, y2: i32, x: i32, map: &mut Map) {
    for y in cmp::min(y1, y2)..(cmp::max(y1, y2) + 1) {
        map[x as usize][y as usize] = Tile::empty();
    }
}

fn vline_up(x: i32, y: i32, floor: &mut Map){
    let mut new_y = y;
    while new_y >= 0 && floor[x as usize][new_y as usize].blocks == true {
        floor[x as usize][new_y as usize] = Tile::empty();
        new_y -= 1;
    }
}

fn vline_down(x: i32, y: i32, floor: &mut Map){
    let mut new_y = y;
    while new_y < FLOOR_HEIGHT && floor[x as usize][new_y as usize].blocks == true{
        floor[x as usize][new_y as usize] = Tile::empty();
        new_y += 1;
    }
}

fn hline_left(x: i32, y: i32, floor: &mut Map) {
    let mut new_x = x;
    while new_x >= 0 && floor[new_x as usize][y as usize].blocks == true {
        floor[new_x as usize][y as usize] = Tile::empty();
        new_x -= 1
    }
}

fn hline_right(x: i32, y: i32, floor: &mut Map) {
    let mut new_x = x;
    while new_x < FLOOR_WIDTH && floor[new_x as usize][y as usize].blocks == true {
        floor[new_x as usize][y as usize] = Tile::empty();
        new_x += 1
    }
}

fn place_objects(room: Rect, map: &Map, objects: &mut Vec<object::Object>) {
    let num_monsters = rand::thread_rng().gen_range(0, MAX_ROOM_MONSTERS + 1);

    for _ in 0..num_monsters {
        let x = rand::thread_rng().gen_range(room.x1 + 1, room.x2);
        let y = rand::thread_rng().gen_range(room.y1 + 1, room.y2);
        if !is_blocked(x, y, map, objects) {
            let mut monster = if rand::random::<f32>() < 0.8 {
                let mut c_zombie = object::Object::new(x, y, 'Z', "Chrysalis zombie",
                                          colors::DESATURATED_GREEN, true);
                c_zombie.fighter = Some(actor::Fighter{
                    max_hp: 10, hp: 10, defense: 0, power: 3,
                    on_death: actor::DeathCallback::Monster,
                });
                c_zombie.ai = Some(Ai::Chrysalis);
                c_zombie
            } else {
                let mut zombie = object::Object::new(x, y, 'Z', "runner zombie",
                                            colors::DARKER_GREEN, true);
                zombie.fighter = Some(actor::Fighter{
                    max_hp: 16, hp: 16, defense: 1, power: 4,
                    on_death: actor::DeathCallback::Monster,
                });
                zombie.ai = Some(Ai::Basic);
                zombie
            };
            monster.alive = true;
            objects.push(monster);
        }
    }

    let num_items = rand::thread_rng().gen_range(0, MAX_ROOM_ITEMS + 1);

    for _ in 0..num_items {
        let x = rand::thread_rng().gen_range(room.x1 + 1, room.x2);
        let y = rand::thread_rng().gen_range(room.y1 + 1, room.y2);

        if !is_blocked(x, y, map, objects) {
            let dice = rand::random::<f32>();
            let item = if dice < 0.7 {
                let mut object = object::Object::new(x, y, '!', "First aid kit",
                                             colors::VIOLET, false);
                object.item = Some(Item::Heal);
                object
            } else if dice < 0.7 + 0.1 {
                let mut object = object::Object::new(x, y, '#',
                                             "scroll of lightning bolt",
                                             colors::LIGHT_YELLOW, false);
                object.item = Some(Item::Lightning);
                object
            } else if dice < 0.7 + 0.1 + 0.1 {
                let mut object = object::Object::new(x, y, '#', "molotov cocktail",
                                             colors::LIGHT_YELLOW, false);
                object.item = Some(Item::Fireball);
                object
            } else {
                let mut object = object::Object::new(x, y, '#', "scroll of confusion",
                                             colors::LIGHT_YELLOW, false);
                object.item = Some(Item::Confuse);
                object
            };
            objects.push(item);
        }
    }
}

fn traverse_node(node: &mut Bsp, mut floor: &mut Map) -> bool {
    if node.is_leaf() {
        let mut minx = node.x + 1;
        let mut maxx = node.x + node.w - 1;
        let mut miny = node.y + 1;
        let mut maxy = node.y + node.h - 1;
        if maxx == FLOOR_WIDTH - 1 {
            maxx -= 1;
        }
        if maxy == FLOOR_HEIGHT - 1 {
            maxy -= 1;
        }
        node.x = minx;
        node.y = miny;
        node.w = maxx - minx + 1;
        node.h = maxy - miny + 1;

        create_room2(node, floor);
    } else {
        // if node.left().is_some() && node.right().is_some() {
        //     let left = node.left().unwrap();
        //     let right = node.right().unwrap();
        if let (Some(left), Some(right)) = (node.left(), node.right()) {
            node.x = cmp::min(left.x, right.x);
            node.y = cmp::min(left.y, right.y);
            node.w = cmp::max(left.x + left.w, right.x + right.w) - node.x;
            node.h = cmp::max(left.y + left.h, right.y + right.h) - node.y;
            if node.horizontal() {
                if left.x + left.w - 1 < right.x ||
                    right.x + right.w - 1 < left.x {
                        let x1 = rand::thread_rng()
                            .gen_range(left.x, left.x + left.w - 1);
                        let x2 = rand::thread_rng()
                            .gen_range(right.x, right.x + right.w - 1);
                        let y = rand::thread_rng()
                            .gen_range(left.y + left.h, right.y);
                        vline_up(x1, y - 1, &mut floor);
                        create_h_tunnel(x1, x2, y, &mut floor);
                        vline_down(x2, y + 1, &mut floor);
                    } else {
                        let minx = cmp::max(left.x, right.x);
                        let maxx = cmp::min(left.x + left.w - 1,
                                            right.x + right.w - 1);
                        let x = rand::thread_rng().gen_range(minx, maxx);
                        vline_down(x, right.y, &mut floor);
                        vline_up(x, right.y - 1, &mut floor);
                    }

            } else {
                if left.y + left.h - 1 < right.y ||
                    right.y + right.h - 1 < left.y {
                        let y1 = rand::thread_rng()
                            .gen_range(left.y, left.y + left.h - 1);
                        let y2 = rand::thread_rng()
                            .gen_range(right.y, right.y + right.h - 1);
                        let x = rand::thread_rng()
                            .gen_range(left.x + left.w, right.x);
                        hline_left(x - 1, y1, &mut floor);
                        create_v_tunnel(y1, y2, x, &mut floor);
                        hline_right(x + 1, y2, &mut floor);
                    } else {
                        let miny = cmp::max(left.y, right.y);
                        let maxy = cmp::min(left.y + left.h - 1,
                                            right.y + right.h - 1);
                        let y = rand::thread_rng().gen_range(miny, maxy);
                        hline_left(right.x - 1, y, &mut floor);
                        hline_right(right.x, y, &mut floor);
                    }
            }
        }
    }
    true
}

pub fn make_floor() -> Map {
    let mut floor = vec![vec![Tile::wall(); FLOOR_HEIGHT as usize];
                         FLOOR_WIDTH as usize];
    // let mut rooms = vec![];

    let mut bsp = Bsp::new_with_size(0, 0, FLOOR_WIDTH, FLOOR_HEIGHT);
    bsp.split_recursive(None, 10, 6, 6, 1.5, 1.5);
    let mut counter = 0;
    bsp.traverse(TraverseOrder::InvertedLevelOrder, |node| {
        traverse_node(node, &mut floor)
    });
    floor
}

pub fn make_map(objects: &mut Vec<object::Object>) -> Map {
    make_floor();
    let mut map = vec![vec![Tile::wall(); MAP_HEIGHT as usize];
                       MAP_WIDTH as usize];
    let mut rooms = vec![];
    assert_eq!(&objects[consts::PLAYER] as *const _, &objects[0] as *const _);
    objects.truncate(1);

    for _ in 0..MAX_ROOMS {
        let w = rand::thread_rng().gen_range(ROOM_MIN_SIZE,
                                             ROOM_MAX_SIZE + 1);
        let h = rand::thread_rng().gen_range(ROOM_MIN_SIZE,
                                             ROOM_MAX_SIZE + 1);
        let x = rand::thread_rng().gen_range(0, MAP_WIDTH - w);
        let y = rand::thread_rng().gen_range(0, MAP_HEIGHT - h);

        let new_room = Rect::new(x, y, w, h);

        let failed = rooms.iter().any(|other_room
                                      |new_room.intersects_with(
                                          other_room));

        if !failed {

            create_room(new_room, &mut map);
            place_objects(new_room, &map, objects);

            let (new_x, new_y) = new_room.center();

            if rooms.is_empty() {
                objects[consts::PLAYER].set_pos(new_x, new_y);
            } else {
                let (prev_x, prev_y) =
                    rooms[rooms.len() - 1].center();

                if rand::random() {
                    create_h_tunnel(prev_x, new_x,
                                    prev_y, &mut map);
                    create_v_tunnel(prev_y, new_y,
                                    prev_x, &mut map);
                } else {
                    create_v_tunnel(prev_y, new_y,
                                    prev_x, &mut map);
                    create_h_tunnel(prev_x, new_x,
                                    prev_y, &mut map);
                }
            }
            rooms.push(new_room);
        }

    }
    let (last_room_x, last_room_y) = rooms[rooms.len() - 1].center();
    let stairs = object::Object::new(last_room_x, last_room_y, '>', "stairs up",
                             colors::WHITE, false);
    objects.push(stairs);
    map
}
<|endoftext|>


<commit_before>/// `RouteGraph` defines a Directed Acyclic Graph of Effects.
/// The edges connecting each Effect have a source and destination slot.
/// Edges are also allowed to go to null, in which case they are treated as outputs.
/// Edges can also come from null, in which case they are treated as inputs.

use std::collections::hash_map::HashMap;
use std::collections::hash_map;
use std::collections::hash_set::HashSet;
use std::rc::Rc;

use resman::ResMan;
use super::adjlist::AdjList;
use super::effect;
use super::effect::Effect;
use super::nullable_int::NullableInt;

#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
pub struct EdgeWeight {
    from_slot: u32,
    to_slot: u32,
}

pub type NodeData = Rc<Effect>;

/// None represents the Dag's I/O
type PrimNodeHandle = NullableInt<u32>;

#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
pub struct NodeHandle {
    node_handle: PrimNodeHandle,
}

#[derive(Clone, Debug, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
pub struct Edge {
    from: NodeHandle,
    to: NodeHandle,
    weight: EdgeWeight,
}

#[derive(Debug)]
pub enum Error {
    /// Raised when an attempt to modify the graph would create a dependency cycle.
    WouldCycle,
    /// Raised on attempt to delete a node when it still has edges.
    NodeInUse,
    /// Raised on attempt to create a node with an id that's already in use.
    NodeExists,
    /// Error inside some Effect:: method
    EffectError(effect::Error),
}

/// Alias for a `Result` with our error type.
pub type ResultE<T> = Result<T, Error>;

#[derive(Default, Debug)]
pub struct RouteGraph {
    edges: HashMap<NodeHandle, EdgeSet>,
    node_data: HashMap<NodeHandle, NodeData>,
}

#[derive(Debug)]
struct EdgeSet {
    outbound: HashSet<Edge>,
    inbound: HashSet<Edge>,
}

impl RouteGraph {
    pub fn new() -> Self {
        Default::default()
    }
    pub fn iter_nodes<'a>(&'a self) -> impl Iterator<Item=(&NodeHandle, &NodeData)> + 'a {
        self.node_data.iter()
    }
    pub fn iter_edges<'a>(&'a self) -> impl Iterator<Item=&Edge> + 'a {
        self.edges.values().flat_map(|v_set| v_set.outbound.iter())
    }
    pub fn get_data(&self, handle: &NodeHandle) -> Option<&NodeData> {
        self.node_data.get(handle)
    }
    /// Try to create a node with the given handle/data.
    /// Will error if the handle is already in use.
    pub fn add_node(&mut self, handle: NodeHandle, node_data: NodeData) -> ResultE<()> {
        // Create storage for the node's outgoing edges
        match self.edges.entry(handle) {
            hash_map::Entry::Occupied(_) => Err(Error::NodeExists),
            hash_map::Entry::Vacant(entry) => { entry.insert(EdgeSet::new()); Ok(()) },
        }?;
        // Store the node's data
        assert!(self.node_data.insert(handle, node_data.clone()).is_none());
        Ok(())
    }
    pub fn add_edge(&mut self, edge: Edge) -> ResultE<()> {
        // Algorithm:
        //   Assume we currently have a DAG.
        //   Given that, the only way this new edge could introduce a cycle is if it was a part of
        //     that cycle.
        //   Therefore, if no path exists from the edge to itself, then it is safe to add the edge.
        let is_reachable = self.is_edge_reachable(&edge, &edge);
        if is_reachable {
            Err(Error::WouldCycle)
        } else {
            self.add_edge_unchecked(edge);
            Ok(())
        }
    }
    fn add_edge_unchecked(&mut self, edge: Edge) {
        // associate the edge with its origin.
        self.edges.entry(edge.from_full()).or_insert_with(EdgeSet::new).outbound.insert(edge.clone());
        // associate the edge with its destination.
        self.edges.entry(edge.to_full()).or_insert_with(EdgeSet::new).inbound.insert(edge);
    }
    fn is_edge_reachable(&self, from: &Edge, target: &Edge) -> bool {
        // Algorithm:
        //   Try to reach `edge` from `edge`.
        //   If we reach the boundary of the DAG while doing so, consider all reachable outbound
        //     edges of the DAG
        //     For each such edge, try to reach this DAG (recursively), and then resume the search for `edge`.
        if let Some(_to) = from.to.node_handle.get() {
            // The edge points to a NODE inside a DAG.
            // Consider all (reachable) outgoing edges of the node:
            if let Some(node_data) = self.edges.get(&from.to_full()) {
                for candidate_edge in &node_data.outbound {
                    if self.are_edges_internally_connected(from, candidate_edge) &&
                      self.is_edge_reachable(candidate_edge, target) {
                        return true;
                    }
                }
            }
        }
        false
    }
    /// Assuming from.to() == to.from(), will return true if & only if
    /// from and to are internally connected within the node.
    fn are_edges_internally_connected(&self, from: &Edge, to: &Edge) -> bool {
        self.node_data[&from.to_full()]
            .are_slots_connected(from.weight.to_slot, to.weight.from_slot)
    }
    /// Returns true if there's a path from `in` to `out` at the toplevel DAG.
    pub fn are_slots_connected(&self, in_slot: u32, out_slot: u32) -> bool {
        // Consider all edges from None paired with all edges to None:
        let root_dag = NodeHandle::toplevel();
        let edges_from = self.edges[&root_dag].outbound.iter().filter(|&edge| {
            edge.weight.from_slot == in_slot
        });
        for edge_from in edges_from {
            let edges_to = self.edges[&root_dag].inbound.iter().filter(|&edge| {
                edge.weight.to_slot == out_slot
            });
            for edge_to in edges_to {
                if self.is_edge_reachable(edge_from, edge_to) {
                    return true;
                }
            }
        }
        false
    }
    pub fn del_node(&mut self, node: NodeHandle) -> ResultE<()> {
        let ok_to_delete = match self.edges.entry(node) {
            // Already deleted
            hash_map::Entry::Vacant(_) => Ok(()),
            hash_map::Entry::Occupied(entry) => {
                if entry.get().is_empty() {
                    entry.remove();
                    Ok(())
                } else {
                    // Node has edges
                    Err(Error::NodeInUse)
                }
            }
        };
        if ok_to_delete.is_ok() {
            // delete the data associated with this node
            self.node_data.remove(&node);
        }
        ok_to_delete
    }
    pub fn del_edge(&mut self, edge: Edge) {
        // TODO: garbage collect the edge sets.
        if let Some(edge_set) = self.edges.get_mut(&edge.from_full()) {
            edge_set.outbound.remove(&edge);
        }
        if let Some(edge_set) = self.edges.get_mut(&edge.to_full()) {
            edge_set.inbound.remove(&edge);
        }
    }

    pub fn to_adjlist(&self) -> AdjList {
        // Map Effect -> EffectId
        let nodes = self.node_data.iter().map(|(handle, data)| {
            (*handle, data.id().clone())
        }).collect();
        // Doubly-linked edges -> singly-linked
        let edges = self.edges.iter().flat_map(|(_key, edgeset)| {
            edgeset.outbound.clone().into_iter()
        }).collect();

        AdjList {
            nodes: nodes,
            edges: edges,
        }
    }
    pub fn from_adjlist(adj: AdjList, res: &ResMan) -> ResultE<Self> {
        // Unwrap struct fields to local variables
        let (nodes, edges) = (adj.nodes, adj.edges);

        // Map EffectId -> Effect
        let nodes: ResultE<HashMap<NodeHandle, NodeData>> = nodes.into_iter().map(|(handle, id)| {
            let decoded_data = Effect::from_id(id, res)?;
            Ok((handle, decoded_data))
        }).collect();
        // Type deduction isn't smart enough to unwrap nodes in above statement.
        let nodes = nodes?;

        // Build self with only nodes and no edges
        let mut me = Self {
            edges: HashMap::new(),
            node_data: nodes,
        };

        // Add the edges one at a time, enforcing zero cycles
        for edge in &edges {
            me.add_edge(edge.clone())?
        }
        Ok(me)
    }
}

impl NodeHandle {
    pub fn toplevel() -> Self {
        NodeHandle::new(None)
    }
    pub fn new<T>(node_handle: T) -> Self
        where T: Into<PrimNodeHandle>
    {
        Self{ node_handle: node_handle.into() }
    }
    pub fn node_handle(&self) -> &PrimNodeHandle {
        &self.node_handle
    }
}

impl Edge {
    /// Create an edge from `from` to null (i.e. an output)
    pub fn new_to_null(from: NodeHandle, weight: EdgeWeight) -> Self {
        Self {
            from,
            to: NodeHandle::toplevel(),
            weight,
        }
    }
    pub fn new_from_null(to: NodeHandle, weight: EdgeWeight) -> Self {
        Self {
            from: NodeHandle::toplevel(),
            to,
            weight
        }
    }
    /// Create an edge between the two nodes.
    pub fn new(from: NodeHandle, to: NodeHandle, weight: EdgeWeight) -> Self {
        Self{ from, to, weight }
    }
    // TODO: rename to 'from' and 'to' or 'from_hnd', 'to_hnd'?
    pub fn from_full(&self) -> NodeHandle {
        self.from
    }
    pub fn to_full(&self) -> NodeHandle {
        self.to
    }
    pub fn to_slot(&self) -> u32 {
        self.weight.to_slot
    }
    pub fn from_slot(&self) -> u32 {
        self.weight.from_slot
    }
}

impl EdgeWeight {
    pub fn new(from_slot: u32, to_slot: u32) -> Self {
        Self{ from_slot, to_slot }
    }
}

impl EdgeSet {
    fn new() -> Self {
        EdgeSet {
            outbound: HashSet::new(),
            inbound: HashSet::new(),
        }
    }
    fn is_empty(&self) -> bool {
        self.outbound.is_empty() && self.inbound.is_empty()
    }
}

/// Conversion from `effect::Error` for use with the `?` operator
impl From<effect::Error> for Error {
    fn from(e: effect::Error) -> Self {
        Error::EffectError(e)
    }
}
<commit_msg>Impl `Display` for NodeHandle<commit_after>/// `RouteGraph` defines a Directed Acyclic Graph of Effects.
/// The edges connecting each Effect have a source and destination slot.
/// Edges are also allowed to go to null, in which case they are treated as outputs.
/// Edges can also come from null, in which case they are treated as inputs.

use std::collections::hash_map::HashMap;
use std::collections::hash_map;
use std::collections::hash_set::HashSet;
use std::fmt::{Display, Formatter};
use std::fmt;
use std::rc::Rc;

use resman::ResMan;
use super::adjlist::AdjList;
use super::effect;
use super::effect::Effect;
use super::nullable_int::NullableInt;

#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
pub struct EdgeWeight {
    from_slot: u32,
    to_slot: u32,
}

pub type NodeData = Rc<Effect>;

/// None represents the Dag's I/O
type PrimNodeHandle = NullableInt<u32>;

#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
pub struct NodeHandle {
    node_handle: PrimNodeHandle,
}

#[derive(Clone, Debug, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
pub struct Edge {
    from: NodeHandle,
    to: NodeHandle,
    weight: EdgeWeight,
}

#[derive(Debug)]
pub enum Error {
    /// Raised when an attempt to modify the graph would create a dependency cycle.
    WouldCycle,
    /// Raised on attempt to delete a node when it still has edges.
    NodeInUse,
    /// Raised on attempt to create a node with an id that's already in use.
    NodeExists,
    /// Error inside some Effect:: method
    EffectError(effect::Error),
}

/// Alias for a `Result` with our error type.
pub type ResultE<T> = Result<T, Error>;

#[derive(Default, Debug)]
pub struct RouteGraph {
    edges: HashMap<NodeHandle, EdgeSet>,
    node_data: HashMap<NodeHandle, NodeData>,
}

#[derive(Debug)]
struct EdgeSet {
    outbound: HashSet<Edge>,
    inbound: HashSet<Edge>,
}

impl RouteGraph {
    pub fn new() -> Self {
        Default::default()
    }
    pub fn iter_nodes<'a>(&'a self) -> impl Iterator<Item=(&NodeHandle, &NodeData)> + 'a {
        self.node_data.iter()
    }
    pub fn iter_edges<'a>(&'a self) -> impl Iterator<Item=&Edge> + 'a {
        self.edges.values().flat_map(|v_set| v_set.outbound.iter())
    }
    pub fn get_data(&self, handle: &NodeHandle) -> Option<&NodeData> {
        self.node_data.get(handle)
    }
    /// Try to create a node with the given handle/data.
    /// Will error if the handle is already in use.
    pub fn add_node(&mut self, handle: NodeHandle, node_data: NodeData) -> ResultE<()> {
        // Create storage for the node's outgoing edges
        match self.edges.entry(handle) {
            hash_map::Entry::Occupied(_) => Err(Error::NodeExists),
            hash_map::Entry::Vacant(entry) => { entry.insert(EdgeSet::new()); Ok(()) },
        }?;
        // Store the node's data
        assert!(self.node_data.insert(handle, node_data.clone()).is_none());
        Ok(())
    }
    pub fn add_edge(&mut self, edge: Edge) -> ResultE<()> {
        // Algorithm:
        //   Assume we currently have a DAG.
        //   Given that, the only way this new edge could introduce a cycle is if it was a part of
        //     that cycle.
        //   Therefore, if no path exists from the edge to itself, then it is safe to add the edge.
        let is_reachable = self.is_edge_reachable(&edge, &edge);
        if is_reachable {
            Err(Error::WouldCycle)
        } else {
            self.add_edge_unchecked(edge);
            Ok(())
        }
    }
    fn add_edge_unchecked(&mut self, edge: Edge) {
        // associate the edge with its origin.
        self.edges.entry(edge.from_full()).or_insert_with(EdgeSet::new).outbound.insert(edge.clone());
        // associate the edge with its destination.
        self.edges.entry(edge.to_full()).or_insert_with(EdgeSet::new).inbound.insert(edge);
    }
    fn is_edge_reachable(&self, from: &Edge, target: &Edge) -> bool {
        // Algorithm:
        //   Try to reach `edge` from `edge`.
        //   If we reach the boundary of the DAG while doing so, consider all reachable outbound
        //     edges of the DAG
        //     For each such edge, try to reach this DAG (recursively), and then resume the search for `edge`.
        if let Some(_to) = from.to.node_handle.get() {
            // The edge points to a NODE inside a DAG.
            // Consider all (reachable) outgoing edges of the node:
            if let Some(node_data) = self.edges.get(&from.to_full()) {
                for candidate_edge in &node_data.outbound {
                    if self.are_edges_internally_connected(from, candidate_edge) &&
                      self.is_edge_reachable(candidate_edge, target) {
                        return true;
                    }
                }
            }
        }
        false
    }
    /// Assuming from.to() == to.from(), will return true if & only if
    /// from and to are internally connected within the node.
    fn are_edges_internally_connected(&self, from: &Edge, to: &Edge) -> bool {
        self.node_data[&from.to_full()]
            .are_slots_connected(from.weight.to_slot, to.weight.from_slot)
    }
    /// Returns true if there's a path from `in` to `out` at the toplevel DAG.
    pub fn are_slots_connected(&self, in_slot: u32, out_slot: u32) -> bool {
        // Consider all edges from None paired with all edges to None:
        let root_dag = NodeHandle::toplevel();
        let edges_from = self.edges[&root_dag].outbound.iter().filter(|&edge| {
            edge.weight.from_slot == in_slot
        });
        for edge_from in edges_from {
            let edges_to = self.edges[&root_dag].inbound.iter().filter(|&edge| {
                edge.weight.to_slot == out_slot
            });
            for edge_to in edges_to {
                if self.is_edge_reachable(edge_from, edge_to) {
                    return true;
                }
            }
        }
        false
    }
    pub fn del_node(&mut self, node: NodeHandle) -> ResultE<()> {
        let ok_to_delete = match self.edges.entry(node) {
            // Already deleted
            hash_map::Entry::Vacant(_) => Ok(()),
            hash_map::Entry::Occupied(entry) => {
                if entry.get().is_empty() {
                    entry.remove();
                    Ok(())
                } else {
                    // Node has edges
                    Err(Error::NodeInUse)
                }
            }
        };
        if ok_to_delete.is_ok() {
            // delete the data associated with this node
            self.node_data.remove(&node);
        }
        ok_to_delete
    }
    pub fn del_edge(&mut self, edge: Edge) {
        // TODO: garbage collect the edge sets.
        if let Some(edge_set) = self.edges.get_mut(&edge.from_full()) {
            edge_set.outbound.remove(&edge);
        }
        if let Some(edge_set) = self.edges.get_mut(&edge.to_full()) {
            edge_set.inbound.remove(&edge);
        }
    }

    pub fn to_adjlist(&self) -> AdjList {
        // Map Effect -> EffectId
        let nodes = self.node_data.iter().map(|(handle, data)| {
            (*handle, data.id().clone())
        }).collect();
        // Doubly-linked edges -> singly-linked
        let edges = self.edges.iter().flat_map(|(_key, edgeset)| {
            edgeset.outbound.clone().into_iter()
        }).collect();

        AdjList {
            nodes: nodes,
            edges: edges,
        }
    }
    pub fn from_adjlist(adj: AdjList, res: &ResMan) -> ResultE<Self> {
        // Unwrap struct fields to local variables
        let (nodes, edges) = (adj.nodes, adj.edges);

        // Map EffectId -> Effect
        let nodes: ResultE<HashMap<NodeHandle, NodeData>> = nodes.into_iter().map(|(handle, id)| {
            let decoded_data = Effect::from_id(id, res)?;
            Ok((handle, decoded_data))
        }).collect();
        // Type deduction isn't smart enough to unwrap nodes in above statement.
        let nodes = nodes?;

        // Build self with only nodes and no edges
        let mut me = Self {
            edges: HashMap::new(),
            node_data: nodes,
        };

        // Add the edges one at a time, enforcing zero cycles
        for edge in &edges {
            me.add_edge(edge.clone())?
        }
        Ok(me)
    }
}

impl NodeHandle {
    pub fn toplevel() -> Self {
        NodeHandle::new(None)
    }
    pub fn new<T>(node_handle: T) -> Self
        where T: Into<PrimNodeHandle>
    {
        Self{ node_handle: node_handle.into() }
    }
    pub fn node_handle(&self) -> &PrimNodeHandle {
        &self.node_handle
    }
}
impl Display for NodeHandle {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        self.node_handle.fmt(f)
    }
}

impl Edge {
    /// Create an edge from `from` to null (i.e. an output)
    pub fn new_to_null(from: NodeHandle, weight: EdgeWeight) -> Self {
        Self {
            from,
            to: NodeHandle::toplevel(),
            weight,
        }
    }
    pub fn new_from_null(to: NodeHandle, weight: EdgeWeight) -> Self {
        Self {
            from: NodeHandle::toplevel(),
            to,
            weight
        }
    }
    /// Create an edge between the two nodes.
    pub fn new(from: NodeHandle, to: NodeHandle, weight: EdgeWeight) -> Self {
        Self{ from, to, weight }
    }
    // TODO: rename to 'from' and 'to' or 'from_hnd', 'to_hnd'?
    pub fn from_full(&self) -> NodeHandle {
        self.from
    }
    pub fn to_full(&self) -> NodeHandle {
        self.to
    }
    pub fn to_slot(&self) -> u32 {
        self.weight.to_slot
    }
    pub fn from_slot(&self) -> u32 {
        self.weight.from_slot
    }
}

impl EdgeWeight {
    pub fn new(from_slot: u32, to_slot: u32) -> Self {
        Self{ from_slot, to_slot }
    }
}

impl EdgeSet {
    fn new() -> Self {
        EdgeSet {
            outbound: HashSet::new(),
            inbound: HashSet::new(),
        }
    }
    fn is_empty(&self) -> bool {
        self.outbound.is_empty() && self.inbound.is_empty()
    }
}

/// Conversion from `effect::Error` for use with the `?` operator
impl From<effect::Error> for Error {
    fn from(e: effect::Error) -> Self {
        Error::EffectError(e)
    }
}
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::fmt::{Display, self};
use std::str::FromStr;
use url::Url;
use url::ParseError as UrlError;

use Error;

/// The Request-URI of a Request's StartLine.
///
/// From Section 5.3, Request Target:
/// > Once an inbound connection is obtained, the client sends an HTTP
/// > request message (Section 3) with a request-target derived from the
/// > target URI.  There are four distinct formats for the request-target,
/// > depending on both the method being requested and whether the request
/// > is to a proxy.
/// >
/// > ```notrust
/// > request-target = origin-form
/// >                / absolute-form
/// >                / authority-form
/// >                / asterisk-form
/// > ```
///
/// # Uri explanations
///
/// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
/// |-|   |-------------------------------||--------| |-------------------| |-----|
///  |                  |                       |               |              |
/// scheme          authority                 path            query         fragment
#[derive(Clone)]
pub struct Uri {
    source: Cow<'static, str>,
    scheme_end: Option<usize>,
    authority_end: Option<usize>,
    query: Option<usize>,
    fragment: Option<usize>,
}

impl Uri {
    /// Parse a string into a `Uri`.
    pub fn new(s: &str) -> Result<Uri, Error> {
        let bytes = s.as_bytes();
        if bytes.len() == 0 {
            Err(Error::Uri(UrlError::RelativeUrlWithoutBase))
        } else if bytes == b"*" {
            Ok(Uri {
                source: "*".into(),
                scheme_end: None,
                authority_end: None,
                query: None,
                fragment: None,
            })
        } else if bytes == b"/" {
            Ok(Uri::default())
        } else if bytes.starts_with(b"/") {
            Ok(Uri {
                source: s.to_owned().into(),
                scheme_end: None,
                authority_end: None,
                query: parse_query(s),
                fragment: parse_fragment(s),
            })
        } else if s.contains("://") {
            let scheme = parse_scheme(s);
            let auth = parse_authority(s);
            if let Some(end) = scheme {
                match &s[..end] {
                    "ftp" | "gopher" | "http" | "https" | "ws" | "wss" => {},
                    "blob" | "file" => return Err(Error::Method),
                    _ => return Err(Error::Method),
                }
                if let Some(a) = auth {
                    if (end + 3) == a {
                        return Err(Error::Method);
                    }
                }
            }
            Ok(Uri {
                source: s.to_owned().into(),
                scheme_end: scheme,
                authority_end: auth,
                query: parse_query(s),
                fragment: parse_fragment(s),
            })
        } else {
            Ok(Uri {
                source: s.to_owned().into(),
                scheme_end: None,
                authority_end: Some(s.len()),
                query: None,
                fragment: None,
            })
        }
    }

    /// Get the path of this `Uri`.
    pub fn path(&self) -> &str {
        let index = self.authority_end.unwrap_or(self.scheme_end.unwrap_or(0));
        let query_len = self.query.unwrap_or(0);
        let fragment_len = self.fragment.unwrap_or(0);
        let end = self.source.len() - if query_len > 0 { query_len + 1 } else { 0 } -
            if fragment_len > 0 { fragment_len + 1 } else { 0 };
        if index >= end {
            if self.scheme().is_some() {
                return "/" // absolute-form MUST have path
            }
            ""
        } else {
            &self.source[index..end]
        }
    }

    /// Get the scheme of this `Uri`.
    pub fn scheme(&self) -> Option<&str> {
        if let Some(end) = self.scheme_end {
            Some(&self.source[..end])
        } else {
            None
        }
    }

    /// Get the authority of this `Uri`.
    pub fn authority(&self) -> Option<&str> {
        if let Some(end) = self.authority_end {
            let index = self.scheme_end.map(|i| i + 3).unwrap_or(0);

            Some(&self.source[index..end])
        } else {
            None
        }
    }

    /// Get the host of this `Uri`.
    pub fn host(&self) -> Option<&str> {
        if let Some(auth) = self.authority() {
            auth.split(":").next()
        } else {
            None
        }
    }

    /// Get the port of this `Uri.
    pub fn port(&self) -> Option<u16> {
        if let Some(auth) = self.authority() {
            let v: Vec<&str> = auth.split(":").collect();
            if v.len() == 2 {
                u16::from_str(v[1]).ok()
            } else {
                None
            }
        } else {
            None
        }
    }

    /// Get the query string of this `Uri`, starting after the `?`.
    pub fn query(&self) -> Option<&str> {
        let fragment_len = self.fragment.unwrap_or(0);
        let fragment_len = if fragment_len > 0 { fragment_len + 1 } else { 0 };
        if let Some(len) = self.query {
            Some(&self.source[self.source.len() - len - fragment_len..self.source.len() - fragment_len])
        } else {
            None
        }
    }

    #[cfg(test)]
    fn fragment(&self) -> Option<&str> {
        if let Some(len) = self.fragment {
            Some(&self.source[self.source.len() - len..])
        } else {
            None
        }
    }
}

fn parse_scheme(s: &str) -> Option<usize> {
    s.find(':')
}

fn parse_authority(s: &str) -> Option<usize> {
    let v: Vec<&str> = s.split("://").collect();
    let auth = v.last().unwrap()
        .split("/")
        .next()
        .unwrap_or(s)
        .len() + if v.len() == 2 { v[0].len() + 3 } else { 0 };

    return Some(auth);
}

fn parse_query(s: &str) -> Option<usize> {
    match s.find('?') {
        Some(i) => {
            let frag_pos = s.find('#').unwrap_or(s.len());

            return Some(frag_pos - i - 1);
        },
        None => None,
    }
}

fn parse_fragment(s: &str) -> Option<usize> {
    match s.find('#') {
        Some(i) => Some(s.len() - i - 1),
        None => None,
    }
}

impl FromStr for Uri {
    type Err = Error;

    fn from_str(s: &str) -> Result<Uri, Error> {
        Uri::new(s)
    }
}

impl From<Url> for Uri {
    fn from(url: Url) -> Uri {
        Uri::new(url.as_str()).expect("Uri::From<Url> failed")
    }
}

impl PartialEq for Uri {
    fn eq(&self, other: &Uri) -> bool {
        self.source == other.source
    }
}

impl AsRef<str> for Uri {
    fn as_ref(&self) -> &str {
        &self.source
    }
}

impl Default for Uri {
    fn default() -> Uri {
        Uri {
            source: "/".into(),
            scheme_end: None,
            authority_end: None,
            query: None,
            fragment: None,
        }
    }
}

impl fmt::Debug for Uri {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.source.as_ref(), f)
    }
}

impl Display for Uri {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(&self.source)
    }
}

macro_rules! test_parse {
    (
        $test_name:ident,
        $str:expr,
        $($method:ident = $value:expr,)*
    ) => (
        #[test]
        fn $test_name() {
            let uri = Uri::new($str).unwrap();
            $(
            assert_eq!(uri.$method(), $value);
            )+
        }
    );
}

test_parse! {
    test_uri_parse_origin_form,
    "/some/path/here?and=then&hello#and-bye",

    scheme = None,
    authority = None,
    path = "/some/path/here",
    query = Some("and=then&hello"),
    fragment = Some("and-bye"),
}

test_parse! {
    test_uri_parse_absolute_form,
    "http://127.0.0.1:61761/chunks",

    scheme = Some("http"),
    authority = Some("127.0.0.1:61761"),
    path = "/chunks",
    query = None,
    fragment = None,
}

test_parse! {
    test_uri_parse_absolute_form_without_path,
    "https://127.0.0.1:61761",

    scheme = Some("https"),
    authority = Some("127.0.0.1:61761"),
    path = "/",
    query = None,
    fragment = None,
}

test_parse! {
    test_uri_parse_asterisk_form,
    "*",

    scheme = None,
    authority = None,
    path = "*",
    query = None,
    fragment = None,
}

test_parse! {
    test_uri_parse_authority_form,
    "localhost:3000",

    scheme = None,
    authority = Some("localhost:3000"),
    path = "",
    query = None,
    fragment = None,
}

test_parse! {
    test_uri_parse_absolute_with_default_port_http,
    "http://127.0.0.1:80",

    scheme = Some("http"),
    authority = Some("127.0.0.1:80"),
    path = "/",
    query = None,
    fragment = None,
}

test_parse! {
    test_uri_parse_absolute_with_default_port_https,
    "https://127.0.0.1:443",

    scheme = Some("https"),
    authority = Some("127.0.0.1:443"),
    path = "/",
    query = None,
    fragment = None,
}

#[test]
fn test_uri_parse_error() {
    fn err(s: &str) {
        Uri::new(s).unwrap_err();
    }

    err("http://");
    //TODO: these should error
    //err("htt:p//host");
    //err("hyper.rs/");
    //err("hyper.rs?key=val");
}

#[test]
fn test_uri_from_url() {
    let uri = Uri::from(Url::parse("http://test.com/nazghul?test=3").unwrap());
    assert_eq!(uri.path(), "/nazghul");
    assert_eq!(uri.authority(), Some("test.com"));
    assert_eq!(uri.scheme(), Some("http"));
    assert_eq!(uri.query(), Some("test=3"));
    assert_eq!(uri.as_ref(), "http://test.com/nazghul?test=3");
}
<commit_msg>refactor(uri): Improve parse_authority safety<commit_after>use std::borrow::Cow;
use std::fmt::{Display, self};
use std::str::FromStr;
use url::Url;
use url::ParseError as UrlError;

use Error;

/// The Request-URI of a Request's StartLine.
///
/// From Section 5.3, Request Target:
/// > Once an inbound connection is obtained, the client sends an HTTP
/// > request message (Section 3) with a request-target derived from the
/// > target URI.  There are four distinct formats for the request-target,
/// > depending on both the method being requested and whether the request
/// > is to a proxy.
/// >
/// > ```notrust
/// > request-target = origin-form
/// >                / absolute-form
/// >                / authority-form
/// >                / asterisk-form
/// > ```
///
/// # Uri explanations
///
/// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
/// |-|   |-------------------------------||--------| |-------------------| |-----|
///  |                  |                       |               |              |
/// scheme          authority                 path            query         fragment
#[derive(Clone)]
pub struct Uri {
    source: Cow<'static, str>,
    scheme_end: Option<usize>,
    authority_end: Option<usize>,
    query: Option<usize>,
    fragment: Option<usize>,
}

impl Uri {
    /// Parse a string into a `Uri`.
    pub fn new(s: &str) -> Result<Uri, Error> {
        let bytes = s.as_bytes();
        if bytes.len() == 0 {
            Err(Error::Uri(UrlError::RelativeUrlWithoutBase))
        } else if bytes == b"*" {
            Ok(Uri {
                source: "*".into(),
                scheme_end: None,
                authority_end: None,
                query: None,
                fragment: None,
            })
        } else if bytes == b"/" {
            Ok(Uri::default())
        } else if bytes.starts_with(b"/") {
            Ok(Uri {
                source: s.to_owned().into(),
                scheme_end: None,
                authority_end: None,
                query: parse_query(s),
                fragment: parse_fragment(s),
            })
        } else if s.contains("://") {
            let scheme = parse_scheme(s);
            let auth = parse_authority(s);
            if let Some(end) = scheme {
                match &s[..end] {
                    "ftp" | "gopher" | "http" | "https" | "ws" | "wss" => {},
                    "blob" | "file" => return Err(Error::Method),
                    _ => return Err(Error::Method),
                }
                match auth {
                    Some(a) => {
                        if (end + 3) == a {
                            return Err(Error::Method);
                        }
                    },
                    None => return Err(Error::Method),
                }
            }
            Ok(Uri {
                source: s.to_owned().into(),
                scheme_end: scheme,
                authority_end: auth,
                query: parse_query(s),
                fragment: parse_fragment(s),
            })
        } else {
            Ok(Uri {
                source: s.to_owned().into(),
                scheme_end: None,
                authority_end: Some(s.len()),
                query: None,
                fragment: None,
            })
        }
    }

    /// Get the path of this `Uri`.
    pub fn path(&self) -> &str {
        let index = self.authority_end.unwrap_or(self.scheme_end.unwrap_or(0));
        let query_len = self.query.unwrap_or(0);
        let fragment_len = self.fragment.unwrap_or(0);
        let end = self.source.len() - if query_len > 0 { query_len + 1 } else { 0 } -
            if fragment_len > 0 { fragment_len + 1 } else { 0 };
        if index >= end {
            if self.scheme().is_some() {
                return "/" // absolute-form MUST have path
            }
            ""
        } else {
            &self.source[index..end]
        }
    }

    /// Get the scheme of this `Uri`.
    pub fn scheme(&self) -> Option<&str> {
        if let Some(end) = self.scheme_end {
            Some(&self.source[..end])
        } else {
            None
        }
    }

    /// Get the authority of this `Uri`.
    pub fn authority(&self) -> Option<&str> {
        if let Some(end) = self.authority_end {
            let index = self.scheme_end.map(|i| i + 3).unwrap_or(0);

            Some(&self.source[index..end])
        } else {
            None
        }
    }

    /// Get the host of this `Uri`.
    pub fn host(&self) -> Option<&str> {
        if let Some(auth) = self.authority() {
            auth.split(":").next()
        } else {
            None
        }
    }

    /// Get the port of this `Uri.
    pub fn port(&self) -> Option<u16> {
        if let Some(auth) = self.authority() {
            let v: Vec<&str> = auth.split(":").collect();
            if v.len() == 2 {
                u16::from_str(v[1]).ok()
            } else {
                None
            }
        } else {
            None
        }
    }

    /// Get the query string of this `Uri`, starting after the `?`.
    pub fn query(&self) -> Option<&str> {
        let fragment_len = self.fragment.unwrap_or(0);
        let fragment_len = if fragment_len > 0 { fragment_len + 1 } else { 0 };
        if let Some(len) = self.query {
            Some(&self.source[self.source.len() - len - fragment_len..self.source.len() - fragment_len])
        } else {
            None
        }
    }

    #[cfg(test)]
    fn fragment(&self) -> Option<&str> {
        if let Some(len) = self.fragment {
            Some(&self.source[self.source.len() - len..])
        } else {
            None
        }
    }
}

fn parse_scheme(s: &str) -> Option<usize> {
    s.find(':')
}

fn parse_authority(s: &str) -> Option<usize> {
    let v: Vec<&str> = s.split("://").collect();
    match v.last() {
        Some(auth) => Some(auth.split("/")
                           .next()
                           .unwrap_or(s)
                           .len() + if v.len() == 2 { v[0].len() + 3 } else { 0 }),
        None => None,
    }
}

fn parse_query(s: &str) -> Option<usize> {
    match s.find('?') {
        Some(i) => {
            let frag_pos = s.find('#').unwrap_or(s.len());

            return Some(frag_pos - i - 1);
        },
        None => None,
    }
}

fn parse_fragment(s: &str) -> Option<usize> {
    match s.find('#') {
        Some(i) => Some(s.len() - i - 1),
        None => None,
    }
}

impl FromStr for Uri {
    type Err = Error;

    fn from_str(s: &str) -> Result<Uri, Error> {
        Uri::new(s)
    }
}

impl From<Url> for Uri {
    fn from(url: Url) -> Uri {
        Uri::new(url.as_str()).expect("Uri::From<Url> failed")
    }
}

impl PartialEq for Uri {
    fn eq(&self, other: &Uri) -> bool {
        self.source == other.source
    }
}

impl AsRef<str> for Uri {
    fn as_ref(&self) -> &str {
        &self.source
    }
}

impl Default for Uri {
    fn default() -> Uri {
        Uri {
            source: "/".into(),
            scheme_end: None,
            authority_end: None,
            query: None,
            fragment: None,
        }
    }
}

impl fmt::Debug for Uri {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.source.as_ref(), f)
    }
}

impl Display for Uri {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(&self.source)
    }
}

macro_rules! test_parse {
    (
        $test_name:ident,
        $str:expr,
        $($method:ident = $value:expr,)*
    ) => (
        #[test]
        fn $test_name() {
            let uri = Uri::new($str).unwrap();
            $(
            assert_eq!(uri.$method(), $value);
            )+
        }
    );
}

test_parse! {
    test_uri_parse_origin_form,
    "/some/path/here?and=then&hello#and-bye",

    scheme = None,
    authority = None,
    path = "/some/path/here",
    query = Some("and=then&hello"),
    fragment = Some("and-bye"),
}

test_parse! {
    test_uri_parse_absolute_form,
    "http://127.0.0.1:61761/chunks",

    scheme = Some("http"),
    authority = Some("127.0.0.1:61761"),
    path = "/chunks",
    query = None,
    fragment = None,
}

test_parse! {
    test_uri_parse_absolute_form_without_path,
    "https://127.0.0.1:61761",

    scheme = Some("https"),
    authority = Some("127.0.0.1:61761"),
    path = "/",
    query = None,
    fragment = None,
}

test_parse! {
    test_uri_parse_asterisk_form,
    "*",

    scheme = None,
    authority = None,
    path = "*",
    query = None,
    fragment = None,
}

test_parse! {
    test_uri_parse_authority_form,
    "localhost:3000",

    scheme = None,
    authority = Some("localhost:3000"),
    path = "",
    query = None,
    fragment = None,
}

test_parse! {
    test_uri_parse_absolute_with_default_port_http,
    "http://127.0.0.1:80",

    scheme = Some("http"),
    authority = Some("127.0.0.1:80"),
    path = "/",
    query = None,
    fragment = None,
}

test_parse! {
    test_uri_parse_absolute_with_default_port_https,
    "https://127.0.0.1:443",

    scheme = Some("https"),
    authority = Some("127.0.0.1:443"),
    path = "/",
    query = None,
    fragment = None,
}

#[test]
fn test_uri_parse_error() {
    fn err(s: &str) {
        Uri::new(s).unwrap_err();
    }

    err("http://");
    //TODO: these should error
    //err("htt:p//host");
    //err("hyper.rs/");
    //err("hyper.rs?key=val");
}

#[test]
fn test_uri_from_url() {
    let uri = Uri::from(Url::parse("http://test.com/nazghul?test=3").unwrap());
    assert_eq!(uri.path(), "/nazghul");
    assert_eq!(uri.authority(), Some("test.com"));
    assert_eq!(uri.scheme(), Some("http"));
    assert_eq!(uri.query(), Some("test=3"));
    assert_eq!(uri.as_ref(), "http://test.com/nazghul?test=3");
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::hash::Hash;
use std::sync::Arc;

use hyper::client::Client;
use hyper::client::Response;
use hyper::client::IntoUrl;
use hyper::header::ContentType;
use hyper::header::Headers;
use hyper::mime;

use url::form_urlencoded;
use url::form_urlencoded::Target;

use super::errors::*;
use super::sig;
use super::util;

pub struct Open189Client<'a> {
    http: Arc<Client>,
    app_id: &'a str,
    secret: &'a str,
    access_token: Option<&'a str>,
}

fn prepare_request_params(params: &mut HashMap<&'static str, String>,
                          app_id: &str,
                          secret: &str,
                          access_token: &str) {
    params.insert("app_id", app_id.to_string());
    params.insert("access_token", access_token.to_string());
    params.insert("timestamp", util::get_api_timestamp());
    let sign = sig::sign(params, secret);
    params.insert("sign", sign);
}

impl<'a> Open189Client<'a> {
    pub fn new(http_client: Client,
               app_id: &'a str,
               secret: &'a str,
               access_token: Option<&'a str>)
               -> Open189Client<'a> {
        Open189Client {
            http: Arc::new(http_client),
            app_id: app_id,
            secret: secret,
            access_token: access_token,
        }
    }

    fn require_access_token(&self) -> Result<()> {
        if self.access_token.is_none() {
            Err(ErrorKind::AccessTokenRequired.into())
        } else {
            Ok(())
        }
    }

    pub fn get_sync<U: IntoUrl>(&self,
                                url: U,
                                mut params: HashMap<&'static str, String>)
                                -> Result<Response> {
        self.require_access_token()?;

        let mut url = url.into_url()?;
        prepare_request_params(&mut params,
                               self.app_id,
                               self.secret,
                               self.access_token.unwrap());
        {
            let mut qs = url.query_pairs_mut();
            qs.clear();
            for (k, v) in params.iter() {
                qs.append_pair(k.as_ref(), v.as_ref());
            }
        }

        let response = self.http.get(url).send()?;

        Ok(response)
    }

    pub fn post_sync<U: IntoUrl>(&self,
                                 url: U,
                                 mut params: HashMap<&'static str, String>)
                                 -> Result<Response> {
        self.require_access_token()?;
        prepare_request_params(&mut params,
                               self.app_id,
                               self.secret,
                               self.access_token.unwrap());
        self.post_sync_prepared(url, params)
    }

    fn post_sync_prepared<U: IntoUrl>(&self,
                                      url: U,
                                      params: HashMap<&'static str, String>)
                                      -> Result<Response> {
        let url = url.into_url()?;
        let body = {
            let mut serializer = form_urlencoded::Serializer::new(String::new());
            for (k, v) in params.iter() {
                serializer.append_pair(k, v);
            }
            serializer.finish()
        };

        let headers = {
            let mut tmp = Headers::new();
            tmp.set(ContentType(mime::Mime(mime::TopLevel::Application,
                                           mime::SubLevel::WwwFormUrlEncoded,
                                           vec![(mime::Attr::Charset, mime::Value::Utf8)])));
            tmp
        };

        let response = self.http.post(url).headers(headers).body(&body).send()?;
        Ok(response)
    }
}
<commit_msg>init(net): port access token requests from pyopen189<commit_after>use std::collections::HashMap;
use std::hash::Hash;
use std::sync::Arc;

use hyper::client::Client;
use hyper::client::Response;
use hyper::client::IntoUrl;
use hyper::header::ContentType;
use hyper::header::Headers;
use hyper::mime;

use url::form_urlencoded;
use url::form_urlencoded::Target;

use super::errors::*;
use super::sig;
use super::util;

const URL_ACCESS_TOKEN_REQ: &'static str = "https://oauth.api.189.cn/emp/oauth2/v3/access_token";

pub struct Open189Client<'a> {
    http: Arc<Client>,
    app_id: &'a str,
    secret: &'a str,
    access_token: Option<&'a str>,
}

fn prepare_request_params(params: &mut HashMap<&'static str, String>,
                          app_id: &str,
                          secret: &str,
                          access_token: &str) {
    params.insert("app_id", app_id.to_string());
    params.insert("access_token", access_token.to_string());
    params.insert("timestamp", util::get_api_timestamp());
    let sign = sig::sign(params, secret);
    params.insert("sign", sign);
}

impl<'a> Open189Client<'a> {
    pub fn new(http_client: Client,
               app_id: &'a str,
               secret: &'a str,
               access_token: Option<&'a str>)
               -> Open189Client<'a> {
        Open189Client {
            http: Arc::new(http_client),
            app_id: app_id,
            secret: secret,
            access_token: access_token,
        }
    }

    fn require_access_token(&self) -> Result<()> {
        if self.access_token.is_none() {
            Err(ErrorKind::AccessTokenRequired.into())
        } else {
            Ok(())
        }
    }

    pub fn get_sync<U: IntoUrl>(&self,
                                url: U,
                                mut params: HashMap<&'static str, String>)
                                -> Result<Response> {
        self.require_access_token()?;

        let mut url = url.into_url()?;
        prepare_request_params(&mut params,
                               self.app_id,
                               self.secret,
                               self.access_token.unwrap());
        {
            let mut qs = url.query_pairs_mut();
            qs.clear();
            for (k, v) in params.iter() {
                qs.append_pair(k.as_ref(), v.as_ref());
            }
        }

        let response = self.http.get(url).send()?;

        Ok(response)
    }

    pub fn post_sync<U: IntoUrl>(&self,
                                 url: U,
                                 mut params: HashMap<&'static str, String>)
                                 -> Result<Response> {
        self.require_access_token()?;
        prepare_request_params(&mut params,
                               self.app_id,
                               self.secret,
                               self.access_token.unwrap());
        self.post_sync_prepared(url, params)
    }

    pub fn perform_access_token_req(&self,
                                    mut params: HashMap<&'static str, String>)
                                    -> Result<Response> {
        params.insert("app_id", self.app_id.to_string());
        params.insert("app_secret", self.secret.to_string());
        params.insert("state", util::get_random_state_str());
        self.post_sync_prepared(URL_ACCESS_TOKEN_REQ, params)
    }

    fn post_sync_prepared<U: IntoUrl>(&self,
                                      url: U,
                                      params: HashMap<&'static str, String>)
                                      -> Result<Response> {
        let url = url.into_url()?;
        let body = {
            let mut serializer = form_urlencoded::Serializer::new(String::new());
            for (k, v) in params.iter() {
                serializer.append_pair(k, v);
            }
            serializer.finish()
        };

        let headers = {
            let mut tmp = Headers::new();
            tmp.set(ContentType(mime::Mime(mime::TopLevel::Application,
                                           mime::SubLevel::WwwFormUrlEncoded,
                                           vec![(mime::Attr::Charset, mime::Value::Utf8)])));
            tmp
        };

        let response = self.http.post(url).headers(headers).body(&body).send()?;
        Ok(response)
    }
}
<|endoftext|>


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

use std::iter::range_step;
use std::num::Int;

use cryptoutil::{write_u32_le, read_u32v_le, FixedBuffer, FixedBuffer64, StandardPadding};
use digest::Digest;

// A structure that represents that state of a digest computation for the MD5 digest function
struct Md5State {
    s0: u32,
    s1: u32,
    s2: u32,
    s3: u32
}

impl Md5State {
    fn new() -> Md5State {
        Md5State {
            s0: 0x67452301,
            s1: 0xefcdab89,
            s2: 0x98badcfe,
            s3: 0x10325476
        }
    }

    fn reset(&mut self) {
        self.s0 = 0x67452301;
        self.s1 = 0xefcdab89;
        self.s2 = 0x98badcfe;
        self.s3 = 0x10325476;
    }

    fn process_block(&mut self, input: &[u8]) {
        fn f(u: u32, v: u32, w: u32) -> u32 {
            (u & v) | (!u & w)
        }

        fn g(u: u32, v: u32, w: u32) -> u32 {
            (u & w) | (v & !w)
        }

        fn h(u: u32, v: u32, w: u32) -> u32 {
            u ^ v ^ w
        }

        fn i(u: u32, v: u32, w: u32) -> u32 {
            v ^ (u | !w)
        }

        fn op_f(w: u32, x: u32, y: u32, z: u32, m: u32, s: u32) -> u32 {
            (w + f(x, y, z) + m).rotate_left(s as uint) + x
        }

        fn op_g(w: u32, x: u32, y: u32, z: u32, m: u32, s: u32) -> u32 {
            (w + g(x, y, z) + m).rotate_left(s as uint) + x
        }

        fn op_h(w: u32, x: u32, y: u32, z: u32, m: u32, s: u32) -> u32 {
            (w + h(x, y, z) + m).rotate_left(s as uint) + x
        }

        fn op_i(w: u32, x: u32, y: u32, z: u32, m: u32, s: u32) -> u32 {
            (w + i(x, y, z) + m).rotate_left(s as uint) + x
        }

        let mut a = self.s0;
        let mut b = self.s1;
        let mut c = self.s2;
        let mut d = self.s3;

        let mut data = [0u32; 16];

        read_u32v_le(&mut data, input);

        // round 1
        for i in range_step(0u, 16, 4) {
            a = op_f(a, b, c, d, data[i] + C1[i], 7);
            d = op_f(d, a, b, c, data[i + 1] + C1[i + 1], 12);
            c = op_f(c, d, a, b, data[i + 2] + C1[i + 2], 17);
            b = op_f(b, c, d, a, data[i + 3] + C1[i + 3], 22);
        }

        // round 2
        let mut t = 1;
        for i in range_step(0u, 16, 4) {
            a = op_g(a, b, c, d, data[t & 0x0f] + C2[i], 5);
            d = op_g(d, a, b, c, data[(t + 5) & 0x0f] + C2[i + 1], 9);
            c = op_g(c, d, a, b, data[(t + 10) & 0x0f] + C2[i + 2], 14);
            b = op_g(b, c, d, a, data[(t + 15) & 0x0f] + C2[i + 3], 20);
            t += 20;
        }

        // round 3
        t = 5;
        for i in range_step(0u, 16, 4) {
            a = op_h(a, b, c, d, data[t & 0x0f] + C3[i], 4);
            d = op_h(d, a, b, c, data[(t + 3) & 0x0f] + C3[i + 1], 11);
            c = op_h(c, d, a, b, data[(t + 6) & 0x0f] + C3[i + 2], 16);
            b = op_h(b, c, d, a, data[(t + 9) & 0x0f] + C3[i + 3], 23);
            t += 12;
        }

        // round 4
        t = 0;
        for i in range_step(0u, 16, 4) {
            a = op_i(a, b, c, d, data[t & 0x0f] + C4[i], 6);
            d = op_i(d, a, b, c, data[(t + 7) & 0x0f] + C4[i + 1], 10);
            c = op_i(c, d, a, b, data[(t + 14) & 0x0f] + C4[i + 2], 15);
            b = op_i(b, c, d, a, data[(t + 21) & 0x0f] + C4[i + 3], 21);
            t += 28;
        }

        self.s0 += a;
        self.s1 += b;
        self.s2 += c;
        self.s3 += d;
    }
}

// Round 1 constants
static C1: [u32; 16] = [
    0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
    0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821
];

// Round 2 constants
static C2: [u32; 16] = [
    0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
    0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a
];

// Round 3 constants
static C3: [u32; 16] = [
    0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
    0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665
];

// Round 4 constants
static C4: [u32; 16] = [
    0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
    0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
];

/// The MD5 Digest algorithm
pub struct Md5 {
    length_bytes: u64,
    buffer: FixedBuffer64,
    state: Md5State,
    finished: bool,
}

impl Md5 {
    /// Construct a new instance of the MD5 Digest.
    pub fn new() -> Md5 {
        Md5 {
            length_bytes: 0,
            buffer: FixedBuffer64::new(),
            state: Md5State::new(),
            finished: false
        }
    }
}

impl Digest for Md5 {
    fn input(&mut self, input: &[u8]) {
        assert!(!self.finished);
        // Unlike Sha1 and Sha2, the length value in MD5 is defined as the length of the message mod
        // 2^64 - ie: integer overflow is OK.
        self.length_bytes += input.len() as u64;
        let self_state = &mut self.state;
        self.buffer.input(input, |d: &[u8]| { self_state.process_block(d);}
        );
    }

    fn reset(&mut self) {
        self.length_bytes = 0;
        self.buffer.reset();
        self.state.reset();
        self.finished = false;
    }

    fn result(&mut self, out: &mut [u8]) {
        if !self.finished {
            let self_state = &mut self.state;
            self.buffer.standard_padding(8, |d: &[u8]| { self_state.process_block(d); });
            write_u32_le(self.buffer.next(4), (self.length_bytes << 3) as u32);
            write_u32_le(self.buffer.next(4), (self.length_bytes >> 29) as u32);
            self_state.process_block(self.buffer.full_buffer());
            self.finished = true;
        }

        write_u32_le(&mut out[0..4], self.state.s0);
        write_u32_le(&mut out[4..8], self.state.s1);
        write_u32_le(&mut out[8..12], self.state.s2);
        write_u32_le(&mut out[12..16], self.state.s3);
    }

    fn output_bits(&self) -> uint { 128 }

    fn block_size(&self) -> uint { 64 }
}

#[cfg(test)]
mod tests {
    use cryptoutil::test::test_digest_1million_random;
    use digest::Digest;
    use md5::Md5;

    struct Test {
        input: &'static str,
        output_str: &'static str,
    }

    fn test_hash<D: Digest>(sh: &mut D, tests: &[Test]) {
        // Test that it works when accepting the message all at once
        for t in tests.iter() {
            sh.input_str(t.input);

            let out_str = sh.result_str();
            assert_eq!(out_str, t.output_str);

            sh.reset();
        }

        // Test that it works when accepting the message in pieces
        for t in tests.iter() {
            let len = t.input.len();
            let mut left = len;
            while left > 0u {
                let take = (left + 1u) / 2u;
                sh.input_str(&t.input[len - left..take + len - left]);
                left = left - take;
            }

            let out_str = sh.result_str();
            assert_eq!(out_str, t.output_str);

            sh.reset();
        }
    }

    #[test]
    fn test_md5() {
        // Examples from wikipedia
        let wikipedia_tests = vec![
            Test {
                input: "",
                output_str: "d41d8cd98f00b204e9800998ecf8427e"
            },
            Test {
                input: "The quick brown fox jumps over the lazy dog",
                output_str: "9e107d9d372bb6826bd81d3542a419d6"
            },
            Test {
                input: "The quick brown fox jumps over the lazy dog.",
                output_str: "e4d909c290d0fb1ca068ffaddf22cbd0"
            },
        ];

        let tests = wikipedia_tests;

        let mut sh = Md5::new();

        test_hash(&mut sh, &tests[]);
    }

    #[test]
    fn test_1million_random_md5() {
        let mut sh = Md5::new();
        test_digest_1million_random(
            &mut sh,
            64,
            "7707d6ae4e027c70eea2a935c2296f21");
    }
}

#[cfg(test)]
mod bench {
    use test::Bencher;

    use digest::Digest;
    use md5::Md5;

    #[bench]
    pub fn md5_10(bh: & mut Bencher) {
        let mut sh = Md5::new();
        let bytes = [1u8; 10];
        bh.iter( || {
            sh.input(&bytes);
        });
        bh.bytes = bytes.len() as u64;
    }

    #[bench]
    pub fn md5_1k(bh: & mut Bencher) {
        let mut sh = Md5::new();
        let bytes = [1u8; 1024];
        bh.iter( || {
            sh.input(&bytes);
        });
        bh.bytes = bytes.len() as u64;
    }

    #[bench]
    pub fn md5_64k(bh: & mut Bencher) {
        let mut sh = Md5::new();
        let bytes = [1u8; 65536];
        bh.iter( || {
            sh.input(&bytes);
        });
        bh.bytes = bytes.len() as u64;
    }
}
<commit_msg>Pick more appropriate int types for md5<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::iter::range_step;
use std::num::Int;

use cryptoutil::{write_u32_le, read_u32v_le, FixedBuffer, FixedBuffer64, StandardPadding};
use digest::Digest;

// A structure that represents that state of a digest computation for the MD5 digest function
struct Md5State {
    s0: u32,
    s1: u32,
    s2: u32,
    s3: u32
}

impl Md5State {
    fn new() -> Md5State {
        Md5State {
            s0: 0x67452301,
            s1: 0xefcdab89,
            s2: 0x98badcfe,
            s3: 0x10325476
        }
    }

    fn reset(&mut self) {
        self.s0 = 0x67452301;
        self.s1 = 0xefcdab89;
        self.s2 = 0x98badcfe;
        self.s3 = 0x10325476;
    }

    fn process_block(&mut self, input: &[u8]) {
        fn f(u: u32, v: u32, w: u32) -> u32 {
            (u & v) | (!u & w)
        }

        fn g(u: u32, v: u32, w: u32) -> u32 {
            (u & w) | (v & !w)
        }

        fn h(u: u32, v: u32, w: u32) -> u32 {
            u ^ v ^ w
        }

        fn i(u: u32, v: u32, w: u32) -> u32 {
            v ^ (u | !w)
        }

        fn op_f(w: u32, x: u32, y: u32, z: u32, m: u32, s: u32) -> u32 {
            (w + f(x, y, z) + m).rotate_left(s as usize) + x
        }

        fn op_g(w: u32, x: u32, y: u32, z: u32, m: u32, s: u32) -> u32 {
            (w + g(x, y, z) + m).rotate_left(s as usize) + x
        }

        fn op_h(w: u32, x: u32, y: u32, z: u32, m: u32, s: u32) -> u32 {
            (w + h(x, y, z) + m).rotate_left(s as usize) + x
        }

        fn op_i(w: u32, x: u32, y: u32, z: u32, m: u32, s: u32) -> u32 {
            (w + i(x, y, z) + m).rotate_left(s as usize) + x
        }

        let mut a = self.s0;
        let mut b = self.s1;
        let mut c = self.s2;
        let mut d = self.s3;

        let mut data = [0u32; 16];

        read_u32v_le(&mut data, input);

        // round 1
        for i in range_step(0, 16, 4) {
            a = op_f(a, b, c, d, data[i] + C1[i], 7);
            d = op_f(d, a, b, c, data[i + 1] + C1[i + 1], 12);
            c = op_f(c, d, a, b, data[i + 2] + C1[i + 2], 17);
            b = op_f(b, c, d, a, data[i + 3] + C1[i + 3], 22);
        }

        // round 2
        let mut t = 1;
        for i in range_step(0, 16, 4) {
            a = op_g(a, b, c, d, data[t & 0x0f] + C2[i], 5);
            d = op_g(d, a, b, c, data[(t + 5) & 0x0f] + C2[i + 1], 9);
            c = op_g(c, d, a, b, data[(t + 10) & 0x0f] + C2[i + 2], 14);
            b = op_g(b, c, d, a, data[(t + 15) & 0x0f] + C2[i + 3], 20);
            t += 20;
        }

        // round 3
        t = 5;
        for i in range_step(0, 16, 4) {
            a = op_h(a, b, c, d, data[t & 0x0f] + C3[i], 4);
            d = op_h(d, a, b, c, data[(t + 3) & 0x0f] + C3[i + 1], 11);
            c = op_h(c, d, a, b, data[(t + 6) & 0x0f] + C3[i + 2], 16);
            b = op_h(b, c, d, a, data[(t + 9) & 0x0f] + C3[i + 3], 23);
            t += 12;
        }

        // round 4
        t = 0;
        for i in range_step(0, 16, 4) {
            a = op_i(a, b, c, d, data[t & 0x0f] + C4[i], 6);
            d = op_i(d, a, b, c, data[(t + 7) & 0x0f] + C4[i + 1], 10);
            c = op_i(c, d, a, b, data[(t + 14) & 0x0f] + C4[i + 2], 15);
            b = op_i(b, c, d, a, data[(t + 21) & 0x0f] + C4[i + 3], 21);
            t += 28;
        }

        self.s0 += a;
        self.s1 += b;
        self.s2 += c;
        self.s3 += d;
    }
}

// Round 1 constants
static C1: [u32; 16] = [
    0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
    0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821
];

// Round 2 constants
static C2: [u32; 16] = [
    0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
    0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a
];

// Round 3 constants
static C3: [u32; 16] = [
    0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
    0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665
];

// Round 4 constants
static C4: [u32; 16] = [
    0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
    0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
];

/// The MD5 Digest algorithm
pub struct Md5 {
    length_bytes: u64,
    buffer: FixedBuffer64,
    state: Md5State,
    finished: bool,
}

impl Md5 {
    /// Construct a new instance of the MD5 Digest.
    pub fn new() -> Md5 {
        Md5 {
            length_bytes: 0,
            buffer: FixedBuffer64::new(),
            state: Md5State::new(),
            finished: false
        }
    }
}

impl Digest for Md5 {
    fn input(&mut self, input: &[u8]) {
        assert!(!self.finished);
        // Unlike Sha1 and Sha2, the length value in MD5 is defined as the length of the message mod
        // 2^64 - ie: integer overflow is OK.
        self.length_bytes += input.len() as u64;
        let self_state = &mut self.state;
        self.buffer.input(input, |d: &[u8]| { self_state.process_block(d);}
        );
    }

    fn reset(&mut self) {
        self.length_bytes = 0;
        self.buffer.reset();
        self.state.reset();
        self.finished = false;
    }

    fn result(&mut self, out: &mut [u8]) {
        if !self.finished {
            let self_state = &mut self.state;
            self.buffer.standard_padding(8, |d: &[u8]| { self_state.process_block(d); });
            write_u32_le(self.buffer.next(4), (self.length_bytes << 3) as u32);
            write_u32_le(self.buffer.next(4), (self.length_bytes >> 29) as u32);
            self_state.process_block(self.buffer.full_buffer());
            self.finished = true;
        }

        write_u32_le(&mut out[0..4], self.state.s0);
        write_u32_le(&mut out[4..8], self.state.s1);
        write_u32_le(&mut out[8..12], self.state.s2);
        write_u32_le(&mut out[12..16], self.state.s3);
    }

    fn output_bits(&self) -> usize { 128 }

    fn block_size(&self) -> usize { 64 }
}

#[cfg(test)]
mod tests {
    use cryptoutil::test::test_digest_1million_random;
    use digest::Digest;
    use md5::Md5;

    struct Test {
        input: &'static str,
        output_str: &'static str,
    }

    fn test_hash<D: Digest>(sh: &mut D, tests: &[Test]) {
        // Test that it works when accepting the message all at once
        for t in tests.iter() {
            sh.input_str(t.input);

            let out_str = sh.result_str();
            assert_eq!(out_str, t.output_str);

            sh.reset();
        }

        // Test that it works when accepting the message in pieces
        for t in tests.iter() {
            let len = t.input.len();
            let mut left = len;
            while left > 0 {
                let take = (left + 1) / 2;
                sh.input_str(&t.input[len - left..take + len - left]);
                left = left - take;
            }

            let out_str = sh.result_str();
            assert_eq!(out_str, t.output_str);

            sh.reset();
        }
    }

    #[test]
    fn test_md5() {
        // Examples from wikipedia
        let wikipedia_tests = vec![
            Test {
                input: "",
                output_str: "d41d8cd98f00b204e9800998ecf8427e"
            },
            Test {
                input: "The quick brown fox jumps over the lazy dog",
                output_str: "9e107d9d372bb6826bd81d3542a419d6"
            },
            Test {
                input: "The quick brown fox jumps over the lazy dog.",
                output_str: "e4d909c290d0fb1ca068ffaddf22cbd0"
            },
        ];

        let tests = wikipedia_tests;

        let mut sh = Md5::new();

        test_hash(&mut sh, &tests[]);
    }

    #[test]
    fn test_1million_random_md5() {
        let mut sh = Md5::new();
        test_digest_1million_random(
            &mut sh,
            64,
            "7707d6ae4e027c70eea2a935c2296f21");
    }
}

#[cfg(test)]
mod bench {
    use test::Bencher;

    use digest::Digest;
    use md5::Md5;

    #[bench]
    pub fn md5_10(bh: & mut Bencher) {
        let mut sh = Md5::new();
        let bytes = [1u8; 10];
        bh.iter( || {
            sh.input(&bytes);
        });
        bh.bytes = bytes.len() as u64;
    }

    #[bench]
    pub fn md5_1k(bh: & mut Bencher) {
        let mut sh = Md5::new();
        let bytes = [1u8; 1024];
        bh.iter( || {
            sh.input(&bytes);
        });
        bh.bytes = bytes.len() as u64;
    }

    #[bench]
    pub fn md5_64k(bh: & mut Bencher) {
        let mut sh = Md5::new();
        let bytes = [1u8; 65536];
        bh.iter( || {
            sh.input(&bytes);
        });
        bh.bytes = bytes.len() as u64;
    }
}
<|endoftext|>


<commit_before>use std::fmt::Display;

pub trait Concatable {
  fn concat2(&self) -> String;
  fn join2(&self, delim: &str) -> String;
}

impl<V: Display> Concatable for [V] {
  fn concat2(&self) -> String {
    let mut buf = String::new();
    for x in self.iter() {
      buf.push_str(&format!("{}", x));
    }
    buf
  }

  fn join2(&self, delim: &str) -> String {
    let mut buf = String::new();
    let mut first = true;

    for s in self.iter() {
      if first {
        first = false;
      } else {
        buf.push_str(delim);
      }

      buf.push_str(&format!("{}", s));
    }

    buf
  }
}

pub trait ConcatableWithMap<V, F: Fn(&V) -> String> {
  fn concat_with_map(&self, f: F) -> String;
  fn join_with_map(&self, delim: &str, f: F) -> String;
}

impl<V, F: Fn(&V) -> String> ConcatableWithMap<V, F> for [V] {

  fn concat_with_map(&self, f: F) -> String {
     let mut buf = String::new();
     for v in self.iter() {
       buf.push_str(&f(v));
     }
     buf
  }

  fn join_with_map(&self, delim: &str, f: F) -> String {
    let mut buf = String::new();
    let mut first = true;

    for v in self.iter() {
      if first {
        first = false;
      } else {
        buf.push_str(delim);
      }

      buf.push_str(&f(v));
    }

    buf
  }
}

pub fn join<S, T>(strs: T, delimiter: &str) -> String
    where S: Display,
          T: IntoIterator<Item=S> {

  let mut buf = String::new();
  let mut first = true;

  for s in strs.into_iter() {

    if first {
      first = false;
    } else {
      buf.push_str(delimiter);
    }

    buf.push_str(&format!("{}", s));
  }

  buf
}

pub fn join_with_map<'a, S, T, F>(strs: T, delimiter: &str, f: F) -> String
    where T: IntoIterator<Item=S>,
          F: Fn(S) -> String {

  let mut buf = String::new();
  let mut first = true;

  for s in strs.into_iter() {

    if first {
      first = false;
    } else {
      buf.push_str(delimiter);
    }

    buf.push_str(&f(s));
  }

  buf
}

#[cfg(test)]
mod tests {
  use std::fmt;
  use super::{Concatable, ConcatableWithMap};
  use super::{join, join_with_map};

  pub struct Test {
    x: i32
  }

  impl fmt::Display for Test {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
      write!(f, "<{}>", self.x)
    }
  }

#[test]
  fn test_concatable() {
    let ts = vec![
      Test {x: 1}, Test {x: 2}
    ];

    assert_eq!("<1><2>".to_string(), ts.concat2());
  }

  #[test]
  fn test_join() {
    let str_vec = vec!["a", "b", "c"];
    let str_arr = ["a", "b", "c"];

    assert_eq!("a,b,c".to_string(), join(&str_vec, ","));
    assert_eq!("a,b,c".to_string(), join(&str_arr, ","));

    assert_eq!("abc".to_string(), str_vec.concat2());
    assert_eq!("abc".to_string(), str_arr.concat2());

    assert_eq!("abc".to_string(), str_vec.concat_with_map(|x| format!("{}", x)));
    assert_eq!("abc".to_string(), str_arr.concat_with_map(|x| format!("{}", x)));

    assert_eq!("a,b,c".to_string(), join_with_map(&str_vec, ",", |x| x.to_string()));
    assert_eq!("a,b,c".to_string(), join_with_map(&str_arr, ",", |x| x.to_string()));
  }
}
<commit_msg>Fix line width according to coding standard<commit_after>use std::fmt::Display;

pub trait Concatable {
  fn concat2(&self) -> String;
  fn join2(&self, delim: &str) -> String;
}

impl<V: Display> Concatable for [V] {
  fn concat2(&self) -> String {
    let mut buf = String::new();
    for x in self.iter() {
      buf.push_str(&format!("{}", x));
    }
    buf
  }

  fn join2(&self, delim: &str) -> String {
    let mut buf = String::new();
    let mut first = true;

    for s in self.iter() {
      if first {
        first = false;
      } else {
        buf.push_str(delim);
      }

      buf.push_str(&format!("{}", s));
    }

    buf
  }
}

pub trait ConcatableWithMap<V, F: Fn(&V) -> String> {
  fn concat_with_map(&self, f: F) -> String;
  fn join_with_map(&self, delim: &str, f: F) -> String;
}

impl<V, F: Fn(&V) -> String> ConcatableWithMap<V, F> for [V] {

  fn concat_with_map(&self, f: F) -> String {
     let mut buf = String::new();
     for v in self.iter() {
       buf.push_str(&f(v));
     }
     buf
  }

  fn join_with_map(&self, delim: &str, f: F) -> String {
    let mut buf = String::new();
    let mut first = true;

    for v in self.iter() {
      if first {
        first = false;
      } else {
        buf.push_str(delim);
      }

      buf.push_str(&f(v));
    }

    buf
  }
}

pub fn join<S, T>(strs: T, delimiter: &str) -> String
    where S: Display,
          T: IntoIterator<Item=S> {

  let mut buf = String::new();
  let mut first = true;

  for s in strs.into_iter() {

    if first {
      first = false;
    } else {
      buf.push_str(delimiter);
    }

    buf.push_str(&format!("{}", s));
  }

  buf
}

pub fn join_with_map<'a, S, T, F>(strs: T, delimiter: &str, f: F) -> String
    where T: IntoIterator<Item=S>,
          F: Fn(S) -> String {

  let mut buf = String::new();
  let mut first = true;

  for s in strs.into_iter() {

    if first {
      first = false;
    } else {
      buf.push_str(delimiter);
    }

    buf.push_str(&f(s));
  }

  buf
}

#[cfg(test)]
mod tests {
  use std::fmt;
  use super::{Concatable, ConcatableWithMap};
  use super::{join, join_with_map};

  pub struct Test {
    x: i32
  }

  impl fmt::Display for Test {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
      write!(f, "<{}>", self.x)
    }
  }

#[test]
  fn test_concatable() {
    let ts = vec![
      Test {x: 1}, Test {x: 2}
    ];

    assert_eq!("<1><2>".to_string(), ts.concat2());
  }

  #[test]
  fn test_join() {
    let str_vec = vec!["a", "b", "c"];
    let str_arr = ["a", "b", "c"];

    assert_eq!("a,b,c".to_string(), join(&str_vec, ","));
    assert_eq!("a,b,c".to_string(), join(&str_arr, ","));

    assert_eq!("abc".to_string(), str_vec.concat2());
    assert_eq!("abc".to_string(), str_arr.concat2());

    assert_eq!("abc".to_string(),
      str_vec.concat_with_map(|x| format!("{}", x)));
    assert_eq!("abc".to_string(),
      str_arr.concat_with_map(|x| format!("{}", x)));

    assert_eq!("a,b,c".to_string(),
      join_with_map(&str_vec, ",", |x| x.to_string()));
    assert_eq!("a,b,c".to_string(),
      join_with_map(&str_arr, ",", |x| x.to_string()));
  }
}
<|endoftext|>