<commit_before>use bot::LalafellBot;
use tasks::RunsTask;
use database::models::DeleteAllMessages;

use discord::GetMessages;
use discord::model::ChannelId;

use chrono::prelude::*;
use chrono::Duration;

use error::*;

use diesel::prelude::*;

use std::sync::Arc;
use std::thread;

#[derive(Debug)]
pub struct DeleteAllMessagesTask {
  next_sleep: i64
}

impl DeleteAllMessagesTask {
  pub fn new() -> Self {
    DeleteAllMessagesTask {
      next_sleep: 30
    }
  }
}

impl RunsTask for DeleteAllMessagesTask {
  fn start(mut self, s: Arc<LalafellBot>) {
    loop {
      thread::sleep(Duration::seconds(self.next_sleep).to_std().unwrap());
      info!("Delete messages task running");
      let dams: Result<Vec<DeleteAllMessages>> = ::bot::CONNECTION.with(|c| {
        use database::schema::delete_all_messages::dsl;
        dsl::delete_all_messages.load(c).chain_err(|| "could not load delete_all_messages")
      });
      let dams = match dams {
        Ok(d) => d,
        Err(e) => {
          warn!("could not load delete_all_messages: {}", e);
          continue;
        }
      };
      for dam in dams {
        let channel = ChannelId(*dam.channel_id);
        let messages = match s.discord.get_messages(channel, GetMessages::MostRecent, None) {
          Ok(m) => m,
          Err(e) => {
            warn!("Could not get messages for channel {}: {}", channel, e);
            continue;
          }
        };
        let mut to_delete = Vec::new();
        let exclude = dam.exclude();
        for message in messages {
          if exclude.contains(&message.id.0) {
            continue;
          }
          if message.timestamp.with_timezone(&Utc) + Duration::seconds(i64::from(dam.after)) > Utc::now() {
            continue;
          }
          to_delete.push(message);
        }
        info!("{} message{} to delete", to_delete.len(), if to_delete.len() == 1 { "" } else { "s" });
        for chunk in to_delete.chunks(100) {
          info!("Deleting chunk of {} message{}", chunk.len(), if chunk.len() == 1 { "" } else { "s" });
          let result = if chunk.len() == 1 {
            s.discord.delete_message(channel, chunk[0].id)
          } else {
            let ids: Vec<_> = chunk.iter().map(|m| m.id).collect();
            s.discord.delete_messages(channel, &ids)
          };
          if let Err(e) = result {
            warn!("Could not delete messages: {}", e);
          }
        }
        info!("Delete messages task done");
      }
      self.next_sleep = 60;
    }
  }
}
<commit_msg>fix: don't output more messages than necessary<commit_after>use bot::LalafellBot;
use tasks::RunsTask;
use database::models::DeleteAllMessages;

use discord::GetMessages;
use discord::model::ChannelId;

use chrono::prelude::*;
use chrono::Duration;

use error::*;

use diesel::prelude::*;

use std::sync::Arc;
use std::thread;

#[derive(Debug)]
pub struct DeleteAllMessagesTask {
  next_sleep: i64
}

impl DeleteAllMessagesTask {
  pub fn new() -> Self {
    DeleteAllMessagesTask {
      next_sleep: 30
    }
  }
}

impl RunsTask for DeleteAllMessagesTask {
  fn start(mut self, s: Arc<LalafellBot>) {
    loop {
      thread::sleep(Duration::seconds(self.next_sleep).to_std().unwrap());
      info!("Delete messages task running");
      let dams: Result<Vec<DeleteAllMessages>> = ::bot::CONNECTION.with(|c| {
        use database::schema::delete_all_messages::dsl;
        dsl::delete_all_messages.load(c).chain_err(|| "could not load delete_all_messages")
      });
      let dams = match dams {
        Ok(d) => d,
        Err(e) => {
          warn!("could not load delete_all_messages: {}", e);
          continue;
        }
      };
      for dam in dams {
        let channel = ChannelId(*dam.channel_id);
        let messages = match s.discord.get_messages(channel, GetMessages::MostRecent, None) {
          Ok(m) => m,
          Err(e) => {
            warn!("Could not get messages for channel {}: {}", channel, e);
            continue;
          }
        };
        let mut to_delete = Vec::new();
        let exclude = dam.exclude();
        for message in messages {
          if exclude.contains(&message.id.0) {
            continue;
          }
          if message.timestamp.with_timezone(&Utc) + Duration::seconds(i64::from(dam.after)) > Utc::now() {
            continue;
          }
          to_delete.push(message);
        }
        if !to_delete.is_empty() {
          info!("{} message{} to delete", to_delete.len(), if to_delete.len() == 1 { "" } else { "s" });
        }
        for chunk in to_delete.chunks(100) {
          info!("Deleting chunk of {} message{}", chunk.len(), if chunk.len() == 1 { "" } else { "s" });
          let result = if chunk.len() == 1 {
            s.discord.delete_message(channel, chunk[0].id)
          } else {
            let ids: Vec<_> = chunk.iter().map(|m| m.id).collect();
            s.discord.delete_messages(channel, &ids)
          };
          if let Err(e) = result {
            warn!("Could not delete messages: {}", e);
          }
        }
      }
      info!("Delete messages task done");
      self.next_sleep = 60;
    }
  }
}
<|endoftext|>


<commit_before>use std::env;
use std::ffi::{OsStr, OsString};
use std::fs::copy;
use std::path::Path;

extern crate walkdir;
use walkdir::{DirEntry, WalkDir};

fn main() {

    // Assume libsdl2*-dev etc. are installed with the package manager on unix family systems.
    //
    // On a windows OS we look for the C built sdl2 libraries for the relevant platform/architecture
    // and add them to the Link arguments.
    // We also ensure that the DLLs have been copied to ./sdl_libs (or SDL_LIBS_DIR).
    // The `cargo run` command will look for sdl2 dlls in ./sdl_libs...it's unknown why cargo cannot
    // be told to find the DLLs in subdirectories of sdl_libs.
    if cfg!(target_family = "windows") {

        let root_libs_dir = if let Ok(dir) = env::var("SDL_LIBS_DIR") {
            Some(dir)
        } else {
            if let Ok(cargo_root_dir) = env::var("CARGO_MANIFEST_DIR") {
                Some(format!("{}/sdl_libs", cargo_root_dir))
            } else {
                None
            }
        };

        if let Some(libs) = root_libs_dir {

            // Add link flag for the compiler
            println!("cargo:rustc-flags=-L {}", libs);

            // Copy sdl2 related DLLs to the root libs directory.
            let is_x64 = cfg!(target_arch = "x86_64");
            let is_mingw = cfg!(target_env = "gnu");

            let select_libs_dir = |base_dir| {
                let dir = format!("{}/{}/{}/{}",
                                  libs,
                                  base_dir,
                                  if is_mingw {
                                      "mingw"
                                  } else {
                                      "msvc"
                                  },
                                  if is_x64 {
                                      "x64"
                                  } else {
                                      "x32"
                                  });
                dir
            };

            let machine_lib_dirs = [select_libs_dir("sdl2"),
                                    select_libs_dir("sdl2-image"),
                                    select_libs_dir("sdl2-ttf")];

            for dir in &machine_lib_dirs {

                println!("cargo:rustc-flags=-L {}", dir);

                for entry in WalkDir::new(dir) {
                    let entry = entry.unwrap();

                    if is_dll_file(&entry) {

                        let src_file_path: &Path = entry.path();
                        let src_file_name: &OsStr = entry.file_name();
                        let target_dir: &String = &libs;
                        let target_dir_path: &Path = Path::new(target_dir);
                        let target_file_str: OsString = target_dir_path.join(src_file_name)
                                                                       .into_os_string();
                        let target_file_path: &Path = Path::new(&target_file_str);

                        if !target_file_path.exists() ||
                           are_different_file_contents(&entry, target_file_path) {

                            copy(src_file_path, target_file_path)
                                .expect(format!("Failed to copy windows os dll from {} to {}",
                                                src_file_path.display(),
                                                target_file_path.display())
                                            .as_str());
                        }
                    }
                }
            }
        }
    }
}

fn is_dll_file(entry: &DirEntry) -> bool {

    if entry.file_type().is_file() {
        if let Some(osstr_ext) = entry.path().extension() {
            if let Some(ext) = osstr_ext.to_str() {
                return ext == "dll";
            }
        }
    }

    false
}

fn are_different_file_contents(entry: &DirEntry, file_path: &Path) -> bool {
    let entry_meta_r = entry.metadata();
    let file_meta_r = file_path.metadata();

    if let (Ok(entry_meta), Ok(file_meta)) = (entry_meta_r, file_meta_r) {

        if entry_meta.is_file() && file_meta.is_file() && entry_meta.len() == file_meta.len() {
            false
        } else {
            true
        }

    } else {
        // When we cannot read the metadata then default to assuming
        // different files.
        true
    }
}
<commit_msg>Windows MSVC build.<commit_after>use std::env;
use std::ffi::{OsStr, OsString};
use std::fs::copy;
use std::path::Path;

extern crate walkdir;
use walkdir::{DirEntry, WalkDir};

fn main() {

    // Assume libsdl2*-dev etc. are installed with the package manager on unix family systems.
    //
    // On a windows OS we look for the C built sdl2 libraries for the relevant platform/architecture
    // and add them to the Link arguments.
    // We also ensure that the DLLs have been copied to the project root (or SDL_DLLS_RUN_DIR env var dir)
    // so that cargo run can find them.
    if cfg!(target_family = "windows") {

        // Assuming cargo always sets this environment variable.
        let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();

        let win_sdl_dlls_dir = if let Ok(dir) = env::var("SDL_DLLS_RUN_DIR") {
                dir
            } else {
                manifest_dir.clone()
            };

        let win_sdl_libs_dir =
            format!("{}/sdl_libs", manifest_dir);

        let is_x64 = cfg!(target_arch = "x86_64");
        let is_mingw = cfg!(target_env = "gnu");

        let select_libs_dir = |base_dir| {
            let dir = format!("{}/{}/{}/{}",
                              win_sdl_libs_dir,
                              base_dir,
                              if is_mingw {
                                  "mingw"
                              } else {
                                  "msvc"
                              },
                              if is_x64 {
                                  "x64"
                              } else {
                                  "x32"
                              });
            dir
        };

        let machine_lib_dirs = [select_libs_dir("sdl2"),
                                select_libs_dir("sdl2-image"),
                                select_libs_dir("sdl2-ttf")];

        for dir in &machine_lib_dirs {

            println!("cargo:rustc-flags=-L {}", dir);

            // Copy sdl2 related DLLs to win_sdl_dlls_dir so `cargo run` succeeds.
            for entry in WalkDir::new(dir) {
                let entry = entry.unwrap();

                if is_dll_file(&entry) {

                    let src_file_path: &Path = entry.path();
                    let src_file_name: &OsStr = entry.file_name();
                    let target_dir: &String = &win_sdl_dlls_dir;
                    let target_dir_path: &Path = Path::new(target_dir);
                    let target_file_str: OsString = target_dir_path.join(src_file_name)
                                                                   .into_os_string();
                    let target_file_path: &Path = Path::new(&target_file_str);

                    if !target_file_path.exists() ||
                       are_different_file_contents(&entry, target_file_path) {

                        copy(src_file_path, target_file_path)
                            .expect(format!("Failed to copy windows os dll from {} to {}",
                                            src_file_path.display(),
                                            target_file_path.display())
                                        .as_str());
                    }
                }
            }
        }
    }
}

