<commit_before>//! Exported verifier functions

use std::env;
use std::str;
use std::str::FromStr;
use std::sync::Arc;

use clap::{AppSettings, ArgMatches, ErrorKind};
use log::{debug, error, LevelFilter};
use simplelog::{Config, TerminalMode, TermLogger};

use pact_matching::s;
use pact_models::http_utils::HttpAuth;
use pact_models::PactSpecification;
use pact_verifier::*;
use pact_verifier::callback_executors::HttpRequestProviderStateExecutor;

use super::args;

fn pact_source(matches: &ArgMatches) -> Vec<PactSource> {
  let mut sources = vec![];

  if let Some(values) = matches.values_of("file") {
    sources.extend(values.map(|v| PactSource::File(s!(v))).collect::<Vec<PactSource>>());
  };

  if let Some(values) = matches.values_of("dir") {
    sources.extend(values.map(|v| PactSource::Dir(s!(v))).collect::<Vec<PactSource>>());
  };

  if let Some(values) = matches.values_of("url") {
    sources.extend(values.map(|v| {
      if matches.is_present("user") {
        PactSource::URL(s!(v), matches.value_of("user").map(|user| {
          HttpAuth::User(user.to_string(), matches.value_of("password").map(|p| p.to_string()))
        }))
      } else if matches.is_present("token") {
        PactSource::URL(s!(v), matches.value_of("token").map(|token| HttpAuth::Token(token.to_string())))
      } else {
        PactSource::URL(s!(v), None)
      }
    }).collect::<Vec<PactSource>>());
  };

  if let Some(broker_url) = matches.value_of("broker-url") {
    let name = matches.value_of("provider-name").map(|n| n.to_string()).unwrap_or_default();
    let auth = matches.value_of("user").map(|user| {
      HttpAuth::User(user.to_string(), matches.value_of("password").map(|p| p.to_string()))
    }).or_else(|| matches.value_of("token").map(|t| HttpAuth::Token(t.to_string())));

    let source = if matches.is_present("consumer-version-selectors") || matches.is_present("consumer-version-tags") {
      let pending = matches.is_present("enable-pending");
      let wip = matches.value_of("include-wip-pacts-since").map(|wip| wip.to_string());
      let provider_tags = matches.values_of("provider-tags")
        .map_or_else(Vec::new, |tags| tags.map(|tag| tag.to_string()).collect());

      let selectors = if matches.is_present("consumer-version-selectors") {
        matches.values_of("consumer-version-selectors")
          .map_or_else(Vec::new, |s| json_to_selectors(s.collect::<Vec<_>>()))
      } else if matches.is_present("consumer-version-tags") {
        matches.values_of("consumer-version-tags")
          .map_or_else(Vec::new, |tags| consumer_tags_to_selectors(tags.collect::<Vec<_>>()))
      } else {
        vec![]
      };

      PactSource::BrokerWithDynamicConfiguration {
        provider_name: name,
        broker_url: broker_url.into(),
        enable_pending: pending,
        include_wip_pacts_since: wip,
        provider_tags,
        selectors,
        auth,
        links: vec![]
      }
    } else {
      PactSource::BrokerUrl(name, broker_url.to_string(), auth, vec![])
    };
    sources.push(source);
  };
  sources
}

fn consumer_tags_to_selectors(tags: Vec<&str>) -> Vec<pact_verifier::ConsumerVersionSelector> {
  tags.iter().map(|t| {
    pact_verifier::ConsumerVersionSelector {
      consumer: None,
      fallback_tag: None,
      tag: Some(t.to_string()),
      latest: Some(true),
      branch: None,
      deployed_or_released: None,
      deployed: None,
      released: None,
      main_branch: None,
      environment: None,
    }
  }).collect()
}

fn json_to_selectors(tags: Vec<&str>) -> Vec<pact_verifier::ConsumerVersionSelector> {
  tags.iter().map(|t| serde_json::from_str(t))
  .flatten()
  .collect()
}

fn interaction_filter(matches: &ArgMatches) -> FilterInfo {
  if matches.is_present("filter-description") &&
      (matches.is_present("filter-state") || matches.is_present("filter-no-state")) {
      if matches.is_present("filter-state") {
          FilterInfo::DescriptionAndState(s!(matches.value_of("filter-description").unwrap()),
              s!(matches.value_of("filter-state").unwrap()))
      } else {
          FilterInfo::DescriptionAndState(s!(matches.value_of("filter-description").unwrap()),
              s!(""))
      }
  } else if matches.is_present("filter-description") {
      FilterInfo::Description(s!(matches.value_of("filter-description").unwrap()))
  } else if matches.is_present("filter-state") {
      FilterInfo::State(s!(matches.value_of("filter-state").unwrap()))
  } else if matches.is_present("filter-no-state") {
      FilterInfo::State(s!(""))
  } else {
      FilterInfo::None
  }
}

/// Handles the command line arguments from the running process
pub async fn handle_cli(version: &str) -> Result<(), i32> {
  let args: Vec<String> = env::args().collect();
  let program = args[0].clone();
  let app = args::setup_app(program, version);
  let matches = app
                  .setting(AppSettings::ArgRequiredElseHelp)
                  .setting(AppSettings::ColoredHelp)
                  .get_matches_safe();

  match matches {
    Ok(results) => handle_matches(&results).await,
    Err(ref err) => {
      match err.kind {
          ErrorKind::HelpDisplayed => {
              println!("{}", err.message);
              Ok(())
          },
          ErrorKind::VersionDisplayed => {
              print_version(version);
              println!();
              Ok(())
          },
          _ => {
              err.exit()
          }
      }
    }
  }
}

// TODO: it's possible to introspect the clap::Error and return it or wrapped error type
// so that the caller could have more control over the error output.
//
// Currently, clap prints things out as if it were a CLI call
#[allow(dead_code, missing_docs)]
pub async fn handle_args(args: Vec<String>) -> Result<(), i32> {
  let program = "pact_verifier_cli".to_string();
  let version = format!("v{}", clap::crate_version!()).as_str().to_owned();
  let app = args::setup_app(program, &version);
  let matches = app
                  .setting(AppSettings::NoBinaryName)
                  .setting(AppSettings::ColorNever)
                  .get_matches_from_safe(args);

  match matches {
    Ok(results) => handle_matches(&results).await,
    Err(ref err) => {
      log::error!("error verifying Pact: {:?} {:?}", err.message, err);
      Err(4)
    }
  }
}

async fn handle_matches(matches: &clap::ArgMatches<'_>) -> Result<(), i32> {
    let level = matches.value_of("loglevel").unwrap_or("warn");
    let log_level = match level {
        "none" => LevelFilter::Off,
        _ => LevelFilter::from_str(level).unwrap()
    };
    TermLogger::init(log_level, Config::default(), TerminalMode::Mixed).unwrap_or_default();
    let provider = ProviderInfo {
      host: s!(matches.value_of("hostname").unwrap_or("localhost")),
      port: matches.value_of("port").map(|port| port.parse::<u16>().unwrap()),
      path: matches.value_of("base-path").unwrap_or("/").into(),
      protocol: s!(matches.value_of("scheme").unwrap_or("http")),
      .. ProviderInfo::default()
    };
    let source = pact_source(matches);
    let filter = interaction_filter(matches);
    let provider_state_executor = Arc::new(HttpRequestProviderStateExecutor {
      state_change_url: matches.value_of("state-change-url").map(|s| s.to_string()),
      state_change_body: !matches.is_present("state-change-as-query"),
      state_change_teardown: matches.is_present("state-change-teardown")
    });

    let options = VerificationOptions {
      publish: matches.is_present("publish"),
      provider_version: matches.value_of("provider-version").map(|v| v.to_string()),
      build_url: matches.value_of("build-url").map(|v| v.to_string()),
      request_filter: None::<Arc<NullRequestFilterExecutor>>,
      provider_tags: matches.values_of("provider-tags")
        .map_or_else(Vec::new, |tags| tags.map(|tag| tag.to_string()).collect()),
      disable_ssl_verification: matches.is_present("disable-ssl-verification"),
      request_timeout: matches.value_of("request-timeout")
        .map(|t| t.parse::<u64>().unwrap_or(5000)).unwrap_or(5000)
    };

    for s in &source {
      debug!("Pact source to verify = {}", s);
    };

    verify_provider_async(
        provider,
        source,
        filter,
        matches.values_of_lossy("filter-consumer").unwrap_or_default(),
        options,
        &provider_state_executor
    ).await
      .map_err(|err| {
        error!("Verification failed with error: {}", err);
        2
      })
      .and_then(|result| if result { Ok(()) } else { Err(1) })
}

fn print_version(version: &str) {
  println!("\npact verifier version     : v{}", version);
  println!("pact specification version: v{}", PactSpecification::V3.version_str());
}
<commit_msg>chore: deprecate the old verifier functions<commit_after>//! Exported verifier functions

use std::env;
use std::str;
use std::str::FromStr;
use std::sync::Arc;

use clap::{AppSettings, ArgMatches, ErrorKind};
use log::{debug, error, LevelFilter};
use simplelog::{Config, TerminalMode, TermLogger};

use pact_matching::s;
use pact_models::http_utils::HttpAuth;
use pact_models::PactSpecification;
use pact_verifier::*;
use pact_verifier::callback_executors::HttpRequestProviderStateExecutor;

use super::args;

#[deprecated(since = "0.1.0-beta.0", note = "use the handle based interface instead. See pact_ffi/src/verifier/handle.rs")]
fn pact_source(matches: &ArgMatches) -> Vec<PactSource> {
  let mut sources = vec![];

  if let Some(values) = matches.values_of("file") {
    sources.extend(values.map(|v| PactSource::File(s!(v))).collect::<Vec<PactSource>>());
  };

  if let Some(values) = matches.values_of("dir") {
    sources.extend(values.map(|v| PactSource::Dir(s!(v))).collect::<Vec<PactSource>>());
  };

  if let Some(values) = matches.values_of("url") {
    sources.extend(values.map(|v| {
      if matches.is_present("user") {
        PactSource::URL(s!(v), matches.value_of("user").map(|user| {
          HttpAuth::User(user.to_string(), matches.value_of("password").map(|p| p.to_string()))
        }))
      } else if matches.is_present("token") {
        PactSource::URL(s!(v), matches.value_of("token").map(|token| HttpAuth::Token(token.to_string())))
      } else {
        PactSource::URL(s!(v), None)
      }
    }).collect::<Vec<PactSource>>());
  };

  if let Some(broker_url) = matches.value_of("broker-url") {
    let name = matches.value_of("provider-name").map(|n| n.to_string()).unwrap_or_default();
    let auth = matches.value_of("user").map(|user| {
      HttpAuth::User(user.to_string(), matches.value_of("password").map(|p| p.to_string()))
    }).or_else(|| matches.value_of("token").map(|t| HttpAuth::Token(t.to_string())));

    let source = if matches.is_present("consumer-version-selectors") || matches.is_present("consumer-version-tags") {
      let pending = matches.is_present("enable-pending");
      let wip = matches.value_of("include-wip-pacts-since").map(|wip| wip.to_string());
      let provider_tags = matches.values_of("provider-tags")
        .map_or_else(Vec::new, |tags| tags.map(|tag| tag.to_string()).collect());

      let selectors = if matches.is_present("consumer-version-selectors") {
        matches.values_of("consumer-version-selectors")
          .map_or_else(Vec::new, |s| json_to_selectors(s.collect::<Vec<_>>()))
      } else if matches.is_present("consumer-version-tags") {
        matches.values_of("consumer-version-tags")
          .map_or_else(Vec::new, |tags| consumer_tags_to_selectors(tags.collect::<Vec<_>>()))
      } else {
        vec![]
      };

      PactSource::BrokerWithDynamicConfiguration {
        provider_name: name,
        broker_url: broker_url.into(),
        enable_pending: pending,
        include_wip_pacts_since: wip,
        provider_tags,
        selectors,
        auth,
        links: vec![]
      }
    } else {
      PactSource::BrokerUrl(name, broker_url.to_string(), auth, vec![])
    };
    sources.push(source);
  };
  sources
}

