<commit_before>pub mod tag_command;
pub mod autotag;
pub mod update_tags;
pub mod update_tag;

pub use self::tag_command::TagCommand;
pub use self::autotag::AutoTagCommand;
pub use self::update_tags::UpdateTagsCommand;
pub use self::update_tag::UpdateTagCommand;

use bot::BotEnv;
use database::models::{Tag, NewTag, Verification};

use lalafell::error::*;
use lalafell::commands::prelude::*;

use serenity::prelude::Mentionable;
use serenity::model::guild::Role;
use serenity::model::id::{RoleId, UserId};
use serenity::Error as SError;
use serenity::http::{HttpError, StatusCode};

use diesel::prelude::*;

use url::Url;

use make_hyper_great_again::Client;
use hyper_rustls::HttpsConnector;

use std::sync::Mutex;
use std::collections::HashSet;
use std::thread;

lazy_static! {
  // Limbo roles are roles that may or may not be added to the Discord bot state.
  static ref LIMBO_ROLES: Mutex<Vec<Role>> = Mutex::default();
}

pub struct Tagger;

impl Tagger {
  fn add_to_xivdb<N: Into<String>, S: Into<String>>(name: N, server: S) {
    let name: String = name.into();
    let server: String = server.into();
    thread::spawn(move || {
      let mut url = Url::parse("https://xivsync.com/character/search").unwrap();
      url.query_pairs_mut()
        .append_pair("name", &name)
        .append_pair("server", &server);
      let client = Client::create_connector(|c| HttpsConnector::new(4, &c.handle())).unwrap();
      client.get(url).send().ok();
    });
  }

  pub fn search_tag(env: &BotEnv, who: UserId, on: GuildId, server: &str, character_name: &str, ignore_verified: bool) -> Result<Option<String>> {
    let params = &[
      ("one", "characters"),
      ("strict", "on"),
      ("server|et", server)
    ];

    let res = env.xivdb.search(character_name, params).chain_err(|| "could not query XIVDB")?;

    let search_chars = res.characters.unwrap().results;
    if search_chars.is_empty() {
      Tagger::add_to_xivdb(character_name, server);
      return Ok(Some(format!("Could not find any character by the name {} on {}.\nIf you typed everything correctly, wait up to five minutes and try again.", character_name, server)));
    }

    let char_id = match search_chars[0]["id"].as_u64() {
      Some(u) => u,
      None => bail!("character ID was not a u64")
    };

    let name = match search_chars[0]["name"].as_str() {
      Some(s) => s,
      None => bail!("character name was not a string")
    };

    if name.to_lowercase() != character_name.to_lowercase() {
      return Ok(Some(format!("Could not find any character by the name {} on {}.", character_name, server)));
    }

    Tagger::tag(env, who, on, char_id, ignore_verified)
  }

  fn find_or_create_role(guild: GuildId, name: &str, add_roles: &mut Vec<Role>, created_roles: &mut Vec<Role>) -> Result<()> {
    let lower_name = name.to_lowercase();
    let guild = guild.get().chain_err(|| "could not get guild")?;
    match guild.roles.values().find(|x| x.name.to_lowercase() == lower_name) {
      Some(r) => add_roles.push(r.clone()),
      None => {
        let role = guild.create_role(|r| r.name(&lower_name)).chain_err(|| "could not create role")?;
        created_roles.push(role);
      }
    }
    Ok(())
  }

  pub fn tag(env: &BotEnv, who: UserId, on: GuildId, char_id: u64, ignore_verified: bool) -> Result<Option<String>> {
    let tag: Option<Tag> = ::bot::CONNECTION.with(|c| {
      use database::schema::tags::dsl;
      dsl::tags
        .filter(dsl::user_id.eq(who.0.to_string()).and(dsl::server_id.eq(on.0.to_string())))
        .first(c)
        .optional()
        .chain_err(|| "could not load tags")
    })?;
    let is_verified = match tag {
      Some(t) => {
        let verification: Verification = ::bot::CONNECTION.with(|c| {
          Verification::belonging_to(&t).first(c).optional().chain_err(|| "could not load verifications")
        })?.unwrap_or_default();
        if verification.verified && !ignore_verified && char_id != *t.character_id {
          return Ok(Some(format!("{} is verified as {} on {}, so they cannot switch to another account.", who.mention(), t.character, t.server)));
        }
        verification.verified
      },
      None => false
    };

    // This is still a disaster, just slightly less so
    let member = match on.member(who) {
      Ok(m) => m,
      Err(SError::Http(HttpError::UnsuccessfulRequest(ref r))) if r.status == StatusCode::NotFound => {
        ::bot::CONNECTION.with(|c| {
          use database::schema::tags::dsl;
          ::diesel::delete(dsl::tags
            .filter(dsl::user_id.eq(who.0.to_string()).and(dsl::server_id.eq(on.0.to_string()))))
            .execute(c)
            .chain_err(|| format!("could not remove tag {} on {}, but it was expected to be in database", who.0, on.0))
        })?;
        bail!("could not get user {} as a member of {}: removing their tag", who.0, on.0);
      },
      Err(e) => return Err(e).chain_err(|| "could not get member for tagging")
    };

    let character = env.xivdb.character(char_id).chain_err(|| "could not look up character")?;

    let tag: Option<Tag> = ::bot::CONNECTION.with(|c| {
      use database::schema::tags::dsl;
      dsl::tags
        .filter(dsl::user_id.eq(who.0.to_string()).and(dsl::server_id.eq(on.0.to_string())))
        .first(c)
        .optional()
        .chain_err(|| "could not load tags")
    })?;
    match tag {
      Some(mut t) => {
        let (id, name, server) = (character.lodestone_id, character.name.clone(), character.server.clone());
        t.character_id = id.into();
        t.character = name;
        t.server = server;
        ::bot::CONNECTION.with(|c| t.save_changes::<Tag>(c).chain_err(|| "could not update tag"))?;
      },
      None => {
        let new_tag = NewTag::new(
          who.0,
          on.0,
          character.lodestone_id,
          &character.name,
          &character.server
        );
        ::bot::CONNECTION.with(|c| {
          use database::schema::tags;
          ::diesel::insert_into(tags::table).values(&new_tag).execute(c).chain_err(|| "could not insert tag")
        })?;
      }
    }

    // Get a copy of the roles on the server.
    let mut roles: Vec<Role> = match on.find() {
      Some(g) => g.read().roles.values().cloned().collect(),
      None => on.get().chain_err(|| "could not get guild")?.roles.values().cloned().collect()
    };

    // Check for existing limbo roles.
    {
      let limbo = &mut *LIMBO_ROLES.lock().unwrap();
      for role in &roles {
        // If the server has updated to contain the limbo role, remove it.
        if let Some(i) = limbo.iter().position(|x| x.id == role.id) {
          limbo.remove(i);
        }
      }
    }
    // Get a copy of the limbo roles.
    let limbo = LIMBO_ROLES.lock().unwrap().clone();
    // Extend the server roles with the limbo roles.
    roles.extend(limbo);

    // Find or create the necessary roles
    let mut created_roles = Vec::new();
    let mut add_roles = Vec::new();
    Tagger::find_or_create_role(on, &character.data.race, &mut add_roles, &mut created_roles)?;
    Tagger::find_or_create_role(on, &character.data.gender, &mut add_roles, &mut created_roles)?;
    Tagger::find_or_create_role(on, &character.server, &mut add_roles, &mut created_roles)?;

    if is_verified {
      Tagger::find_or_create_role(on, "verified", &mut add_roles, &mut created_roles)?;
    }

    // If we created any roles, the server may or may not update with them fast enough, so store a copy in the limbo
    // roles.
    {
      let limbo = &mut *LIMBO_ROLES.lock().unwrap();
      for created in &created_roles {
        limbo.push(created.clone());
      }
    }

    debug!("Created the following roles:\n:{:#?}", created_roles);

    debug!("Existing roles:\n{:#?}", add_roles);

    // Extend the roles to add with the roles we created.
    add_roles.extend(created_roles);
    // Get all the roles that are part of groups
    let all_group_roles: Vec<String> = env.config.roles.groups.iter().flat_map(|x| x).map(|x| x.to_lowercase()).collect();
    // Filter all roles on the server to only the roles the member has
    let keep: Vec<&Role> = roles.iter().filter(|x| member.roles.contains(&x.id)).collect();
    // Filter all the roles the member has, keeping the ones not in a group. These roles will not be touched when
    // updating the tag.
    let keep: Vec<&Role> = keep.into_iter().filter(|x| !all_group_roles.contains(&x.name.to_lowercase())).collect();
    debug!("Roles to keep:\n{:#?}", keep);
    // Combine the two sets of roles and map them to IDs
    let mut role_set: Vec<RoleId> = add_roles.iter().map(|r| r.id).chain(keep.into_iter().map(|r| r.id)).collect();
    // Sort the IDs so we can dedup them
    role_set.sort();
    // Remove the duplicate roles, if any
    role_set.dedup();

    debug!("Final role set:\n{:#?}", role_set);

    // Only update the roles if they are different
    let different = {
      let member_roles: HashSet<u64> = member.roles.iter().map(|x| x.0).collect();
      let actual_role_set: HashSet<u64> = role_set.iter().map(|x| x.0).collect();
      member_roles != actual_role_set
    };
    if different {
      on.edit_member(who, |m| m.roles(&role_set)).chain_err(|| "could not add roles")?;
    }

    // cannot edit nickname of those with a higher role
    let nick = match member.nick {
      Some(n) => n,
      None => Default::default()
    };
    if nick != character.name {
      on.edit_member(who, |m| m.nickname(&character.name)).ok();
    }
    Ok(None)
  }
}

#[derive(Debug, Deserialize)]
struct DiscordNotFoundError {
  code: u64,
  message: Option<String>
}
<commit_msg>feat: hoist servers<commit_after>pub mod tag_command;
pub mod autotag;
pub mod update_tags;
pub mod update_tag;

pub use self::tag_command::TagCommand;
pub use self::autotag::AutoTagCommand;
pub use self::update_tags::UpdateTagsCommand;
pub use self::update_tag::UpdateTagCommand;

use bot::BotEnv;
use database::models::{Tag, NewTag, Verification};

use lalafell::error::*;
use lalafell::commands::prelude::*;

use serenity::prelude::Mentionable;
use serenity::builder::EditRole;
use serenity::model::guild::Role;
use serenity::model::id::{RoleId, UserId};
use serenity::Error as SError;
use serenity::http::{HttpError, StatusCode};

use diesel::prelude::*;

use url::Url;

use make_hyper_great_again::Client;
use hyper_rustls::HttpsConnector;

use std::sync::Mutex;
use std::collections::HashSet;
use std::thread;

lazy_static! {
  // Limbo roles are roles that may or may not be added to the Discord bot state.
  static ref LIMBO_ROLES: Mutex<Vec<Role>> = Mutex::default();
}

pub struct Tagger;

impl Tagger {
  fn add_to_xivdb<N: Into<String>, S: Into<String>>(name: N, server: S) {
    let name: String = name.into();
    let server: String = server.into();
    thread::spawn(move || {
      let mut url = Url::parse("https://xivsync.com/character/search").unwrap();
      url.query_pairs_mut()
        .append_pair("name", &name)
        .append_pair("server", &server);
      let client = Client::create_connector(|c| HttpsConnector::new(4, &c.handle())).unwrap();
      client.get(url).send().ok();
    });
  }

  pub fn search_tag(env: &BotEnv, who: UserId, on: GuildId, server: &str, character_name: &str, ignore_verified: bool) -> Result<Option<String>> {
    let params = &[
      ("one", "characters"),
      ("strict", "on"),
      ("server|et", server)
    ];

    let res = env.xivdb.search(character_name, params).chain_err(|| "could not query XIVDB")?;

    let search_chars = res.characters.unwrap().results;
    if search_chars.is_empty() {
      Tagger::add_to_xivdb(character_name, server);
      return Ok(Some(format!("Could not find any character by the name {} on {}.\nIf you typed everything correctly, wait up to five minutes and try again.", character_name, server)));
    }

    let char_id = match search_chars[0]["id"].as_u64() {
      Some(u) => u,
      None => bail!("character ID was not a u64")
    };

    let name = match search_chars[0]["name"].as_str() {
      Some(s) => s,
      None => bail!("character name was not a string")
    };

    if name.to_lowercase() != character_name.to_lowercase() {
      return Ok(Some(format!("Could not find any character by the name {} on {}.", character_name, server)));
    }

    Tagger::tag(env, who, on, char_id, ignore_verified)
  }

