<commit_before>use rustc_serialize::json::{Json, ToJson};

#[derive(Debug, Clone)]
pub struct SendTextRequest {
    openid: String,
    account: Option<String>,
    content: String,
}

#[derive(Debug, Clone)]
pub struct SendImageRequest {
    openid: String,
    account: Option<String>,
    media_id: String,
}

#[derive(Debug, Clone)]
pub struct SendVoiceRequest {
    openid: String,
    account: Option<String>,
    media_id: String,
}

impl SendTextRequest {
    pub fn new(openid: &str, content: &str) -> SendTextRequest {
        SendTextRequest {
            openid: openid.to_owned(),
            content: content.to_owned(),
            account: None,
        }
    }

    pub fn with_account(openid: &str, content: &str, account: &str) -> SendTextRequest {
        SendTextRequest {
            openid: openid.to_owned(),
            content: content.to_owned(),
            account: Some(account.to_owned()),
        }
    }
}

impl ToJson for SendTextRequest {
    fn to_json(&self) -> Json {
        if let Some(ref account) = self.account {
            json!({
                "msgtype": "text",
                "touser": (self.openid),
                "text": {"content": (self.content)},
                "customservice": {"kf_account": (account)},
            })
        } else {
            json!({
                "msgtype": "text",
                "touser": (self.openid),
                "text": {"content": (self.content)},
            })
        }
    }
}

make_encodable!(SendTextRequest);

impl SendImageRequest {
    pub fn new(openid: &str, media_id: &str) -> SendImageRequest {
        SendImageRequest {
            openid: openid.to_owned(),
            account: None,
            media_id: media_id.to_owned(),
        }
    }

    pub fn with_account(openid: &str, media_id: &str, account: &str) -> SendImageRequest {
        SendImageRequest {
            openid: openid.to_owned(),
            account: Some(account.to_owned()),
            media_id: media_id.to_owned(),
        }
    }
}
impl ToJson for SendImageRequest {
    fn to_json(&self) -> Json {
        if let Some(ref account) = self.account {
            json!({
                "msgtype": "image",
                "touser": (self.openid),
                "image": {"media_id": (self.media_id)},
                "customservice": {"kf_account": (account)},
            })
        } else {
            json!({
                "msgtype": "image",
                "touser": (self.openid),
                "image": {"media_id": (self.media_id)},
            })
        }
    }
}

make_encodable!(SendImageRequest);

impl SendVoiceRequest {
    pub fn new(openid: &str, media_id: &str) -> SendVoiceRequest {
        SendVoiceRequest {
            openid: openid.to_owned(),
            account: None,
            media_id: media_id.to_owned(),
        }
    }

    pub fn with_account(openid: &str, media_id: &str, account: &str) -> SendVoiceRequest {
        SendVoiceRequest {
            openid: openid.to_owned(),
            account: Some(account.to_owned()),
            media_id: media_id.to_owned(),
        }
    }
}
impl ToJson for SendVoiceRequest {
    fn to_json(&self) -> Json {
        if let Some(ref account) = self.account {
            json!({
                "msgtype": "voice",
                "touser": (self.openid),
                "voice": {"media_id": (self.media_id)},
                "customservice": {"kf_account": (account)},
            })
        } else {
            json!({
                "msgtype": "voice",
                "touser": (self.openid),
                "voice": {"media_id": (self.media_id)},
            })
        }
    }
}
make_encodable!(SendVoiceRequest);
<commit_msg>Add SendVideoRequest. [ci skip]<commit_after>use rustc_serialize::json::{Json, ToJson};

#[derive(Debug, Clone)]
pub struct SendTextRequest {
    openid: String,
    account: Option<String>,
    content: String,
}

#[derive(Debug, Clone)]
pub struct SendImageRequest {
    openid: String,
    account: Option<String>,
    media_id: String,
}

#[derive(Debug, Clone)]
pub struct SendVoiceRequest {
    openid: String,
    account: Option<String>,
    media_id: String,
}

#[derive(Debug, Clone)]
pub struct SendVideoRequest {
    openid: String,
    account: Option<String>,
    media_id: String,
    thumb_media_id: String,
    title: Option<String>,
    description: Option<String>,
}

#[derive(Debug, Clone)]
pub struct SendMusicRequest {
    openid: String,
    account: Option<String>,
    music_url: String,
    hq_music_url: String,
    thumb_media_id: String,
    title: Option<String>,
    description: Option<String>,
}

#[derive(Debug, Clone)]
pub struct Article {
    title: String,
    url: String,
    description: Option<String>,
    image: Option<String>,
}

#[derive(Debug, Clone)]
pub struct SendArticlesRequest {
    openid: String,
    account: Option<String>,
    articles: Vec<Article>,
}

impl SendTextRequest {
    pub fn new(openid: &str, content: &str) -> SendTextRequest {
        SendTextRequest {
            openid: openid.to_owned(),
            content: content.to_owned(),
            account: None,
        }
    }

    pub fn with_account(openid: &str, content: &str, account: &str) -> SendTextRequest {
        SendTextRequest {
            openid: openid.to_owned(),
            content: content.to_owned(),
            account: Some(account.to_owned()),
        }
    }
}

impl ToJson for SendTextRequest {
    fn to_json(&self) -> Json {
        if let Some(ref account) = self.account {
            json!({
                "msgtype": "text",
                "touser": (self.openid),
                "text": {"content": (self.content)},
                "customservice": {"kf_account": (account)},
            })
        } else {
            json!({
                "msgtype": "text",
                "touser": (self.openid),
                "text": {"content": (self.content)},
            })
        }
    }
}

make_encodable!(SendTextRequest);

impl SendImageRequest {
    pub fn new(openid: &str, media_id: &str) -> SendImageRequest {
        SendImageRequest {
            openid: openid.to_owned(),
            account: None,
            media_id: media_id.to_owned(),
        }
    }

    pub fn with_account(openid: &str, media_id: &str, account: &str) -> SendImageRequest {
        SendImageRequest {
            openid: openid.to_owned(),
            account: Some(account.to_owned()),
            media_id: media_id.to_owned(),
        }
    }
}
impl ToJson for SendImageRequest {
    fn to_json(&self) -> Json {
        if let Some(ref account) = self.account {
            json!({
                "msgtype": "image",
                "touser": (self.openid),
                "image": {"media_id": (self.media_id)},
                "customservice": {"kf_account": (account)},
            })
        } else {
            json!({
                "msgtype": "image",
                "touser": (self.openid),
                "image": {"media_id": (self.media_id)},
            })
        }
    }
}

make_encodable!(SendImageRequest);

impl SendVoiceRequest {
    pub fn new(openid: &str, media_id: &str) -> SendVoiceRequest {
        SendVoiceRequest {
            openid: openid.to_owned(),
            account: None,
            media_id: media_id.to_owned(),
        }
    }

    pub fn with_account(openid: &str, media_id: &str, account: &str) -> SendVoiceRequest {
        SendVoiceRequest {
            openid: openid.to_owned(),
            account: Some(account.to_owned()),
            media_id: media_id.to_owned(),
        }
    }
}

impl ToJson for SendVoiceRequest {
    fn to_json(&self) -> Json {
        if let Some(ref account) = self.account {
            json!({
                "msgtype": "voice",
                "touser": (self.openid),
                "voice": {"media_id": (self.media_id)},
                "customservice": {"kf_account": (account)},
            })
        } else {
            json!({
                "msgtype": "voice",
                "touser": (self.openid),
                "voice": {"media_id": (self.media_id)},
            })
        }
    }
}

make_encodable!(SendVoiceRequest);

impl SendVideoRequest {
    pub fn new(openid: &str, media_id: &str, thumb_media_id: &str, title: Option<String>, description: Option<String>) -> SendVideoRequest {
        SendVideoRequest {
            openid: openid.to_owned(),
            account: None,
            media_id: media_id.to_owned(),
            thumb_media_id: thumb_media_id.to_owned(),
            title: title,
            description: description,
        }
    }

    pub fn with_account(openid: &str, account: &str, media_id: &str, thumb_media_id: &str, title: Option<String>, description: Option<String>) -> SendVideoRequest {
        SendVideoRequest {
            openid: openid.to_owned(),
            account: Some(account.to_owned()),
            media_id: media_id.to_owned(),
            thumb_media_id: thumb_media_id.to_owned(),
            title: title,
            description: description,
        }
    }
}

impl ToJson for SendVideoRequest {
    fn to_json(&self) -> Json {
        if let Some(ref account) = self.account {
            json!({
                "msgtype": "video",
                "touser": (self.openid),
                "video": {
                    "media_id": (self.media_id),
                    "thumb_media_id": (self.thumb_media_id),
                    "title": (self.title),
                    "description": (self.description),
                },
                "customservice": {"kf_account": (account)},
            })
        } else {
            json!({
                "msgtype": "video",
                "touser": (self.openid),
                "video": {
                    "media_id": (self.media_id),
                    "thumb_media_id": (self.thumb_media_id),
                    "title": (self.title),
                    "description": (self.description),
                },
            })
        }
    }
}

make_encodable!(SendVideoRequest);
<|endoftext|>


<commit_before>use super::collect_versions;
use crate::{config::Config, env::Env, file_saver::save_to_file, nameutil, version::Version};
use log::info;
use std::{collections::HashMap, fs::File, io::prelude::*};
use toml::{self, value::Table, Value};

pub fn generate(env: &Env) -> String {
    info!("Generating sys Cargo.toml for {}", env.config.library_name);

    let path = env.config.target_path.join("Cargo.toml");

    let mut toml_str = String::new();
    if let Ok(mut file) = File::open(&path) {
        file.read_to_string(&mut toml_str).unwrap();
    }
    let empty = toml_str.trim().is_empty();
    let mut root_table = toml::from_str(&toml_str).unwrap_or_else(|_| Table::new());
    let crate_name = get_crate_name(&env.config, &root_table);

    if empty {
        fill_empty(&mut root_table, env, &crate_name);
    }
    fill_in(&mut root_table, env);

    save_to_file(&path, env.config.make_backup, |w| {
        w.write_all(toml::to_string(&root_table).unwrap().as_bytes())
    });

    crate_name
}

fn fill_empty(root: &mut Table, env: &Env, crate_name: &str) {
    let package_name = nameutil::exported_crate_name(crate_name);

    {
        let package = upsert_table(root, "package");
        set_string(package, "name", package_name);
        set_string(package, "version", "0.0.1");
        set_string(
            package,
            "links",
            nameutil::shared_libs_to_links(&env.namespaces.main().shared_libs),
        );
    }

    {
        let lib = upsert_table(root, "lib");
        set_string(lib, "name", crate_name);
    }

    let deps = upsert_table(root, "dependencies");
    for ext_lib in &env.config.external_libraries {
        let ext_package = if ext_lib.crate_name == "cairo" {
            format!("{}-sys-rs", ext_lib.crate_name)
        } else if ext_lib.crate_name == "gdk_pixbuf" {
            "gdk-pixbuf-sys".into()
        } else {
            format!("{}-sys", ext_lib.crate_name)
        };
        let dep = upsert_table(deps, &*ext_package);
        if ext_lib.crate_name == "cairo" {
            set_string(dep, "git", "https://github.com/gtk-rs/cairo");
        } else if ext_package.starts_with("sourceview") {
            set_string(dep, "git", "https://github.com/gtk-rs/sourceview");
        } else {
            set_string(dep, "git", "https://github.com/gtk-rs/sys");
        }
    }
}

