<commit_before>use std::{cell::Cell, rc::Weak};

use libc::{c_double, c_uint};
use wlroots_sys::{wlr_input_device, wlr_input_device_pointer, wlr_input_device_type,
                  wlr_input_device_type::*};

use utils::c_to_rust_string;

use {KeyboardHandle, PointerHandle, TouchHandle, TabletPadHandle, TabletToolHandle};

/// A handle to an input device.
pub enum InputHandle {
    Keyboard(KeyboardHandle),
    Pointer(PointerHandle),
    Touch(TouchHandle),
    TabletPad(TabletPadHandle),
    TabletTool(TabletToolHandle)
}

pub(crate) struct InputState {
    pub(crate) handle: Weak<Cell<bool>>,
    pub(crate) device: InputDevice
}

/// Wrapper for wlr_input_device
#[derive(Debug, Eq, PartialEq, Hash)]
pub struct InputDevice {
    device: *mut wlr_input_device
}

impl InputDevice {
    /// Just like `std::clone::Clone`, but unsafe.
    ///
    /// # Unsafety
    /// This is unsafe because the user should not be able to clone
    /// this type out because it isn't bound by anything but the underlying
    /// pointer could be removed at any time.
    ///
    /// This isn't exposed to the user, but still marked as `unsafe` to reduce
    /// possible bugs from using this.
    pub(crate) unsafe fn clone(&self) -> Self {
        InputDevice { device: self.device }
    }

    pub fn vendor(&self) -> c_uint {
        unsafe { (*self.device).vendor }
    }

    pub fn product(&self) -> c_uint {
        unsafe { (*self.device).product }
    }

    pub fn name(&self) -> Option<String> {
        unsafe { c_to_rust_string((*self.device).name) }
    }

    /// Get the size in (width_mm, height_mm) format.
    ///
    /// These values will be 0 if it's not supported.
    pub fn size(&self) -> (c_double, c_double) {
        unsafe { ((*self.device).width_mm, (*self.device).height_mm) }
    }

    /// Get the type of the device
    pub fn dev_type(&self) -> wlr_input_device_type {
        unsafe { (*self.device).type_ }
    }

    /// Get a handle to the backing input device.
    pub fn device(&self) -> InputHandle {
        unsafe {
            match self.dev_type() {
                WLR_INPUT_DEVICE_KEYBOARD => {
                    let keyboard_ptr = (*self.device).__bindgen_anon_1.keyboard;
                    InputHandle::Keyboard(KeyboardHandle::from_ptr(keyboard_ptr))
                },
                WLR_INPUT_DEVICE_POINTER => {
                    let pointer_ptr = (*self.device).__bindgen_anon_1.pointer;
                    InputHandle::Pointer(PointerHandle::from_ptr(pointer_ptr))
                },
                WLR_INPUT_DEVICE_TOUCH => {
                    let touch_ptr = (*self.device).__bindgen_anon_1.touch;
                    InputHandle::Touch(TouchHandle::from_ptr(touch_ptr))
                },
                WLR_INPUT_DEVICE_TABLET_TOOL => {
                    let tablet_tool_ptr = (*self.device).__bindgen_anon_1.tablet_tool;
                    InputHandle::TabletTool(TabletToolHandle::from_ptr(tablet_tool_ptr))
                },
                WLR_INPUT_DEVICE_TABLET_PAD => {
                    let tablet_pad_ptr = (*self.device).__bindgen_anon_1.tablet_pad;
                    InputHandle::TabletPad(TabletPadHandle::from_ptr(tablet_pad_ptr))
                },
            }
        }
    }

    pub(crate) unsafe fn dev_union(&self) -> wlr_input_device_pointer {
        (*self.device).__bindgen_anon_1
    }

    pub(crate) unsafe fn from_ptr(device: *mut wlr_input_device) -> Self {
        InputDevice { device: device }
    }

    pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_input_device {
        self.device
    }
}
<commit_msg>Added output_name to InputDevice<commit_after>use std::{cell::Cell, rc::Weak};

use libc::{c_double, c_uint};
use wlroots_sys::{wlr_input_device, wlr_input_device_pointer, wlr_input_device_type,
                  wlr_input_device_type::*};

use utils::c_to_rust_string;

use {KeyboardHandle, PointerHandle, TouchHandle, TabletPadHandle, TabletToolHandle};

/// A handle to an input device.
pub enum InputHandle {
    Keyboard(KeyboardHandle),
    Pointer(PointerHandle),
    Touch(TouchHandle),
    TabletPad(TabletPadHandle),
    TabletTool(TabletToolHandle)
}

pub(crate) struct InputState {
    pub(crate) handle: Weak<Cell<bool>>,
    pub(crate) device: InputDevice
}

/// Wrapper for wlr_input_device
#[derive(Debug, Eq, PartialEq, Hash)]
pub struct InputDevice {
    device: *mut wlr_input_device
}

impl InputDevice {
    /// Just like `std::clone::Clone`, but unsafe.
    ///
    /// # Unsafety
    /// This is unsafe because the user should not be able to clone
    /// this type out because it isn't bound by anything but the underlying
    /// pointer could be removed at any time.
    ///
    /// This isn't exposed to the user, but still marked as `unsafe` to reduce
    /// possible bugs from using this.
    pub(crate) unsafe fn clone(&self) -> Self {
        InputDevice { device: self.device }
    }

    pub fn vendor(&self) -> c_uint {
        unsafe { (*self.device).vendor }
    }

    pub fn product(&self) -> c_uint {
        unsafe { (*self.device).product }
    }

    pub fn name(&self) -> Option<String> {
        unsafe { c_to_rust_string((*self.device).name) }
    }

    pub fn output_name(&self) -> Option<String> {
        unsafe { c_to_rust_string((*self.device).output_name) }
    }

    /// Get the size in (width_mm, height_mm) format.
    ///
    /// These values will be 0 if it's not supported.
    pub fn size(&self) -> (c_double, c_double) {
        unsafe { ((*self.device).width_mm, (*self.device).height_mm) }
    }

    /// Get the type of the device
    pub fn dev_type(&self) -> wlr_input_device_type {
        unsafe { (*self.device).type_ }
    }

    /// Get a handle to the backing input device.
    pub fn device(&self) -> InputHandle {
        unsafe {
            match self.dev_type() {
                WLR_INPUT_DEVICE_KEYBOARD => {
                    let keyboard_ptr = (*self.device).__bindgen_anon_1.keyboard;
                    InputHandle::Keyboard(KeyboardHandle::from_ptr(keyboard_ptr))
                },
                WLR_INPUT_DEVICE_POINTER => {
                    let pointer_ptr = (*self.device).__bindgen_anon_1.pointer;
                    InputHandle::Pointer(PointerHandle::from_ptr(pointer_ptr))
                },
                WLR_INPUT_DEVICE_TOUCH => {
                    let touch_ptr = (*self.device).__bindgen_anon_1.touch;
                    InputHandle::Touch(TouchHandle::from_ptr(touch_ptr))
                },
                WLR_INPUT_DEVICE_TABLET_TOOL => {
                    let tablet_tool_ptr = (*self.device).__bindgen_anon_1.tablet_tool;
                    InputHandle::TabletTool(TabletToolHandle::from_ptr(tablet_tool_ptr))
                },
                WLR_INPUT_DEVICE_TABLET_PAD => {
                    let tablet_pad_ptr = (*self.device).__bindgen_anon_1.tablet_pad;
                    InputHandle::TabletPad(TabletPadHandle::from_ptr(tablet_pad_ptr))
                },
            }
        }
    }

    pub(crate) unsafe fn dev_union(&self) -> wlr_input_device_pointer {
        (*self.device).__bindgen_anon_1
    }

    pub(crate) unsafe fn from_ptr(device: *mut wlr_input_device) -> Self {
        InputDevice { device: device }
    }

    pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_input_device {
        self.device
    }
}
<|endoftext|>


<commit_before>use std::default;

use enum_iterator::IntoEnumIterator;
use int_enum::IntEnum;

#[repr(usize)]
#[derive(Clone, Copy, Debug, IntoEnumIterator, IntEnum, PartialEq)]
pub enum ResistorColor {
    Black = 0,
    Brown = 1,
    Red = 2,
    Orange = 3,
    Yellow = 4,
    Green = 5,
    Blue = 6,
    Violet = 7,
    Grey = 8,
    White = 9,
}

pub fn color_to_value(_color: ResistorColor) -> usize {
    return _color.int_value()
}

pub fn value_to_color_string(value: usize) -> String {
    for color in ResistorColor::into_enum_iter() {
        if value == color.int_value() {
            return label(color)
        }
    }

    return "value out of range".to_string()
}

pub fn colors() -> Vec<ResistorColor> {
    unimplemented!("return a list of all the colors ordered by resistance")
}

fn label(color: ResistorColor) -> String {
    match color {
        ResistorColor::Black => "Black".to_string(),
        ResistorColor::Brown => "Brown".to_string(),
        ResistorColor::Red => "Red".to_string(),
        ResistorColor::Orange => "Orange".to_string(),
        ResistorColor::Yellow => "Yellow".to_string(),
        ResistorColor::Green => "Green".to_string(),
        ResistorColor::Blue => "Blue".to_string(),
        ResistorColor::Violet => "Violet".to_string(),
        ResistorColor::Grey => "Grey".to_string(),
        ResistorColor::White => "White".to_string(),
    }
}
<commit_msg>Refactor value_to_color_string<commit_after>use std::default;

use enum_iterator::IntoEnumIterator;
use int_enum::IntEnum;

#[repr(usize)]
#[derive(Clone, Copy, Debug, IntoEnumIterator, IntEnum, PartialEq)]
pub enum ResistorColor {
    Black = 0,
    Brown = 1,
    Red = 2,
    Orange = 3,
    Yellow = 4,
    Green = 5,
    Blue = 6,
    Violet = 7,
    Grey = 8,
    White = 9,
}

pub fn color_to_value(_color: ResistorColor) -> usize {
    return _color.int_value()
}

pub fn value_to_color_string(value: usize) -> String {
    match value {
        0 => "Black".to_string(),
        1 => "Brown".to_string(),
        2 => "Red".to_string(),
        3 => "Orange".to_string(),
        4 => "Yellow".to_string(),
        5 => "Green".to_string(),
        6 => "Blue".to_string(),
        7 => "Violet".to_string(),
        8 => "Grey".to_string(),
        9 => "White".to_string(),
        _ => "value out of range".to_string()
    }
}

pub fn colors() -> Vec<ResistorColor> {
    unimplemented!("return a list of all the colors ordered by resistance")
}
<|endoftext|>


<commit_before>//! The state of the game itself.

use message;

use std::collections::HashMap;
use std::sync::mpsc;