// Moved to the pact_verifier crate. See pact_verifier/src/selectors.rs
#[deprecated(since = "0.1.0-beta.0", note = "Moved to the pact_verifier crate. See pact_verifier/src/selectors.rs")]
fn consumer_tags_to_selectors(tags: Vec<&str>) -> Vec<pact_verifier::ConsumerVersionSelector> {
  tags.iter().map(|t| {
    pact_verifier::ConsumerVersionSelector {
      consumer: None,
      fallback_tag: None,
      tag: Some(t.to_string()),
      latest: Some(true),
      branch: None,
      deployed_or_released: None,
      deployed: None,
      released: None,
      main_branch: None,
      environment: None,
    }
  }).collect()
}

// Moved to the pact_verifier crate. See pact_verifier/src/selectors.rs
#[deprecated(since = "0.1.0-beta.0", note = "Moved to the pact_verifier crate. See pact_verifier/src/selectors.rs")]
fn json_to_selectors(tags: Vec<&str>) -> Vec<pact_verifier::ConsumerVersionSelector> {
  tags.iter().map(|t| serde_json::from_str(t))
  .flatten()
  .collect()
}

#[deprecated(since = "0.1.0-beta.0", note = "use the handle based interface instead. See pact_ffi/src/verifier/handle.rs")]
fn interaction_filter(matches: &ArgMatches) -> FilterInfo {
  if matches.is_present("filter-description") &&
      (matches.is_present("filter-state") || matches.is_present("filter-no-state")) {
      if matches.is_present("filter-state") {
          FilterInfo::DescriptionAndState(matches.value_of("filter-description").unwrap().to_string(),
              matches.value_of("filter-state").unwrap().to_string())
      } else {
          FilterInfo::DescriptionAndState(matches.value_of("filter-description").unwrap().to_string(),
              String::new())
      }
  } else if matches.is_present("filter-description") {
      FilterInfo::Description(matches.value_of("filter-description").unwrap().to_string())
  } else if matches.is_present("filter-state") {
      FilterInfo::State(matches.value_of("filter-state").unwrap().to_string())
  } else if matches.is_present("filter-no-state") {
      FilterInfo::State(String::new())
  } else {
      FilterInfo::None
  }
}

/// Handles the command line arguments from the running process
/// This method is now deprecated and duplicated in the verifier CLI module. FFI consumers
/// should use the handle based interface instead
#[deprecated(since = "0.1.0-beta.0", note = "use the handle based interface instead. See pact_ffi/src/verifier/handle.rs")]
pub async fn handle_cli(version: &str) -> Result<(), i32> {
  let args: Vec<String> = env::args().collect();
  let program = args[0].clone();
  let app = args::setup_app(program, version);
  let matches = app
                  .setting(AppSettings::ArgRequiredElseHelp)
                  .setting(AppSettings::ColoredHelp)
                  .get_matches_safe();

  match matches {
    Ok(results) => handle_matches(&results).await,
    Err(ref err) => {
      match err.kind {
          ErrorKind::HelpDisplayed => {
              println!("{}", err.message);
              Ok(())
          },
          ErrorKind::VersionDisplayed => {
              print_version(version);
              println!();
              Ok(())
          },
          _ => {
              err.exit()
          }
      }
    }
  }
}

// TODO: it's possible to introspect the clap::Error and return it or wrapped error type
// so that the caller could have more control over the error output.
//
// Currently, clap prints things out as if it were a CLI call
#[allow(dead_code, missing_docs)]
/// This method is now deprecated and duplicated in the verifier CLI module. FFI consumers
/// should use the handle based interface instead
#[deprecated(since = "0.1.0-beta.0", note = "use the handle based interface instead. See pact_ffi/src/verifier/handle.rs")]
pub async fn handle_args(args: Vec<String>) -> Result<(), i32> {
  let program = "pact_verifier_cli".to_string();
  let version = format!("v{}", clap::crate_version!()).as_str().to_owned();
  let app = args::setup_app(program, &version);
  let matches = app
                  .setting(AppSettings::NoBinaryName)
                  .setting(AppSettings::ColorNever)
                  .get_matches_from_safe(args);

  match matches {
    Ok(results) => handle_matches(&results).await,
    Err(ref err) => {
      log::error!("error verifying Pact: {:?} {:?}", err.message, err);
      Err(4)
    }
  }
}

#[deprecated(since = "0.1.0-beta.0", note = "use the handle based interface instead. See pact_ffi/src/verifier/handle.rs")]
async fn handle_matches(matches: &clap::ArgMatches<'_>) -> Result<(), i32> {
    let level = matches.value_of("loglevel").unwrap_or("warn");
    let log_level = match level {
        "none" => LevelFilter::Off,
        _ => LevelFilter::from_str(level).unwrap()
    };
    TermLogger::init(log_level, Config::default(), TerminalMode::Mixed).unwrap_or_default();
    let provider = ProviderInfo {
      host: s!(matches.value_of("hostname").unwrap_or("localhost")),
      port: matches.value_of("port").map(|port| port.parse::<u16>().unwrap()),
      path: matches.value_of("base-path").unwrap_or("/").into(),
      protocol: s!(matches.value_of("scheme").unwrap_or("http")),
      .. ProviderInfo::default()
    };
    let source = pact_source(matches);
    let filter = interaction_filter(matches);
    let provider_state_executor = Arc::new(HttpRequestProviderStateExecutor {
      state_change_url: matches.value_of("state-change-url").map(|s| s.to_string()),
      state_change_body: !matches.is_present("state-change-as-query"),
      state_change_teardown: matches.is_present("state-change-teardown")
    });

    let options = VerificationOptions {
      publish: matches.is_present("publish"),
      provider_version: matches.value_of("provider-version").map(|v| v.to_string()),
      build_url: matches.value_of("build-url").map(|v| v.to_string()),
      request_filter: None::<Arc<NullRequestFilterExecutor>>,
      provider_tags: matches.values_of("provider-tags")
        .map_or_else(Vec::new, |tags| tags.map(|tag| tag.to_string()).collect()),
      disable_ssl_verification: matches.is_present("disable-ssl-verification"),
      request_timeout: matches.value_of("request-timeout")
        .map(|t| t.parse::<u64>().unwrap_or(5000)).unwrap_or(5000)
    };

    for s in &source {
      debug!("Pact source to verify = {}", s);
    };

    verify_provider_async(
        provider,
        source,
        filter,
        matches.values_of_lossy("filter-consumer").unwrap_or_default(),
        options,
        &provider_state_executor
    ).await
      .map_err(|err| {
        error!("Verification failed with error: {}", err);
        2
      })
      .and_then(|result| if result { Ok(()) } else { Err(1) })
}

fn print_version(version: &str) {
  println!("\npact verifier version     : v{}", version);
  println!("pact specification version: v{}", PactSpecification::V3.version_str());
}
<|endoftext|>


<commit_before>//! Exported verifier functions
use std::env;
use std::str;
use std::str::{FromStr};
use std::sync::Arc;
use clap::{AppSettings, ArgMatches, ErrorKind};
use log::{debug, LevelFilter};
use simplelog::{Config, TerminalMode, TermLogger};

use pact_matching::s;
use pact_models::http_utils::HttpAuth;
use pact_models::PactSpecification;
use pact_verifier::*;
use pact_verifier::callback_executors::HttpRequestProviderStateExecutor;

use super::args;

fn pact_source(matches: &ArgMatches) -> Vec<PactSource> {
  let mut sources = vec![];

  if let Some(values) = matches.values_of("file") {
    sources.extend(values.map(|v| PactSource::File(s!(v))).collect::<Vec<PactSource>>());
  };

  if let Some(values) = matches.values_of("dir") {
    sources.extend(values.map(|v| PactSource::Dir(s!(v))).collect::<Vec<PactSource>>());
  };

  if let Some(values) = matches.values_of("url") {
    sources.extend(values.map(|v| {
      if matches.is_present("user") {
        PactSource::URL(s!(v), matches.value_of("user").map(|user| {
          HttpAuth::User(user.to_string(), matches.value_of("password").map(|p| p.to_string()))
        }))
      } else if matches.is_present("token") {
        PactSource::URL(s!(v), matches.value_of("token").map(|token| HttpAuth::Token(token.to_string())))
      } else {
        PactSource::URL(s!(v), None)
      }
    }).collect::<Vec<PactSource>>());
  };

  if let Some(broker_url) = matches.value_of("broker-url") {
    let name = matches.value_of("provider-name").map(|n| n.to_string()).unwrap_or_default();
    let auth = matches.value_of("user").map(|user| {
      HttpAuth::User(user.to_string(), matches.value_of("password").map(|p| p.to_string()))
    }).or_else(|| matches.value_of("token").map(|t| HttpAuth::Token(t.to_string())));

    let source = if matches.is_present("consumer-version-selectors") || matches.is_present("consumer-version-tags") {
      let pending = matches.is_present("enable-pending");
      let wip = matches.value_of("include-wip-pacts-since").map(|wip| wip.to_string());
      let provider_tags = matches.values_of("provider-tags")
        .map_or_else(Vec::new, |tags| tags.map(|tag| tag.to_string()).collect());

      let selectors = if matches.is_present("consumer-version-selectors") {
        matches.values_of("consumer-version-selectors")
          .map_or_else(Vec::new, |s| json_to_selectors(s.collect::<Vec<_>>()))
      } else if matches.is_present("consumer-version-tags") {
        matches.values_of("consumer-version-tags")
          .map_or_else(Vec::new, |tags| consumer_tags_to_selectors(tags.collect::<Vec<_>>()))
      } else {
        vec![]
      };

      PactSource::BrokerWithDynamicConfiguration {
        provider_name: name,
        broker_url: broker_url.into(),
        enable_pending: pending,
        include_wip_pacts_since: wip,
        provider_tags,
        selectors,
        auth,
        links: vec![]
      }
    } else {
      PactSource::BrokerUrl(name, broker_url.to_string(), auth, vec![])
    };
    sources.push(source);
  };
  sources
}

fn consumer_tags_to_selectors(tags: Vec<&str>) -> Vec<pact_verifier::ConsumerVersionSelector> {
  tags.iter().map(|t| {
    pact_verifier::ConsumerVersionSelector {
      consumer: None,
      fallback_tag: None,
      tag: Some(t.to_string()),
      latest: Some(true),
      branch: None,
      deployed_or_released: None,
      deployed: None,
      released: None,
      main_branch: None,
      environment: None,
    }
  }).collect()
}

fn json_to_selectors(tags: Vec<&str>) -> Vec<pact_verifier::ConsumerVersionSelector> {
  tags.iter().map(|t| serde_json::from_str(t))
  .flatten()
  .collect()
}

fn interaction_filter(matches: &ArgMatches) -> FilterInfo {
  if matches.is_present("filter-description") &&
      (matches.is_present("filter-state") || matches.is_present("filter-no-state")) {
      if matches.is_present("filter-state") {
          FilterInfo::DescriptionAndState(s!(matches.value_of("filter-description").unwrap()),
              s!(matches.value_of("filter-state").unwrap()))
      } else {
          FilterInfo::DescriptionAndState(s!(matches.value_of("filter-description").unwrap()),
              s!(""))
      }
  } else if matches.is_present("filter-description") {
      FilterInfo::Description(s!(matches.value_of("filter-description").unwrap()))
  } else if matches.is_present("filter-state") {
      FilterInfo::State(s!(matches.value_of("filter-state").unwrap()))
  } else if matches.is_present("filter-no-state") {
      FilterInfo::State(s!(""))
  } else {
      FilterInfo::None
  }
}