fn is_dll_file(entry: &DirEntry) -> bool {

    if entry.file_type().is_file() {
        if let Some(osstr_ext) = entry.path().extension() {
            if let Some(ext) = osstr_ext.to_str() {
                return ext == "dll";
            }
        }
    }

    false
}

fn are_different_file_contents(entry: &DirEntry, file_path: &Path) -> bool {
    let entry_meta_r = entry.metadata();
    let file_meta_r = file_path.metadata();

    if let (Ok(entry_meta), Ok(file_meta)) = (entry_meta_r, file_meta_r) {

        if entry_meta.is_file() && file_meta.is_file() && entry_meta.len() == file_meta.len() {
            false
        } else {
            true
        }

    } else {
        // When we cannot read the metadata then default to assuming
        // different files.
        true
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::process::Command;
use std::str::{self, FromStr};

// The rustc-cfg strings below are *not* public API. Please let us know by
// opening a GitHub issue if your build environment requires some way to enable
// these cfgs other than by executing our build script.
fn main() {
    let compiler = match rustc_version() {
        Some(compiler) => compiler,
        None => return,
    };

    if compiler.minor < 36 {
        println!("cargo:rustc-cfg=syn_omit_await_from_token_macro");
    }

    if !compiler.nightly {
        println!("cargo:rustc-cfg=syn_disable_nightly_tests");
    }
}

struct Compiler {
    minor: u32,
    nightly: bool,
}

fn rustc_version() -> Option<Compiler> {
    let rustc = match env::var_os("RUSTC") {
        Some(rustc) => rustc,
        None => return None,
    };

    let output = match Command::new(rustc).arg("--version").output() {
        Ok(output) => output,
        Err(_) => return None,
    };

    let version = match str::from_utf8(&output.stdout) {
        Ok(version) => version,
        Err(_) => return None,
    };

    let mut pieces = version.split('.');
    if pieces.next() != Some("rustc 1") {
        return None;
    }

    let next = match pieces.next() {
        Some(next) => next,
        None => return None,
    };

    let minor = match u32::from_str(next) {
        Ok(minor) => minor,
        Err(_) => return None,
    };

    Some(Compiler {
        minor,
        nightly: version.contains("nightly"),
    })
}
<commit_msg>Condense build script using question mark<commit_after>use std::env;
use std::process::Command;
use std::str::{self, FromStr};

// The rustc-cfg strings below are *not* public API. Please let us know by
// opening a GitHub issue if your build environment requires some way to enable
// these cfgs other than by executing our build script.
fn main() {
    let compiler = match rustc_version() {
        Some(compiler) => compiler,
        None => return,
    };

    if compiler.minor < 36 {
        println!("cargo:rustc-cfg=syn_omit_await_from_token_macro");
    }

    if !compiler.nightly {
        println!("cargo:rustc-cfg=syn_disable_nightly_tests");
    }
}

struct Compiler {
    minor: u32,
    nightly: bool,
}

fn rustc_version() -> Option<Compiler> {
    let rustc = env::var_os("RUSTC")?;
    let output = Command::new(rustc).arg("--version").output().ok()?;
    let version = str::from_utf8(&output.stdout).ok()?;
    let mut pieces = version.split('.');
    if pieces.next() != Some("rustc 1") {
        return None;
    }
    let next = pieces.next()?;
    let minor = u32::from_str(next).ok()?;
    let nightly = version.contains("nightly");
    Some(Compiler { minor, nightly })
}
<|endoftext|>


<commit_before>extern crate gcc;

fn main() {
    let sources = ::std::fs::read_dir("llvm/lib/Fuzzer")
        .expect("listable source directory")
        .map(|de| de.expect("file in directory").path())
        .filter(|p| p.extension().map(|ext| ext == "cpp") == Some(true))
        .collect::<Vec<_>>();
    let mut config = gcc::Config::new();
    for source in sources.iter() {
        config.file(source.to_str().unwrap());
    }
    config.flag("-std=c++11");
    config.flag("-fno-omit-frame-pointer");
    config.cpp(true);
    config.compile("libfuzzer.a");
}
<commit_msg>Optionally use a custom libFuzzer.a archive<commit_after>extern crate gcc;

fn main() {
    if let Ok(custom) = ::std::env::var("CUSTOM_LIBFUZZER_PATH") {
        let custom_lib_dir = ::std::path::PathBuf::from(&custom);
        let custom_lib_dir = custom_lib_dir.parent().unwrap().to_string_lossy();

        let custom_lib_name = ::std::path::PathBuf::from(&custom);
        let custom_lib_name = custom_lib_name.file_stem().unwrap().to_string_lossy();
        let custom_lib_name = &custom_lib_name[3..];

        println!("cargo:rustc-link-search=native={}", custom_lib_dir);
        println!("cargo:rustc-link-lib=static={}", custom_lib_name);
        println!("cargo:rustc-link-lib=stdc++");
    } else {
        let mut config = gcc::Config::new();
        let sources = ::std::fs::read_dir("llvm/lib/Fuzzer")
            .expect("listable source directory")
            .map(|de| de.expect("file in directory").path())
            .filter(|p| p.extension().map(|ext| ext == "cpp") == Some(true))
            .collect::<Vec<_>>();
        for source in sources.iter() {
            config.file(source.to_str().unwrap());
        }
        config.flag("-std=c++11");
        config.flag("-fno-omit-frame-pointer");
        config.cpp(true);
        config.compile("libfuzzer.a");
    }
}
<|endoftext|>


<commit_before>use std::process::Command;
use std::path::Path;
use std::env;

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();

    // note that there are a number of downsides to this approach, the comments
    // below detail how to improve the portability of these commands.
    Command::new("gcc").args(&["container.c", "-c", "-fPIC",
                               "-std=c99", "-D_GNU_SOURCE", "-o"])
                       .arg(&format!("{}/container.o", out_dir))
                       .status().unwrap();
    Command::new("ar").args(&["crus", "libcontainer.a", "container.o"])
                      .current_dir(&Path::new(&out_dir))
                      .status().unwrap();

    println!("cargo:rustc-link-search=native={}", out_dir);
    println!("cargo:rustc-link-lib=static=container");
}
<commit_msg>Removes `build.rs` which is not used any more (about 1.5 years)<commit_after><|endoftext|>


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

extern crate linuxdvb;

use std::fs;
use std::error::Error;
use std::path::Path;

use linuxdvb::{Frontend,ReadWriteMode,BlockMode};
use linuxdvb::properties::GetProperty as GP;
use linuxdvb::properties::GetPropertyValue as GPV;

type SimpleResult<T> = Result<T, Box<Error>>;

fn show_frontend_info(path: &Path, yet_another_one: bool) -> SimpleResult<()> {
    let frontend = try!(Frontend::open(path, ReadWriteMode::ReadOnly, BlockMode::NonBlocking));
    if yet_another_one {
        println!("--");
    }
    println!("Device: {}", path.to_string_lossy());
    let info = try!(frontend.get_info());
    println!("Name: {}", info.name);

    let properties = try!(frontend.get_properties(&[
        GP::DtvEnumDelsys
        ]));
    if let GPV::DtvEnumDelsys(delsys) = properties[0] {
        println!("Supported delivery systems: {:?}", delsys.delivery_systems());
    }

    println!("Minimal frequency: {}", info.frequency_min);
    println!("Maximal frequency: {}", info.frequency_max);
    println!("Frequency step: {}", info.frequency_stepsize);
    println!("Frequency tolerance: {}", info.frequency_tolerance);
    println!("Minimal symbol rate: {}", info.symbol_rate_min);
    println!("Maximal symbol rate: {}", info.symbol_rate_max);
    println!("Maximal symbol rate tolerance: {}", info.symbol_rate_tolerance);

    let caps: Vec<linuxdvb::caps::FrontendCapsEnum> = info.caps.into();
    println!("Frontend capabilities: {:?}", caps);

    Ok(())
}

fn iterate_devices(adapter_dir: &Path, yet_another_one: bool) -> SimpleResult<bool> {
    let mut has_frontend = false;
    for device in try!(fs::read_dir(adapter_dir)) {
        let device = try!(device);
        let is_frontend = device.path().file_name()
            .map(|f| f.to_str())
            .unwrap_or(None)
            .map_or(false, |f| f.starts_with("frontend"));
        if is_frontend {
            try!(show_frontend_info(&device.path(), yet_another_one));
            has_frontend = true;
        }
    }
    Ok(has_frontend)
}

fn iterate_adapters() -> SimpleResult<bool> {
    let mut has_frontend = false;
    for adapter_dir in try!(fs::read_dir("/dev/dvb")) {
        let adapter_dir = try!(adapter_dir);
        let is_frontend = try!(iterate_devices(&adapter_dir.path(), has_frontend));
        has_frontend = is_frontend || has_frontend;
    }
    Ok(has_frontend)
}

fn main() {
    let has_frontend = match iterate_adapters() {
        Ok(has_frontend) => has_frontend,
        Err(error) => {
            println!("Error: {}", error.description());
            return;
        }
    };
    if !has_frontend {
        println!("No DVB frontend devices were found");
    }
}<commit_msg>Add status info to frontend-info.<commit_after>// Copyright 2015 Ilkka Rauta
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate linuxdvb;

use std::fs;
use std::error::Error;
use std::path::Path;

use linuxdvb::{Frontend,ReadWriteMode,BlockMode};
use linuxdvb::properties::GetProperty as GP;
use linuxdvb::properties::GetPropertyValue as GPV;

type SimpleResult<T> = Result<T, Box<Error>>;

fn show_frontend_info(path: &Path, yet_another_one: bool) -> SimpleResult<()> {
    let frontend = try!(Frontend::open(path, ReadWriteMode::ReadOnly, BlockMode::NonBlocking));
    if yet_another_one {
        println!("--");
    }
    println!("Device: {}", path.to_string_lossy());
    let info = try!(frontend.get_info());
    println!("Name: {}", info.name);

    let properties = try!(frontend.get_properties(&[
        GP::DtvEnumDelsys
        ]));
    if let GPV::DtvEnumDelsys(delsys) = properties[0] {
        println!("Supported delivery systems: {:?}", delsys.delivery_systems());
    }

    println!("Minimal frequency: {}", info.frequency_min);
    println!("Maximal frequency: {}", info.frequency_max);
    println!("Frequency step: {}", info.frequency_stepsize);
    println!("Frequency tolerance: {}", info.frequency_tolerance);
    println!("Minimal symbol rate: {}", info.symbol_rate_min);
    println!("Maximal symbol rate: {}", info.symbol_rate_max);
    println!("Maximal symbol rate tolerance: {}", info.symbol_rate_tolerance);

    let caps: Vec<linuxdvb::caps::FrontendCapsEnum> = info.caps.into();
    println!("Frontend capabilities: {:?}", caps);

    let status = try!(frontend.read_status());
    println!("Status:");
    println!("    Has a signal: {}", status.has_signal);
    println!("    Has DVB signal: {}", status.has_carrier);
    println!("    Inner coding is stable: {}", status.has_viterbi);
    println!("    Synchronization bytes found: {}", status.has_sync);
    println!("    Has DVB lock: {}", status.has_lock);
    println!("    Timed out: {}", status.timedout);
    println!("    Frontend was reinitialized: {}", status.reinit);

    Ok(())
}

fn iterate_devices(adapter_dir: &Path, yet_another_one: bool) -> SimpleResult<bool> {
    let mut has_frontend = false;
    for device in try!(fs::read_dir(adapter_dir)) {
        let device = try!(device);
        let is_frontend = device.path().file_name()
            .map(|f| f.to_str())
            .unwrap_or(None)
            .map_or(false, |f| f.starts_with("frontend"));
        if is_frontend {
            try!(show_frontend_info(&device.path(), yet_another_one));
            has_frontend = true;
        }
    }
    Ok(has_frontend)
}

fn iterate_adapters() -> SimpleResult<bool> {
    let mut has_frontend = false;
    for adapter_dir in try!(fs::read_dir("/dev/dvb")) {
        let adapter_dir = try!(adapter_dir);
        let is_frontend = try!(iterate_devices(&adapter_dir.path(), has_frontend));
        has_frontend = is_frontend || has_frontend;
    }
    Ok(has_frontend)
}

fn main() {
    let has_frontend = match iterate_adapters() {
        Ok(has_frontend) => has_frontend,
        Err(error) => {
            println!("Error: {}", error.description());
            return;
        }
    };
    if !has_frontend {
        println!("No DVB frontend devices were found");
    }
}<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::env;
use std::ffi::{OsStr, OsString};
use std::fmt;
use std::path::Path;
use std::process::{Command, Output, Stdio};

use jobserver::Client;
use shell_escape::escape;

use util::{process_error, CargoError, CargoResult, CargoResultExt, read2};

/// A builder object for an external process, similar to `std::process::Command`.
#[derive(Clone, Debug)]
pub struct ProcessBuilder {
    /// The program to execute.
    program: OsString,
    /// A list of arguments to pass to the program.
    args: Vec<OsString>,
    /// Any environment variables that should be set for the program.
    env: HashMap<String, Option<OsString>>,
    /// Which directory to run the program from.
    cwd: Option<OsString>,
    /// The `make` jobserver. See the [jobserver crate][jobserver_docs] for
    /// more information.
    ///
    /// [jobserver_docs]: https://docs.rs/jobserver/0.1.6/jobserver/
    jobserver: Option<Client>,
}

impl fmt::Display for ProcessBuilder {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "`{}", self.program.to_string_lossy())?;

        for arg in &self.args {
            write!(f, " {}", escape(arg.to_string_lossy()))?;
        }

        write!(f, "`")
    }
}

