<commit_before>//! Management of the directory layout of a build
//!
//! The directory layout is a little tricky at times, hence a separate file to
//! house this logic. The current layout looks like this:
//!
//! ```ignore
//! # This is the root directory for all output, the top-level package
//! # places all of its output here.
//! target/
//!
//!     # This is the root directory for all output of *dependencies*
//!     deps/
//!
//!     # Root directory for all compiled examples
//!     examples/
//!
//!     # This is the location at which the output of all custom build
//!     # commands are rooted
//!     build/
//!
//!         # Each package gets its own directory where its build script and
//!         # script output are placed
//!         $pkg1/
//!         $pkg2/
//!         $pkg3/
//!
//!             # Each directory package has a `out` directory where output
//!             # is placed.
//!             out/
//!
//!     # This is the location at which the output of all old custom build
//!     # commands are rooted
//!     native/
//!
//!         # Each package gets its own directory for where its output is
//!         # placed. We can't track exactly what's getting put in here, so
//!         # we just assume that all relevant output is in these
//!         # directories.
//!         $pkg1/
//!         $pkg2/
//!         $pkg3/
//!
//!     # Directory used to store incremental data for the compiler (when
//!     # incremental is enabled.
//!     incremental/
//!
//!     # Hidden directory that holds all of the fingerprint files for all
//!     # packages
//!     .fingerprint/
//! ```

use std::fs;
use std::io;
use std::path::{PathBuf, Path};

use core::Workspace;
use util::{Config, FileLock, CargoResult, Filesystem};

/// Contains the paths of all target output locations.
///
/// See module docs for more information.
pub struct Layout {
    root: PathBuf,
    deps: PathBuf,
    native: PathBuf,
    build: PathBuf,
    incremental: PathBuf,
    fingerprint: PathBuf,
    examples: PathBuf,
    /// The lockfile for a build, will be unlocked when this struct is `drop`ped.
    _lock: FileLock,
}

pub fn is_bad_artifact_name(name: &str) -> bool {
    ["deps", "examples", "build", "native", "incremental"]
        .iter()
        .any(|&reserved| reserved == name)
}

impl Layout {
    /// Calcuate the paths for build output, lock the build directory, and return as a Layout.
    ///
    /// This function will block if the directory is already locked.
    ///
    /// Differs from `at` in that it calculates the root path from the workspace target directory,
    /// adding the target triple and the profile (debug, release, ...).
    pub fn new(ws: &Workspace,
               triple: Option<&str>,
               dest: &str) -> CargoResult<Layout> {
        let mut path = ws.target_dir();
        // Flexible target specifications often point at filenames, so interpret
        // the target triple as a Path and then just use the file stem as the
        // component for the directory name.
        if let Some(triple) = triple {
            path.push(Path::new(triple).file_stem().ok_or_else(|| "target was empty")?);
        }
        path.push(dest);
        Layout::at(ws.config(), path)
    }

    /// Calcuate the paths for build output, lock the build directory, and return as a Layout.
    ///
    /// This function will block if the directory is already locked.
    pub fn at(config: &Config, root: Filesystem) -> CargoResult<Layout> {
        // For now we don't do any more finer-grained locking on the artifact
        // directory, so just lock the entire thing for the duration of this
        // compile.
        let lock = root.open_rw(".cargo-lock", config, "build directory")?;
        let root = root.into_path_unlocked();

        Ok(Layout {
            deps: root.join("deps"),
            native: root.join("native"),
            build: root.join("build"),
            incremental: root.join("incremental"),
            fingerprint: root.join(".fingerprint"),
            examples: root.join("examples"),
            root: root,
            _lock: lock,
        })
    }

    #[cfg(not(target_os = "macos"))]
    fn exclude_from_backups(&self, _: &Path) {}

    #[cfg(target_os = "macos")]
    /// Marks files or directories as excluded from Time Machine on macOS
    ///
    /// This is recommended to prevent derived/temporary files from bloating backups.
    fn exclude_from_backups(&self, path: &Path) {
        use std::ptr;
        use core_foundation::{url, number, string};
        use core_foundation::base::TCFType;

        // For compatibility with 10.7 a string is used instead of global kCFURLIsExcludedFromBackupKey
        let is_excluded_key: Result<string::CFString, _> = "NSURLIsExcludedFromBackupKey".parse();
        match (url::CFURL::from_path(path, false), is_excluded_key) {
            (Some(path), Ok(is_excluded_key)) => unsafe {
                url::CFURLSetResourcePropertyForKey(
                    path.as_concrete_TypeRef(),
                    is_excluded_key.as_concrete_TypeRef(),
                    number::kCFBooleanTrue as *const _,
                    ptr::null_mut(),
                );
            },
            // Errors are ignored, since it's an optional feature and failure
            // doesn't prevent Cargo from working
            _ => {}
        }
    }

    /// Make sure all directories stored in the Layout exist on the filesystem.
    pub fn prepare(&mut self) -> io::Result<()> {
        if fs::metadata(&self.root).is_err() {
            fs::create_dir_all(&self.root)?;
        }

        self.exclude_from_backups(&self.root);

        mkdir(&self.deps)?;
        mkdir(&self.native)?;
        mkdir(&self.incremental)?;
        mkdir(&self.fingerprint)?;
        mkdir(&self.examples)?;
        mkdir(&self.build)?;

        return Ok(());

        fn mkdir(dir: &Path) -> io::Result<()> {
            if fs::metadata(&dir).is_err() {
                fs::create_dir(dir)?;
            }
            Ok(())
        }
    }

    /// Fetch the root path.
    pub fn dest(&self) -> &Path { &self.root }
    /// Fetch the deps path.
    pub fn deps(&self) -> &Path { &self.deps }
    /// Fetch the examples path.
    pub fn examples(&self) -> &Path { &self.examples }
    /// Fetch the root path.
    pub fn root(&self) -> &Path { &self.root }
    /// Fetch the incremental path.
    pub fn incremental(&self) -> &Path { &self.incremental }
    /// Fetch the fingerprint path.
    pub fn fingerprint(&self) -> &Path { &self.fingerprint }
    /// Fetch the build path.
    pub fn build(&self) -> &Path { &self.build }
}
<commit_msg>Auto merge of #4610 - hdhoang:patch-1, r=alexcrichton<commit_after>//! Management of the directory layout of a build
//!
//! The directory layout is a little tricky at times, hence a separate file to
//! house this logic. The current layout looks like this:
//!
//! ```ignore
//! # This is the root directory for all output, the top-level package
//! # places all of its output here.
//! target/
//!
//!     # This is the root directory for all output of *dependencies*
//!     deps/
//!
//!     # Root directory for all compiled examples
//!     examples/
//!
//!     # This is the location at which the output of all custom build
//!     # commands are rooted
//!     build/
//!
//!         # Each package gets its own directory where its build script and
//!         # script output are placed
//!         $pkg1/
//!         $pkg2/
//!         $pkg3/
//!
//!             # Each directory package has a `out` directory where output
//!             # is placed.
//!             out/
//!
//!     # This is the location at which the output of all old custom build
//!     # commands are rooted
//!     native/
//!
//!         # Each package gets its own directory for where its output is
//!         # placed. We can't track exactly what's getting put in here, so
//!         # we just assume that all relevant output is in these
//!         # directories.
//!         $pkg1/
//!         $pkg2/
//!         $pkg3/
//!
//!     # Directory used to store incremental data for the compiler (when
//!     # incremental is enabled.
//!     incremental/
//!
//!     # Hidden directory that holds all of the fingerprint files for all
//!     # packages
//!     .fingerprint/
//! ```

use std::fs;
use std::io;
use std::path::{PathBuf, Path};

use core::Workspace;
use util::{Config, FileLock, CargoResult, Filesystem};

/// Contains the paths of all target output locations.
///
/// See module docs for more information.
pub struct Layout {
    root: PathBuf,
    deps: PathBuf,
    native: PathBuf,
    build: PathBuf,
    incremental: PathBuf,
    fingerprint: PathBuf,
    examples: PathBuf,
    /// The lockfile for a build, will be unlocked when this struct is `drop`ped.
    _lock: FileLock,
}

pub fn is_bad_artifact_name(name: &str) -> bool {
    ["deps", "examples", "build", "native", "incremental"]
        .iter()
        .any(|&reserved| reserved == name)
}

impl Layout {
    /// Calculate the paths for build output, lock the build directory, and return as a Layout.
    ///
    /// This function will block if the directory is already locked.
    ///
    /// Differs from `at` in that this calculates the root path from the workspace target directory,
    /// adding the target triple and the profile (debug, release, ...).
    pub fn new(ws: &Workspace,
               triple: Option<&str>,
               dest: &str) -> CargoResult<Layout> {
        let mut path = ws.target_dir();
        // Flexible target specifications often point at filenames, so interpret
        // the target triple as a Path and then just use the file stem as the
        // component for the directory name.
        if let Some(triple) = triple {
            path.push(Path::new(triple).file_stem().ok_or_else(|| "target was empty")?);
        }
        path.push(dest);
        Layout::at(ws.config(), path)
    }

    /// Calculate the paths for build output, lock the build directory, and return as a Layout.
    ///
    /// This function will block if the directory is already locked.
    pub fn at(config: &Config, root: Filesystem) -> CargoResult<Layout> {
        // For now we don't do any more finer-grained locking on the artifact
        // directory, so just lock the entire thing for the duration of this
        // compile.
        let lock = root.open_rw(".cargo-lock", config, "build directory")?;
        let root = root.into_path_unlocked();

        Ok(Layout {
            deps: root.join("deps"),
            native: root.join("native"),
            build: root.join("build"),
            incremental: root.join("incremental"),
            fingerprint: root.join(".fingerprint"),
            examples: root.join("examples"),
            root: root,
            _lock: lock,
        })
    }

    #[cfg(not(target_os = "macos"))]
    fn exclude_from_backups(&self, _: &Path) {}

    #[cfg(target_os = "macos")]
    /// Marks files or directories as excluded from Time Machine on macOS
    ///
    /// This is recommended to prevent derived/temporary files from bloating backups.
    fn exclude_from_backups(&self, path: &Path) {
        use std::ptr;
        use core_foundation::{url, number, string};
        use core_foundation::base::TCFType;

        // For compatibility with 10.7 a string is used instead of global kCFURLIsExcludedFromBackupKey
        let is_excluded_key: Result<string::CFString, _> = "NSURLIsExcludedFromBackupKey".parse();
        match (url::CFURL::from_path(path, false), is_excluded_key) {
            (Some(path), Ok(is_excluded_key)) => unsafe {
                url::CFURLSetResourcePropertyForKey(
                    path.as_concrete_TypeRef(),
                    is_excluded_key.as_concrete_TypeRef(),
                    number::kCFBooleanTrue as *const _,
                    ptr::null_mut(),
                );
            },
            // Errors are ignored, since it's an optional feature and failure
            // doesn't prevent Cargo from working
            _ => {}
        }
    }

    /// Make sure all directories stored in the Layout exist on the filesystem.
    pub fn prepare(&mut self) -> io::Result<()> {
        if fs::metadata(&self.root).is_err() {
            fs::create_dir_all(&self.root)?;
        }

        self.exclude_from_backups(&self.root);

        mkdir(&self.deps)?;
        mkdir(&self.native)?;
        mkdir(&self.incremental)?;
        mkdir(&self.fingerprint)?;
        mkdir(&self.examples)?;
        mkdir(&self.build)?;

        return Ok(());

        fn mkdir(dir: &Path) -> io::Result<()> {
            if fs::metadata(&dir).is_err() {
                fs::create_dir(dir)?;
            }
            Ok(())
        }
    }