use math::distance_between;
use rand::{thread_rng, Rng};

use self::super::Client;
use self::super::WebSocketEvent;

static BULLET_RADIUS: f32 = 5.0;
static PLAYER_RADIUS: f32 = 10.0;
static BULLET_SPEED: f32 = 3.0;
static PLAYER_SPEED: f32 = 2.0;
static MAP_HEIGHT: f32 = 500.0;
static MAP_WIDTH: f32 = 500.0;
static TICKS_BETWEEN_FULL_UPDATES: u32 = 600; // 10s @ 60FPS

/// The `GameState` contains the whole state of the game.
///
/// It consists of both players, and all the clients which are currently connected.
#[derive(Debug)]
pub struct GameState {
    players: HashMap<u32, message::Player>,
    bullets: HashMap<u32, message::Bullet>,
    clients: HashMap<u32, Client>,
    next_bullet_id: u32,
    ticks_since_last_full_update: u32,
}

impl GameState {
    /// Create a new game state.
    pub fn new() -> GameState {
        GameState {
            players: HashMap::new(),
            bullets: HashMap::new(),
            clients: HashMap::new(),
            next_bullet_id: 0,
            ticks_since_last_full_update: 0,
        }
    }

    /// Tries to process every available websocket event without blocking.
    pub fn process_websocket_events(&mut self, game_messages: &mpsc::Receiver<WebSocketEvent>) {
        loop {
            match game_messages.try_recv() {
                Ok(message) => self.process_websocket_event(message),
                Err(mpsc::TryRecvError::Empty) => return,
                Err(mpsc::TryRecvError::Disconnected) => panic!("Now I am disconnected?"),
            }
        }
    }

    /// Updates the game state in one tick.
    pub fn process_game_update(&mut self) {
        // Do a normal position update
        let player_ids: Vec<_> = self.players.keys().map(|i| *i).collect();
        for cur_player_id in &player_ids {
            {
                let cur_player = self.players.get(cur_player_id).unwrap();
                match (cur_player.move_x, cur_player.move_y) {
                    (None, None) => continue,
                    (Some(move_x), Some(move_y)) => {
                        let mut collides = false;
                        for cmp_player_id in &player_ids {
                            if cmp_player_id != cur_player_id {
                                let cmp_player = self.players.get(cmp_player_id).unwrap();
                                if distance_between(cur_player.x + move_x,
                                                    cur_player.y + move_y,
                                                    cmp_player.x,
                                                    cmp_player.y) <
                                   2.0 * PLAYER_RADIUS {
                                    collides = true;
                                    break;
                                }
                            }
                        }
                        if collides {
                            continue;
                        }
                    }
                    _ => panic!("Invariant not met: player moves only in one direction"),
                }
            }

            let mut player = self.players.get_mut(cur_player_id).unwrap();
            player.x = (player.x + player.move_x.unwrap_or(0.0) * PLAYER_SPEED)
                           .max(PLAYER_RADIUS)
                           .min(MAP_WIDTH - PLAYER_RADIUS);
            player.y = (player.y + player.move_y.unwrap_or(0.0) * PLAYER_SPEED)
                           .max(PLAYER_RADIUS)
                           .min(MAP_HEIGHT - PLAYER_RADIUS);
        }

        let mut destroyed_bullets = Vec::new();
        let mut destroyed_players = Vec::new();

        for (_, bullet) in &mut self.bullets {
            bullet.x += bullet.move_x.unwrap_or(0.0) * BULLET_SPEED;
            bullet.y += bullet.move_y.unwrap_or(0.0) * BULLET_SPEED;

            if bullet.x < 0.0 || bullet.x > MAP_WIDTH || bullet.y < 0.0 || bullet.y > MAP_HEIGHT {
                destroyed_bullets.push(bullet.id);
            }
        }

        // Check for collisions
        for (_, bullet) in &mut self.bullets {
            for (_, player) in &mut self.players {
                if distance_between(bullet.x, bullet.y, player.x, player.y) <
                   BULLET_RADIUS + PLAYER_RADIUS {
                    destroyed_bullets.push(bullet.id);
                    destroyed_players.push(player.id);
                }
            }
        }

        // Process destroy requests
        for bullet_id in destroyed_bullets {
            let _ = self.bullets.remove(&bullet_id);
        }

        let mut rng = thread_rng();
        for player_id in destroyed_players {
            self.send_to_everybody(message::Message::PlayerDestroyed {
                id: player_id,
                killer_id: None,
                bullet_id: None,
            });

            let (new_x, new_y) = self.random_free_spot(&mut rng);

            {
                let dead_player = self.players.get_mut(&player_id).unwrap();
                dead_player.x = new_x;
                dead_player.y = new_y;
            }

            self.send_to_everybody(message::Message::PlayerSpawned {
                id: player_id,
                x: new_x,
                y: new_y,
            });
        }
    }

    /// Send the current state to each client.
    pub fn send_state_updates(&mut self) {
        if self.ticks_since_last_full_update == TICKS_BETWEEN_FULL_UPDATES {
            self.ticks_since_last_full_update = 0;
            self.send_to_everybody(self.serialize());
        } else {
            self.ticks_since_last_full_update += 1;
        }
    }

    /// Process a web socket event.
    fn process_websocket_event(&mut self, message: WebSocketEvent) {
        match message {
            WebSocketEvent::ClientCreated { client } => {
                let welcome_message = message::Message::Welcome {
                    id: client.id,
                    speed: PLAYER_SPEED,
                    size: PLAYER_RADIUS,
                    bullet_speed: BULLET_SPEED,
                    bullet_size: BULLET_RADIUS,
                };

                let _ = client.send(welcome_message.to_string());
                self.send_to_everybody(message::Message::PlayerJoined { id: client.id });

                let (x, y) = self.random_free_spot(&mut thread_rng());
                let _ = self.players
                            .insert(client.id, message::Player::not_moving(client.id, x, y));
                self.send_to_everybody(message::Message::PlayerSpawned {
                    id: client.id,
                    x: x,
                    y: y,
                });

                let _ = client.send(self.serialize().to_string());

                let _ = self.clients.insert(client.id, client);
            }
            WebSocketEvent::ClientClosed { client_id } => {
                let _ = self.players.remove(&client_id);
                let _ = self.clients.remove(&client_id);

                self.send_to_everybody(message::Message::PlayerLeft { id: client_id });
            }
            WebSocketEvent::ClientMessage { client_id, message } => {
                self.process_client_message(client_id, message);
            }
        }
    }

    /// Serialize the entire game state into one json string.
    fn serialize(&self) -> message::Message {
        let players: Vec<_> = self.players
                                  .values()
                                  .cloned()
                                  .collect();
        let bullets: Vec<_> = self.bullets
                                  .values()
                                  .cloned()
                                  .collect();
        message::Message::WorldState {
            player_count: players.len() as u32,
            alive_players: players,
            alive_bullets: bullets,
        }
    }

    /// Process a simple string message from the client.
    fn process_client_message(&mut self, client_id: u32, message: message::Message) {
        match message {
            message::Message::StartMoving { move_x, move_y } => {
                let resp = {
                    let player = self.players.get_mut(&client_id).unwrap();
                    player.move_x = Some(move_x);
                    player.move_y = Some(move_y);

                    message::Message::PlayerMoving {
                        id: player.id,
                        x: player.x,
                        y: player.y,
                        move_x: move_x,
                        move_y: move_y,
                    }
                };
                self.send_to_everybody(resp);
            }
            message::Message::StopMoving => {
                let resp = {
                    let player = self.players.get_mut(&client_id).unwrap();
                    player.move_x = None;
                    player.move_y = None;

                    message::Message::PlayerStopped {
                        id: player.id,
                        x: player.x,
                        y: player.y,
                    }
                };
                self.send_to_everybody(resp);
            }
            message::Message::Fire { move_x, move_y } => {
                let player = self.players.get(&client_id).unwrap();

                // Have to move the bullet out of the way of the player to avoid an instant collision.
                let start_x = player.x + move_x * (BULLET_RADIUS + PLAYER_RADIUS + 1.0);
                let start_y = player.y + move_y * (BULLET_RADIUS + PLAYER_RADIUS + 1.0);

                let _ = self.bullets.insert(self.next_bullet_id,
                                            message::Bullet::moving(self.next_bullet_id,
                                                                    start_x,
                                                                    start_y,
                                                                    move_x,
                                                                    move_y));

                let resp = message::Message::ShotsFired {
                    id: player.id,
                    bullet_id: self.next_bullet_id,
                    x: start_x,
                    y: start_y,
                    aim_x: move_x,
                    aim_y: move_y,
                };
                self.send_to_everybody(resp);

                self.next_bullet_id += 1;
            }
            _ => panic!("Unprocessed message! {}", message.to_string()),
        }
    }

    fn random_free_spot<R: Rng>(&self, rng: &mut R) -> (f32, f32) {
        static MAX_ITERATIONS: u32 = 100;

        let min_vial_x = PLAYER_RADIUS;
        let min_vial_y = PLAYER_RADIUS;
        let max_vial_x = MAP_WIDTH - PLAYER_RADIUS;
        let max_vial_y = MAP_HEIGHT - PLAYER_RADIUS;

        for _ in 1..MAX_ITERATIONS {
            let x: f32 = rng.gen_range(min_vial_x, max_vial_x);
            let y: f32 = rng.gen_range(min_vial_y, max_vial_y);

            let mut collides = false;

            for (_, player) in &self.players {
                if distance_between(x, y, player.x, player.y) < 2.0 * PLAYER_RADIUS {
                    collides = true;
                    break;
                }
            }

            for (_, bullet) in &self.bullets {
                if distance_between(x, y, bullet.x, bullet.y) < PLAYER_RADIUS + BULLET_RADIUS {
                    collides = true;
                    break;
                }
            }

            if !collides {
                return (x, y);
            }
        }
        println!("Failed to find a random empty spot for player after {} iterations",
                 MAX_ITERATIONS);

        (rng.gen_range(0.0, MAP_WIDTH), rng.gen_range(0.0, MAP_HEIGHT))
    }

    fn send_to_everybody(&self, what: message::Message) {
        let value = what.to_string();
        for (_, client) in &self.clients {
            // Always ignore if the send fails.
            // We will eventually get a disconnect WebSocketMessage where we will cleanly do the disconnect.
            let _ = client.send(value.clone());
        }
    }
}
<commit_msg>Send player_stopped message when player is forced to stop<commit_after>//! The state of the game itself.

use message;

use std::collections::HashMap;
use std::sync::mpsc;

use math::distance_between;
use rand::{thread_rng, Rng};

use self::super::Client;
use self::super::WebSocketEvent;