impl ProcessBuilder {
    /// (chainable) Set the executable for the process.
    pub fn program<T: AsRef<OsStr>>(&mut self, program: T) -> &mut ProcessBuilder {
        self.program = program.as_ref().to_os_string();
        self
    }

    /// (chainable) Add an arg to the args list.
    pub fn arg<T: AsRef<OsStr>>(&mut self, arg: T) -> &mut ProcessBuilder {
        self.args.push(arg.as_ref().to_os_string());
        self
    }

    /// (chainable) Add many args to the args list.
    pub fn args<T: AsRef<OsStr>>(&mut self, arguments: &[T]) -> &mut ProcessBuilder {
        self.args
            .extend(arguments.iter().map(|t| t.as_ref().to_os_string()));
        self
    }

    /// (chainable) Replace args with new args list
    pub fn args_replace<T: AsRef<OsStr>>(&mut self, arguments: &[T]) -> &mut ProcessBuilder {
        self.args = arguments
            .iter()
            .map(|t| t.as_ref().to_os_string())
            .collect();
        self
    }

    /// (chainable) Set the current working directory of the process
    pub fn cwd<T: AsRef<OsStr>>(&mut self, path: T) -> &mut ProcessBuilder {
        self.cwd = Some(path.as_ref().to_os_string());
        self
    }

    /// (chainable) Set an environment variable for the process.
    pub fn env<T: AsRef<OsStr>>(&mut self, key: &str, val: T) -> &mut ProcessBuilder {
        self.env
            .insert(key.to_string(), Some(val.as_ref().to_os_string()));
        self
    }

    /// (chainable) Unset an environment variable for the process.
    pub fn env_remove(&mut self, key: &str) -> &mut ProcessBuilder {
        self.env.insert(key.to_string(), None);
        self
    }

    /// Get the executable name.
    pub fn get_program(&self) -> &OsString {
        &self.program
    }

    /// Get the program arguments
    pub fn get_args(&self) -> &[OsString] {
        &self.args
    }

    /// Get the current working directory for the process
    pub fn get_cwd(&self) -> Option<&Path> {
        self.cwd.as_ref().map(Path::new)
    }

    /// Get an environment variable as the process will see it (will inherit from environment
    /// unless explicitally unset).
    pub fn get_env(&self, var: &str) -> Option<OsString> {
        self.env
            .get(var)
            .cloned()
            .or_else(|| Some(env::var_os(var)))
            .and_then(|s| s)
    }

    /// Get all environment variables explicitly set or unset for the process (not inherited
    /// vars).
    pub fn get_envs(&self) -> &HashMap<String, Option<OsString>> {
        &self.env
    }

    /// Set the `make` jobserver. See the [jobserver crate][jobserver_docs] for
    /// more information.
    ///
    /// [jobserver_docs]: https://docs.rs/jobserver/0.1.6/jobserver/
    pub fn inherit_jobserver(&mut self, jobserver: &Client) -> &mut Self {
        self.jobserver = Some(jobserver.clone());
        self
    }

    /// Run the process, waiting for completion, and mapping non-success exit codes to an error.
    pub fn exec(&self) -> CargoResult<()> {
        let mut command = self.build_command();
        let exit = command.status().chain_err(|| {
            process_error(
                &format!("could not execute process `{}`", self.debug_string()),
                None,
                None,
            )
        })?;

        if exit.success() {
            Ok(())
        } else {
            Err(process_error(
                &format!(
                    "process didn't exit successfully: `{}`",
                    self.debug_string()
                ),
                Some(&exit),
                None,
            ).into())
        }
    }

    /// On unix, executes the process using the unix syscall `execvp`, which will block this
    /// process, and will only return if there is an error. On windows this is a synonym for
    /// `exec`.
    #[cfg(unix)]
    pub fn exec_replace(&self) -> CargoResult<()> {
        use std::os::unix::process::CommandExt;

        let mut command = self.build_command();
        let error = command.exec();
        Err(CargoError::from(error)
            .context(process_error(
                &format!("could not execute process `{}`", self.debug_string()),
                None,
                None,
            ))
            .into())
    }

    /// On unix, executes the process using the unix syscall `execvp`, which will block this
    /// process, and will only return if there is an error. On windows this is a synonym for
    /// `exec`.
    #[cfg(windows)]
    pub fn exec_replace(&self) -> CargoResult<()> {
        self.exec()
    }

    /// Execute the process, returning the stdio output, or an error if non-zero exit status.
    pub fn exec_with_output(&self) -> CargoResult<Output> {
        let mut command = self.build_command();

        let output = command.output().chain_err(|| {
            process_error(
                &format!("could not execute process `{}`", self.debug_string()),
                None,
                None,
            )
        })?;

        if output.status.success() {
            Ok(output)
        } else {
            Err(process_error(
                &format!(
                    "process didn't exit successfully: `{}`",
                    self.debug_string()
                ),
                Some(&output.status),
                Some(&output),
            ).into())
        }
    }

    /// Execute a command, passing each line of stdout and stderr to the supplied callbacks, which
    /// can mutate the string data.
    ///
    /// If any invocations of these function return an error, it will be propagated.
    ///
    /// Optionally, output can be passed to errors using `print_output`
    pub fn exec_with_streaming(
        &self,
        on_stdout_line: &mut FnMut(&str) -> CargoResult<()>,
        on_stderr_line: &mut FnMut(&str) -> CargoResult<()>,
        print_output: bool,
    ) -> CargoResult<Output> {
        let mut stdout = Vec::new();
        let mut stderr = Vec::new();

        let mut cmd = self.build_command();
        cmd.stdout(Stdio::piped())
            .stderr(Stdio::piped())
            .stdin(Stdio::null());

        let mut callback_error = None;
        let status = (|| {
            let mut child = cmd.spawn()?;
            let out = child.stdout.take().unwrap();
            let err = child.stderr.take().unwrap();
            read2(out, err, &mut |is_out, data, eof| {
                let idx = if eof {
                    data.len()
                } else {
                    match data.iter().rposition(|b| *b == b'\n') {
                        Some(i) => i + 1,
                        None => return,
                    }
                };
                let data = data.drain(..idx);
                let dst = if is_out { &mut stdout } else { &mut stderr };
                let start = dst.len();
                dst.extend(data);
                for line in String::from_utf8_lossy(&dst[start..]).lines() {
                    if callback_error.is_some() {
                        break;
                    }
                    let callback_result = if is_out {
                        on_stdout_line(line)
                    } else {
                        on_stderr_line(line)
                    };
                    if let Err(e) = callback_result {
                        callback_error = Some(e);
                    }
                }
            })?;
            child.wait()
        })()
            .chain_err(|| {
            process_error(
                &format!("could not execute process `{}`", self.debug_string()),
                None,
                None,
            )
        })?;
        let output = Output {
            stdout,
            stderr,
            status,
        };

        {
            let to_print = if print_output { Some(&output) } else { None };
            if !output.status.success() {
                return Err(process_error(
                    &format!(
                        "process didn't exit successfully: `{}`",
                        self.debug_string()
                    ),
                    Some(&output.status),
                    to_print,
                ).into());
            } else if let Some(e) = callback_error {
                let cx = process_error(
                    &format!("failed to parse process output: `{}`", self.debug_string()),
                    Some(&output.status),
                    to_print,
                );
                return Err(CargoError::from(e).context(cx).into());
            }
        }

        Ok(output)
    }

    /// Converts ProcessBuilder into a `std::process::Command`, and handles the jobserver if
    /// present.
    pub fn build_command(&self) -> Command {
        let mut command = Command::new(&self.program);
        if let Some(cwd) = self.get_cwd() {
            command.current_dir(cwd);
        }
        for arg in &self.args {
            command.arg(arg);
        }
        for (k, v) in &self.env {
            match *v {
                Some(ref v) => {
                    command.env(k, v);
                }
                None => {
                    command.env_remove(k);
                }
            }
        }
        if let Some(ref c) = self.jobserver {
            c.configure(&mut command);
        }
        command
    }