/// Handles the command line arguments from the running process
pub async fn handle_cli(version: &str) -> Result<(), i32> {
  let args: Vec<String> = env::args().collect();
  let program = args[0].clone();
  let app = args::setup_app(program, version);
  let matches = app
                  .setting(AppSettings::ArgRequiredElseHelp)
                  .setting(AppSettings::ColoredHelp)
                  .get_matches_safe();

  match matches {
    Ok(results) => handle_matches(&results).await,
    Err(ref err) => {
      match err.kind {
          ErrorKind::HelpDisplayed => {
              println!("{}", err.message);
              Ok(())
          },
          ErrorKind::VersionDisplayed => {
              print_version(version);
              println!();
              Ok(())
          },
          _ => {
              err.exit()
          }
      }
    }
  }
}

// TODO: it's possible to introspect the clap::Error and return it or wrapped error type
// so that the caller could have more control over the error output.
//
// Currently, clap prints things out as if it were a CLI call
#[allow(dead_code, missing_docs)]
pub async fn handle_args(args: Vec<String>) -> Result<(), i32> {
  let program = "pact_verifier_cli".to_string();
  let version = format!("v{}", clap::crate_version!()).as_str().to_owned();
  let app = args::setup_app(program, &version);
  let matches = app
                  .setting(AppSettings::NoBinaryName)
                  .setting(AppSettings::ColorNever)
                  .get_matches_from_safe(args);

  match matches {
    Ok(results) => handle_matches(&results).await,
    Err(ref err) => {
      log::error!("error verifying Pact: {:?} {:?}", err.message, err);
      Err(4)
    }
  }
}

async fn handle_matches(matches: &clap::ArgMatches<'_>) -> Result<(), i32> {
    let level = matches.value_of("loglevel").unwrap_or("warn");
    let log_level = match level {
        "none" => LevelFilter::Off,
        _ => LevelFilter::from_str(level).unwrap()
    };
    TermLogger::init(log_level, Config::default(), TerminalMode::Mixed).unwrap_or_default();
    let provider = ProviderInfo {
      host: s!(matches.value_of("hostname").unwrap_or("localhost")),
      port: matches.value_of("port").map(|port| port.parse::<u16>().unwrap()),
      path: matches.value_of("base-path").unwrap_or("/").into(),
      protocol: s!(matches.value_of("scheme").unwrap_or("http")),
      .. ProviderInfo::default()
    };
    let source = pact_source(matches);
    let filter = interaction_filter(matches);
    let provider_state_executor = Arc::new(HttpRequestProviderStateExecutor {
      state_change_url: matches.value_of("state-change-url").map(|s| s.to_string()),
      state_change_body: !matches.is_present("state-change-as-query"),
      state_change_teardown: matches.is_present("state-change-teardown")
    });

    let options = VerificationOptions {
      publish: matches.is_present("publish"),
      provider_version: matches.value_of("provider-version").map(|v| v.to_string()),
      build_url: matches.value_of("build-url").map(|v| v.to_string()),
      request_filter: None::<Arc<NullRequestFilterExecutor>>,
      provider_tags: matches.values_of("provider-tags").map_or_else(Vec::new, |tags| tags.map(|tag| tag.to_string()).collect()),
      disable_ssl_verification: matches.is_present("disable-ssl-verification"),
      request_timeout: matches.value_of("request-timeout").map(|t| t.parse::<u64>().unwrap_or(5000)).unwrap_or(5000),
      .. VerificationOptions::default()
    };

    for s in &source {
      debug!("Pact source to verify = {}", s);
    };

    if verify_provider_async(
        provider,
        source,
        filter,
        matches.values_of_lossy("filter-consumer").unwrap_or_default(),
        options,
        &provider_state_executor
    ).await {
        Ok(())
    } else {
        Err(1)
    }
}

fn print_version(version: &str) {
  println!("\npact verifier version     : v{}", version);
  println!("pact specification version: v{}", PactSpecification::V3.version_str());
}
<commit_msg>feat(ffi verifier): revert unwanted changes<commit_after>//! Exported verifier functions

use std::env;
use std::str;
use std::str::FromStr;
use std::sync::Arc;

use clap::{AppSettings, ArgMatches, ErrorKind};
use log::{debug, LevelFilter};
use simplelog::{Config, TerminalMode, TermLogger};

use pact_matching::s;
use pact_models::http_utils::HttpAuth;
use pact_models::PactSpecification;
use pact_verifier::*;
use pact_verifier::callback_executors::HttpRequestProviderStateExecutor;

use super::args;

fn pact_source(matches: &ArgMatches) -> Vec<PactSource> {
  let mut sources = vec![];

  if let Some(values) = matches.values_of("file") {
    sources.extend(values.map(|v| PactSource::File(s!(v))).collect::<Vec<PactSource>>());
  };

  if let Some(values) = matches.values_of("dir") {
    sources.extend(values.map(|v| PactSource::Dir(s!(v))).collect::<Vec<PactSource>>());
  };

  if let Some(values) = matches.values_of("url") {
    sources.extend(values.map(|v| {
      if matches.is_present("user") {
        PactSource::URL(s!(v), matches.value_of("user").map(|user| {
          HttpAuth::User(user.to_string(), matches.value_of("password").map(|p| p.to_string()))
        }))
      } else if matches.is_present("token") {
        PactSource::URL(s!(v), matches.value_of("token").map(|token| HttpAuth::Token(token.to_string())))
      } else {
        PactSource::URL(s!(v), None)
      }
    }).collect::<Vec<PactSource>>());
  };

  if let Some(broker_url) = matches.value_of("broker-url") {
    let name = matches.value_of("provider-name").map(|n| n.to_string()).unwrap_or_default();
    let auth = matches.value_of("user").map(|user| {
      HttpAuth::User(user.to_string(), matches.value_of("password").map(|p| p.to_string()))
    }).or_else(|| matches.value_of("token").map(|t| HttpAuth::Token(t.to_string())));

    let source = if matches.is_present("consumer-version-selectors") || matches.is_present("consumer-version-tags") {
      let pending = matches.is_present("enable-pending");
      let wip = matches.value_of("include-wip-pacts-since").map(|wip| wip.to_string());
      let provider_tags = matches.values_of("provider-tags")
        .map_or_else(Vec::new, |tags| tags.map(|tag| tag.to_string()).collect());

      let selectors = if matches.is_present("consumer-version-selectors") {
        matches.values_of("consumer-version-selectors")
          .map_or_else(Vec::new, |s| json_to_selectors(s.collect::<Vec<_>>()))
      } else if matches.is_present("consumer-version-tags") {
        matches.values_of("consumer-version-tags")
          .map_or_else(Vec::new, |tags| consumer_tags_to_selectors(tags.collect::<Vec<_>>()))
      } else {
        vec![]
      };

      PactSource::BrokerWithDynamicConfiguration {
        provider_name: name,
        broker_url: broker_url.into(),
        enable_pending: pending,
        include_wip_pacts_since: wip,
        provider_tags,
        selectors,
        auth,
        links: vec![]
      }
    } else {
      PactSource::BrokerUrl(name, broker_url.to_string(), auth, vec![])
    };
    sources.push(source);
  };
  sources
}

fn consumer_tags_to_selectors(tags: Vec<&str>) -> Vec<pact_verifier::ConsumerVersionSelector> {
  tags.iter().map(|t| {
    pact_verifier::ConsumerVersionSelector {
      consumer: None,
      fallback_tag: None,
      tag: Some(t.to_string()),
      latest: Some(true),
      branch: None,
      deployed_or_released: None,
      deployed: None,
      released: None,
      main_branch: None,
      environment: None,
    }
  }).collect()
}

fn json_to_selectors(tags: Vec<&str>) -> Vec<pact_verifier::ConsumerVersionSelector> {
  tags.iter().map(|t| serde_json::from_str(t))
  .flatten()
  .collect()
}

fn interaction_filter(matches: &ArgMatches) -> FilterInfo {
  if matches.is_present("filter-description") &&
      (matches.is_present("filter-state") || matches.is_present("filter-no-state")) {
      if matches.is_present("filter-state") {
          FilterInfo::DescriptionAndState(s!(matches.value_of("filter-description").unwrap()),
              s!(matches.value_of("filter-state").unwrap()))
      } else {
          FilterInfo::DescriptionAndState(s!(matches.value_of("filter-description").unwrap()),
              s!(""))
      }
  } else if matches.is_present("filter-description") {
      FilterInfo::Description(s!(matches.value_of("filter-description").unwrap()))
  } else if matches.is_present("filter-state") {
      FilterInfo::State(s!(matches.value_of("filter-state").unwrap()))
  } else if matches.is_present("filter-no-state") {
      FilterInfo::State(s!(""))
  } else {
      FilterInfo::None
  }
}

/// Handles the command line arguments from the running process
pub async fn handle_cli(version: &str) -> Result<(), i32> {
  let args: Vec<String> = env::args().collect();
  let program = args[0].clone();
  let app = args::setup_app(program, version);
  let matches = app
                  .setting(AppSettings::ArgRequiredElseHelp)
                  .setting(AppSettings::ColoredHelp)
                  .get_matches_safe();

  match matches {
    Ok(results) => handle_matches(&results).await,
    Err(ref err) => {
      match err.kind {
          ErrorKind::HelpDisplayed => {
              println!("{}", err.message);
              Ok(())
          },
          ErrorKind::VersionDisplayed => {
              print_version(version);
              println!();
              Ok(())
          },
          _ => {
              err.exit()
          }
      }
    }
  }
}

// TODO: it's possible to introspect the clap::Error and return it or wrapped error type
// so that the caller could have more control over the error output.
//
// Currently, clap prints things out as if it were a CLI call
#[allow(dead_code, missing_docs)]
pub async fn handle_args(args: Vec<String>) -> Result<(), i32> {
  let program = "pact_verifier_cli".to_string();
  let version = format!("v{}", clap::crate_version!()).as_str().to_owned();
  let app = args::setup_app(program, &version);
  let matches = app
                  .setting(AppSettings::NoBinaryName)
                  .setting(AppSettings::ColorNever)
                  .get_matches_from_safe(args);

  match matches {
    Ok(results) => handle_matches(&results).await,
    Err(ref err) => {
      log::error!("error verifying Pact: {:?} {:?}", err.message, err);
      Err(4)
    }
  }
}

async fn handle_matches(matches: &clap::ArgMatches<'_>) -> Result<(), i32> {
    let level = matches.value_of("loglevel").unwrap_or("warn");
    let log_level = match level {
        "none" => LevelFilter::Off,
        _ => LevelFilter::from_str(level).unwrap()
    };
    TermLogger::init(log_level, Config::default(), TerminalMode::Mixed).unwrap_or_default();
    let provider = ProviderInfo {
      host: s!(matches.value_of("hostname").unwrap_or("localhost")),
      port: matches.value_of("port").map(|port| port.parse::<u16>().unwrap()),
      path: matches.value_of("base-path").unwrap_or("/").into(),
      protocol: s!(matches.value_of("scheme").unwrap_or("http")),
      .. ProviderInfo::default()
    };
    let source = pact_source(matches);
    let filter = interaction_filter(matches);
    let provider_state_executor = Arc::new(HttpRequestProviderStateExecutor {
      state_change_url: matches.value_of("state-change-url").map(|s| s.to_string()),
      state_change_body: !matches.is_present("state-change-as-query"),
      state_change_teardown: matches.is_present("state-change-teardown")
    });

    let options = VerificationOptions {
      publish: matches.is_present("publish"),
      provider_version: matches.value_of("provider-version").map(|v| v.to_string()),
      build_url: matches.value_of("build-url").map(|v| v.to_string()),
      request_filter: None::<Arc<NullRequestFilterExecutor>>,
      provider_tags: matches.values_of("provider-tags").map_or_else(Vec::new, |tags| tags.map(|tag| tag.to_string()).collect()),
      disable_ssl_verification: matches.is_present("disable-ssl-verification"),
      request_timeout: matches.value_of("request-timeout").map(|t| t.parse::<u64>().unwrap_or(5000)).unwrap_or(5000),
      .. VerificationOptions::default()
    };

    for s in &source {
      debug!("Pact source to verify = {}", s);
    };

    if verify_provider_async(
        provider,
        source,
        filter,
        matches.values_of_lossy("filter-consumer").unwrap_or_default(),
        options,
        &provider_state_executor
    ).await {
        Ok(())
    } else {
        Err(1)
    }
}