    /// Fetch the root path.
    pub fn dest(&self) -> &Path { &self.root }
    /// Fetch the deps path.
    pub fn deps(&self) -> &Path { &self.deps }
    /// Fetch the examples path.
    pub fn examples(&self) -> &Path { &self.examples }
    /// Fetch the root path.
    pub fn root(&self) -> &Path { &self.root }
    /// Fetch the incremental path.
    pub fn incremental(&self) -> &Path { &self.incremental }
    /// Fetch the fingerprint path.
    pub fn fingerprint(&self) -> &Path { &self.fingerprint }
    /// Fetch the build path.
    pub fn build(&self) -> &Path { &self.build }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(clippy)]

struct One;

#[deny(len_without_is_empty)]
impl One {
	fn len(self: &Self) -> isize { //~ERROR
		1
	}
}

#[deny(len_without_is_empty)]
trait TraitsToo {
	fn len(self: &Self) -> isize; //~ERROR
}

impl TraitsToo for One {
	fn len(self: &Self) -> isize {
		0
	}
}

#[allow(dead_code)]
struct HasIsEmpty;

#[deny(len_without_is_empty)]
#[allow(dead_code)]
impl HasIsEmpty {
	fn len(self: &Self) -> isize {
		1
	}

	fn is_empty() -> bool {
		false
	}
}

#[deny(len_zero)]
fn main() {
	let x = [1, 2];
	if x.len() == 0 { //~ERROR
		println!("This should not happen!");
	}

	let y = One;
	// false positives here
	if y.len()  == 0 { //~ERROR
		println!("This should not happen either!");
	}

	let z : &TraitsToo = &y;
	if z.len() > 0 { //~ERROR
		println!("Nor should this!");
	}
}
<commit_msg>added messages to test error comments<commit_after>#![feature(plugin)]
#![plugin(clippy)]

struct One;

#[deny(len_without_is_empty)]
impl One {
	fn len(self: &Self) -> isize { //~ERROR Item 'One' has a '.len()' method
		1
	}
}

#[deny(len_without_is_empty)]
trait TraitsToo {
	fn len(self: &Self) -> isize; //~ERROR Trait 'TraitsToo' has a '.len()' method,
}

impl TraitsToo for One {
	fn len(self: &Self) -> isize {
		0
	}
}

#[allow(dead_code)]
struct HasIsEmpty;

#[deny(len_without_is_empty)]
#[allow(dead_code)]
impl HasIsEmpty {
	fn len(self: &Self) -> isize {
		1
	}

	fn is_empty() -> bool {
		false
	}
}

#[deny(len_zero)]
fn main() {
	let x = [1, 2];
	if x.len() == 0 { //~ERROR Consider replacing the len comparison
		println!("This should not happen!");
	}

	let y = One;
	// false positives here
	if y.len()  == 0 { //~ERROR Consider replacing the len comparison
		println!("This should not happen either!");
	}

	let z : &TraitsToo = &y;
	if z.len() > 0 { //~ERROR Consider replacing the len comparison
		println!("Nor should this!");
	}
}
<|endoftext|>


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

use get_if_addrs::get_if_addrs;
use parity_multiaddr::{Multiaddr, Protocol};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::{
    collections::HashSet,
    hash::BuildHasher,
    net::{IpAddr, TcpListener, TcpStream},
};
use types::transaction::SCRIPT_HASH_LENGTH;

/// Return an ephemeral, available port. On unix systems, the port returned will be in the
/// TIME_WAIT state ensuring that the OS won't hand out this port for some grace period.
/// Callers should be able to bind to this port given they use SO_REUSEADDR.
pub fn get_available_port() -> u16 {
    const MAX_PORT_RETRIES: u32 = 1000;

    for _ in 0..MAX_PORT_RETRIES {
        if let Ok(port) = get_ephemeral_port() {
            return port;
        }
    }

    panic!("Error: could not find an available port");
}

fn get_ephemeral_port() -> ::std::io::Result<u16> {
    // Request a random available port from the OS
    let listener = TcpListener::bind(("localhost", 0))?;
    let addr = listener.local_addr()?;

    // Create and accept a connection (which we'll promptly drop) in order to force the port
    // into the TIME_WAIT state, ensuring that the port will be reserved from some limited
    // amount of time (roughly 60s on some Linux systems)
    let _sender = TcpStream::connect(addr)?;
    let _incoming = listener.accept()?;

    Ok(addr.port())
}

/// Extracts one local non-loopback IP address, if one exists. Otherwise returns None.
pub fn get_local_ip() -> Option<Multiaddr> {
    get_if_addrs().ok().and_then(|if_addrs| {
        if_addrs
            .into_iter()
            .filter(|if_addr| !if_addr.is_loopback())
            .nth(0)
            .and_then(|if_addr| {
                let mut addr = Multiaddr::empty();
                match if_addr.ip() {
                    IpAddr::V4(a) => {
                        addr.push(Protocol::Ip4(a));
                    }
                    IpAddr::V6(a) => {
                        addr.push(Protocol::Ip6(a));
                    }
                }
                Some(addr)
            })
    })
}

pub fn deserialize_whitelist<'de, D>(
    deserializer: D,
) -> ::std::result::Result<HashSet<[u8; SCRIPT_HASH_LENGTH]>, D::Error>
where
    D: Deserializer<'de>,
{
    let whitelisted_scripts: Vec<String> = Deserialize::deserialize(deserializer)?;
    let whitelist = whitelisted_scripts
        .iter()
        .map(|s| {
            let mut hash = [0u8; SCRIPT_HASH_LENGTH];
            let decoded_hash =
                hex::decode(s).expect("Unable to decode script hash from configuration file.");
            assert_eq!(decoded_hash.len(), SCRIPT_HASH_LENGTH);
            hash.copy_from_slice(decoded_hash.as_slice());
            hash
        })
        .collect();
    Ok(whitelist)
}

pub fn serialize_whitelist<S, H>(
    whitelist: &HashSet<[u8; SCRIPT_HASH_LENGTH], H>,
    serializer: S,
) -> Result<S::Ok, S::Error>
where
    S: Serializer,
    H: BuildHasher,
{
    let encoded_whitelist: Vec<String> = whitelist.iter().map(hex::encode).collect();
    encoded_whitelist.serialize(serializer)
}
<commit_msg>Rewrite `.filter(..).nth(0)` to `.find(..)`<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use get_if_addrs::get_if_addrs;
use parity_multiaddr::{Multiaddr, Protocol};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::{
    collections::HashSet,
    hash::BuildHasher,
    net::{IpAddr, TcpListener, TcpStream},
};
use types::transaction::SCRIPT_HASH_LENGTH;

/// Return an ephemeral, available port. On unix systems, the port returned will be in the
/// TIME_WAIT state ensuring that the OS won't hand out this port for some grace period.
/// Callers should be able to bind to this port given they use SO_REUSEADDR.
pub fn get_available_port() -> u16 {
    const MAX_PORT_RETRIES: u32 = 1000;

    for _ in 0..MAX_PORT_RETRIES {
        if let Ok(port) = get_ephemeral_port() {
            return port;
        }
    }

    panic!("Error: could not find an available port");
}

fn get_ephemeral_port() -> ::std::io::Result<u16> {
    // Request a random available port from the OS
    let listener = TcpListener::bind(("localhost", 0))?;
    let addr = listener.local_addr()?;

    // Create and accept a connection (which we'll promptly drop) in order to force the port
    // into the TIME_WAIT state, ensuring that the port will be reserved from some limited
    // amount of time (roughly 60s on some Linux systems)
    let _sender = TcpStream::connect(addr)?;
    let _incoming = listener.accept()?;

    Ok(addr.port())
}

/// Extracts one local non-loopback IP address, if one exists. Otherwise returns None.
pub fn get_local_ip() -> Option<Multiaddr> {
    get_if_addrs().ok().and_then(|if_addrs| {
        if_addrs
            .into_iter()
            .find(|if_addr| !if_addr.is_loopback())
            .and_then(|if_addr| {
                let mut addr = Multiaddr::empty();
                match if_addr.ip() {
                    IpAddr::V4(a) => {
                        addr.push(Protocol::Ip4(a));
                    }
                    IpAddr::V6(a) => {
                        addr.push(Protocol::Ip6(a));
                    }
                }
                Some(addr)
            })
    })
}

pub fn deserialize_whitelist<'de, D>(
    deserializer: D,
) -> ::std::result::Result<HashSet<[u8; SCRIPT_HASH_LENGTH]>, D::Error>
where
    D: Deserializer<'de>,
{
    let whitelisted_scripts: Vec<String> = Deserialize::deserialize(deserializer)?;
    let whitelist = whitelisted_scripts
        .iter()
        .map(|s| {
            let mut hash = [0u8; SCRIPT_HASH_LENGTH];
            let decoded_hash =
                hex::decode(s).expect("Unable to decode script hash from configuration file.");
            assert_eq!(decoded_hash.len(), SCRIPT_HASH_LENGTH);
            hash.copy_from_slice(decoded_hash.as_slice());
            hash
        })
        .collect();
    Ok(whitelist)
}

pub fn serialize_whitelist<S, H>(
    whitelist: &HashSet<[u8; SCRIPT_HASH_LENGTH], H>,
    serializer: S,
) -> Result<S::Ok, S::Error>
where
    S: Serializer,
    H: BuildHasher,
{
    let encoded_whitelist: Vec<String> = whitelist.iter().map(hex::encode).collect();
    encoded_whitelist.serialize(serializer)
}
<|endoftext|>


<commit_before>use crate::rpc::{RPCEvent, RPCMessage, Rpc};
use crate::NetworkConfig;
use futures::prelude::*;
use libp2p::{
    core::{
        swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess},
        PublicKey,
    },
    gossipsub::{Gossipsub, GossipsubEvent},
    identify::{protocol::IdentifyInfo, Identify, IdentifyEvent},
    tokio_io::{AsyncRead, AsyncWrite},
    NetworkBehaviour, PeerId,
};
use types::Topic;

/// Builds the network behaviour for the libp2p Swarm.
/// Implements gossipsub message routing.
#[derive(NetworkBehaviour)]
#[behaviour(out_event = "BehaviourEvent", poll_method = "poll")]
pub struct Behaviour<TSubstream: AsyncRead + AsyncWrite> {
    /// The routing pub-sub mechanism for eth2.
    gossipsub: Gossipsub<TSubstream>,
    // TODO: Add Kademlia for peer discovery
    /// The events generated by this behaviour to be consumed in the swarm poll.
    serenity_rpc: Rpc<TSubstream>,
    /// Allows discovery of IP addresses for peers on the network.
    identify: Identify<TSubstream>,
    #[behaviour(ignore)]
    events: Vec<BehaviourEvent>,
}

// Implement the NetworkBehaviourEventProcess trait so that we can derive NetworkBehaviour for Behaviour
impl<TSubstream: AsyncRead + AsyncWrite> NetworkBehaviourEventProcess<GossipsubEvent>
    for Behaviour<TSubstream>
{
    fn inject_event(&mut self, event: GossipsubEvent) {
        match event {
            GossipsubEvent::Message(message) => {
                let gs_message = String::from_utf8_lossy(&message.data);
                // TODO: Remove this type - debug only
                self.events
                    .push(BehaviourEvent::Message(gs_message.to_string()))
            }
            _ => {}
        }
    }
}

impl<TSubstream: AsyncRead + AsyncWrite> NetworkBehaviourEventProcess<RPCMessage>
    for Behaviour<TSubstream>
{
    fn inject_event(&mut self, event: RPCMessage) {
        match event {
            RPCMessage::PeerDialed(peer_id) => {
                self.events.push(BehaviourEvent::PeerDialed(peer_id))
            }
            RPCMessage::RPC(peer_id, rpc_event) => {
                self.events.push(BehaviourEvent::RPC(peer_id, rpc_event))
            }
        }
    }
}