    /// Get the command line for the process as a string.
    fn debug_string(&self) -> String {
        let mut program = format!("{}", self.program.to_string_lossy());
        for arg in &self.args {
            program.push(' ');
            program.push_str(&format!("{}", arg.to_string_lossy()));
        }
        program
    }
}

/// A helper function to create a `ProcessBuilder`.
pub fn process<T: AsRef<OsStr>>(cmd: T) -> ProcessBuilder {
    ProcessBuilder {
        program: cmd.as_ref().to_os_string(),
        args: Vec::new(),
        cwd: None,
        env: HashMap::new(),
        jobserver: None,
    }
}
<commit_msg>Always use the Display impl for ProcessBuilder output<commit_after>use std::collections::HashMap;
use std::env;
use std::ffi::{OsStr, OsString};
use std::fmt;
use std::path::Path;
use std::process::{Command, Output, Stdio};

use jobserver::Client;
use shell_escape::escape;

use util::{process_error, CargoError, CargoResult, CargoResultExt, read2};

/// A builder object for an external process, similar to `std::process::Command`.
#[derive(Clone, Debug)]
pub struct ProcessBuilder {
    /// The program to execute.
    program: OsString,
    /// A list of arguments to pass to the program.
    args: Vec<OsString>,
    /// Any environment variables that should be set for the program.
    env: HashMap<String, Option<OsString>>,
    /// Which directory to run the program from.
    cwd: Option<OsString>,
    /// The `make` jobserver. See the [jobserver crate][jobserver_docs] for
    /// more information.
    ///
    /// [jobserver_docs]: https://docs.rs/jobserver/0.1.6/jobserver/
    jobserver: Option<Client>,
}

impl fmt::Display for ProcessBuilder {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "`{}", self.program.to_string_lossy())?;

        for arg in &self.args {
            write!(f, " {}", escape(arg.to_string_lossy()))?;
        }

        write!(f, "`")
    }
}

impl ProcessBuilder {
    /// (chainable) Set the executable for the process.
    pub fn program<T: AsRef<OsStr>>(&mut self, program: T) -> &mut ProcessBuilder {
        self.program = program.as_ref().to_os_string();
        self
    }

    /// (chainable) Add an arg to the args list.
    pub fn arg<T: AsRef<OsStr>>(&mut self, arg: T) -> &mut ProcessBuilder {
        self.args.push(arg.as_ref().to_os_string());
        self
    }

    /// (chainable) Add many args to the args list.
    pub fn args<T: AsRef<OsStr>>(&mut self, arguments: &[T]) -> &mut ProcessBuilder {
        self.args
            .extend(arguments.iter().map(|t| t.as_ref().to_os_string()));
        self
    }

    /// (chainable) Replace args with new args list
    pub fn args_replace<T: AsRef<OsStr>>(&mut self, arguments: &[T]) -> &mut ProcessBuilder {
        self.args = arguments
            .iter()
            .map(|t| t.as_ref().to_os_string())
            .collect();
        self
    }

    /// (chainable) Set the current working directory of the process
    pub fn cwd<T: AsRef<OsStr>>(&mut self, path: T) -> &mut ProcessBuilder {
        self.cwd = Some(path.as_ref().to_os_string());
        self
    }

    /// (chainable) Set an environment variable for the process.
    pub fn env<T: AsRef<OsStr>>(&mut self, key: &str, val: T) -> &mut ProcessBuilder {
        self.env
            .insert(key.to_string(), Some(val.as_ref().to_os_string()));
        self
    }

    /// (chainable) Unset an environment variable for the process.
    pub fn env_remove(&mut self, key: &str) -> &mut ProcessBuilder {
        self.env.insert(key.to_string(), None);
        self
    }

    /// Get the executable name.
    pub fn get_program(&self) -> &OsString {
        &self.program
    }

    /// Get the program arguments
    pub fn get_args(&self) -> &[OsString] {
        &self.args
    }

    /// Get the current working directory for the process
    pub fn get_cwd(&self) -> Option<&Path> {
        self.cwd.as_ref().map(Path::new)
    }

    /// Get an environment variable as the process will see it (will inherit from environment
    /// unless explicitally unset).
    pub fn get_env(&self, var: &str) -> Option<OsString> {
        self.env
            .get(var)
            .cloned()
            .or_else(|| Some(env::var_os(var)))
            .and_then(|s| s)
    }

    /// Get all environment variables explicitly set or unset for the process (not inherited
    /// vars).
    pub fn get_envs(&self) -> &HashMap<String, Option<OsString>> {
        &self.env
    }

    /// Set the `make` jobserver. See the [jobserver crate][jobserver_docs] for
    /// more information.
    ///
    /// [jobserver_docs]: https://docs.rs/jobserver/0.1.6/jobserver/
    pub fn inherit_jobserver(&mut self, jobserver: &Client) -> &mut Self {
        self.jobserver = Some(jobserver.clone());
        self
    }

    /// Run the process, waiting for completion, and mapping non-success exit codes to an error.
    pub fn exec(&self) -> CargoResult<()> {
        let mut command = self.build_command();
        let exit = command.status().chain_err(|| {
            process_error(
                &format!("could not execute process {}", self),
                None,
                None,
            )
        })?;

        if exit.success() {
            Ok(())
        } else {
            Err(process_error(
                &format!("process didn't exit successfully: {}", self),
                Some(&exit),
                None,
            ).into())
        }
    }

    /// On unix, executes the process using the unix syscall `execvp`, which will block this
    /// process, and will only return if there is an error. On windows this is a synonym for
    /// `exec`.
    #[cfg(unix)]
    pub fn exec_replace(&self) -> CargoResult<()> {
        use std::os::unix::process::CommandExt;

        let mut command = self.build_command();
        let error = command.exec();
        Err(CargoError::from(error)
            .context(process_error(
                &format!("could not execute process {}", self),
                None,
                None,
            ))
            .into())
    }

    /// On unix, executes the process using the unix syscall `execvp`, which will block this
    /// process, and will only return if there is an error. On windows this is a synonym for
    /// `exec`.
    #[cfg(windows)]
    pub fn exec_replace(&self) -> CargoResult<()> {
        self.exec()
    }

    /// Execute the process, returning the stdio output, or an error if non-zero exit status.
    pub fn exec_with_output(&self) -> CargoResult<Output> {
        let mut command = self.build_command();

        let output = command.output().chain_err(|| {
            process_error(
                &format!("could not execute process {}", self),
                None,
                None,
            )
        })?;

        if output.status.success() {
            Ok(output)
        } else {
            Err(process_error(
                &format!("process didn't exit successfully: {}", self),
                Some(&output.status),
                Some(&output),
            ).into())
        }
    }

    /// Execute a command, passing each line of stdout and stderr to the supplied callbacks, which
    /// can mutate the string data.
    ///
    /// If any invocations of these function return an error, it will be propagated.
    ///
    /// Optionally, output can be passed to errors using `print_output`
    pub fn exec_with_streaming(
        &self,
        on_stdout_line: &mut FnMut(&str) -> CargoResult<()>,
        on_stderr_line: &mut FnMut(&str) -> CargoResult<()>,
        print_output: bool,
    ) -> CargoResult<Output> {
        let mut stdout = Vec::new();
        let mut stderr = Vec::new();

        let mut cmd = self.build_command();
        cmd.stdout(Stdio::piped())
            .stderr(Stdio::piped())
            .stdin(Stdio::null());

        let mut callback_error = None;
        let status = (|| {
            let mut child = cmd.spawn()?;
            let out = child.stdout.take().unwrap();
            let err = child.stderr.take().unwrap();
            read2(out, err, &mut |is_out, data, eof| {
                let idx = if eof {
                    data.len()
                } else {
                    match data.iter().rposition(|b| *b == b'\n') {
                        Some(i) => i + 1,
                        None => return,
                    }
                };
                let data = data.drain(..idx);
                let dst = if is_out { &mut stdout } else { &mut stderr };
                let start = dst.len();
                dst.extend(data);
                for line in String::from_utf8_lossy(&dst[start..]).lines() {
                    if callback_error.is_some() {
                        break;
                    }
                    let callback_result = if is_out {
                        on_stdout_line(line)
                    } else {
                        on_stderr_line(line)
                    };
                    if let Err(e) = callback_result {
                        callback_error = Some(e);
                    }
                }
            })?;
            child.wait()
        })()
            .chain_err(|| {
            process_error(
                &format!("could not execute process {}", self),
                None,
                None,
            )
        })?;
        let output = Output {
            stdout,
            stderr,
            status,
        };

        {
            let to_print = if print_output { Some(&output) } else { None };
            if !output.status.success() {
                return Err(process_error(
                    &format!("process didn't exit successfully: {}", self),
                    Some(&output.status),
                    to_print,
                ).into());
            } else if let Some(e) = callback_error {
                let cx = process_error(
                    &format!("failed to parse process output: {}", self),
                    Some(&output.status),
                    to_print,
                );
                return Err(CargoError::from(e).context(cx).into());
            }
        }

        Ok(output)
    }

    /// Converts ProcessBuilder into a `std::process::Command`, and handles the jobserver if
    /// present.
    pub fn build_command(&self) -> Command {
        let mut command = Command::new(&self.program);
        if let Some(cwd) = self.get_cwd() {
            command.current_dir(cwd);
        }
        for arg in &self.args {
            command.arg(arg);
        }
        for (k, v) in &self.env {
            match *v {
                Some(ref v) => {
                    command.env(k, v);
                }
                None => {
                    command.env_remove(k);
                }
            }
        }
        if let Some(ref c) = self.jobserver {
            c.configure(&mut command);
        }
        command
    }
}

