<commit_before>//! This is a binary running in the server environment
//!
//! You have to provide all needed configuration attributes via command line parameters,
//! or you could specify a configuration file. The format of configuration file is defined
//! in mod `config`.
//!
//! *It should be notice that the extented configuration file is not suitable for the server
//! side.*

extern crate clap;
extern crate env_logger;
#[macro_use]
extern crate log;
extern crate shadowsocks;
extern crate time;

use std::env;

use clap::{App, Arg};

use env_logger::LogBuilder;
use log::{LogLevelFilter, LogRecord};

use shadowsocks::{run_server, Config, ConfigType, ServerAddr, ServerConfig};
use shadowsocks::plugin::PluginConfig;

fn log_time(without_time: bool, record: &LogRecord) -> String {
    if without_time {
        format!("[{}] {}", record.level(), record.args())
    } else {
        format!("[{}][{}] {}", time::now().strftime("%Y-%m-%d][%H:%M:%S.%f").unwrap(), record.level(), record.args())
    }
}

fn log_time_module(without_time: bool, record: &LogRecord) -> String {
    if without_time {
        format!("[{}] [{}] {}", record.level(), record.location().module_path(), record.args())
    } else {
        format!("[{}][{}] [{}] {}",
                time::now().strftime("%Y-%m-%d][%H:%M:%S.%f").unwrap(),
                record.level(),
                record.location().module_path(),
                record.args())
    }
}

fn main() {
    let matches = App::new("shadowsocks")
        .version(shadowsocks::VERSION)
        .author("Y. T. Chung")
        .about("A fast tunnel proxy that helps you bypass firewalls.")
        .arg(Arg::with_name("VERBOSE")
                 .short("v")
                 .multiple(true)
                 .help("Set the level of debug"))
        .arg(Arg::with_name("ENABLE_UDP")
                 .short("u")
                 .long("enable-udp")
                 .help("Enable UDP relay"))
        .arg(Arg::with_name("CONFIG")
                 .short("c")
                 .long("config")
                 .takes_value(true)
                 .help("Specify config file"))
        .arg(Arg::with_name("SERVER_ADDR")
                 .short("s")
                 .long("server-addr")
                 .takes_value(true)
                 .help("Server address"))
        .arg(Arg::with_name("LOCAL_ADDR")
                 .short("b")
                 .long("local-addr")
                 .takes_value(true)
                 .help("Local address, listen only to this address if specified"))
        .arg(Arg::with_name("LOCAL_PORT")
                 .short("l")
                 .long("local-port")
                 .takes_value(true)
                 .help("Local port"))
        .arg(Arg::with_name("PASSWORD")
                 .short("k")
                 .long("password")
                 .takes_value(true)
                 .help("Password"))
        .arg(Arg::with_name("ENCRYPT_METHOD")
                 .short("m")
                 .long("encrypt-method")
                 .takes_value(true)
                 .help("Encryption method"))
        .arg(Arg::with_name("PLUGIN")
                 .long("plugin")
                 .takes_value(true)
                 .help("Enable SIP003 plugin. (Experimental)"))
        .arg(Arg::with_name("PLUGIN_OPT")
                 .long("plugin-opts")
                 .takes_value(true)
                 .help("Set SIP003 plugin options. (Experimental)"))
        .arg(Arg::with_name("LOG_WITHOUT_TIME")
                 .long("log-without-time")
                 .help("Disable time in log"))
        .get_matches();

    let mut log_builder = LogBuilder::new();
    log_builder.filter(None, LogLevelFilter::Info);

    let without_time = matches.is_present("LOG_WITHOUT_TIME");

    let debug_level = matches.occurrences_of("VERBOSE");
    match debug_level {
        0 => {
            // Default filter
            log_builder.format(move |r| log_time(without_time, r));
        }
        1 => {
            let log_builder = log_builder.format(move |r| log_time_module(without_time, r));
            log_builder.filter(Some("ssserver"), LogLevelFilter::Debug);
        }
        2 => {
            let log_builder = log_builder.format(move |r| log_time_module(without_time, r));
            log_builder.filter(Some("ssserver"), LogLevelFilter::Debug)
                       .filter(Some("shadowsocks"), LogLevelFilter::Debug);
        }
        3 => {
            let log_builder = log_builder.format(move |r| log_time_module(without_time, r));
            log_builder.filter(Some("ssserver"), LogLevelFilter::Trace)
                       .filter(Some("shadowsocks"), LogLevelFilter::Trace);
        }
        _ => {
            let log_builder = log_builder.format(move |r| log_time_module(without_time, r));
            log_builder.filter(None, LogLevelFilter::Trace);
        }
    }

    if let Ok(env_conf) = env::var("RUST_LOG") {
        log_builder.parse(&env_conf);
    }

    log_builder.init().unwrap();

    let mut has_provided_config = false;
    let mut config = match matches.value_of("CONFIG") {
        Some(cpath) => {
            match Config::load_from_file(cpath, ConfigType::Server) {
                Ok(cfg) => {
                    has_provided_config = true;
                    cfg
                }
                Err(err) => {
                    error!("{:?}", err);
                    return;
                }
            }
        }
        None => Config::new(),
    };

    let has_provided_server_config =
        match (matches.value_of("SERVER_ADDR"), matches.value_of("PASSWORD"), matches.value_of("ENCRYPT_METHOD")) {
            (Some(svr_addr), Some(password), Some(method)) => {
                let method = match method.parse() {
                    Ok(m) => m,
                    Err(err) => {
                        panic!("Does not support {:?} method: {:?}", method, err);
                    }
                };

                let sc = ServerConfig::new(svr_addr.parse::<ServerAddr>().expect("Invalid server addr"),
                                           password.to_owned(),
                                           method,
                                           None,
                                           None);

                config.server.push(sc);
                true
            }
            (None, None, None) => {
                // Does not provide server config
                false
            }
            _ => {
                panic!("`server-addr`, `method` and `password` should be provided together");
            }
        };

    if !has_provided_config && !has_provided_server_config {
        println!("You have to specify a configuration file or pass arguments from argument list");
        println!("{}", matches.usage());
        return;
    }

    config.enable_udp |= matches.is_present("ENABLE_UDP");

    if let Some(p) = matches.value_of("PLUGIN") {
        let plugin = PluginConfig {
            plugin: p.to_owned(),
            plugin_opt: matches.value_of("PLUGIN_OPT").map(ToOwned::to_owned),
        };

        // Overrides config in file
        for svr in config.server.iter_mut() {
            svr.set_plugin(plugin.clone());
        }
    };

    info!("ShadowSocks {}", shadowsocks::VERSION);

    debug!("Config: {:?}", config);

    run_server(config).unwrap();
}
<commit_msg>Remove unused LOCAL_ADDR, LOCAL_PORT for ssserver<commit_after>//! This is a binary running in the server environment
//!
//! You have to provide all needed configuration attributes via command line parameters,
//! or you could specify a configuration file. The format of configuration file is defined
//! in mod `config`.
//!
//! *It should be notice that the extented configuration file is not suitable for the server
//! side.*

extern crate clap;
extern crate env_logger;
#[macro_use]
extern crate log;
extern crate shadowsocks;
extern crate time;

use std::env;

use clap::{App, Arg};

use env_logger::LogBuilder;
use log::{LogLevelFilter, LogRecord};

use shadowsocks::{run_server, Config, ConfigType, ServerAddr, ServerConfig};
use shadowsocks::plugin::PluginConfig;

fn log_time(without_time: bool, record: &LogRecord) -> String {
    if without_time {
        format!("[{}] {}", record.level(), record.args())
    } else {
        format!("[{}][{}] {}", time::now().strftime("%Y-%m-%d][%H:%M:%S.%f").unwrap(), record.level(), record.args())
    }
}

fn log_time_module(without_time: bool, record: &LogRecord) -> String {
    if without_time {
        format!("[{}] [{}] {}", record.level(), record.location().module_path(), record.args())
    } else {
        format!("[{}][{}] [{}] {}",
                time::now().strftime("%Y-%m-%d][%H:%M:%S.%f").unwrap(),
                record.level(),
                record.location().module_path(),
                record.args())
    }
}

fn main() {
    let matches = App::new("shadowsocks")
        .version(shadowsocks::VERSION)
        .author("Y. T. Chung")
        .about("A fast tunnel proxy that helps you bypass firewalls.")
        .arg(Arg::with_name("VERBOSE")
                 .short("v")
                 .multiple(true)
                 .help("Set the level of debug"))
        .arg(Arg::with_name("ENABLE_UDP")
                 .short("u")
                 .long("enable-udp")
                 .help("Enable UDP relay"))
        .arg(Arg::with_name("CONFIG")
                 .short("c")
                 .long("config")
                 .takes_value(true)
                 .help("Specify config file"))
        .arg(Arg::with_name("SERVER_ADDR")
                 .short("s")
                 .long("server-addr")
                 .takes_value(true)
                 .help("Server address"))
        .arg(Arg::with_name("PASSWORD")
                 .short("k")
                 .long("password")
                 .takes_value(true)
                 .help("Password"))
        .arg(Arg::with_name("ENCRYPT_METHOD")
                 .short("m")
                 .long("encrypt-method")
                 .takes_value(true)
                 .help("Encryption method"))
        .arg(Arg::with_name("PLUGIN")
                 .long("plugin")
                 .takes_value(true)
                 .help("Enable SIP003 plugin. (Experimental)"))
        .arg(Arg::with_name("PLUGIN_OPT")
                 .long("plugin-opts")
                 .takes_value(true)
                 .help("Set SIP003 plugin options. (Experimental)"))
        .arg(Arg::with_name("LOG_WITHOUT_TIME")
                 .long("log-without-time")
                 .help("Disable time in log"))
        .get_matches();

    let mut log_builder = LogBuilder::new();
    log_builder.filter(None, LogLevelFilter::Info);

    let without_time = matches.is_present("LOG_WITHOUT_TIME");

    let debug_level = matches.occurrences_of("VERBOSE");
    match debug_level {
        0 => {
            // Default filter
            log_builder.format(move |r| log_time(without_time, r));
        }
        1 => {
            let log_builder = log_builder.format(move |r| log_time_module(without_time, r));
            log_builder.filter(Some("ssserver"), LogLevelFilter::Debug);
        }
        2 => {
            let log_builder = log_builder.format(move |r| log_time_module(without_time, r));
            log_builder.filter(Some("ssserver"), LogLevelFilter::Debug)
                       .filter(Some("shadowsocks"), LogLevelFilter::Debug);
        }
        3 => {
            let log_builder = log_builder.format(move |r| log_time_module(without_time, r));
            log_builder.filter(Some("ssserver"), LogLevelFilter::Trace)
                       .filter(Some("shadowsocks"), LogLevelFilter::Trace);
        }
        _ => {
            let log_builder = log_builder.format(move |r| log_time_module(without_time, r));
            log_builder.filter(None, LogLevelFilter::Trace);
        }
    }

    if let Ok(env_conf) = env::var("RUST_LOG") {
        log_builder.parse(&env_conf);
    }

    log_builder.init().unwrap();

    let mut has_provided_config = false;
    let mut config = match matches.value_of("CONFIG") {
        Some(cpath) => {
            match Config::load_from_file(cpath, ConfigType::Server) {
                Ok(cfg) => {
                    has_provided_config = true;
                    cfg
                }
                Err(err) => {
                    error!("{:?}", err);
                    return;
                }
            }
        }
        None => Config::new(),
    };

    let has_provided_server_config =
        match (matches.value_of("SERVER_ADDR"), matches.value_of("PASSWORD"), matches.value_of("ENCRYPT_METHOD")) {
            (Some(svr_addr), Some(password), Some(method)) => {
                let method = match method.parse() {
                    Ok(m) => m,
                    Err(err) => {
                        panic!("Does not support {:?} method: {:?}", method, err);
                    }
                };

                let sc = ServerConfig::new(svr_addr.parse::<ServerAddr>().expect("Invalid server addr"),
                                           password.to_owned(),
                                           method,
                                           None,
                                           None);

                config.server.push(sc);
                true
            }
            (None, None, None) => {
                // Does not provide server config
                false
            }
            _ => {
                panic!("`server-addr`, `method` and `password` should be provided together");
            }
        };

    if !has_provided_config && !has_provided_server_config {
        println!("You have to specify a configuration file or pass arguments from argument list");
        println!("{}", matches.usage());
        return;
    }

    config.enable_udp |= matches.is_present("ENABLE_UDP");

    if let Some(p) = matches.value_of("PLUGIN") {
        let plugin = PluginConfig {
            plugin: p.to_owned(),
            plugin_opt: matches.value_of("PLUGIN_OPT").map(ToOwned::to_owned),
        };

        // Overrides config in file
        for svr in config.server.iter_mut() {
            svr.set_plugin(plugin.clone());
        }
    };

    info!("ShadowSocks {}", shadowsocks::VERSION);

    debug!("Config: {:?}", config);

    run_server(config).unwrap();
}
<|endoftext|>