fn print_version(version: &str) {
  println!("\npact verifier version     : v{}", version);
  println!("pact specification version: v{}", PactSpecification::V3.version_str());
}
<|endoftext|>


<commit_before>use core::prelude::*;

use collections::vec::Vec;
use collections::Mutable;

pub struct RollingAverage<T> {
    pub entries: Vec<T>,
    sum: T,
    count: uint,
    pos: uint,
}

#[allow(dead_code)]
impl<T: Add<T,T> + Sub<T, T> + ::std::num::Zero + Div<f32, T> + Clone> RollingAverage<T> {
    pub fn new(count: uint) -> RollingAverage<T> {
        RollingAverage {
            entries: Vec::from_elem(count, ::std::num::zero::<T>()),
            sum: ::std::num::zero::<T>(),
            count: 0,
            pos: 0,
        }
    }
    pub fn push(&mut self, value: T) -> T {
        let len = self.entries.len();
        if self.count < len {
            self.count += 1;
        } else {
            self.sum = self.sum - self.entries[self.pos];
        }
        *self.entries.get_mut(self.pos) = value.clone();
        self.sum = self.sum + value;
        self.pos = (self.pos + 1) % self.entries.len();
        self.get_average()
    }
    pub fn get_average(&self) -> T {
        self.sum / self.count as f32
    }
    pub fn clear(&mut self) {
        self.sum = ::std::num::zero::<T>();
        self.count = 0;
        self.pos = 0;
        self.entries.clear();
    }
}
<commit_msg>fix rollingaverage<commit_after>use core::prelude::*;

use collections::vec::Vec;
use collections::Mutable;

pub struct RollingAverage<T> {
    pub entries: Vec<T>,
    sum: T,
    count: uint,
    pos: uint,
}

#[allow(dead_code)]
impl<T: Add<T,T> + Sub<T, T> + ::std::num::Zero + Div<f32, T> + Clone> RollingAverage<T> {
    pub fn new(count: uint) -> RollingAverage<T> {
        RollingAverage {
            entries: Vec::from_elem(count, ::std::num::zero::<T>()),
            sum: ::std::num::zero::<T>(),
            count: 0,
            pos: 0,
        }
    }
    pub fn push(&mut self, value: T) -> T {
        let len = self.entries.len();
        if self.count < len {
            self.count += 1;
        } else {
            self.sum = self.sum - self.entries[self.pos];
        }
        *self.entries.get_mut(self.pos) = value.clone();
        self.sum = self.sum + value;
        self.pos = (self.pos + 1) % self.entries.len();
        self.get_average()
    }
    pub fn get_average(&self) -> T {
        self.sum / self.count as f32
    }
    pub fn clear(&mut self) {
        self.sum = ::std::num::zero::<T>();
        self.count = 0;
        self.pos = 0;
    }
}
<|endoftext|>


<commit_before><commit_msg>Fix clone_macro example<commit_after><|endoftext|>


<commit_before>use std::env;
use std::fs;
use std::path::Path;

fn main() {
	let target = env::var("TARGET").unwrap();
	println!("target={}", target);
	match target.find("-windows-") {
		Some(..) => {
			// do not build c-code on windows, use binaries
			let output_dir = env::var("OUT_DIR").unwrap();
			let prebuilt_dir = env::var("INDY_PREBUILT_DEPS_DIR").unwrap();

			let dst = Path::new(&output_dir[..]).join("..\\..\\..");
			let prebuilt_lib = Path::new(&prebuilt_dir[..]).join("lib");

			println!("cargo:rustc-link-search=native={}", prebuilt_dir);
			println!("cargo:rustc-flags=-L {}/lib", prebuilt_dir);
			println!("cargo:include={}/include", prebuilt_dir);

			let files = vec!["libeay32md.dll", "libsodium.dll", "libzmq.dll", "ssleay32md.dll"];
			for f in files.iter() {
				if let Ok(_) = fs::copy(&prebuilt_lib.join(f), &dst.join(f)) {
					println!("copy {} -> {}", &prebuilt_lib.join(f).display(), &dst.join(f).display());
				}
			}
			return;
		}
		None => {}
	}
}
<commit_msg>Fix path in build.rs of libindy.<commit_after>use std::env;
use std::fs;
use std::path::Path;

fn main() {
	let target = env::var("TARGET").unwrap();
	println!("target={}", target);
	match target.find("-windows-") {
		Some(..) => {
			// do not build c-code on windows, use binaries
			let output_dir = env::var("OUT_DIR").unwrap();
			let prebuilt_dir = env::var("INDY_PREBUILT_DEPS_DIR").unwrap();

			let dst = Path::new(&output_dir[..]).join("..\\..\\..");
			let prebuilt_lib = Path::new(&prebuilt_dir[..]).join("lib");

			println!("cargo:rustc-link-search=native={}", prebuilt_dir);
			println!("cargo:rustc-flags=-L {}\\lib", prebuilt_dir);
			println!("cargo:include={}\\include", prebuilt_dir);

			let files = vec!["libeay32md.dll", "libsodium.dll", "libzmq.dll", "ssleay32md.dll"];
			for f in files.iter() {
				if let Ok(_) = fs::copy(&prebuilt_lib.join(f), &dst.join(f)) {
					println!("copy {} -> {}", &prebuilt_lib.join(f).display(), &dst.join(f).display());
				}
			}
			return;
		}
		None => {}
	}
}
<|endoftext|>


<commit_before><commit_msg>hash_tables: implement delete() for SeparateChainingHashST<commit_after><|endoftext|>


<commit_before>//! Provides a keyframe transformation which is a transform associated
//! with a specific point in time

use std::f32;
use std::cmp::{Eq, Ord, PartialOrd, PartialEq, Ordering};

use linalg::{self, quaternion, Vector, Matrix4, Quaternion, Transform};

/// A transformation associated with a specific point in time
#[derive(Debug, Copy, Clone)]
pub struct Keyframe {
    pub time: f32,
    translation: Vector,
    rotation: Quaternion,
    scaling: Matrix4,
}

impl Keyframe {
    /// Construct a new keyframe transformation by associating the
    /// transform passed with the time point `time`. The transform will
    /// be stored in a decomposed form, M = TRS.
    pub fn new(transform: &Transform, time: f32) -> Keyframe {
        assert!(f32::is_finite(time));
        let (t, r, s) = Keyframe::decompose(transform);
        Keyframe { time: time, translation: t, rotation: r, scaling: s }
    }
    /// Decompose the transformation into its component translation, rotation and
    /// scaling operations.
    fn decompose(transform: &Transform) -> (Vector, Quaternion, Matrix4) {
        let mut m = transform.mat;
        // Extract the translation component and remove it from the matrix
        let translation = Vector::new(*m.at(0, 3), *m.at(1, 3), *m.at(2, 3));
        for i in 0..3 {
            *m.at_mut(i, 3) = 0.0;
            *m.at_mut(3, i) = 0.0;
        }
        *m.at_mut(3, 3) = 1.0;
        // Extract rotation component using polar decomposition by computing
        // M_{i + 1} = 1/2 (M_i + (M_i^T)^-1) to convergence
        let mut rot_mat = m;
        for _ in 0..100 {
            let m_inv_trans = rot_mat.transpose().inverse();
            let r_next: Matrix4 = rot_mat.iter().zip(m_inv_trans.iter())
                .map(|(&a, &b)| 0.5 * (a - b)).collect();
            let mut norm = 0.0;
            for i in 0..3 {
                let n = f32::abs(*rot_mat.at(i, 0) - *r_next.at(i, 0))
                    + f32::abs(*rot_mat.at(i, 1) - *r_next.at(i, 1))
                    + f32::abs(*rot_mat.at(i, 2) - *r_next.at(i, 2));
                norm = f32::max(norm, n);
            }
            rot_mat = r_next;
            if norm <= 0.0001 {
                break;
            }
        }
        (translation, Quaternion::from_matrix(&rot_mat), rot_mat.inverse() * m)
    }
    /// Return the transformation stored for this keyframe
    pub fn transform(&self) -> Transform {
        let m = self.rotation.to_matrix() * self.scaling;
        Transform::translate(&self.translation) * Transform::from_mat(&m)
    }
}

/// Interpolate between the two keyframes at some time. If time is before
/// or after the interval spanned by the keyframes then the nearest one is
/// returned. Otherwise the transforms are interpolated and this new
/// transform is returned.
pub fn interpolate(time: f32, a: &Keyframe, b: &Keyframe) -> Transform {
    // Order the transformations by their time points
    let (first, second) = if a.time < b.time { (a, b) } else { (b, a) };
    if time <= first.time {
        let m = first.rotation.to_matrix() * first.scaling;
        Transform::translate(&first.translation) * Transform::from_mat(&m)
    } else if time >= second.time {
        let m = second.rotation.to_matrix() * second.scaling;
        Transform::translate(&second.translation) * Transform::from_mat(&m)
    } else {
        let dt = (time - first.time) / (second.time - first.time);
        let translation = (1.0 - dt) * first.translation + dt * second.translation;
        let rotation = quaternion::slerp(dt, &first.rotation, &second.rotation);
        let scaling: Matrix4 = first.scaling.iter().zip(second.scaling.iter())
                .map(|(a, b)| linalg::lerp(dt, a, b)).collect();
        let m = rotation.to_matrix() * scaling;
        Transform::translate(&translation) * Transform::from_mat(&m)
    }
}