/// A helper function to create a `ProcessBuilder`.
pub fn process<T: AsRef<OsStr>>(cmd: T) -> ProcessBuilder {
    ProcessBuilder {
        program: cmd.as_ref().to_os_string(),
        args: Vec::new(),
        cwd: None,
        env: HashMap::new(),
        jobserver: None,
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

use anyhow::{bail, format_err, Result};
use libra_logger::info;
use rusoto_autoscaling::{
    AutoScalingGroupNamesType, Autoscaling, AutoscalingClient, SetDesiredCapacityType,
};
use rusoto_core::Region;
use rusoto_sts::WebIdentityProvider;

/// set_asg_size sets the size of the given autoscaling group
#[allow(clippy::collapsible_if)]
pub async fn set_asg_size(
    desired_capacity: i64,
    buffer_percent: f64,
    asg_name: &str,
    wait_for_completion: bool,
    scaling_down: bool,
) -> Result<()> {
    let buffer = if scaling_down {
        0
    } else {
        ((desired_capacity as f64 * buffer_percent) / 100_f64).ceil() as i64
    };
    info!(
        "Scaling to desired_capacity : {}, buffer: {}, asg_name: {}",
        desired_capacity, buffer, asg_name
    );
    let set_desired_capacity_type = SetDesiredCapacityType {
        auto_scaling_group_name: asg_name.to_string(),
        desired_capacity: desired_capacity + buffer,
        honor_cooldown: Some(false),
    };
    let credentials_provider = WebIdentityProvider::from_k8s_env();

    let dispatcher = rusoto_core::HttpClient::new().expect("failed to create request dispatcher");
    let asc = AutoscalingClient::new_with(dispatcher, credentials_provider, Region::UsWest2);
    asc.set_desired_capacity(set_desired_capacity_type)
        .await
        .map_err(|e| format_err!("set_desired_capacity failed: {:?}", e))?;
    if !wait_for_completion {
        return Ok(());
    }
    libra_retrier::retry_async(libra_retrier::fixed_retry_strategy(10_000, 60), || {
        let asc_clone = asc.clone();
        Box::pin(async move {
            let mut total = 0;
            let mut current_token = None;
            loop {
                let current_token_clone = current_token.clone();
                let auto_scaling_group_names_type = AutoScalingGroupNamesType {
                    auto_scaling_group_names: Some(vec![asg_name.to_string()]),
                    // https://docs.aws.amazon.com/autoscaling/ec2/APIReference/API_DescribeAutoScalingGroups.html
                    // max value is 100
                    max_records: Some(100),
                    next_token: current_token_clone,
                };
                let asgs = asc_clone
                    .describe_auto_scaling_groups(auto_scaling_group_names_type)
                    .await?;
                if asgs.auto_scaling_groups.is_empty() {
                    bail!("asgs.auto_scaling_groups.is_empty()");
                }
                let asg = &asgs.auto_scaling_groups[0];
                if scaling_down {
                    total += asg
                        .instances
                        .clone()
                        .ok_or_else(|| format_err!("instances not found for auto_scaling_group"))?
                        .len() as i64;
                } else {
                    total += asg
                        .instances
                        .clone()
                        .ok_or_else(|| format_err!("instances not found for auto_scaling_group"))?
                        .iter()
                        .filter(|instance| instance.lifecycle_state == "InService")
                        .count() as i64;
                }
                if asgs.next_token.is_none() {
                    break;
                }
                current_token = asgs.next_token;
            }
            info!(
                "Waiting for scaling to complete. Current size: {}, Min Desired Size: {}",
                total, desired_capacity
            );
            if scaling_down {
                if total > desired_capacity {
                    bail!(
                    "Waiting for scale-down to complete. Current size: {}, Min Desired Size: {}",
                    total,
                    desired_capacity
                );
                } else {
                    info!("Scale down completed");
                    Ok(())
                }
            } else {
                if total < desired_capacity {
                    bail!(
                        "Waiting for scale-up to complete. Current size: {}, Min Desired Size: {}",
                        total,
                        desired_capacity
                    );
                } else {
                    info!("Scale up completed");
                    Ok(())
                }
            }
        })
    })
    .await
}
<commit_msg>[cluster-test] Retry set_desired_capacity<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

use anyhow::{bail, format_err, Result};
use libra_logger::{info, warn};
use rusoto_autoscaling::{
    AutoScalingGroupNamesType, Autoscaling, AutoscalingClient, SetDesiredCapacityType,
};
use rusoto_core::Region;
use rusoto_sts::WebIdentityProvider;

/// set_asg_size sets the size of the given autoscaling group
#[allow(clippy::collapsible_if)]
pub async fn set_asg_size(
    desired_capacity: i64,
    buffer_percent: f64,
    asg_name: &str,
    wait_for_completion: bool,
    scaling_down: bool,
) -> Result<()> {
    let buffer = if scaling_down {
        0
    } else {
        ((desired_capacity as f64 * buffer_percent) / 100_f64).ceil() as i64
    };
    info!(
        "Scaling to desired_capacity : {}, buffer: {}, asg_name: {}",
        desired_capacity, buffer, asg_name
    );
    let set_desired_capacity_type = SetDesiredCapacityType {
        auto_scaling_group_name: asg_name.to_string(),
        desired_capacity: desired_capacity + buffer,
        honor_cooldown: Some(false),
    };
    let credentials_provider = WebIdentityProvider::from_k8s_env();

    let dispatcher = rusoto_core::HttpClient::new().expect("failed to create request dispatcher");
    let asc = AutoscalingClient::new_with(dispatcher, credentials_provider, Region::UsWest2);
    libra_retrier::retry_async(libra_retrier::fixed_retry_strategy(10_000, 60), || {
        let asc = asc.clone();
        let set_desired_capacity_type = set_desired_capacity_type.clone();
        Box::pin(async move {
            asc.set_desired_capacity(set_desired_capacity_type)
                .await
                .map_err(|e| {
                    warn!("set_desired_capacity failed: {}, retrying", e);
                    format_err!("set_desired_capacity failed: {}", e)
                })
        })
    })
    .await?;
    if !wait_for_completion {
        return Ok(());
    }
    libra_retrier::retry_async(libra_retrier::fixed_retry_strategy(10_000, 60), || {
        let asc_clone = asc.clone();
        Box::pin(async move {
            let mut total = 0;
            let mut current_token = None;
            loop {
                let current_token_clone = current_token.clone();
                let auto_scaling_group_names_type = AutoScalingGroupNamesType {
                    auto_scaling_group_names: Some(vec![asg_name.to_string()]),
                    // https://docs.aws.amazon.com/autoscaling/ec2/APIReference/API_DescribeAutoScalingGroups.html
                    // max value is 100
                    max_records: Some(100),
                    next_token: current_token_clone,
                };
                let asgs = asc_clone
                    .describe_auto_scaling_groups(auto_scaling_group_names_type)
                    .await?;
                if asgs.auto_scaling_groups.is_empty() {
                    bail!("asgs.auto_scaling_groups.is_empty()");
                }
                let asg = &asgs.auto_scaling_groups[0];
                if scaling_down {
                    total += asg
                        .instances
                        .clone()
                        .ok_or_else(|| format_err!("instances not found for auto_scaling_group"))?
                        .len() as i64;
                } else {
                    total += asg
                        .instances
                        .clone()
                        .ok_or_else(|| format_err!("instances not found for auto_scaling_group"))?
                        .iter()
                        .filter(|instance| instance.lifecycle_state == "InService")
                        .count() as i64;
                }
                if asgs.next_token.is_none() {
                    break;
                }
                current_token = asgs.next_token;
            }
            info!(
                "Waiting for scaling to complete. Current size: {}, Min Desired Size: {}",
                total, desired_capacity
            );
            if scaling_down {
                if total > desired_capacity {
                    bail!(
                    "Waiting for scale-down to complete. Current size: {}, Min Desired Size: {}",
                    total,
                    desired_capacity
                );
                } else {
                    info!("Scale down completed");
                    Ok(())
                }
            } else {
                if total < desired_capacity {
                    bail!(
                        "Waiting for scale-up to complete. Current size: {}, Min Desired Size: {}",
                        total,
                        desired_capacity
                    );
                } else {
                    info!("Scale up completed");
                    Ok(())
                }
            }
        })
    })
    .await
}
<|endoftext|>


<commit_before>use std::io::process::{Command,ProcessOutput,ProcessExit,ExitStatus,ExitSignal};
use std::io::IoError;
use std::fmt;
use std::fmt::{Show, Formatter};

use TomlError = toml::Error;

pub trait CargoError {
    fn description(&self) -> String;
    fn detail(&self) -> Option<String> { None }
    fn cause<'a>(&'a self) -> Option<&'a CargoError> { None }
    fn is_human(&self) -> bool { false }

    fn to_error<E: FromError<Self>>(self) -> E {
        FromError::from_error(self)
    }

    fn box_error(self) -> Box<CargoError> {
        box self as Box<CargoError>
    }

    fn concrete(&self) -> ConcreteCargoError {
        ConcreteCargoError {
            description: self.description(),
            detail: self.detail(),
            cause: self.cause().map(|c| box c.concrete() as Box<CargoError>),
            is_human: self.is_human()
        }
    }
}

pub trait FromError<E> {
    fn from_error(error: E) -> Self;
}

impl<E: CargoError> FromError<E> for Box<CargoError> {
    fn from_error(error: E) -> Box<CargoError> {
        error.box_error()
    }
}

macro_rules! from_error (
    ($ty:ty) => {
        impl FromError<$ty> for $ty {
            fn from_error(error: $ty) -> $ty {
                error
            }
        }
    }
)

impl Show for Box<CargoError> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        try!(write!(f, "{}", self.description()));
        Ok(())
    }
}

impl CargoError for Box<CargoError> {
    fn description(&self) -> String {
        (*self).description()
    }

    fn detail(&self) -> Option<String> {
        (*self).detail()
    }

    fn cause<'a>(&'a self) -> Option<&'a CargoError> {
        (*self).cause()
    }

    fn is_human(&self) -> bool {
        (*self).is_human()
    }

    fn box_error(self) -> Box<CargoError> {
        self
    }
}

pub type CargoResult<T> = Result<T, Box<CargoError>>;

pub trait BoxError<T> {
    fn box_error(self) -> CargoResult<T>;
}

pub trait ChainError<T> {
    fn chain_error<E: CargoError>(self, callback: || -> E) -> CargoResult<T> ;
}

impl<T, E: CargoError> BoxError<T> for Result<T, E> {
    fn box_error(self) -> CargoResult<T> {
        self.map_err(|err| err.box_error())
    }
}

impl<T, E: CargoError> ChainError<T> for Result<T, E> {
    fn chain_error<E: CargoError>(self, callback: || -> E) -> CargoResult<T>  {
        self.map_err(|err| {
            let mut update = callback().concrete();
            update.cause = Some(err.box_error());
            box update as Box<CargoError>
        })
    }
}

impl CargoError for IoError {
    fn description(&self) -> String { self.to_str() }
}

from_error!(IoError)

impl CargoError for TomlError {
    fn description(&self) -> String { self.to_str() }
}

from_error!(TomlError)

pub struct ProcessError {
    pub msg: String,
    pub command: String,
    pub exit: Option<ProcessExit>,
    pub output: Option<ProcessOutput>,
    pub detail: Option<String>,
    pub cause: Option<Box<CargoError>>
}

from_error!(ProcessError)

impl Show for ProcessError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let exit = match self.exit {
            Some(ExitStatus(i)) | Some(ExitSignal(i)) => i.to_str(),
            None => "never executed".to_str()
        };
        write!(f, "{} (status={})", self.msg, exit)
    }
}

impl CargoError for ProcessError {
    fn description(&self) -> String {
        let exit = match self.exit {
            Some(ExitStatus(i)) | Some(ExitSignal(i)) => i.to_str(),
            None => "never executed".to_str()
        };
        format!("{} (status={})", self.msg, exit)
    }

    fn detail(&self) -> Option<String> {
        self.detail.clone()
    }

    fn cause<'a>(&'a self) -> Option<&'a CargoError> {
        self.cause.as_ref().map(|c| { let err: &CargoError = *c; err })
    }
}

pub struct ConcreteCargoError {
    description: String,
    detail: Option<String>,
    cause: Option<Box<CargoError>>,
    is_human: bool
}

impl Show for ConcreteCargoError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{}", self.description)
    }
}

impl CargoError for ConcreteCargoError {
    fn description(&self) -> String {
        self.description.clone()
    }