fn fill_in(root: &mut Table, env: &Env) {
    {
        let package = upsert_table(root, "package");
        set_string(package, "build", "build.rs");
        //set_string(package, "version", "0.2.0");
    }

    {
        let deps = upsert_table(root, "dependencies");
        set_string(deps, "libc", "0.2");
    }

    {
        let build_deps = upsert_table(root, "build-dependencies");
        set_string(build_deps, "system-deps", "1.3");
    }

    {
        let dev_deps = upsert_table(root, "dev-dependencies");
        set_string(dev_deps, "shell-words", "1.0.0");
        set_string(dev_deps, "tempfile", "3");
        unset(dev_deps, "tempdir");
    }

    {
        let features = upsert_table(root, "features");
        let versions = collect_versions(env);
        versions.keys().fold(None::<Version>, |prev, &version| {
            let prev_array: Vec<Value> =
                get_feature_dependencies(version, prev, &env.config.feature_dependencies)
                    .iter()
                    .map(|s| Value::String(s.clone()))
                    .collect();
            features.insert(version.to_feature(), Value::Array(prev_array));
            Some(version)
        });
        features.insert("dox".to_string(), Value::Array(Vec::new()));
    }

    {
        let meta = upsert_table(root, "package");
        let meta = upsert_table(meta, "metadata");
        let meta = upsert_table(meta, "system-deps");

        let ns = env.namespaces.main();
        let lib_name = ns.package_name.as_ref().unwrap();

        let meta = upsert_table(meta, nameutil::lib_name_to_toml(lib_name));
        set_string(meta, "name", lib_name);
        set_string(meta, "version", env.config.min_cfg_version.to_string());

        let versions = upsert_table(meta, "feature-versions");
        collect_versions(env)
            .iter()
            .filter(|(&v, _)| v > env.config.min_cfg_version)
            .for_each(|(v, lib_version)| {
                set_string(versions, &v.to_feature(), lib_version.to_string());
            });
    }

    {
        // Small trick to prevent having double quotes around it since toml doesn't like having '.'
        let docs_rs_metadata = upsert_table(root, "package");
        let docs_rs_metadata = upsert_table(docs_rs_metadata, "metadata");
        let docs_rs_metadata = upsert_table(docs_rs_metadata, "docs");
        let docs_rs_metadata = upsert_table(docs_rs_metadata, "rs");
        let mut docs_rs_features = env.config.docs_rs_features.clone();
        docs_rs_features.push("dox".to_owned());
        docs_rs_metadata.insert(
            "features".to_string(),
            Value::Array(
                docs_rs_features
                    .into_iter()
                    .map(Value::String)
                    .collect::<Vec<_>>(),
            ),
        );
    }
}

fn get_feature_dependencies(
    version: Version,
    prev_version: Option<Version>,
    feature_dependencies: &HashMap<Version, Vec<String>>,
) -> Vec<String> {
    let mut vec = Vec::with_capacity(10);
    if let Some(v) = prev_version {
        vec.push(v.to_feature());
    }
    if let Some(dependencies) = feature_dependencies.get(&version) {
        vec.extend_from_slice(dependencies);
    }
    vec
}

/// Returns the name of crate being currently generated.
fn get_crate_name(config: &Config, root: &Table) -> String {
    if let Some(&Value::Table(ref lib)) = root.get("lib") {
        if let Some(&Value::String(ref lib_name)) = lib.get("name") {
            //Converting don't needed as library target names cannot contain hyphens
            return lib_name.to_owned();
        }
    }
    if let Some(&Value::Table(ref package)) = root.get("package") {
        if let Some(&Value::String(ref package_name)) = package.get("name") {
            return nameutil::crate_name(package_name);
        }
    }
    return format!("{}_sys", nameutil::crate_name(&config.library_name));
}

fn set_string<S: Into<String>>(table: &mut Table, name: &str, new_value: S) {
    if let Some(v) = table.get_mut(name) {
        *v = Value::String(new_value.into());
        return;
    }
    table.insert(name.into(), Value::String(new_value.into()));
}

fn unset(table: &mut Table, name: &str) {
    table.remove(name);
}

fn upsert_table<S: Into<String>>(parent: &mut Table, name: S) -> &mut Table {
    if let Value::Table(ref mut table) = *parent
        .entry(name.into())
        .or_insert_with(|| Value::Table(toml::map::Map::new()))
    {
        table
    } else {
        unreachable!()
    }
}
<commit_msg>toml: use new system-deps versions syntax<commit_after>use super::collect_versions;
use crate::{config::Config, env::Env, file_saver::save_to_file, nameutil, version::Version};
use log::info;
use std::{collections::HashMap, fs::File, io::prelude::*};
use toml::{self, value::Table, Value};

pub fn generate(env: &Env) -> String {
    info!("Generating sys Cargo.toml for {}", env.config.library_name);

    let path = env.config.target_path.join("Cargo.toml");

    let mut toml_str = String::new();
    if let Ok(mut file) = File::open(&path) {
        file.read_to_string(&mut toml_str).unwrap();
    }
    let empty = toml_str.trim().is_empty();
    let mut root_table = toml::from_str(&toml_str).unwrap_or_else(|_| Table::new());
    let crate_name = get_crate_name(&env.config, &root_table);

    if empty {
        fill_empty(&mut root_table, env, &crate_name);
    }
    fill_in(&mut root_table, env);

    save_to_file(&path, env.config.make_backup, |w| {
        w.write_all(toml::to_string(&root_table).unwrap().as_bytes())
    });

    crate_name
}

fn fill_empty(root: &mut Table, env: &Env, crate_name: &str) {
    let package_name = nameutil::exported_crate_name(crate_name);

    {
        let package = upsert_table(root, "package");
        set_string(package, "name", package_name);
        set_string(package, "version", "0.0.1");
        set_string(
            package,
            "links",
            nameutil::shared_libs_to_links(&env.namespaces.main().shared_libs),
        );
    }

    {
        let lib = upsert_table(root, "lib");
        set_string(lib, "name", crate_name);
    }

    let deps = upsert_table(root, "dependencies");
    for ext_lib in &env.config.external_libraries {
        let ext_package = if ext_lib.crate_name == "cairo" {
            format!("{}-sys-rs", ext_lib.crate_name)
        } else if ext_lib.crate_name == "gdk_pixbuf" {
            "gdk-pixbuf-sys".into()
        } else {
            format!("{}-sys", ext_lib.crate_name)
        };
        let dep = upsert_table(deps, &*ext_package);
        if ext_lib.crate_name == "cairo" {
            set_string(dep, "git", "https://github.com/gtk-rs/cairo");
        } else if ext_package.starts_with("sourceview") {
            set_string(dep, "git", "https://github.com/gtk-rs/sourceview");
        } else {
            set_string(dep, "git", "https://github.com/gtk-rs/sys");
        }
    }
}

fn fill_in(root: &mut Table, env: &Env) {
    {
        let package = upsert_table(root, "package");
        set_string(package, "build", "build.rs");
        //set_string(package, "version", "0.2.0");
    }

    {
        let deps = upsert_table(root, "dependencies");
        set_string(deps, "libc", "0.2");
    }

    {
        let build_deps = upsert_table(root, "build-dependencies");
        set_string(build_deps, "system-deps", "2.0");
    }

    {
        let dev_deps = upsert_table(root, "dev-dependencies");
        set_string(dev_deps, "shell-words", "1.0.0");
        set_string(dev_deps, "tempfile", "3");
        unset(dev_deps, "tempdir");
    }

    {
        let features = upsert_table(root, "features");
        let versions = collect_versions(env);
        versions.keys().fold(None::<Version>, |prev, &version| {
            let prev_array: Vec<Value> =
                get_feature_dependencies(version, prev, &env.config.feature_dependencies)
                    .iter()
                    .map(|s| Value::String(s.clone()))
                    .collect();
            features.insert(version.to_feature(), Value::Array(prev_array));
            Some(version)
        });
        features.insert("dox".to_string(), Value::Array(Vec::new()));
    }

    {
        let meta = upsert_table(root, "package");
        let meta = upsert_table(meta, "metadata");
        let meta = upsert_table(meta, "system-deps");

        let ns = env.namespaces.main();
        let lib_name = ns.package_name.as_ref().unwrap();

        let meta = upsert_table(meta, nameutil::lib_name_to_toml(lib_name));
        set_string(meta, "name", lib_name);
        set_string(meta, "version", env.config.min_cfg_version.to_string());

        // Old version API
        unset(meta, "feature-versions");

        collect_versions(env)
            .iter()
            .filter(|(&v, _)| v > env.config.min_cfg_version)
            .for_each(|(v, lib_version)| {
                let version_section = upsert_table(meta, &v.to_feature());
                set_string(version_section, "version", lib_version.to_string());
            });
    }

    {
        // Small trick to prevent having double quotes around it since toml doesn't like having '.'
        let docs_rs_metadata = upsert_table(root, "package");
        let docs_rs_metadata = upsert_table(docs_rs_metadata, "metadata");
        let docs_rs_metadata = upsert_table(docs_rs_metadata, "docs");
        let docs_rs_metadata = upsert_table(docs_rs_metadata, "rs");
        let mut docs_rs_features = env.config.docs_rs_features.clone();
        docs_rs_features.push("dox".to_owned());
        docs_rs_metadata.insert(
            "features".to_string(),
            Value::Array(
                docs_rs_features
                    .into_iter()
                    .map(Value::String)
                    .collect::<Vec<_>>(),
            ),
        );
    }
}

fn get_feature_dependencies(
    version: Version,
    prev_version: Option<Version>,
    feature_dependencies: &HashMap<Version, Vec<String>>,
) -> Vec<String> {
    let mut vec = Vec::with_capacity(10);
    if let Some(v) = prev_version {
        vec.push(v.to_feature());
    }
    if let Some(dependencies) = feature_dependencies.get(&version) {
        vec.extend_from_slice(dependencies);
    }
    vec
}

/// Returns the name of crate being currently generated.
fn get_crate_name(config: &Config, root: &Table) -> String {
    if let Some(&Value::Table(ref lib)) = root.get("lib") {
        if let Some(&Value::String(ref lib_name)) = lib.get("name") {
            //Converting don't needed as library target names cannot contain hyphens
            return lib_name.to_owned();
        }
    }
    if let Some(&Value::Table(ref package)) = root.get("package") {
        if let Some(&Value::String(ref package_name)) = package.get("name") {
            return nameutil::crate_name(package_name);
        }
    }
    return format!("{}_sys", nameutil::crate_name(&config.library_name));
}

fn set_string<S: Into<String>>(table: &mut Table, name: &str, new_value: S) {
    if let Some(v) = table.get_mut(name) {
        *v = Value::String(new_value.into());
        return;
    }
    table.insert(name.into(), Value::String(new_value.into()));
}

fn unset(table: &mut Table, name: &str) {
    table.remove(name);
}

fn upsert_table<S: Into<String>>(parent: &mut Table, name: S) -> &mut Table {
    if let Value::Table(ref mut table) = *parent
        .entry(name.into())
        .or_insert_with(|| Value::Table(toml::map::Map::new()))
    {
        table
    } else {
        unreachable!()
    }
}
<|endoftext|>


<commit_before>use super::collect_versions;
use crate::{config::Config, env::Env, file_saver::save_to_file, nameutil, version::Version};
use log::info;
use std::{collections::HashMap, fs::File, io::prelude::*};
use toml::{self, value::Table, Value};