impl Ord for Keyframe {
    fn cmp(&self, other: &Keyframe) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

impl PartialOrd for Keyframe {
    fn partial_cmp(&self, other: &Keyframe) -> Option<Ordering> {
        self.time.partial_cmp(&other.time)
    }
}

impl Eq for Keyframe {}

impl PartialEq for Keyframe {
    fn eq(&self, other: &Keyframe) -> bool {
        self.time == other.time
    }
}

<commit_msg>Should be adding a and b not subtracting!<commit_after>//! Provides a keyframe transformation which is a transform associated
//! with a specific point in time

use std::f32;
use std::cmp::{Eq, Ord, PartialOrd, PartialEq, Ordering};

use linalg::{self, quaternion, Vector, Matrix4, Quaternion, Transform};

/// A transformation associated with a specific point in time
#[derive(Debug, Copy, Clone)]
pub struct Keyframe {
    pub time: f32,
    translation: Vector,
    rotation: Quaternion,
    scaling: Matrix4,
}

impl Keyframe {
    /// Construct a new keyframe transformation by associating the
    /// transform passed with the time point `time`. The transform will
    /// be stored in a decomposed form, M = TRS.
    pub fn new(transform: &Transform, time: f32) -> Keyframe {
        assert!(f32::is_finite(time));
        let (t, r, s) = Keyframe::decompose(transform);
        Keyframe { time: time, translation: t, rotation: r, scaling: s }
    }
    /// Decompose the transformation into its component translation, rotation and
    /// scaling operations.
    fn decompose(transform: &Transform) -> (Vector, Quaternion, Matrix4) {
        let mut m = transform.mat;
        // Extract the translation component and remove it from the matrix
        let translation = Vector::new(*m.at(0, 3), *m.at(1, 3), *m.at(2, 3));
        for i in 0..3 {
            *m.at_mut(i, 3) = 0.0;
            *m.at_mut(3, i) = 0.0;
        }
        *m.at_mut(3, 3) = 1.0;
        println!("m = {:?}", m);
        // Extract rotation component using polar decomposition by computing
        // M_{i + 1} = 1/2 (M_i + (M_i^T)^-1) to convergence
        let mut rot_mat = m;
        for _ in 0..100 {
            let m_inv_trans = rot_mat.transpose().inverse();
            println!("computed inverse");
            let r_next: Matrix4 = rot_mat.iter().zip(m_inv_trans.iter())
                .map(|(&a, &b)| 0.5 * (a + b)).collect();
            let mut norm = 0.0;
            for i in 0..3 {
                let n = f32::abs(*rot_mat.at(i, 0) - *r_next.at(i, 0))
                    + f32::abs(*rot_mat.at(i, 1) - *r_next.at(i, 1))
                    + f32::abs(*rot_mat.at(i, 2) - *r_next.at(i, 2));
                norm = f32::max(norm, n);
            }
            rot_mat = r_next;
            if norm <= 0.0001 {
                break;
            }
        }
        (translation, Quaternion::from_matrix(&rot_mat), rot_mat.inverse() * m)
    }
    /// Return the transformation stored for this keyframe
    pub fn transform(&self) -> Transform {
        let m = self.rotation.to_matrix() * self.scaling;
        Transform::translate(&self.translation) * Transform::from_mat(&m)
    }
}

/// Interpolate between the two keyframes at some time. If time is before
/// or after the interval spanned by the keyframes then the nearest one is
/// returned. Otherwise the transforms are interpolated and this new
/// transform is returned.
pub fn interpolate(time: f32, a: &Keyframe, b: &Keyframe) -> Transform {
    // Order the transformations by their time points
    let (first, second) = if a.time < b.time { (a, b) } else { (b, a) };
    if time <= first.time {
        let m = first.rotation.to_matrix() * first.scaling;
        Transform::translate(&first.translation) * Transform::from_mat(&m)
    } else if time >= second.time {
        let m = second.rotation.to_matrix() * second.scaling;
        Transform::translate(&second.translation) * Transform::from_mat(&m)
    } else {
        let dt = (time - first.time) / (second.time - first.time);
        let translation = (1.0 - dt) * first.translation + dt * second.translation;
        let rotation = quaternion::slerp(dt, &first.rotation, &second.rotation);
        let scaling: Matrix4 = first.scaling.iter().zip(second.scaling.iter())
                .map(|(a, b)| linalg::lerp(dt, a, b)).collect();
        let m = rotation.to_matrix() * scaling;
        Transform::translate(&translation) * Transform::from_mat(&m)
    }
}

impl Ord for Keyframe {
    fn cmp(&self, other: &Keyframe) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

impl PartialOrd for Keyframe {
    fn partial_cmp(&self, other: &Keyframe) -> Option<Ordering> {
        self.time.partial_cmp(&other.time)
    }
}

impl Eq for Keyframe {}

impl PartialEq for Keyframe {
    fn eq(&self, other: &Keyframe) -> bool {
        self.time == other.time
    }
}

<|endoftext|>


<commit_before>//! Intel's Restricted Transactional Memory (RTM).
//!
//! This CPU feature is available on Intel Broadwell or later CPUs (and some Haswell).
//!
//! The reference is [Intel 64 and IA-32 Architectures Software Developer's
//! Manual Volume 2: Instruction Set Reference, A-Z][intel64_ref].
//!
//! [Wikipedia][wikipedia_rtm] provides a quick overview of the assembly instructions, and
//! Intel's [programming considerations][intel_consid] details what sorts of instructions within a
//! transaction are likely to cause an abort.
//!
//! [intel64_ref]: http://www.intel.de/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf
//! [wikipedia_rtm]: https://en.wikipedia.org/wiki/Transactional_Synchronization_Extensions#Restricted_Transactional_Memory
//! [intel_consid]: https://software.intel.com/en-us/cpp-compiler-developer-guide-and-reference-intel-transactional-synchronization-extensions-intel-tsx-programming-considerations

#[cfg(test)]
use stdsimd_test::assert_instr;

extern "C" {
    #[link_name = "llvm.x86.xbegin"]
    fn x86_xbegin() -> i32;
    #[link_name = "llvm.x86.xend"]
    fn x86_xend() -> ();
    #[link_name = "llvm.x86.xabort"]
    fn x86_xabort(imm8: i8) -> ();
    #[link_name = "llvm.x86.xtest"]
    fn x86_xtest() -> i32;
}

/// Transaction successfully started.
pub const _XBEGIN_STARTED: u32 = !0;

/// Transaction explicitly aborted with xabort. The parameter passed to xabort is available with
/// _xabort_code(status).
pub const _XABORT_EXPLICIT: u32 = 1 << 0;

/// Transaction retry is possible.
pub const _XABORT_RETRY: u32 = 1 << 1;

/// Transaction abort due to a memory conflict with another thread.
pub const _XABORT_CONFLICT: u32 = 1 << 2;

/// Transaction abort due to the transaction using too much memory.
pub const _XABORT_CAPACITY: u32 = 1 << 3;

/// Transaction abort due to a debug trap.
pub const _XABORT_DEBUG: u32 = 1 << 4;

/// Transaction abort in a inner nested transaction.
pub const _XABORT_NESTED: u32 = 1 << 5;

/// Specifies the start of a restricted transactional memory (RTM) code region and returns a value
/// indicating status.
///
/// [Intel's documentation](https://software.intel.com/en-us/cpp-compiler-developer-guide-and-reference-xbegin).
#[inline]
#[target_feature(enable = "rtm")]
#[cfg_attr(test, assert_instr(xbegin))]
pub unsafe fn _xbegin() -> u32 {
    x86_xbegin() as _
}

/// Specifies the end of a restricted transactional memory (RTM) code region.
///
/// [Intel's documentation](https://software.intel.com/en-us/cpp-compiler-developer-guide-and-reference-xend).
#[inline]
#[target_feature(enable = "rtm")]
#[cfg_attr(test, assert_instr(xend))]
pub unsafe fn _xend() {
    x86_xend()
}

/// Forces a restricted transactional memory (RTM) region to abort.
///
/// [Intel's documentation](https://software.intel.com/en-us/cpp-compiler-developer-guide-and-reference-xabort).
#[inline]
#[target_feature(enable = "rtm")]
#[cfg_attr(test, assert_instr(xabort))]
pub unsafe fn _xabort(imm8: u32) {
    macro_rules! call {
        ($imm8:expr) => {
            x86_xabort($imm8)
        };
    }
    constify_imm8!(imm8, call)
}

/// Queries whether the processor is executing in a transactional region identified by restricted
/// transactional memory (RTM) or hardware lock elision (HLE).
///
/// [Intel's documentation](https://software.intel.com/en-us/cpp-compiler-developer-guide-and-reference-xtest).
#[inline]
#[target_feature(enable = "rtm")]
#[cfg_attr(test, assert_instr(xtest))]
pub unsafe fn _xtest() -> u8 {
    x86_xtest() as _
}

/// Retrieves the parameter passed to [`_xabort`] when [`_xbegin`]'s status has the
/// `_XABORT_EXPLICIT` flag set.
#[inline]
pub const fn _xabort_code(status: u32) -> u32 {
    (status >> 24) & 0xFF
}

#[cfg(test)]
mod tests {
    use stdsimd_test::simd_test;

    use crate::core_arch::x86::*;

    #[simd_test(enable = "rtm")]
    unsafe fn test_xbegin_xend() {
        let mut x = 0;
        for _ in 0..10 {
            let code = rtm::_xbegin();
            if code == _XBEGIN_STARTED {
                x += 1;
                rtm::_xend();
                assert_eq!(x, 1);
                break
            }
            assert_eq!(x, 0);
        }
    }

    #[simd_test(enable = "rtm")]
    unsafe fn test_xabort() {
        const ABORT_CODE: u32 = 42;
        // aborting outside a transactional region does nothing
        _xabort(ABORT_CODE);

        for _ in 0..10 {
            let mut x = 0;
            let code = rtm::_xbegin();
            if code == _XBEGIN_STARTED {
                x += 1;
                rtm::_xabort(ABORT_CODE);
            } else if code & _XABORT_EXPLICIT != 0 {
                let test_abort_code = rtm::_xabort_code(code);
                assert_eq!(test_abort_code, ABORT_CODE);
            }
            assert_eq!(x, 0);
        }
    }

    #[simd_test(enable = "rtm")]
    unsafe fn test_xtest() {
        assert_eq!(_xtest(), 0);

        for _ in 0..10 {
            let code = rtm::_xbegin();
            if code == _XBEGIN_STARTED {
                let in_tx = _xtest();
                rtm::_xend();

                // putting the assert inside the transaction would abort the transaction on fail
                // without any output/panic/etc
                assert_eq!(in_tx, 1);
                break
            }
        }
    }
}<commit_msg>clippy fix<commit_after>//! Intel's Restricted Transactional Memory (RTM).
//!
//! This CPU feature is available on Intel Broadwell or later CPUs (and some Haswell).
//!
//! The reference is [Intel 64 and IA-32 Architectures Software Developer's
//! Manual Volume 2: Instruction Set Reference, A-Z][intel64_ref].
//!
//! [Wikipedia][wikipedia_rtm] provides a quick overview of the assembly instructions, and
//! Intel's [programming considerations][intel_consid] details what sorts of instructions within a
//! transaction are likely to cause an abort.
//!
//! [intel64_ref]: http://www.intel.de/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf
//! [wikipedia_rtm]: https://en.wikipedia.org/wiki/Transactional_Synchronization_Extensions#Restricted_Transactional_Memory
//! [intel_consid]: https://software.intel.com/en-us/cpp-compiler-developer-guide-and-reference-intel-transactional-synchronization-extensions-intel-tsx-programming-considerations

#[cfg(test)]
use stdsimd_test::assert_instr;

extern "C" {
    #[link_name = "llvm.x86.xbegin"]
    fn x86_xbegin() -> i32;
    #[link_name = "llvm.x86.xend"]
    fn x86_xend() -> ();
    #[link_name = "llvm.x86.xabort"]
    fn x86_xabort(imm8: i8) -> ();
    #[link_name = "llvm.x86.xtest"]
    fn x86_xtest() -> i32;
}

/// Transaction successfully started.
pub const _XBEGIN_STARTED: u32 = !0;

/// Transaction explicitly aborted with xabort. The parameter passed to xabort is available with
/// `_xabort_code(status)`.
pub const _XABORT_EXPLICIT: u32 = 1 << 0;

/// Transaction retry is possible.
pub const _XABORT_RETRY: u32 = 1 << 1;

/// Transaction abort due to a memory conflict with another thread.
pub const _XABORT_CONFLICT: u32 = 1 << 2;

/// Transaction abort due to the transaction using too much memory.
pub const _XABORT_CAPACITY: u32 = 1 << 3;

/// Transaction abort due to a debug trap.
pub const _XABORT_DEBUG: u32 = 1 << 4;

/// Transaction abort in a inner nested transaction.
pub const _XABORT_NESTED: u32 = 1 << 5;

/// Specifies the start of a restricted transactional memory (RTM) code region and returns a value
/// indicating status.
///
/// [Intel's documentation](https://software.intel.com/en-us/cpp-compiler-developer-guide-and-reference-xbegin).
#[inline]
#[target_feature(enable = "rtm")]
#[cfg_attr(test, assert_instr(xbegin))]
pub unsafe fn _xbegin() -> u32 {
    x86_xbegin() as _
}

/// Specifies the end of a restricted transactional memory (RTM) code region.
///
/// [Intel's documentation](https://software.intel.com/en-us/cpp-compiler-developer-guide-and-reference-xend).
#[inline]
#[target_feature(enable = "rtm")]
#[cfg_attr(test, assert_instr(xend))]
pub unsafe fn _xend() {
    x86_xend()
}

/// Forces a restricted transactional memory (RTM) region to abort.
///
/// [Intel's documentation](https://software.intel.com/en-us/cpp-compiler-developer-guide-and-reference-xabort).
#[inline]
#[target_feature(enable = "rtm")]
#[cfg_attr(test, assert_instr(xabort))]
pub unsafe fn _xabort(imm8: u32) {
    macro_rules! call {
        ($imm8:expr) => {
            x86_xabort($imm8)
        };
    }
    constify_imm8!(imm8, call)
}

/// Queries whether the processor is executing in a transactional region identified by restricted
/// transactional memory (RTM) or hardware lock elision (HLE).
///
/// [Intel's documentation](https://software.intel.com/en-us/cpp-compiler-developer-guide-and-reference-xtest).
#[inline]
#[target_feature(enable = "rtm")]
#[cfg_attr(test, assert_instr(xtest))]
pub unsafe fn _xtest() -> u8 {
    x86_xtest() as _
}

/// Retrieves the parameter passed to [`_xabort`] when [`_xbegin`]'s status has the
/// `_XABORT_EXPLICIT` flag set.
#[inline]
pub const fn _xabort_code(status: u32) -> u32 {
    (status >> 24) & 0xFF
}

#[cfg(test)]
mod tests {
    use stdsimd_test::simd_test;