  fn find_or_create_role(guild: GuildId, name: &str, add_roles: &mut Vec<Role>, created_roles: &mut Vec<Role>) -> Result<()> {
    Tagger::find_or_create_role_and(guild, name, add_roles, created_roles, |r| r)
  }

  fn find_or_create_role_and<F>(guild: GuildId, name: &str, add_roles: &mut Vec<Role>, created_roles: &mut Vec<Role>, f: F) -> Result<()>
    where F: FnOnce(EditRole) -> EditRole
  {
    let lower_name = name.to_lowercase();
    let guild = guild.get().chain_err(|| "could not get guild")?;
    match guild.roles.values().find(|x| x.name.to_lowercase() == lower_name) {
      Some(r) => add_roles.push(r.clone()),
      None => {
        let role = guild.create_role(|r| f(r).name(&lower_name)).chain_err(|| "could not create role")?;
        created_roles.push(role);
      }
    }
    Ok(())
  }

  pub fn tag(env: &BotEnv, who: UserId, on: GuildId, char_id: u64, ignore_verified: bool) -> Result<Option<String>> {
    let tag: Option<Tag> = ::bot::CONNECTION.with(|c| {
      use database::schema::tags::dsl;
      dsl::tags
        .filter(dsl::user_id.eq(who.0.to_string()).and(dsl::server_id.eq(on.0.to_string())))
        .first(c)
        .optional()
        .chain_err(|| "could not load tags")
    })?;
    let is_verified = match tag {
      Some(t) => {
        let verification: Verification = ::bot::CONNECTION.with(|c| {
          Verification::belonging_to(&t).first(c).optional().chain_err(|| "could not load verifications")
        })?.unwrap_or_default();
        if verification.verified && !ignore_verified && char_id != *t.character_id {
          return Ok(Some(format!("{} is verified as {} on {}, so they cannot switch to another account.", who.mention(), t.character, t.server)));
        }
        verification.verified
      },
      None => false
    };

    // This is still a disaster, just slightly less so
    let member = match on.member(who) {
      Ok(m) => m,
      Err(SError::Http(HttpError::UnsuccessfulRequest(ref r))) if r.status == StatusCode::NotFound => {
        ::bot::CONNECTION.with(|c| {
          use database::schema::tags::dsl;
          ::diesel::delete(dsl::tags
            .filter(dsl::user_id.eq(who.0.to_string()).and(dsl::server_id.eq(on.0.to_string()))))
            .execute(c)
            .chain_err(|| format!("could not remove tag {} on {}, but it was expected to be in database", who.0, on.0))
        })?;
        bail!("could not get user {} as a member of {}: removing their tag", who.0, on.0);
      },
      Err(e) => return Err(e).chain_err(|| "could not get member for tagging")
    };

    let character = env.xivdb.character(char_id).chain_err(|| "could not look up character")?;

    let tag: Option<Tag> = ::bot::CONNECTION.with(|c| {
      use database::schema::tags::dsl;
      dsl::tags
        .filter(dsl::user_id.eq(who.0.to_string()).and(dsl::server_id.eq(on.0.to_string())))
        .first(c)
        .optional()
        .chain_err(|| "could not load tags")
    })?;
    match tag {
      Some(mut t) => {
        let (id, name, server) = (character.lodestone_id, character.name.clone(), character.server.clone());
        t.character_id = id.into();
        t.character = name;
        t.server = server;
        ::bot::CONNECTION.with(|c| t.save_changes::<Tag>(c).chain_err(|| "could not update tag"))?;
      },
      None => {
        let new_tag = NewTag::new(
          who.0,
          on.0,
          character.lodestone_id,
          &character.name,
          &character.server
        );
        ::bot::CONNECTION.with(|c| {
          use database::schema::tags;
          ::diesel::insert_into(tags::table).values(&new_tag).execute(c).chain_err(|| "could not insert tag")
        })?;
      }
    }

    // Get a copy of the roles on the server.
    let mut roles: Vec<Role> = match on.find() {
      Some(g) => g.read().roles.values().cloned().collect(),
      None => on.get().chain_err(|| "could not get guild")?.roles.values().cloned().collect()
    };

    // Check for existing limbo roles.
    {
      let limbo = &mut *LIMBO_ROLES.lock().unwrap();
      for role in &roles {
        // If the server has updated to contain the limbo role, remove it.
        if let Some(i) = limbo.iter().position(|x| x.id == role.id) {
          limbo.remove(i);
        }
      }
    }
    // Get a copy of the limbo roles.
    let limbo = LIMBO_ROLES.lock().unwrap().clone();
    // Extend the server roles with the limbo roles.
    roles.extend(limbo);

    // Find or create the necessary roles
    let mut created_roles = Vec::new();
    let mut add_roles = Vec::new();
    Tagger::find_or_create_role(on, &character.data.race, &mut add_roles, &mut created_roles)?;
    Tagger::find_or_create_role(on, &character.data.gender, &mut add_roles, &mut created_roles)?;
    Tagger::find_or_create_role_and(on, &character.server, &mut add_roles, &mut created_roles, |r| r.hoist(true))?;

    if is_verified {
      Tagger::find_or_create_role(on, "verified", &mut add_roles, &mut created_roles)?;
    }

    // If we created any roles, the server may or may not update with them fast enough, so store a copy in the limbo
    // roles.
    {
      let limbo = &mut *LIMBO_ROLES.lock().unwrap();
      for created in &created_roles {
        limbo.push(created.clone());
      }
    }

    debug!("Created the following roles:\n:{:#?}", created_roles);

    debug!("Existing roles:\n{:#?}", add_roles);

    // Extend the roles to add with the roles we created.
    add_roles.extend(created_roles);
    // Get all the roles that are part of groups
    let all_group_roles: Vec<String> = env.config.roles.groups.iter().flat_map(|x| x).map(|x| x.to_lowercase()).collect();
    // Filter all roles on the server to only the roles the member has
    let keep: Vec<&Role> = roles.iter().filter(|x| member.roles.contains(&x.id)).collect();
    // Filter all the roles the member has, keeping the ones not in a group. These roles will not be touched when
    // updating the tag.
    let keep: Vec<&Role> = keep.into_iter().filter(|x| !all_group_roles.contains(&x.name.to_lowercase())).collect();
    debug!("Roles to keep:\n{:#?}", keep);
    // Combine the two sets of roles and map them to IDs
    let mut role_set: Vec<RoleId> = add_roles.iter().map(|r| r.id).chain(keep.into_iter().map(|r| r.id)).collect();
    // Sort the IDs so we can dedup them
    role_set.sort();
    // Remove the duplicate roles, if any
    role_set.dedup();

    debug!("Final role set:\n{:#?}", role_set);

    // Only update the roles if they are different
    let different = {
      let member_roles: HashSet<u64> = member.roles.iter().map(|x| x.0).collect();
      let actual_role_set: HashSet<u64> = role_set.iter().map(|x| x.0).collect();
      member_roles != actual_role_set
    };
    if different {
      on.edit_member(who, |m| m.roles(&role_set)).chain_err(|| "could not add roles")?;
    }

    // cannot edit nickname of those with a higher role
    let nick = match member.nick {
      Some(n) => n,
      None => Default::default()
    };
    if nick != character.name {
      on.edit_member(who, |m| m.nickname(&character.name)).ok();
    }
    Ok(None)
  }
}

#[derive(Debug, Deserialize)]
struct DiscordNotFoundError {
  code: u64,
  message: Option<String>
}
<|endoftext|>


<commit_before>extern crate clap;

use clap::{App, Arg, SubCommand, AppSettings, ErrorKind};

#[test]
fn sub_command_negate_required() {
    App::new("sub_command_negate")
        .setting(AppSettings::SubcommandsNegateReqs)
        .arg(Arg::with_name("test")
               .required(true)
               .index(1))
        .subcommand(SubCommand::with_name("sub1"))
        .get_matches_from(vec!["myprog", "sub1"]);
}

#[test]
fn global_version() {
    let app = App::new("global_version")
        .setting(AppSettings::GlobalVersion)
        .version("1.1")
        .subcommand(SubCommand::with_name("sub1"));
    assert_eq!(app.p.subcommands[0].p.meta.version, Some("1.1"));
}