impl<TSubstream: AsyncRead + AsyncWrite> NetworkBehaviourEventProcess<IdentifyEvent>
    for Behaviour<TSubstream>
{
    fn inject_event(&mut self, event: IdentifyEvent) {
        match event {
            IdentifyEvent::Identified {
                peer_id, mut info, ..
            } => {
                if info.listen_addrs.len() > 20 {
                    info.listen_addrs.truncate(20);
                }
                self.events.push(BehaviourEvent::Identified(peer_id, info));
            }
            IdentifyEvent::Error { .. } => {}
            IdentifyEvent::SendBack { .. } => {}
        }
    }
}

impl<TSubstream: AsyncRead + AsyncWrite> Behaviour<TSubstream> {
    pub fn new(local_public_key: PublicKey, net_conf: &NetworkConfig, log: &slog::Logger) -> Self {
        let local_peer_id = local_public_key.clone().into_peer_id();
        let identify_config = net_conf.identify_config.clone();

        Behaviour {
            gossipsub: Gossipsub::new(local_peer_id, net_conf.gs_config.clone()),
            serenity_rpc: Rpc::new(log),
            identify: Identify::new(
                identify_config.version,
                identify_config.user_agent,
                local_public_key,
            ),
            events: Vec::new(),
        }
    }

    /// Consumes the events list when polled.
    fn poll<TBehaviourIn>(
        &mut self,
    ) -> Async<NetworkBehaviourAction<TBehaviourIn, BehaviourEvent>> {
        if !self.events.is_empty() {
            return Async::Ready(NetworkBehaviourAction::GenerateEvent(self.events.remove(0)));
        }

        Async::NotReady
    }
}

/// Implements the combined behaviour for the libp2p service.
impl<TSubstream: AsyncRead + AsyncWrite> Behaviour<TSubstream> {
    /// Subscribes to a gossipsub topic.
    pub fn subscribe(&mut self, topic: Topic) -> bool {
        self.gossipsub.subscribe(topic)
    }

    /// Sends an RPC Request/Response via the RPC protocol.
    pub fn send_rpc(&mut self, peer_id: PeerId, rpc_event: RPCEvent) {
        self.serenity_rpc.send_rpc(peer_id, rpc_event);
    }
}

/// The types of events than can be obtained from polling the behaviour.
pub enum BehaviourEvent {
    RPC(PeerId, RPCEvent),
    PeerDialed(PeerId),
    Identified(PeerId, IdentifyInfo),
    // TODO: This is a stub at the moment
    Message(String),
}
<commit_msg>Add logging to libp2p behaviour<commit_after>use crate::rpc::{RPCEvent, RPCMessage, Rpc};
use crate::NetworkConfig;
use futures::prelude::*;
use libp2p::{
    core::{
        swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess},
        PublicKey,
    },
    gossipsub::{Gossipsub, GossipsubEvent},
    identify::{protocol::IdentifyInfo, Identify, IdentifyEvent},
    tokio_io::{AsyncRead, AsyncWrite},
    NetworkBehaviour, PeerId,
};
use slog::{debug, o};
use types::Topic;

/// Builds the network behaviour for the libp2p Swarm.
/// Implements gossipsub message routing.
#[derive(NetworkBehaviour)]
#[behaviour(out_event = "BehaviourEvent", poll_method = "poll")]
pub struct Behaviour<TSubstream: AsyncRead + AsyncWrite> {
    /// The routing pub-sub mechanism for eth2.
    gossipsub: Gossipsub<TSubstream>,
    // TODO: Add Kademlia for peer discovery
    /// The events generated by this behaviour to be consumed in the swarm poll.
    serenity_rpc: Rpc<TSubstream>,
    /// Allows discovery of IP addresses for peers on the network.
    identify: Identify<TSubstream>,
    #[behaviour(ignore)]
    events: Vec<BehaviourEvent>,
    #[behaviour(ignore)]
    /// Logger for behaviour actions.
    log: slog::Logger,
}

// Implement the NetworkBehaviourEventProcess trait so that we can derive NetworkBehaviour for Behaviour
impl<TSubstream: AsyncRead + AsyncWrite> NetworkBehaviourEventProcess<GossipsubEvent>
    for Behaviour<TSubstream>
{
    fn inject_event(&mut self, event: GossipsubEvent) {
        match event {
            GossipsubEvent::Message(message) => {
                let gs_message = String::from_utf8_lossy(&message.data);
                // TODO: Remove this type - debug only
                self.events
                    .push(BehaviourEvent::Message(gs_message.to_string()))
            }
            _ => {}
        }
    }
}

impl<TSubstream: AsyncRead + AsyncWrite> NetworkBehaviourEventProcess<RPCMessage>
    for Behaviour<TSubstream>
{
    fn inject_event(&mut self, event: RPCMessage) {
        match event {
            RPCMessage::PeerDialed(peer_id) => {
                self.events.push(BehaviourEvent::PeerDialed(peer_id))
            }
            RPCMessage::RPC(peer_id, rpc_event) => {
                self.events.push(BehaviourEvent::RPC(peer_id, rpc_event))
            }
        }
    }
}

impl<TSubstream: AsyncRead + AsyncWrite> NetworkBehaviourEventProcess<IdentifyEvent>
    for Behaviour<TSubstream>
{
    fn inject_event(&mut self, event: IdentifyEvent) {
        match event {
            IdentifyEvent::Identified {
                peer_id, mut info, ..
            } => {
                if info.listen_addrs.len() > 20 {
                    debug!(
                        self.log,
                        "More than 20 peers have been identified, truncating"
                    );
                    info.listen_addrs.truncate(20);
                }
                self.events.push(BehaviourEvent::Identified(peer_id, info));
            }
            IdentifyEvent::Error { .. } => {}
            IdentifyEvent::SendBack { .. } => {}
        }
    }
}

impl<TSubstream: AsyncRead + AsyncWrite> Behaviour<TSubstream> {
    pub fn new(local_public_key: PublicKey, net_conf: &NetworkConfig, log: &slog::Logger) -> Self {
        let local_peer_id = local_public_key.clone().into_peer_id();
        let identify_config = net_conf.identify_config.clone();
        let behaviour_log = log.new(o!());

        Behaviour {
            gossipsub: Gossipsub::new(local_peer_id, net_conf.gs_config.clone()),
            serenity_rpc: Rpc::new(log),
            identify: Identify::new(
                identify_config.version,
                identify_config.user_agent,
                local_public_key,
            ),
            events: Vec::new(),
            log: behaviour_log,
        }
    }

    /// Consumes the events list when polled.
    fn poll<TBehaviourIn>(
        &mut self,
    ) -> Async<NetworkBehaviourAction<TBehaviourIn, BehaviourEvent>> {
        if !self.events.is_empty() {
            return Async::Ready(NetworkBehaviourAction::GenerateEvent(self.events.remove(0)));
        }

        Async::NotReady
    }
}

/// Implements the combined behaviour for the libp2p service.
impl<TSubstream: AsyncRead + AsyncWrite> Behaviour<TSubstream> {
    /// Subscribes to a gossipsub topic.
    pub fn subscribe(&mut self, topic: Topic) -> bool {
        self.gossipsub.subscribe(topic)
    }

    /// Sends an RPC Request/Response via the RPC protocol.
    pub fn send_rpc(&mut self, peer_id: PeerId, rpc_event: RPCEvent) {
        self.serenity_rpc.send_rpc(peer_id, rpc_event);
    }
}

/// The types of events than can be obtained from polling the behaviour.
pub enum BehaviourEvent {
    RPC(PeerId, RPCEvent),
    PeerDialed(PeerId),
    Identified(PeerId, IdentifyInfo),
    // TODO: This is a stub at the moment
    Message(String),
}
<|endoftext|>


<commit_before>use std::thread;
use std::sync::mpsc;
use websocket;
use websocket::{Message, Sender, Receiver};
use websocket::server::sender;
use websocket::stream::WebSocketStream;
use websocket::message::CloseData;
use std::io::prelude::*;
use std::fs::{OpenOptions};
use std::net::Shutdown;
use rustc_serialize::json::{Json, ToJson};
use cbor;
use hyper::header::Cookie;

use value::Value;
use relation::Change;
use flow::{Changes, Flow};

// The server manages a single Eve program and handles communication with the editor and clients
// TODO needs review / refactoring, especially session handling

pub struct Server {
    pub flow: Flow,
    pub senders: Vec<sender::Sender<WebSocketStream>>,
}

#[derive(Debug, Clone)]
pub struct Event {
    pub changes: Changes,
    pub session: String,
    // commands that affect the whole program state have to go through this side-channel rather than being added to a view
    pub commands: Vec<Vec<String>>,
}

pub enum ServerEvent {
    Change(Vec<u8>),
    Sync((sender::Sender<WebSocketStream>, Option<String>)),
    Terminate(Option<CloseData>),
}

// --- json encodings ---

pub trait FromJson {
    fn from_json(json: &Json) -> Self;
}

impl ToJson for Value {
    fn to_json(&self) -> Json {
        match *self {
            Value::Null => panic!("Cannot allow the client to see nulls"),
            Value::Bool(bool) => Json::Boolean(bool),
            Value::String(ref string) => Json::String(string.clone()),
            Value::Float(float) => Json::F64(float),
            Value::Column(ref column) => Json::Array(column.iter().map(|v| v.to_json()).collect()),
        }
    }
}

impl FromJson for Value {
    fn from_json(json: &Json) -> Self {
        match *json {
            Json::Boolean(bool) => Value::Bool(bool),
            Json::String(ref string) => Value::String(string.clone()),
            Json::F64(float) => Value::Float(float),
            Json::I64(int) => Value::Float(int as f64),
            Json::U64(uint) => Value::Float(uint as f64),
            Json::Array(ref array) => Value::Column(array.iter().map(FromJson::from_json).collect()),
            _ => panic!("Cannot decode {:?} as Value", json),
        }
    }
}

impl FromJson for String {
    fn from_json(json: &Json) -> Self {
        json.as_string().unwrap().to_owned()
    }
}

impl<T: FromJson> FromJson for Vec<T> {
    fn from_json(json: &Json) -> Self {
        json.as_array().unwrap().iter().map(|t| FromJson::from_json(t)).collect()
    }
}

impl ToJson for Event {
    fn to_json(&self) -> Json {
        Json::Object(vec![
            ("changes".to_string(), Json::Array(
                self.changes.iter().map(|&(ref view_id, ref view_changes)| {
                    Json::Array(vec![
                        view_id.to_json(),
                        view_changes.fields.to_json(),
                        view_changes.insert.to_json(),
                        view_changes.remove.to_json(),
                        ])
                }).collect()
                )
            ),
            ("session".to_string(), self.session.to_json()),
            ("commands".to_string(), self.commands.to_json()),
        ].into_iter().collect())
    }
}

impl FromJson for Event {
    fn from_json(json: &Json) -> Self {
        Event{
            changes: json.as_object().unwrap()["changes"]
            .as_array().unwrap().iter().map(|change| {
                let change = change.as_array().unwrap();
                assert_eq!(change.len(), 4);
                let view_id = FromJson::from_json(&change[0]);
                let fields = FromJson::from_json(&change[1]);
                let insert = FromJson::from_json(&change[2]);
                let remove = FromJson::from_json(&change[3]);
                (view_id, Change{fields:fields, insert: insert, remove: remove})
            }).collect(),
            session: "".to_string(),
            commands: FromJson::from_json(json.as_object().unwrap().get("commands").unwrap_or(&Json::Array(vec![]))),
        }
    }
}

// --- persistence ---

pub fn read_file(filename: &str) -> String {
    let mut file = OpenOptions::new().create(true).open(filename).unwrap();
    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();
    contents
}

pub fn write_file(filename: &str, contents: &str) {
    let mut file = OpenOptions::new().create(true).truncate(true).write(true).open(filename).unwrap();
    file.write_all(contents.as_bytes()).unwrap();
}

pub fn load(flow: &mut Flow, filename: &str) {
    for line in read_file(filename).lines() {
        let json = Json::from_str(&line).unwrap();
        let event: Event = FromJson::from_json(&json);
        flow.quiesce(event.changes);
    }
}