    use crate::core_arch::x86::*;

    #[simd_test(enable = "rtm")]
    unsafe fn test_xbegin_xend() {
        let mut x = 0;
        for _ in 0..10 {
            let code = rtm::_xbegin();
            if code == _XBEGIN_STARTED {
                x += 1;
                rtm::_xend();
                assert_eq!(x, 1);
                break
            }
            assert_eq!(x, 0);
        }
    }

    #[simd_test(enable = "rtm")]
    unsafe fn test_xabort() {
        const ABORT_CODE: u32 = 42;
        // aborting outside a transactional region does nothing
        _xabort(ABORT_CODE);

        for _ in 0..10 {
            let mut x = 0;
            let code = rtm::_xbegin();
            if code == _XBEGIN_STARTED {
                x += 1;
                rtm::_xabort(ABORT_CODE);
            } else if code & _XABORT_EXPLICIT != 0 {
                let test_abort_code = rtm::_xabort_code(code);
                assert_eq!(test_abort_code, ABORT_CODE);
            }
            assert_eq!(x, 0);
        }
    }

    #[simd_test(enable = "rtm")]
    unsafe fn test_xtest() {
        assert_eq!(_xtest(), 0);

        for _ in 0..10 {
            let code = rtm::_xbegin();
            if code == _XBEGIN_STARTED {
                let in_tx = _xtest();
                rtm::_xend();

                // putting the assert inside the transaction would abort the transaction on fail
                // without any output/panic/etc
                assert_eq!(in_tx, 1);
                break
            }
        }
    }
}<|endoftext|>


<commit_before>
use std::rc::Rc;
use std::cell::RefCell;
use std::any::Any;
use std::collections::HashMap;
use std::time::{Instant, Duration};

pub struct Registry<Id> {
    /// A worker-specific identifier.
    id: Id,
    /// A map from names to typed loggers.
    map: HashMap<String, (Box<Any>, Box<Flush>)>,
    /// An instant common to all logging statements.
    time: Instant,
}

impl<Id: Clone+'static> Registry<Id> {
    /// Binds a log name to an action on log event batches.
    ///
    /// This method also returns any pre-installed action, rather than overwriting it
    /// and pivoting the logging destination mid-stream. New loggers with this name will
    /// use the new destination, and existing loggers will use the old destination.
    ///
    /// The action should respond to a sequence of events with non-decreasing timestamps
    /// (Durations) and well as a timestamp that lower bounds the next event that could be
    /// seen (likely greater or equal to the timestamp of the last event). The end of a
    /// logging stream is indicated only by dropping the associated action, which can be
    /// accomplished with `remove` (or a call to insert, though this is not recommended).
    pub fn insert<T: 'static, F: FnMut(&Duration, &mut Vec<(Duration, Id, T)>)+'static>(
        &mut self,
        name: &str,
        action: F) -> Option<Box<Any>>
    {
        let logger = Logger::<T, Id>::new(self.time.clone(), self.id.clone(), action);
        self.map.insert(name.to_owned(), (Box::new(logger.clone()), Box::new(logger))).map(|x| x.0)
    }

    /// Removes a bound logger.
    ///
    /// This is intended primarily to close a logging stream and let the associated writer
    /// communicate that the stream is closed to any consumers. If a binding is not removed,
    /// then the stream cannot be complete as in principle anyone could acquire a handle to
    /// the logger and start further logging.
    pub fn remove(&mut self, name: &str) -> Option<Box<Any>> {
        self.map.remove(name).map(|x| x.0)
    }

    /// Retrieves a shared logger, if one has been inserted.
    pub fn get<T: 'static>(&self, name: &str) -> Option<Logger<T, Id>> {
        self.map
            .get(name)
            .and_then(|entry| entry.0.downcast_ref::<Logger<T, Id>>())
            .map(|x| (*x).clone())
    }

    /// Creates a new logger registry.
    pub fn new(time: Instant, id: Id) -> Self {
        Registry {
            id,
            time,
            map: HashMap::new(),
        }
    }

    /// Flushes all registered logs.
    pub fn flush(&mut self) {
        <Self as Flush>::flush(self);
    }
}

impl<Id> Flush for Registry<Id> {
    fn flush(&mut self) {
        for value in self.map.values_mut() {
            value.1.flush();
        }
    }
}

/// A buffering logger.
pub struct Logger<T, E> {
    id:     E,
    time:   Instant,                                                    // common instant used for all loggers.
    action: Rc<RefCell<FnMut(&Duration, &mut Vec<(Duration, E, T)>)>>,  // action to take on full log buffers.
    buffer: Rc<RefCell<Vec<(Duration, E, T)>>>,                         // shared buffer; not obviously best design.
}

impl<T, E: Clone> Clone for Logger<T, E> {
    fn clone(&self) -> Self {
        Logger {
            id: self.id.clone(),
            time: self.time,
            action: self.action.clone(),
            buffer: self.buffer.clone(),
        }
    }
}

impl<T, E: Clone> Logger<T, E> {
    /// Allocates a new shareable logger bound to a write destination.
    pub fn new<F>(time: Instant, id: E, action: F) -> Self
    where
        F: FnMut(&Duration, &mut Vec<(Duration, E, T)>)+'static
    {
        Logger {
            id,
            time,
            action: Rc::new(RefCell::new(action)),
            buffer: Rc::new(RefCell::new(Vec::with_capacity(1024))),
        }
    }

    /// Logs an event.
    ///
    /// The event has its timestamp recorded at the moment of logging, but it may be delayed
    /// due to buffering. It will be written when the logger is next flushed, either due to
    /// the buffer reaching capacity or a direct call to flush.
    ///
    /// This implementation borrows a shared (but thread-local) buffer of log events, to ensure
    /// that the `action` only sees one stream of events with increasing timestamps. This may
    /// have a cost that we don't entirely understand.
    pub fn log<S: Into<T>>(&self, event: S) {
        let mut buffer = self.buffer.borrow_mut();
        buffer.push((self.time.elapsed(), self.id.clone(), event.into()));
        if buffer.len() == buffer.capacity() {
            // Would call `self.flush()`, but for `RefCell` panic.
            let mut action = self.action.borrow_mut();
            let action = &mut *action;
            (*action)(&self.time.elapsed(), &mut *buffer);
            buffer.clear();
        }
    }

    /// Flushes logged messages and communicates the new minimal timestamp.
    pub fn flush(&mut self) {
        <Self as Flush>::flush(self);
    }
}

/// Bit weird, because we only have to flush on the *last* drop, but this should be ok.
impl<T, E> Drop for Logger<T, E> {
    fn drop(&mut self) { self.flush(); }
}

/// Types that can be flushed.
trait Flush {
    /// Flushes buffered data.
    fn flush(&mut self);
}

impl<T, E> Flush for Logger<T, E> {
    fn flush(&mut self) {
        let mut buffer = self.buffer.borrow_mut();
        let mut action = self.action.borrow_mut();
        let action = &mut *action;
        (*action)(&self.time.elapsed(), &mut *buffer);
        buffer.clear();
    }
}<commit_msg>ensure minimum buffer size<commit_after>
use std::rc::Rc;
use std::cell::RefCell;
use std::any::Any;
use std::collections::HashMap;
use std::time::{Instant, Duration};

pub struct Registry<Id> {
    /// A worker-specific identifier.
    id: Id,
    /// A map from names to typed loggers.
    map: HashMap<String, (Box<Any>, Box<Flush>)>,
    /// An instant common to all logging statements.
    time: Instant,
}

impl<Id: Clone+'static> Registry<Id> {
    /// Binds a log name to an action on log event batches.
    ///
    /// This method also returns any pre-installed action, rather than overwriting it
    /// and pivoting the logging destination mid-stream. New loggers with this name will
    /// use the new destination, and existing loggers will use the old destination.
    ///
    /// The action should respond to a sequence of events with non-decreasing timestamps
    /// (Durations) and well as a timestamp that lower bounds the next event that could be
    /// seen (likely greater or equal to the timestamp of the last event). The end of a
    /// logging stream is indicated only by dropping the associated action, which can be
    /// accomplished with `remove` (or a call to insert, though this is not recommended).
    pub fn insert<T: 'static, F: FnMut(&Duration, &mut Vec<(Duration, Id, T)>)+'static>(
        &mut self,
        name: &str,
        action: F) -> Option<Box<Any>>
    {
        let logger = Logger::<T, Id>::new(self.time.clone(), self.id.clone(), action);
        self.map.insert(name.to_owned(), (Box::new(logger.clone()), Box::new(logger))).map(|x| x.0)
    }

    /// Removes a bound logger.
    ///
    /// This is intended primarily to close a logging stream and let the associated writer
    /// communicate that the stream is closed to any consumers. If a binding is not removed,
    /// then the stream cannot be complete as in principle anyone could acquire a handle to
    /// the logger and start further logging.
    pub fn remove(&mut self, name: &str) -> Option<Box<Any>> {
        self.map.remove(name).map(|x| x.0)
    }

    /// Retrieves a shared logger, if one has been inserted.
    pub fn get<T: 'static>(&self, name: &str) -> Option<Logger<T, Id>> {
        self.map
            .get(name)
            .and_then(|entry| entry.0.downcast_ref::<Logger<T, Id>>())
            .map(|x| (*x).clone())
    }

    /// Creates a new logger registry.
    pub fn new(time: Instant, id: Id) -> Self {
        Registry {
            id,
            time,
            map: HashMap::new(),
        }
    }

    /// Flushes all registered logs.
    pub fn flush(&mut self) {
        <Self as Flush>::flush(self);
    }
}

impl<Id> Flush for Registry<Id> {
    fn flush(&mut self) {
        for value in self.map.values_mut() {
            value.1.flush();
        }
    }
}

/// A buffering logger.
pub struct Logger<T, E> {
    id:     E,
    time:   Instant,                                                    // common instant used for all loggers.
    action: Rc<RefCell<FnMut(&Duration, &mut Vec<(Duration, E, T)>)>>,  // action to take on full log buffers.
    buffer: Rc<RefCell<Vec<(Duration, E, T)>>>,                         // shared buffer; not obviously best design.
}

