<commit_before>
//! Management of entities, components, systems, and managers

use std::cell::RefCell;
use std::collections::HashMap;
use std::mem;

use {Component, ComponentId};
use Entity;
use {Manager, MutableManager};
use Phantom;
use {Passive, System};
use component::ComponentList;
use entity::EntityManager;

pub struct World
{
    entities: RefCell<EntityManager>,
    components: ComponentManager,
    systems: RefCell<SystemManager>,
    mut_managers: Vec<RefCell<Box<MutableManager>>>,
    managers: Vec<Box<Manager>>,
    locked: bool,
}

pub struct Components<'a>
{
    inner: &'a mut ComponentManager,
}

struct ComponentManager
{
    components: HashMap<ComponentId, ComponentList>,
}

struct SystemManager
{
    systems: Vec<Box<System>>,
    passive: HashMap<&'static str, Box<Passive>>,
}

impl World
{
    pub fn new() -> World
    {
        World
        {
            entities: RefCell::new(EntityManager::new()),
            components: ComponentManager::new(),
            systems: RefCell::new(SystemManager::new()),
            mut_managers: Vec::new(),
            managers: Vec::new(),
            locked: false,
        }
    }

    /// Lock down the managers and systems, and components of a world.
    ///
    /// This must be called before entities can be created and modified.
    /// After it is called, no systems/managers/components may be registered.
    pub fn finalise(&mut self)
    {
        if self.locked
        {
            fail!("World is already finalised")
        }
        self.locked = true;
    }

    /// Returns if an entity has been activated.
    #[inline]
    pub fn is_active(&self, entity: &Entity) -> bool
    {
        self.entities.borrow().is_activated(entity)
    }

    /// Registers a mutable manager.
    ///
    /// # Failure
    ///
    /// If the world has been finalised
    #[experimental]
    pub fn register_manager_mut(&mut self, manager: Box<MutableManager>)
    {
        if self.locked
        {
            fail!("World is locked. Managers may not be registered")
        }
        self.mut_managers.push(RefCell::new(manager));
    }

    /// Registers an immutable manager.
    ///
    /// # Failure
    ///
    /// If the world has been finalised
    #[experimental]
    pub fn register_manager(&mut self, manager: Box<Manager>)
    {
        if self.locked
        {
            fail!("World is locked. Managers may not be registered")
        }
        self.managers.push(manager);
    }

    /// Registers a component.
    ///
    /// # Failure
    ///
    /// If the world has been finalised
    pub fn register_component<T: Component>(&mut self)
    {
        if self.locked
        {
            fail!("World is locked. Components may not be registered")
        }
        self.components.register(ComponentList::new(Phantom::<T>));
    }

    /// Registers a system.
    ///
    /// # Failure
    ///
    /// If the world has been finalised
    pub fn register_system(&mut self, sys: Box<System>)
    {
        if self.locked
        {
            fail!("World is locked. Systems may not be registered")
        }
        self.systems.borrow_mut().register(sys);
    }