pub fn generate(env: &Env) -> String {
    info!("Generating sys Cargo.toml for {}", env.config.library_name);

    let path = env.config.target_path.join("Cargo.toml");

    let mut toml_str = String::new();
    if let Ok(mut file) = File::open(&path) {
        file.read_to_string(&mut toml_str).unwrap();
    }
    let empty = toml_str.trim().is_empty();
    let mut root_table = toml::from_str(&toml_str).unwrap_or_else(|_| Table::new());
    let crate_name = get_crate_name(&env.config, &root_table);

    if empty {
        fill_empty(&mut root_table, env, &crate_name);
    }
    fill_in(&mut root_table, env);

    save_to_file(&path, env.config.make_backup, |w| {
        w.write_all(toml::to_string(&root_table).unwrap().as_bytes())
    });

    crate_name
}

fn fill_empty(root: &mut Table, env: &Env, crate_name: &str) {
    let package_name = nameutil::exported_crate_name(crate_name);

    {
        let package = upsert_table(root, "package");
        set_string(package, "name", package_name);
        set_string(package, "version", "0.0.1");
        set_string(package, "edition", "2021");
    }

    {
        let lib = upsert_table(root, "lib");
        set_string(lib, "name", crate_name);
    }

    let deps = upsert_table(root, "dependencies");
    for ext_lib in &env.config.external_libraries {
        let dep = upsert_table(deps, &ext_lib.crate_name);
        let ext_package = if ext_lib.crate_name == "cairo" {
            format!("{}-sys-rs", ext_lib.crate_name)
        } else if ext_lib.crate_name == "gdk_pixbuf" {
            "gdk-pixbuf-sys".into()
        } else {
            format!("{}-sys", ext_lib.crate_name)
        };
        let repo_url = match ext_package.as_str() {
            // Not sure if glib-macros and gobject-sys are needed here
            "cairo-sys-rs" | "gdk-pixbuf-sys" | "gio-sys" | "gobject-sys" | "glib-macros"
            | "glib-sys" | "graphene-sys" | "pango-sys" | "pangocairo-sys" => {
                "https://github.com/gtk-rs/gtk-rs-core"
            }
            // Not sure if gtk-macros is needed here
            "atk-sys" | "gdk-sys" | "gdkwayland-sys" | "gdkx11-sys" | "gtk-sys" | "gtk-macros" => {
                "https://github.com/gtk-rs/gtk3-rs"
            }
            // Not sure if gtk4-macros is needed here
            "gdk4-wayland-sys" | "gdk4-x11-sys" | "gdk4-sys" | "gsk4-sys" | "gtk4-macros"
            | "gtk4-sys" => "https://github.com/gtk-rs/gtk4-rs",
            &_ => "Unknown dependency, please create an issue",
        };
        set_string(dep, "package", ext_package);
        set_string(dep, "git", repo_url);
    }
}

fn fill_in(root: &mut Table, env: &Env) {
    {
        let package = upsert_table(root, "package");
        set_string(package, "build", "build.rs");
        //set_string(package, "version", "0.2.0");
    }

    {
        let deps = upsert_table(root, "dependencies");
        set_string(deps, "libc", "0.2");
    }

    {
        let build_deps = upsert_table(root, "build-dependencies");
        set_string(build_deps, "system-deps", "6");
    }

    {
        let dev_deps = upsert_table(root, "dev-dependencies");
        set_string(dev_deps, "shell-words", "1.0.0");
        set_string(dev_deps, "tempfile", "3");
        unset(dev_deps, "tempdir");
    }

    {
        let features = upsert_table(root, "features");
        let versions = collect_versions(env);
        versions.keys().fold(None::<Version>, |prev, &version| {
            let prev_array: Vec<Value> =
                get_feature_dependencies(version, prev, &env.config.feature_dependencies)
                    .iter()
                    .map(|s| Value::String(s.clone()))
                    .collect();
            features.insert(version.to_feature(), Value::Array(prev_array));
            Some(version)
        });
        features.insert(
            "dox".to_string(),
            Value::Array(
                env.config
                    .dox_feature_dependencies
                    .iter()
                    .map(|s| Value::String(s.clone()))
                    .collect(),
            ),
        );
    }

    {
        let meta = upsert_table(root, "package");
        let meta = upsert_table(meta, "metadata");
        let meta = upsert_table(meta, "system-deps");

        let ns = env.namespaces.main();
        let lib_name = ns.package_name.as_ref().unwrap();

        let meta = upsert_table(meta, nameutil::lib_name_to_toml(lib_name));
        // Allow both the name and version of a system dep to be overridden by hand
        meta.entry("name")
            .or_insert_with(|| Value::String(lib_name.to_owned()));
        meta.entry("version")
            .or_insert_with(|| Value::String(env.config.min_cfg_version.to_string()));

        // Old version API
        unset(meta, "feature-versions");

        collect_versions(env)
            .iter()
            .filter(|(&v, _)| v > env.config.min_cfg_version)
            .for_each(|(v, lib_version)| {
                let version_section = upsert_table(meta, &v.to_feature());
                // Allow system-deps version for this feature level to be overridden by hand
                version_section
                    .entry("version")
                    .or_insert_with(|| Value::String(lib_version.to_string()));
            });
    }

    {
        // TODO: Copy this part to wrapper Cargo.toml generation code to fix builds on docs.rs
        // Small trick to prevent having double quotes around it since toml doesn't like having '.'
        let docs_rs_metadata = upsert_table(root, "package");
        let docs_rs_metadata = upsert_table(docs_rs_metadata, "metadata");
        let docs_rs_metadata = upsert_table(docs_rs_metadata, "docs");
        let docs_rs_metadata = upsert_table(docs_rs_metadata, "rs");
        let mut docs_rs_features = env.config.docs_rs_features.clone();
        docs_rs_features.push("dox".to_owned());
        docs_rs_metadata.insert(
            "features".to_string(),
            Value::Array(
                docs_rs_features
                    .into_iter()
                    .map(Value::String)
                    .collect::<Vec<_>>(),
            ),
        );
    }
}

fn get_feature_dependencies(
    version: Version,
    prev_version: Option<Version>,
    feature_dependencies: &HashMap<Version, Vec<String>>,
) -> Vec<String> {
    let mut vec = Vec::with_capacity(10);
    if let Some(v) = prev_version {
        vec.push(v.to_feature());
    }
    if let Some(dependencies) = feature_dependencies.get(&version) {
        vec.extend_from_slice(dependencies);
    }
    vec
}

/// Returns the name of crate being currently generated.
fn get_crate_name(config: &Config, root: &Table) -> String {
    if let Some(Value::Table(lib)) = root.get("lib") {
        if let Some(Value::String(lib_name)) = lib.get("name") {
            //Converting don't needed as library target names cannot contain hyphens
            return lib_name.to_owned();
        }
    }
    if let Some(Value::Table(package)) = root.get("package") {
        if let Some(Value::String(package_name)) = package.get("name") {
            return nameutil::crate_name(package_name);
        }
    }
    return format!("{}_sys", nameutil::crate_name(&config.library_name));
}

fn set_string<S: Into<String>>(table: &mut Table, name: &str, new_value: S) {
    table.insert(name.into(), Value::String(new_value.into()));
}

fn unset(table: &mut Table, name: &str) {
    table.remove(name);
}

fn upsert_table<S: Into<String>>(parent: &mut Table, name: S) -> &mut Table {
    if let Value::Table(table) = parent
        .entry(name.into())
        .or_insert_with(|| Value::Table(toml::map::Map::new()))
    {
        table
    } else {
        unreachable!()
    }
}
<commit_msg>Remove comment<commit_after>use super::collect_versions;
use crate::{config::Config, env::Env, file_saver::save_to_file, nameutil, version::Version};
use log::info;
use std::{collections::HashMap, fs::File, io::prelude::*};
use toml::{self, value::Table, Value};

pub fn generate(env: &Env) -> String {
    info!("Generating sys Cargo.toml for {}", env.config.library_name);

    let path = env.config.target_path.join("Cargo.toml");

    let mut toml_str = String::new();
    if let Ok(mut file) = File::open(&path) {
        file.read_to_string(&mut toml_str).unwrap();
    }
    let empty = toml_str.trim().is_empty();
    let mut root_table = toml::from_str(&toml_str).unwrap_or_else(|_| Table::new());
    let crate_name = get_crate_name(&env.config, &root_table);

    if empty {
        fill_empty(&mut root_table, env, &crate_name);
    }
    fill_in(&mut root_table, env);

    save_to_file(&path, env.config.make_backup, |w| {
        w.write_all(toml::to_string(&root_table).unwrap().as_bytes())
    });

    crate_name
}

fn fill_empty(root: &mut Table, env: &Env, crate_name: &str) {
    let package_name = nameutil::exported_crate_name(crate_name);

    {
        let package = upsert_table(root, "package");
        set_string(package, "name", package_name);
        set_string(package, "version", "0.0.1");
        set_string(package, "edition", "2021");
    }

    {
        let lib = upsert_table(root, "lib");
        set_string(lib, "name", crate_name);
    }

    let deps = upsert_table(root, "dependencies");
    for ext_lib in &env.config.external_libraries {
        let dep = upsert_table(deps, &ext_lib.crate_name);
        let ext_package = if ext_lib.crate_name == "cairo" {
            format!("{}-sys-rs", ext_lib.crate_name)
        } else if ext_lib.crate_name == "gdk_pixbuf" {
            "gdk-pixbuf-sys".into()
        } else {
            format!("{}-sys", ext_lib.crate_name)
        };
        let repo_url = match ext_package.as_str() {
            // Not sure if glib-macros and gobject-sys are needed here
            "cairo-sys-rs" | "gdk-pixbuf-sys" | "gio-sys" | "gobject-sys" | "glib-macros"
            | "glib-sys" | "graphene-sys" | "pango-sys" | "pangocairo-sys" => {
                "https://github.com/gtk-rs/gtk-rs-core"
            }
            // Not sure if gtk-macros is needed here
            "atk-sys" | "gdk-sys" | "gdkwayland-sys" | "gdkx11-sys" | "gtk-sys" | "gtk-macros" => {
                "https://github.com/gtk-rs/gtk3-rs"
            }
            // Not sure if gtk4-macros is needed here
            "gdk4-wayland-sys" | "gdk4-x11-sys" | "gdk4-sys" | "gsk4-sys" | "gtk4-macros"
            | "gtk4-sys" => "https://github.com/gtk-rs/gtk4-rs",
            &_ => "Unknown dependency, please create an issue",
        };
        set_string(dep, "package", ext_package);
        set_string(dep, "git", repo_url);
    }
}