impl<T, E: Clone> Clone for Logger<T, E> {
    fn clone(&self) -> Self {
        Logger {
            id: self.id.clone(),
            time: self.time,
            action: self.action.clone(),
            buffer: self.buffer.clone(),
        }
    }
}

impl<T, E: Clone> Logger<T, E> {
    /// Allocates a new shareable logger bound to a write destination.
    pub fn new<F>(time: Instant, id: E, action: F) -> Self
    where
        F: FnMut(&Duration, &mut Vec<(Duration, E, T)>)+'static
    {
        Logger {
            id,
            time,
            action: Rc::new(RefCell::new(action)),
            buffer: Rc::new(RefCell::new(Vec::with_capacity(1024))),
        }
    }

    /// Logs an event.
    ///
    /// The event has its timestamp recorded at the moment of logging, but it may be delayed
    /// due to buffering. It will be written when the logger is next flushed, either due to
    /// the buffer reaching capacity or a direct call to flush.
    ///
    /// This implementation borrows a shared (but thread-local) buffer of log events, to ensure
    /// that the `action` only sees one stream of events with increasing timestamps. This may
    /// have a cost that we don't entirely understand.
    pub fn log<S: Into<T>>(&self, event: S) {
        let mut buffer = self.buffer.borrow_mut();
        buffer.push((self.time.elapsed(), self.id.clone(), event.into()));
        if buffer.len() == buffer.capacity() {
            // Would call `self.flush()`, but for `RefCell` panic.
            let mut action = self.action.borrow_mut();
            let action = &mut *action;
            (*action)(&self.time.elapsed(), &mut *buffer);
            buffer.clear();
            buffer.reserve(1024);
        }
    }

    /// Flushes logged messages and communicates the new minimal timestamp.
    pub fn flush(&mut self) {
        <Self as Flush>::flush(self);
    }
}

/// Bit weird, because we only have to flush on the *last* drop, but this should be ok.
impl<T, E> Drop for Logger<T, E> {
    fn drop(&mut self) { self.flush(); }
}

/// Types that can be flushed.
trait Flush {
    /// Flushes buffered data.
    fn flush(&mut self);
}

impl<T, E> Flush for Logger<T, E> {
    fn flush(&mut self) {
        let mut buffer = self.buffer.borrow_mut();
        let mut action = self.action.borrow_mut();
        let action = &mut *action;
        (*action)(&self.time.elapsed(), &mut *buffer);
        buffer.clear();
        buffer.reserve(1024);
    }
}<|endoftext|>