    /// Registers a passive system.
    ///
    /// # Failure
    ///
    /// If the world has been finalised
    pub fn register_passive(&mut self, key: &'static str, sys: Box<Passive>)
    {
        if self.locked
        {
            fail!("World is locked. Systems may not be registered")
        }
        self.systems.borrow_mut().register_passive(key, sys);
    }

    /// Updates the world by processing all systems.
    ///
    /// # Failure
    ///
    /// If the world has not been finalised
    pub fn update(&mut self)
    {
        if !self.locked
        {
            fail!("World must be locked before updating")
        }
        self.systems.borrow_mut().update(self, self.components());
    }

    /// Updates the passive system corresponding to `key`
    ///
    /// # Failure
    ///
    /// If the world has not been finalised
    pub fn update_passive(&mut self, key: &'static str)
    {
        if !self.locked
        {
            fail!("World must be locked before updating")
        }
        self.systems.borrow_mut().update_passive(key, self);
    }

    fn components(&self) -> Components
    {
        Components
        {
            inner: unsafe {
                mem::transmute(&self.components)
            },
        }
    }

    /// Creates an entity
    ///
    /// # Failure
    ///
    /// If the world has not been finalised
    pub fn create_entity(&mut self) -> Entity
    {
        if !self.locked
        {
            fail!("World must be locked before creating entities")
        }
        let ret = self.entities.borrow_mut().create_entity();
        for ref manager in self.mut_managers.iter()
        {
            manager.borrow_mut().added(&ret, self);
        }
        for ref manager in self.managers.iter()
        {
            manager.added(&ret, self);
        }
        ret
    }

    /// Activates an entity
    ///
    /// Once activated, components cannot be added to the entity,
    /// and systems will be able to process it.
    ///
    /// # Failure
    ///
    /// If the entity is invalid or already activated
    pub fn activate_entity(&mut self, entity: &Entity)
    {
        if self.is_active(entity)
        {
            fail!("Entity is already activated")
        }
        if !self.entities.borrow().is_valid(entity)
        {
            fail!("Cannot activate invalid entity")
        }
        self.entities.borrow_mut().activate_entity(entity);
        self.systems.borrow_mut().activated(entity, self);
        for ref manager in self.mut_managers.iter()
        {
            manager.borrow_mut().activated(entity, self);
        }
        for ref manager in self.managers.iter()
        {
            manager.activated(entity, self);
        }
    }

    /// Deactivates an entity
    ///
    /// It will then be ignored by all systems.
    /// Components can only be added/removed from an entity while deactivated.
    ///
    /// # Failure
    ///
    /// If the entity is not already activated
    pub fn deactivate_entity(&mut self, entity: &Entity)
    {
        if !self.is_active(entity)
        {
            fail!("Cannot deactivate unactivated entity")
        }
        self.entities.borrow_mut().deactivate_entity(entity);
        self.systems.borrow_mut().deactivated(entity, self);
        for ref manager in self.mut_managers.iter()
        {
            manager.borrow_mut().deactivated(entity, self);
        }
        for ref manager in self.managers.iter()
        {
            manager.deactivated(entity, self);
        }
    }

    /// Deletes an entity, deactivating it if it is activated
    ///
    /// # Failure
    ///
    /// If an entity is invalid
    pub fn delete_entity(&mut self, entity: &Entity)
    {
        if !self.entities.borrow().is_valid(entity)
        {
            fail!("Cannot delete invalid entity")
        }
        if self.is_active(entity)
        {
            self.deactivate_entity(entity);
        }
        self.entities.borrow_mut().delete_entity(entity);
        self.components.delete_entity(entity);
        for ref manager in self.mut_managers.iter()
        {
            manager.borrow_mut().removed(entity, self);
        }
        for ref manager in self.managers.iter()
        {
            manager.removed(entity, self);
        }
    }

    /// Add a component to an entity
    ///
    /// Returns false if the component could not be added (entity invalid or activated).
    pub fn add_component<T: Component>(&mut self, entity: &Entity, component: T) -> bool
    {
        self.entities.borrow().is_valid(entity)
        && !self.is_active(entity)
        && self.components.add::<T>(entity, component)
    }

    /// Removes a component from an entity.
    ///
    /// Returns false if the component could not be removed (entity invalid or activated).
    pub fn remove_component<T: Component>(&mut self, entity: &Entity) -> bool
    {
        self.entities.borrow().is_valid(entity)
        && !self.is_active(entity)
        && self.components.remove::<T>(entity)
    }

    /// Set the value of a component for an entity
    ///
    /// Returns false if the entity does not contain that component.
    pub fn set_component<T: Component>(&mut self, entity: &Entity, component: T) -> bool
    {
        self.entities.borrow().is_valid(entity)
        && self.components.set::<T>(entity, component)
    }

    /// Returns the value of a component for an entity (or None)
    pub fn get_component<T: Component>(&self, entity: &Entity) -> Option<T>
    {
        if self.entities.borrow().is_valid(entity)
        {
            self.components.get::<T>(entity)
        }
        else
        {
            None
        }
    }

    /// Returns if an entity contains a component.
    pub fn has_component(&self, entity: &Entity, id: ComponentId) -> bool
    {
        self.components.has(entity, id)
    }

    /// Returns a reference to an entity's component. (or None)
    pub fn borrow_component<T: Component>(&self, entity: &Entity) -> Option<&T>
    {
        if self.is_active(entity)
        {
            self.components.borrow::<T>(entity)
        }
        else
        {
            None
        }
    }

    /// Returns a mutable reference to an entity's component. (or None)
    pub fn borrow_mut_component<T: Component>(&mut self, entity: &Entity) -> Option<&mut T>
    {
        if self.is_active(entity)
        {
            self.components.borrow_mut::<T>(entity)
        }
        else
        {
            None
        }
    }
}

impl SystemManager
{
    pub fn new() -> SystemManager
    {
        SystemManager
        {
            systems: Vec::new(),
            passive: HashMap::new(),
        }
    }

    pub fn register(&mut self, sys: Box<System>)
    {
        self.systems.push(sys);
    }

    pub fn register_passive(&mut self, key: &'static str, sys: Box<Passive>)
    {
        self.passive.insert(key, sys);
    }

    pub fn update(&mut self, world: &World, mut components: Components)
    {
        for sys in self.systems.mut_iter()
        {
            sys.preprocess(world);
        }
        for sys in self.systems.iter()
        {
            sys.process(world, &mut components);
        }
        for sys in self.systems.mut_iter()
        {
            sys.postprocess(world);
        }
    }

    pub fn update_passive(&mut self, key: &'static str, world: &World)
    {
        self.passive.get_mut(&key).process(world);
    }
}

impl MutableManager for SystemManager
{
    fn added(&mut self, _: &Entity, _: &World)
    {

    }

    fn removed(&mut self, _: &Entity, _: &World)
    {

    }

    fn activated(&mut self, e: &Entity, w: &World)
    {
        for sys in self.systems.mut_iter()
        {
            sys.activated(e, w);
        }
    }

    fn deactivated(&mut self, e: &Entity, _: &World)
    {
        for sys in self.systems.mut_iter()
        {
            sys.deactivated(e);
        }
    }
}

impl ComponentManager
{
    pub fn new() -> ComponentManager
    {
        ComponentManager
        {
            components: HashMap::new(),
        }
    }

    pub fn register(&mut self, list: ComponentList)
    {
        self.components.insert(list.get_cid(), list);
    }

    fn delete_entity(&mut self, entity: &Entity)
    {
        for (_, list) in self.components.mut_iter()
        {
            list.rm(entity);
        }
    }

    fn add<T:Component>(&mut self, entity: &Entity, component: T) -> bool
    {
        self.components.get_mut(&Component::cid(Phantom::<T>)).add::<T>(entity, &component)
    }

    fn set<T:Component>(&mut self, entity: &Entity, component: T) -> bool
    {
        self.components.get_mut(&Component::cid(Phantom::<T>)).set::<T>(entity, &component)
    }

    fn get<T:Component>(&self, entity: &Entity) -> Option<T>
    {
        self.components[Component::cid(Phantom::<T>)].get::<T>(entity)
    }

    pub fn has(&self, entity: &Entity, id: ComponentId) -> bool
    {
        self.components[id].has(entity)
    }

    fn borrow<T:Component>(&self, entity: &Entity) -> Option<&T>
    {
        self.components[Component::cid(Phantom::<T>)].borrow::<T>(entity)
    }

    fn borrow_mut<T:Component>(&mut self, entity: &Entity) -> Option<&mut T>
    {
        self.components.get_mut(&Component::cid(Phantom::<T>)).borrow_mut::<T>(entity)
    }

    fn remove<T:Component>(&mut self, entity: &Entity) -> bool
    {
        self.components.get_mut(&Component::cid(Phantom::<T>)).rm(entity)
    }
}

impl<'a> Components<'a>
{
    pub fn borrow<T:Component>(&self, entity: &Entity) -> Option<&T>
    {
        self.inner.borrow::<T>(entity)
    }

    pub fn borrow_mut<T:Component>(&mut self, entity: &Entity) -> Option<&mut T>
    {
        self.inner.borrow_mut::<T>(entity)
    }
}
<commit_msg>fixed bug where passive systems would not get (de)activation signals<commit_after>
//! Management of entities, components, systems, and managers

use std::cell::RefCell;
use std::collections::HashMap;
use std::mem;

use {Component, ComponentId};
use Entity;
use {Manager, MutableManager};
use Phantom;
use {Passive, System};
use component::ComponentList;
use entity::EntityManager;

pub struct World
{
    entities: RefCell<EntityManager>,
    components: ComponentManager,
    systems: RefCell<SystemManager>,
    mut_managers: Vec<RefCell<Box<MutableManager>>>,
    managers: Vec<Box<Manager>>,
    locked: bool,
}

pub struct Components<'a>
{
    inner: &'a mut ComponentManager,
}

struct ComponentManager
{
    components: HashMap<ComponentId, ComponentList>,
}

struct SystemManager
{
    systems: Vec<Box<System>>,
    passive: HashMap<&'static str, Box<Passive>>,
}

impl World
{
    pub fn new() -> World
    {
        World
        {
            entities: RefCell::new(EntityManager::new()),
            components: ComponentManager::new(),
            systems: RefCell::new(SystemManager::new()),
            mut_managers: Vec::new(),
            managers: Vec::new(),
            locked: false,
        }
    }

    /// Lock down the managers and systems, and components of a world.
    ///
    /// This must be called before entities can be created and modified.
    /// After it is called, no systems/managers/components may be registered.
    pub fn finalise(&mut self)
    {
        if self.locked
        {
            fail!("World is already finalised")
        }
        self.locked = true;
    }

    /// Returns if an entity has been activated.
    #[inline]
    pub fn is_active(&self, entity: &Entity) -> bool
    {
        self.entities.borrow().is_activated(entity)
    }

    /// Registers a mutable manager.
    ///
    /// # Failure
    ///
    /// If the world has been finalised
    #[experimental]
    pub fn register_manager_mut(&mut self, manager: Box<MutableManager>)
    {
        if self.locked
        {
            fail!("World is locked. Managers may not be registered")
        }
        self.mut_managers.push(RefCell::new(manager));
    }

    /// Registers an immutable manager.
    ///
    /// # Failure
    ///
    /// If the world has been finalised
    #[experimental]
    pub fn register_manager(&mut self, manager: Box<Manager>)
    {
        if self.locked
        {
            fail!("World is locked. Managers may not be registered")
        }
        self.managers.push(manager);
    }

    /// Registers a component.
    ///
    /// # Failure
    ///
    /// If the world has been finalised
    pub fn register_component<T: Component>(&mut self)
    {
        if self.locked
        {
            fail!("World is locked. Components may not be registered")
        }
        self.components.register(ComponentList::new(Phantom::<T>));
    }

    /// Registers a system.
    ///
    /// # Failure
    ///
    /// If the world has been finalised
    pub fn register_system(&mut self, sys: Box<System>)
    {
        if self.locked
        {
            fail!("World is locked. Systems may not be registered")
        }
        self.systems.borrow_mut().register(sys);
    }

    /// Registers a passive system.
    ///
    /// # Failure
    ///
    /// If the world has been finalised
    pub fn register_passive(&mut self, key: &'static str, sys: Box<Passive>)
    {
        if self.locked
        {
            fail!("World is locked. Systems may not be registered")
        }
        self.systems.borrow_mut().register_passive(key, sys);
    }

    /// Updates the world by processing all systems.
    ///
    /// # Failure
    ///
    /// If the world has not been finalised
    pub fn update(&mut self)
    {
        if !self.locked
        {
            fail!("World must be locked before updating")
        }
        self.systems.borrow_mut().update(self, self.components());
    }

    /// Updates the passive system corresponding to `key`
    ///
    /// # Failure
    ///
    /// If the world has not been finalised
    pub fn update_passive(&mut self, key: &'static str)
    {
        if !self.locked
        {
            fail!("World must be locked before updating")
        }
        self.systems.borrow_mut().update_passive(key, self);
    }

    fn components(&self) -> Components
    {
        Components
        {
            inner: unsafe {
                mem::transmute(&self.components)
            },
        }
    }

    /// Creates an entity
    ///
    /// # Failure
    ///
    /// If the world has not been finalised
    pub fn create_entity(&mut self) -> Entity
    {
        if !self.locked
        {
            fail!("World must be locked before creating entities")
        }
        let ret = self.entities.borrow_mut().create_entity();
        for ref manager in self.mut_managers.iter()
        {
            manager.borrow_mut().added(&ret, self);
        }
        for ref manager in self.managers.iter()
        {
            manager.added(&ret, self);
        }
        ret
    }

    /// Activates an entity
    ///
    /// Once activated, components cannot be added to the entity,
    /// and systems will be able to process it.
    ///
    /// # Failure
    ///
    /// If the entity is invalid or already activated
    pub fn activate_entity(&mut self, entity: &Entity)
    {
        if self.is_active(entity)
        {
            fail!("Entity is already activated")
        }
        if !self.entities.borrow().is_valid(entity)
        {
            fail!("Cannot activate invalid entity")
        }
        self.entities.borrow_mut().activate_entity(entity);
        self.systems.borrow_mut().activated(entity, self);
        for ref manager in self.mut_managers.iter()
        {
            manager.borrow_mut().activated(entity, self);
        }
        for ref manager in self.managers.iter()
        {
            manager.activated(entity, self);
        }
    }

    /// Deactivates an entity
    ///
    /// It will then be ignored by all systems.
    /// Components can only be added/removed from an entity while deactivated.
    ///
    /// # Failure
    ///
    /// If the entity is not already activated
    pub fn deactivate_entity(&mut self, entity: &Entity)
    {
        if !self.is_active(entity)
        {
            fail!("Cannot deactivate unactivated entity")
        }
        self.entities.borrow_mut().deactivate_entity(entity);
        self.systems.borrow_mut().deactivated(entity, self);
        for ref manager in self.mut_managers.iter()
        {
            manager.borrow_mut().deactivated(entity, self);
        }
        for ref manager in self.managers.iter()
        {
            manager.deactivated(entity, self);
        }
    }

    /// Deletes an entity, deactivating it if it is activated
    ///
    /// # Failure
    ///
    /// If an entity is invalid
    pub fn delete_entity(&mut self, entity: &Entity)
    {
        if !self.entities.borrow().is_valid(entity)
        {
            fail!("Cannot delete invalid entity")
        }
        if self.is_active(entity)
        {
            self.deactivate_entity(entity);
        }
        self.entities.borrow_mut().delete_entity(entity);
        self.components.delete_entity(entity);
        for ref manager in self.mut_managers.iter()
        {
            manager.borrow_mut().removed(entity, self);
        }
        for ref manager in self.managers.iter()
        {
            manager.removed(entity, self);
        }
    }

    /// Add a component to an entity
    ///
    /// Returns false if the component could not be added (entity invalid or activated).
    pub fn add_component<T: Component>(&mut self, entity: &Entity, component: T) -> bool
    {
        self.entities.borrow().is_valid(entity)
        && !self.is_active(entity)
        && self.components.add::<T>(entity, component)
    }

    /// Removes a component from an entity.
    ///
    /// Returns false if the component could not be removed (entity invalid or activated).
    pub fn remove_component<T: Component>(&mut self, entity: &Entity) -> bool
    {
        self.entities.borrow().is_valid(entity)
        && !self.is_active(entity)
        && self.components.remove::<T>(entity)
    }

    /// Set the value of a component for an entity
    ///
    /// Returns false if the entity does not contain that component.
    pub fn set_component<T: Component>(&mut self, entity: &Entity, component: T) -> bool
    {
        self.entities.borrow().is_valid(entity)
        && self.components.set::<T>(entity, component)
    }

    /// Returns the value of a component for an entity (or None)
    pub fn get_component<T: Component>(&self, entity: &Entity) -> Option<T>
    {
        if self.entities.borrow().is_valid(entity)
        {
            self.components.get::<T>(entity)
        }
        else
        {
            None
        }
    }

    /// Returns if an entity contains a component.
    pub fn has_component(&self, entity: &Entity, id: ComponentId) -> bool
    {
        self.components.has(entity, id)
    }

    /// Returns a reference to an entity's component. (or None)
    pub fn borrow_component<T: Component>(&self, entity: &Entity) -> Option<&T>
    {
        if self.is_active(entity)
        {
            self.components.borrow::<T>(entity)
        }
        else
        {
            None
        }
    }

    /// Returns a mutable reference to an entity's component. (or None)
    pub fn borrow_mut_component<T: Component>(&mut self, entity: &Entity) -> Option<&mut T>
    {
        if self.is_active(entity)
        {
            self.components.borrow_mut::<T>(entity)
        }
        else
        {
            None
        }
    }
}

impl SystemManager
{
    pub fn new() -> SystemManager
    {
        SystemManager
        {
            systems: Vec::new(),
            passive: HashMap::new(),
        }
    }

    pub fn register(&mut self, sys: Box<System>)
    {
        self.systems.push(sys);
    }

    pub fn register_passive(&mut self, key: &'static str, sys: Box<Passive>)
    {
        self.passive.insert(key, sys);
    }

    pub fn update(&mut self, world: &World, mut components: Components)
    {
        for sys in self.systems.mut_iter()
        {
            sys.preprocess(world);
        }
        for sys in self.systems.iter()
        {
            sys.process(world, &mut components);
        }
        for sys in self.systems.mut_iter()
        {
            sys.postprocess(world);
        }
    }

    pub fn update_passive(&mut self, key: &'static str, world: &World)
    {
        self.passive.get_mut(&key).process(world);
    }
}

impl MutableManager for SystemManager
{
    fn added(&mut self, _: &Entity, _: &World)
    {

    }

    fn removed(&mut self, _: &Entity, _: &World)
    {

    }

    fn activated(&mut self, e: &Entity, w: &World)
    {
        for sys in self.systems.mut_iter()
        {
            sys.activated(e, w);
        }
        for (_, sys) in self.passive.mut_iter()
        {
            sys.activated(e, w);
        }
    }

    fn deactivated(&mut self, e: &Entity, _: &World)
    {
        for sys in self.systems.mut_iter()
        {
            sys.deactivated(e);
        }
        for (_, sys) in self.passive.mut_iter()
        {
            sys.deactivated(e);
        }
    }
}

impl ComponentManager
{
    pub fn new() -> ComponentManager
    {
        ComponentManager
        {
            components: HashMap::new(),
        }
    }

    pub fn register(&mut self, list: ComponentList)
    {
        self.components.insert(list.get_cid(), list);
    }

    fn delete_entity(&mut self, entity: &Entity)
    {
        for (_, list) in self.components.mut_iter()
        {
            list.rm(entity);
        }
    }

    fn add<T:Component>(&mut self, entity: &Entity, component: T) -> bool
    {
        self.components.get_mut(&Component::cid(Phantom::<T>)).add::<T>(entity, &component)
    }

    fn set<T:Component>(&mut self, entity: &Entity, component: T) -> bool
    {
        self.components.get_mut(&Component::cid(Phantom::<T>)).set::<T>(entity, &component)
    }

    fn get<T:Component>(&self, entity: &Entity) -> Option<T>
    {
        self.components[Component::cid(Phantom::<T>)].get::<T>(entity)
    }

    pub fn has(&self, entity: &Entity, id: ComponentId) -> bool
    {
        self.components[id].has(entity)
    }

    fn borrow<T:Component>(&self, entity: &Entity) -> Option<&T>
    {
        self.components[Component::cid(Phantom::<T>)].borrow::<T>(entity)
    }

    fn borrow_mut<T:Component>(&mut self, entity: &Entity) -> Option<&mut T>
    {
        self.components.get_mut(&Component::cid(Phantom::<T>)).borrow_mut::<T>(entity)
    }

    fn remove<T:Component>(&mut self, entity: &Entity) -> bool
    {
        self.components.get_mut(&Component::cid(Phantom::<T>)).rm(entity)
    }
}

impl<'a> Components<'a>
{
    pub fn borrow<T:Component>(&self, entity: &Entity) -> Option<&T>
    {
        self.inner.borrow::<T>(entity)
    }

    pub fn borrow_mut<T:Component>(&mut self, entity: &Entity) -> Option<&mut T>
    {
        self.inner.borrow_mut::<T>(entity)
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 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.

#![allow(dead_code)]

enum X { A = 0 as isize }

enum Y { A = X::A as isize }

fn main() { }
<commit_msg>Add a test for casts of univariant C-like enums<commit_after>// Copyright 2015 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.

#![allow(dead_code)]

enum X { A = 42 as isize }

enum Y { A = X::A as isize }

fn main() {
    let x = X::A;
    let x = x as isize;
    assert_eq!(x, 42);
    assert_eq!(Y::A as isize, 42);
}
<|endoftext|>


<commit_before>use turtle::event::Key::{Left, Right};
use turtle::Event::KeyPressed;
use turtle::Turtle;

fn main() {
    let mut turtle = Turtle::new();

    println!("Turn using the left and right arrow keys");

    turtle.set_pen_color("red");
    turtle.set_pen_size(1.0);
    turtle.set_speed(4);
    loop {
        turtle.forward(1.0);

        while let Some(event) = turtle.drawing_mut().poll_event() {
            match event {
                KeyPressed(key) => match key {
                    Left => {
                        turtle.set_speed(8);
                        for _ in 0..20 {
                            turtle.forward(1.0);
                            turtle.left(4.5);
                        }
                        turtle.set_speed(4);
                    }
                    Right => {
                        turtle.set_speed(8);
                        for _ in 0..20 {
                            turtle.forward(1.0);
                            turtle.right(4.5);
                        }
                        turtle.set_speed(4);
                    }
                    _ => {}
                },
                _ => {}
            }
        }
    }
}
<commit_msg>Updated arrowkeys example to use events API<commit_after>use turtle::{Turtle, Event, event::{Key, PressedState}};

fn main() {
    let mut turtle = Turtle::new();

    println!("Turn using the left and right arrow keys");

    turtle.set_pen_color("red");
    turtle.set_pen_size(1.0);
    turtle.set_speed(4);
    loop {
        turtle.forward(1.0);

        while let Some(event) = turtle.drawing_mut().poll_event() {
            use Key::{LeftArrow, RightArrow};
            match event {
                Event::Key(key, PressedState::Pressed) => match key {
                    LeftArrow => {
                        turtle.set_speed(8);
                        for _ in 0..20 {
                            turtle.forward(1.0);
                            turtle.left(4.5);
                        }
                        turtle.set_speed(4);
                    },
                    RightArrow => {
                        turtle.set_speed(8);
                        for _ in 0..20 {
                            turtle.forward(1.0);
                            turtle.right(4.5);
                        }
                        turtle.set_speed(4);
                    },
                    _ => {},
                },
                _ => {}
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Local server that accepts SOCKS 5 protocol

use std::{io, net::SocketAddr, sync::Arc};

use futures::{self, stream::Stream, Future};

use tokio::{
    self,
    net::{TcpListener, TcpStream},
};
use tokio_io::{
    io::{flush, ReadHalf, WriteHalf},
    AsyncRead,
};

use config::{Config, ServerConfig};

use relay::{
    boxed_future,
    loadbalancing::server::{LoadBalancer, RoundRobin},
    socks5::{self, Address, HandshakeRequest, HandshakeResponse, TcpRequestHeader, TcpResponseHeader},
    tcprelay::crypto_io::{DecryptedRead, EncryptedWrite},
};

use super::{ignore_until_end, try_timeout, tunnel};

#[derive(Debug, Clone)]
struct UdpConfig {
    enable_udp: bool,
    client_addr: SocketAddr,
}

fn handle_socks5_connect(
    config: Arc<Config>,
    (r, w): (ReadHalf<TcpStream>, WriteHalf<TcpStream>),
    client_addr: SocketAddr,
    addr: Address,
    svr_cfg: Arc<ServerConfig>,
) -> impl Future<Item = (), Error = io::Error> + Send {
    let cloned_addr = addr.clone();
    let cloned_svr_cfg = svr_cfg.clone();
    let timeout = *svr_cfg.timeout();
    super::connect_proxy_server(config.clone(), svr_cfg)
        .then(move |res| {
            match res {
                Ok(svr_s) => {
                    trace!("Proxy server connected");

                    // Tell the client that we are ready
                    let header = TcpResponseHeader::new(socks5::Reply::Succeeded, Address::SocketAddress(client_addr));
                    trace!("Send header: {:?}", header);

                    boxed_future(
                        try_timeout(try_timeout(header.write_to(w), timeout).and_then(flush), timeout)
                            .map(move |w| (svr_s, w)),
                    )
                }
                Err(err) => {
                    use relay::socks5::Reply;
                    use std::io::ErrorKind;

                    error!("Failed to connect remote server, err: {}", err);

                    let reply = match err.kind() {
                        ErrorKind::ConnectionRefused => Reply::ConnectionRefused,
                        ErrorKind::ConnectionAborted => Reply::HostUnreachable,
                        _ => Reply::NetworkUnreachable,
                    };

                    let header = TcpResponseHeader::new(reply, Address::SocketAddress(client_addr));
                    trace!("Send header: {:?}", header);

                    boxed_future(
                        try_timeout(try_timeout(header.write_to(w), timeout).and_then(flush), timeout)
                            .and_then(|_| Err(err)),
                    )
                }
            }
        })
        .and_then(move |(svr_s, w)| {
            let svr_cfg = cloned_svr_cfg;
            let timeout = *svr_cfg.timeout();
            super::proxy_server_handshake(svr_s, svr_cfg, addr).and_then(move |(svr_r, svr_w)| {
                let cloned_timeout = timeout;
                let rhalf = svr_r.and_then(move |svr_r| svr_r.copy_timeout_opt(w, timeout));
                let whalf = svr_w.and_then(move |svr_w| svr_w.copy_timeout_opt(r, cloned_timeout));

                tunnel(cloned_addr, whalf, rhalf)
            })
        })
}

fn handle_socks5_client(
    config: Arc<Config>,
    s: TcpStream,
    conf: Arc<ServerConfig>,
    udp_conf: UdpConfig,
) -> io::Result<()> {
    if let Err(err) = s.set_keepalive(*conf.timeout()) {
        error!("Failed to set keep alive: {:?}", err);
    }

    if let Err(err) = s.set_nodelay(true) {
        error!("Failed to set no delay: {:?}", err);
    }

    let client_addr = s.peer_addr()?;
    let cloned_client_addr = client_addr;
    let fut = futures::lazy(|| Ok(s.split()))
        .and_then(|(r, w)| {
            // Socks5 handshakes
            HandshakeRequest::read_from(r).and_then(move |(r, req)| {
                trace!("Socks5 {:?}", req);

                if !req.methods.contains(&socks5::SOCKS5_AUTH_METHOD_NONE) {
                    let resp = HandshakeResponse::new(socks5::SOCKS5_AUTH_METHOD_NOT_ACCEPTABLE);
                    let fut = resp.write_to(w).then(|_| {
                        warn!("Currently shadowsocks-rust does not support authentication");
                        Err(io::Error::new(
                            io::ErrorKind::Other,
                            "Currently shadowsocks-rust does not support authentication",
                        ))
                    });
                    boxed_future(fut)
                } else {
                    // Reply to client
                    let resp = HandshakeResponse::new(socks5::SOCKS5_AUTH_METHOD_NONE);
                    trace!("Reply handshake {:?}", resp);
                    let fut = resp.write_to(w).and_then(flush).and_then(|w| Ok((r, w)));
                    boxed_future(fut)
                }
            })
        })
        .and_then(move |(r, w)| {
            // Fetch headers
            TcpRequestHeader::read_from(r).then(move |res| match res {
                Ok((r, h)) => boxed_future(futures::finished((r, w, h))),
                Err(err) => {
                    error!("Failed to get TcpRequestHeader: {}", err);
                    let fut = TcpResponseHeader::new(err.reply, Address::SocketAddress(client_addr))
                        .write_to(w)
                        .then(|_| Err(From::from(err)));
                    boxed_future(fut)
                }
            })
        })
        .and_then(move |(r, w, header)| {
            trace!("Socks5 {:?}", header);

            let addr = header.address;
            match header.command {
                socks5::Command::TcpConnect => {
                    debug!("CONNECT {}", addr);
                    let fut = handle_socks5_connect(config, (r, w), cloned_client_addr, addr, conf);
                    boxed_future(fut)
                }
                socks5::Command::TcpBind => {
                    warn!("BIND is not supported");
                    let fut = TcpResponseHeader::new(socks5::Reply::CommandNotSupported, addr)
                        .write_to(w)
                        .map(|_| ());
                    boxed_future(fut)
                }
                socks5::Command::UdpAssociate => {
                    if udp_conf.enable_udp {
                        debug!("UDP ASSOCIATE {}", addr);
                        let fut = TcpResponseHeader::new(socks5::Reply::Succeeded, From::from(udp_conf.client_addr))
                            .write_to(w)
                            .and_then(flush)
                            .and_then(|_| {
                                // Hold the connection until it ends by its own
                                ignore_until_end(r).map(|_| ())
                            });

                        boxed_future(fut)
                    } else {
                        warn!("UDP Associate is not enabled");
                        let fut = TcpResponseHeader::new(socks5::Reply::CommandNotSupported, addr)
                            .write_to(w)
                            .map(|_| ());
                        boxed_future(fut)
                    }
                }
            }
        });

    tokio::spawn(fut.then(|res| match res {
        Ok(..) => Ok(()),
        Err(err) => {
            if err.kind() != io::ErrorKind::BrokenPipe {
                error!("Failed to handle client: {}", err);
            }
            Err(())
        }
    }));

    Ok(())
}

/// Starts a TCP local server with Socks5 proxy protocol
pub fn run(config: Arc<Config>) -> impl Future<Item = (), Error = io::Error> + Send {
    let local_addr = *config.local.as_ref().expect("Missing local config");

    let listener = TcpListener::bind(&local_addr).unwrap_or_else(|err| panic!("Failed to listen, {}", err));

    info!("ShadowSocks TCP Listening on {}", local_addr);

    let udp_conf = UdpConfig {
        enable_udp: config.enable_udp,
        client_addr: local_addr,
    };

    let mut servers = RoundRobin::new(&*config);
    listener.incoming().for_each(move |socket| {
        let server_cfg = servers.pick_server();

        trace!("Got connection, addr: {}", socket.peer_addr()?);
        trace!("Picked proxy server: {:?}", server_cfg);

        handle_socks5_client(config.clone(), socket, server_cfg, udp_conf.clone())
    })
}
<commit_msg>Removed some boxed_future calls<commit_after>//! Local server that accepts SOCKS 5 protocol

use std::{io, net::SocketAddr, sync::Arc};

use futures::{self, stream::Stream, Future};

use tokio::{
    self,
    net::{TcpListener, TcpStream},
};
use tokio_io::{
    io::{flush, ReadHalf, WriteHalf},
    AsyncRead,
};

use config::{Config, ServerConfig};

use relay::{
    boxed_future,
    loadbalancing::server::{LoadBalancer, RoundRobin},
    socks5::{self, Address, HandshakeRequest, HandshakeResponse, TcpRequestHeader, TcpResponseHeader},
    tcprelay::crypto_io::{DecryptedRead, EncryptedWrite},
};

use super::{ignore_until_end, try_timeout, tunnel};

#[derive(Debug, Clone)]
struct UdpConfig {
    enable_udp: bool,
    client_addr: SocketAddr,
}

fn handle_socks5_connect(
    config: Arc<Config>,
    (r, w): (ReadHalf<TcpStream>, WriteHalf<TcpStream>),
    client_addr: SocketAddr,
    addr: Address,
    svr_cfg: Arc<ServerConfig>,
) -> impl Future<Item = (), Error = io::Error> + Send {
    let cloned_addr = addr.clone();
    let cloned_svr_cfg = svr_cfg.clone();
    let timeout = *svr_cfg.timeout();
    super::connect_proxy_server(config.clone(), svr_cfg)
        .then(move |res| {
            let (header, r) = match res {
                Ok(svr_s) => {
                    trace!("Proxy server connected");

                    // Tell the client that we are ready
                    let header = TcpResponseHeader::new(socks5::Reply::Succeeded, Address::SocketAddress(client_addr));

                    (header, Ok(svr_s))
                }
                Err(err) => {
                    use relay::socks5::Reply;
                    use std::io::ErrorKind;

                    error!("Failed to connect remote server, err: {}", err);

                    let reply = match err.kind() {
                        ErrorKind::ConnectionRefused => Reply::ConnectionRefused,
                        ErrorKind::ConnectionAborted => Reply::HostUnreachable,
                        _ => Reply::NetworkUnreachable,
                    };

                    let header = TcpResponseHeader::new(reply, Address::SocketAddress(client_addr));

                    (header, Err(err))
                }
            };

            trace!("Send header: {:?}", header);
            try_timeout(try_timeout(header.write_to(w), timeout).and_then(flush), timeout).and_then(|w| match r {
                Ok(svr_s) => Ok((svr_s, w)),
                Err(err) => Err(err),
            })
        })
        .and_then(move |(svr_s, w)| {
            let svr_cfg = cloned_svr_cfg;
            let timeout = *svr_cfg.timeout();
            super::proxy_server_handshake(svr_s, svr_cfg, addr).and_then(move |(svr_r, svr_w)| {
                let cloned_timeout = timeout;
                let rhalf = svr_r.and_then(move |svr_r| svr_r.copy_timeout_opt(w, timeout));
                let whalf = svr_w.and_then(move |svr_w| svr_w.copy_timeout_opt(r, cloned_timeout));

                tunnel(cloned_addr, whalf, rhalf)
            })
        })
}

fn handle_socks5_client(
    config: Arc<Config>,
    s: TcpStream,
    conf: Arc<ServerConfig>,
    udp_conf: UdpConfig,
) -> io::Result<()> {
    if let Err(err) = s.set_keepalive(*conf.timeout()) {
        error!("Failed to set keep alive: {:?}", err);
    }

    if let Err(err) = s.set_nodelay(true) {
        error!("Failed to set no delay: {:?}", err);
    }

    let client_addr = s.peer_addr()?;
    let cloned_client_addr = client_addr;
    let fut = futures::lazy(|| Ok(s.split()))
        .and_then(|(r, w)| {
            // Socks5 handshakes
            HandshakeRequest::read_from(r).and_then(move |(r, req)| {
                trace!("Socks5 {:?}", req);

                let (resp, res) = if !req.methods.contains(&socks5::SOCKS5_AUTH_METHOD_NONE) {
                    let resp = HandshakeResponse::new(socks5::SOCKS5_AUTH_METHOD_NOT_ACCEPTABLE);
                    warn!("Currently shadowsocks-rust does not support authentication");
                    (
                        resp,
                        Err(io::Error::new(
                            io::ErrorKind::Other,
                            "Currently shadowsocks-rust does not support authentication",
                        )),
                    )
                } else {
                    // Reply to client
                    let resp = HandshakeResponse::new(socks5::SOCKS5_AUTH_METHOD_NONE);
                    trace!("Reply handshake {:?}", resp);
                    (resp, Ok(()))
                };

                resp.write_to(w).and_then(flush).and_then(move |w| match res {
                    Ok(..) => Ok((r, w)),
                    Err(err) => Err(err),
                })
            })
        })
        .and_then(move |(r, w)| {
            // Fetch headers
            TcpRequestHeader::read_from(r).then(move |res| match res {
                Ok((r, h)) => boxed_future(futures::finished((r, w, h))),
                Err(err) => {
                    error!("Failed to get TcpRequestHeader: {}", err);
                    let fut = TcpResponseHeader::new(err.reply, Address::SocketAddress(client_addr))
                        .write_to(w)
                        .then(|_| Err(From::from(err)));
                    boxed_future(fut)
                }
            })
        })
        .and_then(move |(r, w, header)| {
            trace!("Socks5 {:?}", header);

            let addr = header.address;
            match header.command {
                socks5::Command::TcpConnect => {
                    debug!("CONNECT {}", addr);
                    let fut = handle_socks5_connect(config, (r, w), cloned_client_addr, addr, conf);
                    boxed_future(fut)
                }
                socks5::Command::TcpBind => {
                    warn!("BIND is not supported");
                    let fut = TcpResponseHeader::new(socks5::Reply::CommandNotSupported, addr)
                        .write_to(w)
                        .map(|_| ());
                    boxed_future(fut)
                }
                socks5::Command::UdpAssociate => {
                    if udp_conf.enable_udp {
                        debug!("UDP ASSOCIATE {}", addr);
                        let fut = TcpResponseHeader::new(socks5::Reply::Succeeded, From::from(udp_conf.client_addr))
                            .write_to(w)
                            .and_then(flush)
                            .and_then(|_| {
                                // Hold the connection until it ends by its own
                                ignore_until_end(r).map(|_| ())
                            });

                        boxed_future(fut)
                    } else {
                        warn!("UDP Associate is not enabled");
                        let fut = TcpResponseHeader::new(socks5::Reply::CommandNotSupported, addr)
                            .write_to(w)
                            .map(|_| ());
                        boxed_future(fut)
                    }
                }
            }
        });

    tokio::spawn(fut.then(|res| match res {
        Ok(..) => Ok(()),
        Err(err) => {
            if err.kind() != io::ErrorKind::BrokenPipe {
                error!("Failed to handle client: {}", err);
            }
            Err(())
        }
    }));

    Ok(())
}

/// Starts a TCP local server with Socks5 proxy protocol
pub fn run(config: Arc<Config>) -> impl Future<Item = (), Error = io::Error> + Send {
    let local_addr = *config.local.as_ref().expect("Missing local config");

    let listener = TcpListener::bind(&local_addr).unwrap_or_else(|err| panic!("Failed to listen, {}", err));

    info!("ShadowSocks TCP Listening on {}", local_addr);

    let udp_conf = UdpConfig {
        enable_udp: config.enable_udp,
        client_addr: local_addr,
    };

    let mut servers = RoundRobin::new(&*config);
    listener.incoming().for_each(move |socket| {
        let server_cfg = servers.pick_server();

        trace!("Got connection, addr: {}", socket.peer_addr()?);
        trace!("Picked proxy server: {:?}", server_cfg);

        handle_socks5_client(config.clone(), socket, server_cfg, udp_conf.clone())
    })
}
<|endoftext|>


<commit_before>use clap::{App, Arg, ArgGroup, ArgMatches};
use cluster_test::{
    aws::Aws,
    cluster::Cluster,
    experiments::{Experiment, RebootRandomValidator},
    health::{AwsLogTail, HealthCheckRunner},
};
use std::{
    collections::HashSet,
    sync::mpsc::{self, TryRecvError},
    thread,
    time::{Duration, Instant},
};
use termion::{color, style};

const HEALTH_POLL_INTERVAL: Duration = Duration::from_secs(5);

pub fn main() {
    let matches = arg_matches();

    let workplace = matches
        .value_of(ARG_WORKPLACE)
        .expect("workplace should be set");
    let aws = Aws::new(workplace.into());
    let logs = AwsLogTail::spawn_new(aws.clone()).expect("Failed to start aws log tail");
    println!("Aws log thread started");
    let cluster = Cluster::discover(&aws).expect("Failed to discover cluster");
    println!("Discovered {} peers", cluster.instances().len());

    if matches.is_present(ARG_RUN) {
        let mut health_check_runner = HealthCheckRunner::new_all(cluster.clone());
        let events = logs.recv_all();
        if !health_check_runner.run(&events).is_empty() {
            panic!("Some validators are unhealthy before experiment started");
        }

        let experiment = RebootRandomValidator::new(&cluster);
        println!(
            "{}Starting experiment {}{}{}{}",
            style::Bold,
            color::Fg(color::Blue),
            experiment,
            color::Fg(color::Reset),
            style::Reset
        );
        let affected_validators = experiment.affected_validators();
        let (exp_result_sender, exp_result_recv) = mpsc::channel();
        thread::spawn(move || {
            let result = experiment.run();
            exp_result_sender
                .send(result)
                .expect("Failed to send experiment result");
        });

        // We expect experiments completes and cluster go into healthy state within 2 minutes
        let experiment_deadline = Instant::now() + Duration::from_secs(2 * 60);

        loop {
            if Instant::now() > experiment_deadline {
                panic!("Experiment did not complete in time");
            }
            let deadline = Instant::now() + HEALTH_POLL_INTERVAL;
            // Receive all events that arrived to aws log tail within next 1 second
            // This assumes so far that event propagation time is << 1s, this need to be refined
            // in future to account for actual event propagation delay
            let events = logs.recv_all_until_deadline(deadline);
            let failed_validators = health_check_runner.run(&events);
            for failed in failed_validators {
                if !affected_validators.contains(&failed) {
                    panic!(
                        "Validator {} failed, not expected for this experiment",
                        failed
                    );
                }
            }
            match exp_result_recv.try_recv() {
                Ok(result) => {
                    result.expect("Failed to run experiment");
                    break;
                }
                Err(TryRecvError::Empty) => {
                    // Experiment in progress, continue monitoring health
                }
                Err(TryRecvError::Disconnected) => {
                    panic!("Experiment thread exited without returning result");
                }
            }
        }

        println!(
            "{}Experiment finished, waiting until all affected validators recover{}",
            style::Bold,
            style::Reset
        );

        loop {
            if Instant::now() > experiment_deadline {
                panic!("Cluster did not become healthy in time");
            }
            let deadline = Instant::now() + HEALTH_POLL_INTERVAL;
            // Receive all events that arrived to aws log tail within next 1 second
            // This assumes so far that event propagation time is << 1s, this need to be refined
            // in future to account for actual event propagation delay
            let events = logs.recv_all_until_deadline(deadline);
            let failed_validators = health_check_runner.run(&events);
            let mut still_affected_validator = HashSet::new();
            for failed in failed_validators {
                if !affected_validators.contains(&failed) {
                    panic!(
                        "Validator {} failed, not expected for this experiment",
                        failed
                    );
                }
                still_affected_validator.insert(failed);
            }
            if still_affected_validator.is_empty() {
                break;
            }
        }

        println!("Experiment completed");
    }
    if matches.is_present(ARG_TAIL_LOGS) {
        for log in logs.event_receiver {
            println!("{:?}", log);
        }
    } else if matches.is_present(HEALTH_CHECK) {
        let mut health_check_runner = HealthCheckRunner::new_all(cluster.clone());
        loop {
            let deadline = Instant::now() + Duration::from_secs(1);
            // Receive all events that arrived to aws log tail within next 1 second
            // This assumes so far that event propagation time is << 1s, this need to be refined
            // in future to account for actual event propagation delay
            let events = logs.recv_all_until_deadline(deadline);
            health_check_runner.run(&events);
        }
    }
}

const ARG_TAIL_LOGS: &str = "tail-logs";
const HEALTH_CHECK: &str = "health-check";
const ARG_RUN: &str = "run";
const ARG_WORKPLACE: &str = "workplace";

fn arg_matches() -> ArgMatches<'static> {
    let run = Arg::with_name(ARG_RUN).long("--run");
    let workplace = Arg::with_name(ARG_WORKPLACE)
        .long("--workplace")
        .short("-w")
        .takes_value(true)
        .required(true);
    let tail_logs = Arg::with_name(ARG_TAIL_LOGS).long("--tail-logs");
    let health_check = Arg::with_name(HEALTH_CHECK)
        .long("--health-check")
        .conflicts_with(ARG_TAIL_LOGS);
    // This grouping means at least one action (tail logs, or run test, or both) is required
    let action_group = ArgGroup::with_name("action")
        .multiple(true)
        .args(&[ARG_TAIL_LOGS, ARG_RUN, HEALTH_CHECK])
        .required(true);

    App::new("cluster_test")
        .author("Libra Association <opensource@libra.org>")
        .group(action_group)
        .args(&[workplace, run, tail_logs, health_check])
        .get_matches()
}
<commit_msg>[cluster_test] Organize main code into ClusterTestRunner struct<commit_after>use clap::{App, Arg, ArgGroup, ArgMatches};
use cluster_test::{
    aws::Aws,
    cluster::Cluster,
    experiments::{Experiment, RebootRandomValidator},
    health::{AwsLogTail, HealthCheckRunner},
};
use std::{
    collections::HashSet,
    env,
    sync::mpsc::{self, TryRecvError},
    thread,
    time::{Duration, Instant},
};
use termion::{color, style};

const HEALTH_POLL_INTERVAL: Duration = Duration::from_secs(5);

pub fn main() {
    let matches = arg_matches();
    let mut runner = ClusterTestRunner::setup(&matches);

    if matches.is_present(ARG_RUN) {
        runner.run_experiments_in_loop();
    } else if matches.is_present(ARG_RUN_ONCE) {
        runner.run_single_experiment();
    } else if matches.is_present(ARG_TAIL_LOGS) {
        runner.tail_logs();
    } else if matches.is_present(ARG_HEALTH_CHECK) {
        runner.run_health_check();
    }
}

struct ClusterTestRunner {
    logs: AwsLogTail,
    cluster: Cluster,
    health_check_runner: HealthCheckRunner,
}

impl ClusterTestRunner {
    /// Discovers cluster, setup log, etc
    pub fn setup(matches: &ArgMatches) -> Self {
        let workplace = matches
            .value_of(ARG_WORKPLACE)
            .expect("workplace should be set");
        let aws = Aws::new(workplace.into());
        let logs = AwsLogTail::spawn_new(aws.clone()).expect("Failed to start aws log tail");
        println!("Aws log thread started");
        let cluster = Cluster::discover(&aws).expect("Failed to discover cluster");
        println!("Discovered {} peers", cluster.instances().len());
        let health_check_runner = HealthCheckRunner::new_all(cluster.clone());
        Self {
            logs,
            cluster,
            health_check_runner,
        }
    }

    /// Run experiments every EXPERIMENT_INTERVAL seconds until fails
    pub fn run_experiments_in_loop(&mut self) {
        let experiment_interval_sec = match env::var("EXPERIMENT_INTERVAL") {
            Ok(s) => s.parse().expect("EXPERIMENT_INTERVAL env is not a number"),
            Err(..) => 15,
        };
        let experiment_interval = Duration::from_secs(experiment_interval_sec);
        loop {
            self.run_single_experiment();
            thread::sleep(experiment_interval);
        }
    }

    pub fn run_single_experiment(&mut self) {
        let events = self.logs.recv_all();
        if !self.health_check_runner.run(&events).is_empty() {
            panic!("Some validators are unhealthy before experiment started");
        }

        let experiment = RebootRandomValidator::new(&self.cluster);
        println!(
            "{}Starting experiment {}{}{}{}",
            style::Bold,
            color::Fg(color::Blue),
            experiment,
            color::Fg(color::Reset),
            style::Reset
        );
        let affected_validators = experiment.affected_validators();
        let (exp_result_sender, exp_result_recv) = mpsc::channel();
        thread::spawn(move || {
            let result = experiment.run();
            exp_result_sender
                .send(result)
                .expect("Failed to send experiment result");
        });

        // We expect experiments completes and cluster go into healthy state within 2 minutes
        let experiment_deadline = Instant::now() + Duration::from_secs(2 * 60);

        loop {
            if Instant::now() > experiment_deadline {
                panic!("Experiment did not complete in time");
            }
            let deadline = Instant::now() + HEALTH_POLL_INTERVAL;
            // Receive all events that arrived to aws log tail within next 1 second
            // This assumes so far that event propagation time is << 1s, this need to be refined
            // in future to account for actual event propagation delay
            let events = self.logs.recv_all_until_deadline(deadline);
            let failed_validators = self.health_check_runner.run(&events);
            for failed in failed_validators {
                if !affected_validators.contains(&failed) {
                    panic!(
                        "Validator {} failed, not expected for this experiment",
                        failed
                    );
                }
            }
            match exp_result_recv.try_recv() {
                Ok(result) => {
                    result.expect("Failed to run experiment");
                    break;
                }
                Err(TryRecvError::Empty) => {
                    // Experiment in progress, continue monitoring health
                }
                Err(TryRecvError::Disconnected) => {
                    panic!("Experiment thread exited without returning result");
                }
            }
        }

        println!(
            "{}Experiment finished, waiting until all affected validators recover{}",
            style::Bold,
            style::Reset
        );

        loop {
            if Instant::now() > experiment_deadline {
                panic!("Cluster did not become healthy in time");
            }
            let deadline = Instant::now() + HEALTH_POLL_INTERVAL;
            // Receive all events that arrived to aws log tail within next 1 second
            // This assumes so far that event propagation time is << 1s, this need to be refined
            // in future to account for actual event propagation delay
            let events = self.logs.recv_all_until_deadline(deadline);
            let failed_validators = self.health_check_runner.run(&events);
            let mut still_affected_validator = HashSet::new();
            for failed in failed_validators {
                if !affected_validators.contains(&failed) {
                    panic!(
                        "Validator {} failed, not expected for this experiment",
                        failed
                    );
                }
                still_affected_validator.insert(failed);
            }
            if still_affected_validator.is_empty() {
                break;
            }
        }

        println!("Experiment completed");
    }

    fn run_health_check(&mut self) {
        loop {
            let deadline = Instant::now() + Duration::from_secs(1);
            // Receive all events that arrived to aws log tail within next 1 second
            // This assumes so far that event propagation time is << 1s, this need to be refined
            // in future to account for actual event propagation delay
            let events = self.logs.recv_all_until_deadline(deadline);
            self.health_check_runner.run(&events);
        }
    }

    fn tail_logs(self) {
        for log in self.logs.event_receiver {
            println!("{:?}", log);
        }
    }
}

const ARG_WORKPLACE: &str = "workplace";
// Actions:
const ARG_TAIL_LOGS: &str = "tail-logs";
const ARG_HEALTH_CHECK: &str = "health-check";
const ARG_RUN: &str = "run";
const ARG_RUN_ONCE: &str = "run-once";

fn arg_matches() -> ArgMatches<'static> {
    let run = Arg::with_name(ARG_RUN).long("--run");
    let run_once = Arg::with_name(ARG_RUN_ONCE).long("--run-once");
    let workplace = Arg::with_name(ARG_WORKPLACE)
        .long("--workplace")
        .short("-w")
        .takes_value(true)
        .required(true);
    let tail_logs = Arg::with_name(ARG_TAIL_LOGS).long("--tail-logs");
    let health_check = Arg::with_name(ARG_HEALTH_CHECK).long("--health-check");
    // This grouping requires one and only one action (tail logs, run test, etc)
    let action_group = ArgGroup::with_name("action")
        .args(&[ARG_TAIL_LOGS, ARG_RUN, ARG_RUN_ONCE, ARG_HEALTH_CHECK])
        .required(true);

    App::new("cluster_test")
        .author("Libra Association <opensource@libra.org>")
        .group(action_group)
        .args(&[workplace, run, run_once, tail_logs, health_check])
        .get_matches()
}
<|endoftext|>


<commit_before>//! An rope.
//!
//! A rope is an efficient data structure for large mutable strings. It's
//! essentially a binary tree whose leaves are strings.

#[derive(Debug)]
enum Node<T> { /// A leaf node
               Leaf(T)
             , /// A branch node
               Branch(Box<Node<T>>, Box<Node<T>>)
             , None
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<commit_msg>rope: start an rope API<commit_after>//! An rope.
//!
//! A rope is an efficient data structure for large mutable strings. It's
//! essentially a binary tree whose leaves are strings.
//!
//! For more information, see the following resources:
//! + http://scienceblogs.com/goodmath/2009/01/26/ropes-twining-together-strings/
//! + https://www.ibm.com/developerworks/library/j-ropes/

use std::ops;

#[derive(Debug)]
pub struct Rope{
    // can we get away with having these be of &str or will they need
    // to be string?
    root: Node
}

#[derive(Debug)]
enum Node { /// A leaf node
            // todo: is box<str> the right choice?
            Leaf(Box<str>)
          , /// A branch node
            Branch { l: Box<Node>, r: Box<Node> }
          , /// Nothing
            None
}

impl ops::Add for Rope {
    type Output = Rope;

    // This is the concat operation.
    fn add(self, other: Rope) -> Rope {
        unimplemented!()
    }
}

impl ops::Index<usize> for Rope {
    type Output = char;

    // Index a character
    fn index(&self, i: usize) -> &char {
        unimplemented!()
    }
}

// slicing operators -----------------------------------------
impl ops::Index<ops::Range<usize>> for Rope {
    type Output = str;

    // Index a substring
    fn index(&self, i: ops::Range<usize>) -> &str {
        unimplemented!()
    }
}

impl ops::Index<ops::RangeTo<usize>> for Rope {
    type Output = str;

    fn index(&self, i: ops::RangeTo<usize>) -> &str {
        unimplemented!()
    }
}

impl ops::Index<ops::RangeFrom<usize>> for Rope {
    type Output = str;

    fn index(&self, i: ops::RangeFrom<usize>) -> &str {
        unimplemented!()
    }
}

impl ops::IndexMut<ops::Range<usize>> for Rope {
    fn index_mut(&mut self, i: ops::Range<usize>) -> &mut str {
        unimplemented!()
    }
}

impl ops::IndexMut<ops::RangeTo<usize>> for Rope {
    fn index_mut(&mut self, i: ops::RangeTo<usize>) -> &mut str {
        unimplemented!()
    }
}

impl ops::IndexMut<ops::RangeFrom<usize>> for Rope {
    fn index_mut(&mut self, i: ops::RangeFrom<usize>) -> &mut str {
        unimplemented!()
    }
}
#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<|endoftext|>


<commit_before>extern crate time;
extern crate stopwatch;

use stopwatch::{Stopwatch};
use std::num::SignedInt;
use std::io::timer;
use std::time::Duration;

static SLEEP_MS: i64 = 50;
static TOLERANCE_PERCENTAGE: f64 = 0.3;

#[test]
fn elapsed_none() {
	let sw = Stopwatch::new();
	assert_eq!(sw.elapsed_ms(), 0);
}

#[test]
fn elapsed_ms() {
	let sw = Stopwatch::start_new();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	assert_sw_near(sw, SLEEP_MS);
}

#[test]
fn stop() {
	let mut sw = Stopwatch::start_new();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	sw.stop();
	assert_sw_near(sw, SLEEP_MS);

	timer::sleep(Duration::milliseconds(SLEEP_MS));
	assert_sw_near(sw, SLEEP_MS);
}

#[test]
fn resume_once() {
	let mut sw = Stopwatch::start_new();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	sw.stop();
	assert_sw_near(sw, SLEEP_MS);
	sw.start();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	assert_sw_near(sw, 2 * SLEEP_MS);
}

#[test]
fn resume_twice() {
	let mut sw = Stopwatch::start_new();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	sw.stop();
	assert_sw_near(sw, SLEEP_MS);
	sw.start();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	sw.stop();
	assert_sw_near(sw, 2 * SLEEP_MS);
	sw.start();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	assert_sw_near(sw, 3 * SLEEP_MS);
}

#[test]
fn is_running() {
	let mut sw = Stopwatch::new();
	assert!(!sw.is_running());
	sw.start();
	assert!(sw.is_running());
	sw.stop();
	assert!(!sw.is_running());
}

#[test]
fn restart() {
	let mut sw = Stopwatch::start_new();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	sw.restart();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	assert_sw_near(sw, SLEEP_MS);
}

#[test]
fn reset() {
	let mut sw = Stopwatch::start_new();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	sw.reset();
	assert!(!sw.is_running());
	assert_eq!(sw.elapsed_ms(), 0);
}

/////////////// helpers

fn assert_near(x: i64, y: i64, tolerance: i64) {
	let diff = (x - y).abs();
	if diff > tolerance {
		panic!("Expected {}, got {}", x, y);
	}
}

fn assert_sw_near(sw: Stopwatch, elapsed: i64) {
	let tolerance_value = (TOLERANCE_PERCENTAGE * elapsed as f64) as i64;
	assert_near(elapsed, sw.elapsed_ms(), tolerance_value);
}<commit_msg>added test to make sure repeated stops don't increase the timer<commit_after>extern crate time;
extern crate stopwatch;

use stopwatch::{Stopwatch};
use std::num::SignedInt;
use std::io::timer;
use std::time::Duration;

static SLEEP_MS: i64 = 50;
static TOLERANCE_PERCENTAGE: f64 = 0.3;

#[test]
fn repeated_stops() {
	let mut sw = Stopwatch::start_new();
	for _ in range(0, 1000i) {
		sw.stop();
		sw.start();
	}
	assert_sw_near(sw, 0);
}

#[test]
fn elapsed_none() {
	let sw = Stopwatch::new();
	assert_eq!(sw.elapsed_ms(), 0);
}

#[test]
fn elapsed_ms() {
	let sw = Stopwatch::start_new();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	assert_sw_near(sw, SLEEP_MS);
}

#[test]
fn stop() {
	let mut sw = Stopwatch::start_new();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	sw.stop();
	assert_sw_near(sw, SLEEP_MS);

	timer::sleep(Duration::milliseconds(SLEEP_MS));
	assert_sw_near(sw, SLEEP_MS);
}

#[test]
fn resume_once() {
	let mut sw = Stopwatch::start_new();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	sw.stop();
	assert_sw_near(sw, SLEEP_MS);
	sw.start();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	assert_sw_near(sw, 2 * SLEEP_MS);
}

#[test]
fn resume_twice() {
	let mut sw = Stopwatch::start_new();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	sw.stop();
	assert_sw_near(sw, SLEEP_MS);
	sw.start();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	sw.stop();
	assert_sw_near(sw, 2 * SLEEP_MS);
	sw.start();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	assert_sw_near(sw, 3 * SLEEP_MS);
}

#[test]
fn is_running() {
	let mut sw = Stopwatch::new();
	assert!(!sw.is_running());
	sw.start();
	assert!(sw.is_running());
	sw.stop();
	assert!(!sw.is_running());
}

#[test]
fn restart() {
	let mut sw = Stopwatch::start_new();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	sw.restart();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	assert_sw_near(sw, SLEEP_MS);
}

#[test]
fn reset() {
	let mut sw = Stopwatch::start_new();
	timer::sleep(Duration::milliseconds(SLEEP_MS));
	sw.reset();
	assert!(!sw.is_running());
	assert_eq!(sw.elapsed_ms(), 0);
}

/////////////// helpers

fn assert_near(x: i64, y: i64, tolerance: i64) {
	let diff = (x - y).abs();
	if diff > tolerance {
		panic!("Expected {}, got {}", x, y);
	}
}

fn assert_sw_near(sw: Stopwatch, elapsed: i64) {
	let tolerance_value = (TOLERANCE_PERCENTAGE * elapsed as f64) as i64;
	assert_near(elapsed, sw.elapsed_ms(), tolerance_value);
}<|endoftext|>


<commit_before>// Copyright 2012-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 syntax::abi::{Abi};
use syntax::ast;
use syntax::codemap::Span;

use rustc::ty::{self, TyCtxt};
use rustc::mir::repr::{self, Mir};

use super::super::gather_moves::{MovePath, MovePathIndex};
use super::BitDenotation;
use super::DataflowResults;
use super::HasMoveData;

/// This function scans `mir` for all calls to the intrinsic
/// `rustc_peek` that have the expression form `rustc_peek(&expr)`.
///
/// For each such call, determines what the dataflow bit-state is for
/// the L-value corresponding to `expr`; if the bit-state is a 1, then
/// that call to `rustc_peek` is ignored by the sanity check. If the
/// bit-state is a 0, then this pass emits a error message saying
/// "rustc_peek: bit not set".
///
/// The intention is that one can write unit tests for dataflow by
/// putting code into a compile-fail test and using `rustc_peek` to
/// make observations about the results of dataflow static analyses.
///
/// (If there are any calls to `rustc_peek` that do not match the
/// expression form above, then that emits an error as well, but those
/// errors are not intended to be used for unit tests.)
pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                mir: &Mir<'tcx>,
                                                id: ast::NodeId,
                                                _attributes: &[ast::Attribute],
                                                flow_ctxt: &O::Ctxt,
                                                results: &DataflowResults<O>)
    where O: BitDenotation<Bit=MovePath<'tcx>, Idx=MovePathIndex>, O::Ctxt: HasMoveData<'tcx>
{
    debug!("sanity_check_via_rustc_peek id: {:?}", id);
    // FIXME: this is not DRY. Figure out way to abstract this and
    // `dataflow::build_sets`. (But note it is doing non-standard
    // stuff, so such generalization may not be realistic.)

    let blocks = mir.all_basic_blocks();
    'next_block: for bb in blocks {
        let bb_data = mir.basic_block_data(bb);
        let &repr::BasicBlockData { ref statements,
                                    ref terminator,
                                    is_cleanup: _ } = bb_data;

        let (args, span) = match is_rustc_peek(tcx, terminator) {
            Some(args_and_span) => args_and_span,
            None => continue,
        };
        assert!(args.len() == 1);
        let peek_arg_lval = match args[0] {
            repr::Operand::Consume(ref lval @ repr::Lvalue::Temp(_)) => {
                lval
            }
            repr::Operand::Consume(_) => {
                bug!("dataflow::sanity_check cannot feed a non-temp to rustc_peek.");
            }
            repr::Operand::Constant(_) => {
                bug!("dataflow::sanity_check cannot feed a constant to rustc_peek.");
            }
        };

        let mut entry = results.0.sets.on_entry_set_for(bb.index()).to_owned();
        let mut gen = results.0.sets.gen_set_for(bb.index()).to_owned();
        let mut kill = results.0.sets.kill_set_for(bb.index()).to_owned();

        let move_data = flow_ctxt.move_data();

        // Emulate effect of all statements in the block up to (but
        // not including) the borrow within `peek_arg_lval`. Do *not*
        // include call to `peek_arg_lval` itself (since we are
        // peeking the state of the argument at time immediate
        // preceding Call to `rustc_peek`).

        let mut sets = super::BlockSets { on_entry: &mut entry,
                                          gen_set: &mut gen,
                                          kill_set: &mut kill };

        for (j, stmt) in statements.iter().enumerate() {
            debug!("rustc_peek: ({:?},{}) {:?}", bb, j, stmt);
            let (lvalue, rvalue) = match stmt.kind {
                repr::StatementKind::Assign(ref lvalue, ref rvalue) => {
                    (lvalue, rvalue)
                }
            };

            if lvalue == peek_arg_lval {
                if let repr::Rvalue::Ref(_,
                                         repr::BorrowKind::Shared,
                                         ref peeking_at_lval) = *rvalue {
                    // Okay, our search is over.
                    let peek_mpi = move_data.rev_lookup.find(peeking_at_lval);
                    let bit_state = sets.on_entry.contains(&peek_mpi);
                    debug!("rustc_peek({:?} = &{:?}) bit_state: {}",
                           lvalue, peeking_at_lval, bit_state);
                    if !bit_state {
                        tcx.sess.span_err(span, &format!("rustc_peek: bit not set"));
                    }
                    continue 'next_block;
                } else {
                    // Our search should have been over, but the input
                    // does not match expectations of `rustc_peek` for
                    // this sanity_check.
                    tcx.sess.span_err(span, &format!("rustc_peek: argument expression \
                                                      must be immediate borrow of form `&expr`"));
                }
            }

            let lhs_mpi = move_data.rev_lookup.find(lvalue);

            debug!("rustc_peek: computing effect on lvalue: {:?} ({:?}) in stmt: {:?}",
                   lvalue, lhs_mpi, stmt);
            // reset GEN and KILL sets before emulating their effect.
            for e in sets.gen_set.words_mut() { *e = 0; }
            for e in sets.kill_set.words_mut() { *e = 0; }
            results.0.operator.statement_effect(flow_ctxt, &mut sets, bb, j);
            sets.on_entry.union(sets.gen_set);
            sets.on_entry.subtract(sets.kill_set);
        }

        tcx.sess.span_err(span, &format!("rustc_peek: MIR did not match \
                                          anticipated pattern; note that \
                                          rustc_peek expects input of \
                                          form `&expr`"));
    }

}

fn is_rustc_peek<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           terminator: &'a Option<repr::Terminator<'tcx>>)
                           -> Option<(&'a [repr::Operand<'tcx>], Span)> {
    if let Some(repr::Terminator { ref kind, span, .. }) = *terminator {
        if let repr::TerminatorKind::Call { func: ref oper, ref args, .. } = *kind
        {
            if let repr::Operand::Constant(ref func) = *oper
            {
                if let ty::TyFnDef(def_id, _, &ty::BareFnTy { abi, .. }) = func.ty.sty
                {
                    let name = tcx.item_name(def_id);
                    if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
                        if name.as_str() == "rustc_peek" {
                            return Some((args, span));
                        }
                    }
                }
            }
        }
    }
    return None;
}
<commit_msg>`mir::dataflow::sanity_check`: extract an `fn each_block` to simplify presentation.<commit_after>// Copyright 2012-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 syntax::abi::{Abi};
use syntax::ast;
use syntax::codemap::Span;

use rustc::ty::{self, TyCtxt};
use rustc::mir::repr::{self, Mir};

use super::super::gather_moves::{MovePath, MovePathIndex};
use super::BitDenotation;
use super::DataflowResults;
use super::HasMoveData;

/// This function scans `mir` for all calls to the intrinsic
/// `rustc_peek` that have the expression form `rustc_peek(&expr)`.
///
/// For each such call, determines what the dataflow bit-state is for
/// the L-value corresponding to `expr`; if the bit-state is a 1, then
/// that call to `rustc_peek` is ignored by the sanity check. If the
/// bit-state is a 0, then this pass emits a error message saying
/// "rustc_peek: bit not set".
///
/// The intention is that one can write unit tests for dataflow by
/// putting code into a compile-fail test and using `rustc_peek` to
/// make observations about the results of dataflow static analyses.
///
/// (If there are any calls to `rustc_peek` that do not match the
/// expression form above, then that emits an error as well, but those
/// errors are not intended to be used for unit tests.)
pub fn sanity_check_via_rustc_peek<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                mir: &Mir<'tcx>,
                                                id: ast::NodeId,
                                                _attributes: &[ast::Attribute],
                                                flow_ctxt: &O::Ctxt,
                                                results: &DataflowResults<O>)
    where O: BitDenotation<Bit=MovePath<'tcx>, Idx=MovePathIndex>, O::Ctxt: HasMoveData<'tcx>
{
    debug!("sanity_check_via_rustc_peek id: {:?}", id);
    // FIXME: this is not DRY. Figure out way to abstract this and
    // `dataflow::build_sets`. (But note it is doing non-standard
    // stuff, so such generalization may not be realistic.)

    let blocks = mir.all_basic_blocks();
    'next_block: for bb in blocks {
        each_block(tcx, mir, flow_ctxt, results, bb);
    }
}

fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           mir: &Mir<'tcx>,
                           flow_ctxt: &O::Ctxt,
                           results: &DataflowResults<O>,
                           bb: repr::BasicBlock) where
    O: BitDenotation<Bit=MovePath<'tcx>, Idx=MovePathIndex>, O::Ctxt: HasMoveData<'tcx>
{
    let bb_data = mir.basic_block_data(bb);
    let &repr::BasicBlockData { ref statements,
                                ref terminator,
                                is_cleanup: _ } = bb_data;

    let (args, span) = match is_rustc_peek(tcx, terminator) {
        Some(args_and_span) => args_and_span,
        None => return,
    };
    assert!(args.len() == 1);
    let peek_arg_lval = match args[0] {
        repr::Operand::Consume(ref lval @ repr::Lvalue::Temp(_)) => {
            lval
        }
        repr::Operand::Consume(_) |
        repr::Operand::Constant(_) => {
            tcx.sess.diagnostic().span_err(
                span, "dataflow::sanity_check cannot feed a non-temp to rustc_peek.");
            return;
        }
    };

    let mut entry = results.0.sets.on_entry_set_for(bb.index()).to_owned();
    let mut gen = results.0.sets.gen_set_for(bb.index()).to_owned();
    let mut kill = results.0.sets.kill_set_for(bb.index()).to_owned();

    let move_data = flow_ctxt.move_data();

    // Emulate effect of all statements in the block up to (but not
    // including) the borrow within `peek_arg_lval`. Do *not* include
    // call to `peek_arg_lval` itself (since we are peeking the state
    // of the argument at time immediate preceding Call to
    // `rustc_peek`).

    let mut sets = super::BlockSets { on_entry: &mut entry,
                                      gen_set: &mut gen,
                                      kill_set: &mut kill };

    for (j, stmt) in statements.iter().enumerate() {
        debug!("rustc_peek: ({:?},{}) {:?}", bb, j, stmt);
        let (lvalue, rvalue) = match stmt.kind {
            repr::StatementKind::Assign(ref lvalue, ref rvalue) => {
                (lvalue, rvalue)
            }
        };

        if lvalue == peek_arg_lval {
            if let repr::Rvalue::Ref(_,
                                     repr::BorrowKind::Shared,
                                     ref peeking_at_lval) = *rvalue {
                // Okay, our search is over.
                let peek_mpi = move_data.rev_lookup.find(peeking_at_lval);
                let bit_state = sets.on_entry.contains(&peek_mpi);
                debug!("rustc_peek({:?} = &{:?}) bit_state: {}",
                       lvalue, peeking_at_lval, bit_state);
                if !bit_state {
                    tcx.sess.span_err(span, &format!("rustc_peek: bit not set"));
                }
                return;
            } else {
                // Our search should have been over, but the input
                // does not match expectations of `rustc_peek` for
                // this sanity_check.
                let msg = &format!("rustc_peek: argument expression \
                                    must be immediate borrow of form `&expr`");
                tcx.sess.span_err(span, msg);
            }
        }

        let lhs_mpi = move_data.rev_lookup.find(lvalue);

        debug!("rustc_peek: computing effect on lvalue: {:?} ({:?}) in stmt: {:?}",
               lvalue, lhs_mpi, stmt);
        // reset GEN and KILL sets before emulating their effect.
        for e in sets.gen_set.words_mut() { *e = 0; }
        for e in sets.kill_set.words_mut() { *e = 0; }
        results.0.operator.statement_effect(flow_ctxt, &mut sets, bb, j);
        sets.on_entry.union(sets.gen_set);
        sets.on_entry.subtract(sets.kill_set);
    }

    tcx.sess.span_err(span, &format!("rustc_peek: MIR did not match \
                                      anticipated pattern; note that \
                                      rustc_peek expects input of \
                                      form `&expr`"));
}

fn is_rustc_peek<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           terminator: &'a Option<repr::Terminator<'tcx>>)
                           -> Option<(&'a [repr::Operand<'tcx>], Span)> {
    if let Some(repr::Terminator { ref kind, span, .. }) = *terminator {
        if let repr::TerminatorKind::Call { func: ref oper, ref args, .. } = *kind
        {
            if let repr::Operand::Constant(ref func) = *oper
            {
                if let ty::TyFnDef(def_id, _, &ty::BareFnTy { abi, .. }) = func.ty.sty
                {
                    let name = tcx.item_name(def_id);
                    if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
                        if name.as_str() == "rustc_peek" {
                            return Some((args, span));
                        }
                    }
                }
            }
        }
    }
    return None;
}
<|endoftext|>


<commit_before>use super::ScalarInt;
use rustc_macros::HashStable;

#[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)]
#[derive(HashStable)]
/// This datastructure is used to represent the value of constants used in the type system.
///
/// We explicitly choose a different datastructure from the way values are processed within
/// CTFE, as in the type system equal values (according to their `PartialEq`) must also have
/// equal representation (`==` on the rustc data structure, e.g. `ValTree`) and vice versa.
/// Since CTFE uses `AllocId` to represent pointers, it often happens that two different
/// `AllocId`s point to equal values. So we may end up with different representations for
/// two constants whose value is `&42`. Furthermore any kind of struct that has padding will
/// have arbitrary values within that padding, even if the values of the struct are the same.
///
/// `ValTree` does not have this problem with representation, as it only contains integers or
/// lists of values of itself.
pub enum ValTree<'tcx> {
    /// ZSTs, integers, `bool`, `char` are represented as scalars.
    /// See the `ScalarInt` documentation for how `ScalarInt` guarantees that equal values
    /// of these types have the same representation.
    Leaf(ScalarInt),
    /// The fields of any kind of aggregate. Structs, tuples and arrays are represented by
    /// listing their fields' values in order.
    /// Enums are represented by storing their discriminant as a field, followed by all
    /// the fields of the variant.
    Branch(&'tcx [ValTree<'tcx>]),
}