fn fill_in(root: &mut Table, env: &Env) {
    {
        let package = upsert_table(root, "package");
        set_string(package, "build", "build.rs");
        //set_string(package, "version", "0.2.0");
    }

    {
        let deps = upsert_table(root, "dependencies");
        set_string(deps, "libc", "0.2");
    }

    {
        let build_deps = upsert_table(root, "build-dependencies");
        set_string(build_deps, "system-deps", "6");
    }

    {
        let dev_deps = upsert_table(root, "dev-dependencies");
        set_string(dev_deps, "shell-words", "1.0.0");
        set_string(dev_deps, "tempfile", "3");
        unset(dev_deps, "tempdir");
    }

    {
        let features = upsert_table(root, "features");
        let versions = collect_versions(env);
        versions.keys().fold(None::<Version>, |prev, &version| {
            let prev_array: Vec<Value> =
                get_feature_dependencies(version, prev, &env.config.feature_dependencies)
                    .iter()
                    .map(|s| Value::String(s.clone()))
                    .collect();
            features.insert(version.to_feature(), Value::Array(prev_array));
            Some(version)
        });
        features.insert(
            "dox".to_string(),
            Value::Array(
                env.config
                    .dox_feature_dependencies
                    .iter()
                    .map(|s| Value::String(s.clone()))
                    .collect(),
            ),
        );
    }

    {
        let meta = upsert_table(root, "package");
        let meta = upsert_table(meta, "metadata");
        let meta = upsert_table(meta, "system-deps");

        let ns = env.namespaces.main();
        let lib_name = ns.package_name.as_ref().unwrap();

        let meta = upsert_table(meta, nameutil::lib_name_to_toml(lib_name));
        // Allow both the name and version of a system dep to be overridden by hand
        meta.entry("name")
            .or_insert_with(|| Value::String(lib_name.to_owned()));
        meta.entry("version")
            .or_insert_with(|| Value::String(env.config.min_cfg_version.to_string()));

        // Old version API
        unset(meta, "feature-versions");

        collect_versions(env)
            .iter()
            .filter(|(&v, _)| v > env.config.min_cfg_version)
            .for_each(|(v, lib_version)| {
                let version_section = upsert_table(meta, &v.to_feature());
                // Allow system-deps version for this feature level to be overridden by hand
                version_section
                    .entry("version")
                    .or_insert_with(|| Value::String(lib_version.to_string()));
            });
    }

    {
        // Small trick to prevent having double quotes around it since toml doesn't like having '.'
        let docs_rs_metadata = upsert_table(root, "package");
        let docs_rs_metadata = upsert_table(docs_rs_metadata, "metadata");
        let docs_rs_metadata = upsert_table(docs_rs_metadata, "docs");
        let docs_rs_metadata = upsert_table(docs_rs_metadata, "rs");
        let mut docs_rs_features = env.config.docs_rs_features.clone();
        docs_rs_features.push("dox".to_owned());
        docs_rs_metadata.insert(
            "features".to_string(),
            Value::Array(
                docs_rs_features
                    .into_iter()
                    .map(Value::String)
                    .collect::<Vec<_>>(),
            ),
        );
    }
}

fn get_feature_dependencies(
    version: Version,
    prev_version: Option<Version>,
    feature_dependencies: &HashMap<Version, Vec<String>>,
) -> Vec<String> {
    let mut vec = Vec::with_capacity(10);
    if let Some(v) = prev_version {
        vec.push(v.to_feature());
    }
    if let Some(dependencies) = feature_dependencies.get(&version) {
        vec.extend_from_slice(dependencies);
    }
    vec
}

/// Returns the name of crate being currently generated.
fn get_crate_name(config: &Config, root: &Table) -> String {
    if let Some(Value::Table(lib)) = root.get("lib") {
        if let Some(Value::String(lib_name)) = lib.get("name") {
            //Converting don't needed as library target names cannot contain hyphens
            return lib_name.to_owned();
        }
    }
    if let Some(Value::Table(package)) = root.get("package") {
        if let Some(Value::String(package_name)) = package.get("name") {
            return nameutil::crate_name(package_name);
        }
    }
    return format!("{}_sys", nameutil::crate_name(&config.library_name));
}

fn set_string<S: Into<String>>(table: &mut Table, name: &str, new_value: S) {
    table.insert(name.into(), Value::String(new_value.into()));
}

fn unset(table: &mut Table, name: &str) {
    table.remove(name);
}

fn upsert_table<S: Into<String>>(parent: &mut Table, name: S) -> &mut Table {
    if let Value::Table(table) = parent
        .entry(name.into())
        .or_insert_with(|| Value::Table(toml::map::Map::new()))
    {
        table
    } else {
        unreachable!()
    }
}
<|endoftext|>


<commit_before>extern crate onmf;
use onmf::helpers::{ToImage, Normalize};
use onmf::testimage_generator;
use onmf::testimage_generator::{magnify};

extern crate nalgebra;
use self::nalgebra::{DMat};

extern crate rand;
use rand::{StdRng, SeedableRng};

extern crate num;
use num::{Float};

fn main() {
    let mag_factor = 10;

    let seed: &[_] = &[1, 2, 3, 4];
    let mut rng: StdRng = SeedableRng::from_seed(seed);

    let steps = 6;
    let per_step = 1000;
    let nsamples = steps * per_step;
    let nobserved = 10 * 10;
    let nhidden = 20 + steps * 2;

    let mut data = DMat::<f64>::new_zeros(nsamples, nobserved);

    // write one testimage into each row of data
    for (step, i, factor) in testimage_generator::testimages::<f64, _>(per_step, &mut rng) {
        let row = step * i;
        for (col, val) in factor.as_vec().iter().enumerate() {
            data[(row, col)] = val.clone();
        }
    }

    let mut nmf = onmf::OrthogonalNMF::<f64>::init_randomly(
        nhidden, nobserved, nsamples);

    let mut iteration: i32 = 0;
    loop {
        // alpha gets larger and larger with each iteration
        // 0.1, 0.101, 0.102, 0.103, ...
        // at iteration 232 alpha first goes above 1.0
        // iteration = 232 -> alpha = 1.005
        // let alpha = 0.1 * 1.01.powi(iteration);
        // TODO this could converge faster
        // let alpha = 0.1 * 1.001.powi(iteration);

        let alpha = 0.1;

        // TODO maybe try an even smaller alpha
        let alpha = 0.01;

        println!("iteration = {} alpha = {}", iteration, alpha);

        nmf.iterate(alpha, &data);

        // read testimage out of each row of nmf.hidden
        for irow in 0..nhidden {
            let mut column = Vec::<f64>::new();
            for icol in 0..nobserved {
                column.push(nmf.hidden[(irow, icol)]);
            }
            let image = DMat::<f64>::from_col_vec(10, 10, &column[..]);
            // println!("image {}", irow);
            // println!("{:?}", image);
            magnify(image.normalize(), mag_factor).save_to_png(&format!("orthogonal-nmf-hidden-{}.png", irow)[..]).unwrap();
        }

        iteration += 1;
    }
}
<commit_msg>ortho nmf: back to std alpha. using a few more latent vars<commit_after>extern crate onmf;
use onmf::helpers::{ToImage, Normalize};
use onmf::testimage_generator;
use onmf::testimage_generator::{magnify};

extern crate nalgebra;
use self::nalgebra::{DMat};

extern crate rand;
use rand::{StdRng, SeedableRng};

extern crate num;
use num::{Float};

fn main() {
    let mag_factor = 10;

    let seed: &[_] = &[1, 2, 3, 4];
    let mut rng: StdRng = SeedableRng::from_seed(seed);

    let steps = 6;
    let per_step = 1000;
    let nsamples = steps * per_step;
    let nobserved = 10 * 10;
    // let nhidden = 20 + steps * 2;
    let nhidden = 40;

    let mut data = DMat::<f64>::new_zeros(nsamples, nobserved);

    // write one testimage into each row of data
    for (step, i, factor) in testimage_generator::testimages::<f64, _>(per_step, &mut rng) {
        let row = step * i;
        for (col, val) in factor.as_vec().iter().enumerate() {
            data[(row, col)] = val.clone();
        }
    }

    let mut nmf = onmf::OrthogonalNMF::<f64>::init_randomly(
        nhidden, nobserved, nsamples);

    let mut iteration: i32 = 0;
    loop {
        // alpha gets larger and larger with each iteration
        // 0.1, 0.101, 0.102, 0.103, ...
        // at iteration 232 alpha first goes above 1.0
        // iteration = 232 -> alpha = 1.005
        let alpha = 0.1 * 1.01.powi(iteration);
        // TODO this could converge faster
        // let alpha = 0.1 * 1.001.powi(iteration);

        // let alpha = 0.1;

        // TODO maybe try an even smaller alpha
        // let alpha = 0.01;

        println!("iteration = {} alpha = {}", iteration, alpha);

        nmf.iterate(alpha, &data);

        // read testimage out of each row of nmf.hidden
        for irow in 0..nhidden {
            let mut column = Vec::<f64>::new();
            for icol in 0..nobserved {
                column.push(nmf.hidden[(irow, icol)]);
            }
            let image = DMat::<f64>::from_col_vec(10, 10, &column[..]);
            // println!("image {}", irow);
            // println!("{:?}", image);
            magnify(image.normalize(), mag_factor).save_to_png(&format!("orthogonal-nmf-hidden-{}.png", irow)[..]).unwrap();
        }

        iteration += 1;
    }
}
<|endoftext|>


<commit_before>use rust_install::*;
use config::Cfg;

use std::process::Command;
use std::path::{Path, PathBuf};
use std::ffi::OsStr;
use std::borrow::Cow;

use regex::Regex;
use hyper;

pub struct Toolchain<'a> {
	cfg: &'a Cfg,
	name: String,
	prefix: InstallPrefix,
}

impl<'a> Toolchain<'a> {
	pub fn from(cfg: &'a Cfg, name: &str) -> Self {
		Toolchain {
			cfg: cfg,
			name: name.to_owned(),
			prefix: InstallPrefix::from(cfg.toolchains_dir.join(name), InstallType::Owned),
		}
	}
	pub fn cfg(&self) -> &'a Cfg {
		self.cfg
	}
	pub fn name(&self) -> &str {
		&self.name
	}
	pub fn prefix(&self) -> &InstallPrefix {
		&self.prefix
	}
	pub fn exists(&self) -> bool {
		utils::is_directory(self.prefix.path())
	}
	pub fn verify(&self) -> Result<()> {
		utils::assert_is_directory(self.prefix.path())
	}
	pub fn remove(&self) -> Result<()> {
		self.prefix.uninstall(&self.cfg.notify_handler)
	}
	pub fn remove_if_exists(&self) -> Result<()> {
		if self.exists() {
			self.remove()
		} else {
			Ok(())
		}
	}
	pub fn install(&self, install_method: InstallMethod) -> Result<()> {
		self.prefix.install(install_method, &self.cfg.notify_handler)
	}
	pub fn install_if_not_installed(&self, install_method: InstallMethod) -> Result<()> {
		if !self.exists() {
			self.install(install_method)
		} else {
			Ok(())
		}
	}
	pub fn update_hash(&self) -> Option<PathBuf> {
		if self.is_custom() {
			None
		} else {
			Some(self.cfg.update_hash_dir.join(&self.name))
		}
	}

	fn download_cfg(&self) -> dist::DownloadCfg {
		dist::DownloadCfg {
			dist_root: &self.cfg.dist_root_url,
			temp_cfg: &self.cfg.temp_cfg,
			notify_handler: &self.cfg.notify_handler,
		}
	}

	pub fn install_from_dist(&self) -> Result<()> {
		let update_hash = self.update_hash();
		self.install(InstallMethod::Dist(&self.name, update_hash.as_ref().map(|p| &**p), self.download_cfg()))
	}
	pub fn install_from_dist_if_not_installed(&self) -> Result<()> {
		let update_hash = self.update_hash();
		self.install_if_not_installed(InstallMethod::Dist(&self.name, update_hash.as_ref().map(|p| &**p), self.download_cfg()))
	}
	pub fn is_custom(&self) -> bool {
		dist::ToolchainDesc::from_str(&self.name).is_none()
	}

	pub fn ensure_custom(&self) -> Result<()> {
		if !self.is_custom() {
			Err(Error::InvalidToolchainName)
		} else {
			Ok(())
		}
	}

	pub fn install_from_installers(&self, installers: &[&OsStr]) -> Result<()> {
		try!(self.ensure_custom());

		try!(self.remove_if_exists());

		let work_dir = try!(self.cfg.temp_cfg.new_directory());

		for installer in installers {
			let local_installer;
			let installer_str = installer.to_str();
			if let Some(Ok(url)) = installer_str.map(hyper::Url::parse) {
				// If installer is a URL

				// Extract basename from url (eg. 'rust-1.3.0-x86_64-unknown-linux-gnu.tar.gz')
				let re = Regex::new(r"[\\/]([^\\/?]+)(\?.*)?$").unwrap();
				let basename = try!(re.captures(installer_str.unwrap())
					.ok_or(Error::InvalidInstallerUrl)).at(1).unwrap();

				// Download to a local file
				local_installer = Cow::Owned(work_dir.join(basename));
				try!(utils::download_file(url, &local_installer, &self.cfg.notify_handler));
			} else {
				// If installer is a filename

				// No need to download
				local_installer = Cow::Borrowed(Path::new(installer));
			}

			// Install from file
			try!(self.install(InstallMethod::Installer(&local_installer, &self.cfg.temp_cfg)));
		}

		Ok(())
	}

	pub fn install_from_dir(&self, src: &Path, link: bool) -> Result<()> {
		if link {
			self.install(InstallMethod::Link(src))
		} else {
			self.install(InstallMethod::Copy(src))
		}
	}

	pub fn with_env<T, F: FnOnce() -> Result<T>>(&self, f: F) -> Result<T> {
		self.prefix.with_env(|| {
			env_var::with("MULTIRUST_TOOLCHAIN", self.prefix.path().as_ref(), || {
				env_var::with("MULTIRUST_HOME", self.cfg.multirust_dir.as_ref(), || {
					f()
				})
			})
		})
	}

	pub fn create_command(&self, binary: &str) -> Result<Command> {
		let binary_path = self.prefix.binary_file(binary);

		self.with_env(|| Ok(Command::new(binary_path)))
	}

	pub fn doc_path(&self, relative: &str) -> Result<PathBuf> {
		try!(self.verify());
		self.prefix.doc_path(relative)
	}
	pub fn open_docs(&self, relative: &str) -> Result<()> {
		try!(self.verify());
		self.prefix.open_docs(relative)
	}

	pub fn make_default(&self) -> Result<()> {
		self.cfg.set_default(&self.name)
	}
	pub fn make_override(&self, path: &Path) -> Result<()> {
		self.cfg.override_db.set(path, &self.name, &self.cfg.temp_cfg, &self.cfg.notify_handler)
	}
}
<commit_msg>Add missing notifications<commit_after>use rust_install::*;
use config::Cfg;