    fn detail(&self) -> Option<String> {
        self.detail.clone()
    }

    fn cause<'a>(&'a self) -> Option<&'a CargoError> {
        self.cause.as_ref().map(|c| { let err: &CargoError = *c; err })
    }

    fn is_human(&self) -> bool {
        self.is_human
    }
}

pub type CliResult<T> = Result<T, CliError>;

#[deriving(Show)]
pub struct CliError {
    pub error: Box<CargoError>,
    pub exit_code: uint
}

impl CliError {
    pub fn new<S: Str>(error: S, code: uint) -> CliError {
        let error = human(error.as_slice().to_str());
        CliError::from_boxed(error, code)
    }

    pub fn from_error<E: CargoError + 'static>(error: E, code: uint) -> CliError {
        let error = box error as Box<CargoError>;
        CliError::from_boxed(error, code)
    }

    pub fn from_boxed(error: Box<CargoError>, code: uint) -> CliError {
        let error = if error.is_human() {
            error
        } else {
            chain(error, human("An unknown error occurred"))
        };

        CliError { error: error, exit_code: code }
    }
}

pub fn process_error<S: Str>(msg: S, command: &Command, status: Option<&ProcessExit>, output: Option<&ProcessOutput>) -> ProcessError {
    ProcessError {
        msg: msg.as_slice().to_str(),
        command: command.to_str(),
        exit: status.map(|o| o.clone()),
        output: output.map(|o| o.clone()),
        detail: None,
        cause: None
    }
}

pub fn internal_error<S1: Str, S2: Str>(error: S1, detail: S2) -> Box<CargoError> {
    box ConcreteCargoError {
        description: error.as_slice().to_str(),
        detail: Some(detail.as_slice().to_str()),
        cause: None,
        is_human: false
    } as Box<CargoError>
}

pub fn internal<S1: Str>(error: S1) -> Box<CargoError> {
    box ConcreteCargoError {
        description: error.as_slice().to_str(),
        detail: None,
        cause: None,
        is_human: false
    } as Box<CargoError>
}

pub fn human<S: Str>(error: S) -> Box<CargoError> {
    box ConcreteCargoError {
        description: error.as_slice().to_str(),
        detail: None,
        cause: None,
        is_human: true
    } as Box<CargoError>
}

pub fn chain<E: CargoError>(original: Box<CargoError>, update: E) -> Box<CargoError> {
    let mut concrete = update.concrete();
    concrete.cause = Some(original);
    box concrete as Box<CargoError>
}
<commit_msg>Add mark_human<commit_after>use std::io::process::{Command,ProcessOutput,ProcessExit,ExitStatus,ExitSignal};
use std::io::IoError;
use std::fmt;
use std::fmt::{Show, Formatter};

use TomlError = toml::Error;

pub trait CargoError {
    fn description(&self) -> String;
    fn detail(&self) -> Option<String> { None }
    fn cause<'a>(&'a self) -> Option<&'a CargoError> { None }
    fn is_human(&self) -> bool { false }

    fn to_error<E: FromError<Self>>(self) -> E {
        FromError::from_error(self)
    }

    fn box_error(self) -> Box<CargoError> {
        box self as Box<CargoError>
    }

    fn concrete(&self) -> ConcreteCargoError {
        ConcreteCargoError {
            description: self.description(),
            detail: self.detail(),
            cause: self.cause().map(|c| box c.concrete() as Box<CargoError>),
            is_human: self.is_human()
        }
    }

    fn mark_human(self) -> Box<CargoError> {
        let mut concrete = self.concrete();
        concrete.is_human = true;
        box concrete as Box<CargoError>
    }
}

pub trait FromError<E> {
    fn from_error(error: E) -> Self;
}

impl<E: CargoError> FromError<E> for Box<CargoError> {
    fn from_error(error: E) -> Box<CargoError> {
        error.box_error()
    }
}

macro_rules! from_error (
    ($ty:ty) => {
        impl FromError<$ty> for $ty {
            fn from_error(error: $ty) -> $ty {
                error
            }
        }
    }
)

impl Show for Box<CargoError> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        try!(write!(f, "{}", self.description()));
        Ok(())
    }
}

impl CargoError for Box<CargoError> {
    fn description(&self) -> String {
        (*self).description()
    }

    fn detail(&self) -> Option<String> {
        (*self).detail()
    }

    fn cause<'a>(&'a self) -> Option<&'a CargoError> {
        (*self).cause()
    }

    fn is_human(&self) -> bool {
        (*self).is_human()
    }

    fn box_error(self) -> Box<CargoError> {
        self
    }
}

pub type CargoResult<T> = Result<T, Box<CargoError>>;

pub trait BoxError<T> {
    fn box_error(self) -> CargoResult<T>;
}

pub trait ChainError<T> {
    fn chain_error<E: CargoError>(self, callback: || -> E) -> CargoResult<T> ;
}

impl<T, E: CargoError> BoxError<T> for Result<T, E> {
    fn box_error(self) -> CargoResult<T> {
        self.map_err(|err| err.box_error())
    }
}

impl<T, E: CargoError> ChainError<T> for Result<T, E> {
    fn chain_error<E: CargoError>(self, callback: || -> E) -> CargoResult<T>  {
        self.map_err(|err| {
            let mut update = callback().concrete();
            update.cause = Some(err.box_error());
            box update as Box<CargoError>
        })
    }
}

impl CargoError for IoError {
    fn description(&self) -> String { self.to_str() }
}

from_error!(IoError)

impl CargoError for TomlError {
    fn description(&self) -> String { self.to_str() }
}

from_error!(TomlError)

pub struct ProcessError {
    pub msg: String,
    pub command: String,
    pub exit: Option<ProcessExit>,
    pub output: Option<ProcessOutput>,
    pub detail: Option<String>,
    pub cause: Option<Box<CargoError>>
}

from_error!(ProcessError)

impl Show for ProcessError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let exit = match self.exit {
            Some(ExitStatus(i)) | Some(ExitSignal(i)) => i.to_str(),
            None => "never executed".to_str()
        };
        write!(f, "{} (status={})", self.msg, exit)
    }
}

impl CargoError for ProcessError {
    fn description(&self) -> String {
        let exit = match self.exit {
            Some(ExitStatus(i)) | Some(ExitSignal(i)) => i.to_str(),
            None => "never executed".to_str()
        };
        format!("{} (status={})", self.msg, exit)
    }

    fn detail(&self) -> Option<String> {
        self.detail.clone()
    }

    fn cause<'a>(&'a self) -> Option<&'a CargoError> {
        self.cause.as_ref().map(|c| { let err: &CargoError = *c; err })
    }
}

pub struct ConcreteCargoError {
    description: String,
    detail: Option<String>,
    cause: Option<Box<CargoError>>,
    is_human: bool
}

impl Show for ConcreteCargoError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{}", self.description)
    }
}

impl CargoError for ConcreteCargoError {
    fn description(&self) -> String {
        self.description.clone()
    }

    fn detail(&self) -> Option<String> {
        self.detail.clone()
    }

    fn cause<'a>(&'a self) -> Option<&'a CargoError> {
        self.cause.as_ref().map(|c| { let err: &CargoError = *c; err })
    }

    fn is_human(&self) -> bool {
        self.is_human
    }
}

pub type CliResult<T> = Result<T, CliError>;

#[deriving(Show)]
pub struct CliError {
    pub error: Box<CargoError>,
    pub exit_code: uint
}

impl CliError {
    pub fn new<S: Str>(error: S, code: uint) -> CliError {
        let error = human(error.as_slice().to_str());
        CliError::from_boxed(error, code)
    }

    pub fn from_error<E: CargoError + 'static>(error: E, code: uint) -> CliError {
        let error = box error as Box<CargoError>;
        CliError::from_boxed(error, code)
    }

    pub fn from_boxed(error: Box<CargoError>, code: uint) -> CliError {
        let error = if error.is_human() {
            error
        } else {
            chain(error, human("An unknown error occurred"))
        };

        CliError { error: error, exit_code: code }
    }
}

pub fn process_error<S: Str>(msg: S, command: &Command, status: Option<&ProcessExit>, output: Option<&ProcessOutput>) -> ProcessError {
    ProcessError {
        msg: msg.as_slice().to_str(),
        command: command.to_str(),
        exit: status.map(|o| o.clone()),
        output: output.map(|o| o.clone()),
        detail: None,
        cause: None
    }
}

pub fn internal_error<S1: Str, S2: Str>(error: S1, detail: S2) -> Box<CargoError> {
    box ConcreteCargoError {
        description: error.as_slice().to_str(),
        detail: Some(detail.as_slice().to_str()),
        cause: None,
        is_human: false
    } as Box<CargoError>
}

pub fn internal<S1: Str>(error: S1) -> Box<CargoError> {
    box ConcreteCargoError {
        description: error.as_slice().to_str(),
        detail: None,
        cause: None,
        is_human: false
    } as Box<CargoError>
}

pub fn human<S: Str>(error: S) -> Box<CargoError> {
    box ConcreteCargoError {
        description: error.as_slice().to_str(),
        detail: None,
        cause: None,
        is_human: true
    } as Box<CargoError>
}

pub fn chain<E: CargoError>(original: Box<CargoError>, update: E) -> Box<CargoError> {
    let mut concrete = update.concrete();
    concrete.cause = Some(original);
    box concrete as Box<CargoError>
}
<|endoftext|>


<commit_before>extern crate rand;

//use std::process::Command;
use chip8::Chip8;

pub struct Interpreter;