impl ValTree<'tcx> {
    pub fn zst() -> Self {
        Self::Branch(&[])
    }
}
<commit_msg>Update compiler/rustc_middle/src/ty/consts/valtree.rs<commit_after>use super::ScalarInt;
use rustc_macros::HashStable;

#[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)]
#[derive(HashStable)]
/// This datastructure is used to represent the value of constants used in the type system.
///
/// We explicitly choose a different datastructure from the way values are processed within
/// CTFE, as in the type system equal values (according to their `PartialEq`) must also have
/// equal representation (`==` on the rustc data structure, e.g. `ValTree`) and vice versa.
/// Since CTFE uses `AllocId` to represent pointers, it often happens that two different
/// `AllocId`s point to equal values. So we may end up with different representations for
/// two constants whose value is `&42`. Furthermore any kind of struct that has padding will
/// have arbitrary values within that padding, even if the values of the struct are the same.
///
/// `ValTree` does not have this problem with representation, as it only contains integers or
/// lists of (nested) `ValTree`.
pub enum ValTree<'tcx> {
    /// ZSTs, integers, `bool`, `char` are represented as scalars.
    /// See the `ScalarInt` documentation for how `ScalarInt` guarantees that equal values
    /// of these types have the same representation.
    Leaf(ScalarInt),
    /// The fields of any kind of aggregate. Structs, tuples and arrays are represented by
    /// listing their fields' values in order.
    /// Enums are represented by storing their discriminant as a field, followed by all
    /// the fields of the variant.
    Branch(&'tcx [ValTree<'tcx>]),
}

impl ValTree<'tcx> {
    pub fn zst() -> Self {
        Self::Branch(&[])
    }
}
<|endoftext|>