<commit_before>use config::{Config, Environment, File};
use failure::Error;
use std::path::{Path, MAIN_SEPARATOR};
use url::Url;

#[cfg(target_os = "windows")]
const CFG_FILE: &str = "ctehxk2";
#[cfg(not(target_os = "windows"))]
const CFG_FILE: &str = "libctehxk2";

#[derive(Debug, Deserialize, PartialEq)]
pub struct Settings {
    pub timeout: Option<u64>,
    pub base_url: String,
    pub log_level: String,
    pub log_path: Option<String>,
    pub ctn: Option<u16>,
    pub pn: Option<u16>,
}

impl Settings {
    pub fn init() -> Result<Self, Error> {
        let mut settings = Config::new();

        // set defaults
        let _ = settings
            .set_default("base_url", "http://localhost:8088/k2/ctapi/")
            .expect("Failed to set default for base_url!")
            .set_default("log_level", "Error")
            .expect("Failed to set default for log_level!");

        // merge with optional config file and env variables
        let _ = settings
            .merge(File::with_name(CFG_FILE).required(false))
            .expect("Failed to merge config file!")
            .merge(Environment::with_prefix("K2").ignore_empty(true))
            .expect("Failed to merge env variables!");

        // force trailing slash for base_url
        if let Ok(mut url) = settings.get::<String>("base_url") {
            let _ = Url::parse(&url)?; // check url

            if !url.trim().ends_with('/') {
                url.push_str("/");
                let _ = settings.set("base_url", url);
            }
        }

        // force trailing slash for log_path
        if let Ok(Some(mut path)) = settings.get::<Option<String>>("log_path") {
            if !Path::new(&path).exists() {
                return Err(format_err!("log_path does not exists"));
            }

            if !path.trim().ends_with(MAIN_SEPARATOR) {
                path.push(MAIN_SEPARATOR);
                let _ = settings.set("log_path", Some(path));
            }
        }

        // enforce a value for pn and ctn
        if let (Ok(Some(_)), Ok(Some(_))) = (
            settings.get::<Option<u16>>("ctn"),
            settings.get::<Option<u16>>("pn"),
        ) {
            // ok
        } else {
            let _ = settings.set("ctn", None::<String>);
            let _ = settings.set("pn", None::<String>);
        }

        settings.try_into().map_err(failure::Error::from)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use rand;
    use spectral::assert_that;
    use std::env;
    use std::fs::File;
    use std::io::Write;
    use std::path::MAIN_SEPARATOR;
    use tempfile::tempdir;
    use test_server::helper::random_string;

    #[test]
    fn default_configuration() {
        let default = Settings::init();

        assert_eq!(
            default.ok(),
            Some(Settings {
                timeout: None,
                base_url: String::from("http://localhost:8088/k2/ctapi/"),
                log_level: String::from("Error"),
                log_path: None,
                ctn: None,
                pn: None,
            })
        );
    }

    #[test]
    fn env_variables_overrides() {
        let timeout = u64::from(rand::random::<u32>()); // panics with u64 random
        env::set_var("K2_TIMEOUT", format!("{}", timeout));

        assert_eq!(
            Settings::init().ok(),
            Some(Settings {
                timeout: Some(timeout),
                base_url: String::from("http://localhost:8088/k2/ctapi/"),
                log_level: String::from("Error"),
                log_path: None,
                ctn: None,
                pn: None,
            })
        );

        let base_url = String::from("ftp://unknown.de/");
        env::set_var("K2_BASE_URL", base_url.clone());

        assert_eq!(
            Settings::init().ok(),
            Some(Settings {
                timeout: Some(timeout),
                base_url: base_url.clone(),
                log_level: String::from("Error"),
                log_path: None,
                ctn: None,
                pn: None,
            })
        );

        let log_level = random_string(10);
        env::set_var("K2_LOG_LEVEL", log_level.clone());

        assert_eq!(
            Settings::init().ok(),
            Some(Settings {
                timeout: Some(timeout),
                base_url: base_url.clone(),
                log_level: log_level.clone(),
                log_path: None,
                ctn: None,
                pn: None,
            })
        );

        let config_file_folder_path = tempdir().unwrap().into_path();
        let log_path = format!(
            "{}{}",
            config_file_folder_path.to_str().unwrap(),
            MAIN_SEPARATOR
        );
        env::set_var("K2_LOG_PATH", log_path.clone());

        assert_eq!(
            Settings::init().ok(),
            Some(Settings {
                timeout: Some(timeout),
                base_url: base_url.clone(),
                log_level: log_level.clone(),
                log_path: Some(log_path.clone()),
                ctn: None,
                pn: None,
            })
        );

        let ctn = rand::random::<u16>();
        env::set_var("K2_CTN", format!("{}", ctn));

        assert_eq!(
            Settings::init().ok(),
            Some(Settings {
                timeout: Some(timeout),
                base_url: base_url.clone(),
                log_level: log_level.clone(),
                log_path: Some(log_path.clone()),
                ctn: None,
                pn: None,
            })
        );

        let pn = rand::random::<u16>();
        env::set_var("K2_PN", format!("{}", pn));

        assert_eq!(
            Settings::init().ok(),
            Some(Settings {
                timeout: Some(timeout),
                base_url: base_url.clone(),
                log_level: log_level.clone(),
                log_path: Some(log_path.clone()),
                ctn: Some(ctn),
                pn: Some(pn),
            })
        );

        env::remove_var("K2_BASE_URL");
        env::remove_var("K2_CTN");
        env::remove_var("K2_LOG_LEVEL");
        env::remove_var("K2_LOG_PATH");
        env::remove_var("K2_PN");
        env::remove_var("K2_TIMEOUT");
    }

    #[test]
    fn config_file_overrides() {
        let config_file_folder = tempdir().unwrap();
        let config_file_folder_path = tempdir().unwrap().into_path();
        let log_path = format!(
            "{}{}",
            config_file_folder_path.to_str().unwrap(),
            MAIN_SEPARATOR
        );

        let config_file_path = config_file_folder.path().join(format!("{}.json", CFG_FILE));
        let mut config_file = File::create(config_file_path.clone()).unwrap();
        let _ = env::set_current_dir(config_file_folder.path().to_owned());

        let config = json!({
            "log_level": "debug",
            "log_path": log_path,
            "base_url": "http://localhost:5050/",
            "timeout": 1000,
            "ctn": 9,
            "pn": 12,
        });

        writeln!(config_file, "{}", config).unwrap();

        assert_eq!(
            Settings::init().ok(),
            Some(Settings {
                timeout: config["timeout"].as_u64(),
                base_url: String::from(config["base_url"].as_str().unwrap()),
                log_level: String::from(config["log_level"].as_str().unwrap()),
                log_path: Some(String::from(config["log_path"].as_str().unwrap())),
                ctn: Some(
                    config["ctn"]
                        .as_u64()
                        .unwrap()
                        .to_string()
                        .parse::<u16>()
                        .unwrap()
                ),
                pn: Some(
                    config["pn"]
                        .as_u64()
                        .unwrap()
                        .to_string()
                        .parse::<u16>()
                        .unwrap()
                ),
            })
        );
    }

    #[test]
    fn env_variable_beats_config_file() {
        let config_file_folder = tempdir().unwrap();
        let config_file_path = config_file_folder.path().join(format!("{}.yaml", CFG_FILE));
        let mut config_file = File::create(config_file_path.clone()).unwrap();
        let _ = env::set_current_dir(config_file_folder.path().to_owned());

        let config = "
timeout: 300
log_level: debug
";

        writeln!(config_file, "{}", config).unwrap();

        env::set_var("K2_LOG_LEVEL", "trace");

        assert_eq!(
            Settings::init().ok(),
            Some(Settings {
                timeout: Some(300),
                base_url: String::from("http://localhost:8088/k2/ctapi/"),
                log_level: String::from("trace"),
                log_path: None,
                ctn: None,
                pn: None,
            })
        );

        env::remove_var("K2_LOG_LEVEL");
    }

    #[test]
    fn force_trailing_slash_for_base_url() {
        let url = "http://127.0.0.1";
        env::set_var("K2_BASE_URL", url);

        assert_eq!(
            Settings::init().ok(),
            Some(Settings {
                timeout: None,
                base_url: format!("{}/", url),
                log_level: String::from("Error"),
                log_path: None,
                ctn: None,
                pn: None,
            })
        );

        env::remove_var("K2_BASE_URL");
    }

    #[test]
    fn force_trailing_slash_for_log_path() {
        let path = tempdir().unwrap().into_path();;
        let path_str = path.to_str().unwrap();
        env::set_var("K2_LOG_PATH", path_str);

        assert_eq!(
            Settings::init().ok(),
            Some(Settings {
                timeout: None,
                base_url: String::from("http://localhost:8088/k2/ctapi/"),
                log_level: String::from("Error"),
                log_path: Some(format!("{}{}", path_str, MAIN_SEPARATOR)),
                ctn: None,
                pn: None,
            })
        );

        env::remove_var("K2_LOG_PATH");
    }

    #[test]
    fn read_config_from_ini_file() {
        let config_file_folder = tempdir().unwrap();
        let config_file_path = config_file_folder.path().join(format!("{}.ini", CFG_FILE));
        let mut config_file = File::create(config_file_path.clone()).unwrap();
        let _ = env::set_current_dir(config_file_folder.path().to_owned());

        let config = "
timeout = 300
log_level = \"debug\"
";

        writeln!(config_file, "{}", config).unwrap();

        assert_eq!(
            Settings::init().ok(),
            Some(Settings {
                timeout: Some(300),
                base_url: String::from("http://localhost:8088/k2/ctapi/"),
                log_level: String::from("debug"),
                log_path: None,
                ctn: None,
                pn: None,
            })
        );
    }

    #[test]
    fn error_with_wrong_log_path() {
        let path = random_string(100);
        env::set_var("K2_LOG_PATH", path);

        assert!(Settings::init().is_err());

        env::remove_var("K2_LOG_PATH");
    }

    #[test]
    fn error_with_wrong_base_url() {
        let url = random_string(100);
        env::set_var("K2_BASE_URL", url);

        assert!(Settings::init().is_err());

        env::remove_var("K2_BASE_URL");
    }

    #[test]
    fn enforce_ctn_and_pn_were_set() {
        let mut settings = Settings::init().unwrap();
        assert_that(&settings)
            .map(|val| &val.ctn)
            .is_equal_to(&None);
        assert_that(&settings).map(|val| &val.pn).is_equal_to(&None);

        let ctn = rand::random::<u16>();
        env::set_var("K2_CTN", format!("{}", ctn));

        settings = Settings::init().unwrap();
        assert_that(&settings)
            .map(|val| &val.ctn)
            .is_equal_to(&None);
        assert_that(&settings).map(|val| &val.pn).is_equal_to(&None);

        env::remove_var("K2_CTN");

        let pn = rand::random::<u16>();
        env::set_var("K2_PN", format!("{}", pn));

        settings = Settings::init().unwrap();
        assert_that(&settings)
            .map(|val| &val.ctn)
            .is_equal_to(&None);
        assert_that(&settings).map(|val| &val.pn).is_equal_to(&None);

        env::set_var("K2_CTN", format!("{}", ctn));

        settings = Settings::init().unwrap();
        assert_that(&settings)
            .map(|val| &val.ctn)
            .is_equal_to(&Some(ctn));
        assert_that(&settings)
            .map(|val| &val.pn)
            .is_equal_to(&Some(pn));

        env::remove_var("K2_CTN");
        env::remove_var("K2_PN");
    }
}
<commit_msg>Cargo fmt<commit_after>use config::{Config, Environment, File};
use failure::Error;
use std::path::{Path, MAIN_SEPARATOR};
use url::Url;

#[cfg(target_os = "windows")]
const CFG_FILE: &str = "ctehxk2";
#[cfg(not(target_os = "windows"))]
const CFG_FILE: &str = "libctehxk2";

#[derive(Debug, Deserialize, PartialEq)]
pub struct Settings {
    pub timeout: Option<u64>,
    pub base_url: String,
    pub log_level: String,
    pub log_path: Option<String>,
    pub ctn: Option<u16>,
    pub pn: Option<u16>,
}

impl Settings {
    pub fn init() -> Result<Self, Error> {
        let mut settings = Config::new();

        // set defaults
        let _ = settings
            .set_default("base_url", "http://localhost:8088/k2/ctapi/")
            .expect("Failed to set default for base_url!")
            .set_default("log_level", "Error")
            .expect("Failed to set default for log_level!");

        // merge with optional config file and env variables
        let _ = settings
            .merge(File::with_name(CFG_FILE).required(false))
            .expect("Failed to merge config file!")
            .merge(Environment::with_prefix("K2").ignore_empty(true))
            .expect("Failed to merge env variables!");

        // force trailing slash for base_url
        if let Ok(mut url) = settings.get::<String>("base_url") {
            let _ = Url::parse(&url)?; // check url

            if !url.trim().ends_with('/') {
                url.push_str("/");
                let _ = settings.set("base_url", url);
            }
        }

        // force trailing slash for log_path
        if let Ok(Some(mut path)) = settings.get::<Option<String>>("log_path") {
            if !Path::new(&path).exists() {
                return Err(format_err!("log_path does not exists"));
            }

            if !path.trim().ends_with(MAIN_SEPARATOR) {
                path.push(MAIN_SEPARATOR);
                let _ = settings.set("log_path", Some(path));
            }
        }

        // enforce a value for pn and ctn
        if let (Ok(Some(_)), Ok(Some(_))) = (
            settings.get::<Option<u16>>("ctn"),
            settings.get::<Option<u16>>("pn"),
        ) {
            // ok
        } else {
            let _ = settings.set("ctn", None::<String>);
            let _ = settings.set("pn", None::<String>);
        }

        settings.try_into().map_err(failure::Error::from)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use rand;
    use spectral::assert_that;
    use std::env;
    use std::fs::File;
    use std::io::Write;
    use std::path::MAIN_SEPARATOR;
    use tempfile::tempdir;
    use test_server::helper::random_string;

    #[test]
    fn default_configuration() {
        let default = Settings::init();

        assert_eq!(
            default.ok(),
            Some(Settings {
                timeout: None,
                base_url: String::from("http://localhost:8088/k2/ctapi/"),
                log_level: String::from("Error"),
                log_path: None,
                ctn: None,
                pn: None,
            })
        );
    }

    #[test]
    fn env_variables_overrides() {
        let timeout = u64::from(rand::random::<u32>()); // panics with u64 random
        env::set_var("K2_TIMEOUT", format!("{}", timeout));

        assert_eq!(
            Settings::init().ok(),
            Some(Settings {
                timeout: Some(timeout),
                base_url: String::from("http://localhost:8088/k2/ctapi/"),
                log_level: String::from("Error"),
                log_path: None,
                ctn: None,
                pn: None,
            })
        );

        let base_url = String::from("ftp://unknown.de/");
        env::set_var("K2_BASE_URL", base_url.clone());

        assert_eq!(
            Settings::init().ok(),
            Some(Settings {
                timeout: Some(timeout),
                base_url: base_url.clone(),
                log_level: String::from("Error"),
                log_path: None,
                ctn: None,
                pn: None,
            })
        );

        let log_level = random_string(10);
        env::set_var("K2_LOG_LEVEL", log_level.clone());

        assert_eq!(
            Settings::init().ok(),
            Some(Settings {
                timeout: Some(timeout),
                base_url: base_url.clone(),
                log_level: log_level.clone(),
                log_path: None,
                ctn: None,
                pn: None,
            })
        );

        let config_file_folder_path = tempdir().unwrap().into_path();
        let log_path = format!(
            "{}{}",
            config_file_folder_path.to_str().unwrap(),
            MAIN_SEPARATOR
        );
        env::set_var("K2_LOG_PATH", log_path.clone());

        assert_eq!(
            Settings::init().ok(),
            Some(Settings {
                timeout: Some(timeout),
                base_url: base_url.clone(),
                log_level: log_level.clone(),
                log_path: Some(log_path.clone()),
                ctn: None,
                pn: None,
            })
        );

        let ctn = rand::random::<u16>();
        env::set_var("K2_CTN", format!("{}", ctn));

        assert_eq!(
            Settings::init().ok(),
            Some(Settings {
                timeout: Some(timeout),
                base_url: base_url.clone(),
                log_level: log_level.clone(),
                log_path: Some(log_path.clone()),
                ctn: None,
                pn: None,
            })
        );

        let pn = rand::random::<u16>();
        env::set_var("K2_PN", format!("{}", pn));

        assert_eq!(
            Settings::init().ok(),
            Some(Settings {
                timeout: Some(timeout),
                base_url: base_url.clone(),
                log_level: log_level.clone(),
                log_path: Some(log_path.clone()),
                ctn: Some(ctn),
                pn: Some(pn),
            })
        );

        env::remove_var("K2_BASE_URL");
        env::remove_var("K2_CTN");
        env::remove_var("K2_LOG_LEVEL");
        env::remove_var("K2_LOG_PATH");
        env::remove_var("K2_PN");
        env::remove_var("K2_TIMEOUT");
    }

    #[test]
    fn config_file_overrides() {
        let config_file_folder = tempdir().unwrap();
        let config_file_folder_path = tempdir().unwrap().into_path();
        let log_path = format!(
            "{}{}",
            config_file_folder_path.to_str().unwrap(),
            MAIN_SEPARATOR
        );

        let config_file_path = config_file_folder.path().join(format!("{}.json", CFG_FILE));
        let mut config_file = File::create(config_file_path.clone()).unwrap();
        let _ = env::set_current_dir(config_file_folder.path().to_owned());

        let config = json!({
            "log_level": "debug",
            "log_path": log_path,
            "base_url": "http://localhost:5050/",
            "timeout": 1000,
            "ctn": 9,
            "pn": 12,
        });

        writeln!(config_file, "{}", config).unwrap();

        assert_eq!(
            Settings::init().ok(),
            Some(Settings {
                timeout: config["timeout"].as_u64(),
                base_url: String::from(config["base_url"].as_str().unwrap()),
                log_level: String::from(config["log_level"].as_str().unwrap()),
                log_path: Some(String::from(config["log_path"].as_str().unwrap())),
                ctn: Some(
                    config["ctn"]
                        .as_u64()
                        .unwrap()
                        .to_string()
                        .parse::<u16>()
                        .unwrap()
                ),
                pn: Some(
                    config["pn"]
                        .as_u64()
                        .unwrap()
                        .to_string()
                        .parse::<u16>()
                        .unwrap()
                ),
            })
        );
    }

    #[test]
    fn env_variable_beats_config_file() {
        let config_file_folder = tempdir().unwrap();
        let config_file_path = config_file_folder.path().join(format!("{}.yaml", CFG_FILE));
        let mut config_file = File::create(config_file_path.clone()).unwrap();
        let _ = env::set_current_dir(config_file_folder.path().to_owned());

        let config = "
timeout: 300
log_level: debug
";

        writeln!(config_file, "{}", config).unwrap();

        env::set_var("K2_LOG_LEVEL", "trace");

        assert_eq!(
            Settings::init().ok(),
            Some(Settings {
                timeout: Some(300),
                base_url: String::from("http://localhost:8088/k2/ctapi/"),
                log_level: String::from("trace"),
                log_path: None,
                ctn: None,
                pn: None,
            })
        );

        env::remove_var("K2_LOG_LEVEL");
    }

    #[test]
    fn force_trailing_slash_for_base_url() {
        let url = "http://127.0.0.1";
        env::set_var("K2_BASE_URL", url);

        assert_eq!(
            Settings::init().ok(),
            Some(Settings {
                timeout: None,
                base_url: format!("{}/", url),
                log_level: String::from("Error"),
                log_path: None,
                ctn: None,
                pn: None,
            })
        );

        env::remove_var("K2_BASE_URL");
    }

    #[test]
    fn force_trailing_slash_for_log_path() {
        let path = tempdir().unwrap().into_path();
        let path_str = path.to_str().unwrap();
        env::set_var("K2_LOG_PATH", path_str);

        assert_eq!(
            Settings::init().ok(),
            Some(Settings {
                timeout: None,
                base_url: String::from("http://localhost:8088/k2/ctapi/"),
                log_level: String::from("Error"),
                log_path: Some(format!("{}{}", path_str, MAIN_SEPARATOR)),
                ctn: None,
                pn: None,
            })
        );

        env::remove_var("K2_LOG_PATH");
    }

    #[test]
    fn read_config_from_ini_file() {
        let config_file_folder = tempdir().unwrap();
        let config_file_path = config_file_folder.path().join(format!("{}.ini", CFG_FILE));
        let mut config_file = File::create(config_file_path.clone()).unwrap();
        let _ = env::set_current_dir(config_file_folder.path().to_owned());

        let config = "
timeout = 300
log_level = \"debug\"
";

        writeln!(config_file, "{}", config).unwrap();

        assert_eq!(
            Settings::init().ok(),
            Some(Settings {
                timeout: Some(300),
                base_url: String::from("http://localhost:8088/k2/ctapi/"),
                log_level: String::from("debug"),
                log_path: None,
                ctn: None,
                pn: None,
            })
        );
    }

    #[test]
    fn error_with_wrong_log_path() {
        let path = random_string(100);
        env::set_var("K2_LOG_PATH", path);

        assert!(Settings::init().is_err());

        env::remove_var("K2_LOG_PATH");
    }

    #[test]
    fn error_with_wrong_base_url() {
        let url = random_string(100);
        env::set_var("K2_BASE_URL", url);

        assert!(Settings::init().is_err());

        env::remove_var("K2_BASE_URL");
    }

    #[test]
    fn enforce_ctn_and_pn_were_set() {
        let mut settings = Settings::init().unwrap();
        assert_that(&settings)
            .map(|val| &val.ctn)
            .is_equal_to(&None);
        assert_that(&settings).map(|val| &val.pn).is_equal_to(&None);

        let ctn = rand::random::<u16>();
        env::set_var("K2_CTN", format!("{}", ctn));

        settings = Settings::init().unwrap();
        assert_that(&settings)
            .map(|val| &val.ctn)
            .is_equal_to(&None);
        assert_that(&settings).map(|val| &val.pn).is_equal_to(&None);

        env::remove_var("K2_CTN");

        let pn = rand::random::<u16>();
        env::set_var("K2_PN", format!("{}", pn));

        settings = Settings::init().unwrap();
        assert_that(&settings)
            .map(|val| &val.ctn)
            .is_equal_to(&None);
        assert_that(&settings).map(|val| &val.pn).is_equal_to(&None);

        env::set_var("K2_CTN", format!("{}", ctn));

        settings = Settings::init().unwrap();
        assert_that(&settings)
            .map(|val| &val.ctn)
            .is_equal_to(&Some(ctn));
        assert_that(&settings)
            .map(|val| &val.pn)
            .is_equal_to(&Some(pn));

        env::remove_var("K2_CTN");
        env::remove_var("K2_PN");
    }
}
<|endoftext|>


<commit_before>use crate::utils::{
    add_extra_ty_param_bound, add_extra_where_clauses, field_idents, get_field_types,
    named_to_vec, unnamed_to_vec,
};
use proc_macro2::{Span, TokenStream};
use quote::{quote, ToTokens};
use syn::{Data, DeriveInput, Field, Fields, Ident};

pub fn expand(input: &DeriveInput, trait_name: &str) -> TokenStream {
    let trait_ident = Ident::new(trait_name, Span::call_site());
    let method_name = trait_name.to_string().to_lowercase();
    let method_ident = Ident::new(&(method_name), Span::call_site());
    let input_type = &input.ident;
    let trait_path = quote!(::core::iter::#trait_ident);
    let op_trait_name = if trait_name == "Sum" { "Add" } else { "Mul" };
    let op_trait_ident = Ident::new(op_trait_name, Span::call_site());
    let op_path = quote!(::core::ops::#op_trait_ident);
    let op_method_ident = Ident::new(
        &(op_trait_name.to_string().to_lowercase()),
        Span::call_site(),
    );
    let type_params: Vec<_> = input
        .generics
        .type_params()
        .map(|t| t.ident.clone())
        .collect();
    let generics = if type_params.is_empty() {
        input.generics.clone()
    } else {
        let generic_type = quote!(<#(#type_params),*>);
        let generics = add_extra_ty_param_bound(&input.generics, &trait_path);
        let operator_where_clause = quote! {
            where #input_type#generic_type: #op_path<Output=#input_type#generic_type>
        };
        add_extra_where_clauses(&generics, operator_where_clause)
    };
    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

    let identity = match input.data {
        Data::Struct(ref data_struct) => match data_struct.fields {
            Fields::Unnamed(ref fields) => {
                tuple_identity(input_type, &unnamed_to_vec(fields), &method_ident)
            }
            Fields::Named(ref fields) => {
                struct_identity(input_type, &named_to_vec(fields), &method_ident)
            }
            _ => panic!(format!("Unit structs cannot use derive({})", trait_name)),
        },

        _ => panic!(format!("Only structs can use derive({})", trait_name)),
    };

    quote!(
        impl#impl_generics #trait_path for #input_type#ty_generics #where_clause {
            #[inline]
            fn #method_ident<I: ::core::iter::Iterator<Item = Self>>(iter: I) -> Self {
                iter.fold(#identity, #op_path::#op_method_ident)
            }
        }
    )
}

fn tuple_identity<T: ToTokens>(
    input_type: &T,
    fields: &[&Field],
    method_ident: &Ident,
) -> TokenStream {
    let types = &get_field_types(fields);
    quote!(#input_type(#(::core::iter::empty::<#types>().#method_ident()),*))
}

fn struct_identity(
    input_type: &Ident,
    fields: &[&Field],
    method_ident: &Ident,
) -> TokenStream {
    let field_names = field_idents(fields);
    let types = &get_field_types(fields);

    quote!(#input_type{#(#field_names: ::core::iter::empty::<#types>().#method_ident()),*})
}
<commit_msg>Make Sum use State<commit_after>use crate::utils::{
    add_extra_ty_param_bound, add_extra_where_clauses, MultiFieldData, State,
};
use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::{DeriveInput, Ident, Result};

pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result<TokenStream> {
    let state = State::new(
        input,
        trait_name,
        quote!(::core::iter),
        trait_name.to_lowercase(),
    )?;
    let multi_field_data = state.enabled_fields_data();
    let MultiFieldData {
        input_type,
        field_types,
        trait_path,
        method_ident,
        ..
    } = multi_field_data.clone();

    let op_trait_name = if trait_name == "Sum" { "Add" } else { "Mul" };
    let op_trait_ident = Ident::new(op_trait_name, Span::call_site());
    let op_path = quote!(::core::ops::#op_trait_ident);
    let op_method_ident =
        Ident::new(&(op_trait_name.to_lowercase()), Span::call_site());
    let type_params: Vec<_> = input
        .generics
        .type_params()
        .map(|t| t.ident.clone())
        .collect();
    let generics = if type_params.is_empty() {
        input.generics.clone()
    } else {
        let generic_type = quote!(<#(#type_params),*>);
        let generics = add_extra_ty_param_bound(&input.generics, &trait_path);
        let operator_where_clause = quote! {
            where #input_type#generic_type: #op_path<Output=#input_type#generic_type>
        };
        add_extra_where_clauses(&generics, operator_where_clause)
    };
    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

    let initializers: Vec<_> = field_types
        .iter()
        .map(|field_type| quote!(#trait_path::#method_ident(::core::iter::empty::<#field_type>())))
        .collect();
    let identity = multi_field_data.initializer(&initializers);

    Ok(quote!(
        impl#impl_generics #trait_path for #input_type#ty_generics #where_clause {
            #[inline]
            fn #method_ident<I: ::core::iter::Iterator<Item = Self>>(iter: I) -> Self {
                iter.fold(#identity, #op_path::#op_method_ident)
            }
        }
    ))
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::sync::{Arc, RwLock};

use super::{Editor, Result};
use completion::Completer;
use config::{Config, EditMode};
use edit::init_state;
use keymap::{Cmd, InputState};
use keys::KeyPress;
use tty::Sink;

mod common;
mod emacs;
mod history;
mod vi_cmd;
mod vi_insert;

fn init_editor(mode: EditMode, keys: &[KeyPress]) -> Editor<()> {
    let config = Config::builder().edit_mode(mode).build();
    let mut editor = Editor::<()>::with_config(config);
    editor.term.keys.extend(keys.iter().cloned());
    editor
}

struct SimpleCompleter;
impl Completer for SimpleCompleter {
    type Candidate = String;

    fn complete(&self, line: &str, _pos: usize) -> Result<(usize, Vec<String>)> {
        Ok((0, vec![line.to_owned() + "t"]))
    }
}

#[test]
fn complete_line() {
    let mut out = Sink::new();
    let mut s = init_state(&mut out, "rus", 3);
    let config = Config::default();
    let mut input_state = InputState::new(&config, Arc::new(RwLock::new(HashMap::new())));
    let keys = &[KeyPress::Enter];
    let mut rdr = keys.iter();
    let completer = SimpleCompleter;
    let cmd = super::complete_line(
        &mut rdr,
        &mut s,
        &mut input_state,
        &completer,
        None,
        &Config::default(),
    )
    .unwrap();
    assert_eq!(Some(Cmd::AcceptLine), cmd);
    assert_eq!("rust", s.line.as_str());
    assert_eq!(4, s.line.pos());
}

// `keys`: keys to press
// `expected_line`: line after enter key
fn assert_line(mode: EditMode, keys: &[KeyPress], expected_line: &str) {
    let mut editor = init_editor(mode, keys);
    let actual_line = editor.readline(">>").unwrap();
    assert_eq!(expected_line, actual_line);
}

// `initial`: line status before `keys` pressed: strings before and after cursor
// `keys`: keys to press
// `expected_line`: line after enter key
fn assert_line_with_initial(
    mode: EditMode,
    initial: (&str, &str),
    keys: &[KeyPress],
    expected_line: &str,
) {
    let mut editor = init_editor(mode, keys);
    let actual_line = editor.readline_with_initial(">>", initial).unwrap();
    assert_eq!(expected_line, actual_line);
}

// `initial`: line status before `keys` pressed: strings before and after cursor
// `keys`: keys to press
// `expected`: line status before enter key: strings before and after cursor
fn assert_cursor(mode: EditMode, initial: (&str, &str), keys: &[KeyPress], expected: (&str, &str)) {
    let mut editor = init_editor(mode, keys);
    let actual_line = editor.readline_with_initial("", initial).unwrap();
    assert_eq!(expected.0.to_owned() + expected.1, actual_line);
    assert_eq!(expected.0.len(), editor.term.cursor);
}

// `entries`: history entries before `keys` pressed
// `keys`: keys to press
// `expected`: line status before enter key: strings before and after cursor
fn assert_history(mode: EditMode, entries: &[&str], keys: &[KeyPress], expected: (&str, &str)) {
    let mut editor = init_editor(mode, keys);
    for entry in entries {
        editor.history.add(*entry);
    }
    let actual_line = editor.readline("").unwrap();
    assert_eq!(expected.0.to_owned() + expected.1, actual_line);
    assert_eq!(expected.0.len(), editor.term.cursor);
}

#[test]
fn unknown_esc_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_line(*mode, &[KeyPress::UnknownEscSeq, KeyPress::Enter], "");
    }
}
<commit_msg>Fix some rustc warnings<commit_after>use std::collections::HashMap;
use std::sync::{Arc, RwLock};

use super::{Editor, Result, StdStream};
use completion::Completer;
use config::{Config, EditMode, OutputStreamType};
use edit::init_state;
use keymap::{Cmd, InputState};
use keys::KeyPress;
use tty::Sink;

mod common;
mod emacs;
mod history;
mod vi_cmd;
mod vi_insert;

fn init_editor(mode: EditMode, keys: &[KeyPress]) -> Editor<()> {
    let config = Config::builder().edit_mode(mode).build();
    let mut editor = Editor::<()>::with_config(config);
    editor.term.keys.extend(keys.iter().cloned());
    editor
}

struct SimpleCompleter;
impl Completer for SimpleCompleter {
    type Candidate = String;

    fn complete(&self, line: &str, _pos: usize) -> Result<(usize, Vec<String>)> {
        Ok((0, vec![line.to_owned() + "t"]))
    }
}

#[test]
fn complete_line() {
    let mut out = Sink::new();
    let mut s = init_state(&mut out, "rus", 3);
    let config = Config::default();
    let mut input_state = InputState::new(&config, Arc::new(RwLock::new(HashMap::new())));
    let keys = &[KeyPress::Enter];
    let mut rdr = keys.iter();
    let completer = SimpleCompleter;
    let cmd = super::complete_line(
        &mut rdr,
        &mut s,
        &mut input_state,
        &completer,
        None,
        &Config::default(),
    )
    .unwrap();
    assert_eq!(Some(Cmd::AcceptLine), cmd);
    assert_eq!("rust", s.line.as_str());
    assert_eq!(4, s.line.pos());
}

// `keys`: keys to press
// `expected_line`: line after enter key
fn assert_line(mode: EditMode, keys: &[KeyPress], expected_line: &str) {
    let mut editor = init_editor(mode, keys);
    let actual_line = editor.readline(">>").unwrap();
    assert_eq!(expected_line, actual_line);
}

// `initial`: line status before `keys` pressed: strings before and after cursor
// `keys`: keys to press
// `expected_line`: line after enter key
fn assert_line_with_initial(
    mode: EditMode,
    initial: (&str, &str),
    keys: &[KeyPress],
    expected_line: &str,
) {
    let mut editor = init_editor(mode, keys);
    let actual_line = editor.readline_with_initial(">>", initial).unwrap();
    assert_eq!(expected_line, actual_line);
}

// `initial`: line status before `keys` pressed: strings before and after cursor
// `keys`: keys to press
// `expected`: line status before enter key: strings before and after cursor
fn assert_cursor(mode: EditMode, initial: (&str, &str), keys: &[KeyPress], expected: (&str, &str)) {
    let mut editor = init_editor(mode, keys);
    let actual_line = editor.readline_with_initial("", initial).unwrap();
    assert_eq!(expected.0.to_owned() + expected.1, actual_line);
    assert_eq!(expected.0.len(), editor.term.cursor);
}

// `entries`: history entries before `keys` pressed
// `keys`: keys to press
// `expected`: line status before enter key: strings before and after cursor
fn assert_history(mode: EditMode, entries: &[&str], keys: &[KeyPress], expected: (&str, &str)) {
    let mut editor = init_editor(mode, keys);
    for entry in entries {
        editor.history.add(*entry);
    }
    let actual_line = editor.readline("").unwrap();
    assert_eq!(expected.0.to_owned() + expected.1, actual_line);
    assert_eq!(expected.0.len(), editor.term.cursor);
}

#[test]
fn unknown_esc_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_line(*mode, &[KeyPress::UnknownEscSeq, KeyPress::Enter], "");
    }
}

#[test]
fn from_stream_type() {
    StdStream::from_stream_type(OutputStreamType::Stdout);
}
<|endoftext|>


<commit_before>// build-fail
#![allow(non_camel_case_types)]
#![feature(repr_simd, platform_intrinsics)]

// Test for #73542 to verify out-of-bounds shuffle vectors do not compile.

#[repr(simd)]
#[derive(Copy, Clone)]
struct u8x2(u8, u8);

#[repr(simd)]
#[derive(Copy, Clone)]
struct u8x4(u8, u8, u8, u8);

#[repr(simd)]
#[derive(Copy, Clone)]
struct u8x8(u8, u8, u8, u8, u8, u8, u8, u8);

#[repr(simd)]
#[derive(Copy, Clone)]
struct u8x16(
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
);

#[repr(simd)]
#[derive(Copy, Clone)]
struct u8x32(
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
);

#[repr(simd)]
#[derive(Copy, Clone)]
struct u8x64(
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
);

// Test vectors by lane size. Since LLVM does not distinguish between a shuffle
// over two f32s and a shuffle over two u64s, or any other such combination,
// it is not necessary to test every possible vector, only lane counts.
macro_rules! test_shuffle_lanes {
    ($n:literal, $x:ident, $y:ident, $t:tt) => {
        unsafe {
                let shuffle: $x = {
                    const ARR: [u32; $n] = {
                        let mut arr = [0; $n];
                        arr[0] = $n * 2;
                        arr
                    };
                    extern "platform-intrinsic" {
                        pub fn $y<T, U>(x: T, y: T, idx: [u32; $n]) -> U;
                    }
                    let vec1 = $x$t;
                    let vec2 = $x$t;
                    $y(vec1, vec2, ARR)
                };
        }
    }
}
//~^^^^^ ERROR: invalid monomorphization of `simd_shuffle2` intrinsic
//~^^^^^^ ERROR: invalid monomorphization of `simd_shuffle4` intrinsic
//~^^^^^^^ ERROR: invalid monomorphization of `simd_shuffle8` intrinsic
//~^^^^^^^^ ERROR: invalid monomorphization of `simd_shuffle16` intrinsic
//~^^^^^^^^^ ERROR: invalid monomorphization of `simd_shuffle32` intrinsic
//~^^^^^^^^^^ ERROR: invalid monomorphization of `simd_shuffle64` intrinsic
// Because the test is mostly embedded in a macro, all the errors have the same origin point.

fn main() {
    test_shuffle_lanes!(2, u8x2, simd_shuffle2, (2, 1));
    test_shuffle_lanes!(4, u8x4, simd_shuffle4, (4, 3, 2, 1));
    test_shuffle_lanes!(8, u8x8, simd_shuffle8, (8, 7, 6, 5, 4, 3, 2, 1));
    test_shuffle_lanes!(16, u8x16, simd_shuffle16,
        (16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
    test_shuffle_lanes!(32, u8x32, simd_shuffle32,
        (32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16,
         15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
    test_shuffle_lanes!(64, u8x64, simd_shuffle64,
        (64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49,
         48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33,
         32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17,
         16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
}
<commit_msg>Flatten arrows with further comment<commit_after>// build-fail
#![allow(non_camel_case_types)]
#![feature(repr_simd, platform_intrinsics)]

// Test for #73542 to verify out-of-bounds shuffle vectors do not compile.

#[repr(simd)]
#[derive(Copy, Clone)]
struct u8x2(u8, u8);

#[repr(simd)]
#[derive(Copy, Clone)]
struct u8x4(u8, u8, u8, u8);

#[repr(simd)]
#[derive(Copy, Clone)]
struct u8x8(u8, u8, u8, u8, u8, u8, u8, u8);

#[repr(simd)]
#[derive(Copy, Clone)]
struct u8x16(
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
);

#[repr(simd)]
#[derive(Copy, Clone)]
struct u8x32(
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
);

#[repr(simd)]
#[derive(Copy, Clone)]
struct u8x64(
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
    u8,
);

// Test vectors by lane size. Since LLVM does not distinguish between a shuffle
// over two f32s and a shuffle over two u64s, or any other such combination,
// it is not necessary to test every possible vector, only lane counts.
macro_rules! test_shuffle_lanes {
    ($n:literal, $x:ident, $y:ident, $t:tt) => {
        unsafe {
                let shuffle: $x = {
                    const ARR: [u32; $n] = {
                        let mut arr = [0; $n];
                        arr[0] = $n * 2;
                        arr
                    };
                    extern "platform-intrinsic" {
                        pub fn $y<T, U>(x: T, y: T, idx: [u32; $n]) -> U;
                    }
                    let vec1 = $x$t;
                    let vec2 = $x$t;
                    $y(vec1, vec2, ARR)
                };
        }
    }
}
//~^^^^^ ERROR: invalid monomorphization of `simd_shuffle2` intrinsic
//~| ERROR: invalid monomorphization of `simd_shuffle4` intrinsic
//~| ERROR: invalid monomorphization of `simd_shuffle8` intrinsic
//~| ERROR: invalid monomorphization of `simd_shuffle16` intrinsic
//~| ERROR: invalid monomorphization of `simd_shuffle32` intrinsic
//~| ERROR: invalid monomorphization of `simd_shuffle64` intrinsic
// Because the test is mostly embedded in a macro, all the errors have the same origin point.
// And unfortunately, standard comments, as in the UI test harness, disappear in macros!

fn main() {
    test_shuffle_lanes!(2, u8x2, simd_shuffle2, (2, 1));
    test_shuffle_lanes!(4, u8x4, simd_shuffle4, (4, 3, 2, 1));
    test_shuffle_lanes!(8, u8x8, simd_shuffle8, (8, 7, 6, 5, 4, 3, 2, 1));
    test_shuffle_lanes!(16, u8x16, simd_shuffle16,
        (16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
    test_shuffle_lanes!(32, u8x32, simd_shuffle32,
        (32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16,
         15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
    test_shuffle_lanes!(64, u8x64, simd_shuffle64,
        (64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49,
         48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33,
         32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17,
         16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1));
}
<|endoftext|>


<commit_before>
fn main() {

    // formatted output
    println!("Hello, Rust!");
    println!("Integer number = {}", 23);
    println!("Float number = {}", 1.012);
    println!("Repeat printing: {0}, {1}, {1}, {3}, {2}", 2, 1, 44, 9);
    println!("Named arguments: {name}, {age}, {occupation}", age="24", name="Ann", occupation="Designer");
    println!("{:08b} XOR {:08b} = {:08b}", 3i8, 32i8, 3i8 ^ 34i8);
    println!("Floating point number {:?}", 2.910210);
    println!("Hex: {:08X}, {:08x}", 131342112, 131342112);
    // TODO find out why this doesn't work:
    //println!("{0:08X}, {0:08x}", 7661);

    // variables
    let integer = 3i32;
    let floatingPoint = 2.1137;

    let mut uInteger = 3u32;
    //integer += 1; error: an immutable variable
    uInteger += 1;

    println!("{}, {}, {}", integer, floatingPoint, uInteger);
    // TODO find out why snake case instead of camel case

    // shadowing
    let first_var = 4;
    {
        let first_var = 51;
        println!("first_var = {}", first_var);
    }
    println!("first_var = {}", first_var);

    // unitialized variables
    let uninit_var;
    //println!("uninit_var = {}", uninit_var); error: use of an init variable
    uninit_var = 231.2;
    println!("already initialized uninit_var = {}", uninit_var);

    // type casting
    let a_integer = 0x40_u8;
    let a_char = a_integer as char;
    println!("char cast from integer {}: {}", a_integer, a_char);

    let a_float = 8.45511;
    println!("integer cast from float {}: {}", a_float, a_float as i32);

    println!("Binary represntation of {}: {:08b}", -1_i8, -1_i8);
    println!("Binary represntation of {}: {:08b}", -2_i8, -2_i8);

    // aliases
    type FloatingPoint32 = f32;
    let a_float_2 : FloatingPoint32 = 3 as f32;
    println!("Type alias: {}, size of var {}", a_float_2, std::mem::size_of_val(&a_float_2));

    // expressions
    let expr = {
        let x = 4.09;
        let y = 1.28;
        println!("x = {}, y = {}", x, y);
        x / y
    };
    println!("expr = {}", expr);

    // if-statement (every if-statement is an expression too, which is really a cool thing)
    let speed = 10;
    let mass = 890;
    let consumption =
        if speed < 0 {
            -1.0
        }
        else if speed == 0 {
            0.8
        }
        else if speed > 0 && speed < 10 {
            18.52
        }
        else if speed >= 10 && speed < 30 {
            let x = mass / speed;
            (x as f32) * 0.05
        }
        else {
            11.71
        };
        println!("Speed = {}, consumption = {}", speed, consumption);

        // loop
        let mut count = 0u32;
        loop {
            println!("loop iteration #{}", count);
            count += 1;
            if count > 9 {
            break;
            }
        }

        count = 0;
        while count < 10 {
            println!("while loop iteration #{}", count);
            count += 1;
        }

        for n in 0u32..10 {
            println!("for loop iteration #{}", n);
        }

        // matching
        let age = 19;
        match age {
            1  => println!("Seems like 1"),
            5  => println!("It's 5"),
            18 => println!("Exactly 18!"),
            _  => println!("I couldn't guess :("),
        }

        match age {
            a if a > 1 && a <= 9  => println!("The age is in range [1,9]"),
            a if a > 9 && a <= 19 => println!("The age is in range [10, 19]"),
            _                     => println!("Nothing, I don't know what range the age is in :("),
        }

        // the previous match is equivalent to the following:
        match age {
            a @ 1...9   => println!("The age is in range [1,9]"),
            a @ 10...19 => println!("The age is in range [10, 19]"),
            a           => println!("Nothing, I don't know what range the age is in :("),
        }

        // if let
        let a_some = Some(0.0008);
        if let Some(i) = a_some {
            println!("a_some is not None, {}", i);
            println!("result {}",  9.0 / i);
        }
        else {
            println!("None");
        }

        // while let
        let mut a_optional = Some(10);

        while let Some(i) = a_optional {
            if i == 20 {
                println!("while let: i equals 20, leave");
                a_optional = None;
            }
            else {
                a_optional = Some(i + 1);
            }
        }

        // functions, finally!
        let first_integer: i32 = -20;
        let second_integer: i32 = 8;
        let result_of_addition = add_two_integers(first_integer, second_integer);
        println!("{} + {} = {}", first_integer, second_integer, result_of_addition);

        // modules
        mod simple_functions {
            pub fn print_hello_world() {
                println!("Hello, World! (from the simple_functions module)");
            }

            // nested modules
            pub mod simple_math {
                pub fn multiple_two_integers(a: i32, b: i32) -> i32 {
                    a * b
                }
            }
        }

        simple_functions::print_hello_world();
        let mul_result = simple_functions::simple_math::multiple_two_integers(3, 15);
        println!("Modules: multiplication result = {}", mul_result);

        // this doesn't work.. why?
        //use simple_functions::simple_math::multiple_two_integers;
        //println!("Modules: multiplication result 2 = {}", multiple_two_integers(-1, 8));
}

fn add_two_integers(a: i32, b: i32) -> i32 {
    a + b
}
<commit_msg>Module and the corresponding use statement should be outside main. Then it works.<commit_after>
// modules
mod simple_functions {
    pub fn print_hello_world() {
        println!("Hello, World! (from the simple_functions module)");
     }

    // nested modules
    pub mod simple_math {
        pub fn multiple_two_integers(a: i32, b: i32) -> i32 {
            a * b
        }
    }
}

use simple_functions::simple_math::multiple_two_integers;

fn main() {

    // formatted output
    println!("Hello, Rust!");
    println!("Integer number = {}", 23);
    println!("Float number = {}", 1.012);
    println!("Repeat printing: {0}, {1}, {1}, {3}, {2}", 2, 1, 44, 9);
    println!("Named arguments: {name}, {age}, {occupation}", age="24", name="Ann", occupation="Designer");
    println!("{:08b} XOR {:08b} = {:08b}", 3i8, 32i8, 3i8 ^ 34i8);
    println!("Floating point number {:?}", 2.910210);
    println!("Hex: {:08X}, {:08x}", 131342112, 131342112);
    // TODO find out why this doesn't work:
    //println!("{0:08X}, {0:08x}", 7661);

    // variables
    let integer = 3i32;
    let floatingPoint = 2.1137;

    let mut uInteger = 3u32;
    //integer += 1; error: an immutable variable
    uInteger += 1;

    println!("{}, {}, {}", integer, floatingPoint, uInteger);
    // TODO find out why snake case instead of camel case

    // shadowing
    let first_var = 4;
    {
        let first_var = 51;
        println!("first_var = {}", first_var);
    }
    println!("first_var = {}", first_var);

    // unitialized variables
    let uninit_var;
    //println!("uninit_var = {}", uninit_var); error: use of an init variable
    uninit_var = 231.2;
    println!("already initialized uninit_var = {}", uninit_var);

    // type casting
    let a_integer = 0x40_u8;
    let a_char = a_integer as char;
    println!("char cast from integer {}: {}", a_integer, a_char);

    let a_float = 8.45511;
    println!("integer cast from float {}: {}", a_float, a_float as i32);

    println!("Binary represntation of {}: {:08b}", -1_i8, -1_i8);
    println!("Binary represntation of {}: {:08b}", -2_i8, -2_i8);

    // aliases
    type FloatingPoint32 = f32;
    let a_float_2 : FloatingPoint32 = 3 as f32;
    println!("Type alias: {}, size of var {}", a_float_2, std::mem::size_of_val(&a_float_2));

    // expressions
    let expr = {
        let x = 4.09;
        let y = 1.28;
        println!("x = {}, y = {}", x, y);
        x / y
    };
    println!("expr = {}", expr);

    // if-statement (every if-statement is an expression too, which is really a cool thing)
    let speed = 10;
    let mass = 890;
    let consumption =
        if speed < 0 {
            -1.0
        }
        else if speed == 0 {
            0.8
        }
        else if speed > 0 && speed < 10 {
            18.52
        }
        else if speed >= 10 && speed < 30 {
            let x = mass / speed;
            (x as f32) * 0.05
        }
        else {
            11.71
        };
        println!("Speed = {}, consumption = {}", speed, consumption);

        // loop
        let mut count = 0u32;
        loop {
            println!("loop iteration #{}", count);
            count += 1;
            if count > 9 {
            break;
            }
        }

        count = 0;
        while count < 10 {
            println!("while loop iteration #{}", count);
            count += 1;
        }

        for n in 0u32..10 {
            println!("for loop iteration #{}", n);
        }

        // matching
        let age = 19;
        match age {
            1  => println!("Seems like 1"),
            5  => println!("It's 5"),
            18 => println!("Exactly 18!"),
            _  => println!("I couldn't guess :("),
        }

        match age {
            a if a > 1 && a <= 9  => println!("The age is in range [1,9]"),
            a if a > 9 && a <= 19 => println!("The age is in range [10, 19]"),
            _                     => println!("Nothing, I don't know what range the age is in :("),
        }

        // the previous match is equivalent to the following:
        match age {
            a @ 1...9   => println!("The age is in range [1,9]"),
            a @ 10...19 => println!("The age is in range [10, 19]"),
            a           => println!("Nothing, I don't know what range the age is in :("),
        }

        // if let
        let a_some = Some(0.0008);
        if let Some(i) = a_some {
            println!("a_some is not None, {}", i);
            println!("result {}",  9.0 / i);
        }
        else {
            println!("None");
        }

        // while let
        let mut a_optional = Some(10);

        while let Some(i) = a_optional {
            if i == 20 {
                println!("while let: i equals 20, leave");
                a_optional = None;
            }
            else {
                a_optional = Some(i + 1);
            }
        }

        // functions, finally!
        let first_integer: i32 = -20;
        let second_integer: i32 = 8;
        let result_of_addition = add_two_integers(first_integer, second_integer);
        println!("{} + {} = {}", first_integer, second_integer, result_of_addition);

        simple_functions::print_hello_world();
        let mul_result = simple_functions::simple_math::multiple_two_integers(3, 15);
        println!("Modules: multiplication result = {}", mul_result);

        // this doesn't work.. why?
        println!("Modules: multiplication result 2 = {}", multiple_two_integers(-1, 8));
}

fn add_two_integers(a: i32, b: i32) -> i32 {
    a + b
}
<|endoftext|>


<commit_before>use common::*;
use polynomial::Polynomial;
use vector_monomial::VectorMonomial;

// An FENum identifies a finite element in the mesh.
#[deriving(Eq,TotalEq,Ord,TotalOrd,Clone)]
pub struct FENum(uint);

// An NBSideNum identifies a mesh side among all sides in the mesh.
#[deriving(Eq,TotalEq,Ord,TotalOrd,Clone)]
pub struct NBSideNum(uint);

// A SideFace identifies a side within the context of a single oriented shape
// or finite element.
#[deriving(Eq,TotalEq,Ord,TotalOrd,Clone)]
pub struct SideFace(uint);

/// A Face locally identifies either the interior or a side in the context of a single
/// oriented shape or finite element.
#[deriving(Eq,TotalEq,Ord,TotalOrd,Clone)]
pub enum Face {
  Interior,
  Side(SideFace)
}

/// An identifier for the shape of a finite element together with the orientation
/// of the shape (rotation will yield a different oriented shape). Many calculations
/// on a finite element can be expressed in element-local coordinates and will only
/// depend on the oriented shape of the element.
#[deriving(Eq,TotalEq,Ord,TotalOrd,Clone)]
pub struct OShape(uint);

/// The representations of a non-boundary side as a pair of finite element faces.
/// The elements are arranged so that fe1 < fe2.
#[deriving(Eq,TotalEq,Ord,TotalOrd,Clone)]
pub struct NBSideInclusions {
  nb_side_num: NBSideNum,

  fe1: FENum,
  side_face_in_fe1: SideFace,

  fe2: FENum,
  side_face_in_fe2: SideFace
}

pub trait Mesh<Mon> {

  fn num_fes(&self) -> uint;

  fn num_nb_sides(&self) -> uint;

  fn num_oriented_element_shapes(&self) -> uint;

  fn oriented_shape_for_fe(&self, fe: FENum) -> OShape;

  fn num_side_faces_for_fe(&self, fe: FENum) -> uint;

  fn num_side_faces_for_shape(&self, oshape: OShape) -> uint;

  // The dependent dim is, for a given side, the dimension j which is affine-
  // dependent on the other dimensions on the side. That is, the function
  // returns a j for which c_0,...,c_d exist such that
  //   x_j = c_0 + sum_{i=1..d} c_i x_i for all (x_1,...,x_d) in the side.
  // There may be more than one such coordinate number, in which case any
  // one of these may be returned depending on the mesh implementation.
  fn dependent_dim_for_oshape_side(&self, oshape: OShape, side_face: SideFace) -> Dim;

  fn fe_inclusions_of_nb_side(&self, side_num: NBSideNum) -> NBSideInclusions;

  // Return non-boundary side number of the indicated fe relative side.
  fn nb_side_num_for_fe_side(&self, fe: FENum, side_face: SideFace) -> NBSideNum;

  fn is_boundary_side(&self, fe: FENum, side_face: SideFace) -> bool;

  fn num_boundary_sides(&self) -> uint;

  fn boundary_fes_by_oshape_side(&self) -> ~[~[~[FENum]]]; // oshape, side face -> fes

  fn shape_diameter_inv(&self, oshape: OShape) -> R;

  fn max_fe_diameter(&self) -> R;

  fn num_nb_sides_for_fe(&self, fe: FENum) -> uint;

  fn max_num_shape_sides(&self) -> uint;

  // integration functions

  fn intg_global_fn_on_fe_int(&self,
       g: &fn(&[R]) -> R,
       fe: FENum) -> R;

  fn intg_global_fn_x_facerel_mon_on_fe_int(&self,
       g: &fn(&[R]) -> R,
       mon: Mon,
       fe: FENum) -> R;

  fn intg_global_fn_x_facerel_mon_on_fe_side(&self,
       g: &fn(&[R]) -> R,
       mon: Mon,
       fe: FENum,
       side_face: SideFace) -> R;

  fn intg_facerel_poly_on_oshape_int<P:Polynomial<Mon>>(&self,
       p: &P,
       oshape: OShape) -> R;

  fn intg_facerel_poly_x_facerel_poly_on_oshape_int<P:Polynomial<Mon>>(&self,
       p1: &P,
       p2: &P,
       oshape: OShape) -> R;

  fn intg_facerel_poly_x_facerel_poly_on_oshape_side<P:Polynomial<Mon>>(&self,
       p1: &P,
       p2: &P,
       oshape: OShape,
       side_face: SideFace) -> R;

  fn intg_facerel_mon_on_oshape_int(&self,
       mon: Mon,
       oshape: OShape) -> R;

  fn intg_facerel_mon_on_oshape_side(&self,
       mon: Mon,
       oshape: OShape,
       side_face: SideFace) -> R;

  fn intg_facerel_mon_x_facerel_poly_on_oshape_int<P:Polynomial<Mon>>(&self,
       mon: Mon,
       p: &P,
       oshape: OShape) -> R;

  fn intg_facerel_mon_x_facerel_poly_on_oshape_side<P:Polynomial<Mon>>(&self,
       mon: Mon,
       p: &P,
       oshape: OShape,
       side_face: SideFace) -> R;

  fn intg_intrel_mon_x_siderel_mon_on_oshape_side(&self,
       int_mon: Mon,
       side_mon: Mon, oshape: OShape,
       side_face: SideFace) -> R;

  fn intg_siderel_mon_x_intrel_vmon_dot_normal_on_oshape_side(&self,
       mon: Mon,
       q: &VectorMonomial<Mon>,
       oshape: OShape,
       side_face: SideFace) -> R;

  fn intg_siderel_poly_x_intrel_vmon_dot_normal_on_oshape_side<P:Polynomial<Mon>>(&self,
       p: &P,
       q: &VectorMonomial<Mon>,
       oshape: OShape,
       side_face: SideFace) -> R;

}

<commit_msg>Add IterByes auto-derive for FENum, NBSideNum, SideFace.<commit_after>use common::*;
use polynomial::Polynomial;
use vector_monomial::VectorMonomial;

// An FENum identifies a finite element in the mesh.
#[deriving(Eq,TotalEq,Ord,TotalOrd,Clone,IterBytes)]
pub struct FENum(uint);

// An NBSideNum identifies a mesh side among all sides in the mesh.
#[deriving(Eq,TotalEq,Ord,TotalOrd,Clone,IterBytes)]
pub struct NBSideNum(uint);

// A SideFace identifies a side within the context of a single oriented shape
// or finite element.
#[deriving(Eq,TotalEq,Ord,TotalOrd,Clone,IterBytes)]
pub struct SideFace(uint);

/// A Face locally identifies either the interior or a side in the context of a single
/// oriented shape or finite element.
#[deriving(Eq,TotalEq,Ord,TotalOrd,Clone)]
pub enum Face {
  Interior,
  Side(SideFace)
}

/// An identifier for the shape of a finite element together with the orientation
/// of the shape (rotation will yield a different oriented shape). Many calculations
/// on a finite element can be expressed in element-local coordinates and will only
/// depend on the oriented shape of the element.
#[deriving(Eq,TotalEq,Ord,TotalOrd,Clone)]
pub struct OShape(uint);

/// The representations of a non-boundary side as a pair of finite element faces.
/// The elements are arranged so that fe1 < fe2.
#[deriving(Eq,TotalEq,Ord,TotalOrd,Clone)]
pub struct NBSideInclusions {
  nb_side_num: NBSideNum,

  fe1: FENum,
  side_face_in_fe1: SideFace,

  fe2: FENum,
  side_face_in_fe2: SideFace
}

pub trait Mesh<Mon> {

  fn num_fes(&self) -> uint;

  fn num_nb_sides(&self) -> uint;

  fn num_oriented_element_shapes(&self) -> uint;

  fn oriented_shape_for_fe(&self, fe: FENum) -> OShape;

  fn num_side_faces_for_fe(&self, fe: FENum) -> uint;

  fn num_side_faces_for_shape(&self, oshape: OShape) -> uint;

  // The dependent dim is, for a given side, the dimension j which is affine-
  // dependent on the other dimensions on the side. That is, the function
  // returns a j for which c_0,...,c_d exist such that
  //   x_j = c_0 + sum_{i=1..d} c_i x_i for all (x_1,...,x_d) in the side.
  // There may be more than one such coordinate number, in which case any
  // one of these may be returned depending on the mesh implementation.
  fn dependent_dim_for_oshape_side(&self, oshape: OShape, side_face: SideFace) -> Dim;

  fn fe_inclusions_of_nb_side(&self, side_num: NBSideNum) -> NBSideInclusions;

  // Return non-boundary side number of the indicated fe relative side.
  fn nb_side_num_for_fe_side(&self, fe: FENum, side_face: SideFace) -> NBSideNum;

  fn is_boundary_side(&self, fe: FENum, side_face: SideFace) -> bool;

  fn num_boundary_sides(&self) -> uint;

  fn boundary_fes_by_oshape_side(&self) -> ~[~[~[FENum]]]; // oshape, side face -> fes

  fn shape_diameter_inv(&self, oshape: OShape) -> R;

  fn max_fe_diameter(&self) -> R;

  fn num_nb_sides_for_fe(&self, fe: FENum) -> uint;

  fn max_num_shape_sides(&self) -> uint;

  // integration functions

  fn intg_global_fn_on_fe_int(&self,
       g: &fn(&[R]) -> R,
       fe: FENum) -> R;

  fn intg_global_fn_x_facerel_mon_on_fe_int(&self,
       g: &fn(&[R]) -> R,
       mon: Mon,
       fe: FENum) -> R;

  fn intg_global_fn_x_facerel_mon_on_fe_side(&self,
       g: &fn(&[R]) -> R,
       mon: Mon,
       fe: FENum,
       side_face: SideFace) -> R;

  fn intg_facerel_poly_on_oshape_int<P:Polynomial<Mon>>(&self,
       p: &P,
       oshape: OShape) -> R;

  fn intg_facerel_poly_x_facerel_poly_on_oshape_int<P:Polynomial<Mon>>(&self,
       p1: &P,
       p2: &P,
       oshape: OShape) -> R;

  fn intg_facerel_poly_x_facerel_poly_on_oshape_side<P:Polynomial<Mon>>(&self,
       p1: &P,
       p2: &P,
       oshape: OShape,
       side_face: SideFace) -> R;

  fn intg_facerel_mon_on_oshape_int(&self,
       mon: Mon,
       oshape: OShape) -> R;

  fn intg_facerel_mon_on_oshape_side(&self,
       mon: Mon,
       oshape: OShape,
       side_face: SideFace) -> R;

  fn intg_facerel_mon_x_facerel_poly_on_oshape_int<P:Polynomial<Mon>>(&self,
       mon: Mon,
       p: &P,
       oshape: OShape) -> R;

  fn intg_facerel_mon_x_facerel_poly_on_oshape_side<P:Polynomial<Mon>>(&self,
       mon: Mon,
       p: &P,
       oshape: OShape,
       side_face: SideFace) -> R;

  fn intg_intrel_mon_x_siderel_mon_on_oshape_side(&self,
       int_mon: Mon,
       side_mon: Mon, oshape: OShape,
       side_face: SideFace) -> R;

  fn intg_siderel_mon_x_intrel_vmon_dot_normal_on_oshape_side(&self,
       mon: Mon,
       q: &VectorMonomial<Mon>,
       oshape: OShape,
       side_face: SideFace) -> R;

  fn intg_siderel_poly_x_intrel_vmon_dot_normal_on_oshape_side<P:Polynomial<Mon>>(&self,
       p: &P,
       q: &VectorMonomial<Mon>,
       oshape: OShape,
       side_face: SideFace) -> R;

}

<|endoftext|>


<commit_before>use point::Point;
use std::collections::HashSet;
use std::iter;
use std::fmt;
use std::fmt::{Debug, Formatter};

pub static BLOCK: char = '\u{2588}';

#[derive(Clone, Copy)]
pub struct Range {
    pub point: Point,
    pub dir: Dir,
    pub len: usize,
}

pub struct RangeIter<'a> {
    range: Range,
    cw: &'a Crosswords,
}

impl<'a> Iterator for RangeIter<'a> {
    type Item = char;
    fn next(&mut self) -> Option<char> {
        if self.range.len == 0 {
            None
        } else {
            let point = self.range.point;
            self.range.point = self.range.point + self.range.dir.point();
            self.range.len -= 1;
            self.cw.get_char(point)
        }
    }
}

pub struct RangesIter<'a> {
    point: Point,
    dir: Dir,
    ended: bool,
    cw: &'a Crosswords,
    words: bool,
}

impl<'a> RangesIter<'a> {
    fn new_free(cw: &'a Crosswords) -> Self {
        RangesIter {
            point: Point::new(0, 0),
            dir: Dir::Right,
            ended: false,
            cw: cw,
            words: false,
        }
    }

    fn advance(&mut self, len: usize) {
        if self.ended { return; }
        match self.dir {
            Dir::Right => {
                self.point.x += len as i32;
                if self.point.x >= self.cw.width as i32 {
                    self.point.y += 1;
                    self.point.x = 0;
                    if self.point.y >= self.cw.height as i32 {
                        self.point.y = 0;
                        self.dir = Dir::Down;
                    }
                }
            },
            Dir::Down => {
                self.point.y += len as i32;
                if self.point.y >= self.cw.height as i32 {
                    self.point.x += 1;
                    self.point.y = 0;
                    if self.point.x >= self.cw.width as i32 {
                        self.ended = true;
                    }
                }
            }
        }
    }
}

impl<'a> Iterator for RangesIter<'a> {
    type Item = Range;
    fn next(&mut self) -> Option<Range> {
        while !self.ended {
            let len = match self.words {
                true => self.cw.get_word_len_at(self.point, self.dir),
                false => self.cw.get_free_range_at(self.point, self.dir),
            };
            if len > 1 {
                let (point, dir) = (self.point, self.dir);
                self.advance(len); // TODO: If self.words, advance len + 2?
                return Some(Range { point: point, dir: dir, len: len });
            }
            self.advance(1);
        }
        None
    }
}

#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub enum Dir {
    Right,
    Down,
}

impl Dir {
    pub fn other(&self) -> Dir {
        match *self {
            Dir::Right => Dir::Down,
            Dir::Down => Dir::Right,
        }
    }

    pub fn point(&self) -> Point {
        match *self {
            Dir::Right => Point::new(1, 0),
            Dir::Down => Point::new(0, 1),
        }
    }
}

pub struct Crosswords {
    width: usize,
    height: usize,
    chars: Vec<char>,
    right_border: Vec<bool>,
    down_border: Vec<bool>,
    words: HashSet<Vec<char>>,
}

impl Crosswords {
    pub fn new(width: usize, height: usize) -> Crosswords {
        Crosswords {
            width: width,
            height: height,
            chars: iter::repeat(BLOCK).take(width * height).collect(),
            right_border: iter::repeat(true).take((width - 1) * height).collect(),
            down_border: iter::repeat(true).take(width * (height - 1)).collect(),
            words: HashSet::new(),
        }
    }

    pub fn get_width(&self) -> usize { self.width }
    pub fn get_height(&self) -> usize { self.height }

    #[inline]
    pub fn get_border(&self, point: Point, dir: Dir) -> bool {
        match dir {
            Dir::Right => match point.coord(self.width - 1, self.height) {
                None => true,
                Some(p) => self.right_border[p],
            },
            Dir::Down => match point.coord(self.width, self.height - 1) {
                None => true,
                Some(p) => self.down_border[p],
            }
        }
    }

    #[inline]
    fn set_border(&mut self, point: Point, dir: Dir, value: bool) -> bool {
        match dir {
            Dir::Right => match point.coord(self.width - 1, self.height) {
                None => if value { true } else { unreachable!() },
                Some(p) => {
                    let existing = self.right_border[p];
                    self.right_border[p] = value;
                    existing
                },
            },
            Dir::Down => match point.coord(self.width, self.height - 1) {
                None => if value { true} else { unreachable!() },
                Some(p) => {
                    let existing = self.down_border[p];
                    self.down_border[p] = value;
                    existing
                }
            }
        }
    }

    #[inline]
    fn is_char_allowed(&self, point: Point, c: char) -> bool {
        match point.coord(self.width, self.height) {
            None => false,
            Some(p) => {
                let existing = self.chars[p];
                c == existing || existing == BLOCK
            }
        }
    }

    pub fn get_char(&self, point: Point) -> Option<char> {
        point.coord(self.width, self.height).map(|p| self.chars[p])
    }

    pub fn chars<'a>(&'a self, range: Range) -> RangeIter<'a> {
        RangeIter {
            range: range,
            cw: &self,
        }
    }

    #[inline]
    fn put_char(&mut self, point: Point, c: char) -> char {
        let p = point.coord(self.width, self.height).unwrap();
        let existing = self.chars[p];
        self.chars[p] = c;
        existing
    }

    pub fn is_word_allowed(&self, point: Point, dir: Dir, word: &Vec<char>) -> bool {
        let dp = dir.point();
        let len = word.len() as i32;
        !self.words.contains(word) && !word.is_empty()
            && self.get_border(point - dp, dir)
            && self.get_border(point + dp * (len - 1), dir)
            && word.iter().enumerate().all(|(i, &c)| self.is_char_allowed(point + dp * i, c))
    }

    fn push_word(&mut self, point: Point, dir: Dir, word: &Vec<char>) {
        let dp = dir.point();
        let len = word.len() as i32;
        for (i, &c) in word.iter().enumerate() {
            self.put_char(point + dp * i, c);
        }
        for i in 0..(len - 1) {
            self.set_border(point + dp * i, dir, false);
        }
        self.words.insert(word.clone());
    }

    pub fn try_word(&mut self, point: Point, dir: Dir, word: &Vec<char>) -> bool {
        if self.is_word_allowed(point, dir, word) {
            self.push_word(point, dir, word);
            true
        } else {
            false
        }
    }

    pub fn free_ranges<'a>(&'a self) -> RangesIter<'a> {
        RangesIter::new_free(&self)
    }

    pub fn get_free_range_at(&self, mut point: Point, dir: Dir) -> usize {
        let dp = dir.point();
        let mut len = 0;
        if (point - dp).coord(self.width, self.height).is_none()
                || (self.get_border(point - dp, dir) && !self.get_border(point - dp * 2, dir)) {
            while point.coord(self.width, self.height).is_some() && self.get_border(point, dir) {
                len += 1;
                point = point + dp;
            }
        }
        len
    }

    pub fn get_word_len_at(&self, mut point: Point, dir: Dir) -> usize {
        let dp = dir.point();
        if self.get_border(point - dp, dir) {
            let mut len = 1;
            while !self.get_border(point, dir) {
                len += 1;
                point = point + dp;
            }
            len
        } else { 0 }
    }

    pub fn pop_word(&mut self, mut point: Point, dir: Dir) -> Option<Vec<char>> {
        let dp = dir.point();
        if self.get_border(point, dir) || !self.get_border(point - dp, dir) {
            return None;
        }
        let odir = dir.other();
        let odp = odir.point();
        let mut word = Vec::new();
        while let Some(p) = point.coord(self.width, self.height) {
            if self.get_border(point, odir) && self.get_border(point - odp, odir) {
                word.push(self.put_char(point, BLOCK));
            } else {
                word.push(self.chars[p]);
            }
            if self.set_border(point, dir, true) { break; }
            point = point + dp;
        }
        self.words.remove(&word);
        Some(word)
    }

    fn count_borders(&self) -> usize {
        let mut count = 0;
        for p in 0..((self.width - 1) * self.height) {
            if self.right_border[p] { count += 1; }
        }
        for p in 0..(self.width * (self.height - 1)) {
            if self.down_border[p] { count += 1; }
        }
        count
    }
}

impl Debug for Crosswords {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> {
        for _ in 0..self.width {
            try!(formatter.write_str(" \u{2014}"));
        }
        try!(formatter.write_str(" \n"));
        for y in 0..self.height {
            try!(formatter.write_str("|"));
            for x in 0..self.width {
                let point = Point::new(x as i32, y as i32);
                try!((&self.chars[point.coord(self.width, self.height).unwrap()] as &fmt::Display)
                     .fmt(formatter));
                try!(formatter.write_str(
                        if self.get_border(point, Dir::Right) { "|" } else { " " }));
            }
            try!(formatter.write_str("\n"));
            for x in 0..self.width {
                let point = Point::new(x as i32, y as i32);
                try!(formatter.write_str(
                        if self.get_border(point, Dir::Down) { " \u{2014}" } else { "  " }));
            }
            try!(formatter.write_str(" \n"));
        }
        let bcount = self.count_borders();
        let btotal = 2 * self.width * self.height - self.width - self.height;
        let bpercent = 100.0 * (bcount as f32) / (btotal as f32);
        try!(formatter.write_fmt(format_args!("{} / {} borders ({}%)", bcount, btotal, bpercent)));
        Ok(())
    }
}
<commit_msg>Implement Crosswords iterators.<commit_after>use point::Point;
use std::collections::HashSet;
use std::iter;
use std::fmt;
use std::fmt::{Debug, Formatter};

pub static BLOCK: char = '\u{2588}';

#[derive(Clone, Copy)]
pub struct Range {
    pub point: Point,
    pub dir: Dir,
    pub len: usize,
}

pub struct RangeIter<'a> {
    range: Range,
    cw: &'a Crosswords,
}

impl<'a> Iterator for RangeIter<'a> {
    type Item = char;
    fn next(&mut self) -> Option<char> {
        if self.range.len == 0 {
            None
        } else {
            let point = self.range.point;
            self.range.point = self.range.point + self.range.dir.point();
            self.range.len -= 1;
            self.cw.get_char(point)
        }
    }
}

pub struct RangesIter<'a> {
    point: Point,
    dir: Dir,
    ended: bool,
    cw: &'a Crosswords,
    words: bool,
}

impl<'a> RangesIter<'a> {
    fn new_free(cw: &'a Crosswords) -> Self {
        RangesIter {
            point: Point::new(0, 0),
            dir: Dir::Right,
            ended: false,
            cw: cw,
            words: false,
        }
    }

    fn advance(&mut self, len: usize) {
        if self.ended { return; }
        match self.dir {
            Dir::Right => {
                self.point.x += len as i32;
                if self.point.x >= self.cw.width as i32 {
                    self.point.y += 1;
                    self.point.x = 0;
                    if self.point.y >= self.cw.height as i32 {
                        self.point.y = 0;
                        self.dir = Dir::Down;
                    }
                }
            },
            Dir::Down => {
                self.point.y += len as i32;
                if self.point.y >= self.cw.height as i32 {
                    self.point.x += 1;
                    self.point.y = 0;
                    if self.point.x >= self.cw.width as i32 {
                        self.ended = true;
                    }
                }
            }
        }
    }
}

impl<'a> Iterator for RangesIter<'a> {
    type Item = Range;
    fn next(&mut self) -> Option<Range> {
        while !self.ended {
            let len = match self.words {
                true => self.cw.get_word_len_at(self.point, self.dir),
                false => self.cw.get_free_range_at(self.point, self.dir),
            };
            if len > 1 {
                let range = Range { point: self.point, dir: self.dir, len: len };
                self.advance(len); // TODO: If self.words, advance len + 2?
                return Some(range);
            }
            self.advance(1);
        }
        None
    }
}

#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub enum Dir {
    Right,
    Down,
}

impl Dir {
    pub fn other(&self) -> Dir {
        match *self {
            Dir::Right => Dir::Down,
            Dir::Down => Dir::Right,
        }
    }

    pub fn point(&self) -> Point {
        match *self {
            Dir::Right => Point::new(1, 0),
            Dir::Down => Point::new(0, 1),
        }
    }
}

pub struct Crosswords {
    width: usize,
    height: usize,
    chars: Vec<char>,
    right_border: Vec<bool>,
    down_border: Vec<bool>,
    words: HashSet<Vec<char>>,
}

impl Crosswords {
    pub fn new(width: usize, height: usize) -> Crosswords {
        Crosswords {
            width: width,
            height: height,
            chars: iter::repeat(BLOCK).take(width * height).collect(),
            right_border: iter::repeat(true).take((width - 1) * height).collect(),
            down_border: iter::repeat(true).take(width * (height - 1)).collect(),
            words: HashSet::new(),
        }
    }

    pub fn get_width(&self) -> usize { self.width }
    pub fn get_height(&self) -> usize { self.height }

    #[inline]
    pub fn get_border(&self, point: Point, dir: Dir) -> bool {
        match dir {
            Dir::Right => match point.coord(self.width - 1, self.height) {
                None => true,
                Some(p) => self.right_border[p],
            },
            Dir::Down => match point.coord(self.width, self.height - 1) {
                None => true,
                Some(p) => self.down_border[p],
            }
        }
    }

    #[inline]
    fn set_border(&mut self, point: Point, dir: Dir, value: bool) -> bool {
        match dir {
            Dir::Right => match point.coord(self.width - 1, self.height) {
                None => if value { true } else { unreachable!() },
                Some(p) => {
                    let existing = self.right_border[p];
                    self.right_border[p] = value;
                    existing
                },
            },
            Dir::Down => match point.coord(self.width, self.height - 1) {
                None => if value { true} else { unreachable!() },
                Some(p) => {
                    let existing = self.down_border[p];
                    self.down_border[p] = value;
                    existing
                }
            }
        }
    }

    #[inline]
    fn is_char_allowed(&self, point: Point, c: char) -> bool {
        match point.coord(self.width, self.height) {
            None => false,
            Some(p) => {
                let existing = self.chars[p];
                c == existing || existing == BLOCK
            }
        }
    }

    pub fn get_char(&self, point: Point) -> Option<char> {
        point.coord(self.width, self.height).map(|p| self.chars[p])
    }

    pub fn chars<'a>(&'a self, range: Range) -> RangeIter<'a> {
        RangeIter {
            range: range,
            cw: &self,
        }
    }

    #[inline]
    fn put_char(&mut self, point: Point, c: char) -> char {
        let p = point.coord(self.width, self.height).unwrap();
        let existing = self.chars[p];
        self.chars[p] = c;
        existing
    }

    pub fn is_word_allowed(&self, point: Point, dir: Dir, word: &Vec<char>) -> bool {
        let dp = dir.point();
        let len = word.len() as i32;
        !self.words.contains(word) && !word.is_empty()
            && self.get_border(point - dp, dir)
            && self.get_border(point + dp * (len - 1), dir)
            && word.iter().enumerate().all(|(i, &c)| self.is_char_allowed(point + dp * i, c))
    }

    fn push_word(&mut self, point: Point, dir: Dir, word: &Vec<char>) {
        let dp = dir.point();
        let len = word.len() as i32;
        for (i, &c) in word.iter().enumerate() {
            self.put_char(point + dp * i, c);
        }
        for i in 0..(len - 1) {
            self.set_border(point + dp * i, dir, false);
        }
        self.words.insert(word.clone());
    }

    pub fn try_word(&mut self, point: Point, dir: Dir, word: &Vec<char>) -> bool {
        if self.is_word_allowed(point, dir, word) {
            self.push_word(point, dir, word);
            true
        } else {
            false
        }
    }

    pub fn free_ranges<'a>(&'a self) -> RangesIter<'a> {
        RangesIter::new_free(&self)
    }

    pub fn get_free_range_at(&self, mut point: Point, dir: Dir) -> usize {
        let dp = dir.point();
        let mut len = 0;
        if (point - dp).coord(self.width, self.height).is_none()
                || (self.get_border(point - dp, dir) && !self.get_border(point - dp * 2, dir)) {
            while point.coord(self.width, self.height).is_some() && self.get_border(point, dir) {
                len += 1;
                point = point + dp;
            }
        }
        len
    }

    pub fn get_word_len_at(&self, mut point: Point, dir: Dir) -> usize {
        let dp = dir.point();
        if self.get_border(point - dp, dir) {
            let mut len = 1;
            while !self.get_border(point, dir) {
                len += 1;
                point = point + dp;
            }
            len
        } else { 0 }
    }

    pub fn pop_word(&mut self, mut point: Point, dir: Dir) -> Option<Vec<char>> {
        let dp = dir.point();
        if self.get_border(point, dir) || !self.get_border(point - dp, dir) {
            return None;
        }
        let odir = dir.other();
        let odp = odir.point();
        let mut word = Vec::new();
        while let Some(p) = point.coord(self.width, self.height) {
            if self.get_border(point, odir) && self.get_border(point - odp, odir) {
                word.push(self.put_char(point, BLOCK));
            } else {
                word.push(self.chars[p]);
            }
            if self.set_border(point, dir, true) { break; }
            point = point + dp;
        }
        self.words.remove(&word);
        Some(word)
    }

    fn count_borders(&self) -> usize {
        let mut count = 0;
        for p in 0..((self.width - 1) * self.height) {
            if self.right_border[p] { count += 1; }
        }
        for p in 0..(self.width * (self.height - 1)) {
            if self.down_border[p] { count += 1; }
        }
        count
    }
}

impl Debug for Crosswords {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> {
        for _ in 0..self.width {
            try!(formatter.write_str(" \u{2014}"));
        }
        try!(formatter.write_str(" \n"));
        for y in 0..self.height {
            try!(formatter.write_str("|"));
            for x in 0..self.width {
                let point = Point::new(x as i32, y as i32);
                try!((&self.chars[point.coord(self.width, self.height).unwrap()] as &fmt::Display)
                     .fmt(formatter));
                try!(formatter.write_str(
                        if self.get_border(point, Dir::Right) { "|" } else { " " }));
            }
            try!(formatter.write_str("\n"));
            for x in 0..self.width {
                let point = Point::new(x as i32, y as i32);
                try!(formatter.write_str(
                        if self.get_border(point, Dir::Down) { " \u{2014}" } else { "  " }));
            }
            try!(formatter.write_str(" \n"));
        }
        let bcount = self.count_borders();
        let btotal = 2 * self.width * self.height - self.width - self.height;
        let bpercent = 100.0 * (bcount as f32) / (btotal as f32);
        try!(formatter.write_fmt(format_args!("{} / {} borders ({}%)", bcount, btotal, bpercent)));
        Ok(())
    }
}
<|endoftext|>