<commit_before>#[cfg_attr(rustfmt, rustfmt_skip)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct Entry {
    pub id          : String,
    pub osm_node    : Option<u64>,
    pub created     : u64,
    pub version     : u64,
    pub title       : String,
    pub description : String,
    pub lat         : f64,
    pub lng         : f64,
    pub street      : Option<String>,
    pub zip         : Option<String>,
    pub city        : Option<String>,
    pub country     : Option<String>,
    pub email       : Option<String>,
    pub telephone   : Option<String>,
    pub homepage    : Option<String>,
    pub categories  : Vec<String>,
    pub tags        : Vec<String>,
    pub license     : Option<String>,
    pub image_url     : Option<String>,
    pub image_link_url: Option<String>,
}

#[cfg_attr(rustfmt, rustfmt_skip)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct Category {
    pub id      : String,
    pub created : u64,
    pub version : u64,
    pub name    : String
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct Tag {
    pub id: String,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub enum ObjectId {
    #[serde(rename = "entry")]
    Entry(String),
    #[serde(rename = "tag")]
    Tag(String),
    #[serde(rename = "user")]
    User(String),
    #[serde(rename = "comment")]
    Comment(String),
    #[serde(rename = "rating")]
    Rating(String),
    #[serde(rename = "bbox_subscription")]
    BboxSubscription(String),
}

#[cfg_attr(rustfmt, rustfmt_skip)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct User {
    pub id              : String, // TODO: remove
    pub username        : String,
    pub password        : String,
    pub email           : String,
    pub email_confirmed : bool,
}

#[cfg_attr(rustfmt, rustfmt_skip)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct Comment {
    pub id        : String,
    pub created   : u64,
    pub text      : String,
    pub rating_id : String,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub enum RatingContext {
    #[serde(rename = "diversity")]
    Diversity,
    #[serde(rename = "renewable")]
    Renewable,
    #[serde(rename = "fairness")]
    Fairness,
    #[serde(rename = "humanity")]
    Humanity,
    #[serde(rename = "transparency")]
    Transparency,
    #[serde(rename = "solidarity")]
    Solidarity,
}

#[cfg_attr(rustfmt, rustfmt_skip)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct Rating {
    pub id       : String,
    pub entry_id : String,
    pub created  : u64,
    pub title    : String,
    pub value    : i8,
    pub context  : RatingContext,
    pub source   : Option<String>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub struct Coordinate {
    pub lat: f64,
    pub lng: f64,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct Bbox {
    pub south_west: Coordinate,
    pub north_east: Coordinate,
}

#[cfg_attr(rustfmt, rustfmt_skip)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct BboxSubscription {
    pub id       : String,
    pub bbox     : Bbox,
    pub username : String,
}

#[cfg(test)]
pub use self::entry_builder::*;

#[cfg(test)]
pub mod entry_builder {

    use super::*;
    use uuid::Uuid;

    pub trait EntryBuilder {
        fn build() -> EntryBuild;
    }

    pub struct EntryBuild {
        entry: Entry,
    }

    impl EntryBuild {
        pub fn id(mut self, id: &str) -> Self {
            self.entry.id = id.into();
            self
        }
        pub fn version(mut self, v: u64) -> Self {
            self.entry.version = v;
            self
        }
        pub fn title(mut self, title: &str) -> Self {
            self.entry.title = title.into();
            self
        }
        pub fn description(mut self, desc: &str) -> Self {
            self.entry.description = desc.into();
            self
        }
        pub fn lat(mut self, lat: f64) -> Self {
            self.entry.lat = lat;
            self
        }
        pub fn lng(mut self, lng: f64) -> Self {
            self.entry.lng = lng;
            self
        }
        pub fn categories(mut self, cats: Vec<&str>) -> Self {
            self.entry.categories = cats.into_iter().map(|x| x.into()).collect();
            self
        }
        pub fn tags(mut self, tags: Vec<&str>) -> Self {
            self.entry.tags = tags.into_iter().map(|x| x.into()).collect();
            self
        }
        pub fn license(mut self, license: Option<&str>) -> Self {
            self.entry.license = license.map(|s| s.into());
            self
        }
        pub fn image_url(mut self, image_url: Option<&str>) -> Self {
            self.entry.image_url = image_url.map(Into::into);
            self
        }
        pub fn image_link_url(mut self, image_link_url: Option<&str>) -> Self {
            self.entry.image_link_url = image_link_url.map(Into::into);
            self
        }
        pub fn finish(self) -> Entry {
            self.entry
        }
    }

    impl EntryBuilder for Entry {
        fn build() -> EntryBuild {
            EntryBuild {
                entry: Entry::default(),
            }
        }
    }

    impl Default for Entry {
        fn default() -> Entry {
            #[cfg_attr(rustfmt, rustfmt_skip)]
            Entry{
                id          : Uuid::new_v4().simple().to_string(),
                osm_node    : None,
                created     : 0,
                version     : 0,
                title       : "".into(),
                description : "".into(),
                lat         : 0.0,
                lng         : 0.0,
                street      : None,
                zip         : None,
                city        : None,
                country     : None,
                email       : None,
                telephone   : None,
                homepage    : None,
                categories  : vec![],
                tags        : vec![],
                license     : None,
                image_url     : None,
                image_link_url: None,
            }
        }
    }

}
<commit_msg>Use Serde container attribute 'rename_all'<commit_after>#[cfg_attr(rustfmt, rustfmt_skip)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct Entry {
    pub id          : String,
    pub osm_node    : Option<u64>,
    pub created     : u64,
    pub version     : u64,
    pub title       : String,
    pub description : String,
    pub lat         : f64,
    pub lng         : f64,
    pub street      : Option<String>,
    pub zip         : Option<String>,
    pub city        : Option<String>,
    pub country     : Option<String>,
    pub email       : Option<String>,
    pub telephone   : Option<String>,
    pub homepage    : Option<String>,
    pub categories  : Vec<String>,
    pub tags        : Vec<String>,
    pub license     : Option<String>,
    pub image_url     : Option<String>,
    pub image_link_url: Option<String>,
}

#[cfg_attr(rustfmt, rustfmt_skip)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct Category {
    pub id      : String,
    pub created : u64,
    pub version : u64,
    pub name    : String
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct Tag {
    pub id: String,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum ObjectId {
    Entry(String),
    Tag(String),
    User(String),
    Comment(String),
    Rating(String),
    BboxSubscription(String),
}

#[cfg_attr(rustfmt, rustfmt_skip)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct User {
    pub id              : String, // TODO: remove
    pub username        : String,
    pub password        : String,
    pub email           : String,
    pub email_confirmed : bool,
}

#[cfg_attr(rustfmt, rustfmt_skip)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct Comment {
    pub id        : String,
    pub created   : u64,
    pub text      : String,
    pub rating_id : String,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum RatingContext {
    Diversity,
    Renewable,
    Fairness,
    Humanity,
    Transparency,
    Solidarity,
}