use std::process::Command;
use std::path::{Path, PathBuf};
use std::ffi::OsStr;
use std::borrow::Cow;

use regex::Regex;
use hyper;

pub struct Toolchain<'a> {
	cfg: &'a Cfg,
	name: String,
	prefix: InstallPrefix,
}

impl<'a> Toolchain<'a> {
	pub fn from(cfg: &'a Cfg, name: &str) -> Self {
		Toolchain {
			cfg: cfg,
			name: name.to_owned(),
			prefix: InstallPrefix::from(cfg.toolchains_dir.join(name), InstallType::Owned),
		}
	}
	pub fn cfg(&self) -> &'a Cfg {
		self.cfg
	}
	pub fn name(&self) -> &str {
		&self.name
	}
	pub fn prefix(&self) -> &InstallPrefix {
		&self.prefix
	}
	pub fn exists(&self) -> bool {
		utils::is_directory(self.prefix.path())
	}
	pub fn verify(&self) -> Result<()> {
		utils::assert_is_directory(self.prefix.path())
	}
	pub fn remove(&self) -> Result<()> {
		if self.exists() {
			self.cfg.notify_handler.call(UninstallingToolchain(&self.name));
		} else {
			self.cfg.notify_handler.call(ToolchainNotInstalled(&self.name));
		}
		let result = self.prefix.uninstall(&self.cfg.notify_handler);
		if !self.exists() {
			self.cfg.notify_handler.call(UninstalledToolchain(&self.name));
		}
		result
	}
	pub fn remove_if_exists(&self) -> Result<()> {
		if self.exists() {
			self.remove()
		} else {
			Ok(())
		}
	}
	pub fn install(&self, install_method: InstallMethod) -> Result<()> {
		if self.exists() {
			self.cfg.notify_handler.call(UpdatingToolchain(&self.name));
		} else {
			self.cfg.notify_handler.call(InstallingToolchain(&self.name));
		}
		self.cfg.notify_handler.call(ToolchainDirectory(self.prefix.path(), &self.name));
		self.prefix.install(install_method, &self.cfg.notify_handler)
	}
	pub fn install_if_not_installed(&self, install_method: InstallMethod) -> Result<()> {
		self.cfg.notify_handler.call(LookingForToolchain(&self.name));
		if !self.exists() {
			self.install(install_method)
		} else {
			Ok(())
		}
	}
	pub fn update_hash(&self) -> Option<PathBuf> {
		if self.is_custom() {
			None
		} else {
			Some(self.cfg.update_hash_dir.join(&self.name))
		}
	}

	fn download_cfg(&self) -> dist::DownloadCfg {
		dist::DownloadCfg {
			dist_root: &self.cfg.dist_root_url,
			temp_cfg: &self.cfg.temp_cfg,
			notify_handler: &self.cfg.notify_handler,
		}
	}

	pub fn install_from_dist(&self) -> Result<()> {
		let update_hash = self.update_hash();
		self.install(InstallMethod::Dist(&self.name, update_hash.as_ref().map(|p| &**p), self.download_cfg()))
	}
	pub fn install_from_dist_if_not_installed(&self) -> Result<()> {
		let update_hash = self.update_hash();
		self.install_if_not_installed(InstallMethod::Dist(&self.name, update_hash.as_ref().map(|p| &**p), self.download_cfg()))
	}
	pub fn is_custom(&self) -> bool {
		dist::ToolchainDesc::from_str(&self.name).is_none()
	}

	pub fn ensure_custom(&self) -> Result<()> {
		if !self.is_custom() {
			Err(Error::InvalidToolchainName)
		} else {
			Ok(())
		}
	}

	pub fn install_from_installers(&self, installers: &[&OsStr]) -> Result<()> {
		try!(self.ensure_custom());

		try!(self.remove_if_exists());

		let work_dir = try!(self.cfg.temp_cfg.new_directory());

		for installer in installers {
			let local_installer;
			let installer_str = installer.to_str();
			if let Some(Ok(url)) = installer_str.map(hyper::Url::parse) {
				// If installer is a URL

				// Extract basename from url (eg. 'rust-1.3.0-x86_64-unknown-linux-gnu.tar.gz')
				let re = Regex::new(r"[\\/]([^\\/?]+)(\?.*)?$").unwrap();
				let basename = try!(re.captures(installer_str.unwrap())
					.ok_or(Error::InvalidInstallerUrl)).at(1).unwrap();

				// Download to a local file
				local_installer = Cow::Owned(work_dir.join(basename));
				try!(utils::download_file(url, &local_installer, &self.cfg.notify_handler));
			} else {
				// If installer is a filename

				// No need to download
				local_installer = Cow::Borrowed(Path::new(installer));
			}

			// Install from file
			try!(self.install(InstallMethod::Installer(&local_installer, &self.cfg.temp_cfg)));
		}

		Ok(())
	}

	pub fn install_from_dir(&self, src: &Path, link: bool) -> Result<()> {
		if link {
			self.install(InstallMethod::Link(src))
		} else {
			self.install(InstallMethod::Copy(src))
		}
	}

	pub fn with_env<T, F: FnOnce() -> Result<T>>(&self, f: F) -> Result<T> {
		self.prefix.with_env(|| {
			env_var::with("MULTIRUST_TOOLCHAIN", self.prefix.path().as_ref(), || {
				env_var::with("MULTIRUST_HOME", self.cfg.multirust_dir.as_ref(), || {
					f()
				})
			})
		})
	}

	pub fn create_command(&self, binary: &str) -> Result<Command> {
		let binary_path = self.prefix.binary_file(binary);

		self.with_env(|| Ok(Command::new(binary_path)))
	}

	pub fn doc_path(&self, relative: &str) -> Result<PathBuf> {
		try!(self.verify());
		self.prefix.doc_path(relative)
	}
	pub fn open_docs(&self, relative: &str) -> Result<()> {
		try!(self.verify());
		self.prefix.open_docs(relative)
	}

	pub fn make_default(&self) -> Result<()> {
		self.cfg.set_default(&self.name)
	}
	pub fn make_override(&self, path: &Path) -> Result<()> {
		self.cfg.override_db.set(path, &self.name, &self.cfg.temp_cfg, &self.cfg.notify_handler)
	}
}
<|endoftext|>