impl Interpreter {
	pub fn execute_next_instruction(chip8: &mut Chip8) {
		// debug
		/*println!("PC= {:x}", chip8.register_pc);
		println!("I= {:x}", chip8.register_i);
		println!("DT= {:x}", chip8.register_dt);
		println!("ST= {:x}", chip8.register_st);
		println!("SP= {:x}", chip8.register_sp);

		for i in 0..16 as usize {
			println!("V{}= {:x}", i, chip8.register_v[i]);
		}

		let _ = Command::new("cmd.exe").arg("/c").arg("pause").status();*/

		// fetch
		let high_byte = chip8.memory[chip8.register_pc as usize];
		let low_byte = chip8.memory[chip8.register_pc as usize + 1];
		let opcode = (high_byte >> 4, high_byte & 0x0F, low_byte >> 4, low_byte & 0x0F);
		chip8.register_pc += 2;

		// decode & execute
		let nnn = ((high_byte as u16 & 0x0F) << 8) | low_byte as u16;
		let x = high_byte as usize & 0x0F;
		let y = low_byte as usize >> 4;

		match opcode {
			(0x0, 0x0, 0xE, 0x0) => chip8.display.clear(),
			(0x0, 0x0, 0xE, 0xE) => {
				chip8.register_pc = chip8.stack[chip8.register_sp as usize];
				chip8.register_sp -= 1;
			},
			(0x1, ..) => chip8.register_pc = nnn,
			(0x2, ..) => {
				chip8.register_sp += 1;
				chip8.stack[chip8.register_sp as usize] = chip8.register_pc;
				chip8.register_pc = nnn;
			},
			(0x3, ..) => {
				if chip8.register_v[x] == low_byte {
					chip8.register_pc += 2;
				}
			},
			(0x4, ..) => {
				if chip8.register_v[x] != low_byte {
					chip8.register_pc += 2;
				}
			},
			(0x5, _, _, 0x0) => {
				if chip8.register_v[x] == chip8.register_v[y] {
					chip8.register_pc += 2;
				}
			},
			(0x6, ..) => chip8.register_v[x] = low_byte,
			(0x7, ..) => chip8.register_v[x] = chip8.register_v[x].wrapping_add(low_byte),
			(0x8, _, _, 0x0) => chip8.register_v[x] = chip8.register_v[y],
			(0x8, _, _, 0x1) => chip8.register_v[x] |= chip8.register_v[y],
			(0x8, _, _, 0x2) => chip8.register_v[x] &= chip8.register_v[y],
			(0x8, _, _, 0x3) => chip8.register_v[x] ^= chip8.register_v[y],
			(0x8, _, _, 0x4) => {
				let result = chip8.register_v[x] as u16 + chip8.register_v[y] as u16;
				chip8.register_v[x] = result as u8;
				chip8.register_v[0xF] = (result > 0xFF) as u8;
			},
			(0x8, _, _, 0x5) => {
				chip8.register_v[0xF] = (chip8.register_v[x] >= chip8.register_v[y]) as u8;
				chip8.register_v[x] = chip8.register_v[x].wrapping_sub(chip8.register_v[y]);
			},
			(0x8, _, _, 0x6) => {
				chip8.register_v[0xF] = chip8.register_v[y] & 1;
				chip8.register_v[x] = chip8.register_v[y] >> 1;
			},
			(0x8, _, _, 0x7) => {
				chip8.register_v[0xF] = (chip8.register_v[x] <= chip8.register_v[y]) as u8;
				chip8.register_v[x] = chip8.register_v[y].wrapping_sub(chip8.register_v[x]);
			},
			(0x8, _, _, 0xE) => {
				chip8.register_v[0xF] = chip8.register_v[y] >> 7;
				chip8.register_v[x] = chip8.register_v[y] << 1;
			},
			(0x9, _, _, 0x0) => {
				if chip8.register_v[x] != chip8.register_v[y] {
					chip8.register_pc += 2;
				}
			},
			(0xA, ..) => chip8.register_i = nnn,
			(0xB, ..) => chip8.register_pc = nnn + chip8.register_v[0] as u16,
			(0xC, ..) => chip8.register_v[x] = rand::random::<u8>() & low_byte,
			(0xD, _, _, n) => {
				let sprite = &chip8.memory[chip8.register_i as usize .. chip8.register_i as usize + n as usize];
				chip8.register_v[0xF] = chip8.display.draw_sprite(chip8.register_v[x], chip8.register_v[y], sprite) as u8;
			},
			(0xE, _, 0x9, 0xE) => {
				if chip8.keyboard.is_pressed(chip8.register_v[x]) {
					chip8.register_pc += 2;
				}
			},
			(0xE, _, 0xA, 0x1) => {
				if !chip8.keyboard.is_pressed(chip8.register_v[x]) {
					chip8.register_pc += 2;
				}
			},
			(0xF, _, 0x0, 0x7) => chip8.register_v[x] = chip8.register_dt,
			(0xF, _, 0x0, 0xA) => chip8.register_v[x] = chip8.keyboard.wait_key_press(),
			(0xF, _, 0x1, 0x5) => chip8.register_dt = chip8.register_v[x],
			(0xF, _, 0x1, 0x8) => chip8.register_st = chip8.register_v[x],
			(0xF, _, 0x1, 0xE) => chip8.register_i += chip8.register_v[x] as u16,
			(0xF, _, 0x2, 0x9) => chip8.register_i = chip8.register_v[x] as u16 * 5,
			(0xF, _, 0x3, 0x3) => {
				chip8.memory[chip8.register_i as usize] = chip8.register_v[x] / 100;
				chip8.memory[chip8.register_i as usize + 1] = (chip8.register_v[x] % 100) / 10;
				chip8.memory[chip8.register_i as usize + 2] = chip8.register_v[x] % 10;
			},
			(0xF, _, 0x5, 0x5) => {
				for i in 0..(x + 1) {
					chip8.memory[chip8.register_i as usize + i] = chip8.register_v[i];
				}
			},
			(0xF, _, 0x6, 0x5) => {
				for i in 0..(x + 1) {
					chip8.register_v[i] = chip8.memory[chip8.register_i as usize + i];
				}
			},
			_ => panic!("unknown opcode")
		}
	}
}
<commit_msg>Interpreter: fix FX55 and FX65<commit_after>extern crate rand;

//use std::process::Command;
use chip8::Chip8;

pub struct Interpreter;

impl Interpreter {
	pub fn execute_next_instruction(chip8: &mut Chip8) {
		// debug
		/*println!("PC= {:x}", chip8.register_pc);
		println!("I= {:x}", chip8.register_i);
		println!("DT= {:x}", chip8.register_dt);
		println!("ST= {:x}", chip8.register_st);
		println!("SP= {:x}", chip8.register_sp);

		for i in 0..16 as usize {
			println!("V{}= {:x}", i, chip8.register_v[i]);
		}

		let _ = Command::new("cmd.exe").arg("/c").arg("pause").status();*/

		// fetch
		let high_byte = chip8.memory[chip8.register_pc as usize];
		let low_byte = chip8.memory[chip8.register_pc as usize + 1];
		let opcode = (high_byte >> 4, high_byte & 0x0F, low_byte >> 4, low_byte & 0x0F);
		chip8.register_pc += 2;

		// decode & execute
		let nnn = ((high_byte as u16 & 0x0F) << 8) | low_byte as u16;
		let x = high_byte as usize & 0x0F;
		let y = low_byte as usize >> 4;

		match opcode {
			(0x0, 0x0, 0xE, 0x0) => chip8.display.clear(),
			(0x0, 0x0, 0xE, 0xE) => {
				chip8.register_pc = chip8.stack[chip8.register_sp as usize];
				chip8.register_sp -= 1;
			},
			(0x1, ..) => chip8.register_pc = nnn,
			(0x2, ..) => {
				chip8.register_sp += 1;
				chip8.stack[chip8.register_sp as usize] = chip8.register_pc;
				chip8.register_pc = nnn;
			},
			(0x3, ..) => {
				if chip8.register_v[x] == low_byte {
					chip8.register_pc += 2;
				}
			},
			(0x4, ..) => {
				if chip8.register_v[x] != low_byte {
					chip8.register_pc += 2;
				}
			},
			(0x5, _, _, 0x0) => {
				if chip8.register_v[x] == chip8.register_v[y] {
					chip8.register_pc += 2;
				}
			},
			(0x6, ..) => chip8.register_v[x] = low_byte,
			(0x7, ..) => chip8.register_v[x] = chip8.register_v[x].wrapping_add(low_byte),
			(0x8, _, _, 0x0) => chip8.register_v[x] = chip8.register_v[y],
			(0x8, _, _, 0x1) => chip8.register_v[x] |= chip8.register_v[y],
			(0x8, _, _, 0x2) => chip8.register_v[x] &= chip8.register_v[y],
			(0x8, _, _, 0x3) => chip8.register_v[x] ^= chip8.register_v[y],
			(0x8, _, _, 0x4) => {
				let result = chip8.register_v[x] as u16 + chip8.register_v[y] as u16;
				chip8.register_v[x] = result as u8;
				chip8.register_v[0xF] = (result > 0xFF) as u8;
			},
			(0x8, _, _, 0x5) => {
				chip8.register_v[0xF] = (chip8.register_v[x] >= chip8.register_v[y]) as u8;
				chip8.register_v[x] = chip8.register_v[x].wrapping_sub(chip8.register_v[y]);
			},
			(0x8, _, _, 0x6) => {
				chip8.register_v[0xF] = chip8.register_v[y] & 1;
				chip8.register_v[x] = chip8.register_v[y] >> 1;
			},
			(0x8, _, _, 0x7) => {
				chip8.register_v[0xF] = (chip8.register_v[x] <= chip8.register_v[y]) as u8;
				chip8.register_v[x] = chip8.register_v[y].wrapping_sub(chip8.register_v[x]);
			},
			(0x8, _, _, 0xE) => {
				chip8.register_v[0xF] = chip8.register_v[y] >> 7;
				chip8.register_v[x] = chip8.register_v[y] << 1;
			},
			(0x9, _, _, 0x0) => {
				if chip8.register_v[x] != chip8.register_v[y] {
					chip8.register_pc += 2;
				}
			},
			(0xA, ..) => chip8.register_i = nnn,
			(0xB, ..) => chip8.register_pc = nnn + chip8.register_v[0] as u16,
			(0xC, ..) => chip8.register_v[x] = rand::random::<u8>() & low_byte,
			(0xD, _, _, n) => {
				let sprite = &chip8.memory[chip8.register_i as usize .. chip8.register_i as usize + n as usize];
				chip8.register_v[0xF] = chip8.display.draw_sprite(chip8.register_v[x], chip8.register_v[y], sprite) as u8;
			},
			(0xE, _, 0x9, 0xE) => {
				if chip8.keyboard.is_pressed(chip8.register_v[x]) {
					chip8.register_pc += 2;
				}
			},
			(0xE, _, 0xA, 0x1) => {
				if !chip8.keyboard.is_pressed(chip8.register_v[x]) {
					chip8.register_pc += 2;
				}
			},
			(0xF, _, 0x0, 0x7) => chip8.register_v[x] = chip8.register_dt,
			(0xF, _, 0x0, 0xA) => chip8.register_v[x] = chip8.keyboard.wait_key_press(),
			(0xF, _, 0x1, 0x5) => chip8.register_dt = chip8.register_v[x],
			(0xF, _, 0x1, 0x8) => chip8.register_st = chip8.register_v[x],
			(0xF, _, 0x1, 0xE) => chip8.register_i += chip8.register_v[x] as u16,
			(0xF, _, 0x2, 0x9) => chip8.register_i = chip8.register_v[x] as u16 * 5,
			(0xF, _, 0x3, 0x3) => {
				chip8.memory[chip8.register_i as usize] = chip8.register_v[x] / 100;
				chip8.memory[chip8.register_i as usize + 1] = (chip8.register_v[x] % 100) / 10;
				chip8.memory[chip8.register_i as usize + 2] = chip8.register_v[x] % 10;
			},
			(0xF, _, 0x5, 0x5) => {
				for i in 0..(x + 1) {
					chip8.memory[chip8.register_i as usize] = chip8.register_v[i];
					chip8.register_i += 1;
				}
			},
			(0xF, _, 0x6, 0x5) => {
				for i in 0..(x + 1) {
					chip8.register_v[i] = chip8.memory[chip8.register_i as usize];
					chip8.register_i += 1;
				}
			},
			_ => panic!("unknown opcode")
		}
	}
}
<|endoftext|>


<commit_before>#![macro_escape]