// TODO should probably just save changes, not the whole event
pub fn save(flow: &Flow, filename: &str) {
    let changes = flow.as_changes();
    let text = format!("{}", Event{changes: changes, session: "".to_owned(), commands: vec![]}.to_json());
    write_file(filename, &text[..]);
}

// --- server ---

pub fn send_event(server: &mut Server, changes: &Changes, commands: &Vec<Vec<String>>) {
    for sender in server.senders.iter_mut() {
        let session_id = format!("{}", sender.get_mut().peer_addr().unwrap());
        let event = Event{changes: changes.clone(), session: session_id, commands: commands.clone()};
        let text = format!("{}", event.to_json());
        match sender.send_message(Message::Text(text)) {
            Ok(_) => (),
            Err(error) => println!("Send error: {}", error),
        };
    }
}

pub fn get_user_id(cookies: Option<&Cookie>) -> Option<String> {
    match cookies {
        Some(cookies) => {
            match cookies.iter().find(|cookie| cookie.name == "userid") {
                Some(user_id) => Some(user_id.value.clone()),
                None => None,
            }
        },
        None => None,
    }
}

// rust-websocket is blocking, so we have to spawn a thread per connection
// each thread sends events back to a central channel
pub fn server_events() -> mpsc::Receiver<ServerEvent> {
    let (event_sender, event_receiver) = mpsc::channel();
    thread::spawn(move || {
        let server = websocket::Server::bind("0.0.0.0:2794").unwrap();
        for connection in server {
            let event_sender = event_sender.clone();
            thread::spawn(move || {
                // accept request
                let request = connection.unwrap().read_request().unwrap();
                request.validate().unwrap();

                // get the User ID from a cookie in the headers
                let user_id = get_user_id(request.headers.get::<Cookie>());

                let response = request.accept();
                let (mut sender, mut receiver) = response.send().unwrap().split();

                let ip = sender.get_mut().peer_addr().unwrap();
                println!("Connection from {}", ip);
                ::std::io::stdout().flush().unwrap(); // TODO is this actually necessary?

                // hand over the sender
                event_sender.send(ServerEvent::Sync((sender,user_id))).unwrap();

                // handle messages
                for message in receiver.incoming_messages() {
                    let message = match message {
                        Ok(m) => m,
                        Err(_) => return,
                    };
                    match message {
                        Message::Binary(bytes) => {
                            event_sender.send(ServerEvent::Change(bytes)).unwrap();
                        }
                        Message::Close(_) => {
                            let ip_addr = format!("{}", ip);
                            println!("Received close message from {}.",ip_addr);
                            let close_message = CloseData{status_code: 0, reason: ip_addr};
                            event_sender.send(ServerEvent::Terminate(Some(close_message))).unwrap();
                        }
                        _ => println!("Unknown message: {:?}", message)
                    }
                }
            });
        }
    });
    event_receiver
}

pub fn handle_event(server: &mut Server, event: Event, event_json: Json) {
    // save the event
    {
        let mut autosave = OpenOptions::new().write(true).append(true).open("./autosave").unwrap();
        autosave.write_all(format!("{}", event_json).as_bytes()).unwrap();
        autosave.write_all("\n".as_bytes()).unwrap();
        autosave.flush().unwrap();
    }

    // copy the old flow so we can compare to the new flow for changes
    let old_flow = server.flow.clone();

    // run the flow until it reaches fixpoint
    server.flow.quiesce(event.changes);

    // handle commands
    for command in event.commands.iter() {
        let borrowed_words = command.iter().map(|word| &word[..]).collect::<Vec<_>>();
        match &borrowed_words[..] {
            ["load", filename] => {
                server.flow = Flow::new();
                load(&mut server.flow, "./bootstrap");
                load(&mut server.flow, filename);
                save(&server.flow, "./autosave");
                let current_dir = ::std::env::current_dir().unwrap().to_str().unwrap().to_owned();
                send_event(server, &vec![], &vec![
                    vec!["loaded".to_owned(), current_dir, filename.to_owned()]
                    ]);
            }
            ["save", filename] => {
                save(&server.flow, filename);
                let current_dir = ::std::env::current_dir().unwrap().to_str().unwrap().to_owned();
                send_event(server, &vec![], &vec![
                    vec!["saved".to_owned(), current_dir, filename.to_owned()]
                    ]);
            }
            ["get events", id] => {
                let events_string = read_file("./autosave");
                send_event(server, &vec![], &vec![
                    vec!["events got".to_owned(), id.to_owned(), events_string]
                    ]);
            }
            ["set events", id, events_string] => {
                write_file("./autosave", events_string);
                server.flow = Flow::new();
                load(&mut server.flow, "./bootstrap");
                load(&mut server.flow, "./autosave");
                send_event(server, &vec![], &vec![
                    vec!["events set".to_owned(), id.to_owned()]
                    ]);
            }
            other => panic!("Unknown command: {:?}", other),
        }
    }

    let changes = &server.flow.changes_from(old_flow);
    send_event(server, changes, &vec![]);
}

pub fn run() {
    let mut flow = Flow::new();
    time!("reading saved state", {
        load(&mut flow, "./bootstrap");
        load(&mut flow, "./autosave");
    });

    let senders: Vec<sender::Sender<WebSocketStream>> = Vec::new();

    let mut server = Server{flow: flow, senders: senders};

    for server_event in server_events() {
        match server_event {

            // a new client has connected and needs to sync its state
            ServerEvent::Sync((mut sender, user_id)) => {
                let mut changes = vec![];

                // add a session to the session table
                let session_id = format!("{}", sender.get_mut().peer_addr().unwrap());
                changes.push(("sessions".to_owned(),
                    Change{
                        fields: vec!["sessions: id".to_owned(), "sessions: status".to_owned()],
                        insert: vec![vec![Value::String(session_id.clone()), Value::Float(1f64)]],
                        remove: vec![],
                    }));

                // if we have a user ID, add a mapping from the session ID to the user ID
                if let Some(user_id) = user_id {
                    changes.push(("session id to user id".to_owned(),
                        Change{
                            fields: vec!["session id to user id: session id".to_owned(), "session id to user id: user id".to_owned()],
                            insert: vec![vec![Value::String(session_id.clone()), Value::String(user_id)]],
                            remove: vec![]
                        }));
                }

                // handle the session change
                let event = Event{changes: changes, session: session_id.clone(), commands: vec![]};
                let json = event.to_json();
                handle_event(&mut server, event, json);

                // sync the new client
                let changes = server.flow.as_changes();
                let event = Event{changes: changes, session: session_id, commands: vec![]};
                let text = format!("{}", event.to_json());
                match sender.send_message(Message::Text(text)) {
                    Ok(_) => (),
                    Err(error) => println!("Send error: {}", error),
                };
                server.senders.push(sender)
            }

            // an existing client has sent a new message
            ServerEvent::Change(input_bytes) => {
                // TODO we throw cbor in here to avoid https://github.com/rust-lang/rustc-serialize/issues/113
                let mut decoder = cbor::Decoder::from_bytes(&input_bytes[..]);
                let cbor = decoder.items().next().unwrap().unwrap();
                let json = cbor.to_json();
                let event = FromJson::from_json(&json);
                handle_event(&mut server, event, json);
            }

            ServerEvent::Terminate(m) => {
                let terminate_ip = m.unwrap().reason;
                println!("Closing connection from {}...",terminate_ip);

                // find the index of the connection's sender
                let ip_ix = server.senders.iter_mut().position(|mut sender| {
                    let ip = format!("{}",sender.get_mut().peer_addr().unwrap());
                    ip == terminate_ip
                });

                match ip_ix {
                    Some(ix) => {
                        // close the connection
                        let _ = server.senders[ix].send_message(Message::Close(None));
                        match server.senders[ix].get_mut().shutdown(Shutdown::Both) {
                            Ok(_) => println!("Connection from {} has closed successfully.",terminate_ip),
                            Err(e) => println!("Connection from {} failed to shut down properly: {}",terminate_ip,e),
                        }
                        server.senders.remove(ix);

                        // update the session table
                        let sessions = server.flow.get_output("sessions").clone();
                        let ip_string = Value::String(terminate_ip.clone());

                        // change the session status to 0
                        for row in sessions.find(vec![&ip_string, &Value::Null]) {
                            match row {
                                [_, ref status] => {
                                    let change = Change {
                                        fields: sessions.fields.clone(),
                                        insert: vec![vec![ip_string.clone(), Value::Float(0f64)]],
                                        remove: vec![vec![ip_string.clone(), status.clone()]],
                                    };
                                    let event = Event{changes: vec![("sessions".to_string(),change)], session: "".to_string(), commands: vec![]};
                                    let json = event.to_json();
                                    handle_event(&mut server, event, json);
                                }
                                _ => unreachable!(),
                            }
                        }

                    },
                    None => panic!("IP address {} is not connected",terminate_ip),
                }
            }
        }
    }
}<commit_msg>Fix server sending commands and command-initiated diffs separately. fix #164<commit_after>use std::thread;
use std::sync::mpsc;
use websocket;
use websocket::{Message, Sender, Receiver};
use websocket::server::sender;
use websocket::stream::WebSocketStream;
use websocket::message::CloseData;
use std::io::prelude::*;
use std::fs::{OpenOptions};
use std::net::Shutdown;
use rustc_serialize::json::{Json, ToJson};
use cbor;
use hyper::header::Cookie;

use value::Value;
use relation::Change;
use flow::{Changes, Flow};

// The server manages a single Eve program and handles communication with the editor and clients
// TODO needs review / refactoring, especially session handling

pub struct Server {
    pub flow: Flow,
    pub senders: Vec<sender::Sender<WebSocketStream>>,
}

#[derive(Debug, Clone)]
pub struct Event {
    pub changes: Changes,
    pub session: String,
    // commands that affect the whole program state have to go through this side-channel rather than being added to a view
    pub commands: Vec<Vec<String>>,
}

pub enum ServerEvent {
    Change(Vec<u8>),
    Sync((sender::Sender<WebSocketStream>, Option<String>)),
    Terminate(Option<CloseData>),
}

// --- json encodings ---

pub trait FromJson {
    fn from_json(json: &Json) -> Self;
}

impl ToJson for Value {
    fn to_json(&self) -> Json {
        match *self {
            Value::Null => panic!("Cannot allow the client to see nulls"),
            Value::Bool(bool) => Json::Boolean(bool),
            Value::String(ref string) => Json::String(string.clone()),
            Value::Float(float) => Json::F64(float),
            Value::Column(ref column) => Json::Array(column.iter().map(|v| v.to_json()).collect()),
        }
    }
}

impl FromJson for Value {
    fn from_json(json: &Json) -> Self {
        match *json {
            Json::Boolean(bool) => Value::Bool(bool),
            Json::String(ref string) => Value::String(string.clone()),
            Json::F64(float) => Value::Float(float),
            Json::I64(int) => Value::Float(int as f64),
            Json::U64(uint) => Value::Float(uint as f64),
            Json::Array(ref array) => Value::Column(array.iter().map(FromJson::from_json).collect()),
            _ => panic!("Cannot decode {:?} as Value", json),
        }
    }
}

impl FromJson for String {
    fn from_json(json: &Json) -> Self {
        json.as_string().unwrap().to_owned()
    }
}

impl<T: FromJson> FromJson for Vec<T> {
    fn from_json(json: &Json) -> Self {
        json.as_array().unwrap().iter().map(|t| FromJson::from_json(t)).collect()
    }
}

impl ToJson for Event {
    fn to_json(&self) -> Json {
        Json::Object(vec![
            ("changes".to_string(), Json::Array(
                self.changes.iter().map(|&(ref view_id, ref view_changes)| {
                    Json::Array(vec![
                        view_id.to_json(),
                        view_changes.fields.to_json(),
                        view_changes.insert.to_json(),
                        view_changes.remove.to_json(),
                        ])
                }).collect()
                )
            ),
            ("session".to_string(), self.session.to_json()),
            ("commands".to_string(), self.commands.to_json()),
        ].into_iter().collect())
    }
}