static BULLET_RADIUS: f32 = 5.0;
static PLAYER_RADIUS: f32 = 10.0;
static BULLET_SPEED: f32 = 3.0;
static PLAYER_SPEED: f32 = 2.0;
static MAP_HEIGHT: f32 = 500.0;
static MAP_WIDTH: f32 = 500.0;
static TICKS_BETWEEN_FULL_UPDATES: u32 = 600; // 10s @ 60FPS

/// The `GameState` contains the whole state of the game.
///
/// It consists of both players, and all the clients which are currently connected.
#[derive(Debug)]
pub struct GameState {
    players: HashMap<u32, message::Player>,
    bullets: HashMap<u32, message::Bullet>,
    clients: HashMap<u32, Client>,
    next_bullet_id: u32,
    ticks_since_last_full_update: u32,
}

impl GameState {
    /// Create a new game state.
    pub fn new() -> GameState {
        GameState {
            players: HashMap::new(),
            bullets: HashMap::new(),
            clients: HashMap::new(),
            next_bullet_id: 0,
            ticks_since_last_full_update: 0,
        }
    }

    /// Tries to process every available websocket event without blocking.
    pub fn process_websocket_events(&mut self, game_messages: &mpsc::Receiver<WebSocketEvent>) {
        loop {
            match game_messages.try_recv() {
                Ok(message) => self.process_websocket_event(message),
                Err(mpsc::TryRecvError::Empty) => return,
                Err(mpsc::TryRecvError::Disconnected) => panic!("Now I am disconnected?"),
            }
        }
    }

    /// Updates the game state in one tick.
    pub fn process_game_update(&mut self) {
        // Do a normal position update
        let player_ids: Vec<_> = self.players.keys().map(|i| *i).collect();
        let mut force_stopped_player_ids = Vec::new();
        for cur_player_id in &player_ids {
            let collides_with_player = {
                let cur_player = self.players.get(cur_player_id).unwrap();
                match (cur_player.move_x, cur_player.move_y) {
                    (None, None) => continue,
                    (Some(move_x), Some(move_y)) => {
                        let mut collides = false;
                        for cmp_player_id in &player_ids {
                            if cmp_player_id != cur_player_id {
                                let cmp_player = self.players.get(cmp_player_id).unwrap();
                                if distance_between(cur_player.x + move_x,
                                                    cur_player.y + move_y,
                                                    cmp_player.x,
                                                    cmp_player.y) <
                                   2.0 * PLAYER_RADIUS {
                                    collides = true;
                                    break;
                                }
                            }
                        }
                        collides
                    }
                    _ => panic!("Invariant not met: player moves only in one direction"),
                }
            };

            let mut player = self.players.get_mut(cur_player_id).unwrap();
            let mut collides_with_map = false;

            if !collides_with_player {
                player.x = (player.x + player.move_x.unwrap_or(0.0) * PLAYER_SPEED)
                               .max(PLAYER_RADIUS)
                               .min(MAP_WIDTH - PLAYER_RADIUS);
                player.y = (player.y + player.move_y.unwrap_or(0.0) * PLAYER_SPEED)
                               .max(PLAYER_RADIUS)
                               .min(MAP_HEIGHT - PLAYER_RADIUS);

                collides_with_map = (player.x == PLAYER_RADIUS ||
                                     player.x == MAP_WIDTH - PLAYER_RADIUS) ||
                                    (player.y == PLAYER_RADIUS ||
                                     player.y == MAP_WIDTH - PLAYER_RADIUS);
            }

            if collides_with_player || collides_with_map {
                force_stopped_player_ids.push(cur_player_id);
            }
        }

        for force_stopped_player_id in force_stopped_player_ids {
            let (x, y) = {
                let mut player = self.players.get_mut(force_stopped_player_id).unwrap();
                player.move_x = None;
                player.move_y = None;
                (player.x, player.y)
            };
            self.send_to_everybody(message::Message::PlayerStopped {
                id: *force_stopped_player_id,
                x: x,
                y: y,
            });
        }

        let mut destroyed_bullets = Vec::new();
        let mut destroyed_players = Vec::new();

        for (_, bullet) in &mut self.bullets {
            bullet.x += bullet.move_x.unwrap_or(0.0) * BULLET_SPEED;
            bullet.y += bullet.move_y.unwrap_or(0.0) * BULLET_SPEED;

            if bullet.x < 0.0 || bullet.x > MAP_WIDTH || bullet.y < 0.0 || bullet.y > MAP_HEIGHT {
                destroyed_bullets.push(bullet.id);
            }
        }

        // Check for collisions
        for (_, bullet) in &mut self.bullets {
            for (_, player) in &mut self.players {
                if distance_between(bullet.x, bullet.y, player.x, player.y) <
                   BULLET_RADIUS + PLAYER_RADIUS {
                    destroyed_bullets.push(bullet.id);
                    destroyed_players.push(player.id);
                }
            }
        }

        // Process destroy requests
        for bullet_id in destroyed_bullets {
            let _ = self.bullets.remove(&bullet_id);
        }

        let mut rng = thread_rng();
        for player_id in destroyed_players {
            self.send_to_everybody(message::Message::PlayerDestroyed {
                id: player_id,
                killer_id: None,
                bullet_id: None,
            });

            let (new_x, new_y) = self.random_free_spot(&mut rng);

            {
                let dead_player = self.players.get_mut(&player_id).unwrap();
                dead_player.x = new_x;
                dead_player.y = new_y;
            }

            self.send_to_everybody(message::Message::PlayerSpawned {
                id: player_id,
                x: new_x,
                y: new_y,
            });
        }
    }

    /// Send the current state to each client.
    pub fn send_state_updates(&mut self) {
        if self.ticks_since_last_full_update == TICKS_BETWEEN_FULL_UPDATES {
            self.ticks_since_last_full_update = 0;
            self.send_to_everybody(self.serialize());
        } else {
            self.ticks_since_last_full_update += 1;
        }
    }

    /// Process a web socket event.
    fn process_websocket_event(&mut self, message: WebSocketEvent) {
        match message {
            WebSocketEvent::ClientCreated { client } => {
                let welcome_message = message::Message::Welcome {
                    id: client.id,
                    speed: PLAYER_SPEED,
                    size: PLAYER_RADIUS,
                    bullet_speed: BULLET_SPEED,
                    bullet_size: BULLET_RADIUS,
                };

                let _ = client.send(welcome_message.to_string());
                self.send_to_everybody(message::Message::PlayerJoined { id: client.id });

                let (x, y) = self.random_free_spot(&mut thread_rng());
                let _ = self.players
                            .insert(client.id, message::Player::not_moving(client.id, x, y));
                self.send_to_everybody(message::Message::PlayerSpawned {
                    id: client.id,
                    x: x,
                    y: y,
                });

                let _ = client.send(self.serialize().to_string());

                let _ = self.clients.insert(client.id, client);
            }
            WebSocketEvent::ClientClosed { client_id } => {
                let _ = self.players.remove(&client_id);
                let _ = self.clients.remove(&client_id);

                self.send_to_everybody(message::Message::PlayerLeft { id: client_id });
            }
            WebSocketEvent::ClientMessage { client_id, message } => {
                self.process_client_message(client_id, message);
            }
        }
    }

    /// Serialize the entire game state into one json string.
    fn serialize(&self) -> message::Message {
        let players: Vec<_> = self.players
                                  .values()
                                  .cloned()
                                  .collect();
        let bullets: Vec<_> = self.bullets
                                  .values()
                                  .cloned()
                                  .collect();
        message::Message::WorldState {
            player_count: players.len() as u32,
            alive_players: players,
            alive_bullets: bullets,
        }
    }

    /// Process a simple string message from the client.
    fn process_client_message(&mut self, client_id: u32, message: message::Message) {
        match message {
            message::Message::StartMoving { move_x, move_y } => {
                let resp = {
                    let player = self.players.get_mut(&client_id).unwrap();
                    player.move_x = Some(move_x);
                    player.move_y = Some(move_y);

                    message::Message::PlayerMoving {
                        id: player.id,
                        x: player.x,
                        y: player.y,
                        move_x: move_x,
                        move_y: move_y,
                    }
                };
                self.send_to_everybody(resp);
            }
            message::Message::StopMoving => {
                let resp = {
                    let player = self.players.get_mut(&client_id).unwrap();
                    player.move_x = None;
                    player.move_y = None;

                    message::Message::PlayerStopped {
                        id: player.id,
                        x: player.x,
                        y: player.y,
                    }
                };
                self.send_to_everybody(resp);
            }
            message::Message::Fire { move_x, move_y } => {
                let player = self.players.get(&client_id).unwrap();

                // Have to move the bullet out of the way of the player to avoid an instant collision.
                let start_x = player.x + move_x * (BULLET_RADIUS + PLAYER_RADIUS + 1.0);
                let start_y = player.y + move_y * (BULLET_RADIUS + PLAYER_RADIUS + 1.0);

                let _ = self.bullets.insert(self.next_bullet_id,
                                            message::Bullet::moving(self.next_bullet_id,
                                                                    start_x,
                                                                    start_y,
                                                                    move_x,
                                                                    move_y));

                let resp = message::Message::ShotsFired {
                    id: player.id,
                    bullet_id: self.next_bullet_id,
                    x: start_x,
                    y: start_y,
                    aim_x: move_x,
                    aim_y: move_y,
                };
                self.send_to_everybody(resp);

                self.next_bullet_id += 1;
            }
            _ => panic!("Unprocessed message! {}", message.to_string()),
        }
    }

    fn random_free_spot<R: Rng>(&self, rng: &mut R) -> (f32, f32) {
        static MAX_ITERATIONS: u32 = 100;

        let min_vial_x = PLAYER_RADIUS;
        let min_vial_y = PLAYER_RADIUS;
        let max_vial_x = MAP_WIDTH - PLAYER_RADIUS;
        let max_vial_y = MAP_HEIGHT - PLAYER_RADIUS;

        for _ in 1..MAX_ITERATIONS {
            let x: f32 = rng.gen_range(min_vial_x, max_vial_x);
            let y: f32 = rng.gen_range(min_vial_y, max_vial_y);

            let mut collides = false;

            for (_, player) in &self.players {
                if distance_between(x, y, player.x, player.y) < 2.0 * PLAYER_RADIUS {
                    collides = true;
                    break;
                }
            }

            for (_, bullet) in &self.bullets {
                if distance_between(x, y, bullet.x, bullet.y) < PLAYER_RADIUS + BULLET_RADIUS {
                    collides = true;
                    break;
                }
            }

            if !collides {
                return (x, y);
            }
        }
        println!("Failed to find a random empty spot for player after {} iterations",
                 MAX_ITERATIONS);

        (rng.gen_range(0.0, MAP_WIDTH), rng.gen_range(0.0, MAP_HEIGHT))
    }

