<commit_before>#![deny(warnings)]

use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;

struct Test {
    repo: &'static str,
    name: &'static str,
    sha: &'static str,
    lock: Option<&'static str>,
    packages: &'static [&'static str],
}

const TEST_REPOS: &'static [Test] = &[
    Test {
        name: "iron",
        repo: "https://github.com/iron/iron",
        sha: "cf056ea5e8052c1feea6141e40ab0306715a2c33",
        lock: None,
        packages: &[],
    },
    Test {
        name: "ripgrep",
        repo: "https://github.com/BurntSushi/ripgrep",
        sha: "ad9befbc1d3b5c695e7f6b6734ee1b8e683edd41",
        lock: None,
        packages: &[],
    },
    Test {
        name: "tokei",
        repo: "https://github.com/XAMPPRocky/tokei",
        sha: "5e11c4852fe4aa086b0e4fe5885822fbe57ba928",
        lock: None,
        packages: &[],
    },
    Test {
        name: "treeify",
        repo: "https://github.com/dzamlo/treeify",
        sha: "999001b223152441198f117a68fb81f57bc086dd",
        lock: None,
        packages: &[],
    },
    Test {
        name: "xsv",
        repo: "https://github.com/BurntSushi/xsv",
        sha: "66956b6bfd62d6ac767a6b6499c982eae20a2c9f",
        lock: None,
        packages: &[],
    },
    Test {
        name: "servo",
        repo: "https://github.com/servo/servo",
        sha: "caac107ae8145ef2fd20365e2b8fadaf09c2eb3b",
        lock: None,
        // Only test Stylo a.k.a. Quantum CSS, the parts of Servo going into Firefox.
        // This takes much less time to build than all of Servo and supports stable Rust.
        packages: &["selectors"],
    },
    Test {
        name: "webrender",
        repo: "https://github.com/servo/webrender",
        sha: "a3d6e6894c5a601fa547c6273eb963ca1321c2bb",
        lock: None,
        packages: &[],
    },
];

fn main() {
    let args = env::args().collect::<Vec<_>>();
    let ref cargo = args[1];
    let out_dir = Path::new(&args[2]);
    let ref cargo = Path::new(cargo);

    for test in TEST_REPOS.iter().rev() {
        test_repo(cargo, out_dir, test);
    }
}

fn test_repo(cargo: &Path, out_dir: &Path, test: &Test) {
    println!("testing {}", test.repo);
    let dir = clone_repo(test, out_dir);
    if let Some(lockfile) = test.lock {
        fs::write(&dir.join("Cargo.lock"), lockfile).unwrap();
    }
    if !run_cargo_test(cargo, &dir, test.packages) {
        panic!("tests failed for {}", test.repo);
    }
}

fn clone_repo(test: &Test, out_dir: &Path) -> PathBuf {
    let out_dir = out_dir.join(test.name);

    if !out_dir.join(".git").is_dir() {
        let status = Command::new("git").arg("init").arg(&out_dir).status().expect("");
        assert!(status.success());
    }

    // Try progressively deeper fetch depths to find the commit
    let mut found = false;
    for depth in &[0, 1, 10, 100, 1000, 100000] {
        if *depth > 0 {
            let status = Command::new("git")
                .arg("fetch")
                .arg(test.repo)
                .arg("master")
                .arg(&format!("--depth={}", depth))
                .current_dir(&out_dir)
                .status()
                .expect("");
            assert!(status.success());
        }

        let status = Command::new("git")
            .arg("reset")
            .arg(test.sha)
            .arg("--hard")
            .current_dir(&out_dir)
            .status()
            .expect("");

        if status.success() {
            found = true;
            break;
        }
    }

    if !found {
        panic!("unable to find commit {}", test.sha)
    }
    let status =
        Command::new("git").arg("clean").arg("-fdx").current_dir(&out_dir).status().unwrap();
    assert!(status.success());

    out_dir
}

fn run_cargo_test(cargo_path: &Path, crate_path: &Path, packages: &[&str]) -> bool {
    let mut command = Command::new(cargo_path);
    command.arg("test");
    for name in packages {
        command.arg("-p").arg(name);
    }
    let status = command
        // Disable rust-lang/cargo's cross-compile tests
        .env("CFG_DISABLE_CROSS_TESTS", "1")
        // Relax #![deny(warnings)] in some crates
        .env("RUSTFLAGS", "--cap-lints warn")
        .current_dir(crate_path)
        .status()
        .expect("");

    status.success()
}
<commit_msg>Rollup merge of #70626 - pietroalbini:remove-webrender-cargotest, r=Mark-Simulacrum<commit_after>#![deny(warnings)]

use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;

struct Test {
    repo: &'static str,
    name: &'static str,
    sha: &'static str,
    lock: Option<&'static str>,
    packages: &'static [&'static str],
}

const TEST_REPOS: &'static [Test] = &[
    Test {
        name: "iron",
        repo: "https://github.com/iron/iron",
        sha: "cf056ea5e8052c1feea6141e40ab0306715a2c33",
        lock: None,
        packages: &[],
    },
    Test {
        name: "ripgrep",
        repo: "https://github.com/BurntSushi/ripgrep",
        sha: "ad9befbc1d3b5c695e7f6b6734ee1b8e683edd41",
        lock: None,
        packages: &[],
    },
    Test {
        name: "tokei",
        repo: "https://github.com/XAMPPRocky/tokei",
        sha: "5e11c4852fe4aa086b0e4fe5885822fbe57ba928",
        lock: None,
        packages: &[],
    },
    Test {
        name: "treeify",
        repo: "https://github.com/dzamlo/treeify",
        sha: "999001b223152441198f117a68fb81f57bc086dd",
        lock: None,
        packages: &[],
    },
    Test {
        name: "xsv",
        repo: "https://github.com/BurntSushi/xsv",
        sha: "66956b6bfd62d6ac767a6b6499c982eae20a2c9f",
        lock: None,
        packages: &[],
    },
    Test {
        name: "servo",
        repo: "https://github.com/servo/servo",
        sha: "caac107ae8145ef2fd20365e2b8fadaf09c2eb3b",
        lock: None,
        // Only test Stylo a.k.a. Quantum CSS, the parts of Servo going into Firefox.
        // This takes much less time to build than all of Servo and supports stable Rust.
        packages: &["selectors"],
    },
];

fn main() {
    let args = env::args().collect::<Vec<_>>();
    let ref cargo = args[1];
    let out_dir = Path::new(&args[2]);
    let ref cargo = Path::new(cargo);

    for test in TEST_REPOS.iter().rev() {
        test_repo(cargo, out_dir, test);
    }
}

fn test_repo(cargo: &Path, out_dir: &Path, test: &Test) {
    println!("testing {}", test.repo);
    let dir = clone_repo(test, out_dir);
    if let Some(lockfile) = test.lock {
        fs::write(&dir.join("Cargo.lock"), lockfile).unwrap();
    }
    if !run_cargo_test(cargo, &dir, test.packages) {
        panic!("tests failed for {}", test.repo);
    }
}

fn clone_repo(test: &Test, out_dir: &Path) -> PathBuf {
    let out_dir = out_dir.join(test.name);

    if !out_dir.join(".git").is_dir() {
        let status = Command::new("git").arg("init").arg(&out_dir).status().expect("");
        assert!(status.success());
    }

    // Try progressively deeper fetch depths to find the commit
    let mut found = false;
    for depth in &[0, 1, 10, 100, 1000, 100000] {
        if *depth > 0 {
            let status = Command::new("git")
                .arg("fetch")
                .arg(test.repo)
                .arg("master")
                .arg(&format!("--depth={}", depth))
                .current_dir(&out_dir)
                .status()
                .expect("");
            assert!(status.success());
        }

        let status = Command::new("git")
            .arg("reset")
            .arg(test.sha)
            .arg("--hard")
            .current_dir(&out_dir)
            .status()
            .expect("");

        if status.success() {
            found = true;
            break;
        }
    }

    if !found {
        panic!("unable to find commit {}", test.sha)
    }
    let status =
        Command::new("git").arg("clean").arg("-fdx").current_dir(&out_dir).status().unwrap();
    assert!(status.success());

    out_dir
}

fn run_cargo_test(cargo_path: &Path, crate_path: &Path, packages: &[&str]) -> bool {
    let mut command = Command::new(cargo_path);
    command.arg("test");
    for name in packages {
        command.arg("-p").arg(name);
    }
    let status = command
        // Disable rust-lang/cargo's cross-compile tests
        .env("CFG_DISABLE_CROSS_TESTS", "1")
        // Relax #![deny(warnings)] in some crates
        .env("RUSTFLAGS", "--cap-lints warn")
        .current_dir(crate_path)
        .status()
        .expect("");

    status.success()
}
<|endoftext|>


<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::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.read().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>refactor: remove unnecessary match<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.read().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
    if member.nick.as_ref() != Some(&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>// * This file is part of the uutils coreutils package.
// *
// * (c) 2014 T. Jameson Little <t.jameson.little@gmail.com>
// * (c) 2020 nicoo <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

extern crate rand;

#[macro_use]
extern crate uucore;

use std::collections::BTreeMap;
use std::error::Error;
use std::fmt;
use std::io::{self, stdin, stdout, BufRead, Write};
use std::ops;

mod miller_rabin;
mod numeric;
mod rho;
mod table;

static SYNTAX: &str = "[OPTION] [NUMBER]...";
static SUMMARY: &str = "Print the prime factors of the given number(s).
 If none are specified, read from standard input.";
static LONG_HELP: &str = "";

struct Factors {
    f: BTreeMap<u64, u8>,
}

impl Factors {
    fn new() -> Factors {
        Factors { f: BTreeMap::new() }
    }

    fn add(&mut self, prime: u64, exp: u8) {
        debug_assert!(exp > 0);
        let n = *self.f.get(&prime).unwrap_or(&0);
        self.f.insert(prime, exp + n);
    }

    fn push(&mut self, prime: u64) {
        self.add(prime, 1)
    }

    #[cfg(test)]
    fn product(&self) -> u64 {
        self.f
            .iter()
            .fold(1, |acc, (p, exp)| acc * p.pow(*exp as u32))
    }
}

impl ops::MulAssign<Factors> for Factors {
    fn mul_assign(&mut self, other: Factors) {
        for (prime, exp) in &other.f {
            self.add(*prime, *exp);
        }
    }
}

impl fmt::Display for Factors {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        for (p, exp) in self.f.iter() {
            for _ in 0..*exp {
                write!(f, " {}", p)?
            }
        }

        Ok(())
    }
}