impl FromJson for Event {
    fn from_json(json: &Json) -> Self {
        Event{
            changes: json.as_object().unwrap()["changes"]
            .as_array().unwrap().iter().map(|change| {
                let change = change.as_array().unwrap();
                assert_eq!(change.len(), 4);
                let view_id = FromJson::from_json(&change[0]);
                let fields = FromJson::from_json(&change[1]);
                let insert = FromJson::from_json(&change[2]);
                let remove = FromJson::from_json(&change[3]);
                (view_id, Change{fields:fields, insert: insert, remove: remove})
            }).collect(),
            session: "".to_string(),
            commands: FromJson::from_json(json.as_object().unwrap().get("commands").unwrap_or(&Json::Array(vec![]))),
        }
    }
}

// --- persistence ---

pub fn read_file(filename: &str) -> String {
    let mut file = OpenOptions::new().create(true).open(filename).unwrap();
    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();
    contents
}

pub fn write_file(filename: &str, contents: &str) {
    let mut file = OpenOptions::new().create(true).truncate(true).write(true).open(filename).unwrap();
    file.write_all(contents.as_bytes()).unwrap();
}

pub fn load(flow: &mut Flow, filename: &str) {
    for line in read_file(filename).lines() {
        let json = Json::from_str(&line).unwrap();
        let event: Event = FromJson::from_json(&json);
        flow.quiesce(event.changes);
    }
}

// TODO should probably just save changes, not the whole event
pub fn save(flow: &Flow, filename: &str) {
    let changes = flow.as_changes();
    let text = format!("{}", Event{changes: changes, session: "".to_owned(), commands: vec![]}.to_json());
    write_file(filename, &text[..]);
}

// --- server ---

pub fn send_event(server: &mut Server, changes: &Changes, commands: &Vec<Vec<String>>) {
    for sender in server.senders.iter_mut() {
        let session_id = format!("{}", sender.get_mut().peer_addr().unwrap());
        let event = Event{changes: changes.clone(), session: session_id, commands: commands.clone()};
        let text = format!("{}", event.to_json());
        match sender.send_message(Message::Text(text)) {
            Ok(_) => (),
            Err(error) => println!("Send error: {}", error),
        };
    }
}

pub fn get_user_id(cookies: Option<&Cookie>) -> Option<String> {
    match cookies {
        Some(cookies) => {
            match cookies.iter().find(|cookie| cookie.name == "userid") {
                Some(user_id) => Some(user_id.value.clone()),
                None => None,
            }
        },
        None => None,
    }
}

// rust-websocket is blocking, so we have to spawn a thread per connection
// each thread sends events back to a central channel
pub fn server_events() -> mpsc::Receiver<ServerEvent> {
    let (event_sender, event_receiver) = mpsc::channel();
    thread::spawn(move || {
        let server = websocket::Server::bind("0.0.0.0:2794").unwrap();
        for connection in server {
            let event_sender = event_sender.clone();
            thread::spawn(move || {
                // accept request
                let request = connection.unwrap().read_request().unwrap();
                request.validate().unwrap();

                // get the User ID from a cookie in the headers
                let user_id = get_user_id(request.headers.get::<Cookie>());

                let response = request.accept();
                let (mut sender, mut receiver) = response.send().unwrap().split();

                let ip = sender.get_mut().peer_addr().unwrap();
                println!("Connection from {}", ip);
                ::std::io::stdout().flush().unwrap(); // TODO is this actually necessary?

                // hand over the sender
                event_sender.send(ServerEvent::Sync((sender,user_id))).unwrap();

                // handle messages
                for message in receiver.incoming_messages() {
                    let message = match message {
                        Ok(m) => m,
                        Err(_) => return,
                    };
                    match message {
                        Message::Binary(bytes) => {
                            event_sender.send(ServerEvent::Change(bytes)).unwrap();
                        }
                        Message::Close(_) => {
                            let ip_addr = format!("{}", ip);
                            println!("Received close message from {}.",ip_addr);
                            let close_message = CloseData{status_code: 0, reason: ip_addr};
                            event_sender.send(ServerEvent::Terminate(Some(close_message))).unwrap();
                        }
                        _ => println!("Unknown message: {:?}", message)
                    }
                }
            });
        }
    });
    event_receiver
}

pub fn handle_event(server: &mut Server, event: Event, event_json: Json) {
    // save the event
    {
        let mut autosave = OpenOptions::new().write(true).append(true).open("./autosave").unwrap();
        autosave.write_all(format!("{}", event_json).as_bytes()).unwrap();
        autosave.write_all("\n".as_bytes()).unwrap();
        autosave.flush().unwrap();
    }

    // copy the old flow so we can compare to the new flow for changes
    let old_flow = server.flow.clone();

    // run the flow until it reaches fixpoint
    server.flow.quiesce(event.changes);

    // handle commands
    let mut response_commands = vec![];
    for command in event.commands.iter() {
        let borrowed_words = command.iter().map(|word| &word[..]).collect::<Vec<_>>();
        match &borrowed_words[..] {
            ["load", filename] => {
                server.flow = Flow::new();
                load(&mut server.flow, "./bootstrap");
                load(&mut server.flow, filename);
                save(&server.flow, "./autosave");
                let current_dir = ::std::env::current_dir().unwrap().to_str().unwrap().to_owned();
                response_commands.push(vec!["loaded".to_owned(), current_dir, filename.to_owned()]);
            }
            ["save", filename] => {
                save(&server.flow, filename);
                let current_dir = ::std::env::current_dir().unwrap().to_str().unwrap().to_owned();
                response_commands.push(vec!["saved".to_owned(), current_dir, filename.to_owned()]);
            }
            ["get events", id] => {
                let events_string = read_file("./autosave");
                response_commands.push(vec!["events got".to_owned(), id.to_owned(), events_string]);
            }
            ["set events", id, events_string] => {
                write_file("./autosave", events_string);
                server.flow = Flow::new();
                load(&mut server.flow, "./bootstrap");
                load(&mut server.flow, "./autosave");
                response_commands.push(vec!["events set".to_owned(), id.to_owned()]);
            }
            other => panic!("Unknown command: {:?}", other),
        }
    }

    let changes = &server.flow.changes_from(old_flow);
    send_event(server, changes, &response_commands);
}

pub fn run() {
    let mut flow = Flow::new();
    time!("reading saved state", {
        load(&mut flow, "./bootstrap");
        load(&mut flow, "./autosave");
    });

    let senders: Vec<sender::Sender<WebSocketStream>> = Vec::new();

    let mut server = Server{flow: flow, senders: senders};

    for server_event in server_events() {
        match server_event {

            // a new client has connected and needs to sync its state
            ServerEvent::Sync((mut sender, user_id)) => {
                let mut changes = vec![];

                // add a session to the session table
                let session_id = format!("{}", sender.get_mut().peer_addr().unwrap());
                changes.push(("sessions".to_owned(),
                    Change{
                        fields: vec!["sessions: id".to_owned(), "sessions: status".to_owned()],
                        insert: vec![vec![Value::String(session_id.clone()), Value::Float(1f64)]],
                        remove: vec![],
                    }));

                // if we have a user ID, add a mapping from the session ID to the user ID
                if let Some(user_id) = user_id {
                    changes.push(("session id to user id".to_owned(),
                        Change{
                            fields: vec!["session id to user id: session id".to_owned(), "session id to user id: user id".to_owned()],
                            insert: vec![vec![Value::String(session_id.clone()), Value::String(user_id)]],
                            remove: vec![]
                        }));
                }

                // handle the session change
                let event = Event{changes: changes, session: session_id.clone(), commands: vec![]};
                let json = event.to_json();
                handle_event(&mut server, event, json);

                // sync the new client
                let changes = server.flow.as_changes();
                let event = Event{changes: changes, session: session_id, commands: vec![]};
                let text = format!("{}", event.to_json());
                match sender.send_message(Message::Text(text)) {
                    Ok(_) => (),
                    Err(error) => println!("Send error: {}", error),
                };
                server.senders.push(sender)
            }

            // an existing client has sent a new message
            ServerEvent::Change(input_bytes) => {
                // TODO we throw cbor in here to avoid https://github.com/rust-lang/rustc-serialize/issues/113
                let mut decoder = cbor::Decoder::from_bytes(&input_bytes[..]);
                let cbor = decoder.items().next().unwrap().unwrap();
                let json = cbor.to_json();
                let event = FromJson::from_json(&json);
                handle_event(&mut server, event, json);
            }

            ServerEvent::Terminate(m) => {
                let terminate_ip = m.unwrap().reason;
                println!("Closing connection from {}...",terminate_ip);

                // find the index of the connection's sender
                let ip_ix = server.senders.iter_mut().position(|mut sender| {
                    let ip = format!("{}",sender.get_mut().peer_addr().unwrap());
                    ip == terminate_ip
                });

                match ip_ix {
                    Some(ix) => {
                        // close the connection
                        let _ = server.senders[ix].send_message(Message::Close(None));
                        match server.senders[ix].get_mut().shutdown(Shutdown::Both) {
                            Ok(_) => println!("Connection from {} has closed successfully.",terminate_ip),
                            Err(e) => println!("Connection from {} failed to shut down properly: {}",terminate_ip,e),
                        }
                        server.senders.remove(ix);

                        // update the session table
                        let sessions = server.flow.get_output("sessions").clone();
                        let ip_string = Value::String(terminate_ip.clone());

                        // change the session status to 0
                        for row in sessions.find(vec![&ip_string, &Value::Null]) {
                            match row {
                                [_, ref status] => {
                                    let change = Change {
                                        fields: sessions.fields.clone(),
                                        insert: vec![vec![ip_string.clone(), Value::Float(0f64)]],
                                        remove: vec![vec![ip_string.clone(), status.clone()]],
                                    };
                                    let event = Event{changes: vec![("sessions".to_string(),change)], session: "".to_string(), commands: vec![]};
                                    let json = event.to_json();
                                    handle_event(&mut server, event, json);
                                }
                                _ => unreachable!(),
                            }
                        }

                    },
                    None => panic!("IP address {} is not connected",terminate_ip),
                }
            }
        }
    }
}<|endoftext|>


<commit_before>extern crate sfml;

use sfml::system::Vector2f;
use sfml::window::{ContextSettings, VideoMode, event, Close};
use sfml::graphics::{RenderWindow, RenderTarget, CircleShape, Color};

fn main() {
    let mut env = SFMLEnv::new(800, 600);

    let mut circle = CircleShape::new().expect("Error cannot create ball.");
    circle.set_radius(30.);
    circle.set_fill_color(&Color::red());
    circle.set_position(&Vector2f::new(100., 100.));

    while env.win.is_open() {
        for event in env.win.events() {
            match event {
                event::Closed => env.win.close(),
                _ => { }
            }
        }

        env.win.clear(&Color::new_rgb(0, 200, 200));
        env.win.draw(&circle);
        env.win.display();
    }
}

struct SFMLEnv {
    win: RenderWindow,
    width: u32,
    height: u32
}

impl SFMLEnv {
    fn new(width: u32, height: u32) -> SFMLEnv {
        let mut window = RenderWindow::new(VideoMode::new_init(width, height, 32),
                                           "SFML Example",
                                           Close,
                                           &ContextSettings::default())
            .expect("Cannot create a new Render Window.");
        window.set_vertical_sync_enabled(true);
        SFMLEnv {
            win: window,
            width: width,
            height: height
        }
    }
}
<commit_msg>add clear<commit_after>extern crate sfml;

use sfml::system::Vector2f;
use sfml::window::{ContextSettings, VideoMode, event, Close};
use sfml::graphics::{RenderWindow, RenderTarget, CircleShape, Color};