    fn send_to_everybody(&self, what: message::Message) {
        let value = what.to_string();
        for (_, client) in &self.clients {
            // Always ignore if the send fails.
            // We will eventually get a disconnect WebSocketMessage where we will cleanly do the disconnect.
            let _ = client.send(value.clone());
        }
    }
}
<|endoftext|>


<commit_before>use super::BLOCKS_DB_COLUMN as DB_COLUMN;
use super::{ClientDB, DBError};
use ssz::Decodable;
use std::sync::Arc;
use types::{readers::BeaconBlockReader, BeaconBlock, Hash256};

#[derive(Clone, Debug, PartialEq)]
pub enum BeaconBlockAtSlotError {
    UnknownBeaconBlock,
    InvalidBeaconBlock,
    DBError(String),
}

pub struct BeaconBlockStore<T>
where
    T: ClientDB,
{
    db: Arc<T>,
}

// Implements `put`, `get`, `exists` and `delete` for the store.
impl_crud_for_store!(BeaconBlockStore, DB_COLUMN);

impl<T: ClientDB> BeaconBlockStore<T> {
    pub fn new(db: Arc<T>) -> Self {
        Self { db }
    }

    /// Retuns an object implementing `BeaconBlockReader`, or `None` (if hash not known).
    ///
    /// Note: Presently, this function fully deserializes a `BeaconBlock` and returns that. In the
    /// future, it would be ideal to return an object capable of reading directly from serialized
    /// SSZ bytes.
    pub fn get_reader(&self, hash: &Hash256) -> Result<Option<impl BeaconBlockReader>, DBError> {
        match self.get(&hash)? {
            None => Ok(None),
            Some(ssz) => {
                let (block, _) = BeaconBlock::ssz_decode(&ssz, 0).map_err(|_| DBError {
                    message: "Bad BeaconBlock SSZ.".to_string(),
                })?;
                Ok(Some(block))
            }
        }
    }

    /// Retrieve the block at a slot given a "head_hash" and a slot.
    ///
    /// A "head_hash" must be a block hash with a slot number greater than or equal to the desired
    /// slot.
    ///
    /// This function will read each block down the chain until it finds a block with the given
    /// slot number. If the slot is skipped, the function will return None.
    ///
    /// If a block is found, a tuple of (block_hash, serialized_block) is returned.
    ///
    /// Note: this function uses a loop instead of recursion as the compiler is over-strict when it
    /// comes to recursion and the `impl Trait` pattern. See:
    /// https://stackoverflow.com/questions/54032940/using-impl-trait-in-a-recursive-function
    pub fn block_at_slot(
        &self,
        head_hash: &Hash256,
        slot: u64,
    ) -> Result<Option<(Hash256, impl BeaconBlockReader)>, BeaconBlockAtSlotError> {
        let mut current_hash = *head_hash;

        loop {
            if let Some(block_reader) = self.get_reader(&current_hash)? {
                if block_reader.slot() == slot {
                    break Ok(Some((current_hash, block_reader)));
                } else if block_reader.slot() < slot {
                    break Ok(None);
                } else {
                    current_hash = block_reader.parent_root();
                }
            } else {
                break Err(BeaconBlockAtSlotError::UnknownBeaconBlock);
            }
        }
    }
}

impl From<DBError> for BeaconBlockAtSlotError {
    fn from(e: DBError) -> Self {
        BeaconBlockAtSlotError::DBError(e.message)
    }
}

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

    use std::sync::Arc;
    use std::thread;

    use ssz::ssz_encode;
    use types::test_utils::{SeedableRng, TestRandom, XorShiftRng};
    use types::BeaconBlock;
    use types::Hash256;

    test_crud_for_store!(BeaconBlockStore, DB_COLUMN);

    #[test]
    fn test_invalid_block_at_slot() {
        let db = Arc::new(MemoryDB::open());
        let store = BeaconBlockStore::new(db.clone());

        let ssz = "definitly not a valid block".as_bytes();
        let hash = &Hash256::from("some hash".as_bytes());

        db.put(DB_COLUMN, hash, ssz).unwrap();
        assert_eq!(
            store.block_at_slot(hash, 42),
            Err(BeaconBlockAtSlotError::DBError(
                "Bad BeaconBlock SSZ.".into()
            ))
        );
    }

    #[test]
    fn test_unknown_block_at_slot() {
        let db = Arc::new(MemoryDB::open());
        let store = BeaconBlockStore::new(db.clone());

        let ssz = "some bytes".as_bytes();
        let hash = &Hash256::from("some hash".as_bytes());
        let other_hash = &Hash256::from("another hash".as_bytes());

        db.put(DB_COLUMN, hash, ssz).unwrap();
        assert_eq!(
            store.block_at_slot(other_hash, 42),
            Err(BeaconBlockAtSlotError::UnknownBeaconBlock)
        );
    }

    #[test]
    fn test_block_store_on_memory_db() {
        let db = Arc::new(MemoryDB::open());
        let bs = Arc::new(BeaconBlockStore::new(db.clone()));

        let thread_count = 10;
        let write_count = 10;

        // We're expecting the product of these numbers to fit in one byte.
        assert!(thread_count * write_count <= 255);

        let mut handles = vec![];
        for t in 0..thread_count {
            let wc = write_count;
            let bs = bs.clone();
            let handle = thread::spawn(move || {
                for w in 0..wc {
                    let key = (t * w) as u8;
                    let val = 42;
                    bs.put(&[key][..].into(), &vec![val]).unwrap();
                }
            });
            handles.push(handle);
        }

        for handle in handles {
            handle.join().unwrap();
        }

        for t in 0..thread_count {
            for w in 0..write_count {
                let key = (t * w) as u8;
                assert!(bs.exists(&[key][..].into()).unwrap());
                let val = bs.get(&[key][..].into()).unwrap().unwrap();
                assert_eq!(vec![42], val);
            }
        }
    }

    #[test]
    fn test_block_at_slot() {
        let db = Arc::new(MemoryDB::open());
        let bs = Arc::new(BeaconBlockStore::new(db.clone()));
        let mut rng = XorShiftRng::from_seed([42; 16]);

        // Specify test block parameters.
        let hashes = [
            Hash256::from(&[0; 32][..]),
            Hash256::from(&[1; 32][..]),
            Hash256::from(&[2; 32][..]),
            Hash256::from(&[3; 32][..]),
            Hash256::from(&[4; 32][..]),
        ];
        let parent_hashes = [
            Hash256::from(&[255; 32][..]), // Genesis block.
            Hash256::from(&[0; 32][..]),
            Hash256::from(&[1; 32][..]),
            Hash256::from(&[2; 32][..]),
            Hash256::from(&[3; 32][..]),
        ];
        let slots = [0, 1, 3, 4, 5];

        // Generate a vec of random blocks and store them in the DB.
        let block_count = 5;
        let mut blocks: Vec<BeaconBlock> = Vec::with_capacity(5);
        for i in 0..block_count {
            let mut block = BeaconBlock::random_for_test(&mut rng);

            block.parent_root = parent_hashes[i];
            block.slot = slots[i];

            let ssz = ssz_encode(&block);
            db.put(DB_COLUMN, &hashes[i], &ssz).unwrap();

            blocks.push(block);
        }

        // Test that certain slots can be reached from certain hashes.
        let test_cases = vec![(4, 4), (4, 3), (4, 2), (4, 1), (4, 0)];
        for (hashes_index, slot_index) in test_cases {
            let (matched_block_hash, reader) = bs
                .block_at_slot(&hashes[hashes_index], slots[slot_index])
                .unwrap()
                .unwrap();
            assert_eq!(matched_block_hash, hashes[slot_index]);
            assert_eq!(reader.slot(), slots[slot_index]);
        }

        let ssz = bs.block_at_slot(&hashes[4], 2).unwrap();
        assert_eq!(ssz, None);

        let ssz = bs.block_at_slot(&hashes[4], 6).unwrap();
        assert_eq!(ssz, None);

        let ssz = bs.block_at_slot(&Hash256::from("unknown".as_bytes()), 2);
        assert_eq!(ssz, Err(BeaconBlockAtSlotError::UnknownBeaconBlock));
    }
}
<commit_msg>Add additional block_store test.<commit_after>use super::BLOCKS_DB_COLUMN as DB_COLUMN;
use super::{ClientDB, DBError};
use ssz::Decodable;
use std::sync::Arc;
use types::{readers::BeaconBlockReader, BeaconBlock, Hash256};

#[derive(Clone, Debug, PartialEq)]
pub enum BeaconBlockAtSlotError {
    UnknownBeaconBlock,
    InvalidBeaconBlock,
    DBError(String),
}

pub struct BeaconBlockStore<T>
where
    T: ClientDB,
{
    db: Arc<T>,
}

// Implements `put`, `get`, `exists` and `delete` for the store.
impl_crud_for_store!(BeaconBlockStore, DB_COLUMN);

impl<T: ClientDB> BeaconBlockStore<T> {
    pub fn new(db: Arc<T>) -> Self {
        Self { db }
    }

    /// Retuns an object implementing `BeaconBlockReader`, or `None` (if hash not known).
    ///
    /// Note: Presently, this function fully deserializes a `BeaconBlock` and returns that. In the
    /// future, it would be ideal to return an object capable of reading directly from serialized
    /// SSZ bytes.
    pub fn get_reader(&self, hash: &Hash256) -> Result<Option<impl BeaconBlockReader>, DBError> {
        match self.get(&hash)? {
            None => Ok(None),
            Some(ssz) => {
                let (block, _) = BeaconBlock::ssz_decode(&ssz, 0).map_err(|_| DBError {
                    message: "Bad BeaconBlock SSZ.".to_string(),
                })?;
                Ok(Some(block))
            }
        }
    }

    /// Retrieve the block at a slot given a "head_hash" and a slot.
    ///
    /// A "head_hash" must be a block hash with a slot number greater than or equal to the desired
    /// slot.
    ///
    /// This function will read each block down the chain until it finds a block with the given
    /// slot number. If the slot is skipped, the function will return None.
    ///
    /// If a block is found, a tuple of (block_hash, serialized_block) is returned.
    ///
    /// Note: this function uses a loop instead of recursion as the compiler is over-strict when it
    /// comes to recursion and the `impl Trait` pattern. See:
    /// https://stackoverflow.com/questions/54032940/using-impl-trait-in-a-recursive-function
    pub fn block_at_slot(
        &self,
        head_hash: &Hash256,
        slot: u64,
    ) -> Result<Option<(Hash256, impl BeaconBlockReader)>, BeaconBlockAtSlotError> {
        let mut current_hash = *head_hash;

        loop {
            if let Some(block_reader) = self.get_reader(&current_hash)? {
                if block_reader.slot() == slot {
                    break Ok(Some((current_hash, block_reader)));
                } else if block_reader.slot() < slot {
                    break Ok(None);
                } else {
                    current_hash = block_reader.parent_root();
                }
            } else {
                break Err(BeaconBlockAtSlotError::UnknownBeaconBlock);
            }
        }
    }
}