#[test]
fn sub_command_negate_required_2() {
    let result = App::new("sub_command_negate")
        .setting(AppSettings::SubcommandsNegateReqs)
        .arg(Arg::with_name("test")
               .required(true)
               .index(1))
        .subcommand(SubCommand::with_name("sub1"))
        .get_matches_from_safe(vec![""]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
}

#[test]
fn sub_command_required() {
    let result = App::new("sc_required")
        .setting(AppSettings::SubcommandRequired)
        .subcommand(SubCommand::with_name("sub1"))
        .get_matches_from_safe(vec![""]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::MissingSubcommand);
}

#[test]
fn arg_required_else_help() {
    let result = App::new("arg_required")
        .setting(AppSettings::ArgRequiredElseHelp)
        .arg(Arg::with_name("test")
               .index(1))
        .get_matches_from_safe(vec![""]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::MissingArgumentOrSubcommand);
}

#[test]
fn no_bin_name() {
    let result = App::new("arg_required")
        .setting(AppSettings::NoBinaryName)
        .arg(Arg::with_name("test")
               .required(true)
               .index(1))
        .get_matches_from_safe(vec!["testing"]);
    assert!(result.is_ok());
    let matches = result.unwrap();
    assert_eq!(matches.value_of("test").unwrap(), "testing");
}

#[test]
fn unified_help() {
    let mut app = App::new("test")
        .author("Kevin K.")
        .about("tests stuff")
        .version("1.3")
        .setting(AppSettings::UnifiedHelpMessage)
        .args_from_usage("-f, --flag 'some flag'
                          [arg1] 'some pos arg'
                          --option [opt] 'some option'");
    // We call a get_matches method to cause --help and --version to be built
    let _ = app.get_matches_from_safe_borrow(vec![""]);

    // Now we check the output of print_help()
    let mut help = vec![];
    app.write_help(&mut help).ok().expect("failed to print help");
    assert_eq!(&*String::from_utf8_lossy(&*help), &*String::from("test 1.3\n\
Kevin K.
tests stuff

USAGE:
    test [OPTIONS] [arg1]

OPTIONS:
    -f, --flag            some flag
    -h, --help            Prints help information
        --option <opt>    some option
    -V, --version         Prints version information

ARGS:
    <arg1>    some pos arg"));
}

#[test]
fn skip_possible_values() {
    let mut app = App::new("test")
        .author("Kevin K.")
        .about("tests stuff")
        .version("1.3")
        .setting(AppSettings::HidePossibleValuesInHelp)
        .args(&[Arg::from_usage("-o, --opt [opt] 'some option'").possible_values(&["one", "two"]),
                Arg::from_usage("[arg1] 'some pos arg'").possible_values(&["three", "four"])]);
    // We call a get_matches method to cause --help and --version to be built
    let _ = app.get_matches_from_safe_borrow(vec![""]);

    // Now we check the output of print_help()
    let mut help = vec![];
    app.write_help(&mut help).expect("failed to print help");
    assert_eq!(&*String::from_utf8_lossy(&*help), &*String::from("test 1.3\n\
Kevin K.
tests stuff

USAGE:
    test [OPTIONS] [arg1]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
    -o, --opt <opt>    some option

ARGS:
    <arg1>    some pos arg"));
}

#[test]
fn global_setting() {
    let app = App::new("test")
        .global_setting(AppSettings::ColoredHelp)
        .subcommand(SubCommand::with_name("subcmd"));
    assert!(app.p
               .subcommands
               .iter()
               .filter(|s| s.p
                            .meta
                            .name == "subcmd")
               .next()
               .unwrap()
               .p
               .is_set(AppSettings::ColoredHelp));
}

#[test]
fn global_settings() {
    let app = App::new("test")
        .global_settings(&[AppSettings::ColoredHelp, AppSettings::TrailingVarArg])
        .subcommand(SubCommand::with_name("subcmd"));
    assert!(app.p
               .subcommands
               .iter()
               .filter(|s| s.p
                            .meta
                            .name == "subcmd")
               .next()
               .unwrap()
               .p
               .is_set(AppSettings::ColoredHelp));
    assert!(app.p
               .subcommands
               .iter()
               .filter(|s| s.p
                            .meta
                            .name == "subcmd")
               .next()
               .unwrap()
               .p
               .is_set(AppSettings::TrailingVarArg));

}

#[test]
fn stop_delim_values_only_pos_follows() {
    let r = App::new("onlypos")
        .setting(AppSettings::DontDelimitTrailingValues)
        .args(&[Arg::from_usage("-f [flag] 'some opt'"),
                Arg::from_usage("[arg]... 'some arg'")])
        .get_matches_from_safe(vec!["", "--", "-f", "-g,x"]);
    assert!(r.is_ok());
    let m = r.unwrap();
    assert!(m.is_present("arg"));
    assert!(!m.is_present("f"));
    assert_eq!(m.values_of("arg").unwrap().collect::<Vec<_>>(), &["-f", "-g,x"]);
}

#[test]
fn dont_delim_values_trailingvararg() {
    let m = App::new("positional")
        .setting(AppSettings::TrailingVarArg)
        .setting(AppSettings::DontDelimitTrailingValues)
        .arg(
            Arg::from_usage("[opt]... 'some pos'"),
        )
        .get_matches_from(vec!["", "test", "--foo", "-Wl,-bar"]);
    assert!(m.is_present("opt"));
    assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["test", "--foo", "-Wl,-bar"]);
}

#[test]
fn delim_values_only_pos_follows() {
    let r = App::new("onlypos")
        .args(&[Arg::from_usage("-f [flag] 'some opt'"),
                Arg::from_usage("[arg]... 'some arg'")])
        .get_matches_from_safe(vec!["", "--", "-f", "-g,x"]);
    assert!(r.is_ok());
    let m = r.unwrap();
    assert!(m.is_present("arg"));
    assert!(!m.is_present("f"));
    assert_eq!(m.values_of("arg").unwrap().collect::<Vec<_>>(), &["-f", "-g", "x"]);
}

#[test]
fn delim_values_trailingvararg() {
    let m = App::new("positional")
        .setting(AppSettings::TrailingVarArg)
        .arg(
            Arg::from_usage("[opt]... 'some pos'"),
        )
        .get_matches_from(vec!["", "test", "--foo", "-Wl,-bar"]);
    assert!(m.is_present("opt"));
    assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["test", "--foo", "-Wl", "-bar"]);
}
<commit_msg>tests: adds tests for leading hyphen issues<commit_after>extern crate clap;

use clap::{App, Arg, SubCommand, AppSettings, ErrorKind};

#[test]
fn sub_command_negate_required() {
    App::new("sub_command_negate")
        .setting(AppSettings::SubcommandsNegateReqs)
        .arg(Arg::with_name("test")
               .required(true)
               .index(1))
        .subcommand(SubCommand::with_name("sub1"))
        .get_matches_from(vec!["myprog", "sub1"]);
}

#[test]
fn global_version() {
    let app = App::new("global_version")
        .setting(AppSettings::GlobalVersion)
        .version("1.1")
        .subcommand(SubCommand::with_name("sub1"));
    assert_eq!(app.p.subcommands[0].p.meta.version, Some("1.1"));
}

#[test]
fn sub_command_negate_required_2() {
    let result = App::new("sub_command_negate")
        .setting(AppSettings::SubcommandsNegateReqs)
        .arg(Arg::with_name("test")
               .required(true)
               .index(1))
        .subcommand(SubCommand::with_name("sub1"))
        .get_matches_from_safe(vec![""]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
}

#[test]
fn sub_command_required() {
    let result = App::new("sc_required")
        .setting(AppSettings::SubcommandRequired)
        .subcommand(SubCommand::with_name("sub1"))
        .get_matches_from_safe(vec![""]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::MissingSubcommand);
}

#[test]
fn arg_required_else_help() {
    let result = App::new("arg_required")
        .setting(AppSettings::ArgRequiredElseHelp)
        .arg(Arg::with_name("test")
               .index(1))
        .get_matches_from_safe(vec![""]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::MissingArgumentOrSubcommand);
}

#[test]
fn no_bin_name() {
    let result = App::new("arg_required")
        .setting(AppSettings::NoBinaryName)
        .arg(Arg::with_name("test")
               .required(true)
               .index(1))
        .get_matches_from_safe(vec!["testing"]);
    assert!(result.is_ok());
    let matches = result.unwrap();
    assert_eq!(matches.value_of("test").unwrap(), "testing");
}

#[test]
fn unified_help() {
    let mut app = App::new("test")
        .author("Kevin K.")
        .about("tests stuff")
        .version("1.3")
        .setting(AppSettings::UnifiedHelpMessage)
        .args_from_usage("-f, --flag 'some flag'
                          [arg1] 'some pos arg'
                          --option [opt] 'some option'");
    // We call a get_matches method to cause --help and --version to be built
    let _ = app.get_matches_from_safe_borrow(vec![""]);

    // Now we check the output of print_help()
    let mut help = vec![];
    app.write_help(&mut help).ok().expect("failed to print help");
    assert_eq!(&*String::from_utf8_lossy(&*help), &*String::from("test 1.3\n\
Kevin K.
tests stuff

USAGE:
    test [OPTIONS] [arg1]

OPTIONS:
    -f, --flag            some flag
    -h, --help            Prints help information
        --option <opt>    some option
    -V, --version         Prints version information

ARGS:
    <arg1>    some pos arg"));
}

#[test]
fn skip_possible_values() {
    let mut app = App::new("test")
        .author("Kevin K.")
        .about("tests stuff")
        .version("1.3")
        .setting(AppSettings::HidePossibleValuesInHelp)
        .args(&[Arg::from_usage("-o, --opt [opt] 'some option'").possible_values(&["one", "two"]),
                Arg::from_usage("[arg1] 'some pos arg'").possible_values(&["three", "four"])]);
    // We call a get_matches method to cause --help and --version to be built
    let _ = app.get_matches_from_safe_borrow(vec![""]);

    // Now we check the output of print_help()
    let mut help = vec![];
    app.write_help(&mut help).expect("failed to print help");
    assert_eq!(&*String::from_utf8_lossy(&*help), &*String::from("test 1.3\n\
Kevin K.
tests stuff

USAGE:
    test [OPTIONS] [arg1]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
    -o, --opt <opt>    some option

ARGS:
    <arg1>    some pos arg"));
}

#[test]
fn global_setting() {
    let app = App::new("test")
        .global_setting(AppSettings::ColoredHelp)
        .subcommand(SubCommand::with_name("subcmd"));
    assert!(app.p
               .subcommands
               .iter()
               .filter(|s| s.p
                            .meta
                            .name == "subcmd")
               .next()
               .unwrap()
               .p
               .is_set(AppSettings::ColoredHelp));
}

#[test]
fn global_settings() {
    let app = App::new("test")
        .global_settings(&[AppSettings::ColoredHelp, AppSettings::TrailingVarArg])
        .subcommand(SubCommand::with_name("subcmd"));
    assert!(app.p
               .subcommands
               .iter()
               .filter(|s| s.p
                            .meta
                            .name == "subcmd")
               .next()
               .unwrap()
               .p
               .is_set(AppSettings::ColoredHelp));
    assert!(app.p
               .subcommands
               .iter()
               .filter(|s| s.p
                            .meta
                            .name == "subcmd")
               .next()
               .unwrap()
               .p
               .is_set(AppSettings::TrailingVarArg));

}

#[test]
fn stop_delim_values_only_pos_follows() {
    let r = App::new("onlypos")
        .setting(AppSettings::DontDelimitTrailingValues)
        .args(&[Arg::from_usage("-f [flag] 'some opt'"),
                Arg::from_usage("[arg]... 'some arg'")])
        .get_matches_from_safe(vec!["", "--", "-f", "-g,x"]);
    assert!(r.is_ok());
    let m = r.unwrap();
    assert!(m.is_present("arg"));
    assert!(!m.is_present("f"));
    assert_eq!(m.values_of("arg").unwrap().collect::<Vec<_>>(), &["-f", "-g,x"]);
}

#[test]
fn dont_delim_values_trailingvararg() {
    let m = App::new("positional")
        .setting(AppSettings::TrailingVarArg)
        .setting(AppSettings::DontDelimitTrailingValues)
        .arg(
            Arg::from_usage("[opt]... 'some pos'"),
        )
        .get_matches_from(vec!["", "test", "--foo", "-Wl,-bar"]);
    assert!(m.is_present("opt"));
    assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["test", "--foo", "-Wl,-bar"]);
}

#[test]
fn delim_values_only_pos_follows() {
    let r = App::new("onlypos")
        .args(&[Arg::from_usage("-f [flag] 'some opt'"),
                Arg::from_usage("[arg]... 'some arg'")])
        .get_matches_from_safe(vec!["", "--", "-f", "-g,x"]);
    assert!(r.is_ok());
    let m = r.unwrap();
    assert!(m.is_present("arg"));
    assert!(!m.is_present("f"));
    assert_eq!(m.values_of("arg").unwrap().collect::<Vec<_>>(), &["-f", "-g", "x"]);
}

#[test]
fn delim_values_trailingvararg() {
    let m = App::new("positional")
        .setting(AppSettings::TrailingVarArg)
        .arg(
            Arg::from_usage("[opt]... 'some pos'"),
        )
        .get_matches_from(vec!["", "test", "--foo", "-Wl,-bar"]);
    assert!(m.is_present("opt"));
    assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["test", "--foo", "-Wl", "-bar"]);
}

#[test]
fn leading_double_hyphen_trailingvararg() {
    let m = App::new("positional")
        .setting(AppSettings::TrailingVarArg)
        .setting(AppSettings::AllowLeadingHyphen)
        .arg(
            Arg::from_usage("[opt]... 'some pos'"),
        )
        .get_matches_from(vec!["", "--foo", "-Wl", "bar"]);
    assert!(m.is_present("opt"));
    assert_eq!(m.values_of("opt").unwrap().collect::<Vec<_>>(), &["--foo", "-Wl", "bar"]);
}
<|endoftext|>


<commit_before>extern crate cargotest;
extern crate hamcrest;

use cargotest::ChannelChanger;
use cargotest::support::registry::{self, Package};
use cargotest::support::{project, execs};
use hamcrest::assert_that;

#[test]
fn is_feature_gated() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [project]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies.bar]
            version = "0.0.1"
            registry = "alternative"
        "#)
        .file("src/main.rs", "fn main() {}");
    p.build();

    Package::new("bar", "0.0.1").alternative(true).publish();

    assert_that(p.cargo("build").masquerade_as_nightly_cargo(),
                execs().with_status(101)
                .with_stderr_contains("  feature `alternative-registries` is required"));
}

#[test]
fn depend_on_alt_registry() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            cargo-features = ["alternative-registries"]

            [project]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies.bar]
            version = "0.0.1"
            registry = "alternative"
        "#)
        .file("src/main.rs", "fn main() {}");
    p.build();

    Package::new("bar", "0.0.1").alternative(true).publish();

    assert_that(p.cargo("build").masquerade_as_nightly_cargo(),
                execs().with_status(0).with_stderr(&format!("\
[UPDATING] registry `{reg}`
[DOWNLOADING] bar v0.0.1 (registry `file://[..]`)
[COMPILING] bar v0.0.1 (registry `file://[..]`)
[COMPILING] foo v0.0.1 ({dir})
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] secs
",
        dir = p.url(),
        reg = registry::alt_registry())));

    assert_that(p.cargo("clean").masquerade_as_nightly_cargo(), execs().with_status(0));

    // Don't download a second time
    assert_that(p.cargo("build").masquerade_as_nightly_cargo(),
                execs().with_status(0).with_stderr(&format!("\
[COMPILING] bar v0.0.1 (registry `file://[..]`)
[COMPILING] foo v0.0.1 ({dir})
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] secs
",
        dir = p.url())));
}

#[test]
fn registry_incompatible_with_path() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            cargo-features = ["alternative-registries"]

            [project]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies.bar]
            path = ""
            registry = "alternative"
        "#)
        .file("src/main.rs", "fn main() {}");
    p.build();

    assert_that(p.cargo("build").masquerade_as_nightly_cargo(),
                execs().with_status(101)
                .with_stderr_contains("  dependency (bar) specification is ambiguous. Only one of `path` or `registry` is allowed."));
}

#[test]
fn registry_incompatible_with_git() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            cargo-features = ["alternative-registries"]

            [project]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies.bar]
            git = ""
            registry = "alternative"
        "#)
        .file("src/main.rs", "fn main() {}");
    p.build();

    assert_that(p.cargo("build").masquerade_as_nightly_cargo(),
                execs().with_status(101)
                .with_stderr_contains("  dependency (bar) specification is ambiguous. Only one of `git` or `registry` is allowed."));
}

#[test]
fn cannot_publish_with_registry_dependency() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            cargo-features = ["alternative-registries"]

            [project]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies.bar]
            version = "0.0.1"
            registry = "alternative"
        "#)
        .file("src/main.rs", "fn main() {}");
    p.build();

    Package::new("bar", "0.0.1").alternative(true).publish();

    assert_that(p.cargo("publish").masquerade_as_nightly_cargo()
                 .arg("--index").arg(registry::alt_registry().to_string()),
                execs().with_status(101));
}