#[cfg_attr(rustfmt, rustfmt_skip)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct Rating {
    pub id       : String,
    pub entry_id : String,
    pub created  : u64,
    pub title    : String,
    pub value    : i8,
    pub context  : RatingContext,
    pub source   : Option<String>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub struct Coordinate {
    pub lat: f64,
    pub lng: f64,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct Bbox {
    pub south_west: Coordinate,
    pub north_east: Coordinate,
}

#[cfg_attr(rustfmt, rustfmt_skip)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
pub struct BboxSubscription {
    pub id       : String,
    pub bbox     : Bbox,
    pub username : String,
}

#[cfg(test)]
pub use self::entry_builder::*;

#[cfg(test)]
pub mod entry_builder {

    use super::*;
    use uuid::Uuid;

    pub trait EntryBuilder {
        fn build() -> EntryBuild;
    }

    pub struct EntryBuild {
        entry: Entry,
    }

    impl EntryBuild {
        pub fn id(mut self, id: &str) -> Self {
            self.entry.id = id.into();
            self
        }
        pub fn version(mut self, v: u64) -> Self {
            self.entry.version = v;
            self
        }
        pub fn title(mut self, title: &str) -> Self {
            self.entry.title = title.into();
            self
        }
        pub fn description(mut self, desc: &str) -> Self {
            self.entry.description = desc.into();
            self
        }
        pub fn lat(mut self, lat: f64) -> Self {
            self.entry.lat = lat;
            self
        }
        pub fn lng(mut self, lng: f64) -> Self {
            self.entry.lng = lng;
            self
        }
        pub fn categories(mut self, cats: Vec<&str>) -> Self {
            self.entry.categories = cats.into_iter().map(|x| x.into()).collect();
            self
        }
        pub fn tags(mut self, tags: Vec<&str>) -> Self {
            self.entry.tags = tags.into_iter().map(|x| x.into()).collect();
            self
        }
        pub fn license(mut self, license: Option<&str>) -> Self {
            self.entry.license = license.map(|s| s.into());
            self
        }
        pub fn image_url(mut self, image_url: Option<&str>) -> Self {
            self.entry.image_url = image_url.map(Into::into);
            self
        }
        pub fn image_link_url(mut self, image_link_url: Option<&str>) -> Self {
            self.entry.image_link_url = image_link_url.map(Into::into);
            self
        }
        pub fn finish(self) -> Entry {
            self.entry
        }
    }

    impl EntryBuilder for Entry {
        fn build() -> EntryBuild {
            EntryBuild {
                entry: Entry::default(),
            }
        }
    }

    impl Default for Entry {
        fn default() -> Entry {
            #[cfg_attr(rustfmt, rustfmt_skip)]
            Entry{
                id          : Uuid::new_v4().simple().to_string(),
                osm_node    : None,
                created     : 0,
                version     : 0,
                title       : "".into(),
                description : "".into(),
                lat         : 0.0,
                lng         : 0.0,
                street      : None,
                zip         : None,
                city        : None,
                country     : None,
                email       : None,
                telephone   : None,
                homepage    : None,
                categories  : vec![],
                tags        : vec![],
                license     : None,
                image_url     : None,
                image_link_url: None,
            }
        }
    }

}
<|endoftext|>


<commit_before>use std::sync::{Mutex, Arc};
use std::net::{SocketAddr, ToSocketAddrs};
use std::collections::VecDeque;
use std::error::Error;
use std::mem;
use opengl_graphics::GlGraphics;
use opengl_graphics::glyph_cache::GlyphCache;
use piston::input::{Button, Key, MouseButton, RenderArgs, UpdateArgs};

use std::{thread, time};
use std::net::TcpStream;
use network::{Command, Message};

use bincode::{serialize_into, deserialize_from, Infinite};

use state::{UnitId, ClientId, WorldState, GameState, UNIT_SIZE};
use shapes::Shape;
use colors;
use colors::{BLACK, ORANGE, WHITE};

pub mod menu;
pub mod error;

use self::menu::Menu;

pub struct NetworkClient {
    pub game_state: Arc<Mutex<Option<GameState>>>,
    server_addr: SocketAddr,
    stream: Option<TcpStream>,
    commands: Arc<Mutex<VecDeque<Command>>>,
}

impl NetworkClient {
    pub fn new<T: ToSocketAddrs>(server_addrs: T,
                                 game_state: Arc<Mutex<Option<GameState>>>,
                                 commands: Arc<Mutex<VecDeque<Command>>>) -> NetworkClient {
        let server_addr = server_addrs.to_socket_addrs().unwrap().next().unwrap();
        NetworkClient {
            game_state: game_state,
            server_addr: server_addr,
            stream: None,
            commands: commands,
        }
    }

    pub fn connect(&mut self) -> Result<(ClientId, WorldState), Box<Error>>  {
        let mut stream = TcpStream::connect(self.server_addr)?;
        serialize_into(&mut stream, &Message::ClientHello, Infinite)?;
        let server_hello = deserialize_from(&mut stream, Infinite);

        self.stream = Some(stream);
        if let Ok(Message::ServerHello(client_id, world_state)) = server_hello {
            Ok((client_id, world_state))
        } else {
            Err("Could not connect to server".into())
        }
    }

    pub fn update(&self) {
        let stream = self.stream.as_ref().expect("Stream not here :(");
        let mut command_stream = stream.try_clone().unwrap();
        let commands = self.commands.clone();

        // Command sender loop
        thread::spawn(move || {
            loop {
                let command = {
                    let mut commands = commands.lock().unwrap();
                    commands.pop_front()
                };
                command.map(|cmd| {
                    println!("Got command: {:?}", cmd);
                    //let cmd = Message::Command(Command::Move(0.into(), [100f64, 100f64]));
                    serialize_into(&mut command_stream, &Message::Command(cmd), Infinite)
                        .unwrap_or_else(|e|println!("Sending command failed: {}", e));
                });
                thread::sleep(time::Duration::from_millis(10));
            }
        });

        let mut game_state_stream = stream.try_clone().unwrap();
        let game_state = self.game_state.clone();
        thread::spawn(move || {
            loop {
                let game_state_server: Result<GameState,_> = deserialize_from(
                    &mut game_state_stream,
                    Infinite);
                match game_state_server {
                    Ok(game) => {
                        //println!("{:?}", game);
                        let mut game_state_lock = game_state.lock().unwrap();
                        *game_state_lock = Some(game);

                    }
                    Err(e) => {
                        println!("{:?}", e);
                        thread::sleep(time::Duration::from_millis(200));
                    }
                }
            }
        });
    }
}

#[derive(Clone, Debug)]
pub enum State {
    Menu,
    Error(error::Message),
    Running,
}

pub struct App {
    pub gl: GlGraphics, // OpenGL drawing backend.
    pub world_state: Option<WorldState>,
    pub game_state_server: Arc<Mutex<Option<GameState>>>,
    pub game_state: GameState,
    pub selected_units: Vec<UnitId>,
    pub commands: Arc<Mutex<VecDeque<Command>>>,
    pub cursor: [f64; 2],
    pub state: State,
    zoom: f64,
    scroll: [f64; 2],
    menu: Menu,
    client_id: Option<ClientId>,
}

impl App {
    pub fn new(gl: GlGraphics) -> App {
        App {
            gl: gl,
            world_state: None,
            game_state_server: Arc::new(Mutex::new(None)),
            game_state: GameState::new(),
            selected_units: vec![],
            commands: Arc::new(Mutex::new(VecDeque::new())),
            cursor: [0.0, 0.0],
            state: State::Menu,
            zoom: 1.0,
            scroll: [0.0, 0.0],
            menu: Menu::new(),
            client_id: None,
        }
    }

    pub fn start(&mut self) -> Result<(), Box<Error>> {
        let mut network_client = NetworkClient::new(
            ("127.0.0.1", 8080),
            self.game_state_server.clone(),
            self.commands.clone());
        let (client_id, world_state) = network_client.connect()?;
        self.client_id = Some(client_id);
        self.world_state = Some(world_state);
        network_client.update();
        Ok(())
    }

    pub fn select(&mut self, position: [f64;2]) {

        let player = {
            let index = self.client_id.unwrap_or(ClientId(0)).0 as usize;
            self.game_state.players.get(index).map(|v| v.clone())
        };

        self.selected_units.truncate(0);
        if let Some(player) = player {
            for unit in player.units.iter() {
                if unit.is_hit(UNIT_SIZE, position) {
                    self.selected_units.push(unit.id);
                }
            }
        }
    }

    fn render_game(&mut self, args: &RenderArgs, _: &mut GlyphCache) {
        use graphics::{polygon, line, clear, ellipse};
        use graphics::Transformed;
        use graphics::types::{Polygon, Line};

        const FRONT_THICKNESS: f64 = 5.0;

        let game_state = &self.game_state;
        let world = self.world_state.as_ref().unwrap();
        let (wx, wy) = (world.x, world.y);
        let zoom = self.zoom;
        let scroll = self.scroll;
        let selected_units = self.selected_units.clone();

        self.gl.draw(args.viewport(), |c, gl| {

            let transform = c.transform
                .scale(zoom, zoom)
                .trans(scroll[0], scroll[1]);

            // Clear the screen.
            clear(BLACK, gl);

            let world: [Line; 4] = [
                [0.0, 0.0, wx,  0.0],
                [wx,  0.0, wx,  wy],
                [wx,  wy,  0.0, wy],
                [0.0, wy,  0.0, 0.0],
            ];

            for l in world.iter() {
                line(ORANGE, 1.0, *l, transform, gl);
            }

            for i in 0..game_state.players.len() {
                let ref player = game_state.players[i];
                let color = &colors::PLAYERS[i % colors::PLAYERS.len()];
                for s in player.units.iter() {
                    // Create a triangle polygon. The initial orientation is facing east.
                    let triangle: Polygon = &s.get_shape(UNIT_SIZE);

                    // Create a border on the front of the polygon. This is a trapezoid.
                    // Because the angle of the trapezoid side is 22.5°, we know that `dx` is always `2 * dy`.
                    let front: Polygon = &[
                        [UNIT_SIZE, UNIT_SIZE],                                           // Top right
                        [UNIT_SIZE, 0.0],                                                 // Bottom right
                        [UNIT_SIZE - FRONT_THICKNESS, FRONT_THICKNESS / 2.0],             // Bottom left
                        [UNIT_SIZE - FRONT_THICKNESS, UNIT_SIZE - FRONT_THICKNESS / 2.0], // Top left
                    ];

                    // Rotate the front to match the unit
                    let transform_front = transform.trans(s.position[0], s.position[1])
                        .rot_rad(s.angle)
                        .trans(-0.5 * UNIT_SIZE, -0.5 * UNIT_SIZE);

                    // We don't need to apply any transformation to the units
                    let transform_triangle = transform;

                    // Draw the unit ORANGE if selected
                    let selected = selected_units.iter().any(|id| id == &s.id);
                    if selected {
                        polygon(color.primary, triangle, transform_triangle, gl);
                        polygon(color.secondary, front, transform_front, gl);
                    } else {
                        polygon(color.secondary, triangle, transform_triangle, gl);
                        polygon(color.primary, front, transform_front, gl);
                    }

                }
            }
            for b in game_state.bullets.iter() {
                let transform = transform.trans(b.position[0], b.position[1]);
                ellipse(WHITE, [0.0, 0.0, 1.0, 1.0], transform, gl);
            }
        });
    }

    pub fn render(&mut self, args: &RenderArgs, cache: &mut GlyphCache) {
        match self.state {
            State::Menu => self.menu.render(args, &mut self.gl, cache),
            State::Running => self.render_game(args, cache),
            State::Error(ref msg) => msg.render(args, &mut self.gl, cache),
        }
    }

    pub fn update(&mut self, args: &UpdateArgs) {
        // grab updated server state if it is available
        let game_state_option = {
            let mut game_state_lock = self.game_state_server.lock().unwrap();
            mem::replace(&mut *game_state_lock, None)
        };
        if let Some(game_state) = game_state_option {
            self.game_state = game_state;
        } else {
            if let Some(ref world) = self.world_state {
                self.game_state.update(world, args.dt*1000.0);
            }
        }
    }

    pub fn on_button_press(&mut self, button: &Button) -> bool {
        match self.state {
            State::Menu => {
                match button {
                    &Button::Keyboard(Key::Up) => {
                        self.menu.previous();
                    }
                    &Button::Keyboard(Key::Down) => {
                        self.menu.next();
                    }
                    &Button::Keyboard(Key::Return) => {
                        match self.menu.get_selected_entry() {
                            menu::Entries::Start => {
                                match self.start() {
                                    Ok(_) => {
                                        self.state = State::Running;
                                    }
                                    Err(err) => {
                                        self.state = State::Error(error::Message::new(err.description().into()));
                                    }
                                }
                            }
                            menu::Entries::Exit => {
                                return true;
                            }
                        }
                    }
                    _ => { }
                }
            }
            State::Running => {
                match button {
                    &Button::Keyboard(Key::Up) => {
                        self.scroll[1] += 10.0;
                    }
                    &Button::Keyboard(Key::Down) => {
                        self.scroll[1] -= 10.0;
                    }
                    &Button::Keyboard(Key::Left) => {
                        self.scroll[0] += 10.0;
                    }
                    &Button::Keyboard(Key::Right) => {
                        self.scroll[0] -= 10.0;
                    }
                    &Button::Keyboard(Key::F) => {
                        self.shoot_selected();
                    }
                    &Button::Keyboard(_) => { }
                    &Button::Mouse(button) => {
                        self.on_mouse_click(&button);
                    }
                    &Button::Controller(_) => { }
                }
            }
            State::Error(_) => {
                match button {
                    &Button::Keyboard(_) => { self.state = State::Menu; }
                    _ => { }
                }
            }
        };
        false
    }

    pub fn on_mouse_click(&mut self, button: &MouseButton) {
        let cursor = [
            self.cursor[0] / self.zoom - self.scroll[0],
            self.cursor[1] / self.zoom - self.scroll[1],
        ];
        match *button {
            MouseButton::Left  => self.select(cursor),
            MouseButton::Right => self.move_selected(cursor),
            _ => println!("Pressed mouse button '{:?}'", button),
        }
    }

    pub fn on_mouse_move(&mut self, cursor: [f64; 2]) {
        self.cursor = cursor;
    }

    pub fn on_mouse_scroll(&mut self, scroll: [f64; 2]) {
        if scroll[1] > 0.0 {
            self.zoom *= 1.5 * scroll[1];
        } else {
            self.zoom /= 1.5 * -scroll[1];
        }
        println!("zoom: {}", self.zoom);
    }

    pub fn move_selected(&mut self, position: [f64;2]) {
        for u in self.selected_units.iter() {
            let mut commands = self.commands.lock().unwrap();
            commands.push_back(Command::Move(*u, position));
        }
    }

    pub fn shoot_selected(&mut self) {
        for u in self.selected_units.iter() {
            let mut commands = self.commands.lock().unwrap();
            commands.push_back(Command::Shoot(*u));
        }
    }
}
<commit_msg>client: Rename shoot_selected to shoot<commit_after>use std::sync::{Mutex, Arc};
use std::net::{SocketAddr, ToSocketAddrs};
use std::collections::VecDeque;
use std::error::Error;
use std::mem;
use opengl_graphics::GlGraphics;
use opengl_graphics::glyph_cache::GlyphCache;
use piston::input::{Button, Key, MouseButton, RenderArgs, UpdateArgs};

use std::{thread, time};
use std::net::TcpStream;
use network::{Command, Message};

use bincode::{serialize_into, deserialize_from, Infinite};

use state::{UnitId, ClientId, WorldState, GameState, UNIT_SIZE};
use shapes::Shape;
use colors;
use colors::{BLACK, ORANGE, WHITE};

pub mod menu;
pub mod error;

use self::menu::Menu;

pub struct NetworkClient {
    pub game_state: Arc<Mutex<Option<GameState>>>,
    server_addr: SocketAddr,
    stream: Option<TcpStream>,
    commands: Arc<Mutex<VecDeque<Command>>>,
}

impl NetworkClient {
    pub fn new<T: ToSocketAddrs>(server_addrs: T,
                                 game_state: Arc<Mutex<Option<GameState>>>,
                                 commands: Arc<Mutex<VecDeque<Command>>>) -> NetworkClient {
        let server_addr = server_addrs.to_socket_addrs().unwrap().next().unwrap();
        NetworkClient {
            game_state: game_state,
            server_addr: server_addr,
            stream: None,
            commands: commands,
        }
    }

    pub fn connect(&mut self) -> Result<(ClientId, WorldState), Box<Error>>  {
        let mut stream = TcpStream::connect(self.server_addr)?;
        serialize_into(&mut stream, &Message::ClientHello, Infinite)?;
        let server_hello = deserialize_from(&mut stream, Infinite);

        self.stream = Some(stream);
        if let Ok(Message::ServerHello(client_id, world_state)) = server_hello {
            Ok((client_id, world_state))
        } else {
            Err("Could not connect to server".into())
        }
    }

    pub fn update(&self) {
        let stream = self.stream.as_ref().expect("Stream not here :(");
        let mut command_stream = stream.try_clone().unwrap();
        let commands = self.commands.clone();

        // Command sender loop
        thread::spawn(move || {
            loop {
                let command = {
                    let mut commands = commands.lock().unwrap();
                    commands.pop_front()
                };
                command.map(|cmd| {
                    println!("Got command: {:?}", cmd);
                    //let cmd = Message::Command(Command::Move(0.into(), [100f64, 100f64]));
                    serialize_into(&mut command_stream, &Message::Command(cmd), Infinite)
                        .unwrap_or_else(|e|println!("Sending command failed: {}", e));
                });
                thread::sleep(time::Duration::from_millis(10));
            }
        });

        let mut game_state_stream = stream.try_clone().unwrap();
        let game_state = self.game_state.clone();
        thread::spawn(move || {
            loop {
                let game_state_server: Result<GameState,_> = deserialize_from(
                    &mut game_state_stream,
                    Infinite);
                match game_state_server {
                    Ok(game) => {
                        //println!("{:?}", game);
                        let mut game_state_lock = game_state.lock().unwrap();
                        *game_state_lock = Some(game);

                    }
                    Err(e) => {
                        println!("{:?}", e);
                        thread::sleep(time::Duration::from_millis(200));
                    }
                }
            }
        });
    }
}

#[derive(Clone, Debug)]
pub enum State {
    Menu,
    Error(error::Message),
    Running,
}

pub struct App {
    pub gl: GlGraphics, // OpenGL drawing backend.
    pub world_state: Option<WorldState>,
    pub game_state_server: Arc<Mutex<Option<GameState>>>,
    pub game_state: GameState,
    pub selected_units: Vec<UnitId>,
    pub commands: Arc<Mutex<VecDeque<Command>>>,
    pub cursor: [f64; 2],
    pub state: State,
    zoom: f64,
    scroll: [f64; 2],
    menu: Menu,
    client_id: Option<ClientId>,
}

impl App {
    pub fn new(gl: GlGraphics) -> App {
        App {
            gl: gl,
            world_state: None,
            game_state_server: Arc::new(Mutex::new(None)),
            game_state: GameState::new(),
            selected_units: vec![],
            commands: Arc::new(Mutex::new(VecDeque::new())),
            cursor: [0.0, 0.0],
            state: State::Menu,
            zoom: 1.0,
            scroll: [0.0, 0.0],
            menu: Menu::new(),
            client_id: None,
        }
    }

    pub fn start(&mut self) -> Result<(), Box<Error>> {
        let mut network_client = NetworkClient::new(
            ("127.0.0.1", 8080),
            self.game_state_server.clone(),
            self.commands.clone());
        let (client_id, world_state) = network_client.connect()?;
        self.client_id = Some(client_id);
        self.world_state = Some(world_state);
        network_client.update();
        Ok(())
    }

    pub fn select(&mut self, position: [f64;2]) {

        let player = {
            let index = self.client_id.unwrap_or(ClientId(0)).0 as usize;
            self.game_state.players.get(index).map(|v| v.clone())
        };

        self.selected_units.truncate(0);
        if let Some(player) = player {
            for unit in player.units.iter() {
                if unit.is_hit(UNIT_SIZE, position) {
                    self.selected_units.push(unit.id);
                }
            }
        }
    }

    fn render_game(&mut self, args: &RenderArgs, _: &mut GlyphCache) {
        use graphics::{polygon, line, clear, ellipse};
        use graphics::Transformed;
        use graphics::types::{Polygon, Line};

        const FRONT_THICKNESS: f64 = 5.0;

        let game_state = &self.game_state;
        let world = self.world_state.as_ref().unwrap();
        let (wx, wy) = (world.x, world.y);
        let zoom = self.zoom;
        let scroll = self.scroll;
        let selected_units = self.selected_units.clone();

        self.gl.draw(args.viewport(), |c, gl| {

            let transform = c.transform
                .scale(zoom, zoom)
                .trans(scroll[0], scroll[1]);

            // Clear the screen.
            clear(BLACK, gl);

            let world: [Line; 4] = [
                [0.0, 0.0, wx,  0.0],
                [wx,  0.0, wx,  wy],
                [wx,  wy,  0.0, wy],
                [0.0, wy,  0.0, 0.0],
            ];

            for l in world.iter() {
                line(ORANGE, 1.0, *l, transform, gl);
            }

            for i in 0..game_state.players.len() {
                let ref player = game_state.players[i];
                let color = &colors::PLAYERS[i % colors::PLAYERS.len()];
                for s in player.units.iter() {
                    // Create a triangle polygon. The initial orientation is facing east.
                    let triangle: Polygon = &s.get_shape(UNIT_SIZE);

                    // Create a border on the front of the polygon. This is a trapezoid.
                    // Because the angle of the trapezoid side is 22.5°, we know that `dx` is always `2 * dy`.
                    let front: Polygon = &[
                        [UNIT_SIZE, UNIT_SIZE],                                           // Top right
                        [UNIT_SIZE, 0.0],                                                 // Bottom right
                        [UNIT_SIZE - FRONT_THICKNESS, FRONT_THICKNESS / 2.0],             // Bottom left
                        [UNIT_SIZE - FRONT_THICKNESS, UNIT_SIZE - FRONT_THICKNESS / 2.0], // Top left
                    ];

                    // Rotate the front to match the unit
                    let transform_front = transform.trans(s.position[0], s.position[1])
                        .rot_rad(s.angle)
                        .trans(-0.5 * UNIT_SIZE, -0.5 * UNIT_SIZE);

                    // We don't need to apply any transformation to the units
                    let transform_triangle = transform;

                    // Draw the unit ORANGE if selected
                    let selected = selected_units.iter().any(|id| id == &s.id);
                    if selected {
                        polygon(color.primary, triangle, transform_triangle, gl);
                        polygon(color.secondary, front, transform_front, gl);
                    } else {
                        polygon(color.secondary, triangle, transform_triangle, gl);
                        polygon(color.primary, front, transform_front, gl);
                    }

                }
            }
            for b in game_state.bullets.iter() {
                let transform = transform.trans(b.position[0], b.position[1]);
                ellipse(WHITE, [0.0, 0.0, 1.0, 1.0], transform, gl);
            }
        });
    }

    pub fn render(&mut self, args: &RenderArgs, cache: &mut GlyphCache) {
        match self.state {
            State::Menu => self.menu.render(args, &mut self.gl, cache),
            State::Running => self.render_game(args, cache),
            State::Error(ref msg) => msg.render(args, &mut self.gl, cache),
        }
    }

    pub fn update(&mut self, args: &UpdateArgs) {
        // grab updated server state if it is available
        let game_state_option = {
            let mut game_state_lock = self.game_state_server.lock().unwrap();
            mem::replace(&mut *game_state_lock, None)
        };
        if let Some(game_state) = game_state_option {
            self.game_state = game_state;
        } else {
            if let Some(ref world) = self.world_state {
                self.game_state.update(world, args.dt*1000.0);
            }
        }
    }

    pub fn on_button_press(&mut self, button: &Button) -> bool {
        match self.state {
            State::Menu => {
                match button {
                    &Button::Keyboard(Key::Up) => {
                        self.menu.previous();
                    }
                    &Button::Keyboard(Key::Down) => {
                        self.menu.next();
                    }
                    &Button::Keyboard(Key::Return) => {
                        match self.menu.get_selected_entry() {
                            menu::Entries::Start => {
                                match self.start() {
                                    Ok(_) => {
                                        self.state = State::Running;
                                    }
                                    Err(err) => {
                                        self.state = State::Error(error::Message::new(err.description().into()));
                                    }
                                }
                            }
                            menu::Entries::Exit => {
                                return true;
                            }
                        }
                    }
                    _ => { }
                }
            }
            State::Running => {
                match button {
                    &Button::Keyboard(Key::Up) => {
                        self.scroll[1] += 10.0;
                    }
                    &Button::Keyboard(Key::Down) => {
                        self.scroll[1] -= 10.0;
                    }
                    &Button::Keyboard(Key::Left) => {
                        self.scroll[0] += 10.0;
                    }
                    &Button::Keyboard(Key::Right) => {
                        self.scroll[0] -= 10.0;
                    }
                    &Button::Keyboard(Key::F) => {
                        self.shoot();
                    }
                    &Button::Keyboard(_) => { }
                    &Button::Mouse(button) => {
                        self.on_mouse_click(&button);
                    }
                    &Button::Controller(_) => { }
                }
            }
            State::Error(_) => {
                match button {
                    &Button::Keyboard(_) => { self.state = State::Menu; }
                    _ => { }
                }
            }
        };
        false
    }

    pub fn on_mouse_click(&mut self, button: &MouseButton) {
        let cursor = [
            self.cursor[0] / self.zoom - self.scroll[0],
            self.cursor[1] / self.zoom - self.scroll[1],
        ];
        match *button {
            MouseButton::Left  => self.select(cursor),
            MouseButton::Right => self.move_selected(cursor),
            _ => println!("Pressed mouse button '{:?}'", button),
        }
    }

    pub fn on_mouse_move(&mut self, cursor: [f64; 2]) {
        self.cursor = cursor;
    }

    pub fn on_mouse_scroll(&mut self, scroll: [f64; 2]) {
        if scroll[1] > 0.0 {
            self.zoom *= 1.5 * scroll[1];
        } else {
            self.zoom /= 1.5 * -scroll[1];
        }
        println!("zoom: {}", self.zoom);
    }

    pub fn move_selected(&mut self, position: [f64;2]) {
        for u in self.selected_units.iter() {
            let mut commands = self.commands.lock().unwrap();
            commands.push_back(Command::Move(*u, position));
        }
    }

    pub fn shoot(&mut self) {
        for u in self.selected_units.iter() {
            let mut commands = self.commands.lock().unwrap();
            commands.push_back(Command::Shoot(*u));
        }
    }
}
<|endoftext|>


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

//! Implementations of serialization for structures found in libcollections

use std::uint;
use std::default::Default;
use std::hash::{Hash, Hasher};

use {Decodable, Encodable, Decoder, Encoder};
use std::collections::{DList, RingBuf, BTreeMap, BTreeSet, HashMap, HashSet, VecMap};
use std::collections::enum_set::{EnumSet, CLike};

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E>
> Encodable<S, E> for DList<T> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_seq(self.len(), |s| {
            for (i, e) in self.iter().enumerate() {
                try!(s.emit_seq_elt(i, |s| e.encode(s)));
            }
            Ok(())
        })
    }
}