impl From<DBError> for BeaconBlockAtSlotError {
    fn from(e: DBError) -> Self {
        BeaconBlockAtSlotError::DBError(e.message)
    }
}

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

    use std::sync::Arc;
    use std::thread;

    use ssz::ssz_encode;
    use types::test_utils::{SeedableRng, TestRandom, XorShiftRng};
    use types::BeaconBlock;
    use types::Hash256;

    test_crud_for_store!(BeaconBlockStore, DB_COLUMN);

    #[test]
    fn head_hash_slot_too_low() {
        let db = Arc::new(MemoryDB::open());
        let bs = Arc::new(BeaconBlockStore::new(db.clone()));
        let mut rng = XorShiftRng::from_seed([42; 16]);

        let mut block = BeaconBlock::random_for_test(&mut rng);
        block.slot = 10;

        let block_root = block.canonical_root();
        bs.put(&block_root, &ssz_encode(&block)).unwrap();

        let result = bs.block_at_slot(&block_root, 11).unwrap();
        assert_eq!(result, None);
    }

    #[test]
    fn test_invalid_block_at_slot() {
        let db = Arc::new(MemoryDB::open());
        let store = BeaconBlockStore::new(db.clone());

        let ssz = "definitly not a valid block".as_bytes();
        let hash = &Hash256::from("some hash".as_bytes());

        db.put(DB_COLUMN, hash, ssz).unwrap();
        assert_eq!(
            store.block_at_slot(hash, 42),
            Err(BeaconBlockAtSlotError::DBError(
                "Bad BeaconBlock SSZ.".into()
            ))
        );
    }

    #[test]
    fn test_unknown_block_at_slot() {
        let db = Arc::new(MemoryDB::open());
        let store = BeaconBlockStore::new(db.clone());

        let ssz = "some bytes".as_bytes();
        let hash = &Hash256::from("some hash".as_bytes());
        let other_hash = &Hash256::from("another hash".as_bytes());

        db.put(DB_COLUMN, hash, ssz).unwrap();
        assert_eq!(
            store.block_at_slot(other_hash, 42),
            Err(BeaconBlockAtSlotError::UnknownBeaconBlock)
        );
    }

    #[test]
    fn test_block_store_on_memory_db() {
        let db = Arc::new(MemoryDB::open());
        let bs = Arc::new(BeaconBlockStore::new(db.clone()));

        let thread_count = 10;
        let write_count = 10;

        // We're expecting the product of these numbers to fit in one byte.
        assert!(thread_count * write_count <= 255);

        let mut handles = vec![];
        for t in 0..thread_count {
            let wc = write_count;
            let bs = bs.clone();
            let handle = thread::spawn(move || {
                for w in 0..wc {
                    let key = (t * w) as u8;
                    let val = 42;
                    bs.put(&[key][..].into(), &vec![val]).unwrap();
                }
            });
            handles.push(handle);
        }

        for handle in handles {
            handle.join().unwrap();
        }

        for t in 0..thread_count {
            for w in 0..write_count {
                let key = (t * w) as u8;
                assert!(bs.exists(&[key][..].into()).unwrap());
                let val = bs.get(&[key][..].into()).unwrap().unwrap();
                assert_eq!(vec![42], val);
            }
        }
    }

    #[test]
    fn test_block_at_slot() {
        let db = Arc::new(MemoryDB::open());
        let bs = Arc::new(BeaconBlockStore::new(db.clone()));
        let mut rng = XorShiftRng::from_seed([42; 16]);

        // Specify test block parameters.
        let hashes = [
            Hash256::from(&[0; 32][..]),
            Hash256::from(&[1; 32][..]),
            Hash256::from(&[2; 32][..]),
            Hash256::from(&[3; 32][..]),
            Hash256::from(&[4; 32][..]),
        ];
        let parent_hashes = [
            Hash256::from(&[255; 32][..]), // Genesis block.
            Hash256::from(&[0; 32][..]),
            Hash256::from(&[1; 32][..]),
            Hash256::from(&[2; 32][..]),
            Hash256::from(&[3; 32][..]),
        ];
        let slots = [0, 1, 3, 4, 5];

        // Generate a vec of random blocks and store them in the DB.
        let block_count = 5;
        let mut blocks: Vec<BeaconBlock> = Vec::with_capacity(5);
        for i in 0..block_count {
            let mut block = BeaconBlock::random_for_test(&mut rng);

            block.parent_root = parent_hashes[i];
            block.slot = slots[i];

            let ssz = ssz_encode(&block);
            db.put(DB_COLUMN, &hashes[i], &ssz).unwrap();

            blocks.push(block);
        }

        // Test that certain slots can be reached from certain hashes.
        let test_cases = vec![(4, 4), (4, 3), (4, 2), (4, 1), (4, 0)];
        for (hashes_index, slot_index) in test_cases {
            let (matched_block_hash, reader) = bs
                .block_at_slot(&hashes[hashes_index], slots[slot_index])
                .unwrap()
                .unwrap();
            assert_eq!(matched_block_hash, hashes[slot_index]);
            assert_eq!(reader.slot(), slots[slot_index]);
        }

        let ssz = bs.block_at_slot(&hashes[4], 2).unwrap();
        assert_eq!(ssz, None);

        let ssz = bs.block_at_slot(&hashes[4], 6).unwrap();
        assert_eq!(ssz, None);

        let ssz = bs.block_at_slot(&Hash256::from("unknown".as_bytes()), 2);
        assert_eq!(ssz, Err(BeaconBlockAtSlotError::UnknownBeaconBlock));
    }
}
<|endoftext|>


<commit_before>use crate::support::{is_nightly, paths, project, rustc_host, Execs, Project};

fn cargo_build_std(project: &Project, cmd: &str, crates: &str) -> Execs {
    let unstable = if crates.is_empty() {
        "-Zbuild-std".to_string()
    } else {
        format!("-Zbuild-std={}", crates)
    };
    let target = paths::root().join("target");
    let mut execs = project.cargo(cmd);
    if !cmd.contains("--target") {
        execs.arg("--target").arg(rustc_host());
    }
    execs
        .arg(unstable)
        .arg("-Zno-index-update")
        .env_remove("CARGO_HOME")
        .env_remove("HOME")
        .env("CARGO_TARGET_DIR", target.as_os_str())
        .masquerade_as_nightly_cargo();
    execs
}

#[cargo_test]
fn std_lib() {
    if !is_nightly() {
        // -Zbuild-std is nightly
        // -Zno-index-update is nightly
        // We don't want these tests to run on rust-lang/rust.
        return;
    }
    simple_lib_std();
    simple_bin_std();
    lib_nostd();
    check_core();
    cross_custom();
    hashbrown();
    libc();
    test();
    target_proc_macro();
    bench();
    doc();
    check_std();
    doctest();
}

fn simple_lib_std() {
    let p = project().file("src/lib.rs", "").build();
    cargo_build_std(&p, "build -v", "")
        .with_stderr_contains("[RUNNING] `rustc [..]--crate-name std [..]")
        .run();
    // Check freshness.
    p.change_file("src/lib.rs", " ");
    cargo_build_std(&p, "build -v", "std")
        .with_stderr_contains("[FRESH] std[..]")
        .run();
}

fn simple_bin_std() {
    let p = project().file("src/main.rs", "fn main() {}").build();
    cargo_build_std(&p, "run -v", "std").run();
}

fn lib_nostd() {
    let p = project()
        .file(
            "src/lib.rs",
            r#"
            #![no_std]
            pub fn foo() {
                assert_eq!(core::u8::MIN, 0);
            }
            "#,
        )
        .build();
    cargo_build_std(&p, "build -v --lib", "core")
        .with_stderr_does_not_contain("[..]libstd[..]")
        .run();
}

fn check_core() {
    let p = project()
        .file("src/lib.rs", "#![no_std] fn unused_fn() {}")
        .build();

    cargo_build_std(&p, "check -v", "core")
        .with_stderr_contains("[WARNING] [..]unused_fn[..]`")
        .run();
}

fn cross_custom() {
    let p = project()
        .file("src/lib.rs", "#![no_std] pub fn f() {}")
        .file(
            "custom-target.json",
            r#"
            {
                "llvm-target": "x86_64-unknown-none-gnu",
                "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
                "arch": "x86_64",
                "target-endian": "little",
                "target-pointer-width": "64",
                "target-c-int-width": "32",
                "os": "none",
                "linker-flavor": "ld.lld"
            }
            "#,
        )
        .build();

    cargo_build_std(&p, "build --target custom-target.json -v", "core").run();
}

fn hashbrown() {
    let p = project()
        .file(
            "src/lib.rs",
            r#"
            pub fn f() -> hashbrown::HashMap<i32, i32> {
                hashbrown::HashMap::new()
            }
            "#,
        )
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.1.0"
            edition = "2018"

            [dependencies]
            hashbrown = "=0.4.0"
            "#,
        )
        .build();

    cargo_build_std(&p, "build -v", "std").run();
}

fn libc() {
    let p = project()
        .file(
            "src/lib.rs",
            r#"
            pub fn f() -> ! {
                unsafe { libc::exit(123); }
            }
            "#,
        )
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.1.0"
            edition = "2018"

            [dependencies]
            libc = "=0.2.54"
            "#,
        )
        .build();

    cargo_build_std(&p, "build -v", "std").run();
}

fn test() {
    let p = project()
        .file(
            "src/lib.rs",
            r#"
            #[cfg(test)]
            mod tests {
                #[test]
                fn it_works() {
                    assert_eq!(2 + 2, 4);
                }
            }
            "#,
        )
        .build();

    cargo_build_std(&p, "test -v", "std")
        .with_stdout_contains("test tests::it_works ... ok")
        .run();
}

fn target_proc_macro() {
    let p = project()
        .file(
            "src/lib.rs",
            r#"
            extern crate proc_macro;
            pub fn f() {
                let _ts = proc_macro::TokenStream::new();
            }
            "#,
        )
        .build();

    cargo_build_std(&p, "build -v", "std,proc_macro").run();
}

fn bench() {
    let p = project()
        .file(
            "src/lib.rs",
            r#"
            #![feature(test)]
            extern crate test;

            #[bench]
            fn b1(b: &mut test::Bencher) {
                b.iter(|| ())
            }
            "#,
        )
        .build();

    cargo_build_std(&p, "bench -v", "std").run();
}