#[test]
fn alt_registry_and_crates_io_deps() {

    let p = project("foo")
        .file("Cargo.toml", r#"
            cargo-features = ["alternative-registries"]

            [project]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies]
            crates_io_dep = "0.0.1"

            [dependencies.alt_reg_dep]
            version = "0.1.0"
            registry = "alternative"
        "#)
        .file("src/main.rs", "fn main() {}");
    p.build();

    Package::new("crates_io_dep", "0.0.1").publish();
    Package::new("alt_reg_dep", "0.1.0").alternative(true).publish();

    assert_that(p.cargo("build").masquerade_as_nightly_cargo(),
                execs().with_status(0)
                       .with_stderr_contains(format!("\
[UPDATING] registry `{}`", registry::alt_registry()))
                       .with_stderr_contains(&format!("\
[UPDATING] registry `{}`", registry::registry()))
                       .with_stderr_contains("\
[DOWNLOADING] crates_io_dep v0.0.1 (registry `file://[..]`)")
                       .with_stderr_contains("\
[DOWNLOADING] alt_reg_dep v0.1.0 (registry `file://[..]`)")
                       .with_stderr_contains("\
[COMPILING] alt_reg_dep v0.1.0 (registry `file://[..]`)")
                       .with_stderr_contains("\
[COMPILING] crates_io_dep v0.0.1")
                       .with_stderr_contains(&format!("\
[COMPILING] foo v0.0.1 ({})", p.url()))
                       .with_stderr_contains("\
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] secs"))

}

#[test]
fn alt_registry_dep_with_crates_io_dep() {

    let p = project("foo")
        .file("Cargo.toml", r#"
            cargo-features = ["alternative-registries"]

            [project]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies.alt_reg_dep]
            version = "0.1.1"
            registry = "alternative"
        "#)
        .file("src/main.rs", "fn main() {}");
    p.build();

    Package::new("crates_io_dep", "0.0.2").publish();
    Package::new("alt_reg_dep", "0.1.1").alternative(true).registry_dep("crates_io_dep", "0.0.2", registry::registry().as_str()).publish();

    assert_that(p.cargo("build").masquerade_as_nightly_cargo(),
                execs().with_status(0).with_stderr(&format!("\
[UPDATING] registry `{alt_reg}`
[UPDATING] registry `{crates_io_reg}`
[DOWNLOADING] alt_reg_dep v0.1.1 (registry `file://[..]`)
[DOWNLOADING] crates_io_dep v0.0.2 (registry `file://[..]`)
[COMPILING] crates_io_dep v0.0.2 (registry `file://[..]`)
[COMPILING] alt_reg_dep v0.1.1 (registry `file://[..]`)
[COMPILING] foo v0.0.1 ({dir})
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] secs
",
        dir = p.url(),
        crates_io_reg = registry::registry(),
        alt_reg = registry::alt_registry())));
}
<commit_msg>Adding test for alternate registry dependency, with alternate registry dependency.<commit_after>extern crate cargotest;
extern crate hamcrest;

use cargotest::ChannelChanger;
use cargotest::support::registry::{self, Package};
use cargotest::support::{project, execs};
use hamcrest::assert_that;

#[test]
fn is_feature_gated() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [project]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies.bar]
            version = "0.0.1"
            registry = "alternative"
        "#)
        .file("src/main.rs", "fn main() {}");
    p.build();

    Package::new("bar", "0.0.1").alternative(true).publish();

    assert_that(p.cargo("build").masquerade_as_nightly_cargo(),
                execs().with_status(101)
                .with_stderr_contains("  feature `alternative-registries` is required"));
}

#[test]
fn depend_on_alt_registry() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            cargo-features = ["alternative-registries"]

            [project]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies.bar]
            version = "0.0.1"
            registry = "alternative"
        "#)
        .file("src/main.rs", "fn main() {}");
    p.build();

    Package::new("bar", "0.0.1").alternative(true).publish();

    assert_that(p.cargo("build").masquerade_as_nightly_cargo(),
                execs().with_status(0).with_stderr(&format!("\
[UPDATING] registry `{reg}`
[DOWNLOADING] bar v0.0.1 (registry `file://[..]`)
[COMPILING] bar v0.0.1 (registry `file://[..]`)
[COMPILING] foo v0.0.1 ({dir})
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] secs
",
        dir = p.url(),
        reg = registry::alt_registry())));

    assert_that(p.cargo("clean").masquerade_as_nightly_cargo(), execs().with_status(0));

    // Don't download a second time
    assert_that(p.cargo("build").masquerade_as_nightly_cargo(),
                execs().with_status(0).with_stderr(&format!("\
[COMPILING] bar v0.0.1 (registry `file://[..]`)
[COMPILING] foo v0.0.1 ({dir})
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] secs
",
        dir = p.url())));
}

#[test]
fn registry_incompatible_with_path() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            cargo-features = ["alternative-registries"]

            [project]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies.bar]
            path = ""
            registry = "alternative"
        "#)
        .file("src/main.rs", "fn main() {}");
    p.build();

    assert_that(p.cargo("build").masquerade_as_nightly_cargo(),
                execs().with_status(101)
                .with_stderr_contains("  dependency (bar) specification is ambiguous. Only one of `path` or `registry` is allowed."));
}

#[test]
fn registry_incompatible_with_git() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            cargo-features = ["alternative-registries"]

            [project]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies.bar]
            git = ""
            registry = "alternative"
        "#)
        .file("src/main.rs", "fn main() {}");
    p.build();

    assert_that(p.cargo("build").masquerade_as_nightly_cargo(),
                execs().with_status(101)
                .with_stderr_contains("  dependency (bar) specification is ambiguous. Only one of `git` or `registry` is allowed."));
}

#[test]
fn cannot_publish_with_registry_dependency() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            cargo-features = ["alternative-registries"]

            [project]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies.bar]
            version = "0.0.1"
            registry = "alternative"
        "#)
        .file("src/main.rs", "fn main() {}");
    p.build();

    Package::new("bar", "0.0.1").alternative(true).publish();

    assert_that(p.cargo("publish").masquerade_as_nightly_cargo()
                 .arg("--index").arg(registry::alt_registry().to_string()),
                execs().with_status(101));
}

#[test]
fn alt_registry_and_crates_io_deps() {

    let p = project("foo")
        .file("Cargo.toml", r#"
            cargo-features = ["alternative-registries"]

            [project]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies]
            crates_io_dep = "0.0.1"

            [dependencies.alt_reg_dep]
            version = "0.1.0"
            registry = "alternative"
        "#)
        .file("src/main.rs", "fn main() {}");
    p.build();

    Package::new("crates_io_dep", "0.0.1").publish();
    Package::new("alt_reg_dep", "0.1.0").alternative(true).publish();

    assert_that(p.cargo("build").masquerade_as_nightly_cargo(),
                execs().with_status(0)
                       .with_stderr_contains(format!("\
[UPDATING] registry `{}`", registry::alt_registry()))
                       .with_stderr_contains(&format!("\
[UPDATING] registry `{}`", registry::registry()))
                       .with_stderr_contains("\
[DOWNLOADING] crates_io_dep v0.0.1 (registry `file://[..]`)")
                       .with_stderr_contains("\
[DOWNLOADING] alt_reg_dep v0.1.0 (registry `file://[..]`)")
                       .with_stderr_contains("\
[COMPILING] alt_reg_dep v0.1.0 (registry `file://[..]`)")
                       .with_stderr_contains("\
[COMPILING] crates_io_dep v0.0.1")
                       .with_stderr_contains(&format!("\
[COMPILING] foo v0.0.1 ({})", p.url()))
                       .with_stderr_contains("\
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] secs"))

}

#[test]
fn alt_registry_dep_with_crates_io_dep() {

    let p = project("foo")
        .file("Cargo.toml", r#"
            cargo-features = ["alternative-registries"]

            [project]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies.alt_reg_dep]
            version = "0.1.1"
            registry = "alternative"
        "#)
        .file("src/main.rs", "fn main() {}");
    p.build();

    Package::new("crates_io_dep", "0.0.2").publish();
    Package::new("alt_reg_dep", "0.1.1").alternative(true).registry_dep("crates_io_dep", "0.0.2", registry::registry().as_str()).publish();

    assert_that(p.cargo("build").masquerade_as_nightly_cargo(),
                execs().with_status(0).with_stderr(&format!("\
[UPDATING] registry `{alt_reg}`
[UPDATING] registry `{crates_io_reg}`
[DOWNLOADING] alt_reg_dep v0.1.1 (registry `file://[..]`)
[DOWNLOADING] crates_io_dep v0.0.2 (registry `file://[..]`)
[COMPILING] crates_io_dep v0.0.2 (registry `file://[..]`)
[COMPILING] alt_reg_dep v0.1.1 (registry `file://[..]`)
[COMPILING] foo v0.0.1 ({dir})
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] secs
",
        dir = p.url(),
        crates_io_reg = registry::registry(),
        alt_reg = registry::alt_registry())));
}

#[test]
fn alt_reg_dep_with_alt_reg_dep() {

    let p = project("foo")
        .file("Cargo.toml", r#"
            cargo-features = ["alternative-registries"]

            [project]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies.bar]
            version = "0.1.1"
            registry = "alternative"
        "#)
        .file("src/main.rs", "fn main() {}");
    p.build();

    Package::new("baz", "0.0.2").alternative(true).publish();
    Package::new("bar", "0.1.1").alternative(true).registry_dep("baz", "0.0.2", registry::alt_registry().as_str()).publish();

    assert_that(p.cargo("build").masquerade_as_nightly_cargo(),
                execs().with_status(0).with_stderr(&format!("\
[UPDATING] registry `{alt_reg}`
[DOWNLOADING] bar v0.1.1 (registry `file://[..]`)
[DOWNLOADING] baz v0.0.2 (registry `file://[..]`)
[COMPILING] baz v0.0.2 (registry `file://[..]`)
[COMPILING] bar v0.1.1 (registry `file://[..]`)
[COMPILING] foo v0.0.1 ({dir})
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] secs
",
        dir = p.url(),
        alt_reg = registry::alt_registry())));
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;
#[macro_use]
extern crate serde_json;

extern crate difference;
extern crate meta;
extern crate serde;
extern crate term;

use std::fs::File;
use std::io::prelude::*;
use std::io;

use clap::{Arg, App};
use difference::{Changeset, Difference};
use term::Terminal;

use meta::{TaskIndex, Task};

const ABOUT: &'static str = r#"
Query differences between the rust-rosetta repository and the Rosetta Code wiki.

This script prints out the name of each task, followed by whether it is implemented online,
locally, or both.

If no tasks are specified, determines the status for all tasks."#;

arg_enum!{
    #[derive(Debug)]
    enum Filter {
        All,
        LocalOnly,
        RemoteOnly,
        Unimplemented
    }
}

impl Default for Filter {
    fn default() -> Self {
        Filter::All
    }
}

/// Prints a colored diff of two strings to the terminal.
fn print_diff<T: ?Sized>(t: &mut T, s1: &str, s2: &str) -> io::Result<()>
where
    T: Terminal,
{
    let changeset = Changeset::new(&s1, &s2, "\n");

    for change in changeset.diffs {
        match change {
            Difference::Same(ref x) => {
                try!(t.reset());
                try!(writeln!(t, " {}", x));
            }
            Difference::Add(ref x) => {
                try!(t.fg(term::color::GREEN));
                for line in x.split("\n") {
                    try!(writeln!(t, "+{}", line));
                }
            }
            Difference::Rem(ref x) => {
                try!(t.fg(term::color::RED));
                for line in x.split("\n") {
                    try!(writeln!(t, "-{}", line));
                }
            }
        }
    }
    try!(t.reset());
    try!(t.flush());
    Ok(())
}

/// Prints a task in a human-readable format.
fn print_task<T: ?Sized>(t: &mut T, task: &Task, diff: bool) -> io::Result<()>
where
    T: Terminal,
{
    try!(t.attr(term::Attr::Bold));
    try!(writeln!(t, "{}", task.title()));
    try!(t.reset());

    try!(write!(t, "Local:"));
    try!(write_status(t, task.local_code().is_some()));

    try!(write!(t, "Remote:"));
    try!(write_status(t, task.remote_code().is_some()));
    try!(writeln!(t, ""));

    if let (Some(ref local_code), Some(ref remote_code)) = (task.local_code(), task.remote_code()) {
        if diff {
            try!(print_diff(t, remote_code, local_code));
        }
    }

    Ok(())
}