fn factor(mut n: u64) -> Factors {
    let mut factors = Factors::new();

    if n < 2 {
        factors.push(n);
        return factors;
    }

    let z = n.trailing_zeros();
    if z > 0 {
        factors.add(2, z as u8);
        n >>= z;
    }

    if n == 1 {
        return factors;
    }

    let (f, n) = table::factor(n);
    factors *= f;

    if n >= table::NEXT_PRIME {
        factors *= rho::factor(n);
    }

    factors
}

fn print_factors_str(num_str: &str, w: &mut impl io::Write) -> Result<(), Box<dyn Error>> {
    num_str
        .parse::<u64>()
        .map_err(|e| e.into())
        .and_then(|x| writeln!(w, "{}:{}", x, factor(x)).map_err(|e| e.into()))
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let matches = app!(SYNTAX, SUMMARY, LONG_HELP).parse(args.collect_str());
    let stdout = stdout();
    let mut w = io::BufWriter::new(stdout.lock());

    if matches.free.is_empty() {
        let stdin = stdin();

        for line in stdin.lock().lines() {
            for number in line.unwrap().split_whitespace() {
                if let Err(e) = print_factors_str(number, &mut w) {
                    show_warning!("{}: {}", number, e);
                }
            }
        }
    } else {
        for number in &matches.free {
            if let Err(e) = print_factors_str(number, &mut w) {
                show_warning!("{}: {}", number, e);
            }
        }
    }

    if let Err(e) = w.flush() {
        show_error!("{}", e);
    }

    0
}

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

    #[test]
    fn factor_recombines_small() {
        assert!((1..10_000)
            .map(|i| 2 * i + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_overflowing() {
        assert!((0..250)
            .map(|i| 2 * i + 2u64.pow(32) + 1)
            .all(|i| factor(i).product() == i));
    }
}
<commit_msg>factor: Add test exhibiting a bug in ρ<commit_after>// * This file is part of the uutils coreutils package.
// *
// * (c) 2014 T. Jameson Little <t.jameson.little@gmail.com>
// * (c) 2020 nicoo <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

extern crate rand;

#[macro_use]
extern crate uucore;

use std::collections::BTreeMap;
use std::error::Error;
use std::fmt;
use std::io::{self, stdin, stdout, BufRead, Write};
use std::ops;

mod miller_rabin;
mod numeric;
mod rho;
mod table;

static SYNTAX: &str = "[OPTION] [NUMBER]...";
static SUMMARY: &str = "Print the prime factors of the given number(s).
 If none are specified, read from standard input.";
static LONG_HELP: &str = "";

struct Factors {
    f: BTreeMap<u64, u8>,
}

impl Factors {
    fn new() -> Factors {
        Factors { f: BTreeMap::new() }
    }

    fn add(&mut self, prime: u64, exp: u8) {
        debug_assert!(exp > 0);
        let n = *self.f.get(&prime).unwrap_or(&0);
        self.f.insert(prime, exp + n);
    }

    fn push(&mut self, prime: u64) {
        self.add(prime, 1)
    }

    #[cfg(test)]
    fn product(&self) -> u64 {
        self.f
            .iter()
            .fold(1, |acc, (p, exp)| acc * p.pow(*exp as u32))
    }
}

impl ops::MulAssign<Factors> for Factors {
    fn mul_assign(&mut self, other: Factors) {
        for (prime, exp) in &other.f {
            self.add(*prime, *exp);
        }
    }
}

impl fmt::Display for Factors {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        for (p, exp) in self.f.iter() {
            for _ in 0..*exp {
                write!(f, " {}", p)?
            }
        }

        Ok(())
    }
}

fn factor(mut n: u64) -> Factors {
    let mut factors = Factors::new();

    if n < 2 {
        factors.push(n);
        return factors;
    }

    let z = n.trailing_zeros();
    if z > 0 {
        factors.add(2, z as u8);
        n >>= z;
    }

    if n == 1 {
        return factors;
    }

    let (f, n) = table::factor(n);
    factors *= f;

    if n >= table::NEXT_PRIME {
        factors *= rho::factor(n);
    }

    factors
}

fn print_factors_str(num_str: &str, w: &mut impl io::Write) -> Result<(), Box<dyn Error>> {
    num_str
        .parse::<u64>()
        .map_err(|e| e.into())
        .and_then(|x| writeln!(w, "{}:{}", x, factor(x)).map_err(|e| e.into()))
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let matches = app!(SYNTAX, SUMMARY, LONG_HELP).parse(args.collect_str());
    let stdout = stdout();
    let mut w = io::BufWriter::new(stdout.lock());

    if matches.free.is_empty() {
        let stdin = stdin();

        for line in stdin.lock().lines() {
            for number in line.unwrap().split_whitespace() {
                if let Err(e) = print_factors_str(number, &mut w) {
                    show_warning!("{}: {}", number, e);
                }
            }
        }
    } else {
        for number in &matches.free {
            if let Err(e) = print_factors_str(number, &mut w) {
                show_warning!("{}: {}", number, e);
            }
        }
    }

    if let Err(e) = w.flush() {
        show_error!("{}", e);
    }

    0
}

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

    #[test]
    fn factor_recombines_small() {
        assert!((1..10_000)
            .map(|i| 2 * i + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_overflowing() {
        assert!((0..250)
            .map(|i| 2 * i + 2u64.pow(32) + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_strong_pseudoprime() {
        let pseudoprime = 17179869183;
        for _ in 0..20 {
            assert!(factor(pseudoprime).product() == pseudoprime);
        }
    }
}
<|endoftext|>


<commit_before>//! Conversion to the `Stream` type from iterators.

use std::rc::Rc;
use std::cell::RefCell;
use std::default::Default;

use progress::frontier::Antichain;
use progress::{Operate, Timestamp};
use progress::nested::subgraph::Source;
use progress::count_map::CountMap;

use timely_communication::Allocate;

use Data;
use dataflow::channels::Content;
use dataflow::channels::pushers::{Tee, Counter};
use dataflow::channels::pushers::buffer::Buffer;

use dataflow::{Stream, Scope};

pub trait ToStream<D: Data> {
    /// Converts an iterator to a timely `Stream`, with records at the default time.
    ///
    /// #Examples
    /// ```
    /// use timely::dataflow::operators::{ToStream, Inspect};
    ///
    /// timely::example(|scope| {
    ///     (0..10).to_stream(scope)
    ///            .inspect(|x| println!("seen: {:?}", x));
    /// });
    /// ```
    fn to_stream<S: Scope>(self, scope: &mut S) -> Stream<S, D>;
}

impl<D: Data, I: Iterator<Item=D>+'static> ToStream<D> for I {
    fn to_stream<S: Scope>(self, scope: &mut S) -> Stream<S, D> {

        let (output, registrar) = Tee::<S::Timestamp, D>::new();
        let copies = scope.peers();

        let index = scope.add_operator(Operator {
            iterator: Some(self),
            copies: copies,
            output: Buffer::new(Counter::new(output, Rc::new(RefCell::new(CountMap::new())))),
        });

        return Stream::new(Source { index: index, port: 0 }, registrar, scope.clone());
    }
}

struct Operator<T:Timestamp, D: Data, I: Iterator<Item=D>> {
    iterator: Option<I>,
    copies: usize,
    output: Buffer<T, D, Counter<T, D, Tee<T, D>>>,
}

impl<T:Timestamp, D: Data, I: Iterator<Item=D>> Operate<T> for Operator<T, D, I> {
    fn name(&self) -> String { "ToStream".to_owned() }
    fn inputs(&self) -> usize { 0 }
    fn outputs(&self) -> usize { 1 }

    fn get_internal_summary(&mut self) -> (Vec<Vec<Antichain<T::Summary>>>, Vec<CountMap<T>>) {
        let mut map = CountMap::new();
        map.update(&Default::default(), self.copies as i64);
        (Vec::new(), vec![map])
    }

    fn pull_internal_progress(&mut self,_messages_consumed: &mut [CountMap<T>],
                                         frontier_progress: &mut [CountMap<T>],
                                         messages_produced: &mut [CountMap<T>]) -> bool
    {
        if self.iterator.is_some() {

            // if we find that there is a next element, send a bunch.
            if let Some(element) = self.iterator.as_mut().unwrap().next() {

                // send 4096 messages, or whatever the buffer size is.
                let mut session = self.output.session(&Default::default());
                session.give(element);
                for element in self.iterator.as_mut().unwrap().take((16 * Content::<D>::default_length()) - 1) {
                    session.give(element);
                }
            }
            else {

                self.output.cease();
                self.output.inner().pull_progress(&mut messages_produced[0]);
                frontier_progress[0].update(&Default::default(), -1);
                self.iterator = None;
            }
        }

        false
    }

    fn notify_me(&self) -> bool { false }
}
<commit_msg>increased default send amount slightly; fix<commit_after>//! Conversion to the `Stream` type from iterators.

use std::rc::Rc;
use std::cell::RefCell;
use std::default::Default;

use progress::frontier::Antichain;
use progress::{Operate, Timestamp};
use progress::nested::subgraph::Source;
use progress::count_map::CountMap;

use timely_communication::Allocate;

use Data;
use dataflow::channels::Content;
use dataflow::channels::pushers::{Tee, Counter};
use dataflow::channels::pushers::buffer::Buffer;

use dataflow::{Stream, Scope};

pub trait ToStream<D: Data> {
    /// Converts an iterator to a timely `Stream`, with records at the default time.
    ///
    /// #Examples
    /// ```
    /// use timely::dataflow::operators::{ToStream, Inspect};
    ///
    /// timely::example(|scope| {
    ///     (0..10).to_stream(scope)
    ///            .inspect(|x| println!("seen: {:?}", x));
    /// });
    /// ```
    fn to_stream<S: Scope>(self, scope: &mut S) -> Stream<S, D>;
}

impl<D: Data, I: Iterator<Item=D>+'static> ToStream<D> for I {
    fn to_stream<S: Scope>(self, scope: &mut S) -> Stream<S, D> {

        let (output, registrar) = Tee::<S::Timestamp, D>::new();
        let copies = scope.peers();

        let index = scope.add_operator(Operator {
            iterator: Some(self),
            copies: copies,
            output: Buffer::new(Counter::new(output, Rc::new(RefCell::new(CountMap::new())))),
        });

        return Stream::new(Source { index: index, port: 0 }, registrar, scope.clone());
    }
}

struct Operator<T:Timestamp, D: Data, I: Iterator<Item=D>> {
    iterator: Option<I>,
    copies: usize,
    output: Buffer<T, D, Counter<T, D, Tee<T, D>>>,
}

impl<T:Timestamp, D: Data, I: Iterator<Item=D>> Operate<T> for Operator<T, D, I> {
    fn name(&self) -> String { "ToStream".to_owned() }
    fn inputs(&self) -> usize { 0 }
    fn outputs(&self) -> usize { 1 }

    fn get_internal_summary(&mut self) -> (Vec<Vec<Antichain<T::Summary>>>, Vec<CountMap<T>>) {
        let mut map = CountMap::new();
        map.update(&Default::default(), self.copies as i64);
        (Vec::new(), vec![map])
    }

    fn pull_internal_progress(&mut self,_messages_consumed: &mut [CountMap<T>],
                                         frontier_progress: &mut [CountMap<T>],
                                         messages_produced: &mut [CountMap<T>]) -> bool
    {
        if self.iterator.is_some() {

            // if we find that there is a next element, send a bunch.
            if let Some(element) = self.iterator.as_mut().unwrap().next() {

                // send 4096 messages, or whatever the buffer size is.
                let mut session = self.output.session(&Default::default());
                session.give(element);
                for element in self.iterator.as_mut().unwrap().take((256 * Content::<D>::default_length()) - 1) {
                    session.give(element);
                }
            }
            else {

                self.output.cease();
                self.output.inner().pull_progress(&mut messages_produced[0]);
                frontier_progress[0].update(&Default::default(), -1);
                self.iterator = None;
            }
        }

        false
    }

    fn notify_me(&self) -> bool { false }
}
<|endoftext|>


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

pub mod line;
use crate::core::codepointinfo::CodepointInfo;
use std::time::Duration;

use self::line::Line;
use self::line::LineCellIndex;

pub type LineIndex = usize;

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Rect {
    pub x: usize,
    pub y: usize,
    pub width: usize,
    pub height: usize,
}

/// A Screen is composed of Line(s).

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Screen {
    /// the underlying lines storage
    pub line: Vec<Line>,
    /// the index of the line filled with the push method
    pub current_line_index: LineIndex,

    //
    clip: Rect,

    /// maximum number of elements the screen line can hold
    max_width: usize,
    /// maximum number of lines the screen can hold
    max_height: usize,

    /// the number of elements pushed in the screen
    pub nb_push: usize,
    /// placeholder to record the offset of the first pushed CodepointInfo (used by View)
    pub first_offset: u64,
    /// placeholder to record the offset of the last pushed CodepointInfo (used by View)
    pub last_offset: u64,
    /// placeholder to record the maximum offset of the document (eof)
    pub doc_max_offset: u64,
    /// time spent to generate the screen content
    pub time_to_build: Duration,

    pub input_size: usize,
}

impl Screen {
    pub fn new(width: usize, height: usize) -> Screen {
        assert!(width > 0);
        assert!(height > 0);

        let mut line: Vec<Line> = Vec::new();
        for _ in 0..height {
            line.push(Line::new(width));
        }

        Screen {
            line,
            current_line_index: 0,
            clip: Rect {
                x: 0,
                y: 0,
                width,
                height,
            },
            max_width: width,
            max_height: height,

            nb_push: 0,
            first_offset: 0,
            last_offset: 0,
            doc_max_offset: 0,
            time_to_build: Duration::new(0, 0),
            input_size: 0,
        }
    }

    pub fn check_invariants(&self) {
    }

    pub fn copy_to(&mut self, x: usize, y: usize, src: &Screen) -> bool {
        if x + src.width() > self.width() || y + src.height() > self.height() {
            return false;
        }

        for src_y in 0..src.height() {
            for src_x in 0..src.width() {
                if let Some(cpi_src) = src.get_cpinfo(src_x, src_y) {
                    if let Some(cpi_dst) = self.get_mut_cpinfo(x + src_x, y + src_y) {
                        *cpi_dst = *cpi_src;
                    }
                }
            }
        }

        true
    }

    pub fn clip_rect(&self) -> Rect {
        self.clip.clone()
    }

    pub fn width(&self) -> usize {
        self.clip.width - self.clip.x
    }

    pub fn height(&self) -> usize {
        self.clip.height - self.clip.y
    }

    // TODO: return bool
    pub fn set_clipping(&mut self, x: usize, y: usize, width: usize, height: usize) {
        assert!(x < self.max_width);
        assert!(width <= self.max_width);
        assert!(x + width <= self.max_width);

        assert!(y < self.max_height);
        assert!(height <= self.max_height);
        assert!(y + height <= self.max_height);

        for i in y..y + height {
            self.line[i].set_clipping(x, width);
        }

        // store
        self.clip = Rect {
            x,
            y,
            width: x + width,
            height: y + height,
        };

        self.current_line_index = 0; // TODO: save screen state and restore while switching clip
    }

    pub fn resize(&mut self, width: usize, height: usize) {
        self.line.resize(height, Line::new(width));
        for i in 0..height {
            self.line[i].resize(width);
        }
        self.max_height = height;
        self.max_width = width;
        self.set_clipping(0, 0, width, height);

        self.current_line_index = 0;
        self.nb_push = 0;
        self.first_offset = 0;
        self.last_offset = 0;
        self.doc_max_offset = 0;
        self.input_size = 0;
    }

    /// 0-----skip---cur_index----max_height---capacity

    /// append
    pub fn push(&mut self, cpi: CodepointInfo) -> (bool, usize) {
        if self.current_line_index == self.height() {
            return (false, self.current_line_index);
        }

        if self.line[self.clip.y + self.current_line_index].read_only {
            self.current_line_index += 1;
        }

        if self.current_line_index == self.height() {
            return (false, self.current_line_index);
        }

        let cp = cpi.cp;
        let line = &mut self.line[self.clip.y + self.current_line_index];
        let (ok, _) = line.push(cpi);

        if ok {
            self.nb_push += 1;
            if cp == '\n' || cp == '\r' {
                line.read_only = true;
            }
        }
        (ok, self.current_line_index)
    }

    pub fn clear(&mut self) {
        for h in 0..self.max_height {
            self.line[h].clear();
        }
        self.current_line_index = 0;
        self.nb_push = 0;
        self.first_offset = 0;
        self.last_offset = 0;
        self.doc_max_offset = 0;
        self.input_size = 0;
        self.set_clipping(0, 0, self.max_width, self.max_height);
    }

    pub fn max_width(&self) -> usize {
        self.max_width
    }

    pub fn max_height(&self) -> usize {
        self.max_height
    }

    pub fn get_mut_unclipped_line(&mut self, index: usize) -> Option<&mut Line> {
        if index < self.max_height {
            Some(&mut self.line[index])
        } else {
            None
        }
    }

    pub fn get_mut_line(&mut self, index: usize) -> Option<&mut Line> {
        if index < self.height() {
            Some(&mut self.line[self.clip.y + index])
        } else {
            None
        }
    }

    pub fn get_unclipped_line(&self, index: usize) -> Option<&Line> {
        if index < self.max_height {
            Some(&self.line[index])
        } else {
            None
        }
    }

    pub fn get_line(&self, index: usize) -> Option<&Line> {
        if index < self.height() {
            Some(&self.line[self.clip.y + index])
        } else {
            None
        }
    }

    pub fn get_mut_used_line(&mut self, index: usize) -> Option<&mut Line> {
        if index <= self.current_line_index && self.line[self.clip.y + index].nb_cells > 0 {
            Some(&mut self.line[self.clip.y + index])
        } else {
            None
        }
    }

    pub fn get_used_line_clipped(&mut self, index: usize) -> (Option<&Line>, LineIndex) {
        let index = ::std::cmp::min(index, self.current_line_index);
        (self.get_used_line(index), index)
    }

    // improve this: loop over line nb_push > 0
    pub fn get_used_line(&self, index: usize) -> Option<&Line> {
        if index >= self.height() {
            return None;
        }

        if index <= self.current_line_index && self.line[self.clip.y + index].nb_cells > 0 {
            Some(&self.line[self.clip.y + index])
        } else {
            None
        }
    }

    /// there must be 2 lines a least
    pub fn get_first_used_line(&self) -> Option<&Line> {
        if 0 < self.current_line_index {
            Some(&self.line[self.clip.y])
        } else {
            None
        }
    }

    /// there must be 2 line a least
    pub fn get_last_used_line(&self) -> Option<&Line> {
        if self.current_line_index > 0 {
            Some(&self.line[self.clip.y + self.current_line_index - 1])
        } else {
            None
        }
    }

    pub fn get_last_used_line_index(&self) -> usize {
        self.current_line_index
    }

    pub fn get_cpinfo(&self, x: usize, y: usize) -> Option<&CodepointInfo> {
        match self.get_line(y) {
            None => None,
            Some(l) => l.get_cpi(x),
        }
    }

    pub fn get_mut_cpinfo(&mut self, x: usize, y: usize) -> Option<&mut CodepointInfo> {
        match self.get_mut_line(y) {
            None => None,
            Some(l) => l.get_mut_cpi(x),
        }
    }

    pub fn get_used_cpinfo(&self, x: usize, y: usize) -> Option<&CodepointInfo> {
        match self.get_used_line(y) {
            None => None,
            Some(l) => l.get_used_cpi(x),
        }
    }

    pub fn get_mut_used_cpinfo(&mut self, x: usize, y: usize) -> Option<&mut CodepointInfo> {
        match self.get_mut_used_line(y) {
            None => None,
            Some(l) => l.get_mut_used_cpi(x),
        }
    }

    pub fn get_mut_first_cpinfo(&mut self) -> (Option<&mut CodepointInfo>, usize, usize) {
        match self.get_mut_used_line(0) {
            None => (None, 0, 0),
            Some(l) => (l.get_mut_used_cpi(0), 0, 0),
        }
    }

    pub fn get_mut_last_cpinfo(&mut self) -> (Option<&mut CodepointInfo>, usize, usize) {
        let y = self.current_line_index;
        match self.get_mut_used_line(y) {
            None => (None, 0, 0),
            Some(l) => {
                let x = l.nb_cells;
                (l.get_mut_used_cpi(0), x, y)
            }
        }
    }

    pub fn get_first_cpinfo(&self) -> (Option<&CodepointInfo>, usize, usize) {
        match self.get_used_line(0) {
            None => (None, 0, 0),
            Some(l) => (l.get_used_cpi(0), 0, 0),
        }
    }

    pub fn get_last_cpinfo(&self) -> (Option<&CodepointInfo>, usize, usize) {
        // TODO: check
        let y = if self.current_line_index == self.clip.height {
            self.current_line_index - 1
        } else {
            self.current_line_index
        };

        match self.get_used_line(y) {
            None => (None, 0, 0),
            Some(l) => {
                if l.nb_cells > 0 {
                    let x = l.nb_cells - 1;
                    (l.get_used_cpi(0), x, y)
                } else {
                    (None, 0, 0)
                }
            }
        }
    }

    pub fn get_used_cpinfo_unclipped(
        &mut self,
        x: usize,
        y: usize,
    ) -> (Option<&CodepointInfo>, LineCellIndex, LineIndex) {
        match self.get_used_line(y) {
            None => (None, x, y),
            Some(l) => match l.get_used_cpi(x) {
                Some(optcpi) => (Some(optcpi), x, y),
                None => (None, x, y),
            },
        }
    }

    pub fn at_xy(&mut self, x: usize, y: usize) -> Option<&mut CodepointInfo> {
        self.get_mut_cpinfo(x, y)
    }

    pub fn at_yx(&mut self, y: usize, x: usize) -> Option<&mut CodepointInfo> {
        self.at_xy(x, y)
    }

    pub fn find_cpi_by_offset(&self, offset: u64) -> (Option<&CodepointInfo>, usize, usize) {
        // TODO: use dichotomic search

        if offset < self.first_offset || offset > self.last_offset {
            return (None, 0, 0);
        }

        for y in 0..self.height() {
            let l = self.get_line(y).unwrap();
            if l.nb_cells == 0 {
                // continue; // TODO clipping ....
            }

            // TODO: handle line.skip
            for x in 0..l.width() {
                let cpi = l.get_cpi(x).unwrap();
                if cpi.metadata {
                    continue;
                }
                if cpi.offset == offset {
                    return (Some(cpi), x, y);
                }
            }
        }
        (None, 0, 0)
    }

    pub fn contains_offset(&self, offset: u64) -> bool {
        if offset < self.first_offset || offset > self.last_offset {
            return false;
        }

        let (cpi, _, _) = self.find_cpi_by_offset(offset);
        match cpi {
            Some(_) => true,
            _ => false,
        }
    }
}

#[test]
fn test_screen() {
    let mut scr = Screen::new(640, 480);
    assert_eq!(640, scr.width());
    assert_eq!(480, scr.height());
    assert_eq!(scr.height(), scr.line.len());
    assert_eq!(scr.width(), scr.line[0].cells.len());

    scr.resize(800, 600);
    assert_eq!(800, scr.width());
    assert_eq!(600, scr.height());
    assert_eq!(scr.height(), scr.line.len());
    assert_eq!(scr.width(), scr.line[0].cells.len());

    scr.resize(1024, 768);
    assert_eq!(1024, scr.width());
    assert_eq!(768, scr.height());
    assert_eq!(scr.height(), scr.line.len());
    assert_eq!(scr.width(), scr.line[0].cells.len());

    scr.resize(640, 480);
    assert_eq!(640, scr.width());
    assert_eq!(480, scr.height());
    assert_eq!(scr.height(), scr.line.len());
    assert_eq!(scr.width(), scr.line[0].cells.len());
}
<commit_msg>api soundness : usize <-> LineIndex<commit_after>// Copyright (c) Carl-Erwin Griffith
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the
// Software without restriction, including without
// limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice
// shall be included in all copies or substantial portions
// of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER

pub mod line;
use crate::core::codepointinfo::CodepointInfo;
use std::time::Duration;

use self::line::Line;
use self::line::LineCellIndex;

pub type LineIndex = usize;

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Rect {
    pub x: usize,
    pub y: usize,
    pub width: usize,
    pub height: usize,
}

/// A Screen is composed of Line(s).

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Screen {
    /// the underlying lines storage
    pub line: Vec<Line>,
    /// the index of the line filled with the push method
    pub current_line_index: LineIndex,

    //
    clip: Rect,

    /// maximum number of elements the screen line can hold
    max_width: usize,
    /// maximum number of lines the screen can hold
    max_height: usize,

    /// the number of elements pushed in the screen
    pub nb_push: usize,
    /// placeholder to record the offset of the first pushed CodepointInfo (used by View)
    pub first_offset: u64,
    /// placeholder to record the offset of the last pushed CodepointInfo (used by View)
    pub last_offset: u64,
    /// placeholder to record the maximum offset of the document (eof)
    pub doc_max_offset: u64,
    /// time spent to generate the screen content
    pub time_to_build: Duration,

    pub input_size: usize,
}

impl Screen {
    pub fn new(width: usize, height: usize) -> Screen {
        assert!(width > 0);
        assert!(height > 0);

        let mut line: Vec<Line> = Vec::new();
        for _ in 0..height {
            line.push(Line::new(width));
        }

        Screen {
            line,
            current_line_index: 0,
            clip: Rect {
                x: 0,
                y: 0,
                width,
                height,
            },
            max_width: width,
            max_height: height,

            nb_push: 0,
            first_offset: 0,
            last_offset: 0,
            doc_max_offset: 0,
            time_to_build: Duration::new(0, 0),
            input_size: 0,
        }
    }

    pub fn check_invariants(&self) {
    }

    pub fn copy_to(&mut self, x: usize, y: usize, src: &Screen) -> bool {
        if x + src.width() > self.width() || y + src.height() > self.height() {
            return false;
        }

        for src_y in 0..src.height() {
            for src_x in 0..src.width() {
                if let Some(cpi_src) = src.get_cpinfo(src_x, src_y) {
                    if let Some(cpi_dst) = self.get_mut_cpinfo(x + src_x, y + src_y) {
                        *cpi_dst = *cpi_src;
                    }
                }
            }
        }

        true
    }

    pub fn clip_rect(&self) -> Rect {
        self.clip.clone()
    }

    pub fn width(&self) -> usize {
        self.clip.width - self.clip.x
    }

    pub fn height(&self) -> usize {
        self.clip.height - self.clip.y
    }

    // TODO: return bool
    pub fn set_clipping(&mut self, x: usize, y: usize, width: usize, height: usize) {
        assert!(x < self.max_width);
        assert!(width <= self.max_width);
        assert!(x + width <= self.max_width);

        assert!(y < self.max_height);
        assert!(height <= self.max_height);
        assert!(y + height <= self.max_height);

        for i in y..y + height {
            self.line[i].set_clipping(x, width);
        }

        // store
        self.clip = Rect {
            x,
            y,
            width: x + width,
            height: y + height,
        };

        self.current_line_index = 0; // TODO: save screen state and restore while switching clip
    }

    pub fn resize(&mut self, width: usize, height: usize) {
        self.line.resize(height, Line::new(width));
        for i in 0..height {
            self.line[i].resize(width);
        }
        self.max_height = height;
        self.max_width = width;
        self.set_clipping(0, 0, width, height);

        self.current_line_index = 0;
        self.nb_push = 0;
        self.first_offset = 0;
        self.last_offset = 0;
        self.doc_max_offset = 0;
        self.input_size = 0;
    }

    /// 0-----skip---cur_index----max_height---capacity

    /// append
    pub fn push(&mut self, cpi: CodepointInfo) -> (bool, LineIndex) {
        if self.current_line_index == self.height() {
            return (false, self.current_line_index);
        }

        if self.line[self.clip.y + self.current_line_index].read_only {
            self.current_line_index += 1;
        }

        if self.current_line_index == self.height() {
            return (false, self.current_line_index);
        }

        let cp = cpi.cp;
        let line = &mut self.line[self.clip.y + self.current_line_index];
        let (ok, _) = line.push(cpi);

        if ok {
            self.nb_push += 1;
            if cp == '\n' || cp == '\r' {
                line.read_only = true;
            }
        }
        (ok, self.current_line_index)
    }

    pub fn clear(&mut self) {
        for h in 0..self.max_height {
            self.line[h].clear();
        }
        self.current_line_index = 0;
        self.nb_push = 0;
        self.first_offset = 0;
        self.last_offset = 0;
        self.doc_max_offset = 0;
        self.input_size = 0;
        self.set_clipping(0, 0, self.max_width, self.max_height);
    }

    pub fn max_width(&self) -> usize {
        self.max_width
    }

    pub fn max_height(&self) -> usize {
        self.max_height
    }

    pub fn get_mut_unclipped_line(&mut self, index: usize) -> Option<&mut Line> {
        if index < self.max_height {
            Some(&mut self.line[index])
        } else {
            None
        }
    }

    pub fn get_mut_line(&mut self, index: usize) -> Option<&mut Line> {
        if index < self.height() {
            Some(&mut self.line[self.clip.y + index])
        } else {
            None
        }
    }

    pub fn get_unclipped_line(&self, index: usize) -> Option<&Line> {
        if index < self.max_height {
            Some(&self.line[index])
        } else {
            None
        }
    }

    pub fn get_line(&self, index: usize) -> Option<&Line> {
        if index < self.height() {
            Some(&self.line[self.clip.y + index])
        } else {
            None
        }
    }

    pub fn get_mut_used_line(&mut self, index: usize) -> Option<&mut Line> {
        if index <= self.current_line_index && self.line[self.clip.y + index].nb_cells > 0 {
            Some(&mut self.line[self.clip.y + index])
        } else {
            None
        }
    }

    pub fn get_used_line_clipped(&mut self, index: usize) -> (Option<&Line>, LineIndex) {
        let index = ::std::cmp::min(index, self.current_line_index);
        (self.get_used_line(index), index)
    }

    // improve this: loop over line nb_push > 0
    pub fn get_used_line(&self, index: usize) -> Option<&Line> {
        if index >= self.height() {
            return None;
        }

        if index <= self.current_line_index && self.line[self.clip.y + index].nb_cells > 0 {
            Some(&self.line[self.clip.y + index])
        } else {
            None
        }
    }

    /// there must be 2 lines a least
    pub fn get_first_used_line(&self) -> Option<&Line> {
        if 0 < self.current_line_index {
            Some(&self.line[self.clip.y])
        } else {
            None
        }
    }

    /// there must be 2 line a least
    pub fn get_last_used_line(&self) -> Option<&Line> {
        if self.current_line_index > 0 {
            Some(&self.line[self.clip.y + self.current_line_index - 1])
        } else {
            None
        }
    }

    pub fn get_last_used_line_index(&self) -> LineIndex {
        self.current_line_index
    }

    pub fn get_cpinfo(&self, x: usize, y: usize) -> Option<&CodepointInfo> {
        match self.get_line(y) {
            None => None,
            Some(l) => l.get_cpi(x),
        }
    }

    pub fn get_mut_cpinfo(&mut self, x: usize, y: usize) -> Option<&mut CodepointInfo> {
        match self.get_mut_line(y) {
            None => None,
            Some(l) => l.get_mut_cpi(x),
        }
    }

    pub fn get_used_cpinfo(&self, x: usize, y: usize) -> Option<&CodepointInfo> {
        match self.get_used_line(y) {
            None => None,
            Some(l) => l.get_used_cpi(x),
        }
    }

    pub fn get_mut_used_cpinfo(&mut self, x: usize, y: usize) -> Option<&mut CodepointInfo> {
        match self.get_mut_used_line(y) {
            None => None,
            Some(l) => l.get_mut_used_cpi(x),
        }
    }

    pub fn get_mut_first_cpinfo(&mut self) -> (Option<&mut CodepointInfo>, usize, usize) {
        match self.get_mut_used_line(0) {
            None => (None, 0, 0),
            Some(l) => (l.get_mut_used_cpi(0), 0, 0),
        }
    }

    pub fn get_mut_last_cpinfo(&mut self) -> (Option<&mut CodepointInfo>, usize, usize) {
        let y = self.current_line_index;
        match self.get_mut_used_line(y) {
            None => (None, 0, 0),
            Some(l) => {
                let x = l.nb_cells;
                (l.get_mut_used_cpi(0), x, y)
            }
        }
    }

    pub fn get_first_cpinfo(&self) -> (Option<&CodepointInfo>, usize, usize) {
        match self.get_used_line(0) {
            None => (None, 0, 0),
            Some(l) => (l.get_used_cpi(0), 0, 0),
        }
    }

    pub fn get_last_cpinfo(&self) -> (Option<&CodepointInfo>, usize, usize) {
        // TODO: check
        let y = if self.current_line_index == self.clip.height {
            self.current_line_index - 1
        } else {
            self.current_line_index
        };

        match self.get_used_line(y) {
            None => (None, 0, 0),
            Some(l) => {
                if l.nb_cells > 0 {
                    let x = l.nb_cells - 1;
                    (l.get_used_cpi(0), x, y)
                } else {
                    (None, 0, 0)
                }
            }
        }
    }

    pub fn get_used_cpinfo_unclipped(
        &mut self,
        x: usize,
        y: usize,
    ) -> (Option<&CodepointInfo>, LineCellIndex, LineIndex) {
        match self.get_used_line(y) {
            None => (None, x, y),
            Some(l) => match l.get_used_cpi(x) {
                Some(optcpi) => (Some(optcpi), x, y),
                None => (None, x, y),
            },
        }
    }

    pub fn at_xy(&mut self, x: usize, y: usize) -> Option<&mut CodepointInfo> {
        self.get_mut_cpinfo(x, y)
    }

    pub fn at_yx(&mut self, y: usize, x: usize) -> Option<&mut CodepointInfo> {
        self.at_xy(x, y)
    }

    pub fn find_cpi_by_offset(&self, offset: u64) -> (Option<&CodepointInfo>, usize, usize) {
        // TODO: use dichotomic search

        if offset < self.first_offset || offset > self.last_offset {
            return (None, 0, 0);
        }

        for y in 0..self.height() {
            let l = self.get_line(y).unwrap();
            if l.nb_cells == 0 {
                // continue; // TODO clipping ....
            }

            // TODO: handle line.skip
            for x in 0..l.width() {
                let cpi = l.get_cpi(x).unwrap();
                if cpi.metadata {
                    continue;
                }
                if cpi.offset == offset {
                    return (Some(cpi), x, y);
                }
            }
        }
        (None, 0, 0)
    }

    pub fn contains_offset(&self, offset: u64) -> bool {
        if offset < self.first_offset || offset > self.last_offset {
            return false;
        }

        let (cpi, _, _) = self.find_cpi_by_offset(offset);
        match cpi {
            Some(_) => true,
            _ => false,
        }
    }
}

#[test]
fn test_screen() {
    let mut scr = Screen::new(640, 480);
    assert_eq!(640, scr.width());
    assert_eq!(480, scr.height());
    assert_eq!(scr.height(), scr.line.len());
    assert_eq!(scr.width(), scr.line[0].cells.len());

    scr.resize(800, 600);
    assert_eq!(800, scr.width());
    assert_eq!(600, scr.height());
    assert_eq!(scr.height(), scr.line.len());
    assert_eq!(scr.width(), scr.line[0].cells.len());

    scr.resize(1024, 768);
    assert_eq!(1024, scr.width());
    assert_eq!(768, scr.height());
    assert_eq!(scr.height(), scr.line.len());
    assert_eq!(scr.width(), scr.line[0].cells.len());

    scr.resize(640, 480);
    assert_eq!(640, scr.width());
    assert_eq!(480, scr.height());
    assert_eq!(scr.height(), scr.line.len());
    assert_eq!(scr.width(), scr.line[0].cells.len());
}
<|endoftext|>


<commit_before>use std::ops::{Deref, DerefMut};
use rustwlc::{Geometry, Size, Point};
use super::super::borders::Borders;
use ::render::{BaseDraw, Drawable, DrawErr};

/// Draws the borders around windows.
/// They are all of the same size, including the top.
pub struct BordersDraw {
    base: BaseDraw<Borders>
}

impl BordersDraw {
    pub fn new(base: BaseDraw<Borders>) -> Self {
        BordersDraw {
            base: base
        }
    }

    fn draw_left_border(mut self,
                        mut x: f64,
                        mut y: f64,
                        mut w: f64,
                        mut h: f64,
                        border_geometry: Geometry,
                        output_res: Size)
                        -> Result<Self, DrawErr<Borders>> {
        let title_size = Borders::title_bar_size() as f64;
        // yay clamping
        if x < 0.0 {
            w += x;
        }
        if y < 0.0 {
            h += y - title_size;
        }
        x = 0.0;
        y = title_size;
        if border_geometry.origin.x + border_geometry.size.w as i32 > output_res.w as i32 {
            let offset = (border_geometry.origin.x + border_geometry.size.w as i32)
                - output_res.w as i32;
            x += offset as f64;
        }
        if border_geometry.origin.y + border_geometry.size.h as i32 > output_res.h as i32 {
            let offset = (border_geometry.origin.y + border_geometry.size.h as i32)
                - output_res.h as i32;
            y += offset as f64;
        }
        self.base.rectangle(x, y, w, h);

        self.base = try!(self.base.check_cairo());
        self.base.fill();
        self.base = try!(self.base.check_cairo());
        Ok(self)
    }

    fn draw_right_border(mut self,
                         mut x: f64,
                         mut y: f64,
                         w: f64,
                         mut h: f64,
                         border_geometry: Geometry,
                         output_res: Size)
                         -> Result<Self, DrawErr<Borders>> {
        let title_size = Borders::title_bar_size() as f64;
        // yay clamping
        if border_geometry.origin.x < 0 {
            x += border_geometry.origin.x as f64;
        }
        if y < 0.0 {
            h += y - title_size;
        }
        y = title_size;
        if border_geometry.origin.x + border_geometry.size.w as i32 > output_res.w as i32 {
            let offset = (border_geometry.origin.x + border_geometry.size.w as i32)
                - output_res.w as i32;
            x += offset as f64;
        }
        if border_geometry.origin.y + border_geometry.size.h as i32 > output_res.h as i32 {
            let offset = (border_geometry.origin.y + border_geometry.size.h as i32)
                - output_res.h as i32;
            y += offset as f64;
        }
        self.base.rectangle(x, y, w, h);
        self.base = try!(self.base.check_cairo());
        self.base.fill();
        self.base = try!(self.base.check_cairo());
        Ok(self)
    }

    fn draw_title_bar(mut self,
                      mut x: f64,
                      mut y: f64,
                      mut w: f64,
                      mut h: f64,
                      border_geometry: Geometry,
                      output_res: Size) -> Result<Self, DrawErr<Borders>> {
        let title_size = Borders::title_bar_size() as f64;
        let title_color = self.base.inner().title_background_color();
        let title_font_color = self.base.inner().title_font_color();
        let title: String = self.inner().title().into();
        if x < 0.0 {
            w += x;
        }
        if y < 0.0 {
            h += y;
        }
        let mut title_x = Borders::thickness() as f64;
        let mut title_y = title_size;
        x = 0.0;
        y = 0.0;
        if border_geometry.origin.x + border_geometry.size.w as i32 > output_res.w as i32 {
            let offset = (border_geometry.origin.x + border_geometry.size.w as i32)
                - output_res.w as i32;
            x += offset as f64;
            title_x += offset as f64;
        }
        if border_geometry.origin.y + border_geometry.size.h as i32 > output_res.h as i32 {
            let offset = (border_geometry.origin.y + border_geometry.size.h as i32)
                - output_res.h as i32;
            y += offset as f64;
            title_y += offset as f64;
        }
        // Draw background of title bar
        self.base.set_source_rgb(1.0, 0.0, 0.0);
        self.base.set_color_source(title_color);
        self.base.rectangle(x, y, w, title_size);
        self.base = try!(self.base.check_cairo());
        self.base.fill();
        self.base = try!(self.base.check_cairo());

        // Draw title text
        self.base.move_to(title_x, title_y);
        self.base = try!(self.base.check_cairo());
        self.base.set_color_source(title_font_color);
        self.base = try!(self.base.check_cairo());
        self.base.show_text(title.as_str());
        self.base = try!(self.base.check_cairo());
        Ok(self)
    }

    fn draw_top_border(mut self,
                         mut x: f64,
                         mut y: f64,
                         mut w: f64,
                         mut h: f64,
                         border_geometry: Geometry,
                         output_res: Size) -> Result<Self, DrawErr<Borders>> {
        let title_size = Borders::title_bar_size() as f64;
        // yay clamping
        if x < 0.0 {
            w += x;
        }
        if y < 0.0 {
            h += y;
        }
        x = 0.0;
        y = title_size;
        if border_geometry.origin.x + border_geometry.size.w as i32 > output_res.w as i32 {
            let offset = (border_geometry.origin.x + border_geometry.size.w as i32)
                - output_res.w as i32;
            x += offset as f64;
        }
        if border_geometry.origin.y + border_geometry.size.h as i32 > output_res.h as i32 {
            let offset = (border_geometry.origin.y + border_geometry.size.h as i32)
                - output_res.h as i32;
            y += offset as f64;
        }
        self.base.rectangle(x, y, w, h);
        self.base = try!(self.base.check_cairo());
        self.base.fill();
        self.base = try!(self.base.check_cairo());
        Ok(self)
    }

    fn draw_bottom_border(mut self,
                            mut x: f64,
                            mut y: f64,
                            mut w: f64,
                            h: f64,
                            border_geometry: Geometry,
                            output_res: Size)
                            -> Result<Self, DrawErr<Borders>> {
        // yay clamping
        if x < 0.0 {
            w += x;
        }
        if border_geometry.origin.y < 0 {
            y += border_geometry.origin.y as f64;
        }
        x = 0.0;
        if border_geometry.origin.x + border_geometry.size.w as i32 > output_res.w as i32 {
            let offset = (border_geometry.origin.x + border_geometry.size.w as i32)
                - output_res.w as i32;
            x += offset as f64;
        }
        if border_geometry.origin.y + border_geometry.size.h as i32 > output_res.h as i32 {
            let offset = (border_geometry.origin.y + border_geometry.size.h as i32)
                - output_res.h as i32;
            y += offset as f64;
        }
        self.base.rectangle(x, y, w, h);
        self.base = try!(self.base.check_cairo());
        self.base.fill();
        self.base = try!(self.base.check_cairo());
        Ok(self)
    }
}

impl Drawable<Borders> for BordersDraw {
    fn draw(mut self, view_g: Geometry) -> Result<Borders, DrawErr<Borders>> {
        let mut border_g = view_g;
        let thickness = Borders::thickness();
        let edge_thickness = thickness / 2;
        let output_res = self.inner().get_output().get_resolution()
            .expect("Could not get focused output's resolution");
        let title_size = Borders::title_bar_size();
        border_g.origin.x -= edge_thickness as i32;
        border_g.origin.y -= edge_thickness as i32;
        border_g.origin.y -= title_size as i32;
        border_g.size.w += thickness;
        border_g.size.h += thickness;
        border_g.size.h += title_size;

        self.base.set_source_rgba(0.0, 0.0, 0.0, 0.0);
        self.base.paint();
        let color = self.base.inner().color();
        self.base.set_color_source(color);

        let Size { w, h } = border_g.size;
        let Point { x, y } = border_g.origin;
        // basically after everything after this point is floating point arithmetic
        // whee!
        let (x, y, w, h) = (x as f64,
                            y as f64,
                            w as f64,
                            h as f64);
        let edge_thickness = edge_thickness as f64;
        self = self.draw_left_border(x, y, edge_thickness, h, border_g, output_res)?
        .draw_right_border(w - edge_thickness, y, edge_thickness, h, border_g, output_res)?
        .draw_top_border(x, y, w, edge_thickness, border_g, output_res)?
        .draw_bottom_border(x, h, w, -edge_thickness, border_g, output_res)?
        .draw_title_bar(x, y, w, edge_thickness, border_g, output_res)?;

        Ok(self.base.finish(border_g))
    }
}

impl Deref for BordersDraw {
    type Target = BaseDraw<Borders>;

    fn deref(&self) -> &BaseDraw<Borders> {
        &self.base
    }
}

impl DerefMut for BordersDraw {
    fn deref_mut(&mut self) -> &mut BaseDraw<Borders> {
        &mut self.base
    }
}
<commit_msg>Fixed warnings<commit_after>use std::ops::{Deref, DerefMut};
use rustwlc::{Geometry, Size, Point};
use super::super::borders::Borders;
use ::render::{BaseDraw, Drawable, DrawErr};

/// Draws the borders around windows.
/// They are all of the same size, including the top.
pub struct BordersDraw {
    base: BaseDraw<Borders>
}

impl BordersDraw {
    pub fn new(base: BaseDraw<Borders>) -> Self {
        BordersDraw {
            base: base
        }
    }

    fn draw_left_border(mut self,
                        mut x: f64,
                        mut y: f64,
                        mut w: f64,
                        mut h: f64,
                        border_geometry: Geometry,
                        output_res: Size)
                        -> Result<Self, DrawErr<Borders>> {
        let title_size = Borders::title_bar_size() as f64;
        // yay clamping
        if x < 0.0 {
            w += x;
        }
        if y < 0.0 {
            h += y - title_size;
        }
        x = 0.0;
        y = title_size;
        if border_geometry.origin.x + border_geometry.size.w as i32 > output_res.w as i32 {
            let offset = (border_geometry.origin.x + border_geometry.size.w as i32)
                - output_res.w as i32;
            x += offset as f64;
        }
        if border_geometry.origin.y + border_geometry.size.h as i32 > output_res.h as i32 {
            let offset = (border_geometry.origin.y + border_geometry.size.h as i32)
                - output_res.h as i32;
            y += offset as f64;
        }
        self.base.rectangle(x, y, w, h);

        self.base = try!(self.base.check_cairo());
        self.base.fill();
        self.base = try!(self.base.check_cairo());
        Ok(self)
    }

    fn draw_right_border(mut self,
                         mut x: f64,
                         mut y: f64,
                         w: f64,
                         mut h: f64,
                         border_geometry: Geometry,
                         output_res: Size)
                         -> Result<Self, DrawErr<Borders>> {
        let title_size = Borders::title_bar_size() as f64;
        // yay clamping
        if border_geometry.origin.x < 0 {
            x += border_geometry.origin.x as f64;
        }
        if y < 0.0 {
            h += y - title_size;
        }
        y = title_size;
        if border_geometry.origin.x + border_geometry.size.w as i32 > output_res.w as i32 {
            let offset = (border_geometry.origin.x + border_geometry.size.w as i32)
                - output_res.w as i32;
            x += offset as f64;
        }
        if border_geometry.origin.y + border_geometry.size.h as i32 > output_res.h as i32 {
            let offset = (border_geometry.origin.y + border_geometry.size.h as i32)
                - output_res.h as i32;
            y += offset as f64;
        }
        self.base.rectangle(x, y, w, h);
        self.base = try!(self.base.check_cairo());
        self.base.fill();
        self.base = try!(self.base.check_cairo());
        Ok(self)
    }

    fn draw_title_bar(mut self,
                      mut x: f64,
                      _y: f64,
                      mut w: f64,
                      _h: f64,
                      border_geometry: Geometry,
                      output_res: Size) -> Result<Self, DrawErr<Borders>> {
        let title_size = Borders::title_bar_size() as f64;
        let title_color = self.base.inner().title_background_color();
        let title_font_color = self.base.inner().title_font_color();
        let title: String = self.inner().title().into();
        if x < 0.0 {
            w += x;
        }
        let mut title_x = Borders::thickness() as f64;
        let mut title_y = title_size;
        x = 0.0;
        let mut y = 0.0;
        if border_geometry.origin.x + border_geometry.size.w as i32 > output_res.w as i32 {
            let offset = (border_geometry.origin.x + border_geometry.size.w as i32)
                - output_res.w as i32;
            x += offset as f64;
            title_x += offset as f64;
        }
        if border_geometry.origin.y + border_geometry.size.h as i32 > output_res.h as i32 {
            let offset = (border_geometry.origin.y + border_geometry.size.h as i32)
                - output_res.h as i32;
            y += offset as f64;
            title_y += offset as f64;
        }
        // Draw background of title bar
        self.base.set_source_rgb(1.0, 0.0, 0.0);
        self.base.set_color_source(title_color);
        self.base.rectangle(x, y, w, title_size);
        self.base = try!(self.base.check_cairo());
        self.base.fill();
        self.base = try!(self.base.check_cairo());

        // Draw title text
        self.base.move_to(title_x, title_y);
        self.base = try!(self.base.check_cairo());
        self.base.set_color_source(title_font_color);
        self.base = try!(self.base.check_cairo());
        self.base.show_text(title.as_str());
        self.base = try!(self.base.check_cairo());
        Ok(self)
    }

    fn draw_top_border(mut self,
                         mut x: f64,
                         mut y: f64,
                         mut w: f64,
                         mut h: f64,
                         border_geometry: Geometry,
                         output_res: Size) -> Result<Self, DrawErr<Borders>> {
        let title_size = Borders::title_bar_size() as f64;
        // yay clamping
        if x < 0.0 {
            w += x;
        }
        if y < 0.0 {
            h += y;
        }
        x = 0.0;
        y = title_size;
        if border_geometry.origin.x + border_geometry.size.w as i32 > output_res.w as i32 {
            let offset = (border_geometry.origin.x + border_geometry.size.w as i32)
                - output_res.w as i32;
            x += offset as f64;
        }
        if border_geometry.origin.y + border_geometry.size.h as i32 > output_res.h as i32 {
            let offset = (border_geometry.origin.y + border_geometry.size.h as i32)
                - output_res.h as i32;
            y += offset as f64;
        }
        self.base.rectangle(x, y, w, h);
        self.base = try!(self.base.check_cairo());
        self.base.fill();
        self.base = try!(self.base.check_cairo());
        Ok(self)
    }

    fn draw_bottom_border(mut self,
                            mut x: f64,
                            mut y: f64,
                            mut w: f64,
                            h: f64,
                            border_geometry: Geometry,
                            output_res: Size)
                            -> Result<Self, DrawErr<Borders>> {
        // yay clamping
        if x < 0.0 {
            w += x;
        }
        if border_geometry.origin.y < 0 {
            y += border_geometry.origin.y as f64;
        }
        x = 0.0;
        if border_geometry.origin.x + border_geometry.size.w as i32 > output_res.w as i32 {
            let offset = (border_geometry.origin.x + border_geometry.size.w as i32)
                - output_res.w as i32;
            x += offset as f64;
        }
        if border_geometry.origin.y + border_geometry.size.h as i32 > output_res.h as i32 {
            let offset = (border_geometry.origin.y + border_geometry.size.h as i32)
                - output_res.h as i32;
            y += offset as f64;
        }
        self.base.rectangle(x, y, w, h);
        self.base = try!(self.base.check_cairo());
        self.base.fill();
        self.base = try!(self.base.check_cairo());
        Ok(self)
    }
}

impl Drawable<Borders> for BordersDraw {
    fn draw(mut self, view_g: Geometry) -> Result<Borders, DrawErr<Borders>> {
        let mut border_g = view_g;
        let thickness = Borders::thickness();
        let edge_thickness = thickness / 2;
        let output_res = self.inner().get_output().get_resolution()
            .expect("Could not get focused output's resolution");
        let title_size = Borders::title_bar_size();
        border_g.origin.x -= edge_thickness as i32;
        border_g.origin.y -= edge_thickness as i32;
        border_g.origin.y -= title_size as i32;
        border_g.size.w += thickness;
        border_g.size.h += thickness;
        border_g.size.h += title_size;

        self.base.set_source_rgba(0.0, 0.0, 0.0, 0.0);
        self.base.paint();
        let color = self.base.inner().color();
        self.base.set_color_source(color);

        let Size { w, h } = border_g.size;
        let Point { x, y } = border_g.origin;
        // basically after everything after this point is floating point arithmetic
        // whee!
        let (x, y, w, h) = (x as f64,
                            y as f64,
                            w as f64,
                            h as f64);
        let edge_thickness = edge_thickness as f64;
        self = self.draw_left_border(x, y, edge_thickness, h, border_g, output_res)?
        .draw_right_border(w - edge_thickness, y, edge_thickness, h, border_g, output_res)?
        .draw_top_border(x, y, w, edge_thickness, border_g, output_res)?
        .draw_bottom_border(x, h, w, -edge_thickness, border_g, output_res)?
        .draw_title_bar(x, y, w, edge_thickness, border_g, output_res)?;

        Ok(self.base.finish(border_g))
    }
}

impl Deref for BordersDraw {
    type Target = BaseDraw<Borders>;

    fn deref(&self) -> &BaseDraw<Borders> {
        &self.base
    }
}

impl DerefMut for BordersDraw {
    fn deref_mut(&mut self) -> &mut BaseDraw<Borders> {
        &mut self.base
    }
}
<|endoftext|>


<commit_before>/*!
`crypto_stream_xsalsa20`, a particular cipher specified in
[Cryptography in NaCl](http://nacl.cr.yp.to/valid.html), Section 7.
This cipher is conjectured to meet the standard notion of
unpredictability.
*/
use libc::{c_ulonglong, c_int};
use std::intrinsics::volatile_set_memory;
use randombytes::randombytes_into;

stream_module!(crypto_stream_xsalsa20, crypto_stream_xsalsa20_xor, 32, 24)
#[test]
fn test_vector_1() {
    // corresponding to tests/stream.c and tests/stream5.cpp from NaCl
    use crypto::hash::sha256::{hash, Digest};
    let firstkey = Key([0x1b,0x27,0x55,0x64,0x73,0xe9,0x85,0xd4
                       ,0x62,0xcd,0x51,0x19,0x7a,0x9a,0x46,0xc7
                       ,0x60,0x09,0x54,0x9e,0xac,0x64,0x74,0xf2
                       ,0x06,0xc4,0xee,0x08,0x44,0xf6,0x83,0x89]);
    let nonce = Nonce([0x69,0x69,0x6e,0xe9,0x55,0xb6,0x2b,0x73
                      ,0xcd,0x62,0xbd,0xa8,0x75,0xfc,0x73,0xd6
                      ,0x82,0x19,0xe0,0x03,0x6b,0x7a,0x0b,0x37]);
    let output = stream(4194304, &nonce, &firstkey);
    let digest_expected = [0x66, 0x2b, 0x9d, 0x0e, 0x34, 0x63, 0x02, 0x91,
                           0x56, 0x06, 0x9b, 0x12, 0xf9, 0x18, 0x69, 0x1a,
                           0x98, 0xf7, 0xdf, 0xb2, 0xca, 0x03, 0x93, 0xc9,
                           0x6b, 0xbf, 0xc6, 0xb1, 0xfb, 0xd6, 0x30, 0xa2];
    let Digest(digest) = hash(output.as_slice());
    assert!(digest == digest_expected);

}

#[test]
fn test_vector_2() {
    // corresponding to tests/stream3.c and tests/stream7.cpp from NaCl
    let firstkey = Key([0x1b,0x27,0x55,0x64,0x73,0xe9,0x85,0xd4
                       ,0x62,0xcd,0x51,0x19,0x7a,0x9a,0x46,0xc7
                       ,0x60,0x09,0x54,0x9e,0xac,0x64,0x74,0xf2
                       ,0x06,0xc4,0xee,0x08,0x44,0xf6,0x83,0x89]);
    let nonce = Nonce([0x69,0x69,0x6e,0xe9,0x55,0xb6,0x2b,0x73
                      ,0xcd,0x62,0xbd,0xa8,0x75,0xfc,0x73,0xd6
                      ,0x82,0x19,0xe0,0x03,0x6b,0x7a,0x0b,0x37]);
    let rs = stream(32, &nonce, &firstkey);
    let rs_expected = vec![0xee,0xa6,0xa7,0x25,0x1c,0x1e,0x72,0x91
                       ,0x6d,0x11,0xc2,0xcb,0x21,0x4d,0x3c,0x25
                       ,0x25,0x39,0x12,0x1d,0x8e,0x23,0x4e,0x65
                       ,0x2d,0x65,0x1f,0xa4,0xc8,0xcf,0xf8,0x80];
    assert!(rs == rs_expected);
}

#[test]
fn test_vector_3() {
    // corresponding to tests/stream4.c and tests/stream8.cpp from NaCl
    let firstkey = Key([0x1b,0x27,0x55,0x64,0x73,0xe9,0x85,0xd4
                       ,0x62,0xcd,0x51,0x19,0x7a,0x9a,0x46,0xc7
                       ,0x60,0x09,0x54,0x9e,0xac,0x64,0x74,0xf2
                       ,0x06,0xc4,0xee,0x08,0x44,0xf6,0x83,0x89]);
    let nonce = Nonce([0x69,0x69,0x6e,0xe9,0x55,0xb6,0x2b,0x73
                      ,0xcd,0x62,0xbd,0xa8,0x75,0xfc,0x73,0xd6
                      ,0x82,0x19,0xe0,0x03,0x6b,0x7a,0x0b,0x37]);
    let m = &[    0,   0,   0,   0,   0,   0,   0,   0
             ,    0,   0,   0,   0,   0,   0,   0,   0
             ,    0,   0,   0,   0,   0,   0,   0,   0
             ,    0,   0,   0,   0,   0,   0,   0,   0
             , 0xbe,0x07,0x5f,0xc5,0x3c,0x81,0xf2,0xd5
             , 0xcf,0x14,0x13,0x16,0xeb,0xeb,0x0c,0x7b
             , 0x52,0x28,0xc5,0x2a,0x4c,0x62,0xcb,0xd4
             , 0x4b,0x66,0x84,0x9b,0x64,0x24,0x4f,0xfc
             , 0xe5,0xec,0xba,0xaf,0x33,0xbd,0x75,0x1a
             , 0x1a,0xc7,0x28,0xd4,0x5e,0x6c,0x61,0x29
             , 0x6c,0xdc,0x3c,0x01,0x23,0x35,0x61,0xf4
             , 0x1d,0xb6,0x6c,0xce,0x31,0x4a,0xdb,0x31
             , 0x0e,0x3b,0xe8,0x25,0x0c,0x46,0xf0,0x6d
             , 0xce,0xea,0x3a,0x7f,0xa1,0x34,0x80,0x57
             , 0xe2,0xf6,0x55,0x6a,0xd6,0xb1,0x31,0x8a
             , 0x02,0x4a,0x83,0x8f,0x21,0xaf,0x1f,0xde
             , 0x04,0x89,0x77,0xeb,0x48,0xf5,0x9f,0xfd
             , 0x49,0x24,0xca,0x1c,0x60,0x90,0x2e,0x52
             , 0xf0,0xa0,0x89,0xbc,0x76,0x89,0x70,0x40
             , 0xe0,0x82,0xf9,0x37,0x76,0x38,0x48,0x64
             , 0x5e,0x07,0x05];

    let c = stream_xor(m, &nonce, &firstkey);
    let c_expected = [0x8e,0x99,0x3b,0x9f,0x48,0x68,0x12,0x73
                     ,0xc2,0x96,0x50,0xba,0x32,0xfc,0x76,0xce
                     ,0x48,0x33,0x2e,0xa7,0x16,0x4d,0x96,0xa4
                     ,0x47,0x6f,0xb8,0xc5,0x31,0xa1,0x18,0x6a
                     ,0xc0,0xdf,0xc1,0x7c,0x98,0xdc,0xe8,0x7b
                     ,0x4d,0xa7,0xf0,0x11,0xec,0x48,0xc9,0x72
                     ,0x71,0xd2,0xc2,0x0f,0x9b,0x92,0x8f,0xe2
                     ,0x27,0x0d,0x6f,0xb8,0x63,0xd5,0x17,0x38
                     ,0xb4,0x8e,0xee,0xe3,0x14,0xa7,0xcc,0x8a
                     ,0xb9,0x32,0x16,0x45,0x48,0xe5,0x26,0xae
                     ,0x90,0x22,0x43,0x68,0x51,0x7a,0xcf,0xea
                     ,0xbd,0x6b,0xb3,0x73,0x2b,0xc0,0xe9,0xda
                     ,0x99,0x83,0x2b,0x61,0xca,0x01,0xb6,0xde
                     ,0x56,0x24,0x4a,0x9e,0x88,0xd5,0xf9,0xb3
                     ,0x79,0x73,0xf6,0x22,0xa4,0x3d,0x14,0xa6
                     ,0x59,0x9b,0x1f,0x65,0x4c,0xb4,0x5a,0x74
                     ,0xe3,0x55,0xa5];
    assert!(c.slice_from(32) == &c_expected);
}
<commit_msg>Fix compilation failure on latest rust-nightly<commit_after>/*!
`crypto_stream_xsalsa20`, a particular cipher specified in
[Cryptography in NaCl](http://nacl.cr.yp.to/valid.html), Section 7.
This cipher is conjectured to meet the standard notion of
unpredictability.
*/
use libc::{c_ulonglong, c_int};
use std::intrinsics::volatile_set_memory;
use randombytes::randombytes_into;

stream_module!(crypto_stream_xsalsa20, crypto_stream_xsalsa20_xor, 32, 24)
#[test]
fn test_vector_1() {
    // corresponding to tests/stream.c and tests/stream5.cpp from NaCl
    use crypto::hash::sha256::{hash, Digest};
    let firstkey = Key([0x1b,0x27,0x55,0x64,0x73,0xe9,0x85,0xd4
                       ,0x62,0xcd,0x51,0x19,0x7a,0x9a,0x46,0xc7
                       ,0x60,0x09,0x54,0x9e,0xac,0x64,0x74,0xf2
                       ,0x06,0xc4,0xee,0x08,0x44,0xf6,0x83,0x89]);
    let nonce = Nonce([0x69,0x69,0x6e,0xe9,0x55,0xb6,0x2b,0x73
                      ,0xcd,0x62,0xbd,0xa8,0x75,0xfc,0x73,0xd6
                      ,0x82,0x19,0xe0,0x03,0x6b,0x7a,0x0b,0x37]);
    let output = stream(4194304, &nonce, &firstkey);
    let digest_expected = [0x66, 0x2b, 0x9d, 0x0e, 0x34, 0x63, 0x02, 0x91,
                           0x56, 0x06, 0x9b, 0x12, 0xf9, 0x18, 0x69, 0x1a,
                           0x98, 0xf7, 0xdf, 0xb2, 0xca, 0x03, 0x93, 0xc9,
                           0x6b, 0xbf, 0xc6, 0xb1, 0xfb, 0xd6, 0x30, 0xa2];
    let Digest(digest) = hash(output.as_slice());
    assert!(digest == digest_expected);

}

#[test]
fn test_vector_2() {
    // corresponding to tests/stream3.c and tests/stream7.cpp from NaCl
    let firstkey = Key([0x1b,0x27,0x55,0x64,0x73,0xe9,0x85,0xd4
                       ,0x62,0xcd,0x51,0x19,0x7a,0x9a,0x46,0xc7
                       ,0x60,0x09,0x54,0x9e,0xac,0x64,0x74,0xf2
                       ,0x06,0xc4,0xee,0x08,0x44,0xf6,0x83,0x89]);
    let nonce = Nonce([0x69,0x69,0x6e,0xe9,0x55,0xb6,0x2b,0x73
                      ,0xcd,0x62,0xbd,0xa8,0x75,0xfc,0x73,0xd6
                      ,0x82,0x19,0xe0,0x03,0x6b,0x7a,0x0b,0x37]);
    let rs = stream(32, &nonce, &firstkey);
    let rs_expected = vec![0xee,0xa6,0xa7,0x25,0x1c,0x1e,0x72,0x91
                       ,0x6d,0x11,0xc2,0xcb,0x21,0x4d,0x3c,0x25
                       ,0x25,0x39,0x12,0x1d,0x8e,0x23,0x4e,0x65
                       ,0x2d,0x65,0x1f,0xa4,0xc8,0xcf,0xf8,0x80];
    assert!(rs == rs_expected);
}

#[test]
fn test_vector_3() {
    // corresponding to tests/stream4.c and tests/stream8.cpp from NaCl
    let firstkey = Key([0x1b,0x27,0x55,0x64,0x73,0xe9,0x85,0xd4
                       ,0x62,0xcd,0x51,0x19,0x7a,0x9a,0x46,0xc7
                       ,0x60,0x09,0x54,0x9e,0xac,0x64,0x74,0xf2
                       ,0x06,0xc4,0xee,0x08,0x44,0xf6,0x83,0x89]);
    let nonce = Nonce([0x69,0x69,0x6e,0xe9,0x55,0xb6,0x2b,0x73
                      ,0xcd,0x62,0xbd,0xa8,0x75,0xfc,0x73,0xd6
                      ,0x82,0x19,0xe0,0x03,0x6b,0x7a,0x0b,0x37]);
    let m = &[    0,   0,   0,   0,   0,   0,   0,   0
             ,    0,   0,   0,   0,   0,   0,   0,   0
             ,    0,   0,   0,   0,   0,   0,   0,   0
             ,    0,   0,   0,   0,   0,   0,   0,   0
             , 0xbe,0x07,0x5f,0xc5,0x3c,0x81,0xf2,0xd5
             , 0xcf,0x14,0x13,0x16,0xeb,0xeb,0x0c,0x7b
             , 0x52,0x28,0xc5,0x2a,0x4c,0x62,0xcb,0xd4
             , 0x4b,0x66,0x84,0x9b,0x64,0x24,0x4f,0xfc
             , 0xe5,0xec,0xba,0xaf,0x33,0xbd,0x75,0x1a
             , 0x1a,0xc7,0x28,0xd4,0x5e,0x6c,0x61,0x29
             , 0x6c,0xdc,0x3c,0x01,0x23,0x35,0x61,0xf4
             , 0x1d,0xb6,0x6c,0xce,0x31,0x4a,0xdb,0x31
             , 0x0e,0x3b,0xe8,0x25,0x0c,0x46,0xf0,0x6d
             , 0xce,0xea,0x3a,0x7f,0xa1,0x34,0x80,0x57
             , 0xe2,0xf6,0x55,0x6a,0xd6,0xb1,0x31,0x8a
             , 0x02,0x4a,0x83,0x8f,0x21,0xaf,0x1f,0xde
             , 0x04,0x89,0x77,0xeb,0x48,0xf5,0x9f,0xfd
             , 0x49,0x24,0xca,0x1c,0x60,0x90,0x2e,0x52
             , 0xf0,0xa0,0x89,0xbc,0x76,0x89,0x70,0x40
             , 0xe0,0x82,0xf9,0x37,0x76,0x38,0x48,0x64
             , 0x5e,0x07,0x05];

    let c = stream_xor(m, &nonce, &firstkey);
    let c_expected = [0x8e,0x99,0x3b,0x9f,0x48,0x68,0x12,0x73
                     ,0xc2,0x96,0x50,0xba,0x32,0xfc,0x76,0xce
                     ,0x48,0x33,0x2e,0xa7,0x16,0x4d,0x96,0xa4
                     ,0x47,0x6f,0xb8,0xc5,0x31,0xa1,0x18,0x6a
                     ,0xc0,0xdf,0xc1,0x7c,0x98,0xdc,0xe8,0x7b
                     ,0x4d,0xa7,0xf0,0x11,0xec,0x48,0xc9,0x72
                     ,0x71,0xd2,0xc2,0x0f,0x9b,0x92,0x8f,0xe2
                     ,0x27,0x0d,0x6f,0xb8,0x63,0xd5,0x17,0x38
                     ,0xb4,0x8e,0xee,0xe3,0x14,0xa7,0xcc,0x8a
                     ,0xb9,0x32,0x16,0x45,0x48,0xe5,0x26,0xae
                     ,0x90,0x22,0x43,0x68,0x51,0x7a,0xcf,0xea
                     ,0xbd,0x6b,0xb3,0x73,0x2b,0xc0,0xe9,0xda
                     ,0x99,0x83,0x2b,0x61,0xca,0x01,0xb6,0xde
                     ,0x56,0x24,0x4a,0x9e,0x88,0xd5,0xf9,0xb3
                     ,0x79,0x73,0xf6,0x22,0xa4,0x3d,0x14,0xa6
                     ,0x59,0x9b,0x1f,0x65,0x4c,0xb4,0x5a,0x74
                     ,0xe3,0x55,0xa5];
    assert!(c.slice_from(32) == c_expected.as_slice());
}
<|endoftext|>