fn main() {
    let mut env = SFMLEnv::new(800, 600);

    let mut circle = CircleShape::new().expect("Error cannot create ball.");
    circle.set_radius(30.);
    circle.set_fill_color(&Color::red());
    circle.set_position(&Vector2f::new(100., 100.));

    while env.win.is_open() {
        for event in env.win.events() {
            match event {
                event::Closed => env.win.close(),
                _ => { }
            }
        }

        env.clear();

        env.win.draw(&circle);
        env.win.display();
    }
}

struct SFMLEnv {
    win: RenderWindow,
    width: u32,
    height: u32
}

impl SFMLEnv {
    fn new(width: u32, height: u32) -> SFMLEnv {
        let mut window = RenderWindow::new(VideoMode::new_init(width, height, 32),
                                           "SFML Example",
                                           Close,
                                           &ContextSettings::default())
            .expect("Cannot create a new Render Window.");
        window.set_vertical_sync_enabled(true);
        SFMLEnv {
            win: window,
            width: width,
            height: height
        }
    }

    fn clear(&mut self) {
        self.win.clear(&Color::black());
    }
}
<|endoftext|>


<commit_before>use calx::engine::{App, Engine, Key, v2};
use calx::color::consts::*;
use calx::engine;
use calx::world::{World, CompProxyMut};
use world::spatial::{Position};
use world::system::{System, EngineLogic, Entity};
use world::fov::Fov;
use world::mapgen::{MapGen};
use world::area::Area;
use world::mobs::{Mobs, MobComp, Mob};
use world::mobs;
use view::worldview;
use view::tilecache;
use view::tilecache::icon;
use view::main::State;
use view::titlestate::TitleState;

pub struct GameState {
    running: bool,
    world: World<System>,
    camera: Entity,
    in_player_input: bool,
}

impl GameState {
    pub fn new() -> GameState {
        let mut world = World::new(System::new(0, Fx::new()));
        GameState {
            running: true,
            world: world.clone(),
            camera: world.new_entity(),
            in_player_input: false,
        }
    }

    fn move(&mut self, dir8: uint) {
        assert!(self.in_player_input);
        let mut player = self.world.player().unwrap();
        player.smart_move(dir8);

        if self.world.terrain_at(player.location()).is_exit() {
            self.next_level();
        }

        self.end_turn();
    }

    fn reset_fov(&mut self) {
        self.camera.set_component(Fov::new());
    }

    fn get_fov<'a>(&'a self) -> CompProxyMut<System, Fov> {
        // The camera has to always have the FOV component.
        self.camera.into::<Fov>().unwrap()
    }

    fn camera_to_player(&mut self) {
        // Move camera to player's position and recompute FOV.
        match self.world.player() {
            Some(e) => {
                let loc = e.location();
                self.camera.set_location(loc);
                self.get_fov().update(&self.world, loc, 12);
            }
            _ => ()
        }
    }

    fn next_level(&mut self) {
        self.reset_fov();
        self.world.next_level();
        self.camera_to_player();
    }

    fn end_turn(&mut self) {
        self.in_player_input = false;

        self.world.update_mobs();
        self.world.advance_frame();
    }
}

impl App for GameState {
    fn setup(&mut self, _ctx: &mut Engine) {
        let mut e = self.world.new_entity();
        e.set_component(MobComp::new(mobs::Player));

        self.reset_fov();

        self.world.next_level();
        self.world.player().unwrap().location();
        self.camera_to_player();
    }

    fn key_pressed(&mut self, ctx: &mut Engine, key: Key) {
        if self.in_player_input {
            match key {
                engine::Key1 => { self.next_level(); }
                engine::Key2 => {
                    let mut player = self.world.player().unwrap();
                    let loc = player.location();
                    player.attack(loc);
                }

                engine::KeyQ | engine::KeyPad7 => { self.move(7); }
                engine::KeyW | engine::KeyPad8 | engine::KeyUp => { self.move(0); }
                engine::KeyE | engine::KeyPad9 => { self.move(1); }
                engine::KeyA | engine::KeyPad1 => { self.move(5); }
                engine::KeyS | engine::KeyPad2 | engine::KeyDown => { self.move(4); }
                engine::KeyD | engine::KeyPad3 => { self.move(3); }
                engine::KeyLeft => { self.move(6); }
                engine::KeyRight => { self.move(2); }
                _ => (),
            }
        }

        match key {
            engine::KeyEscape => { ctx.quit(); }
            engine::KeyF12 => { ctx.screenshot("/tmp/shot.png"); }
            _ => (),
        }
    }

    fn draw(&mut self, ctx: &mut Engine) {
        self.in_player_input = match self.world.player() {
            Some(p) => p.acts_this_frame(),
            None => false
        };

        self.camera_to_player();
        worldview::draw_area(&self.world, ctx, self.camera.location(), self.get_fov().deref());

        let _mouse_pos = worldview::draw_mouse(ctx, self.camera.location());

        // UI needs player stats to be displayed, so only do it if a player exists.
        match self.world.player() {
            Some(e) => self.draw_ui(ctx, e),
            _ => ()
        }

        if !self.in_player_input {
            self.end_turn();
        }
    }
}

impl State for GameState {
    fn next_state(&self) -> Option<Box<State>> {
        if !self.running {
            Some(box TitleState::new() as Box<State>)
        } else {
            None
        }
    }
}

// UI rendering
impl GameState {
    fn health_bar(&self, ctx: &mut Engine, player: Entity) {
        let mob = player.into::<MobComp>().unwrap();
        ctx.set_color(&RED);
        let num_hearts = (mob.max_hp + 1) / 2;
        let solid_hearts = mob.hp / 2;
        let half_heart = (mob.hp % 2) == 1;
        for i in range(0, num_hearts) {
            let pos = v2(i as f32 * 8f32, 8f32);
            let img =
                if i < solid_hearts {
                    icon::HEART
                } else if i == solid_hearts && half_heart {
                    icon::HALF_HEART
                } else {
                    icon::NO_HEART
                };
            ctx.draw_image(&tilecache::get(img), &pos);
        }

        ctx.set_color(&LIGHTSLATEGRAY);
        let num_shards = (mob.armor + 1) / 2;
        let half_shard = (mob.armor % 2) == 1;

        for i in range(0, num_shards) {
            let pos = v2((i + num_hearts) as f32 * 8f32, 8f32);
            let img =
                if i == num_shards - 1 && half_shard {
                    icon::HALF_SHARD
                } else {
                    icon::SHARD
                };
            ctx.draw_image(&tilecache::get(img), &pos);
        }
    }

    fn draw_ui(&self, ctx: &mut Engine, player: Entity) {
        ctx.set_layer(0.100f32);

        self.health_bar(ctx, player);

        self.world.system().fx.draw(ctx);
    }
}

pub struct Fx {
    // TODO: turn this into a timed queue.
    message: String,
    // TODO: caption
    // TODO: effects
}

impl Fx {
    pub fn new() -> Fx {
        Fx {
            message: "".to_string(),
        }
    }

    pub fn draw(&self, ctx: &mut Engine) {
        ctx.draw_string(self.message.as_slice(), &v2(0f32, 300f32));
    }

    pub fn msg(&mut self, txt: &str) {
        self.message = txt.to_string();
    }

    pub fn caption(&mut self, _txt: &str) {
        unimplemented!();
    }

    pub fn beam(&mut self, _dir6: uint, _length: uint) {
        unimplemented!();
    }
}
<commit_msg>Drawing fx animations on map<commit_after>use cgmath::vector::{Vector, Vector2};
use calx::engine::{App, Engine, Key, v2};
use calx::color::consts::*;
use calx::engine;
use calx::world::{World, CompProxyMut};
use world::spatial::{Position, Location, DIRECTIONS6};
use world::system::{System, EngineLogic, Entity};
use world::fov::Fov;
use world::mapgen::{MapGen};
use world::area::Area;
use world::mobs::{Mobs, MobComp, Mob};
use world::mobs;
use view::worldview;
use view::worldview::{loc_to_view};
use view::tilecache;
use view::drawable::Drawable;
use view::tilecache::icon;
use view::main::State;
use view::titlestate::TitleState;

trait WorldSprite : Drawable {
    /// Return false if the sprite's lifetime is over.
    fn update(&mut self) -> bool;
}

struct WorldEffects {
    sprites: Vec<Box<WorldSprite>>,
}

impl WorldEffects {
    pub fn new() -> WorldEffects {
        WorldEffects {
            sprites: vec!(),
        }
    }

    pub fn add(&mut self, spr: Box<WorldSprite>) {
        self.sprites.push(spr);
    }

    pub fn draw(&mut self, ctx: &mut Engine, center: Location) {
        // FIXME: Effects will be visible on top of remembered-but-not-seen terrain.
        let offset = worldview::loc_to_screen(center, Location::new(0, 0));
        let mut i = 0;
        loop {
            if i >= self.sprites.len() { break; }
            if !self.sprites.get_mut(i).update() {
                // Update returns false when the sprite dies.
                self.sprites.swap_remove(i);
            } else {
                self.sprites[i].draw(ctx, &offset);
                i += 1;
            }
        }
    }
}

struct BeamSprite {
    p1: Location,
    p2: Location,
    life: int,
}

impl Drawable for BeamSprite {
    fn draw(&self, ctx: &mut Engine, offset: &Vector2<f32>) {
        let v1 = loc_to_view(self.p1);
        let v2 = loc_to_view(self.p2);

        ctx.set_color(&LIME);
        ctx.set_layer(worldview::FX_Z);
        ctx.line_width(3f32);
        ctx.line(&v1.add_v(offset), &v2.add_v(offset));
    }
}

impl WorldSprite for BeamSprite {
    fn update(&mut self) -> bool { self.life -= 1; self.life >= 0 }
}

pub struct GameState {
    running: bool,
    world: World<System>,
    camera: Entity,
    in_player_input: bool,
    world_fx: WorldEffects,
}

impl GameState {
    pub fn new() -> GameState {
        let mut world = World::new(System::new(0, Fx::new()));
        GameState {
            running: true,
            world: world.clone(),
            camera: world.new_entity(),
            in_player_input: false,
            world_fx: WorldEffects::new(),
        }
    }

    fn move(&mut self, dir8: uint) {
        assert!(self.in_player_input);
        let mut player = self.world.player().unwrap();
        player.smart_move(dir8);

        if self.world.terrain_at(player.location()).is_exit() {
            self.next_level();
        }

        self.end_turn();
    }

    fn reset_fov(&mut self) {
        self.camera.set_component(Fov::new());
    }

    fn get_fov<'a>(&'a self) -> CompProxyMut<System, Fov> {
        // The camera has to always have the FOV component.
        self.camera.into::<Fov>().unwrap()
    }

    fn camera_to_player(&mut self) {
        // Move camera to player's position and recompute FOV.
        match self.world.player() {
            Some(e) => {
                let loc = e.location();
                self.camera.set_location(loc);
                self.get_fov().update(&self.world, loc, 12);
            }
            _ => ()
        }
    }

    fn next_level(&mut self) {
        self.reset_fov();
        self.world.next_level();
        self.camera_to_player();
    }

    fn end_turn(&mut self) {
        self.in_player_input = false;

        self.world.update_mobs();
        self.world.advance_frame();
    }
}

impl App for GameState {
    fn setup(&mut self, _ctx: &mut Engine) {
        let mut e = self.world.new_entity();
        e.set_component(MobComp::new(mobs::Player));

        self.reset_fov();

        self.world.next_level();
        self.world.player().unwrap().location();
        self.camera_to_player();
    }