<commit_before><commit_msg>Fix indentation before false in tests (#676)<commit_after><|endoftext|>


<commit_before>
//! A 3D camera.

use vecmath::{
    Vector3,
    Matrix4,
    vec3_normalized_sub,
    vec3_cross,
    vec3_dot
};

pub struct Camera {
    pub position: Vector3,
    pub target: Vector3,
    pub right: Vector3,
    pub up: Vector3,
}

pub struct CameraSettings {
    pub fov_rad: f64,
    pub near_clip: f64,
    pub far_clip: f64,
    pub aspect_ratio: f64,
}

impl Camera {
    /// Computes the direction forward.
    ///
    /// Returns the normalized difference between target and position.
    pub fn forward(&self) -> Vector3 {
        vec3_normalized_sub(self.position, self.target)
    }

    /// Computes an orthogonal matrix for the camera.
    ///
    /// This matrix can be used to transform coordinates to the screen.
    pub fn orthogonal(&self) -> Matrix4 {
        let p = self.position;
        let r = self.right;
        let u = self.up;
        let f = self.forward();
        [
            [r[0], u[0], f[0], 0.0],
            [r[1], u[1], f[1], 0.0],
            [r[2], u[2], f[2], 0.0],
            [-vec3_dot(r, p), -vec3_dot(u, p), -vec3_dot(f, p), 1.0]
        ]
    }

    pub fn update_right(&mut self) {
        self.right = vec3_cross(self.up, self.forward());
    }
}

<commit_msg>camera: provide a method to compute a projection matrix.<commit_after>
//! A 3D camera.

use vecmath::{
    Vector3,
    Matrix4,
    vec3_normalized_sub,
    vec3_cross,
    vec3_dot
};

use std::f32::consts::PI;

pub struct Camera {
    pub position: Vector3,
    pub target: Vector3,
    pub right: Vector3,
    pub up: Vector3,
}

pub struct CameraSettings {
    pub fov: f32,
    pub near_clip: f32,
    pub far_clip: f32,
    pub aspect_ratio: f32,
}

impl Camera {
    /// Computes the direction forward.
    ///
    /// Returns the normalized difference between target and position.
    pub fn forward(&self) -> Vector3 {
        vec3_normalized_sub(self.position, self.target)
    }

    /// Computes an orthogonal matrix for the camera.
    ///
    /// This matrix can be used to transform coordinates to the screen.
    pub fn orthogonal(&self) -> Matrix4 {
        let p = self.position;
        let r = self.right;
        let u = self.up;
        let f = self.forward();
        [
            [r[0], u[0], f[0], 0.0],
            [r[1], u[1], f[1], 0.0],
            [r[2], u[2], f[2], 0.0],
            [-vec3_dot(r, p), -vec3_dot(u, p), -vec3_dot(f, p), 1.0]
        ]
    }

    pub fn update_right(&mut self) {
        self.right = vec3_cross(self.up, self.forward());
    }
}

impl CameraSettings {
    /// Computes a projection matrix for the camera settings.
    pub fn projection(&self) -> Matrix4 {
        let f = 1.0 / (self.fov * (PI / 360.0)).tan();
        let (far, near) = (self.far_clip, self.near_clip);
        [
            [f / self.aspect_ratio, 0.0, 0.0, 0.0],
            [0.0, f, 0.0, 0.0],
            [0.0, 0.0, (far + near) / (near - far), -1.0],
            [0.0, 0.0, (2.0 * far * near) / (near - far), 0.0]
        ]
    }
}

<|endoftext|>


<commit_before>use super::interconnect::Interconnect;
use super::interconnect::END_RESERVED;

const INSTRUCTION_SIZE: u16 = 2;

#[derive(Default, Debug)]
pub struct Cpu {
    // Interconnect is used to control system resources like rom and memory.
    interconnect: Interconnect,

    // Program counter.
    pc: u16,

    // The function call stack.
    stack: [u16; 16],

    // Stack pointer.
    sp: u8,

    // General purpose registers v0-vf.
    v0: u8,
    v1: u8,
    v2: u8,
    v3: u8,
    v4: u8,
    v5: u8,
    v6: u8,
    v7: u8,
    v8: u8,
    v9: u8,
    va: u8,
    vb: u8,
    vc: u8,
    vd: u8,
    ve: u8,
    vf: u8,

    // Address register "I".
    i: u16,

    // Timer and sound registers.
    dt: u8,
    st: u8,
}

impl Cpu {
    pub fn new(interconnect: Interconnect) -> Cpu {
        Cpu {
            interconnect: interconnect,
            pc: END_RESERVED as u16,
            ..Cpu::default()
        }
    }

    /// Execute instructions from ram.
    pub fn run(&mut self) {
        loop {
            let word = self.interconnect.read_word(self.pc);

            // Execute until the subroutine ends.
            if self.execute_instruction(word) {
                break
            }
        }
    }

    #[inline(always)]
    fn execute_instruction(&mut self, instr: u16) -> bool {
        let opcode = (instr >> 12) as u8;
        let mut ret: bool = false;

        match opcode {
            0x0 => {
                let identifier = ((instr << 8) >> 8) as u8;

                match identifier {
                    0xE0 => {
                        // 00E0 - CLS
                        // Clears the screen.

                        self.interconnect.clear_display();
                    },
                    0xEE => {
                        // 00EE - RET
                        // Returns from a subroutine.

                        self.sp -= 1;
                        self.pc = self.stack[self.sp as usize];
                        self.stack[self.sp as usize] = 0;

                        // Break out of the execution loop for the current
                        // subroutine.
                        ret = true;
                    },
                    _ => {
                        println!("cpu: {:#?}", self);
                        panic!("Found unknown identifier at instruction: {:#x}, addr: {:#x}", instr, self.pc);
                    },
                }
            },
            0x2 => {
                // 2NNN - CALL NNN
                //
                // Calls subroutine at NNN.

                let addr = ((instr << 4) >> 4) as u16;

                // Add the current program counter to the call stack.
                self.stack[self.sp as usize] = self.pc;
                self.sp += 1;

                // Set the program counter to the call address begin executing
                // the subroutine.
                self.pc = addr;
                self.run();
            },
            0x6 => {
                // 6XNN - LD VX, NN
                //
                // Sets VX to NN.

                let regx = ((instr << 4) >> 12) as u8;
                let byte = ((instr << 8) >> 8) as u8;
                self.set_reg(regx, byte);
            },
            0x7 => {
                // 7XNN - ADD VX, NN
                //
                // Adds NN to VX.

                let regx = ((instr << 4) >> 12) as u8;
                let byte = ((instr << 8) >> 8) as u8;

                let result = self.get_reg(regx) + byte;
                self.set_reg(regx, result);
            },
            0xa => {
                // ANNN - LD I, NNN
                //
                // Sets I to the address NNN.

                let addr = ((instr << 4) >> 4) as u16;
                self.i = addr;
            },
            0xd => {
                // DXYN - DRW VX, VY, N
                //
                // Sprites stored in memory at location in index register (I),
                // 8bits wide. Wraps around the screen. If when drawn, clears a
                // pixel, register VF is set to 1 otherwise it is zero.
                //
                // All drawing is XOR drawing (i.e. it toggles the screen
                // pixels). Sprites are drawn starting at position VX, VY. N is
                // the number of 8bit rows that need to be drawn. If N is
                // greater than 1, second line continues at position VX, VY+1,
                // and so on.

                let regx = ((instr << 4) >> 12) as u8;
                let regy = ((instr << 8) >> 12) as u8;
                let nibble = ((instr << 12) >> 12) as usize;

                // Read N (nibble) bytes out out of memory starting at address
                // register I into our sprite.
                let mut sprite = vec![0 as u8; nibble];
                for i in 0..nibble {
                    sprite[i] = self.interconnect.ram[self.i as usize + i];
                }

                // Get screen coordinates from the requested registers.
                let x = self.get_reg(regx);
                let y = self.get_reg(regy);

                // Draw the sprite and store collision detection results in vf.
                self.vf = self.interconnect.draw(x as usize, y as usize, sprite);
            },
            0xf => {
                let regx = ((instr << 4) >> 12) as u8;
                let identifier = ((instr << 8) >> 8) as u8;

                match identifier {
                    0x29 => {
                        // FX29 - LD F, VX
                        //
                        // Sets I to the location of the sprite for the
                        // character in VX. Characters 0-F (in hexadecimal) are
                        // represented by a 4x5 font.

                        let x: u8 = self.get_reg(regx);
                        self.i = self.interconnect.get_font(x);
                    },
                    0x33 => {
                        // FX33 - LD B, VX
                        //
                        // Stores the Binary-coded decimal representation of VX,
                        // with the most significant of three digits at the
                        // address in I, the middle digit at I plus 1, and the
                        // least significant digit at I plus 2. (In other words,
                        // take the decimal representation of VX, place the
                        // hundreds digit in memory at location in I, the tens
                        // digit at location I+1, and the ones digit at
                        // location I+2.)

                        const DECIMAL_LENGTH: usize = 3;

                        let mut x: u8 = self.get_reg(regx);
                        let mut digits = vec![0 as u8; DECIMAL_LENGTH];
                        let mut digit_count: usize = 0;

                        // Organize the digits in the decimal into a slice.
                        while x > 0 {
                            digit_count += 1;
                            digits[DECIMAL_LENGTH - digit_count] = x % 10;
                            x /= 10;
                        }

                        // Set I, I+1, and I+3 to the values of the digits.
                        let i: usize = self.i as usize;
                        self.interconnect.ram[i] = digits[0];
                        self.interconnect.ram[i + 1] = digits[1];
                        self.interconnect.ram[i + 2] = digits[2];
                    },
                    0x65 => {
                        // FX65 - LD VX, [I]
                        //
                        // Fills V0 to VX with values from memory starting at
                        // address I.

                        let i: usize = self.i as usize;
                        let end_reg = (regx + 1) as usize;

                        for register in 0x0..end_reg {
                            let mem = self.interconnect.ram[i + register];
                            self.set_reg(register as u8, mem);
                        }
                    },
                    _ => {
                        println!("cpu: {:#?}", self);
                        panic!("Found unknown identifier at instruction: {:#x}, addr: {:#x}", instr, self.pc);
                    },
                }
            },
            _ => {
                println!("cpu: {:#?}", self);
                panic!("Found unknown opcode at instruction: {:#x}, addr: {:#x}", instr, self.pc);
            },
        }

        // Increment the program counter to the next instruction.
        self.pc += INSTRUCTION_SIZE;

        // By default the execution loop in not broken. True will be returned
        // only by a successful RET instruction is executed.
        ret
    }

    /// Gets the value at a specified register.
    fn get_reg(&mut self, reg: u8) -> u8 {
        match reg {
            0x0 => self.v0,
            0x1 => self.v1,
            0x2 => self.v2,
            0x3 => self.v3,
            0x4 => self.v4,
            0x5 => self.v5,
            0x6 => self.v6,
            0x7 => self.v7,
            0x8 => self.v8,
            0x9 => self.v9,
            0xa => self.va,
            0xb => self.vb,
            0xc => self.vc,
            0xd => self.vd,
            0xe => self.ve,
            0xf => self.vf,
            _ => {
                panic!("Cannot get unknown register: V{:X}", reg);
            }
        }
    }

    /// Sets the value of a general purpose register.
    fn set_reg(&mut self, reg: u8, byte: u8) {
        match reg {
            0x0 => self.v0 = byte,
            0x1 => self.v1 = byte,
            0x2 => self.v2 = byte,
            0x3 => self.v3 = byte,
            0x4 => self.v4 = byte,
            0x5 => self.v5 = byte,
            0x6 => self.v6 = byte,
            0x7 => self.v7 = byte,
            0x8 => self.v8 = byte,
            0x9 => self.v9 = byte,
            0xa => self.va = byte,
            0xb => self.vb = byte,
            0xc => self.vc = byte,
            0xd => self.vd = byte,
            0xe => self.ve = byte,
            0xf => self.vf = byte,
            _ => {
                panic!("Cannot set unknown register: V{:X}", reg);
            }
        }
    }
}
<commit_msg>Fixed RET where an instruction was skipped<commit_after>use super::interconnect::Interconnect;
use super::interconnect::END_RESERVED;

const INSTRUCTION_SIZE: u16 = 2;

#[derive(Default, Debug)]
pub struct Cpu {
    // Interconnect is used to control system resources like rom and memory.
    interconnect: Interconnect,

    // Program counter.
    pc: u16,

    // The function call stack.
    stack: [u16; 16],

    // Stack pointer.
    sp: u8,

    // General purpose registers v0-vf.
    v0: u8,
    v1: u8,
    v2: u8,
    v3: u8,
    v4: u8,
    v5: u8,
    v6: u8,
    v7: u8,
    v8: u8,
    v9: u8,
    va: u8,
    vb: u8,
    vc: u8,
    vd: u8,
    ve: u8,
    vf: u8,

    // Address register "I".
    i: u16,

    // Timer and sound registers.
    dt: u8,
    st: u8,
}

impl Cpu {
    pub fn new(interconnect: Interconnect) -> Cpu {
        Cpu {
            interconnect: interconnect,
            pc: END_RESERVED as u16,
            ..Cpu::default()
        }
    }

    /// Execute instructions from ram.
    pub fn run(&mut self) {
        loop {
            let word = self.interconnect.read_word(self.pc);

            // Execute until the subroutine ends.
            if self.execute_instruction(word) {
                break
            }
        }
    }

    #[inline(always)]
    fn execute_instruction(&mut self, instr: u16) -> bool {
        let opcode = (instr >> 12) as u8;
        let mut ret: bool = false;

        match opcode {
            0x0 => {
                let identifier = ((instr << 8) >> 8) as u8;

                match identifier {
                    0xE0 => {
                        // 00E0 - CLS
                        // Clears the screen.

                        self.interconnect.clear_display();
                    },
                    0xEE => {
                        // 00EE - RET
                        // Returns from a subroutine.

                        self.sp -= 1;
                        self.pc = self.stack[self.sp as usize];
                        self.stack[self.sp as usize] = 0;

                        // Break out of the execution loop for the current
                        // subroutine.
                        ret = true;
                    },
                    _ => {
                        println!("cpu: {:#?}", self);
                        panic!("Found unknown identifier at instruction: {:#x}, addr: {:#x}", instr, self.pc);
                    },
                }
            },
            0x2 => {
                // 2NNN - CALL NNN
                //
                // Calls subroutine at NNN.

                let addr = ((instr << 4) >> 4) as u16;

                // Add the current program counter to the call stack.
                self.stack[self.sp as usize] = self.pc;
                self.sp += 1;

                // Set the program counter to the call address begin executing
                // the subroutine.
                self.pc = addr;
                self.run();
            },
            0x6 => {
                // 6XNN - LD VX, NN
                //
                // Sets VX to NN.

                let regx = ((instr << 4) >> 12) as u8;
                let byte = ((instr << 8) >> 8) as u8;
                self.set_reg(regx, byte);
            },
            0x7 => {
                // 7XNN - ADD VX, NN
                //
                // Adds NN to VX.

                let regx = ((instr << 4) >> 12) as u8;
                let byte = ((instr << 8) >> 8) as u8;

                let result = self.get_reg(regx) + byte;
                self.set_reg(regx, result);
            },
            0xa => {
                // ANNN - LD I, NNN
                //
                // Sets I to the address NNN.

                let addr = ((instr << 4) >> 4) as u16;
                self.i = addr;
            },
            0xd => {
                // DXYN - DRW VX, VY, N
                //
                // Sprites stored in memory at location in index register (I),
                // 8bits wide. Wraps around the screen. If when drawn, clears a
                // pixel, register VF is set to 1 otherwise it is zero.
                //
                // All drawing is XOR drawing (i.e. it toggles the screen
                // pixels). Sprites are drawn starting at position VX, VY. N is
                // the number of 8bit rows that need to be drawn. If N is
                // greater than 1, second line continues at position VX, VY+1,
                // and so on.

                let regx = ((instr << 4) >> 12) as u8;
                let regy = ((instr << 8) >> 12) as u8;
                let nibble = ((instr << 12) >> 12) as usize;

                // Read N (nibble) bytes out out of memory starting at address
                // register I into our sprite.
                let mut sprite = vec![0 as u8; nibble];
                for i in 0..nibble {
                    sprite[i] = self.interconnect.ram[self.i as usize + i];
                }

                // Get screen coordinates from the requested registers.
                let x = self.get_reg(regx);
                let y = self.get_reg(regy);

                // Draw the sprite and store collision detection results in vf.
                self.vf = self.interconnect.draw(x as usize, y as usize, sprite);
            },
            0xf => {
                let regx = ((instr << 4) >> 12) as u8;
                let identifier = ((instr << 8) >> 8) as u8;

                match identifier {
                    0x29 => {
                        // FX29 - LD F, VX
                        //
                        // Sets I to the location of the sprite for the
                        // character in VX. Characters 0-F (in hexadecimal) are
                        // represented by a 4x5 font.

                        let x: u8 = self.get_reg(regx);
                        self.i = self.interconnect.get_font(x);
                    },
                    0x33 => {
                        // FX33 - LD B, VX
                        //
                        // Stores the Binary-coded decimal representation of VX,
                        // with the most significant of three digits at the
                        // address in I, the middle digit at I plus 1, and the
                        // least significant digit at I plus 2. (In other words,
                        // take the decimal representation of VX, place the
                        // hundreds digit in memory at location in I, the tens
                        // digit at location I+1, and the ones digit at
                        // location I+2.)

                        const DECIMAL_LENGTH: usize = 3;

                        let mut x: u8 = self.get_reg(regx);
                        let mut digits = vec![0 as u8; DECIMAL_LENGTH];
                        let mut digit_count: usize = 0;

                        // Organize the digits in the decimal into a slice.
                        while x > 0 {
                            digit_count += 1;
                            digits[DECIMAL_LENGTH - digit_count] = x % 10;
                            x /= 10;
                        }

                        // Set I, I+1, and I+3 to the values of the digits.
                        let i: usize = self.i as usize;
                        self.interconnect.ram[i] = digits[0];
                        self.interconnect.ram[i + 1] = digits[1];
                        self.interconnect.ram[i + 2] = digits[2];
                    },
                    0x65 => {
                        // FX65 - LD VX, [I]
                        //
                        // Fills V0 to VX with values from memory starting at
                        // address I.

                        let i: usize = self.i as usize;
                        let end_reg = (regx + 1) as usize;

                        for register in 0x0..end_reg {
                            let mem = self.interconnect.ram[i + register];
                            self.set_reg(register as u8, mem);
                        }
                    },
                    _ => {
                        println!("cpu: {:#?}", self);
                        panic!("Found unknown identifier at instruction: {:#x}, addr: {:#x}", instr, self.pc);
                    },
                }
            },
            _ => {
                println!("cpu: {:#?}", self);
                panic!("Found unknown opcode at instruction: {:#x}, addr: {:#x}", instr, self.pc);
            },
        }

        // Increment the program counter to the next instruction.
        if !ret {
            self.pc += INSTRUCTION_SIZE;
        }

        // By default the execution loop in not broken. True will be returned
        // only by a successful RET instruction is executed.
        ret
    }

    /// Gets the value at a specified register.
    fn get_reg(&mut self, reg: u8) -> u8 {
        match reg {
            0x0 => self.v0,
            0x1 => self.v1,
            0x2 => self.v2,
            0x3 => self.v3,
            0x4 => self.v4,
            0x5 => self.v5,
            0x6 => self.v6,
            0x7 => self.v7,
            0x8 => self.v8,
            0x9 => self.v9,
            0xa => self.va,
            0xb => self.vb,
            0xc => self.vc,
            0xd => self.vd,
            0xe => self.ve,
            0xf => self.vf,
            _ => {
                panic!("Cannot get unknown register: V{:X}", reg);
            }
        }
    }

    /// Sets the value of a general purpose register.
    fn set_reg(&mut self, reg: u8, byte: u8) {
        match reg {
            0x0 => self.v0 = byte,
            0x1 => self.v1 = byte,
            0x2 => self.v2 = byte,
            0x3 => self.v3 = byte,
            0x4 => self.v4 = byte,
            0x5 => self.v5 = byte,
            0x6 => self.v6 = byte,
            0x7 => self.v7 = byte,
            0x8 => self.v8 = byte,
            0x9 => self.v9 = byte,
            0xa => self.va = byte,
            0xb => self.vb = byte,
            0xc => self.vc = byte,
            0xd => self.vd = byte,
            0xe => self.ve = byte,
            0xf => self.vf = byte,
            _ => {
                panic!("Cannot set unknown register: V{:X}", reg);
            }
        }
    }
}
<|endoftext|>