fn doc() {
    let p = project()
        .file(
            "src/lib.rs",
            r#"
            /// Doc
            pub fn f() -> Result<(), ()> {Ok(())}
            "#,
        )
        .build();

    cargo_build_std(&p, "doc -v", "std").run();
}

fn check_std() {
    let p = project()
        .file(
            "src/lib.rs",
            "
                extern crate core;
                extern crate alloc;
                extern crate proc_macro;
                pub fn f() {}
            ",
        )
        .file("src/main.rs", "fn main() {}")
        .file(
            "tests/t1.rs",
            r#"
            #[test]
            fn t1() {
                assert_eq!(1, 2);
            }
            "#,
        )
        .build();

    cargo_build_std(&p, "check -v --all-targets", "std").run();
    cargo_build_std(&p, "check -v --all-targets --profile=test", "std").run();
}

fn doctest() {
    let p = project()
        .file(
            "src/lib.rs",
            r#"
            /// Doc
            /// ```
            /// assert_eq!(1, 1);
            /// ```
            pub fn f() {}
            "#,
        )
        .build();

    cargo_build_std(&p, "test --doc -v", "std").run();
}
<commit_msg>Add a test for -Zbuild-std with custom test frameworks<commit_after>use crate::support::{is_nightly, paths, project, rustc_host, Execs, Project};

fn cargo_build_std(project: &Project, cmd: &str, crates: &str) -> Execs {
    let unstable = if crates.is_empty() {
        "-Zbuild-std".to_string()
    } else {
        format!("-Zbuild-std={}", crates)
    };
    let target = paths::root().join("target");
    let mut execs = project.cargo(cmd);
    if !cmd.contains("--target") {
        execs.arg("--target").arg(rustc_host());
    }
    execs
        .arg(unstable)
        .arg("-Zno-index-update")
        .env_remove("CARGO_HOME")
        .env_remove("HOME")
        .env("CARGO_TARGET_DIR", target.as_os_str())
        .masquerade_as_nightly_cargo();
    execs
}

#[cargo_test]
fn std_lib() {
    if !is_nightly() {
        // -Zbuild-std is nightly
        // -Zno-index-update is nightly
        // We don't want these tests to run on rust-lang/rust.
        return;
    }
    simple_lib_std();
    simple_bin_std();
    lib_nostd();
    check_core();
    cross_custom();
    hashbrown();
    libc();
    test();
    custom_test_framework();
    target_proc_macro();
    bench();
    doc();
    check_std();
    doctest();
}

fn simple_lib_std() {
    let p = project().file("src/lib.rs", "").build();
    cargo_build_std(&p, "build -v", "")
        .with_stderr_contains("[RUNNING] `rustc [..]--crate-name std [..]")
        .run();
    // Check freshness.
    p.change_file("src/lib.rs", " ");
    cargo_build_std(&p, "build -v", "std")
        .with_stderr_contains("[FRESH] std[..]")
        .run();
}

fn simple_bin_std() {
    let p = project().file("src/main.rs", "fn main() {}").build();
    cargo_build_std(&p, "run -v", "std").run();
}

fn lib_nostd() {
    let p = project()
        .file(
            "src/lib.rs",
            r#"
            #![no_std]
            pub fn foo() {
                assert_eq!(core::u8::MIN, 0);
            }
            "#,
        )
        .build();
    cargo_build_std(&p, "build -v --lib", "core")
        .with_stderr_does_not_contain("[..]libstd[..]")
        .run();
}

fn check_core() {
    let p = project()
        .file("src/lib.rs", "#![no_std] fn unused_fn() {}")
        .build();

    cargo_build_std(&p, "check -v", "core")
        .with_stderr_contains("[WARNING] [..]unused_fn[..]`")
        .run();
}

fn cross_custom() {
    let p = project()
        .file("src/lib.rs", "#![no_std] pub fn f() {}")
        .file(
            "custom-target.json",
            r#"
            {
                "llvm-target": "x86_64-unknown-none-gnu",
                "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
                "arch": "x86_64",
                "target-endian": "little",
                "target-pointer-width": "64",
                "target-c-int-width": "32",
                "os": "none",
                "linker-flavor": "ld.lld"
            }
            "#,
        )
        .build();

    cargo_build_std(&p, "build --target custom-target.json -v", "core").run();
}

fn hashbrown() {
    let p = project()
        .file(
            "src/lib.rs",
            r#"
            pub fn f() -> hashbrown::HashMap<i32, i32> {
                hashbrown::HashMap::new()
            }
            "#,
        )
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.1.0"
            edition = "2018"

            [dependencies]
            hashbrown = "=0.4.0"
            "#,
        )
        .build();

    cargo_build_std(&p, "build -v", "std").run();
}

fn libc() {
    let p = project()
        .file(
            "src/lib.rs",
            r#"
            pub fn f() -> ! {
                unsafe { libc::exit(123); }
            }
            "#,
        )
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.1.0"
            edition = "2018"

            [dependencies]
            libc = "=0.2.54"
            "#,
        )
        .build();

    cargo_build_std(&p, "build -v", "std").run();
}

fn test() {
    let p = project()
        .file(
            "src/lib.rs",
            r#"
            #[cfg(test)]
            mod tests {
                #[test]
                fn it_works() {
                    assert_eq!(2 + 2, 4);
                }
            }
            "#,
        )
        .build();

    cargo_build_std(&p, "test -v", "std")
        .with_stdout_contains("test tests::it_works ... ok")
        .run();
}

fn custom_test_framework() {
    let p = project()
        .file(
            "src/lib.rs",
            r#"
            #![no_std]
            #![cfg_attr(test, no_main)]
            #![feature(custom_test_frameworks)]
            #![test_runner(crate::test_runner)]

            pub fn test_runner(_tests: &[&dyn Fn()]) {}

            #[panic_handler]
            fn panic(_info: &core::panic::PanicInfo) -> ! {
                loop {}
            }
            "#,
        )
        .file(
            "target.json",
            r#"
            {
                "llvm-target": "x86_64-unknown-none-gnu",
                "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
                "arch": "x86_64",
                "target-endian": "little",
                "target-pointer-width": "64",
                "target-c-int-width": "32",
                "os": "none",
                "linker-flavor": "ld.lld",
                "linker": "rust-lld",
                "executables": true,
                "panic-strategy": "abort"
            }
            "#,
        )
        .build();

    cargo_build_std(&p, "test --target target.json --no-run -v", "core").run();
}

fn target_proc_macro() {
    let p = project()
        .file(
            "src/lib.rs",
            r#"
            extern crate proc_macro;
            pub fn f() {
                let _ts = proc_macro::TokenStream::new();
            }
            "#,
        )
        .build();

    cargo_build_std(&p, "build -v", "std,proc_macro").run();
}

fn bench() {
    let p = project()
        .file(
            "src/lib.rs",
            r#"
            #![feature(test)]
            extern crate test;

            #[bench]
            fn b1(b: &mut test::Bencher) {
                b.iter(|| ())
            }
            "#,
        )
        .build();

    cargo_build_std(&p, "bench -v", "std").run();
}

fn doc() {
    let p = project()
        .file(
            "src/lib.rs",
            r#"
            /// Doc
            pub fn f() -> Result<(), ()> {Ok(())}
            "#,
        )
        .build();

    cargo_build_std(&p, "doc -v", "std").run();
}

fn check_std() {
    let p = project()
        .file(
            "src/lib.rs",
            "
                extern crate core;
                extern crate alloc;
                extern crate proc_macro;
                pub fn f() {}
            ",
        )
        .file("src/main.rs", "fn main() {}")
        .file(
            "tests/t1.rs",
            r#"
            #[test]
            fn t1() {
                assert_eq!(1, 2);
            }
            "#,
        )
        .build();

    cargo_build_std(&p, "check -v --all-targets", "std").run();
    cargo_build_std(&p, "check -v --all-targets --profile=test", "std").run();
}

fn doctest() {
    let p = project()
        .file(
            "src/lib.rs",
            r#"
            /// Doc
            /// ```
            /// assert_eq!(1, 1);
            /// ```
            pub fn f() {}
            "#,
        )
        .build();

    cargo_build_std(&p, "test --doc -v", "std").run();
}
<|endoftext|>


<commit_before>// Copyright 2016 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::cell;
use std::rc::Rc;

use super::{Overlap, specializes};

use middle::cstore::CrateStore;
use middle::def_id::DefId;
use middle::infer;
use middle::traits;
use middle::ty::{self, ImplOrTraitItem, TraitDef, TypeFoldable};
use syntax::ast::Name;
use util::nodemap::DefIdMap;

/// A per-trait graph of impls in specialization order. At the moment, this
/// graph forms a tree rooted with the trait itself, with all other nodes
/// representing impls, and parent-child relationships representing
/// specializations.
///
/// The graph provides two key services:
///
/// - Construction, which implicitly checks for overlapping impls (i.e., impls
///   that overlap but where neither specializes the other -- an artifact of the
///   simple "chain" rule.
///
/// - Parent extraction. In particular, the graph can give you the *immediate*
///   parents of a given specializing impl, which is needed for extracting
///   default items amongst other thigns. In the simple "chain" rule, every impl
///   has at most one parent.
pub struct Graph {
    // all impls have a parent; the "root" impls have as their parent the def_id
    // of the trait
    parent: DefIdMap<DefId>,

    // the "root" impls are found by looking up the trait's def_id.
    children: DefIdMap<Vec<DefId>>,
}

impl Graph {
    pub fn new() -> Graph {
        Graph {
            parent: Default::default(),
            children: Default::default(),
        }
    }