/// Writes a boolean as a pretty, human-readable string.
fn write_status<T: ?Sized>(t: &mut T, boolean: bool) -> io::Result<()>
where
    T: Terminal,
{
    try!(t.attr(term::Attr::Bold));

    if boolean {
        try!(t.fg(term::color::GREEN));
        try!(write!(t, " ✔ "))
    } else {
        try!(t.fg(term::color::RED));
        try!(write!(t, " ✘ "));
    }

    try!(t.reset());
    Ok(())
}

fn main() {
    let matches = App::new("coverage")
        .about(ABOUT)
        .version(crate_version!())
        .max_term_width(100)
        .arg(
            Arg::with_name("task")
                .help("The name of a task on the wiki, such as 'K-d tree'")
                .multiple(true),
        )
        .arg(
            Arg::with_name("diff")
                .help("Print diffs of tasks between the local and remote version")
                .long("diff"),
        )
        .arg(
            Arg::with_name("filter")
                .help("Filter tasks printed by the program.")
                .possible_values(&["all", "local", "remote", "unimplemented"])
                .long("filter")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("json-file")
                .help("Dump json to the provided filename")
                .long("json")
                .takes_value(true),
        )
        .get_matches();

    let mut t = term::stdout().unwrap();

    let filter = value_t!(matches.value_of("filter"), Filter)
        .ok()
        .unwrap_or_default();

    let task_index = TaskIndex::create(env!("CARGO_MANIFEST_DIR")).unwrap();

    let tasks = if let Some(tasks) = matches.values_of("task") {
        let task_names = tasks.map(String::from).collect::<Vec<_>>();
        task_index.fetch_tasks(&task_names)
    } else {
        task_index.fetch_all_tasks()
    };

    let tasks = tasks
        .flat_map(|task| {
            let task = task.unwrap();

            match filter {
                Filter::LocalOnly if !task.is_local_only() => return None,
                Filter::RemoteOnly if !task.is_remote_only() => return None,
                Filter::Unimplemented if !task.is_unimplemented() => return None,
                Filter::All | _ => {}
            }

            print_task(&mut *t, &task, matches.is_present("diff")).unwrap();

            if matches.is_present("json-file") {
                let json = json!({
                    "title": task.title(),
                    "url": task.url().to_string(),
                    "local_code": task.local_code(),
                    "remote_code": task.remote_code(),
                });

                Some(json)
            } else {
                None
            }
        })
        .collect::<Vec<_>>();

    if let Some(filename) = matches.value_of("json-file") {
        let mut file = File::create(filename).unwrap();
        file.write_all(serde_json::to_string_pretty(&tasks).unwrap().as_bytes())
            .unwrap();
    }
}
<commit_msg>clippy & rustfmt<commit_after>#[macro_use]
extern crate clap;
#[macro_use]
extern crate serde_json;

extern crate difference;
extern crate meta;
extern crate serde;
extern crate term;

use std::fs::File;
use std::io::prelude::*;
use std::io;

use clap::{App, Arg};
use difference::{Changeset, Difference};
use term::Terminal;

use meta::{Task, TaskIndex};

const ABOUT: &str = r#"
Query differences between the rust-rosetta repository and the Rosetta Code wiki.

This script prints out the name of each task, followed by whether it is implemented online,
locally, or both.

If no tasks are specified, determines the status for all tasks."#;

arg_enum!{
    #[derive(Debug)]
    enum Filter {
        All,
        LocalOnly,
        RemoteOnly,
        Unimplemented
    }
}

impl Default for Filter {
    fn default() -> Self {
        Filter::All
    }
}

/// Prints a colored diff of two strings to the terminal.
fn print_diff<T: ?Sized>(t: &mut T, s1: &str, s2: &str) -> io::Result<()>
where
    T: Terminal,
{
    let changeset = Changeset::new(s1, s2, "\n");

    for change in changeset.diffs {
        match change {
            Difference::Same(ref x) => {
                try!(t.reset());
                try!(writeln!(t, " {}", x));
            }
            Difference::Add(ref x) => {
                try!(t.fg(term::color::GREEN));
                for line in x.split('\n') {
                    try!(writeln!(t, "+{}", line));
                }
            }
            Difference::Rem(ref x) => {
                try!(t.fg(term::color::RED));
                for line in x.split('\n') {
                    try!(writeln!(t, "-{}", line));
                }
            }
        }
    }
    try!(t.reset());
    try!(t.flush());
    Ok(())
}

/// Prints a task in a human-readable format.
fn print_task<T: ?Sized>(t: &mut T, task: &Task, diff: bool) -> io::Result<()>
where
    T: Terminal,
{
    try!(t.attr(term::Attr::Bold));
    try!(writeln!(t, "{}", task.title()));
    try!(t.reset());

    try!(write!(t, "Local:"));
    try!(write_status(t, task.local_code().is_some()));

    try!(write!(t, "Remote:"));
    try!(write_status(t, task.remote_code().is_some()));
    try!(writeln!(t, ""));

    if let (Some(ref local_code), Some(ref remote_code)) = (task.local_code(), task.remote_code()) {
        if diff {
            try!(print_diff(t, remote_code, local_code));
        }
    }

    Ok(())
}

/// Writes a boolean as a pretty, human-readable string.
fn write_status<T: ?Sized>(t: &mut T, boolean: bool) -> io::Result<()>
where
    T: Terminal,
{
    try!(t.attr(term::Attr::Bold));

    if boolean {
        try!(t.fg(term::color::GREEN));
        try!(write!(t, " ✔ "))
    } else {
        try!(t.fg(term::color::RED));
        try!(write!(t, " ✘ "));
    }

    try!(t.reset());
    Ok(())
}

fn main() {
    let matches = App::new("coverage")
        .about(ABOUT)
        .version(crate_version!())
        .max_term_width(100)
        .arg(
            Arg::with_name("task")
                .help("The name of a task on the wiki, such as 'K-d tree'")
                .multiple(true),
        )
        .arg(
            Arg::with_name("diff")
                .help("Print diffs of tasks between the local and remote version")
                .long("diff"),
        )
        .arg(
            Arg::with_name("filter")
                .help("Filter tasks printed by the program.")
                .possible_values(&["all", "local", "remote", "unimplemented"])
                .long("filter")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("json-file")
                .help("Dump json to the provided filename")
                .long("json")
                .takes_value(true),
        )
        .get_matches();

    let mut t = term::stdout().unwrap();

    let filter = value_t!(matches.value_of("filter"), Filter)
        .ok()
        .unwrap_or_default();

    let task_index = TaskIndex::create(env!("CARGO_MANIFEST_DIR")).unwrap();

    let tasks = if let Some(tasks) = matches.values_of("task") {
        let task_names = tasks.map(String::from).collect::<Vec<_>>();
        task_index.fetch_tasks(&task_names)
    } else {
        task_index.fetch_all_tasks()
    };

    let tasks = tasks
        .flat_map(|task| {
            let task = task.unwrap();

            match filter {
                Filter::LocalOnly if !task.is_local_only() => return None,
                Filter::RemoteOnly if !task.is_remote_only() => return None,
                Filter::Unimplemented if !task.is_unimplemented() => return None,
                Filter::All | _ => {}
            }

            print_task(&mut *t, &task, matches.is_present("diff")).unwrap();

            if matches.is_present("json-file") {
                let json = json!({
                    "title": task.title(),
                    "url": task.url().to_string(),
                    "local_code": task.local_code(),
                    "remote_code": task.remote_code(),
                });

                Some(json)
            } else {
                None
            }
        })
        .collect::<Vec<_>>();

    if let Some(filename) = matches.value_of("json-file") {
        let mut file = File::create(filename).unwrap();
        file.write_all(serde_json::to_string_pretty(&tasks).unwrap().as_bytes())
            .unwrap();
    }
}
<|endoftext|>


<commit_before>// Internal Dependencies ------------------------------------------------------
use ::command::{Command, CommandHandler};
use ::action::{ActionGroup, MessageActions};

// Statics --------------------------------------------------------------------
static HELP_TEXT_ONE: &'static str = "
**The following commands are currently available:**

- `!s <sound>` - Plays the requested sound immediately. See below for details on what `<sound>` can be.
- `!q <sound>` - Queues up the requested sound to be played once all other currently playing / queued sounds have finished.
- `!sounds` [<pattern>, ...] - Show a list of all available sound effects (matching the specified patterns) in a private channel.
- `!delete <effect>` - Deletes the specified sound effect.
- `!rename <old_effect_name> <new_effect_name>` - Renames the specified sound effect.
- `!silence` - Immediately stops all playing sounds and removes all other queued effects.
- `!greeting <add|remove> <user#ident> [<effect_name>]` - Adds or remove a custom greeting for a user.
- `!greetings` - Show a list of all existing custom user greetings in a private channel.
- `!uploader <add|remove> <user#ident> [<effect_name>]` - Adds or remove a user from the list of uploaders for the current server.
- `!uploaders` - Show a list of all users which are whitelisted to upload sound effects to the current server.
- `!alias <add|remove> <name> [<effect_name>, ...]` - Adds or remove a effect alias.
- `!aliases` - Show a list of all existing effect aliases in a private channel.
- `!bans` - Show a list of all banned users for the current server.
- `!ban <add|remove> <user#ident>` - Add or remove user bans.
- `!leave` - Makes the bot leave its current voice channel.
- `!pin` - Pins the bot to its current voice channel.
- `!ip` - Posts the bot's the public IP onto the current channel.
- `!reload` - Reloads the sound list from the on disk flac files.
- `!help` - Displays this help text.
";

static HELP_TEXT_TWO: &'static str = "**Sound Effects**

Sound effects can be played by requesting them via the `!s <sound>` command,
where `<sound>` can either be the *full name*, a *group prefix*, or a *wildcard*.

- `full name` - Simply check the `!sounds` listing.
- `group prefix` - This is the part of a sound name before the first `_`  character (e.g. `siw` is the *group prefix* for `siw_kaffee` etc.), requesting a *group prefix* will select a random sound from the group.
- `wildcards` - These are either `*` for any random sound or `*word*` for any sound effect which contains the specified word part.

**Effect File Uploads**

Sound effects can be directly uploaded by whitelisted users via the default discord file upload feature.

The filename must be at least 3 characters long, the file extension must be `flac` and the file itself must be a valid flac file encoded at 48khz and 16bit with at most 2 MiB.

Also, a effect with the same name may not yet exist.";

// Command Implementation -----------------------------------------------------
pub struct Handler;

impl CommandHandler for Handler {

    delete_command_message!();

    fn run(&self, command: Command) -> ActionGroup {
        vec![
            MessageActions::Send::single_private(
                &command.message, HELP_TEXT_ONE.to_string()
            ),
            MessageActions::Send::single_private(
                &command.message, HELP_TEXT_TWO.to_string()
            )
        ]
    }

}

<commit_msg>Update help text to include streamer watch commands.<commit_after>// Internal Dependencies ------------------------------------------------------
use ::command::{Command, CommandHandler};
use ::action::{ActionGroup, MessageActions};

// Statics --------------------------------------------------------------------
static HELP_TEXT_ONE: &'static str = "
**The following commands are currently available:**

- `!s <sound>` - Plays the requested sound immediately. See below for details on what `<sound>` can be.
- `!q <sound>` - Queues up the requested sound to be played once all other currently playing / queued sounds have finished.
- `!sounds` [<pattern>, ...] - Show a list of all available sound effects (matching the specified patterns) in a private channel.
- `!delete <effect>` - Deletes the specified sound effect.
- `!rename <old_effect_name> <new_effect_name>` - Renames the specified sound effect.
- `!silence` - Immediately stops all playing sounds and removes all other queued effects.
- `!alias <add|remove> <name> [<effect_name>, ...]` - Adds or remove a effect alias.
- `!aliases` - Show a list of all existing effect aliases in a private channel.
- `!bans` - Show a list of all banned users for the current server.
- `!ban <add|remove> <user#ident>` - Add or remove user bans.
- `!greeting <add|remove> <user#ident> [<effect_name>]` - Adds or remove a custom greeting for a user.
- `!greetings` - Show a list of all existing custom user greetings in a private channel.
- `!uploader <add|remove> <user#ident> [<effect_name>]` - Adds or remove a user from the list of uploaders for the current server.
- `!uploaders` - Show a list of all users which are whitelisted to upload sound effects to the current server.
- `!streamer <add|remove> <twitch_nick> [<channel_name>]` - Adds or removes or twitch streamer from the watch list for the specified channel.
- `!streamers` - Show a list of all watched twitch streamers on the current server..
- `!leave` - Makes the bot leave its current voice channel.
- `!pin` - Pins the bot to its current voice channel.
- `!ip` - Posts the bot's the public IP onto the current channel.
- `!reload` - Reloads the sound list from the on disk flac files.
- `!help` - Displays this help text.
";