<commit_before>tests_impls!
{

  #[ test ]
  fn node()
  {
    use TheModule::prelude::*;
    let mut factory = TheFactory::< TheModule::IdentityWithInt >::make();

    let n1 = factory.node_making( 1 );
    let n1b = factory.node( 1 );
    a_id!( n1, n1b.id() );
    dbg!( &n1 );

    let node1a = factory.node( 1 );
    let node1b = factory.node( 1 );
    a_id!( node1a, node1b );

    let node1a = factory.node( &1 );
    let node1b = factory.node( &&1 );
    a_id!( node1a, node1b );

  }

  //

  #[ test ]
  fn make_default()
  {
    use TheModule::prelude::*;

    let mut factory : TheFactory::< TheModule::IdentityWithInt > = make!();
    let n1 = factory.node_making( 1 );
    let n1b = factory.node( 1 );
    a_id!( n1, n1b.id() );

  }

  //

  #[ test ]
  fn basic()
  {
    use TheModule::prelude::*;

    let mut factory = TheFactory::< TheModule::IdentityWithInt >::make();

    let a = factory.node_making( 1 );
    let b = factory.node_making( 2 );

    factory.node_add_out_node( a, b );
    factory.node_add_out_nodes( b, [ a, b ].into_iter() );

    a_id!( factory.nnodes(), 2 );
    a_id!( factory.nedges(), 3 );

    dbg!( factory.node( a ) );
    dbg!( factory.node( b ) );

    let got : HashSet< _ > = factory.out_nodes_ids( a ).collect();
    let exp = hset![ b ];
    a_id!( got, exp );
    let got : HashSet< _ > = factory.out_nodes_ids( b ).collect();
    let exp = hset![ a, b ];
    a_id!( got, exp );

    // let got : HashSet< _ > = factory.out_nodes_ids_2( a ).collect();
    // let exp = hset![ b ];
    // a_id!( got, exp );
    // let got : HashSet< _ > = factory.out_nodes_ids_2( b ).collect();
    // let exp = hset![ a, b ];
    // a_id!( got, exp );

    let got : HashSet< _ > = factory.out_edges( a ).map( | el | ( el.1.in_node, el.1.out_node ) ).collect();
    let exp = hset![ ( a, b ) ];
    a_id!( got, exp );
    let got : HashSet< _ > = factory.out_edges( b ).map( | el | ( el.1.in_node, el.1.out_node ) ).collect();
    let exp = hset![ ( b, a ), ( b, b ) ];
    a_id!( got, exp );

    // let got = factory.out_nodes_ids_2( a ).map( | id |
    // {
    //   // 13_i32
    //   ( id, factory.node( id ) )
    // });
    // use test_tools::inspect_type_of;
    // inspect_type_of!( got );

  }

  //

  #[ test ]
  fn make_with_edge_list()
  {
    use TheModule::prelude::*;

    let mut factory = TheFactory::< TheModule::IdentityWithInt >::make();

    factory.make_with_edge_list
    ([
      1, 2,
      2, 1,
      2, 2,
    ]);

    dbg!( factory.node( 1 ) );
    dbg!( factory.node( 2 ) );

    let exp = hset![ 2 ];
    let got : HashSet< _ > = factory.out_nodes_ids( 1 ).collect();
    a_id!( got, exp );
    let exp = hset![ 1, 2 ];
    let got : HashSet< _ > = factory.out_nodes_ids( 2 ).collect();
    a_id!( got, exp );

    let got : HashSet< _ > = factory.out_edges( 1 ).map( | el | ( el.1.in_node, el.1.out_node ) ).collect();
    let exp = hset![ ( factory.edge_id( 1 ), factory.edge_id( 2 ) ) ];
    a_id!( got, exp );
    let got : HashSet< _ > = factory.out_edges( 2 ).map( | el | ( el.1.in_node, el.1.out_node ) ).collect();
    let exp = hset![ ( factory.edge_id( 2 ), factory.edge_id( 1 ) ), ( factory.edge_id( 2 ), factory.edge_id( 2 ) ) ];
    // let exp = hset![ factory.edge_ids( 2, 1 ), factory.edge_ids( 2, 2 ) ];
    // let exp : HashSet< ( TheModule::IdentityWithInt, TheModule::IdentityWithInt ) > = hset![ ( 2, 1 ).into(), ( 2, 2 ).into() ];
    a_id!( got, exp );

  }

  //

  #[ test ]
  fn make_with_edge_list_string()
  {
    use TheModule::prelude::*;

    let mut factory = TheFactory::< TheModule::IdentityWithName >::make();

    factory.make_with_edge_list
    ([
      "A", "B",
      "B", "A",
      "B", "B",
    ]);

    dbg!( factory.node( "A" ) );
    dbg!( factory.node( "B" ) );

    let exp = hset![ "B" ];
    let got : HashSet< _ > = factory.out_nodes_ids( "A" ).collect();
    a_id!( got, exp );

    let exp = hset![ "A", "B" ];
    let got : HashSet< _ > = factory.out_nodes_ids( "B" ).collect();
    a_id!( got, exp );
  }

  //

  #[ test ]
  fn graph_print()
  {
    use TheModule::prelude::*;

    let mut factory = TheFactory::< TheModule::IdentityWithInt >::make();

    factory.make_with_edge_list
    ([
      1, 2,
      2, 1,
      2, 2,
    ]);

    let exp = r#"NodeFactory
  node::1
   - 2
  node::2
   - 1
   - 2"#;
    let got = format!( "{:?}", factory );
    println!( "{}", got );
    a_id!( got, exp );

  }

}
<commit_msg>!test<commit_after>tests_impls!
{

  #[ test ]
  fn node()
  {
    use TheModule::prelude::*;
    let mut factory = TheFactory::< TheModule::IdentityWithInt >::make();

    let n1 = factory.node_making( 1 );
    let n1b = factory.node( 1 );
    a_id!( n1, n1b.id() );
    dbg!( &n1 );

    let node1a = factory.node( 1 );
    let node1b = factory.node( 1 );
    a_id!( node1a, node1b );

    let node1a = factory.node( &1 );
    let node1b = factory.node( &&1 );
    a_id!( node1a, node1b );

  }

  //

  #[ test ]
  fn make_default()
  {
    use TheModule::prelude::*;

    let mut factory : TheFactory::< TheModule::IdentityWithInt > = make!();
    let n1 = factory.node_making( 1 );
    let n1b = factory.node( 1 );
    a_id!( n1, n1b.id() );

  }

  //

  #[ test ]
  fn basic()
  {
    use TheModule::prelude::*;

    let mut factory = TheFactory::< TheModule::IdentityWithInt >::make();

    let a = factory.node_making( 1 );
    let b = factory.node_making( 2 );

    factory.node_add_out_node( a, b );
    factory.node_add_out_nodes( b, [ a, b ].into_iter() );

    a_id!( factory.nnodes(), 2 );
    a_id!( factory.nedges(), 3 );

    dbg!( factory.node( a ) );
    dbg!( factory.node( b ) );

    let got : HashSet< _ > = factory.out_nodes_ids( a ).collect();
    let exp = hset![ b ];
    a_id!( got, exp );
    let got : HashSet< _ > = factory.out_nodes_ids( b ).collect();
    let exp = hset![ a, b ];
    a_id!( got, exp );

    // let got : HashSet< _ > = factory.out_nodes_ids_2( a ).collect();
    // let exp = hset![ b ];
    // a_id!( got, exp );
    // let got : HashSet< _ > = factory.out_nodes_ids_2( b ).collect();
    // let exp = hset![ a, b ];
    // a_id!( got, exp );

    let got : HashSet< _ > = factory.out_edges( a ).map( | el | ( el.1.in_node, el.1.out_node ) ).collect();
    let exp = hset![ ( a, b ) ];
    a_id!( got, exp );
    let got : HashSet< _ > = factory.out_edges( b ).map( | el | ( el.1.in_node, el.1.out_node ) ).collect();
    let exp = hset![ ( b, a ), ( b, b ) ];
    a_id!( got, exp );

    // let got = factory.out_nodes_ids_2( a ).map( | id |
    // {
    //   // 13_i32
    //   ( id, factory.node( id ) )
    // });
    // use test_tools::inspect_type_of;
    // inspect_type_of!( got );

  }

  //

  #[ test ]
  fn make_with_edge_list()
  {
    use TheModule::prelude::*;

    let mut factory = TheFactory::< TheModule::IdentityWithInt >::make();

    factory.make_with_edge_list
    ([
      1, 2,
      2, 1,
      2, 2,
    ]);

    dbg!( factory.node( 1 ) );
    dbg!( factory.node( 2 ) );

    let exp = hset![ 2 ];
    let got : HashSet< _ > = factory.out_nodes_ids( 1 ).collect();
    a_id!( got, exp );
    let exp = hset![ 1, 2 ];
    let got : HashSet< _ > = factory.out_nodes_ids( 2 ).collect();
    a_id!( got, exp );

    let got : HashSet< _ > = factory.out_edges( 1 ).map( | el | ( el.1.in_node, el.1.out_node ) ).collect();
    let exp = hset![ ( factory.edge_id( 1 ), factory.edge_id( 2 ) ) ];
    a_id!( got, exp );
    let got : HashSet< _ > = factory.out_edges( 2 ).map( | el | ( el.1.in_node, el.1.out_node ) ).collect();
    let exp = hset![ ( factory.edge_id( 2 ), factory.edge_id( 1 ) ), ( factory.edge_id( 2 ), factory.edge_id( 2 ) ) ];
    // let exp = hset![ factory.edge_ids( 2, 1 ), factory.edge_ids( 2, 2 ) ];
    // let exp : HashSet< ( TheModule::IdentityWithInt, TheModule::IdentityWithInt ) > = hset![ ( 2, 1 ).into(), ( 2, 2 ).into() ];
    a_id!( got, exp );

  }

  //

  #[ test ]
  fn make_with_edge_list_string()
  {
    use TheModule::prelude::*;

    let mut factory = TheFactory::< TheModule::IdentityWithName >::make();

    factory.make_with_edge_list
    ([
      "A", "B",
      "B", "A",
      "B", "B",
    ]);

    dbg!( factory.node( "A" ) );
    dbg!( factory.node( "B" ) );

    let exp = hset![ "B" ];
    let got : HashSet< _ > = factory.out_nodes_ids( "A" ).collect();
    a_id!( got, exp );

    let exp = hset![ "A", "B" ];
    let got : HashSet< _ > = factory.out_nodes_ids( "B" ).collect();
    a_id!( got, exp );
  }

  //

  #[ test ]
  fn graph_print()
  {
    use TheModule::prelude::*;

    let mut factory = TheFactory::< TheModule::IdentityWithInt >::make();

    factory.make_with_edge_list
    ([
      1, 2,
      2, 1,
      2, 2,
    ]);

    let exp = r#"NodeFactory
  node::1
   - 2
  node::2
   - 1
   - 2"#;
    let got = format!( "{:?}", factory );
    println!( "{}", got );
    a_id!( got, exp );

  }

}

<|endoftext|>


<commit_before>use std::fmt::{self, Display};

pub type Result<I, E = Error> = ::std::result::Result<I, E>;

/// askama error type
///
/// # Feature Interaction
///
/// If the feature `serde_json` is enabled an
/// additional error variant `Json` is added.
///
/// # Why not `failure`/`error-chain`?
///
/// Error from `error-chain` are not `Sync` which
/// can lead to problems e.g. when this is used
/// by a crate which use `failure`. Implementing
/// `Fail` on the other hand prevents the implementation
/// of `std::error::Error` until specialization lands
/// on stable. While errors impl. `Fail` can be
/// converted to a type impl. `std::error::Error`
/// using a adapter the benefits `failure` would
/// bring to this crate are small, which is why
/// `std::error::Error` was used.
///
#[non_exhaustive]
#[derive(Debug)]
pub enum Error {
    /// formatting error
    Fmt(fmt::Error),

    /// an error raised by using `?` in a template
    Custom(Box<dyn std::error::Error + Send + Sync>),

    /// json conversion error
    #[cfg(feature = "serde_json")]
    Json(::serde_json::Error),

    /// yaml conversion error
    #[cfg(feature = "serde_yaml")]
    Yaml(::serde_yaml::Error),
}

impl std::error::Error for Error {
    fn cause(&self) -> Option<&dyn std::error::Error> {
        match *self {
            Error::Fmt(ref err) => err.source(),
            Error::Custom(ref err) => Some(err.as_ref()),
            #[cfg(feature = "serde_json")]
            Error::Json(ref err) => err.source(),
            #[cfg(feature = "serde_yaml")]
            Error::Yaml(ref err) => err.source(),
        }
    }
}

impl Display for Error {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Error::Fmt(err) => write!(formatter, "formatting error: {}", err),
            Error::Custom(err) => write!(formatter, "{}", err),
            #[cfg(feature = "serde_json")]
            Error::Json(err) => write!(formatter, "json conversion error: {}", err),
            #[cfg(feature = "serde_yaml")]
            Error::Yaml(err) => write!(formatter, "yaml conversion error: {}", err),
        }
    }
}

impl From<fmt::Error> for Error {
    fn from(err: fmt::Error) -> Self {
        Error::Fmt(err)
    }
}

#[cfg(feature = "serde_json")]
impl From<::serde_json::Error> for Error {
    fn from(err: ::serde_json::Error) -> Self {
        Error::Json(err)
    }
}

#[cfg(feature = "serde_yaml")]
impl From<::serde_yaml::Error> for Error {
    fn from(err: ::serde_yaml::Error) -> Self {
        Error::Yaml(err)
    }
}

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

    trait AssertSendSyncStatic: Send + Sync + 'static {}
    impl AssertSendSyncStatic for Error {}
}
<commit_msg>Implement std::error::Error::source<commit_after>use std::fmt::{self, Display};

pub type Result<I, E = Error> = ::std::result::Result<I, E>;