use std::io::BufferedWriter;
use std::io::{File, Writer};
use std::str::Chars;
use std::vec::Vec;

struct ParseBranch {
    matches: Vec<u8>,
    result: Option<String>,
    children: Vec<ParseBranch>,
}

impl ParseBranch {
    fn new() -> ParseBranch {
        ParseBranch {
            matches: Vec::new(),
            result: None,
            children: Vec::new(),
        }
    }
}

#[allow(visible_private_types)]
pub fn branchify(options: &[(&str, &str)], case_sensitive: bool) -> Vec<ParseBranch> {
    let mut root = ParseBranch::new();

    fn go_down_moses(branch: &mut ParseBranch, mut chariter: Chars, result: &str, case_sensitive: bool) {
        match chariter.next() {
            Some(c) => {
                let first_case = if case_sensitive { c as u8 } else { c.to_ascii().to_uppercase().to_byte() };
                for next_branch in branch.children.mut_iter() {
                    if next_branch.matches.as_slice()[0] == first_case {
                        go_down_moses(next_branch, chariter, result, case_sensitive);
                        return;
                    }
                }
                let mut subbranch = ParseBranch::new();
                subbranch.matches.push(first_case);
                if !case_sensitive {
                    let second_case = c.to_ascii().to_lowercase().to_byte();
                    if first_case != second_case {
                        subbranch.matches.push(second_case);
                    }
                }
                branch.children.push(subbranch);
                let index = branch.children.len() -1;
                go_down_moses(&mut branch.children.as_mut_slice()[index], chariter, result, case_sensitive);
            },
            None => {
                assert!(branch.result.is_none());
                branch.result = Some(result.to_string());
            },
        }
    };

    for &(key, result) in options.iter() {
        go_down_moses(&mut root, key.chars(), result, case_sensitive);
    }

    root.children
}

macro_rules! branchify(
    (case sensitive, $($key:expr => $value:ident),*) => (
        ::branchify::branchify([$(($key, stringify!($value))),*], true)
    );
    (case insensitive, $($key:expr => $value:ident),*) => (
        branchify([$(($key, stringify!($value))),*], false)
    );
)

/// Prints the contents to stdout.
///
/// :param branches: the branches to search through
/// :param indent: the level of indentation (each level representing four leading spaces)
/// :param read_call: the function call to read a byte
/// :param end: the byte which marks the end of the sequence
/// :param max_len: the maximum length a value may be before giving up and returning ``None``
/// :param valid: the function call to if a byte ``b`` is valid
/// :param unknown: the expression to call for an unknown value; in this string, ``{}`` will be
///         replaced with an expression (literal or non-literal) evaluating to a ``~str`` (it is
///         ``{}`` only, not arbitrary format strings)
#[allow(visible_private_types)]
pub fn generate_branchified_method(
        writer: &mut BufferedWriter<File>,
        branches: &[ParseBranch],
        indent: uint,
        read_call: &str,
        end: &str,
        max_len: &str,
        valid: &str,
        unknown: &str) {

    // Write Formatted
    let mut wf = |s: String| {
        let indentstr = " ".repeat(indent * 4);
        let result = writer.write(indentstr.as_bytes())
        .and(writer.write(s.as_bytes()))
        .and(writer.write(b"\n"));

        match result {
            Ok(_)  => {},
            Err(e) => fail!("write error: {:s}", e.desc),
        }
    };

    fn r(branch: &ParseBranch, prefix: &str, read_call: &str,
         valid: &str, unknown: &str, write_fmt: &mut |String|) {

        for &c in branch.matches.iter() {
            let next_prefix = format!("{}{}", prefix, c as char);
            (*write_fmt)(format!("Some(b) if b == '{}' as u8 => match {} {{", c as char, read_call));
            for b in branch.children.iter() {
                r(b, next_prefix.as_slice(), read_call, valid, unknown, write_fmt);
            }
            match branch.result {
                Some(ref result) => (*write_fmt)(format!("    Some(b) if b == SP => return Some({}),", *result)),
                None => (*write_fmt)(format!("    Some(b) if b == SP => return Some({}),",
                                unknown.replace("{}", format!("~\"{}\"", next_prefix.as_slice()).as_slice()))),
            }
            (*write_fmt)(format!("    Some(b) if {} => (\"{}\", b),", valid, next_prefix.as_slice()));
            (*write_fmt)(format!("    _ => return None,"));
            (*write_fmt)(format!("}},"));
        }
    }

    wf(format!("let (s, next_byte) = match {} {{", read_call));
    for b in branches.iter() {
        r(b, "", read_call, valid, unknown, &mut wf);
    }
    wf(format!("    Some(b) if {} => (\"\", b),", valid));
    wf(format!("    _ => return None,"));
    wf(format!("}};"));
    wf(format!("// OK, that didn't pan out. Let's read the rest and see what we get."));
    wf(format!("let mut s = s.to_string();"));
    wf(format!("s.push_char(next_byte as char);"));
    wf(format!("loop {{"));
    wf(format!("    match {} {{", read_call));
    wf(format!("        Some(b) if b == {} => return Some({}),", end, unknown.replace("{}", "s")));
    wf(format!("        Some(b) if {} => {{", valid));
    wf(format!("            if s.len() == {} {{", max_len));
    wf(format!("                // Too long; bad request"));
    wf(format!("                return None;"));
    wf(format!("            }}"));
    wf(format!("            s.push_char(b as char);"));
    wf(format!("        }},"));
    wf(format!("        _ => return None,"));
    wf(format!("    }}"));
    wf(format!("}}"));
}
<commit_msg>Fixed "Private type in exported signature" issue.<commit_after>#![macro_escape]

use std::io::BufferedWriter;
use std::io::{File, Writer};
use std::str::Chars;
use std::vec::Vec;

pub struct ParseBranch {
    matches: Vec<u8>,
    result: Option<String>,
    children: Vec<ParseBranch>,
}

impl ParseBranch {
    fn new() -> ParseBranch {
        ParseBranch {
            matches: Vec::new(),
            result: None,
            children: Vec::new(),
        }
    }
}

#[allow(visible_private_types)]
pub fn branchify(options: &[(&str, &str)], case_sensitive: bool) -> Vec<ParseBranch> {
    let mut root = ParseBranch::new();

    fn go_down_moses(branch: &mut ParseBranch, mut chariter: Chars, result: &str, case_sensitive: bool) {
        match chariter.next() {
            Some(c) => {
                let first_case = if case_sensitive { c as u8 } else { c.to_ascii().to_uppercase().to_byte() };
                for next_branch in branch.children.mut_iter() {
                    if next_branch.matches.as_slice()[0] == first_case {
                        go_down_moses(next_branch, chariter, result, case_sensitive);
                        return;
                    }
                }
                let mut subbranch = ParseBranch::new();
                subbranch.matches.push(first_case);
                if !case_sensitive {
                    let second_case = c.to_ascii().to_lowercase().to_byte();
                    if first_case != second_case {
                        subbranch.matches.push(second_case);
                    }
                }
                branch.children.push(subbranch);
                let index = branch.children.len() -1;
                go_down_moses(&mut branch.children.as_mut_slice()[index], chariter, result, case_sensitive);
            },
            None => {
                assert!(branch.result.is_none());
                branch.result = Some(result.to_string());
            },
        }
    };

    for &(key, result) in options.iter() {
        go_down_moses(&mut root, key.chars(), result, case_sensitive);
    }

    root.children
}

macro_rules! branchify(
    (case sensitive, $($key:expr => $value:ident),*) => (
        ::branchify::branchify([$(($key, stringify!($value))),*], true)
    );
    (case insensitive, $($key:expr => $value:ident),*) => (
        branchify([$(($key, stringify!($value))),*], false)
    );
)

/// Prints the contents to stdout.
///
/// :param branches: the branches to search through
/// :param indent: the level of indentation (each level representing four leading spaces)
/// :param read_call: the function call to read a byte
/// :param end: the byte which marks the end of the sequence
/// :param max_len: the maximum length a value may be before giving up and returning ``None``
/// :param valid: the function call to if a byte ``b`` is valid
/// :param unknown: the expression to call for an unknown value; in this string, ``{}`` will be
///         replaced with an expression (literal or non-literal) evaluating to a ``~str`` (it is
///         ``{}`` only, not arbitrary format strings)
#[allow(visible_private_types)]
pub fn generate_branchified_method(
        writer: &mut BufferedWriter<File>,
        branches: &[ParseBranch],
        indent: uint,
        read_call: &str,
        end: &str,
        max_len: &str,
        valid: &str,
        unknown: &str) {

    // Write Formatted
    let mut wf = |s: String| {
        let indentstr = " ".repeat(indent * 4);
        let result = writer.write(indentstr.as_bytes())
        .and(writer.write(s.as_bytes()))
        .and(writer.write(b"\n"));

        match result {
            Ok(_)  => {},
            Err(e) => fail!("write error: {:s}", e.desc),
        }
    };

    fn r(branch: &ParseBranch, prefix: &str, read_call: &str,
         valid: &str, unknown: &str, write_fmt: &mut |String|) {

        for &c in branch.matches.iter() {
            let next_prefix = format!("{}{}", prefix, c as char);
            (*write_fmt)(format!("Some(b) if b == '{}' as u8 => match {} {{", c as char, read_call));
            for b in branch.children.iter() {
                r(b, next_prefix.as_slice(), read_call, valid, unknown, write_fmt);
            }
            match branch.result {
                Some(ref result) => (*write_fmt)(format!("    Some(b) if b == SP => return Some({}),", *result)),
                None => (*write_fmt)(format!("    Some(b) if b == SP => return Some({}),",
                                unknown.replace("{}", format!("~\"{}\"", next_prefix.as_slice()).as_slice()))),
            }
            (*write_fmt)(format!("    Some(b) if {} => (\"{}\", b),", valid, next_prefix.as_slice()));
            (*write_fmt)(format!("    _ => return None,"));
            (*write_fmt)(format!("}},"));
        }
    }

    wf(format!("let (s, next_byte) = match {} {{", read_call));
    for b in branches.iter() {
        r(b, "", read_call, valid, unknown, &mut wf);
    }
    wf(format!("    Some(b) if {} => (\"\", b),", valid));
    wf(format!("    _ => return None,"));
    wf(format!("}};"));
    wf(format!("// OK, that didn't pan out. Let's read the rest and see what we get."));
    wf(format!("let mut s = s.to_string();"));
    wf(format!("s.push_char(next_byte as char);"));
    wf(format!("loop {{"));
    wf(format!("    match {} {{", read_call));
    wf(format!("        Some(b) if b == {} => return Some({}),", end, unknown.replace("{}", "s")));
    wf(format!("        Some(b) if {} => {{", valid));
    wf(format!("            if s.len() == {} {{", max_len));
    wf(format!("                // Too long; bad request"));
    wf(format!("                return None;"));
    wf(format!("            }}"));
    wf(format!("            s.push_char(b as char);"));
    wf(format!("        }},"));
    wf(format!("        _ => return None,"));
    wf(format!("    }}"));
    wf(format!("}}"));
}
<|endoftext|>