impl<E, D:Decoder<E>,T:Decodable<D, E>> Decodable<D, E> for DList<T> {
    fn decode(d: &mut D) -> Result<DList<T>, E> {
        d.read_seq(|d, len| {
            let mut list = DList::new();
            for i in range(0u, len) {
                list.push_back(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
            }
            Ok(list)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E>
> Encodable<S, E> for RingBuf<T> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_seq(self.len(), |s| {
            for (i, e) in self.iter().enumerate() {
                try!(s.emit_seq_elt(i, |s| e.encode(s)));
            }
            Ok(())
        })
    }
}

impl<E, D:Decoder<E>,T:Decodable<D, E>> Decodable<D, E> for RingBuf<T> {
    fn decode(d: &mut D) -> Result<RingBuf<T>, E> {
        d.read_seq(|d, len| {
            let mut deque: RingBuf<T> = RingBuf::new();
            for i in range(0u, len) {
                deque.push_back(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
            }
            Ok(deque)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    K: Encodable<S, E> + PartialEq + Ord,
    V: Encodable<S, E> + PartialEq
> Encodable<S, E> for BTreeMap<K, V> {
    fn encode(&self, e: &mut S) -> Result<(), E> {
        e.emit_map(self.len(), |e| {
            let mut i = 0;
            for (key, val) in self.iter() {
                try!(e.emit_map_elt_key(i, |e| key.encode(e)));
                try!(e.emit_map_elt_val(i, |e| val.encode(e)));
                i += 1;
            }
            Ok(())
        })
    }
}

impl<
    E,
    D: Decoder<E>,
    K: Decodable<D, E> + PartialEq + Ord,
    V: Decodable<D, E> + PartialEq
> Decodable<D, E> for BTreeMap<K, V> {
    fn decode(d: &mut D) -> Result<BTreeMap<K, V>, E> {
        d.read_map(|d, len| {
            let mut map = BTreeMap::new();
            for i in range(0u, len) {
                let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
                let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
                map.insert(key, val);
            }
            Ok(map)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E> + PartialEq + Ord
> Encodable<S, E> for BTreeSet<T> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_seq(self.len(), |s| {
            let mut i = 0;
            for e in self.iter() {
                try!(s.emit_seq_elt(i, |s| e.encode(s)));
                i += 1;
            }
            Ok(())
        })
    }
}

impl<
    E,
    D: Decoder<E>,
    T: Decodable<D, E> + PartialEq + Ord
> Decodable<D, E> for BTreeSet<T> {
    fn decode(d: &mut D) -> Result<BTreeSet<T>, E> {
        d.read_seq(|d, len| {
            let mut set = BTreeSet::new();
            for i in range(0u, len) {
                set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
            }
            Ok(set)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E> + CLike
> Encodable<S, E> for EnumSet<T> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        let mut bits = 0;
        for item in self.iter() {
            bits |= item.to_uint();
        }
        s.emit_uint(bits)
    }
}

impl<
    E,
    D: Decoder<E>,
    T: Decodable<D, E> + CLike
> Decodable<D, E> for EnumSet<T> {
    fn decode(d: &mut D) -> Result<EnumSet<T>, E> {
        let bits = try!(d.read_uint());
        let mut set = EnumSet::new();
        for bit in range(0, uint::BITS) {
            if bits & (1 << bit) != 0 {
                set.insert(CLike::from_uint(1 << bit));
            }
        }
        Ok(set)
    }
}

impl<
    E,
    S: Encoder<E>,
    K: Encodable<S, E> + Hash<X> + Eq,
    V: Encodable<S, E>,
    X,
    H: Hasher<X>
> Encodable<S, E> for HashMap<K, V, H> {
    fn encode(&self, e: &mut S) -> Result<(), E> {
        e.emit_map(self.len(), |e| {
            let mut i = 0;
            for (key, val) in self.iter() {
                try!(e.emit_map_elt_key(i, |e| key.encode(e)));
                try!(e.emit_map_elt_val(i, |e| val.encode(e)));
                i += 1;
            }
            Ok(())
        })
    }
}

impl<
    E,
    D: Decoder<E>,
    K: Decodable<D, E> + Hash<S> + Eq,
    V: Decodable<D, E>,
    S,
    H: Hasher<S> + Default
> Decodable<D, E> for HashMap<K, V, H> {
    fn decode(d: &mut D) -> Result<HashMap<K, V, H>, E> {
        d.read_map(|d, len| {
            let hasher = Default::default();
            let mut map = HashMap::with_capacity_and_hasher(len, hasher);
            for i in range(0u, len) {
                let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
                let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
                map.insert(key, val);
            }
            Ok(map)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E> + Hash<X> + Eq,
    X,
    H: Hasher<X>
> Encodable<S, E> for HashSet<T, H> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_seq(self.len(), |s| {
            let mut i = 0;
            for e in self.iter() {
                try!(s.emit_seq_elt(i, |s| e.encode(s)));
                i += 1;
            }
            Ok(())
        })
    }
}

impl<
    E,
    D: Decoder<E>,
    T: Decodable<D, E> + Hash<S> + Eq,
    S,
    H: Hasher<S> + Default
> Decodable<D, E> for HashSet<T, H> {
    fn decode(d: &mut D) -> Result<HashSet<T, H>, E> {
        d.read_seq(|d, len| {
            let mut set = HashSet::with_capacity_and_hasher(len, Default::default());
            for i in range(0u, len) {
                set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
            }
            Ok(set)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    V: Encodable<S, E>
> Encodable<S, E> for VecMap<V> {
    fn encode(&self, e: &mut S) -> Result<(), E> {
        e.emit_map(self.len(), |e| {
                for (i, (key, val)) in self.iter().enumerate() {
                    try!(e.emit_map_elt_key(i, |e| key.encode(e)));
                    try!(e.emit_map_elt_val(i, |e| val.encode(e)));
                }
                Ok(())
            })
    }
}

impl<
    E,
    D: Decoder<E>,
    V: Decodable<D, E>
> Decodable<D, E> for VecMap<V> {
    fn decode(d: &mut D) -> Result<VecMap<V>, E> {
        d.read_map(|d, len| {
            let mut map = VecMap::new();
            for i in range(0u, len) {
                let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
                let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
                map.insert(key, val);
            }
            Ok(map)
        })
    }
}
<commit_msg>Drop support for `enum_set`.<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementations of serialization for structures found in libcollections

use std::uint;
use std::default::Default;
use std::hash::{Hash, Hasher};

use {Decodable, Encodable, Decoder, Encoder};
use std::collections::{DList, RingBuf, BTreeMap, BTreeSet, HashMap, HashSet, VecMap};

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E>
> Encodable<S, E> for DList<T> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_seq(self.len(), |s| {
            for (i, e) in self.iter().enumerate() {
                try!(s.emit_seq_elt(i, |s| e.encode(s)));
            }
            Ok(())
        })
    }
}

impl<E, D:Decoder<E>,T:Decodable<D, E>> Decodable<D, E> for DList<T> {
    fn decode(d: &mut D) -> Result<DList<T>, E> {
        d.read_seq(|d, len| {
            let mut list = DList::new();
            for i in range(0u, len) {
                list.push_back(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
            }
            Ok(list)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E>
> Encodable<S, E> for RingBuf<T> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_seq(self.len(), |s| {
            for (i, e) in self.iter().enumerate() {
                try!(s.emit_seq_elt(i, |s| e.encode(s)));
            }
            Ok(())
        })
    }
}

impl<E, D:Decoder<E>,T:Decodable<D, E>> Decodable<D, E> for RingBuf<T> {
    fn decode(d: &mut D) -> Result<RingBuf<T>, E> {
        d.read_seq(|d, len| {
            let mut deque: RingBuf<T> = RingBuf::new();
            for i in range(0u, len) {
                deque.push_back(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
            }
            Ok(deque)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    K: Encodable<S, E> + PartialEq + Ord,
    V: Encodable<S, E> + PartialEq
> Encodable<S, E> for BTreeMap<K, V> {
    fn encode(&self, e: &mut S) -> Result<(), E> {
        e.emit_map(self.len(), |e| {
            let mut i = 0;
            for (key, val) in self.iter() {
                try!(e.emit_map_elt_key(i, |e| key.encode(e)));
                try!(e.emit_map_elt_val(i, |e| val.encode(e)));
                i += 1;
            }
            Ok(())
        })
    }
}

impl<
    E,
    D: Decoder<E>,
    K: Decodable<D, E> + PartialEq + Ord,
    V: Decodable<D, E> + PartialEq
> Decodable<D, E> for BTreeMap<K, V> {
    fn decode(d: &mut D) -> Result<BTreeMap<K, V>, E> {
        d.read_map(|d, len| {
            let mut map = BTreeMap::new();
            for i in range(0u, len) {
                let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
                let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
                map.insert(key, val);
            }
            Ok(map)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E> + PartialEq + Ord
> Encodable<S, E> for BTreeSet<T> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_seq(self.len(), |s| {
            let mut i = 0;
            for e in self.iter() {
                try!(s.emit_seq_elt(i, |s| e.encode(s)));
                i += 1;
            }
            Ok(())
        })
    }
}

impl<
    E,
    D: Decoder<E>,
    T: Decodable<D, E> + PartialEq + Ord
> Decodable<D, E> for BTreeSet<T> {
    fn decode(d: &mut D) -> Result<BTreeSet<T>, E> {
        d.read_seq(|d, len| {
            let mut set = BTreeSet::new();
            for i in range(0u, len) {
                set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
            }
            Ok(set)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    K: Encodable<S, E> + Hash<X> + Eq,
    V: Encodable<S, E>,
    X,
    H: Hasher<X>
> Encodable<S, E> for HashMap<K, V, H> {
    fn encode(&self, e: &mut S) -> Result<(), E> {
        e.emit_map(self.len(), |e| {
            let mut i = 0;
            for (key, val) in self.iter() {
                try!(e.emit_map_elt_key(i, |e| key.encode(e)));
                try!(e.emit_map_elt_val(i, |e| val.encode(e)));
                i += 1;
            }
            Ok(())
        })
    }
}

impl<
    E,
    D: Decoder<E>,
    K: Decodable<D, E> + Hash<S> + Eq,
    V: Decodable<D, E>,
    S,
    H: Hasher<S> + Default
> Decodable<D, E> for HashMap<K, V, H> {
    fn decode(d: &mut D) -> Result<HashMap<K, V, H>, E> {
        d.read_map(|d, len| {
            let hasher = Default::default();
            let mut map = HashMap::with_capacity_and_hasher(len, hasher);
            for i in range(0u, len) {
                let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
                let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
                map.insert(key, val);
            }
            Ok(map)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    T: Encodable<S, E> + Hash<X> + Eq,
    X,
    H: Hasher<X>
> Encodable<S, E> for HashSet<T, H> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_seq(self.len(), |s| {
            let mut i = 0;
            for e in self.iter() {
                try!(s.emit_seq_elt(i, |s| e.encode(s)));
                i += 1;
            }
            Ok(())
        })
    }
}

impl<
    E,
    D: Decoder<E>,
    T: Decodable<D, E> + Hash<S> + Eq,
    S,
    H: Hasher<S> + Default
> Decodable<D, E> for HashSet<T, H> {
    fn decode(d: &mut D) -> Result<HashSet<T, H>, E> {
        d.read_seq(|d, len| {
            let mut set = HashSet::with_capacity_and_hasher(len, Default::default());
            for i in range(0u, len) {
                set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
            }
            Ok(set)
        })
    }
}

impl<
    E,
    S: Encoder<E>,
    V: Encodable<S, E>
> Encodable<S, E> for VecMap<V> {
    fn encode(&self, e: &mut S) -> Result<(), E> {
        e.emit_map(self.len(), |e| {
                for (i, (key, val)) in self.iter().enumerate() {
                    try!(e.emit_map_elt_key(i, |e| key.encode(e)));
                    try!(e.emit_map_elt_val(i, |e| val.encode(e)));
                }
                Ok(())
            })
    }
}

impl<
    E,
    D: Decoder<E>,
    V: Decodable<D, E>
> Decodable<D, E> for VecMap<V> {
    fn decode(d: &mut D) -> Result<VecMap<V>, E> {
        d.read_map(|d, len| {
            let mut map = VecMap::new();
            for i in range(0u, len) {
                let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
                let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
                map.insert(key, val);
            }
            Ok(map)
        })
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016-2018 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

//! Host-based adblocker.

use std::collections::HashSet;
use std::fs::File;
use std::io::{self, BufRead, BufReader};
use std::mem;
use std::path::PathBuf;

use url::Url;
use xdg::BaseDirectories;

use super::APP_NAME;

pub struct Adblocker {
    blacklisted_urls: HashSet<String>,
}

impl Adblocker {
    /// Create a new adblocker.
    pub fn new() -> Self {
        Adblocker {
            blacklisted_urls: Adblocker::load_blacklisted_urls(),
        }
    }

    /// Get the hosts path.
    pub fn config_path() -> io::Result<PathBuf> {
        let xdg_dirs = BaseDirectories::with_prefix(APP_NAME).unwrap();
        xdg_dirs.place_data_file("hosts")
    }

    /// Get the blacklisted urls.
    fn load_blacklisted_urls() -> HashSet<String> {
        let mut blacklisted_urls = HashSet::new();
        if let Ok(path) = Adblocker::config_path() {
            match File::open(&path) {
                Ok(file) => {
                    let mut reader = BufReader::new(file);
                    let mut line = String::new();
                    let mut size_read = 1;
                    while size_read > 0 {
                        match reader.read_line(&mut line) {
                            Ok(size) => {
                                size_read = size;
                                if size_read > 0 && line.pop().is_some() { // Remove the leading newline.
                                    blacklisted_urls.insert(mem::replace(&mut line, String::new()));
                                }
                                // Do not insert empty url.
                            }
                            Err(error) => {
                                error!("Error: {}", error);
                                break;
                            },
                        }
                    }
                },
                Err(_) => {
                    error!("Cannot open hosts file {}. Run the command adblock-update",
                           path.to_str().unwrap_or_default())
                },
            }
        }
        else {
            warn!("Cannot find hosts file for the ad blocker");
        }
        blacklisted_urls
    }

    /// Check if the specified url should be blocked.
    pub fn should_block(&self, url: &str) -> bool {
        if let Some(host) = get_url_host(url) {
            let result = self.blacklisted_urls.contains(&host);
            if result {
                info!("Blocked URL {}", host);
            }
            result
        }
        else {
            false
        }
    }
}

/// Get the host from the URL.
fn get_url_host(url: &str) -> Option<String> {
    Url::parse(url).ok()
        .and_then(|url| url.host_str().map(ToString::to_string))
}
<commit_msg>Hide ads on YouTube<commit_after>/*
 * Copyright (c) 2016-2018 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

//! Host-based adblocker.

use std::collections::HashSet;
use std::fs::File;
use std::io::{self, BufRead, BufReader};
use std::mem;
use std::path::PathBuf;

use url::Url;
use xdg::BaseDirectories;

use super::APP_NAME;

pub struct Adblocker {
    blacklisted_urls: HashSet<String>,
}

impl Adblocker {
    /// Create a new adblocker.
    pub fn new() -> Self {
        Adblocker {
            blacklisted_urls: Adblocker::load_blacklisted_urls(),
        }
    }

    /// Get the hosts path.
    pub fn config_path() -> io::Result<PathBuf> {
        let xdg_dirs = BaseDirectories::with_prefix(APP_NAME).unwrap();
        xdg_dirs.place_data_file("hosts")
    }

    /// Get the blacklisted urls.
    fn load_blacklisted_urls() -> HashSet<String> {
        let mut blacklisted_urls = HashSet::new();
        if let Ok(path) = Adblocker::config_path() {
            match File::open(&path) {
                Ok(file) => {
                    let mut reader = BufReader::new(file);
                    let mut line = String::new();
                    let mut size_read = 1;
                    while size_read > 0 {
                        match reader.read_line(&mut line) {
                            Ok(size) => {
                                size_read = size;
                                if size_read > 0 && line.pop().is_some() { // Remove the leading newline.
                                    blacklisted_urls.insert(mem::replace(&mut line, String::new()));
                                }
                                // Do not insert empty url.
                            }
                            Err(error) => {
                                error!("Error: {}", error);
                                break;
                            },
                        }
                    }
                },
                Err(_) => {
                    error!("Cannot open hosts file {}. Run the command adblock-update",
                           path.to_str().unwrap_or_default())
                },
            }
        }
        else {
            warn!("Cannot find hosts file for the ad blocker");
        }
        blacklisted_urls
    }

    /// Check if the specified url should be blocked.
    pub fn should_block(&self, url: &str) -> bool {
        if let Some(host) = get_url_host(url) {
            let result = self.blacklisted_urls.contains(&host) ||
                // Block YouTube ads.
                (host.contains("googlevideo.com") && url.contains("pltype=adhost"));
            if result {
                info!("Blocked URL {}", host);
            }
            result
        }
        else {
            false
        }
    }
}

/// Get the host from the URL.
fn get_url_host(url: &str) -> Option<String> {
    Url::parse(url).ok()
        .and_then(|url| url.host_str().map(ToString::to_string))
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate puyocore;
extern crate test;

use test::Bencher;
use puyocore::bit_field::BitField;

#[bench]
fn simulate_19rensa(b: &mut Bencher) {
    let bf = BitField::from_str(concat!(
        ".G.BRG",
        "GBRRYR",
        "RRYYBY",
        "RGYRBR",
        "YGYRBY",
        "YGBGYR",
        "GRBGYR",
        "BRBYBY",
        "RYYBYY",
        "BRBYBR",
        "BGBYRR",
        "YGBGBG",
        "RBGBGG"));

    b.iter(|| {
        test::black_box(bf.clone().simulate())
    })
}
<commit_msg>Add BitField::simulate_fast bench<commit_after>#![feature(test)]

extern crate puyocore;
extern crate test;

use test::Bencher;
use puyocore::bit_field::BitField;

#[bench]
fn simulate_19rensa(b: &mut Bencher) {
    let bf = BitField::from_str(concat!(
        ".G.BRG",
        "GBRRYR",
        "RRYYBY",
        "RGYRBR",
        "YGYRBY",
        "YGBGYR",
        "GRBGYR",
        "BRBYBY",
        "RYYBYY",
        "BRBYBR",
        "BGBYRR",
        "YGBGBG",
        "RBGBGG"));

    b.iter(|| {
        test::black_box(bf.clone().simulate())
    })
}

#[bench]
fn simulate_fast_19rensa(b: &mut Bencher) {
    let bf = BitField::from_str(concat!(
        ".G.BRG",
        "GBRRYR",
        "RRYYBY",
        "RGYRBR",
        "YGYRBY",
        "YGBGYR",
        "GRBGYR",
        "BRBYBY",
        "RYYBYY",
        "BRBYBR",
        "BGBYRR",
        "YGBGBG",
        "RBGBGG"));

    b.iter(|| {
        test::black_box(bf.clone().simulate_fast())
    })
}
<|endoftext|>


<commit_before>use Prefab;
use Rng;
use calx_grid::Dir6;
use euclid::vec2;
use field::Field;
use form::Form;
use location::{Location, Portal};
use mapfile;
use rand::{self, Rand, SeedableRng};
use serde;
use std::cmp;
use std::collections::BTreeSet;
use std::collections::HashMap;
use std::io::Cursor;
use std::slice;
use terrain::Terrain;
use world::Loadout;

/// Static generated world.
pub struct Worldgen {
    seed: u32,
    terrain: Field<Terrain>,
    portals: HashMap<Location, Portal>,
    spawns: Vec<(Location, Loadout)>,
    player_entry: Location,
}

impl Worldgen {
    pub fn new(seed: u32) -> Worldgen {
        let mut ret = Worldgen {
            seed: seed,
            terrain: Field::new(),
            portals: HashMap::new(),
            spawns: Vec::new(),
            player_entry: Location::new(0, 0, 0),
        };

        let mut rng: Rng = SeedableRng::from_seed([seed, seed, seed, seed]);
        ret.gen_overworld(&mut rng);
        ret.cave_entrance(Location::new(10, 0, 0), Location::new(0, 0, 1));
        ret.gen_caves(&mut rng, Location::new(0, 0, 1));

        ret
    }

    fn sprint_map(&mut self) {
        const SPRINT_PREFAB: &'static str = include_str!("../../sprint.ron");

        let sprint_prefab = mapfile::load_prefab(&mut Cursor::new(SPRINT_PREFAB))
            .expect("Corrupt sprint file");

        // Top-left of the default on-screen area.
        let origin = Location::new(-21, -22, 0);
        self.load_prefab(origin, &sprint_prefab);
    }

    fn load_prefab(&mut self, origin: Location, prefab: &Prefab) {
        for (p, &(ref terrain, ref entities)) in prefab.iter() {
            let loc = origin + p;

            self.terrain.set(loc, *terrain);

            for spawn in entities.iter() {
                if spawn == "player" {
                    self.player_entry = loc;
                } else {
                    let form = Form::named(spawn).expect(&format!(
                        "Bad prefab: Form '{}' not found!",
                        spawn
                    ));
                    self.spawns.push((loc, form.loadout.clone()));
                }
            }
        }
    }

    pub fn seed(&self) -> u32 { self.seed }

    pub fn get_terrain(&self, loc: Location) -> Terrain { self.terrain.get(loc) }

    pub fn get_portal(&self, loc: Location) -> Option<Location> {
        self.portals.get(&loc).map(|&p| loc + p)
    }

    pub fn spawns(&self) -> slice::Iter<(Location, Loadout)> { self.spawns.iter() }

    pub fn player_entry(&self) -> Location { self.player_entry }

    fn gen_overworld<R: rand::Rng>(&mut self, rng: &mut R) {
        use Terrain::*;

        let noise_offset = rng.gen_range(0, 100);

        for y in -40..40 {
            for x in -40..40 {
                let x = x as i8;
                let y = y as i8;
                let loc = Location::new(x, y, 0);
                let noise = Location::new(x, y, noise_offset).noise();

                self.terrain.set(
                    loc,
                    match noise {
                        n if n > 0.8 => Tree,
                        n if n > -0.8 => Grass,
                        _ => Water,
                    },
                );
            }
        }
    }

    fn gen_caves<R: rand::Rng>(&mut self, rng: &mut R, entrance: Location) {
        use self::Prototerrain::*;

        let mut cells_to_dig = 700;

        let mut map = screen_map(Location::new(0, 0, entrance.z));

        debug_assert!(map.get(entrance) == Unused);

        // Create portal enclosure
        entry_cave_enclosure(&mut map, entrance);

        let entrance = entrance + vec2(1, 1);

        let mut edge: BTreeSet<Location> = Dir6::iter()
            .map(|&d| entrance + vec2(2, 2) + d)
            .filter(|&loc| map.get(loc) == Unused)
            .collect();

        // Arbitrary long iteration, should break after digging a sufficient number of cells before
        // this.
        for _ in 0..10000 {
            if edge.is_empty() {
                break;
            }

            let dig_loc = *rand::sample(rng, edge.iter(), 1)[0];

            // Prefer digging narrow corridors, there's an increasing chance to abort the dig when the
            // selected location is in a very open space.
            let adjacent_floors = Dir6::iter()
                .filter(|d| map.get(dig_loc + **d) == Floor)
                .count();
            if rng.gen_range(0, cmp::max(1, adjacent_floors * adjacent_floors)) != 0 {
                continue;
            }

            map.set(dig_loc, Floor);
            edge.extend(Dir6::iter().map(|&d| dig_loc + d).filter(|&loc| {
                map.get(loc) == Unused
            }));

            cells_to_dig -= 1;
            if cells_to_dig == 0 {
                break;
            }
        }

        // Postprocess
        let cells: Vec<_> = map.iter().map(|(&loc, &c)| (loc, c)).collect();
        for (loc, c) in cells.into_iter() {
            // Clear pillars
            if c == Unused {
                let adjacent_floors = Dir6::iter().filter(|d| map.get(loc + **d) == Floor).count();

                if adjacent_floors == 6 {
                    map.set(loc, Floor);
                }
            }
        }

        // Map to actual terrains
        self.terrain.extend(map.iter().map(|(&loc, &t)| {
            let t = match t {
                Outside => Terrain::Empty,
                Unused => Terrain::Rock,
                Border => Terrain::Rock,
                Floor => Terrain::Ground,
                Wall => Terrain::Rock,
                Door => Terrain::Door,
            };
            (loc, t)
        }));

        // XXX: This thing needs to be more automatic
        // Make the backportal cell have transparent terrain
        self.terrain.set(entrance - vec2(1, 1), Terrain::Empty);
    }

    /// Make a cave entrance going down.
    fn cave_entrance(&mut self, loc: Location, cave_start: Location) {
        const DOWNBOUND_ENCLOSURE: [(i32, i32); 5] = [(1, 0), (0, 1), (2, 1), (1, 2), (2, 2)];

        for &v in &DOWNBOUND_ENCLOSURE {
            let loc = loc + vec2(v.0, v.1);
            self.terrain.set(loc, Terrain::Rock);
        }

        self.terrain.set(loc, Terrain::Ground);
        self.terrain.set(loc + vec2(1, 1), Terrain::Ground);

        // Connect the points
        self.portal(loc + vec2(1, 1), cave_start);
        self.portal(cave_start - vec2(1, 1), loc);
    }

    /// Punch a (one-way) portal between two points.
    fn portal(&mut self, origin: Location, destination: Location) {
        self.portals.insert(
            origin,
            Portal::new(origin, destination),
        );
        self.terrain.set(origin, Terrain::Empty);
    }
}

impl serde::Serialize for Worldgen {
    fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
        self.seed.serialize(s)
    }
}

impl<'a> serde::Deserialize<'a> for Worldgen {
    fn deserialize<D: serde::Deserializer<'a>>(d: D) -> Result<Self, D::Error> {
        Ok(Worldgen::new(serde::Deserialize::deserialize(d)?))
    }
}

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
enum Prototerrain {
    /// Area completely outside the map to be generated.
    Outside,
    /// Area that should be filled with map content but hasn't been yet.
    Unused,
    /// Area that the player cannot enter but that may be visible on screen.
    Border,
    Floor,
    Wall,
    Door,
}

impl Default for Prototerrain {
    fn default() -> Self { Prototerrain::Outside }
}

fn screen_map(origin: Location) -> Field<Prototerrain> {
    let mut ret = Field::new();

    // Cells two cells away from the live area at the bottom of the screen can still affect
    // the visible terrain via cell reshaping, so add those as well to the border.
    const BORDER_MASK: [(i32, i32); 9] = [
        (-1, -1),
        (0, -1),
        (1, 0),
        (1, 1),
        (0, 1),
        (-1, 0),
        (2, 1),
        (2, 2),
        (1, 2),
    ];

    for &v in ::onscreen_locations() {
        let loc = origin + v;
        // Paint border for every cell, all except the one from the cells at the actual border will
        // be overwritten.
        for d in &BORDER_MASK {
            let vec = vec2(d.0, d.1);
            if ret.get(loc + vec) == Default::default() {
                ret.set(loc + vec, Prototerrain::Border);
            }
        }

        ret.set(loc, Prototerrain::Unused);
    }

    ret
}

fn entry_cave_enclosure(map: &mut Field<Prototerrain>, entrance: Location) {
    use self::Prototerrain::*;

    debug_assert!(map.get(entrance) == Unused);

    const UPBOUND_ENCLOSURE: [(i32, i32); 7] = [
        (-2, -2),
        (-1, -2),
        (0, -1),
        (-1, 0),
        (-2, -1),
        (1, 0),
        (0, 1),
    ];

    for &v in &UPBOUND_ENCLOSURE {
        let loc = entrance + vec2(v.0, v.1);
        map.set(loc, Wall);
    }

    // Portal site
    map.set(entrance - vec2(1, 1), Floor);
    // Entrance cell
    map.set(entrance, Floor);
    // Enclosure mouth
    map.set(entrance + vec2(1, 1), Floor);
}
<commit_msg>Fix backportal location<commit_after>use Prefab;
use Rng;
use calx_grid::Dir6;
use euclid::vec2;
use field::Field;
use form::Form;
use location::{Location, Portal};
use mapfile;
use rand::{self, Rand, SeedableRng};
use serde;
use std::cmp;
use std::collections::BTreeSet;
use std::collections::HashMap;
use std::io::Cursor;
use std::slice;
use terrain::Terrain;
use world::Loadout;

/// Static generated world.
pub struct Worldgen {
    seed: u32,
    terrain: Field<Terrain>,
    portals: HashMap<Location, Portal>,
    spawns: Vec<(Location, Loadout)>,
    player_entry: Location,
}

impl Worldgen {
    pub fn new(seed: u32) -> Worldgen {
        let mut ret = Worldgen {
            seed: seed,
            terrain: Field::new(),
            portals: HashMap::new(),
            spawns: Vec::new(),
            player_entry: Location::new(0, 0, 0),
        };

        let mut rng: Rng = SeedableRng::from_seed([seed, seed, seed, seed]);
        ret.gen_overworld(&mut rng);
        ret.cave_entrance(Location::new(10, 0, 0), Location::new(0, 0, 1));
        ret.gen_caves(&mut rng, Location::new(0, 0, 1));

        ret
    }

    fn sprint_map(&mut self) {
        const SPRINT_PREFAB: &'static str = include_str!("../../sprint.ron");

        let sprint_prefab = mapfile::load_prefab(&mut Cursor::new(SPRINT_PREFAB))
            .expect("Corrupt sprint file");

        // Top-left of the default on-screen area.
        let origin = Location::new(-21, -22, 0);
        self.load_prefab(origin, &sprint_prefab);
    }

    fn load_prefab(&mut self, origin: Location, prefab: &Prefab) {
        for (p, &(ref terrain, ref entities)) in prefab.iter() {
            let loc = origin + p;

            self.terrain.set(loc, *terrain);

            for spawn in entities.iter() {
                if spawn == "player" {
                    self.player_entry = loc;
                } else {
                    let form = Form::named(spawn).expect(&format!(
                        "Bad prefab: Form '{}' not found!",
                        spawn
                    ));
                    self.spawns.push((loc, form.loadout.clone()));
                }
            }
        }
    }

    pub fn seed(&self) -> u32 { self.seed }

    pub fn get_terrain(&self, loc: Location) -> Terrain { self.terrain.get(loc) }

    pub fn get_portal(&self, loc: Location) -> Option<Location> {
        self.portals.get(&loc).map(|&p| loc + p)
    }

    pub fn spawns(&self) -> slice::Iter<(Location, Loadout)> { self.spawns.iter() }

    pub fn player_entry(&self) -> Location { self.player_entry }

    fn gen_overworld<R: rand::Rng>(&mut self, rng: &mut R) {
        use Terrain::*;

        let noise_offset = rng.gen_range(0, 100);

        for y in -40..40 {
            for x in -40..40 {
                let x = x as i8;
                let y = y as i8;
                let loc = Location::new(x, y, 0);
                let noise = Location::new(x, y, noise_offset).noise();

                self.terrain.set(
                    loc,
                    match noise {
                        n if n > 0.8 => Tree,
                        n if n > -0.8 => Grass,
                        _ => Water,
                    },
                );
            }
        }
    }

    fn gen_caves<R: rand::Rng>(&mut self, rng: &mut R, entrance: Location) {
        use self::Prototerrain::*;

        let mut cells_to_dig = 700;

        let mut map = screen_map(Location::new(0, 0, entrance.z));

        debug_assert!(map.get(entrance) == Unused);

        // Create portal enclosure
        entry_cave_enclosure(&mut map, entrance);

        let entrance = entrance + vec2(1, 1);

        let mut edge: BTreeSet<Location> = Dir6::iter()
            .map(|&d| entrance + vec2(2, 2) + d)
            .filter(|&loc| map.get(loc) == Unused)
            .collect();

        // Arbitrary long iteration, should break after digging a sufficient number of cells before
        // this.
        for _ in 0..10000 {
            if edge.is_empty() {
                break;
            }

            let dig_loc = *rand::sample(rng, edge.iter(), 1)[0];

            // Prefer digging narrow corridors, there's an increasing chance to abort the dig when the
            // selected location is in a very open space.
            let adjacent_floors = Dir6::iter()
                .filter(|d| map.get(dig_loc + **d) == Floor)
                .count();
            if rng.gen_range(0, cmp::max(1, adjacent_floors * adjacent_floors)) != 0 {
                continue;
            }

            map.set(dig_loc, Floor);
            edge.extend(Dir6::iter().map(|&d| dig_loc + d).filter(|&loc| {
                map.get(loc) == Unused
            }));

            cells_to_dig -= 1;
            if cells_to_dig == 0 {
                break;
            }
        }

        // Postprocess
        let cells: Vec<_> = map.iter().map(|(&loc, &c)| (loc, c)).collect();
        for (loc, c) in cells.into_iter() {
            // Clear pillars
            if c == Unused {
                let adjacent_floors = Dir6::iter().filter(|d| map.get(loc + **d) == Floor).count();

                if adjacent_floors == 6 {
                    map.set(loc, Floor);
                }
            }
        }

        // Map to actual terrains
        self.terrain.extend(map.iter().map(|(&loc, &t)| {
            let t = match t {
                Outside => Terrain::Empty,
                Unused => Terrain::Rock,
                Border => Terrain::Rock,
                Floor => Terrain::Ground,
                Wall => Terrain::Rock,
                Door => Terrain::Door,
            };
            (loc, t)
        }));

        // XXX: This thing needs to be more automatic
        // Make the backportal cell have transparent terrain
        self.terrain.set(entrance - vec2(2, 2), Terrain::Empty);
    }

    /// Make a cave entrance going down.
    fn cave_entrance(&mut self, loc: Location, cave_start: Location) {
        const DOWNBOUND_ENCLOSURE: [(i32, i32); 5] = [(1, 0), (0, 1), (2, 1), (1, 2), (2, 2)];

        for &v in &DOWNBOUND_ENCLOSURE {
            let loc = loc + vec2(v.0, v.1);
            self.terrain.set(loc, Terrain::Rock);
        }

        self.terrain.set(loc, Terrain::Ground);
        self.terrain.set(loc + vec2(1, 1), Terrain::Ground);

        // Connect the points
        self.portal(loc + vec2(1, 1), cave_start);
        self.portal(cave_start - vec2(1, 1), loc);
    }

    /// Punch a (one-way) portal between two points.
    fn portal(&mut self, origin: Location, destination: Location) {
        self.portals.insert(
            origin,
            Portal::new(origin, destination),
        );
        self.terrain.set(origin, Terrain::Empty);
    }
}

impl serde::Serialize for Worldgen {
    fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
        self.seed.serialize(s)
    }
}

impl<'a> serde::Deserialize<'a> for Worldgen {
    fn deserialize<D: serde::Deserializer<'a>>(d: D) -> Result<Self, D::Error> {
        Ok(Worldgen::new(serde::Deserialize::deserialize(d)?))
    }
}

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
enum Prototerrain {
    /// Area completely outside the map to be generated.
    Outside,
    /// Area that should be filled with map content but hasn't been yet.
    Unused,
    /// Area that the player cannot enter but that may be visible on screen.
    Border,
    Floor,
    Wall,
    Door,
}

impl Default for Prototerrain {
    fn default() -> Self { Prototerrain::Outside }
}

fn screen_map(origin: Location) -> Field<Prototerrain> {
    let mut ret = Field::new();

    // Cells two cells away from the live area at the bottom of the screen can still affect
    // the visible terrain via cell reshaping, so add those as well to the border.
    const BORDER_MASK: [(i32, i32); 9] = [
        (-1, -1),
        (0, -1),
        (1, 0),
        (1, 1),
        (0, 1),
        (-1, 0),
        (2, 1),
        (2, 2),
        (1, 2),
    ];

    for &v in ::onscreen_locations() {
        let loc = origin + v;
        // Paint border for every cell, all except the one from the cells at the actual border will
        // be overwritten.
        for d in &BORDER_MASK {
            let vec = vec2(d.0, d.1);
            if ret.get(loc + vec) == Default::default() {
                ret.set(loc + vec, Prototerrain::Border);
            }
        }

        ret.set(loc, Prototerrain::Unused);
    }

    ret
}

fn entry_cave_enclosure(map: &mut Field<Prototerrain>, entrance: Location) {
    use self::Prototerrain::*;

    debug_assert!(map.get(entrance) == Unused);

    const UPBOUND_ENCLOSURE: [(i32, i32); 7] = [
        (-2, -2),
        (-1, -2),
        (0, -1),
        (-1, 0),
        (-2, -1),
        (1, 0),
        (0, 1),
    ];

    for &v in &UPBOUND_ENCLOSURE {
        let loc = entrance + vec2(v.0, v.1);
        map.set(loc, Wall);
    }

    // Portal site
    map.set(entrance - vec2(1, 1), Floor);
    // Entrance cell
    map.set(entrance, Floor);
    // Enclosure mouth
    map.set(entrance + vec2(1, 1), Floor);
}
<|endoftext|>