    /// Insert a local impl into the specialization graph. If an existing impl
    /// conflicts with it (has overlap, but neither specializes the other),
    /// information about the area of overlap is returned in the `Err`.
    pub fn insert<'a, 'tcx>(&mut self,
                            tcx: &'a ty::ctxt<'tcx>,
                            impl_def_id: DefId)
                            -> Result<(), Overlap<'a, 'tcx>> {
        assert!(impl_def_id.is_local());

        let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
        let trait_def_id = trait_ref.def_id;

        // if the reference itself contains an earlier error (e.g., due to a
        // resolution failure), then we just insert the impl at the top level of
        // the graph and claim that there's no overlap (in order to supress
        // bogus errors).
        if trait_ref.references_error() {
            debug!("Inserting dummy node for erroneous TraitRef {:?}, \
                    impl_def_id={:?}, trait_def_id={:?}",
                   trait_ref, impl_def_id, trait_def_id);

            self.parent.insert(impl_def_id, trait_def_id);
            self.children.entry(trait_def_id).or_insert(vec![]).push(impl_def_id);
            return Ok(());
        }

        let mut parent = trait_def_id;

        // Ugly hack around borrowck limitations. Assigned only in the case
        // where we bump downward an existing node in the graph.
        let child_to_insert;

        'descend: loop {
            let mut possible_siblings = self.children.entry(parent).or_insert(vec![]);

            for slot in possible_siblings.iter_mut() {
                let possible_sibling = *slot;

                let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None);
                let overlap = traits::overlapping_impls(&infcx, possible_sibling, impl_def_id);

                if let Some(trait_ref) = overlap {
                    let le = specializes(tcx, impl_def_id, possible_sibling);
                    let ge = specializes(tcx, possible_sibling, impl_def_id);

                    if le && !ge {
                        // the impl specializes possible_sibling
                        parent = possible_sibling;
                        continue 'descend;
                    } else if ge && !le {
                        // possible_sibling specializes the impl
                        *slot = impl_def_id;
                        self.parent.insert(impl_def_id, parent);
                        self.parent.insert(possible_sibling, impl_def_id);
                        // we have to defer the insertion, because we can't
                        // relinquish the borrow of `self.children`
                        child_to_insert = possible_sibling;
                        break 'descend;
                    } else {
                        // overlap, but no specialization; error out
                        return Err(Overlap {
                            with_impl: possible_sibling,
                            on_trait_ref: trait_ref,
                            in_context: infcx,
                        });
                    }
                }
            }

            // no overlap with any potential siblings, so add as a new sibling
            self.parent.insert(impl_def_id, parent);
            possible_siblings.push(impl_def_id);
            return Ok(());
        }

        self.children.insert(impl_def_id, vec![child_to_insert]);
        Ok(())
    }

    /// Insert cached metadata mapping from a child impl back to its parent.
    pub fn record_impl_from_cstore(&mut self, parent: DefId, child: DefId) {
        if self.parent.insert(child, parent).is_some() {
            panic!("When recording an impl from the crate store, information about its parent \
                    was already present.");
        }

        self.children.entry(parent).or_insert(vec![]).push(child);
    }

    /// The parent of a given impl, which is the def id of the trait when the
    /// impl is a "specialization root".
    pub fn parent(&self, child: DefId) -> DefId {
        *self.parent.get(&child).unwrap()
    }
}

#[derive(Debug, Copy, Clone)]
/// A node in the specialization graph is either an impl or a trait
/// definition; either can serve as a source of item definitions.
/// There is always exactly one trait definition node: the root.
pub enum Node {
    Impl(DefId),
    Trait(DefId),
}

impl Node {
    pub fn is_from_trait(&self) -> bool {
        match *self {
            Node::Trait(..) => true,
            _ => false,
        }
    }

    /// Iterate over the items defined directly by the given (impl or trait) node.
    pub fn items<'a, 'tcx>(&self, tcx: &'a ty::ctxt<'tcx>) -> NodeItems<'a, 'tcx> {
        match *self {
            Node::Impl(impl_def_id) => {
                NodeItems::Impl {
                    tcx: tcx,
                    items: cell::Ref::map(tcx.impl_items.borrow(),
                                          |impl_items| &impl_items[&impl_def_id]),
                    idx: 0,
                }
            }
            Node::Trait(trait_def_id) => {
                NodeItems::Trait {
                    items: tcx.trait_items(trait_def_id).clone(),
                    idx: 0,
                }
            }
        }
    }

    pub fn def_id(&self) -> DefId {
        match *self {
            Node::Impl(did) => did,
            Node::Trait(did) => did,
        }
    }
}

/// An iterator over the items defined within a trait or impl.
pub enum NodeItems<'a, 'tcx: 'a> {
    Impl {
        tcx: &'a ty::ctxt<'tcx>,
        items: cell::Ref<'a, Vec<ty::ImplOrTraitItemId>>,
        idx: usize,
    },
    Trait {
        items: Rc<Vec<ImplOrTraitItem<'tcx>>>,
        idx: usize,
    },
}

impl<'a, 'tcx> Iterator for NodeItems<'a, 'tcx> {
    type Item = ImplOrTraitItem<'tcx>;
    fn next(&mut self) -> Option<ImplOrTraitItem<'tcx>> {
        match *self {
            NodeItems::Impl { tcx, ref items, ref mut idx } => {
                let items_table = tcx.impl_or_trait_items.borrow();
                if *idx < items.len() {
                    let item_def_id = items[*idx].def_id();
                    let item = items_table[&item_def_id].clone();
                    *idx += 1;
                    Some(item)
                } else {
                    None
                }
            }
            NodeItems::Trait { ref items, ref mut idx } => {
                if *idx < items.len() {
                    let item = items[*idx].clone();
                    *idx += 1;
                    Some(item)
                } else {
                    None
                }
            }
        }
    }
}

pub struct Ancestors<'a, 'tcx: 'a> {
    trait_def: &'a TraitDef<'tcx>,
    current_source: Option<Node>,
}

impl<'a, 'tcx> Iterator for Ancestors<'a, 'tcx> {
    type Item = Node;
    fn next(&mut self) -> Option<Node> {
        let cur = self.current_source.take();
        if let Some(Node::Impl(cur_impl)) = cur {
            let parent = self.trait_def.specialization_graph.borrow().parent(cur_impl);
            if parent == self.trait_def.def_id() {
                self.current_source = Some(Node::Trait(parent));
            } else {
                self.current_source = Some(Node::Impl(parent));
            }
        }
        cur
    }
}

pub struct NodeItem<T> {
    pub node: Node,
    pub item: T,
}

impl<T> NodeItem<T> {
    pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> NodeItem<U> {
        NodeItem {
            node: self.node,
            item: f(self.item),
        }
    }
}

pub struct TypeDefs<'a, 'tcx: 'a> {
    // generally only invoked once or twice, so the box doesn't hurt
    iter: Box<Iterator<Item = NodeItem<Rc<ty::AssociatedType<'tcx>>>> + 'a>,
}

impl<'a, 'tcx> Iterator for TypeDefs<'a, 'tcx> {
    type Item = NodeItem<Rc<ty::AssociatedType<'tcx>>>;
    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next()
    }
}

pub struct FnDefs<'a, 'tcx: 'a> {
    // generally only invoked once or twice, so the box doesn't hurt
    iter: Box<Iterator<Item = NodeItem<Rc<ty::Method<'tcx>>>> + 'a>,
}

impl<'a, 'tcx> Iterator for FnDefs<'a, 'tcx> {
    type Item = NodeItem<Rc<ty::Method<'tcx>>>;
    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next()
    }
}

pub struct ConstDefs<'a, 'tcx: 'a> {
    // generally only invoked once or twice, so the box doesn't hurt
    iter: Box<Iterator<Item = NodeItem<Rc<ty::AssociatedConst<'tcx>>>> + 'a>,
}

impl<'a, 'tcx> Iterator for ConstDefs<'a, 'tcx> {
    type Item = NodeItem<Rc<ty::AssociatedConst<'tcx>>>;
    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next()
    }
}

impl<'a, 'tcx> Ancestors<'a, 'tcx> {
    /// Seach the items from the given ancestors, returning each type definition
    /// with the given name.
    pub fn type_defs(self, tcx: &'a ty::ctxt<'tcx>, name: Name) -> TypeDefs<'a, 'tcx> {
        let iter = self.flat_map(move |node| {
            node.items(tcx)
                .filter_map(move |item| {
                    if let ty::TypeTraitItem(assoc_ty) = item {
                        if assoc_ty.name == name {
                            return Some(NodeItem {
                                node: node,
                                item: assoc_ty,
                            });
                        }
                    }
                    None
                })

        });
        TypeDefs { iter: Box::new(iter) }
    }

    /// Seach the items from the given ancestors, returning each fn definition
    /// with the given name.
    pub fn fn_defs(self, tcx: &'a ty::ctxt<'tcx>, name: Name) -> FnDefs<'a, 'tcx> {
        let iter = self.flat_map(move |node| {
            node.items(tcx)
                .filter_map(move |item| {
                    if let ty::MethodTraitItem(method) = item {
                        if method.name == name {
                            return Some(NodeItem {
                                node: node,
                                item: method,
                            });
                        }
                    }
                    None
                })

        });
        FnDefs { iter: Box::new(iter) }
    }

    /// Seach the items from the given ancestors, returning each const
    /// definition with the given name.
    pub fn const_defs(self, tcx: &'a ty::ctxt<'tcx>, name: Name) -> ConstDefs<'a, 'tcx> {
        let iter = self.flat_map(move |node| {
            node.items(tcx)
                .filter_map(move |item| {
                    if let ty::ConstTraitItem(konst) = item {
                        if konst.name == name {
                            return Some(NodeItem {
                                node: node,
                                item: konst,
                            });
                        }
                    }
                    None
                })

        });
        ConstDefs { iter: Box::new(iter) }
    }
}

/// Walk up the specialization ancestors of a given impl, starting with that
/// impl itself.
pub fn ancestors<'a, 'tcx>(trait_def: &'a TraitDef<'tcx>,
                           start_from_impl: DefId)
                           -> Ancestors<'a, 'tcx> {
    Ancestors {
        trait_def: trait_def,
        current_source: Some(Node::Impl(start_from_impl)),
    }
}
<commit_msg>Add some debugging output for specialization graph assembly<commit_after>// Copyright 2016 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::cell;
use std::rc::Rc;

use super::{Overlap, specializes};

use middle::cstore::CrateStore;
use middle::def_id::DefId;
use middle::infer;
use middle::traits;
use middle::ty::{self, ImplOrTraitItem, TraitDef, TypeFoldable};
use syntax::ast::Name;
use util::nodemap::DefIdMap;

/// A per-trait graph of impls in specialization order. At the moment, this
/// graph forms a tree rooted with the trait itself, with all other nodes
/// representing impls, and parent-child relationships representing
/// specializations.
///
/// The graph provides two key services:
///
/// - Construction, which implicitly checks for overlapping impls (i.e., impls
///   that overlap but where neither specializes the other -- an artifact of the
///   simple "chain" rule.
///
/// - Parent extraction. In particular, the graph can give you the *immediate*
///   parents of a given specializing impl, which is needed for extracting
///   default items amongst other thigns. In the simple "chain" rule, every impl
///   has at most one parent.
pub struct Graph {
    // all impls have a parent; the "root" impls have as their parent the def_id
    // of the trait
    parent: DefIdMap<DefId>,

    // the "root" impls are found by looking up the trait's def_id.
    children: DefIdMap<Vec<DefId>>,
}

impl Graph {
    pub fn new() -> Graph {
        Graph {
            parent: Default::default(),
            children: Default::default(),
        }
    }