/// askama error type
///
/// # Feature Interaction
///
/// If the feature `serde_json` is enabled an
/// additional error variant `Json` is added.
///
/// # Why not `failure`/`error-chain`?
///
/// Error from `error-chain` are not `Sync` which
/// can lead to problems e.g. when this is used
/// by a crate which use `failure`. Implementing
/// `Fail` on the other hand prevents the implementation
/// of `std::error::Error` until specialization lands
/// on stable. While errors impl. `Fail` can be
/// converted to a type impl. `std::error::Error`
/// using a adapter the benefits `failure` would
/// bring to this crate are small, which is why
/// `std::error::Error` was used.
///
#[non_exhaustive]
#[derive(Debug)]
pub enum Error {
    /// formatting error
    Fmt(fmt::Error),

    /// an error raised by using `?` in a template
    Custom(Box<dyn std::error::Error + Send + Sync>),

    /// json conversion error
    #[cfg(feature = "serde_json")]
    Json(::serde_json::Error),

    /// yaml conversion error
    #[cfg(feature = "serde_yaml")]
    Yaml(::serde_yaml::Error),
}

impl std::error::Error for Error {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match *self {
            Error::Fmt(ref err) => Some(err),
            Error::Custom(ref err) => Some(err.as_ref()),
            #[cfg(feature = "serde_json")]
            Error::Json(ref err) => Some(err),
            #[cfg(feature = "serde_yaml")]
            Error::Yaml(ref err) => Some(err),
        }
    }
}

impl Display for Error {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Error::Fmt(err) => write!(formatter, "formatting error: {}", err),
            Error::Custom(err) => write!(formatter, "{}", err),
            #[cfg(feature = "serde_json")]
            Error::Json(err) => write!(formatter, "json conversion error: {}", err),
            #[cfg(feature = "serde_yaml")]
            Error::Yaml(err) => write!(formatter, "yaml conversion error: {}", err),
        }
    }
}

impl From<fmt::Error> for Error {
    fn from(err: fmt::Error) -> Self {
        Error::Fmt(err)
    }
}

#[cfg(feature = "serde_json")]
impl From<::serde_json::Error> for Error {
    fn from(err: ::serde_json::Error) -> Self {
        Error::Json(err)
    }
}

#[cfg(feature = "serde_yaml")]
impl From<::serde_yaml::Error> for Error {
    fn from(err: ::serde_yaml::Error) -> Self {
        Error::Yaml(err)
    }
}

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

    trait AssertSendSyncStatic: Send + Sync + 'static {}
    impl AssertSendSyncStatic for Error {}
}
<|endoftext|>


<commit_before>/*===============================================================================================*/
// Copyright 2016 Kyle Finlay
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*===============================================================================================*/

use ::util::math::Util;

use std::ops::*;
use std::cmp::PartialEq;

/*===============================================================================================*/
/*------VEC3 STRUCT------------------------------------------------------------------------------*/
/*===============================================================================================*/

/// The Vec3 struct
///
/// This is the most used out of the three vector structs.
/// It is used for representing positions in 3D space (vertices, normals, positions, etc).
/// 32-bit floats are used for the values.
#[derive (Copy, Clone, Default, Serialize, Deserialize)]
pub struct Vec3 {

    // Public
    /// X-axis coordinate
    pub x: f32,
    /// Y-axis coordinate
    pub y: f32,
    /// Z-axis coordinate
    pub z: f32
}

/*===============================================================================================*/
/*------VEC3 PUBLIC METHODS----------------------------------------------------------------------*/
/*===============================================================================================*/

impl Vec3 {

    /// Formats the vector as a string.
    ///
    /// # Examples
    /// ```
    /// # use ion_core::util::math::Vec3;
    /// #
    /// let vec = Vec3 {x : 10.0, y : 5.0, z : 1.0};
    /// println! ("Vector = {}", vec.to_string ());
    /// ```
    /// ```c
    /// Output : Vector = 10.0, 5.0, 1.0
    pub fn to_string (&self) -> String {

        format! ("{}, {}, {}", self.x, self.y, self.z)
    }

/*===============================================================================================*/
/*------VEC3 PUBLIC STATIC METHODS---------------------------------------------------------------*/
/*===============================================================================================*/