static HELP_TEXT_TWO: &'static str = "**Sound Effects**

Sound effects can be played by requesting them via the `!s <sound>` command,
where `<sound>` can either be the *full name*, a *group prefix*, or a *wildcard*.

- `full name` - Simply check the `!sounds` listing.
- `group prefix` - This is the part of a sound name before the first `_`  character (e.g. `siw` is the *group prefix* for `siw_kaffee` etc.), requesting a *group prefix* will select a random sound from the group.
- `wildcards` - These are either `*` for any random sound or `*word*` for any sound effect which contains the specified word part.

**Effect File Uploads**

Sound effects can be directly uploaded by whitelisted users via the default discord file upload feature.

The filename must be at least 3 characters long, the file extension must be `flac` and the file itself must be a valid flac file encoded at 48khz and 16bit with at most 2 MiB.

Also, a effect with the same name may not yet exist.";

// Command Implementation -----------------------------------------------------
pub struct Handler;

impl CommandHandler for Handler {

    delete_command_message!();

    fn run(&self, command: Command) -> ActionGroup {
        vec![
            MessageActions::Send::single_private(
                &command.message, HELP_TEXT_ONE.to_string()
            ),
            MessageActions::Send::single_private(
                &command.message, HELP_TEXT_TWO.to_string()
            )
        ]
    }

}

<|endoftext|>


<commit_before>extern crate sdl2;

use sdl2::event::Event;
use sdl2::keyboard::Keycode;

pub enum ViewAction {
    None,
    Quit,
}

pub trait View {
    fn render(&mut self, elapsed: f64) -> ViewAction;
}

fn main()
{
    let context = sdl2::init().unwrap();
    let video = context.video().unwrap();

    let window = video.window("rrthozopsi", 800, 600)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    let mut renderer = window.renderer().build().unwrap();
    let mut event_pump = context.event_pump().unwrap();

    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    break 'running
                },
                Event::KeyDown {..} => {
                    renderer.set_draw_color(sdl2::pixels::Color::RGB(255, 0, 0));
                    renderer.clear();
                    renderer.present();
                },
                _ => {}
            }
        }
    }
}
<commit_msg>View & ViewAction have been removed<commit_after>extern crate sdl2;

fn main()
{
    let context = sdl2::init().unwrap();
    let video = context.video().unwrap();

    let window = video.window("rrthozopsi", 800, 600)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    let mut renderer = window.renderer().build().unwrap();
    let mut event_pump = context.event_pump().unwrap();

    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    break 'running
                },
                Event::KeyDown {..} => {
                    renderer.set_draw_color(sdl2::pixels::Color::RGB(255, 0, 0));
                    renderer.clear();
                    renderer.present();
                },
                _ => {}
            }
        }
    }
}
<|endoftext|>


<commit_before>use types::*;

use cookie_factory::*;

pub fn gen_value<'a>(x: (&'a mut [u8], usize), v: &AMQPValue) -> Result<(&'a mut [u8], usize), GenError> {
    match *v {
        AMQPValue::Boolean(ref b)        => do_gen!(x, gen_type(&v.get_type()) >> gen_boolean(b)),
        AMQPValue::ShortShortInt(ref i)  => do_gen!(x, gen_type(&v.get_type()) >> gen_short_short_int(i)),
        AMQPValue::ShortShortUInt(ref u) => do_gen!(x, gen_type(&v.get_type()) >> gen_short_short_uint(u)),
        AMQPValue::ShortInt(ref i)       => do_gen!(x, gen_type(&v.get_type()) >> gen_short_int(i)),
        AMQPValue::ShortUInt(ref u)      => do_gen!(x, gen_type(&v.get_type()) >> gen_short_uint(u)),
        AMQPValue::LongInt(ref i)        => do_gen!(x, gen_type(&v.get_type()) >> gen_long_int(i)),
        AMQPValue::LongUInt(ref u)       => do_gen!(x, gen_type(&v.get_type()) >> gen_long_uint(u)),
        AMQPValue::LongLongInt(ref i)    => do_gen!(x, gen_type(&v.get_type()) >> gen_long_long_int(i)),
        AMQPValue::LongLongUInt(ref u)   => do_gen!(x, gen_type(&v.get_type()) >> gen_long_long_uint(u)),
        AMQPValue::Float(ref f)          => do_gen!(x, gen_type(&v.get_type()) >> gen_float(f)),
        AMQPValue::Double(ref d)         => do_gen!(x, gen_type(&v.get_type()) >> gen_double(d)),
        AMQPValue::DecimalValue(ref d)   => do_gen!(x, gen_type(&v.get_type()) >> gen_decimal_value(d)),
        AMQPValue::ShortString(ref s)    => do_gen!(x, gen_type(&v.get_type()) >> gen_short_string(s)),
        AMQPValue::LongString(ref s)     => do_gen!(x, gen_type(&v.get_type()) >> gen_long_string(s)),
        AMQPValue::FieldArray(ref a)     => do_gen!(x, gen_type(&v.get_type()) >> gen_field_array(a)),
        AMQPValue::Timestamp(ref t)      => do_gen!(x, gen_type(&v.get_type()) >> gen_timestamp(t)),
        AMQPValue::FieldTable(ref t)     => do_gen!(x, gen_type(&v.get_type()) >> gen_field_table(t)),
        AMQPValue::Void                  => gen_type(x, &v.get_type()),
    }
}

pub fn gen_type<'a>(x: (&'a mut [u8], usize), t: &AMQPType) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_u8!(x, t.get_id() as u8)
}

pub fn gen_boolean<'a>(x: (&'a mut [u8], usize), b: &Boolean) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_u8!(x, if *b { 1 } else { 0 })
}

pub fn gen_short_short_int<'a>(x: (&'a mut [u8], usize), i: &ShortShortInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_i8!(x, *i)
}

pub fn gen_short_short_uint<'a>(x: (&'a mut [u8], usize), u: &ShortShortUInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_u8!(x, *u)
}

pub fn gen_short_int<'a>(x: (&'a mut [u8], usize), i: &ShortInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_i16!(x, *i)
}

pub fn gen_short_uint<'a>(x: (&'a mut [u8], usize), u: &ShortUInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_u16!(x, *u)
}

pub fn gen_long_int<'a>(x: (&'a mut [u8], usize), i: &LongInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_i32!(x, *i)
}

pub fn gen_long_uint<'a>(x: (&'a mut [u8], usize), u: &LongUInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_u32!(x, *u)
}

pub fn gen_long_long_int<'a>(x: (&'a mut [u8], usize), i: &LongLongInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_i64!(x, *i)
}

pub fn gen_long_long_uint<'a>(x: (&'a mut [u8], usize), u: &LongLongUInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_u64!(x, *u)
}

pub fn gen_float<'a>(x: (&'a mut [u8], usize), f: &Float) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_f32!(x, *f)
}

pub fn gen_double<'a>(x: (&'a mut [u8], usize), d: &Double) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_f64!(x, *d)
}

pub fn gen_decimal_value<'a>(x: (&'a mut [u8], usize), d: &DecimalValue) -> Result<(&'a mut [u8], usize), GenError> {
    do_gen!(x, gen_short_short_uint(&d.scale) >> gen_long_uint(&d.value))
}

pub fn gen_short_string<'a>(x: (&'a mut [u8], usize), s: &ShortString) -> Result<(&'a mut [u8], usize), GenError> {
    do_gen!(x, gen_short_short_uint(&(s.len() as ShortShortUInt)) >> gen_slice!(s.as_bytes()))
}

pub fn gen_long_string<'a>(x: (&'a mut [u8], usize), s: &LongString) -> Result<(&'a mut [u8], usize), GenError> {
    do_gen!(x, gen_long_uint(&(s.len() as LongUInt)) >> gen_slice!(s.as_bytes()))
}

pub fn gen_field_array<'a>(x: (&'a mut [u8], usize), a: &FieldArray) -> Result<(&'a mut [u8], usize), GenError> {
    let (x1, index1) = x;
    gen_many_ref!((x1, index1 + 4), a, gen_value).and_then(|(x2, index2)| {
        gen_long_uint((x2, index1), &((index2 - index1 - 4) as LongUInt)).and_then(|(x3, _)| Ok((x3, index2)))
    })
}

pub fn gen_timestamp<'a>(x: (&'a mut [u8], usize), t: &Timestamp) -> Result<(&'a mut [u8], usize), GenError> {
    gen_long_long_uint(x, t)
}

pub fn gen_field_table<'a>(x: (&'a mut [u8], usize), t: &FieldTable) -> Result<(&'a mut [u8], usize), GenError> {
    let (x1, index1) = x;
    gen_many_ref!((x1, index1 + 4), t, gen_field_entry).and_then(|(x2, index2)| {
        gen_long_uint((x2, index1), &((index2 - index1 - 4) as LongUInt)).and_then(|(x3, _)| Ok((x3, index2)))
    })
}

pub fn gen_field_entry<'a>(x: (&'a mut [u8], usize), e: &(&ShortString, &AMQPValue)) -> Result<(&'a mut [u8], usize), GenError> {
    do_gen!(x, gen_short_string(e.0) >> gen_value(e.1))
}

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

    #[test]
    fn test_gen_type() {
        assert_eq!(gen_type((&mut [0], 0), &AMQPType::ShortShortInt).unwrap(), (&mut [98][..], 1));
        assert_eq!(gen_type((&mut [0], 0), &AMQPType::ShortInt).unwrap(),      (&mut [85][..], 1));
    }

    #[test]
    fn test_gen_boolean() {
        assert_eq!(gen_boolean((&mut [0], 0), &false).unwrap(), (&mut [0][..], 1));
        assert_eq!(gen_boolean((&mut [0], 0), &true).unwrap(),  (&mut [1][..], 1));
    }

    #[test]
    fn test_gen_short_short_int() {
        assert_eq!(gen_short_short_int((&mut [0], 0), &0).unwrap(),  (&mut [0][..],   1));
        assert_eq!(gen_short_short_int((&mut [0], 0), &-1).unwrap(), (&mut [255][..], 1));
    }

    #[test]
    fn test_gen_short_short_uint() {
        assert_eq!(gen_short_short_uint((&mut [0], 0), &0).unwrap(),   (&mut [0][..],   1));
        assert_eq!(gen_short_short_uint((&mut [0], 0), &255).unwrap(), (&mut [255][..], 1));
    }

    #[test]
    fn test_gen_short_int() {
        assert_eq!(gen_short_int((&mut [0, 0], 0), &0).unwrap(),  (&mut [0,   0][..],   2));
        assert_eq!(gen_short_int((&mut [0, 0], 0), &-1).unwrap(), (&mut [255, 255][..], 2));
    }

    #[test]
    fn test_gen_short_uint() {
        assert_eq!(gen_short_uint((&mut [0, 0], 0), &0).unwrap(),     (&mut [0,   0][..],   2));
        assert_eq!(gen_short_uint((&mut [0, 0], 0), &65535).unwrap(), (&mut [255, 255][..], 2));
    }

    #[test]
    fn test_gen_long_int() {
        assert_eq!(gen_long_int((&mut [0, 0, 0, 0], 0), &0).unwrap(),  (&mut [0,   0,   0,   0][..],   4));
        assert_eq!(gen_long_int((&mut [0, 0, 0, 0], 0), &-1).unwrap(), (&mut [255, 255, 255, 255][..], 4));
    }

    #[test]
    fn test_gen_long_uint() {
        assert_eq!(gen_long_uint((&mut [0, 0, 0, 0], 0), &0).unwrap(),          (&mut [0,   0,   0,   0][..],   4));
        assert_eq!(gen_long_uint((&mut [0, 0, 0, 0], 0), &4294967295).unwrap(), (&mut [255, 255, 255, 255][..], 4));
    }

    #[test]
    fn test_gen_long_long_int() {
        assert_eq!(gen_long_long_int((&mut [0, 0, 0, 0, 0, 0, 0, 0], 0), &0).unwrap(),  (&mut [0,   0,   0,   0,   0,   0,   0,   0][..],   8));
        assert_eq!(gen_long_long_int((&mut [0, 0, 0, 0, 0, 0, 0, 0], 0), &-1).unwrap(), (&mut [255, 255, 255, 255, 255, 255, 255, 255][..], 8));
    }

    #[test]
    fn test_gen_long_long_uint() {
        assert_eq!(gen_long_long_uint((&mut [0, 0, 0, 0, 0, 0, 0, 0], 0), &0).unwrap(),                    (&mut [0,   0,   0,   0,   0,   0,   0,   0][..],   8));
        assert_eq!(gen_long_long_uint((&mut [0, 0, 0, 0, 0, 0, 0, 0], 0), &18446744073709551615).unwrap(), (&mut [255, 255, 255, 255, 255, 255, 255, 255][..], 8));
    }
}
<commit_msg>types: make a function private<commit_after>use types::*;