    fn key_pressed(&mut self, ctx: &mut Engine, key: Key) {
        if self.in_player_input {
            match key {
                engine::Key1 => { self.next_level(); }
                engine::Key2 => {
                    let mut player = self.world.player().unwrap();
                    let loc = player.location();
                    player.attack(loc);
                }
                engine::Key3 => {
                    let loc = self.world.player().unwrap().location();
                    for i in range(0, 6) {
                    self.world_fx.add(box
                        BeamSprite {
                            p1: loc,
                            p2: Location::new(
                                loc.x + DIRECTIONS6[i].x as i8 * 6,
                                loc.y + DIRECTIONS6[i].y as i8 * 6,),
                            life: 30,
                        });
                    }
                }

                engine::KeyQ | engine::KeyPad7 => { self.move(7); }
                engine::KeyW | engine::KeyPad8 | engine::KeyUp => { self.move(0); }
                engine::KeyE | engine::KeyPad9 => { self.move(1); }
                engine::KeyA | engine::KeyPad1 => { self.move(5); }
                engine::KeyS | engine::KeyPad2 | engine::KeyDown => { self.move(4); }
                engine::KeyD | engine::KeyPad3 => { self.move(3); }
                engine::KeyLeft => { self.move(6); }
                engine::KeyRight => { self.move(2); }
                _ => (),
            }
        }

        match key {
            engine::KeyEscape => { ctx.quit(); }
            engine::KeyF12 => { ctx.screenshot("/tmp/shot.png"); }
            _ => (),
        }
    }

    fn draw(&mut self, ctx: &mut Engine) {
        self.in_player_input = match self.world.player() {
            Some(p) => p.acts_this_frame(),
            None => false
        };

        self.camera_to_player();
        worldview::draw_area(&self.world, ctx, self.camera.location(), self.get_fov().deref());
        self.world_fx.draw(ctx, self.camera.location());

        let _mouse_pos = worldview::draw_mouse(ctx, self.camera.location());

        // UI needs player stats to be displayed, so only do it if a player exists.
        match self.world.player() {
            Some(e) => self.draw_ui(ctx, e),
            _ => ()
        }

        if !self.in_player_input {
            self.end_turn();
        }
    }
}

impl State for GameState {
    fn next_state(&self) -> Option<Box<State>> {
        if !self.running {
            Some(box TitleState::new() as Box<State>)
        } else {
            None
        }
    }
}

// UI rendering
impl GameState {
    fn health_bar(&self, ctx: &mut Engine, player: Entity) {
        let mob = player.into::<MobComp>().unwrap();
        ctx.set_color(&RED);
        let num_hearts = (mob.max_hp + 1) / 2;
        let solid_hearts = mob.hp / 2;
        let half_heart = (mob.hp % 2) == 1;
        for i in range(0, num_hearts) {
            let pos = v2(i as f32 * 8f32, 8f32);
            let img =
                if i < solid_hearts {
                    icon::HEART
                } else if i == solid_hearts && half_heart {
                    icon::HALF_HEART
                } else {
                    icon::NO_HEART
                };
            ctx.draw_image(&tilecache::get(img), &pos);
        }

        ctx.set_color(&LIGHTSLATEGRAY);
        let num_shards = (mob.armor + 1) / 2;
        let half_shard = (mob.armor % 2) == 1;

        for i in range(0, num_shards) {
            let pos = v2((i + num_hearts) as f32 * 8f32, 8f32);
            let img =
                if i == num_shards - 1 && half_shard {
                    icon::HALF_SHARD
                } else {
                    icon::SHARD
                };
            ctx.draw_image(&tilecache::get(img), &pos);
        }
    }

    fn draw_ui(&self, ctx: &mut Engine, player: Entity) {
        ctx.set_layer(0.100f32);

        self.health_bar(ctx, player);

        self.world.system().fx.draw(ctx);
    }
}

pub struct Fx {
    // TODO: turn this into a timed queue.
    message: String,
    // TODO: caption
    // TODO: effects
}

impl Fx {
    pub fn new() -> Fx {
        Fx {
            message: "".to_string(),
        }
    }

    pub fn draw(&self, ctx: &mut Engine) {
        ctx.draw_string(self.message.as_slice(), &v2(0f32, 300f32));
    }

    pub fn msg(&mut self, txt: &str) {
        self.message = txt.to_string();
    }

    pub fn caption(&mut self, _txt: &str) {
        unimplemented!();
    }

    pub fn beam(&mut self, _dir6: uint, _length: uint) {
        unimplemented!();
    }
}
<|endoftext|>


<commit_before>use std::cmp;
use std::ops::DerefMut;
use rand::Rng;
use ecs::*;
use game::*;
use game::data::*;
use game::terrain::util;
use coord::Coord;
use grid::*;
use perlin::*;
use math::*;
use direction::*;

const MAP_WIDTH_MAX: usize = 120;
const MAP_WIDTH_MIN: usize = 60;
const MAP_HEIGHT: usize = 30;
const ROAD_HEIGHT: usize = 6;
const ROAD_TOP: usize = (MAP_HEIGHT + ROAD_HEIGHT) / 2;
const ROAD_BOTTOM: usize = ROAD_TOP - ROAD_HEIGHT;
const START_COORD: Coord = Coord { x: 0, y: MAP_HEIGHT as isize / 2 };

const PERLIN_ZOOM: usize = 5;
const PERLIN_ZOOM_F: f64 = PERLIN_ZOOM as f64;
const PERLIN_MIN: f64 = 0.2;
const PERLIN_MAX: f64 = 0.5;

#[derive(Clone, Copy, PartialEq, Eq)]
enum EntityType {
    Dirt,
    Road,
    Acid,
    Goal,
    Wreck,
    Barrel,
    Letter,
    Zombie,
    Car,
    Bike,
}

const RANDOM_ENTITY_TYPES: [EntityType; 6] = [
    EntityType::Wreck,
    EntityType::Barrel,
    EntityType::Letter,
    EntityType::Zombie,
    EntityType::Car,
    EntityType::Bike,
];
const RANDOM_ENTITY_DIRT_WEIGHTS: [usize; 6] = [5, 10, 2, 40, 0, 0];
const RANDOM_ENTITY_ROAD_WEIGHTS: [usize; 6] = [10, 10, 4, 5, 0, 0];
const RANDOM_ENTITY_TOTAL: usize = 1000;

fn choose_random_entity<R: Rng>(types: &[EntityType], weights: &[usize], total: usize, rng: &mut R) -> Option<EntityType> {
    let mut roll = rng.gen::<usize>() % total;
    for (weight, entity_type) in izip!(weights.iter(), types.iter()) {
        if roll < *weight {
            return Some(*entity_type);
        }
        roll -= *weight;
    }

    None
}

pub fn road<S: TurnScheduleQueue>(ids: &EntityIdReserver,
                                  rng: &GameRng,
                                  schedule: &mut S,
                                  g: &mut EcsAction,
                                  difficulty: usize) -> TerrainMetadata {

    let map_width = rng.gen_usize() % (MAP_WIDTH_MAX - MAP_WIDTH_MIN) + MAP_WIDTH_MIN;
    let mut grid: StaticGrid<Vec<EntityType>> = StaticGrid::new_default(map_width, MAP_HEIGHT);

    let perlin = PerlinGrid::new(map_width / PERLIN_ZOOM, MAP_HEIGHT / PERLIN_ZOOM,
                                 PerlinWrapType::Repeat, rng.inner_mut().deref_mut());

    let random_entity_dirt_weights = [
        5, /* Wreck */
        10, /* Barrrel */
        3, /* Letter */
        20 + cmp::min(difficulty * 10, 60), /* Zombie */
        cmp::min(difficulty / 4, 4), /* Car */
        1 + cmp::min(difficulty / 2, 8), /* Bike */
    ];

    let random_entity_road_weights = [
        5, /* Wreck */
        10, /* Barrrel */
        3, /* Letter */
        10 + cmp::min(difficulty * 5, 30), /* Zombie */
        1 + cmp::min(difficulty / 3, 6), /* Car */
        cmp::min(difficulty / 3, 6), /* Bike */
    ];

    for (coord, cell_mut) in izip!(grid.coord_iter(), grid.iter_mut()) {

        let mut acid = false;
        let perlin_coord = Vector2::new(coord.x as f64 / PERLIN_ZOOM_F, coord.y as f64 / PERLIN_ZOOM_F);
        if let Some(noise) = perlin.noise(perlin_coord.x, perlin_coord.y) {
            if noise > PERLIN_MIN && noise <= PERLIN_MAX {
                acid = true;
            }
        }

        if acid {
            cell_mut.push(EntityType::Acid);
        } else if coord.y > ROAD_BOTTOM as isize && coord.y <= ROAD_TOP as isize {
            cell_mut.push(EntityType::Road);
            if let Some(entity_type) = choose_random_entity(&RANDOM_ENTITY_TYPES,
                                                            &random_entity_road_weights,
                                                            RANDOM_ENTITY_TOTAL,
                                                            rng.inner_mut().deref_mut()) {
                cell_mut.push(entity_type);
            }
        } else {
            cell_mut.push(EntityType::Dirt);
            if let Some(entity_type) = choose_random_entity(&RANDOM_ENTITY_TYPES,
                                                            &random_entity_dirt_weights,
                                                            RANDOM_ENTITY_TOTAL,
                                                            rng.inner_mut().deref_mut()) {
                cell_mut.push(entity_type);
            }
        }

        if coord.x == map_width as isize - 1 {
            cell_mut.push(EntityType::Goal);
        }
    }

    for (coord, cell) in izip!(grid.coord_iter(), grid.iter()) {
        for entity_type in cell.iter() {
            match *entity_type {
                EntityType::Dirt => {
                    prototypes::dirt(g.entity_mut(ids.new_id()), coord, rng);
                }
                EntityType::Road => {
                    prototypes::road(g.entity_mut(ids.new_id()), coord, rng);
                }
                EntityType::Acid => {
                    prototypes::acid(g.entity_mut(ids.new_id()), coord, rng);
                }
                EntityType::Goal => {
                    prototypes::goal(g.entity_mut(ids.new_id()), coord, LevelSwitch::LeaveLevel);
                }
                EntityType::Wreck => {
                    prototypes::wreck(g.entity_mut(ids.new_id()), coord, rng);
                }
                EntityType::Barrel => {
                    prototypes::barrel(g.entity_mut(ids.new_id()), coord);
                }
                EntityType::Letter => {
                    prototypes::letter(g.entity_mut(ids.new_id()), coord);
                }
                EntityType::Zombie => {
                    prototypes::dirt(g.entity_mut(ids.new_id()), coord, rng);
                    let id = ids.new_id();
                    prototypes::zombie(g.entity_mut(id), coord);
                    let turn_offset = g.turn_offset(id).expect("Expected component turn_offset");
                    let ticket = schedule.schedule_turn(id, turn_offset);
                    g.insert_schedule_ticket(id, ticket);
                }
                EntityType::Car => {
                    prototypes::dirt(g.entity_mut(ids.new_id()), coord, rng);
                    let id = ids.new_id();
                    prototypes::car(g.entity_mut(id), coord);
                    let turn_offset = g.turn_offset(id).expect("Expected component turn_offset");
                    let ticket = schedule.schedule_turn(id, turn_offset);
                    g.insert_schedule_ticket(id, ticket);

                    let gun_id = ids.new_id();
                    prototypes::shotgun(g.entity_mut(gun_id));
                    g.weapon_slots_mut(id).unwrap().insert(Direction::North, gun_id);
                    g.weapon_slots_mut(id).unwrap().insert(Direction::South, gun_id);
                }
                EntityType::Bike => {
                    prototypes::dirt(g.entity_mut(ids.new_id()), coord, rng);
                    let id = ids.new_id();
                    prototypes::bike(g.entity_mut(id), coord);
                    let turn_offset = g.turn_offset(id).expect("Expected component turn_offset");
                    let ticket = schedule.schedule_turn(id, turn_offset);
                    g.insert_schedule_ticket(id, ticket);

                    let gun_id = ids.new_id();
                    prototypes::pistol(g.entity_mut(gun_id));
                    g.weapon_slots_mut(id).unwrap().insert(Direction::North, gun_id);
                    g.weapon_slots_mut(id).unwrap().insert(Direction::South, gun_id);
                    g.weapon_slots_mut(id).unwrap().insert(Direction::East, gun_id);
                    g.weapon_slots_mut(id).unwrap().insert(Direction::West, gun_id);
                }
            }
        }
    }

    util::add_management_entities(ids, schedule, g);

    TerrainMetadata {
        width: map_width,
        height: MAP_HEIGHT,
        start_coord: START_COORD,
        connection_report: LevelConnectionReport::new(),
    }
}
<commit_msg>Removed dead code<commit_after>use std::cmp;
use std::ops::DerefMut;
use rand::Rng;
use ecs::*;
use game::*;
use game::data::*;
use game::terrain::util;
use coord::Coord;
use grid::*;
use perlin::*;
use math::*;
use direction::*;