    /// Insert a local impl into the specialization graph. If an existing impl
    /// conflicts with it (has overlap, but neither specializes the other),
    /// information about the area of overlap is returned in the `Err`.
    pub fn insert<'a, 'tcx>(&mut self,
                            tcx: &'a ty::ctxt<'tcx>,
                            impl_def_id: DefId)
                            -> Result<(), Overlap<'a, 'tcx>> {
        assert!(impl_def_id.is_local());

        let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
        let trait_def_id = trait_ref.def_id;

        debug!("inserting TraitRef {:?} into specialization graph", trait_ref);

        // if the reference itself contains an earlier error (e.g., due to a
        // resolution failure), then we just insert the impl at the top level of
        // the graph and claim that there's no overlap (in order to supress
        // bogus errors).
        if trait_ref.references_error() {
            debug!("Inserting dummy node for erroneous TraitRef {:?}, \
                    impl_def_id={:?}, trait_def_id={:?}",
                   trait_ref, impl_def_id, trait_def_id);

            self.parent.insert(impl_def_id, trait_def_id);
            self.children.entry(trait_def_id).or_insert(vec![]).push(impl_def_id);
            return Ok(());
        }

        let mut parent = trait_def_id;

        // Ugly hack around borrowck limitations. Assigned only in the case
        // where we bump downward an existing node in the graph.
        let child_to_insert;

        'descend: loop {
            let mut possible_siblings = self.children.entry(parent).or_insert(vec![]);

            for slot in possible_siblings.iter_mut() {
                let possible_sibling = *slot;

                let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None);
                let overlap = traits::overlapping_impls(&infcx, possible_sibling, impl_def_id);

                if let Some(trait_ref) = overlap {
                    let le = specializes(tcx, impl_def_id, possible_sibling);
                    let ge = specializes(tcx, possible_sibling, impl_def_id);

                    if le && !ge {
                        let parent_trait_ref = tcx.impl_trait_ref(possible_sibling).unwrap();
                        debug!("descending as child of TraitRef {:?}", parent_trait_ref);

                        // the impl specializes possible_sibling
                        parent = possible_sibling;
                        continue 'descend;
                    } else if ge && !le {
                        let child_trait_ref = tcx.impl_trait_ref(possible_sibling).unwrap();
                        debug!("placing as parent of TraitRef {:?}", child_trait_ref);

                        // possible_sibling specializes the impl
                        *slot = impl_def_id;
                        self.parent.insert(impl_def_id, parent);
                        self.parent.insert(possible_sibling, impl_def_id);
                        // we have to defer the insertion, because we can't
                        // relinquish the borrow of `self.children`
                        child_to_insert = possible_sibling;
                        break 'descend;
                    } else {
                        // overlap, but no specialization; error out
                        return Err(Overlap {
                            with_impl: possible_sibling,
                            on_trait_ref: trait_ref,
                            in_context: infcx,
                        });
                    }
                }
            }

            // no overlap with any potential siblings, so add as a new sibling
            debug!("placing as new sibling");
            self.parent.insert(impl_def_id, parent);
            possible_siblings.push(impl_def_id);
            return Ok(());
        }

        self.children.insert(impl_def_id, vec![child_to_insert]);
        Ok(())
    }

    /// Insert cached metadata mapping from a child impl back to its parent.
    pub fn record_impl_from_cstore(&mut self, parent: DefId, child: DefId) {
        if self.parent.insert(child, parent).is_some() {
            panic!("When recording an impl from the crate store, information about its parent \
                    was already present.");
        }

        self.children.entry(parent).or_insert(vec![]).push(child);
    }

    /// The parent of a given impl, which is the def id of the trait when the
    /// impl is a "specialization root".
    pub fn parent(&self, child: DefId) -> DefId {
        *self.parent.get(&child).unwrap()
    }
}

#[derive(Debug, Copy, Clone)]
/// A node in the specialization graph is either an impl or a trait
/// definition; either can serve as a source of item definitions.
/// There is always exactly one trait definition node: the root.
pub enum Node {
    Impl(DefId),
    Trait(DefId),
}

impl Node {
    pub fn is_from_trait(&self) -> bool {
        match *self {
            Node::Trait(..) => true,
            _ => false,
        }
    }

    /// Iterate over the items defined directly by the given (impl or trait) node.
    pub fn items<'a, 'tcx>(&self, tcx: &'a ty::ctxt<'tcx>) -> NodeItems<'a, 'tcx> {
        match *self {
            Node::Impl(impl_def_id) => {
                NodeItems::Impl {
                    tcx: tcx,
                    items: cell::Ref::map(tcx.impl_items.borrow(),
                                          |impl_items| &impl_items[&impl_def_id]),
                    idx: 0,
                }
            }
            Node::Trait(trait_def_id) => {
                NodeItems::Trait {
                    items: tcx.trait_items(trait_def_id).clone(),
                    idx: 0,
                }
            }
        }
    }

    pub fn def_id(&self) -> DefId {
        match *self {
            Node::Impl(did) => did,
            Node::Trait(did) => did,
        }
    }
}

/// An iterator over the items defined within a trait or impl.
pub enum NodeItems<'a, 'tcx: 'a> {
    Impl {
        tcx: &'a ty::ctxt<'tcx>,
        items: cell::Ref<'a, Vec<ty::ImplOrTraitItemId>>,
        idx: usize,
    },
    Trait {
        items: Rc<Vec<ImplOrTraitItem<'tcx>>>,
        idx: usize,
    },
}

impl<'a, 'tcx> Iterator for NodeItems<'a, 'tcx> {
    type Item = ImplOrTraitItem<'tcx>;
    fn next(&mut self) -> Option<ImplOrTraitItem<'tcx>> {
        match *self {
            NodeItems::Impl { tcx, ref items, ref mut idx } => {
                let items_table = tcx.impl_or_trait_items.borrow();
                if *idx < items.len() {
                    let item_def_id = items[*idx].def_id();
                    let item = items_table[&item_def_id].clone();
                    *idx += 1;
                    Some(item)
                } else {
                    None
                }
            }
            NodeItems::Trait { ref items, ref mut idx } => {
                if *idx < items.len() {
                    let item = items[*idx].clone();
                    *idx += 1;
                    Some(item)
                } else {
                    None
                }
            }
        }
    }
}

pub struct Ancestors<'a, 'tcx: 'a> {
    trait_def: &'a TraitDef<'tcx>,
    current_source: Option<Node>,
}

impl<'a, 'tcx> Iterator for Ancestors<'a, 'tcx> {
    type Item = Node;
    fn next(&mut self) -> Option<Node> {
        let cur = self.current_source.take();
        if let Some(Node::Impl(cur_impl)) = cur {
            let parent = self.trait_def.specialization_graph.borrow().parent(cur_impl);
            if parent == self.trait_def.def_id() {
                self.current_source = Some(Node::Trait(parent));
            } else {
                self.current_source = Some(Node::Impl(parent));
            }
        }
        cur
    }
}

pub struct NodeItem<T> {
    pub node: Node,
    pub item: T,
}

impl<T> NodeItem<T> {
    pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> NodeItem<U> {
        NodeItem {
            node: self.node,
            item: f(self.item),
        }
    }
}

pub struct TypeDefs<'a, 'tcx: 'a> {
    // generally only invoked once or twice, so the box doesn't hurt
    iter: Box<Iterator<Item = NodeItem<Rc<ty::AssociatedType<'tcx>>>> + 'a>,
}

impl<'a, 'tcx> Iterator for TypeDefs<'a, 'tcx> {
    type Item = NodeItem<Rc<ty::AssociatedType<'tcx>>>;
    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next()
    }
}

pub struct FnDefs<'a, 'tcx: 'a> {
    // generally only invoked once or twice, so the box doesn't hurt
    iter: Box<Iterator<Item = NodeItem<Rc<ty::Method<'tcx>>>> + 'a>,
}

impl<'a, 'tcx> Iterator for FnDefs<'a, 'tcx> {
    type Item = NodeItem<Rc<ty::Method<'tcx>>>;
    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next()
    }
}

pub struct ConstDefs<'a, 'tcx: 'a> {
    // generally only invoked once or twice, so the box doesn't hurt
    iter: Box<Iterator<Item = NodeItem<Rc<ty::AssociatedConst<'tcx>>>> + 'a>,
}

impl<'a, 'tcx> Iterator for ConstDefs<'a, 'tcx> {
    type Item = NodeItem<Rc<ty::AssociatedConst<'tcx>>>;
    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next()
    }
}

impl<'a, 'tcx> Ancestors<'a, 'tcx> {
    /// Seach the items from the given ancestors, returning each type definition
    /// with the given name.
    pub fn type_defs(self, tcx: &'a ty::ctxt<'tcx>, name: Name) -> TypeDefs<'a, 'tcx> {
        let iter = self.flat_map(move |node| {
            node.items(tcx)
                .filter_map(move |item| {
                    if let ty::TypeTraitItem(assoc_ty) = item {
                        if assoc_ty.name == name {
                            return Some(NodeItem {
                                node: node,
                                item: assoc_ty,
                            });
                        }
                    }
                    None
                })

        });
        TypeDefs { iter: Box::new(iter) }
    }

    /// Seach the items from the given ancestors, returning each fn definition
    /// with the given name.
    pub fn fn_defs(self, tcx: &'a ty::ctxt<'tcx>, name: Name) -> FnDefs<'a, 'tcx> {
        let iter = self.flat_map(move |node| {
            node.items(tcx)
                .filter_map(move |item| {
                    if let ty::MethodTraitItem(method) = item {
                        if method.name == name {
                            return Some(NodeItem {
                                node: node,
                                item: method,
                            });
                        }
                    }
                    None
                })

        });
        FnDefs { iter: Box::new(iter) }
    }

    /// Seach the items from the given ancestors, returning each const
    /// definition with the given name.
    pub fn const_defs(self, tcx: &'a ty::ctxt<'tcx>, name: Name) -> ConstDefs<'a, 'tcx> {
        let iter = self.flat_map(move |node| {
            node.items(tcx)
                .filter_map(move |item| {
                    if let ty::ConstTraitItem(konst) = item {
                        if konst.name == name {
                            return Some(NodeItem {
                                node: node,
                                item: konst,
                            });
                        }
                    }
                    None
                })

        });
        ConstDefs { iter: Box::new(iter) }
    }
}

/// Walk up the specialization ancestors of a given impl, starting with that
/// impl itself.
pub fn ancestors<'a, 'tcx>(trait_def: &'a TraitDef<'tcx>,
                           start_from_impl: DefId)
                           -> Ancestors<'a, 'tcx> {
    Ancestors {
        trait_def: trait_def,
        current_source: Some(Node::Impl(start_from_impl)),
    }
}
<|endoftext|>