use cookie_factory::*;

pub fn gen_value<'a>(x: (&'a mut [u8], usize), v: &AMQPValue) -> Result<(&'a mut [u8], usize), GenError> {
    match *v {
        AMQPValue::Boolean(ref b)        => do_gen!(x, gen_type(&v.get_type()) >> gen_boolean(b)),
        AMQPValue::ShortShortInt(ref i)  => do_gen!(x, gen_type(&v.get_type()) >> gen_short_short_int(i)),
        AMQPValue::ShortShortUInt(ref u) => do_gen!(x, gen_type(&v.get_type()) >> gen_short_short_uint(u)),
        AMQPValue::ShortInt(ref i)       => do_gen!(x, gen_type(&v.get_type()) >> gen_short_int(i)),
        AMQPValue::ShortUInt(ref u)      => do_gen!(x, gen_type(&v.get_type()) >> gen_short_uint(u)),
        AMQPValue::LongInt(ref i)        => do_gen!(x, gen_type(&v.get_type()) >> gen_long_int(i)),
        AMQPValue::LongUInt(ref u)       => do_gen!(x, gen_type(&v.get_type()) >> gen_long_uint(u)),
        AMQPValue::LongLongInt(ref i)    => do_gen!(x, gen_type(&v.get_type()) >> gen_long_long_int(i)),
        AMQPValue::LongLongUInt(ref u)   => do_gen!(x, gen_type(&v.get_type()) >> gen_long_long_uint(u)),
        AMQPValue::Float(ref f)          => do_gen!(x, gen_type(&v.get_type()) >> gen_float(f)),
        AMQPValue::Double(ref d)         => do_gen!(x, gen_type(&v.get_type()) >> gen_double(d)),
        AMQPValue::DecimalValue(ref d)   => do_gen!(x, gen_type(&v.get_type()) >> gen_decimal_value(d)),
        AMQPValue::ShortString(ref s)    => do_gen!(x, gen_type(&v.get_type()) >> gen_short_string(s)),
        AMQPValue::LongString(ref s)     => do_gen!(x, gen_type(&v.get_type()) >> gen_long_string(s)),
        AMQPValue::FieldArray(ref a)     => do_gen!(x, gen_type(&v.get_type()) >> gen_field_array(a)),
        AMQPValue::Timestamp(ref t)      => do_gen!(x, gen_type(&v.get_type()) >> gen_timestamp(t)),
        AMQPValue::FieldTable(ref t)     => do_gen!(x, gen_type(&v.get_type()) >> gen_field_table(t)),
        AMQPValue::Void                  => gen_type(x, &v.get_type()),
    }
}

pub fn gen_type<'a>(x: (&'a mut [u8], usize), t: &AMQPType) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_u8!(x, t.get_id() as u8)
}

pub fn gen_boolean<'a>(x: (&'a mut [u8], usize), b: &Boolean) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_u8!(x, if *b { 1 } else { 0 })
}

pub fn gen_short_short_int<'a>(x: (&'a mut [u8], usize), i: &ShortShortInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_i8!(x, *i)
}

pub fn gen_short_short_uint<'a>(x: (&'a mut [u8], usize), u: &ShortShortUInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_u8!(x, *u)
}

pub fn gen_short_int<'a>(x: (&'a mut [u8], usize), i: &ShortInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_i16!(x, *i)
}

pub fn gen_short_uint<'a>(x: (&'a mut [u8], usize), u: &ShortUInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_u16!(x, *u)
}

pub fn gen_long_int<'a>(x: (&'a mut [u8], usize), i: &LongInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_i32!(x, *i)
}

pub fn gen_long_uint<'a>(x: (&'a mut [u8], usize), u: &LongUInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_u32!(x, *u)
}

pub fn gen_long_long_int<'a>(x: (&'a mut [u8], usize), i: &LongLongInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_i64!(x, *i)
}

pub fn gen_long_long_uint<'a>(x: (&'a mut [u8], usize), u: &LongLongUInt) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_u64!(x, *u)
}

pub fn gen_float<'a>(x: (&'a mut [u8], usize), f: &Float) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_f32!(x, *f)
}

pub fn gen_double<'a>(x: (&'a mut [u8], usize), d: &Double) -> Result<(&'a mut [u8], usize), GenError> {
    gen_be_f64!(x, *d)
}

pub fn gen_decimal_value<'a>(x: (&'a mut [u8], usize), d: &DecimalValue) -> Result<(&'a mut [u8], usize), GenError> {
    do_gen!(x, gen_short_short_uint(&d.scale) >> gen_long_uint(&d.value))
}

pub fn gen_short_string<'a>(x: (&'a mut [u8], usize), s: &ShortString) -> Result<(&'a mut [u8], usize), GenError> {
    do_gen!(x, gen_short_short_uint(&(s.len() as ShortShortUInt)) >> gen_slice!(s.as_bytes()))
}

pub fn gen_long_string<'a>(x: (&'a mut [u8], usize), s: &LongString) -> Result<(&'a mut [u8], usize), GenError> {
    do_gen!(x, gen_long_uint(&(s.len() as LongUInt)) >> gen_slice!(s.as_bytes()))
}

pub fn gen_field_array<'a>(x: (&'a mut [u8], usize), a: &FieldArray) -> Result<(&'a mut [u8], usize), GenError> {
    let (x1, index1) = x;
    gen_many_ref!((x1, index1 + 4), a, gen_value).and_then(|(x2, index2)| {
        gen_long_uint((x2, index1), &((index2 - index1 - 4) as LongUInt)).and_then(|(x3, _)| Ok((x3, index2)))
    })
}

pub fn gen_timestamp<'a>(x: (&'a mut [u8], usize), t: &Timestamp) -> Result<(&'a mut [u8], usize), GenError> {
    gen_long_long_uint(x, t)
}

pub fn gen_field_table<'a>(x: (&'a mut [u8], usize), t: &FieldTable) -> Result<(&'a mut [u8], usize), GenError> {
    let (x1, index1) = x;
    gen_many_ref!((x1, index1 + 4), t, gen_field_entry).and_then(|(x2, index2)| {
        gen_long_uint((x2, index1), &((index2 - index1 - 4) as LongUInt)).and_then(|(x3, _)| Ok((x3, index2)))
    })
}

fn gen_field_entry<'a>(x: (&'a mut [u8], usize), e: &(&ShortString, &AMQPValue)) -> Result<(&'a mut [u8], usize), GenError> {
    do_gen!(x, gen_short_string(e.0) >> gen_value(e.1))
}

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

    #[test]
    fn test_gen_type() {
        assert_eq!(gen_type((&mut [0], 0), &AMQPType::ShortShortInt).unwrap(), (&mut [98][..], 1));
        assert_eq!(gen_type((&mut [0], 0), &AMQPType::ShortInt).unwrap(),      (&mut [85][..], 1));
    }

    #[test]
    fn test_gen_boolean() {
        assert_eq!(gen_boolean((&mut [0], 0), &false).unwrap(), (&mut [0][..], 1));
        assert_eq!(gen_boolean((&mut [0], 0), &true).unwrap(),  (&mut [1][..], 1));
    }

    #[test]
    fn test_gen_short_short_int() {
        assert_eq!(gen_short_short_int((&mut [0], 0), &0).unwrap(),  (&mut [0][..],   1));
        assert_eq!(gen_short_short_int((&mut [0], 0), &-1).unwrap(), (&mut [255][..], 1));
    }

    #[test]
    fn test_gen_short_short_uint() {
        assert_eq!(gen_short_short_uint((&mut [0], 0), &0).unwrap(),   (&mut [0][..],   1));
        assert_eq!(gen_short_short_uint((&mut [0], 0), &255).unwrap(), (&mut [255][..], 1));
    }

    #[test]
    fn test_gen_short_int() {
        assert_eq!(gen_short_int((&mut [0, 0], 0), &0).unwrap(),  (&mut [0,   0][..],   2));
        assert_eq!(gen_short_int((&mut [0, 0], 0), &-1).unwrap(), (&mut [255, 255][..], 2));
    }

    #[test]
    fn test_gen_short_uint() {
        assert_eq!(gen_short_uint((&mut [0, 0], 0), &0).unwrap(),     (&mut [0,   0][..],   2));
        assert_eq!(gen_short_uint((&mut [0, 0], 0), &65535).unwrap(), (&mut [255, 255][..], 2));
    }

    #[test]
    fn test_gen_long_int() {
        assert_eq!(gen_long_int((&mut [0, 0, 0, 0], 0), &0).unwrap(),  (&mut [0,   0,   0,   0][..],   4));
        assert_eq!(gen_long_int((&mut [0, 0, 0, 0], 0), &-1).unwrap(), (&mut [255, 255, 255, 255][..], 4));
    }

    #[test]
    fn test_gen_long_uint() {
        assert_eq!(gen_long_uint((&mut [0, 0, 0, 0], 0), &0).unwrap(),          (&mut [0,   0,   0,   0][..],   4));
        assert_eq!(gen_long_uint((&mut [0, 0, 0, 0], 0), &4294967295).unwrap(), (&mut [255, 255, 255, 255][..], 4));
    }

    #[test]
    fn test_gen_long_long_int() {
        assert_eq!(gen_long_long_int((&mut [0, 0, 0, 0, 0, 0, 0, 0], 0), &0).unwrap(),  (&mut [0,   0,   0,   0,   0,   0,   0,   0][..],   8));
        assert_eq!(gen_long_long_int((&mut [0, 0, 0, 0, 0, 0, 0, 0], 0), &-1).unwrap(), (&mut [255, 255, 255, 255, 255, 255, 255, 255][..], 8));
    }

    #[test]
    fn test_gen_long_long_uint() {
        assert_eq!(gen_long_long_uint((&mut [0, 0, 0, 0, 0, 0, 0, 0], 0), &0).unwrap(),                    (&mut [0,   0,   0,   0,   0,   0,   0,   0][..],   8));
        assert_eq!(gen_long_long_uint((&mut [0, 0, 0, 0, 0, 0, 0, 0], 0), &18446744073709551615).unwrap(), (&mut [255, 255, 255, 255, 255, 255, 255, 255][..], 8));
    }
}
<|endoftext|>


<commit_before>//! Error and solution types for eigenvalue problems.

use impl_prelude::*;

/// Errors from an eigenvalue problem.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EigenError {
    /// The input matrix is not square.
    NotSquare,

    /// The input matrix does not have a conforming layout.
    BadLayout,

    /// The parameter to the LAPACKE method was invalid.
    ///
    /// This error should not occur in user-facing code.
    IllegalParameter(i32),

    /// Eigenvalues could not be found.
    Failed,
}

/// Solution to an eigenvalue problem.
///
/// Contains thte eigenvalues and, optionally, the left and/or right
/// eigenvectors of the solution. For symmetric problems, the
/// eigenvectors are placed in `right_eigenvectors`.
pub struct Solution<IV, EV> {
    /// Eigenvalues of the matrix.
    pub values: Array<EV, Ix1>,

    /// Eigenvectors for the left-eigenvalue problem ($x^H A = \lambda x^H$)
    pub left_vectors: Option<Array<IV, Ix2>>,

    /// Eigenvectors for the right-eigenvalue problem ($Ax = \lambda x$)
    ///
    /// For symmetric eigenvalue problems, the eigenvectors will be stored
    /// in `right_vectors`.
    pub right_vectors: Option<Array<IV, Ix2>>,
}
<commit_msg>eigenvalue Solution learns Debug<commit_after>//! Error and solution types for eigenvalue problems.

use impl_prelude::*;

/// Errors from an eigenvalue problem.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EigenError {
    /// The input matrix is not square.
    NotSquare,

    /// The input matrix does not have a conforming layout.
    BadLayout,

    /// The parameter to the LAPACKE method was invalid.
    ///
    /// This error should not occur in user-facing code.
    IllegalParameter(i32),

    /// Eigenvalues could not be found.
    Failed,
}