const MAP_WIDTH_MAX: usize = 120;
const MAP_WIDTH_MIN: usize = 60;
const MAP_HEIGHT: usize = 30;
const ROAD_HEIGHT: usize = 6;
const ROAD_TOP: usize = (MAP_HEIGHT + ROAD_HEIGHT) / 2;
const ROAD_BOTTOM: usize = ROAD_TOP - ROAD_HEIGHT;
const START_COORD: Coord = Coord { x: 0, y: MAP_HEIGHT as isize / 2 };

const PERLIN_ZOOM: usize = 5;
const PERLIN_ZOOM_F: f64 = PERLIN_ZOOM as f64;
const PERLIN_MIN: f64 = 0.2;
const PERLIN_MAX: f64 = 0.5;

#[derive(Clone, Copy, PartialEq, Eq)]
enum EntityType {
    Dirt,
    Road,
    Acid,
    Goal,
    Wreck,
    Barrel,
    Letter,
    Zombie,
    Car,
    Bike,
}

const RANDOM_ENTITY_TYPES: [EntityType; 6] = [
    EntityType::Wreck,
    EntityType::Barrel,
    EntityType::Letter,
    EntityType::Zombie,
    EntityType::Car,
    EntityType::Bike,
];
const RANDOM_ENTITY_TOTAL: usize = 1000;

fn choose_random_entity<R: Rng>(types: &[EntityType], weights: &[usize], total: usize, rng: &mut R) -> Option<EntityType> {
    let mut roll = rng.gen::<usize>() % total;
    for (weight, entity_type) in izip!(weights.iter(), types.iter()) {
        if roll < *weight {
            return Some(*entity_type);
        }
        roll -= *weight;
    }

    None
}

pub fn road<S: TurnScheduleQueue>(ids: &EntityIdReserver,
                                  rng: &GameRng,
                                  schedule: &mut S,
                                  g: &mut EcsAction,
                                  difficulty: usize) -> TerrainMetadata {

    let map_width = rng.gen_usize() % (MAP_WIDTH_MAX - MAP_WIDTH_MIN) + MAP_WIDTH_MIN;
    let mut grid: StaticGrid<Vec<EntityType>> = StaticGrid::new_default(map_width, MAP_HEIGHT);

    let perlin = PerlinGrid::new(map_width / PERLIN_ZOOM, MAP_HEIGHT / PERLIN_ZOOM,
                                 PerlinWrapType::Repeat, rng.inner_mut().deref_mut());

    let random_entity_dirt_weights = [
        5, /* Wreck */
        10, /* Barrrel */
        3, /* Letter */
        20 + cmp::min(difficulty * 10, 60), /* Zombie */
        cmp::min(difficulty / 4, 4), /* Car */
        1 + cmp::min(difficulty / 2, 8), /* Bike */
    ];

    let random_entity_road_weights = [
        5, /* Wreck */
        10, /* Barrrel */
        3, /* Letter */
        10 + cmp::min(difficulty * 5, 30), /* Zombie */
        1 + cmp::min(difficulty / 3, 6), /* Car */
        cmp::min(difficulty / 3, 6), /* Bike */
    ];

    for (coord, cell_mut) in izip!(grid.coord_iter(), grid.iter_mut()) {

        let mut acid = false;
        let perlin_coord = Vector2::new(coord.x as f64 / PERLIN_ZOOM_F, coord.y as f64 / PERLIN_ZOOM_F);
        if let Some(noise) = perlin.noise(perlin_coord.x, perlin_coord.y) {
            if noise > PERLIN_MIN && noise <= PERLIN_MAX {
                acid = true;
            }
        }

        if acid {
            cell_mut.push(EntityType::Acid);
        } else if coord.y > ROAD_BOTTOM as isize && coord.y <= ROAD_TOP as isize {
            cell_mut.push(EntityType::Road);
            if let Some(entity_type) = choose_random_entity(&RANDOM_ENTITY_TYPES,
                                                            &random_entity_road_weights,
                                                            RANDOM_ENTITY_TOTAL,
                                                            rng.inner_mut().deref_mut()) {
                cell_mut.push(entity_type);
            }
        } else {
            cell_mut.push(EntityType::Dirt);
            if let Some(entity_type) = choose_random_entity(&RANDOM_ENTITY_TYPES,
                                                            &random_entity_dirt_weights,
                                                            RANDOM_ENTITY_TOTAL,
                                                            rng.inner_mut().deref_mut()) {
                cell_mut.push(entity_type);
            }
        }

        if coord.x == map_width as isize - 1 {
            cell_mut.push(EntityType::Goal);
        }
    }

    for (coord, cell) in izip!(grid.coord_iter(), grid.iter()) {
        for entity_type in cell.iter() {
            match *entity_type {
                EntityType::Dirt => {
                    prototypes::dirt(g.entity_mut(ids.new_id()), coord, rng);
                }
                EntityType::Road => {
                    prototypes::road(g.entity_mut(ids.new_id()), coord, rng);
                }
                EntityType::Acid => {
                    prototypes::acid(g.entity_mut(ids.new_id()), coord, rng);
                }
                EntityType::Goal => {
                    prototypes::goal(g.entity_mut(ids.new_id()), coord, LevelSwitch::LeaveLevel);
                }
                EntityType::Wreck => {
                    prototypes::wreck(g.entity_mut(ids.new_id()), coord, rng);
                }
                EntityType::Barrel => {
                    prototypes::barrel(g.entity_mut(ids.new_id()), coord);
                }
                EntityType::Letter => {
                    prototypes::letter(g.entity_mut(ids.new_id()), coord);
                }
                EntityType::Zombie => {
                    prototypes::dirt(g.entity_mut(ids.new_id()), coord, rng);
                    let id = ids.new_id();
                    prototypes::zombie(g.entity_mut(id), coord);
                    let turn_offset = g.turn_offset(id).expect("Expected component turn_offset");
                    let ticket = schedule.schedule_turn(id, turn_offset);
                    g.insert_schedule_ticket(id, ticket);
                }
                EntityType::Car => {
                    prototypes::dirt(g.entity_mut(ids.new_id()), coord, rng);
                    let id = ids.new_id();
                    prototypes::car(g.entity_mut(id), coord);
                    let turn_offset = g.turn_offset(id).expect("Expected component turn_offset");
                    let ticket = schedule.schedule_turn(id, turn_offset);
                    g.insert_schedule_ticket(id, ticket);

                    let gun_id = ids.new_id();
                    prototypes::shotgun(g.entity_mut(gun_id));
                    g.weapon_slots_mut(id).unwrap().insert(Direction::North, gun_id);
                    g.weapon_slots_mut(id).unwrap().insert(Direction::South, gun_id);
                }
                EntityType::Bike => {
                    prototypes::dirt(g.entity_mut(ids.new_id()), coord, rng);
                    let id = ids.new_id();
                    prototypes::bike(g.entity_mut(id), coord);
                    let turn_offset = g.turn_offset(id).expect("Expected component turn_offset");
                    let ticket = schedule.schedule_turn(id, turn_offset);
                    g.insert_schedule_ticket(id, ticket);

                    let gun_id = ids.new_id();
                    prototypes::pistol(g.entity_mut(gun_id));
                    g.weapon_slots_mut(id).unwrap().insert(Direction::North, gun_id);
                    g.weapon_slots_mut(id).unwrap().insert(Direction::South, gun_id);
                    g.weapon_slots_mut(id).unwrap().insert(Direction::East, gun_id);
                    g.weapon_slots_mut(id).unwrap().insert(Direction::West, gun_id);
                }
            }
        }
    }

    util::add_management_entities(ids, schedule, g);

    TerrainMetadata {
        width: map_width,
        height: MAP_HEIGHT,
        start_coord: START_COORD,
        connection_report: LevelConnectionReport::new(),
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(clippy)]
#![deny(clippy)]
#![allow(unused)]
#![feature(associated_consts, associated_type_defaults)]

type Alias = Vec<Vec<Box<(u32, u32, u32, u32)>>>; // no warning here

const CST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); //~ERROR very complex type
static ST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); //~ERROR very complex type

struct S {
    f: Vec<Vec<Box<(u32, u32, u32, u32)>>>, //~ERROR very complex type
}

struct TS(Vec<Vec<Box<(u32, u32, u32, u32)>>>); //~ERROR very complex type

enum E {
    V1(Vec<Vec<Box<(u32, u32, u32, u32)>>>), //~ERROR very complex type
    V2 { f: Vec<Vec<Box<(u32, u32, u32, u32)>>> }, //~ERROR very complex type
}

impl S {
    const A: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); //~ERROR very complex type
    fn impl_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) { } //~ERROR very complex type
}

trait T {
    const A: Vec<Vec<Box<(u32, u32, u32, u32)>>>; //~ERROR very complex type
    type B = Vec<Vec<Box<(u32, u32, u32, u32)>>>; //~ERROR very complex type
    fn method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>); //~ERROR very complex type
    fn def_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) { } //~ERROR very complex type
}

fn test1() -> Vec<Vec<Box<(u32, u32, u32, u32)>>> { vec![] } //~ERROR very complex type

fn test2(_x: Vec<Vec<Box<(u32, u32, u32, u32)>>>) { } //~ERROR very complex type

fn test3() {
    let _y: Vec<Vec<Box<(u32, u32, u32, u32)>>> = vec![]; //~ERROR very complex type
}

fn main() {
}
<commit_msg>workaround for failing test<commit_after>#![feature(plugin)]
#![plugin(clippy)]
#![deny(clippy)]
#![allow(unused)]
#![feature(associated_consts, associated_type_defaults)]

type Alias = Vec<Vec<Box<(u32, u32, u32, u32)>>>; // no warning here

const CST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); //~ERROR very complex type
static ST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); //~ERROR very complex type

struct S {
    f: Vec<Vec<Box<(u32, u32, u32, u32)>>>, //~ERROR very complex type
}

struct TS(Vec<Vec<Box<(u32, u32, u32, u32)>>>); //~ERROR very complex type

enum E {
    V1(Vec<Vec<Box<(u32, u32, u32, u32)>>>), //~ERROR very complex type
    //~^ERROR very complex type
    V2 { f: Vec<Vec<Box<(u32, u32, u32, u32)>>> }, //~ERROR very complex type
}

impl S {
    const A: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); //~ERROR very complex type
    fn impl_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) { } //~ERROR very complex type
}

trait T {
    const A: Vec<Vec<Box<(u32, u32, u32, u32)>>>; //~ERROR very complex type
    type B = Vec<Vec<Box<(u32, u32, u32, u32)>>>; //~ERROR very complex type
    fn method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>); //~ERROR very complex type
    fn def_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) { } //~ERROR very complex type
}

fn test1() -> Vec<Vec<Box<(u32, u32, u32, u32)>>> { vec![] } //~ERROR very complex type

fn test2(_x: Vec<Vec<Box<(u32, u32, u32, u32)>>>) { } //~ERROR very complex type

fn test3() {
    let _y: Vec<Vec<Box<(u32, u32, u32, u32)>>> = vec![]; //~ERROR very complex type
}

fn main() {
}
<|endoftext|>