    /// Creates a vector with a default value of zero.
    ///
    /// # Examples
    /// ```
    /// # use ion_core::util::math::Vec3;
    /// #
    /// let vec = Vec3::new ();
    pub fn new () -> Vec3 {

        Vec3 {x: 0.0,
              y: 0.0,
              z: 0.0}
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Creates a vector with a value of (0, 1, 0).
    pub fn up () -> Vec3 {

        Vec3 {x: 0.0,
              y: 1.0,
              z: 0.0}
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Creates a vector with a value of (0, -1, 0).
    pub fn down () -> Vec3 {

        Vec3 {x: 0.0,
              y: -1.0,
              z: 0.0}
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Creates a vector with a value of (-1, 0, 0).
    pub fn left () -> Vec3 {

        Vec3 {x: -1.0,
              y: 0.0,
              z: 0.0}
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Creates a vector with a value of (1, 0, 0)
    pub fn right () -> Vec3 {

        Vec3 {x: 1.0,
              y: 0.0,
              z: 0.0}
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Creates a vector with a value of (0, 0, 1)
    pub fn forward () -> Vec3 {

        Vec3 {x: 0.0,
              y: 0.0,
              z: 1.0}
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Cretaes a vector with a value of (0, 0, -1)
    pub fn back () -> Vec3 {

        Vec3 {x: 0.0,
              y: 0.0,
              z: -1.0}
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Retuns the cross product of two vectors.
    pub fn cross (lhs: &Vec3, rhs: &Vec3) -> Vec3 {

        Vec3 {x: lhs.y * rhs.z - rhs.y * lhs.z,
              y: lhs.z * rhs.x - rhs.x * lhs.x,
              z: lhs.x * rhs.y - rhs.x * lhs.y}
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns the dot product of two vectors.
    pub fn dot (lhs: &Vec3, rhs: &Vec3) -> f32 {

        (lhs.x * rhs.x) +
        (lhs.y * rhs.y) +
        (lhs.z * rhs.z)
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns the distance between two vectors
    pub fn distance (start: &Vec3, end: &Vec3) -> f32 {

        Vec3::length (& (*start - *end))
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns the length of a vector
    pub fn length (vector: &Vec3) -> f32 {

        (vector.x * vector.x +
         vector.y * vector.y +
         vector.z * vector.z).sqrt ()
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Linearly interpolates between two vectors.
    pub fn lerp (start: &Vec3, end: &Vec3, percentage: f32) -> Vec3 {

        Vec3 {x: Util::lerp (start.x, end.x, percentage),
              y: Util::lerp (start.y, end.y, percentage),
              z: Util::lerp (start.z, end.z, percentage)}
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Linearly interpolates between two vectors without clamping
    pub fn lerp_unclamped (start: &Vec3, end: &Vec3, percentage: f32) -> Vec3 {

        Vec3 {x: Util::lerp_unclamped (start.x, end.x, percentage),
              y: Util::lerp_unclamped (start.y, end.y, percentage),
              z: Util::lerp_unclamped (start.z, end.z, percentage)}
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Get a normalized vector.
    pub fn normalize (vector: &Vec3) -> Vec3 {

        let length = Vec3::length (vector);

        if length != 0.0 {

            return Vec3 {x: vector.x / length,
                         y: vector.y / length,
                         z: vector.z / length}
        }

        Vec3::new ()
    }
}

/*===============================================================================================*/
/*------VEC3 OPERATOR OVERLOADS------------------------------------------------------------------*/
/*===============================================================================================*/

impl Add for Vec3 {

    type Output = Vec3;

    // Addition operator (vector)
    fn add (self, rhs: Vec3) -> Vec3 {

        Vec3 {x: self.x + rhs.x,
              y: self.y + rhs.y,
              z: self.z + rhs.z}
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl Add <f32> for Vec3 {

    type Output = Vec3;

    // Addition operator (f32)
    fn add (self, rhs: f32) -> Vec3 {

        Vec3 {x: self.x + rhs,
              y: self.y + rhs,
              z: self.z + rhs}
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl AddAssign for Vec3 {

    // Addition assignment operator (vector)
    fn add_assign (&mut self, rhs: Vec3) {

        self.x += rhs.x;
        self.y += rhs.y;
        self.z += rhs.z;
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl AddAssign <f32> for Vec3 {

    // Addition assignment operator (f32)
    fn add_assign (&mut self, rhs: f32) {

        self.x += rhs;
        self.y += rhs;
        self.z += rhs;
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl Sub for Vec3 {

    type Output = Vec3;

    // Subtraction operator (vector)
    fn sub (self, rhs: Vec3) -> Vec3 {

        Vec3 {x: self.x - rhs.x,
              y: self.y - rhs.y,
              z: self.z - rhs.z}
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl Sub <f32> for Vec3 {

    type Output = Vec3;

    // Subtraction operator (f32)
    fn sub (self, rhs: f32) -> Vec3 {

        Vec3 {x: self.x - rhs,
              y: self.y - rhs,
              z: self.z - rhs}
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl SubAssign for Vec3 {

    // Subtraction assignment operator (vector)
    fn sub_assign (&mut self, rhs: Vec3) {

        self.x -= rhs.x;
        self.y -= rhs.y;
        self.z -= rhs.z;
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl SubAssign <f32> for Vec3 {

    // Subtraction assignment operator (f32)
    fn sub_assign (&mut self, rhs: f32) {

        self.x -= rhs;
        self.y -= rhs;
        self.z -= rhs;
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl Neg for Vec3 {

    type Output = Vec3;

    // Unary minus operator
    fn neg (self) -> Vec3 {

        Vec3 {x: -self.x,
              y: -self.y,
              z: -self.z}
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl Mul for Vec3 {

    type Output = Vec3;

    // Multiplication operator (vector)
    fn mul (self, rhs: Vec3) -> Vec3 {

        Vec3 {x: self.x * rhs.x,
              y: self.y * rhs.y,
              z: self.z * rhs.z}
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl Mul <f32> for Vec3 {

    type Output = Vec3;

    // Multiplication operator (f32)
    fn mul (self, rhs: f32) -> Vec3 {

        Vec3 {x: self.x * rhs,
              y: self.y * rhs,
              z: self.z * rhs}
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl MulAssign for Vec3 {

    // Multiplication assignment operator (vector)
    fn mul_assign (&mut self, rhs: Vec3) {

        self.x *= rhs.x;
        self.y *= rhs.y;
        self.z *= rhs.z;
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl MulAssign <f32> for Vec3 {

    // Multiplication assignment operator (f32)
    fn mul_assign (&mut self, rhs: f32) {

        self.x *= rhs;
        self.y *= rhs;
        self.z *= rhs;
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl Div for Vec3 {

    type Output = Vec3;

    // Division operator (vector)
    fn div (self, rhs: Vec3) -> Vec3 {

        Vec3 {x: self.x / rhs.x,
              y: self.y / rhs.y,
              z: self.z / rhs.z}
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl Div <f32> for Vec3 {

    type Output = Vec3;

    // Division operator (f32)
    fn div (self, rhs: f32) -> Vec3 {

        Vec3 {x: self.x / rhs,
              y: self.y / rhs,
              z: self.z / rhs}
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl DivAssign for Vec3 {

    // Division assignment operator (vector)
    fn div_assign (&mut self, rhs: Vec3) {

        self.x /= rhs.x;
        self.y /= rhs.y;
        self.z /= rhs.z;
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl DivAssign <f32> for Vec3 {

    // Division assignment operator (f32)
    fn div_assign (&mut self, rhs: f32) {

        self.x /= rhs;
        self.y /= rhs;
        self.z /= rhs;
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl PartialEq for Vec3 {

    // Equal to operator
    fn eq (&self, rhs: &Vec3) -> bool {

        self.x == rhs.x &&
        self.y == rhs.y &&
        self.z == rhs.z
    }

/*-----------------------------------------------------------------------------------------------*/

    // Not equal to operator
    fn ne (&self, rhs: &Vec3) -> bool {

        self.x != rhs.x ||
        self.y != rhs.y ||
        self.z != rhs.z
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl Index <u8> for Vec3 {

    type Output = f32;

    // Index operator (immutable)
    fn index (&self, index: u8) -> &f32 {

        match index {

            0 => &self.x,
            1 => &self.y,
            2 => &self.z,
            _ => unreachable! ("Index out of range for Vec3")
        }
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl IndexMut <u8> for Vec3 {

    // Index operator (mutable)
    fn index_mut (&mut self, index: u8) -> &mut f32 {

        match index {

            0 => &mut self.x,
            1 => &mut self.y,
            2 => &mut self.z,
            _ => unreachable! ("Index out of range for Vec3")
        }
    }
}
<commit_msg>Fixed mistake in cross product calculation.<commit_after>/*===============================================================================================*/
// Copyright 2016 Kyle Finlay
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*===============================================================================================*/

use ::util::math::Util;

use std::ops::*;
use std::cmp::PartialEq;

/*===============================================================================================*/
/*------VEC3 STRUCT------------------------------------------------------------------------------*/
/*===============================================================================================*/

/// The Vec3 struct
///
/// This is the most used out of the three vector structs.
/// It is used for representing positions in 3D space (vertices, normals, positions, etc).
/// 32-bit floats are used for the values.
#[derive (Copy, Clone, Default, Serialize, Deserialize)]
pub struct Vec3 {

    // Public
    /// X-axis coordinate
    pub x: f32,
    /// Y-axis coordinate
    pub y: f32,
    /// Z-axis coordinate
    pub z: f32
}

/*===============================================================================================*/
/*------VEC3 PUBLIC METHODS----------------------------------------------------------------------*/
/*===============================================================================================*/

impl Vec3 {

    /// Formats the vector as a string.
    ///
    /// # Examples
    /// ```
    /// # use ion_core::util::math::Vec3;
    /// #
    /// let vec = Vec3 {x : 10.0, y : 5.0, z : 1.0};
    /// println! ("Vector = {}", vec.to_string ());
    /// ```
    /// ```c
    /// Output : Vector = 10.0, 5.0, 1.0
    pub fn to_string (&self) -> String {

        format! ("{}, {}, {}", self.x, self.y, self.z)
    }

/*===============================================================================================*/
/*------VEC3 PUBLIC STATIC METHODS---------------------------------------------------------------*/
/*===============================================================================================*/

    /// Creates a vector with a default value of zero.
    ///
    /// # Examples
    /// ```
    /// # use ion_core::util::math::Vec3;
    /// #
    /// let vec = Vec3::new ();
    pub fn new () -> Vec3 {

        Vec3 {x: 0.0,
              y: 0.0,
              z: 0.0}
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Creates a vector with a value of (0, 1, 0).
    pub fn up () -> Vec3 {

        Vec3 {x: 0.0,
              y: 1.0,
              z: 0.0}
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Creates a vector with a value of (0, -1, 0).
    pub fn down () -> Vec3 {

        Vec3 {x: 0.0,
              y: -1.0,
              z: 0.0}
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Creates a vector with a value of (-1, 0, 0).
    pub fn left () -> Vec3 {

        Vec3 {x: -1.0,
              y: 0.0,
              z: 0.0}
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Creates a vector with a value of (1, 0, 0)
    pub fn right () -> Vec3 {

        Vec3 {x: 1.0,
              y: 0.0,
              z: 0.0}
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Creates a vector with a value of (0, 0, 1)
    pub fn forward () -> Vec3 {

        Vec3 {x: 0.0,
              y: 0.0,
              z: 1.0}
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Cretaes a vector with a value of (0, 0, -1)
    pub fn back () -> Vec3 {

        Vec3 {x: 0.0,
              y: 0.0,
              z: -1.0}
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Retuns the cross product of two vectors.
    pub fn cross (lhs: &Vec3, rhs: &Vec3) -> Vec3 {

        Vec3 {x: (lhs.y * rhs.z) - (lhs.z * rhs.y),
              y: (lhs.z * rhs.x) - (lhs.x * rhs.z),
              z: (lhs.x * rhs.y) - (lhs.y * rhs.x)}
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns the dot product of two vectors.
    pub fn dot (lhs: &Vec3, rhs: &Vec3) -> f32 {

        (lhs.x * rhs.x) +
        (lhs.y * rhs.y) +
        (lhs.z * rhs.z)
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns the distance between two vectors
    pub fn distance (start: &Vec3, end: &Vec3) -> f32 {

        Vec3::length (& (*start - *end))
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Returns the length of a vector
    pub fn length (vector: &Vec3) -> f32 {

        (vector.x * vector.x +
         vector.y * vector.y +
         vector.z * vector.z).sqrt ()
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Linearly interpolates between two vectors.
    pub fn lerp (start: &Vec3, end: &Vec3, percentage: f32) -> Vec3 {

        Vec3 {x: Util::lerp (start.x, end.x, percentage),
              y: Util::lerp (start.y, end.y, percentage),
              z: Util::lerp (start.z, end.z, percentage)}
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Linearly interpolates between two vectors without clamping
    pub fn lerp_unclamped (start: &Vec3, end: &Vec3, percentage: f32) -> Vec3 {

        Vec3 {x: Util::lerp_unclamped (start.x, end.x, percentage),
              y: Util::lerp_unclamped (start.y, end.y, percentage),
              z: Util::lerp_unclamped (start.z, end.z, percentage)}
    }

/*-----------------------------------------------------------------------------------------------*/

    /// Get a normalized vector.
    pub fn normalize (vector: &Vec3) -> Vec3 {

        let length = Vec3::length (vector);

        if length != 0.0 {

            return Vec3 {x: vector.x / length,
                         y: vector.y / length,
                         z: vector.z / length}
        }

        Vec3::new ()
    }
}

/*===============================================================================================*/
/*------VEC3 OPERATOR OVERLOADS------------------------------------------------------------------*/
/*===============================================================================================*/

impl Add for Vec3 {

    type Output = Vec3;

    // Addition operator (vector)
    fn add (self, rhs: Vec3) -> Vec3 {

        Vec3 {x: self.x + rhs.x,
              y: self.y + rhs.y,
              z: self.z + rhs.z}
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl Add <f32> for Vec3 {

    type Output = Vec3;

    // Addition operator (f32)
    fn add (self, rhs: f32) -> Vec3 {

        Vec3 {x: self.x + rhs,
              y: self.y + rhs,
              z: self.z + rhs}
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl AddAssign for Vec3 {

    // Addition assignment operator (vector)
    fn add_assign (&mut self, rhs: Vec3) {

        self.x += rhs.x;
        self.y += rhs.y;
        self.z += rhs.z;
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl AddAssign <f32> for Vec3 {

    // Addition assignment operator (f32)
    fn add_assign (&mut self, rhs: f32) {

        self.x += rhs;
        self.y += rhs;
        self.z += rhs;
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl Sub for Vec3 {

    type Output = Vec3;

    // Subtraction operator (vector)
    fn sub (self, rhs: Vec3) -> Vec3 {

        Vec3 {x: self.x - rhs.x,
              y: self.y - rhs.y,
              z: self.z - rhs.z}
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl Sub <f32> for Vec3 {

    type Output = Vec3;

    // Subtraction operator (f32)
    fn sub (self, rhs: f32) -> Vec3 {

        Vec3 {x: self.x - rhs,
              y: self.y - rhs,
              z: self.z - rhs}
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl SubAssign for Vec3 {

    // Subtraction assignment operator (vector)
    fn sub_assign (&mut self, rhs: Vec3) {

        self.x -= rhs.x;
        self.y -= rhs.y;
        self.z -= rhs.z;
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl SubAssign <f32> for Vec3 {

    // Subtraction assignment operator (f32)
    fn sub_assign (&mut self, rhs: f32) {

        self.x -= rhs;
        self.y -= rhs;
        self.z -= rhs;
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl Neg for Vec3 {

    type Output = Vec3;

    // Unary minus operator
    fn neg (self) -> Vec3 {

        Vec3 {x: -self.x,
              y: -self.y,
              z: -self.z}
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl Mul for Vec3 {

    type Output = Vec3;

    // Multiplication operator (vector)
    fn mul (self, rhs: Vec3) -> Vec3 {

        Vec3 {x: self.x * rhs.x,
              y: self.y * rhs.y,
              z: self.z * rhs.z}
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl Mul <f32> for Vec3 {

    type Output = Vec3;

    // Multiplication operator (f32)
    fn mul (self, rhs: f32) -> Vec3 {

        Vec3 {x: self.x * rhs,
              y: self.y * rhs,
              z: self.z * rhs}
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl MulAssign for Vec3 {

    // Multiplication assignment operator (vector)
    fn mul_assign (&mut self, rhs: Vec3) {

        self.x *= rhs.x;
        self.y *= rhs.y;
        self.z *= rhs.z;
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl MulAssign <f32> for Vec3 {

    // Multiplication assignment operator (f32)
    fn mul_assign (&mut self, rhs: f32) {

        self.x *= rhs;
        self.y *= rhs;
        self.z *= rhs;
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl Div for Vec3 {

    type Output = Vec3;

    // Division operator (vector)
    fn div (self, rhs: Vec3) -> Vec3 {

        Vec3 {x: self.x / rhs.x,
              y: self.y / rhs.y,
              z: self.z / rhs.z}
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl Div <f32> for Vec3 {

    type Output = Vec3;

    // Division operator (f32)
    fn div (self, rhs: f32) -> Vec3 {

        Vec3 {x: self.x / rhs,
              y: self.y / rhs,
              z: self.z / rhs}
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl DivAssign for Vec3 {

    // Division assignment operator (vector)
    fn div_assign (&mut self, rhs: Vec3) {

        self.x /= rhs.x;
        self.y /= rhs.y;
        self.z /= rhs.z;
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl DivAssign <f32> for Vec3 {

    // Division assignment operator (f32)
    fn div_assign (&mut self, rhs: f32) {

        self.x /= rhs;
        self.y /= rhs;
        self.z /= rhs;
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl PartialEq for Vec3 {

    // Equal to operator
    fn eq (&self, rhs: &Vec3) -> bool {

        self.x == rhs.x &&
        self.y == rhs.y &&
        self.z == rhs.z
    }

/*-----------------------------------------------------------------------------------------------*/

    // Not equal to operator
    fn ne (&self, rhs: &Vec3) -> bool {

        self.x != rhs.x ||
        self.y != rhs.y ||
        self.z != rhs.z
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl Index <u8> for Vec3 {

    type Output = f32;

    // Index operator (immutable)
    fn index (&self, index: u8) -> &f32 {

        match index {

            0 => &self.x,
            1 => &self.y,
            2 => &self.z,
            _ => unreachable! ("Index out of range for Vec3")
        }
    }
}

/*-----------------------------------------------------------------------------------------------*/

impl IndexMut <u8> for Vec3 {

    // Index operator (mutable)
    fn index_mut (&mut self, index: u8) -> &mut f32 {

        match index {

            0 => &mut self.x,
            1 => &mut self.y,
            2 => &mut self.z,
            _ => unreachable! ("Index out of range for Vec3")
        }
    }
}
<|endoftext|>