/// Solution to an eigenvalue problem.
///
/// Contains thte eigenvalues and, optionally, the left and/or right
/// eigenvectors of the solution. For symmetric problems, the
/// eigenvectors are placed in `right_eigenvectors`.
#[derive(Debug)]
pub struct Solution<IV, EV> {
    /// Eigenvalues of the matrix.
    pub values: Array<EV, Ix1>,

    /// Eigenvectors for the left-eigenvalue problem ($x^H A = \lambda x^H$)
    pub left_vectors: Option<Array<IV, Ix2>>,

    /// Eigenvectors for the right-eigenvalue problem ($Ax = \lambda x$)
    ///
    /// For symmetric eigenvalue problems, the eigenvectors will be stored
    /// in `right_vectors`.
    pub right_vectors: Option<Array<IV, Ix2>>,
}
<|endoftext|>


<commit_before>
#[derive(Clone)]
pub struct Mem256f([super::util::floatX;8]);

impl Default for Mem256f {
    fn default() -> Mem256f {
        Mem256f([0.0 as super::util::floatX; 8])
    }
}

pub struct v128i {
    pub x3: i32,
    pub x2: i32,
    pub x1: i32,
    pub x0: i32,
}

pub struct v256i {
    pub hi: v128i,
    pub lo: v128i,
}

pub struct v128 {
    pub x3: super::util::floatX,
    pub x2: super::util::floatX,
    pub x1: super::util::floatX,
    pub x0: super::util::floatX,
}

pub struct v256 {
    pub hi: v128,
    pub lo: v128,
}

macro_rules! vind{
    (($inp:expr)[0]) => (
        $inp.x0
    );
    (($inp:expr)[1]) => (
        $inp.x1
    );
    (($inp:expr)[2]) => (
        $inp.x2
    );
    (($inp:expr)[3]) => (
        $inp.x3
    );
    (($inp:expr)[4]) => (
        $inp.x4
    );
    (($inp:expr)[5]) => (
        $inp.x5
    );
    (($inp:expr)[6]) => (
        $inp.x6
    );
    (($inp:expr)[7]) => (
        $inp.x7
    );
}
use core::ops::Add;
macro_rules! apply128i {
    ($a: expr, $b : expr, $fun : tt) => (
        v128i{x3:$fun($a.x3, $b.x3),
              x2:$fun($a.x2, $b.x2),
              x1:$fun($a.x1, $b.x1),
              x0:$fun($a.x0, $b.x0),
        }
    );
}
macro_rules! apply256i {
    ($a: expr, $b : expr, $fun : tt) => (
        v256i{
            hi:apply128i!($a.hi, $b.hi, $fun),
            lo:apply128i!($a.lo, $b.lo, $fun),
        }
    );
}
macro_rules! op128i {
    ($a: expr, $b : expr, $fun : tt) => (
        v128i{x3:$a.x3.$fun($b.x3),
              x2:$a.x2.$fun($b.x2),
              x1:$a.x1.$fun($b.x1),
              x0:$a.x0.$fun($b.x0),
        }
    );
}
macro_rules! op256i {
    ($a: expr, $b : expr, $fun : tt) => (
        v256i{
            hi:op128i!($a.hi, $b.hi),
            lo:op128i!($a.lo, $b.lo),
        }
    );
}
macro_rules! bcast256i {
    ($inp: expr) => {
        v256i{lo:v128i{x3:$inp,
                       x2:$inp,
                       x1:$inp,
                       x0:$inp,
        },
              hi:v128i{
                  x3:$inp,
                  x2:$inp,
                  x1:$inp,
                  x0:$inp,
              },
        }
    };
}
macro_rules! bcast128i {
    ($inp: expr) => {
        v128i{x3:$inp,
              x2:$inp,
              x1:$inp,
              x0:$inp,
        }
    };
}
macro_rules! shuf128i {
    ($inp: expr, $i3 :tt, $i2 : tt, $i1 : tt, $i0: tt) => {
        v128i{x3:vind!(($inp)[$i3]),
              x2:vind!(($inp)[$i2]),
              x1:vind!(($inp)[$i1]),
              x0:vind!(($inp)[$i0]),
        }
    }
}

macro_rules! apply128 {
    ($a: expr, $b : expr, $fun : tt) => (
        v128{x3:$fun($a.x3, $b.x3),
              x2:$fun($a.x2, $b.x2),
              x1:$fun($a.x1, $b.x1),
              x0:$fun($a.x0, $b.x0),
        }
    );
}
macro_rules! apply256 {
    ($a: expr, $b : expr, $fun : tt) => (
        v256{
            hi:apply128!($a.hi, $b.hi, $fun),
            lo:apply128!($a.lo, $b.lo, $fun),
        }
    );
}
macro_rules! op128 {
    ($a: expr, $b : expr, $fun : tt) => (
        v128{x3:$a.x3.$fun($b.x3),
              x2:$a.x2.$fun($b.x2),
              x1:$a.x1.$fun($b.x1),
              x0:$a.x0.$fun($b.x0),
        }
    );
}
macro_rules! op256 {
    ($a: expr, $b : expr, $fun : tt) => (
        v256{
            hi:op128!($a.hi, $b.hi),
            lo:op128!($a.lo, $b.lo),
        }
    );
}
macro_rules! bcast256 {
    ($inp: expr) => {
        v256{lo:v128{x3:$inp,
                       x2:$inp,
                       x1:$inp,
                       x0:$inp,
        },
              hi:v128{
                  x3:$inp,
                  x2:$inp,
                  x1:$inp,
                  x0:$inp,
              },
        }
    };
}
macro_rules! bcast128 {
    ($inp: expr) => {
        v128{x3:$inp,
              x2:$inp,
              x1:$inp,
              x0:$inp,
        }
    };
}
macro_rules! shuf128 {
    ($inp: expr, $i3 :tt, $i2 : tt, $i1 : tt, $i0: tt) => {
        v128{x3:vind!(($inp)[$i3]),
              x2:vind!(($inp)[$i2]),
              x1:vind!(($inp)[$i1]),
              x0:vind!(($inp)[$i0]),
        }
    }
}

fn sum8(x : v256i) -> i32 {
    // hiQuad = ( x7, x6, x5, x4 )
    let hiQuad = x.hi;
    // loQuad = ( x3, x2, x1, x0 )
    let loQuad = x.lo;
    let sumQuad = op128i!(hiQuad, loQuad, add);
    let shuf = shuf128i!(sumQuad, 1,0,3,2);
    let sumPair = op128i!(sumQuad, shuf, add);
    let sum23 = shuf128i!(sumPair, 1,0,3,2);
    let finalSum = op128i!(sum23, sumPair, add);
    finalSum.x0
}

<commit_msg>appease rust 1.8<commit_after>
#[derive(Clone)]
pub struct Mem256f([super::util::floatX;8]);

impl Default for Mem256f {
    fn default() -> Mem256f {
        Mem256f([0.0 as super::util::floatX; 8])
    }
}

pub struct v128i {
    pub x3: i32,
    pub x2: i32,
    pub x1: i32,
    pub x0: i32,
}

pub struct v256i {
    pub hi: v128i,
    pub lo: v128i,
}

pub struct v128 {
    pub x3: super::util::floatX,
    pub x2: super::util::floatX,
    pub x1: super::util::floatX,
    pub x0: super::util::floatX,
}

pub struct v256 {
    pub hi: v128,
    pub lo: v128,
}

macro_rules! vind{
    (($inp:expr)[0]) => (
        $inp.x0
    );
    (($inp:expr)[1]) => (
        $inp.x1
    );
    (($inp:expr)[2]) => (
        $inp.x2
    );
    (($inp:expr)[3]) => (
        $inp.x3
    );
    (($inp:expr)[4]) => (
        $inp.x4
    );
    (($inp:expr)[5]) => (
        $inp.x5
    );
    (($inp:expr)[6]) => (
        $inp.x6
    );
    (($inp:expr)[7]) => (
        $inp.x7
    );
}
use core::ops::Add;
macro_rules! apply128i {
    ($a: expr, $b : expr, $fun : tt) => (
        v128i{x3:$fun($a.x3, $b.x3),
              x2:$fun($a.x2, $b.x2),
              x1:$fun($a.x1, $b.x1),
              x0:$fun($a.x0, $b.x0),
        }
    );
}
macro_rules! apply256i {
    ($a: expr, $b : expr, $fun : tt) => (
        v256i{
            hi:apply128i!($a.hi, $b.hi, $fun),
            lo:apply128i!($a.lo, $b.lo, $fun),
        }
    );
}
macro_rules! op128i {
    ($a: expr, $b : expr, $fun : tt) => (
        v128i{x3:$a.x3.$fun($b.x3),
              x2:$a.x2.$fun($b.x2),
              x1:$a.x1.$fun($b.x1),
              x0:$a.x0.$fun($b.x0),
        }
    );
}
macro_rules! op256i {
    ($a: expr, $b : expr, $fun : tt) => (
        v256i{
            hi:op128i!($a.hi, $b.hi),
            lo:op128i!($a.lo, $b.lo),
        }
    );
}
macro_rules! bcast256i {
    ($inp: expr) => {
        v256i{lo:v128i{x3:$inp,
                       x2:$inp,
                       x1:$inp,
                       x0:$inp,
        },
              hi:v128i{
                  x3:$inp,
                  x2:$inp,
                  x1:$inp,
                  x0:$inp,
              },
        }
    };
}
macro_rules! bcast128i {
    ($inp: expr) => {
        v128i{x3:$inp,
              x2:$inp,
              x1:$inp,
              x0:$inp,
        }
    };
}
macro_rules! shuf128i {
    ($inp: expr, $i3 :tt, $i2 : tt, $i1 : tt, $i0: tt) => {
        v128i{x3:vind!(($inp)[$i3]),
              x2:vind!(($inp)[$i2]),
              x1:vind!(($inp)[$i1]),
              x0:vind!(($inp)[$i0]),
        }
    }
}

macro_rules! apply128 {
    ($a: expr, $b : expr, $fun : tt) => (
        v128{x3:$fun($a.x3, $b.x3),
              x2:$fun($a.x2, $b.x2),
              x1:$fun($a.x1, $b.x1),
              x0:$fun($a.x0, $b.x0),
        }
    );
}
macro_rules! apply256 {
    ($a: expr, $b : expr, $fun : tt) => (
        v256{
            hi:apply128!($a.hi, $b.hi, $fun),
            lo:apply128!($a.lo, $b.lo, $fun),
        }
    );
}
macro_rules! op128 {
    ($a: expr, $b : expr, $fun : tt) => (
        v128{x3:$a.x3.$fun($b.x3),
              x2:$a.x2.$fun($b.x2),
              x1:$a.x1.$fun($b.x1),
              x0:$a.x0.$fun($b.x0),
        }
    );
}
macro_rules! op256 {
    ($a: expr, $b : expr, $fun : tt) => (
        v256{
            hi:op128!($a.hi, $b.hi),
            lo:op128!($a.lo, $b.lo),
        }
    );
}
macro_rules! bcast256 {
    ($inp: expr) => {
        v256{lo:v128{x3:$inp,
                       x2:$inp,
                       x1:$inp,
                       x0:$inp,
        },
              hi:v128{
                  x3:$inp,
                  x2:$inp,
                  x1:$inp,
                  x0:$inp,
              },
        }
    };
}
macro_rules! bcast128 {
    ($inp: expr) => {
        v128{x3:$inp,
              x2:$inp,
              x1:$inp,
              x0:$inp,
        }
    };
}
macro_rules! shuf128 {
    ($inp: expr, $i3 :tt, $i2 : tt, $i1 : tt, $i0: tt) => {
        v128{x3:vind!(($inp)[$i3]),
              x2:vind!(($inp)[$i2]),
              x1:vind!(($inp)[$i1]),
              x0:vind!(($inp)[$i0]),
        }
    }
}

fn addf(a: super::util::floatX, b:super::util::floatX) -> super::util::floatX{
    a + b
}
fn addi(a: i32, b:i32) -> i32{
    a + b
}

fn sum8(x : v256i) -> i32 {
    // hiQuad = ( x7, x6, x5, x4 )
    let hiQuad = x.hi;
    // loQuad = ( x3, x2, x1, x0 )
    let loQuad = x.lo;
    let sumQuad = apply128i!(hiQuad, loQuad, addi);
    let shuf = shuf128i!(sumQuad, 1,0,3,2);
    let sumPair = apply128i!(sumQuad, shuf, addi);
    let sum23 = shuf128i!(sumPair, 1,0,3,2);
    let finalSum = apply128i!(sum23, sumPair, addi);
    finalSum.x0
}

<|endoftext|>