<commit_before>// Copyright 2017 Pants project contributors (see CONTRIBUTORS.md).
// Licensed under the Apache License, Version 2.0 (see LICENSE).

#![deny(warnings)]
// Enable all clippy lints except for many of the pedantic ones. It's a shame this needs to be copied and pasted across crates, but there doesn't appear to be a way to include inner attributes from a common source.
#![deny(
  clippy::all,
  clippy::default_trait_access,
  clippy::expl_impl_clone_on_copy,
  clippy::if_not_else,
  clippy::needless_continue,
  clippy::unseparated_literal_suffix,
  clippy::used_underscore_binding
)]
// It is often more clear to show that nothing is being moved.
#![allow(clippy::match_ref_pats)]
// Subjective style.
#![allow(
  clippy::len_without_is_empty,
  clippy::redundant_field_names,
  clippy::too_many_arguments
)]
// Default isn't as big a deal as people seem to think it is.
#![allow(clippy::new_without_default, clippy::new_ret_no_self)]
// Arc<Mutex> can be more clear than needing to grok Orderings:
#![allow(clippy::mutex_atomic)]

#[macro_use]
extern crate derivative;

use boxfuture::{BoxFuture, Boxable};
use bytes::Bytes;
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, BTreeSet};
use std::convert::TryFrom;
use std::ops::AddAssign;
use std::path::{Component, Path, PathBuf};
use std::sync::Arc;
use std::time::Duration;
use store::UploadSummary;
use workunit_store::WorkUnitStore;

use futures::compat::Future01CompatExt;
use futures::future::{FutureExt, TryFutureExt};

use async_semaphore::AsyncSemaphore;
use hashing::Digest;

pub mod cache;
#[cfg(test)]
mod cache_tests;

pub mod local;
#[cfg(test)]
mod local_tests;

pub mod remote;
#[cfg(test)]
pub mod remote_tests;

pub mod speculate;
#[cfg(test)]
mod speculate_tests;

pub mod nailgun;

extern crate uname;

#[derive(PartialOrd, Ord, Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum Platform {
  Darwin,
  Linux,
}

impl Platform {
  pub fn current() -> Result<Platform, String> {
    let platform_info =
      uname::uname().map_err(|_| "Failed to get local platform info!".to_string())?;

    match platform_info {
      uname::Info { ref sysname, .. } if sysname.to_lowercase() == "darwin" => Ok(Platform::Darwin),
      uname::Info { ref sysname, .. } if sysname.to_lowercase() == "linux" => Ok(Platform::Linux),
      uname::Info { ref sysname, .. } => Err(format!("Found unknown system name {}", sysname)),
    }
  }
}

#[derive(PartialOrd, Ord, Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum PlatformConstraint {
  Darwin,
  Linux,
  None,
}

impl PlatformConstraint {
  pub fn current_platform_constraint() -> Result<PlatformConstraint, String> {
    Platform::current().map(|p: Platform| p.into())
  }
}

impl From<Platform> for PlatformConstraint {
  fn from(platform: Platform) -> PlatformConstraint {
    match platform {
      Platform::Linux => PlatformConstraint::Linux,
      Platform::Darwin => PlatformConstraint::Darwin,
    }
  }
}

impl TryFrom<&String> for PlatformConstraint {
  type Error = String;
  ///
  /// This is a helper method to convert values from the python/engine/platform.py::PlatformConstraint enum,
  /// which have been serialized, into the rust PlatformConstraint enum.
  ///
  fn try_from(variant_candidate: &String) -> Result<Self, Self::Error> {
    match variant_candidate.as_ref() {
      "darwin" => Ok(PlatformConstraint::Darwin),
      "linux" => Ok(PlatformConstraint::Linux),
      "none" => Ok(PlatformConstraint::None),
      other => Err(format!(
        "Unknown, platform {:?} encountered in parsing",
        other
      )),
    }
  }
}

impl From<Platform> for String {
  fn from(platform: Platform) -> String {
    match platform {
      Platform::Linux => "linux".to_string(),
      Platform::Darwin => "darwin".to_string(),
    }
  }
}

impl From<PlatformConstraint> for String {
  fn from(platform: PlatformConstraint) -> String {
    match platform {
      PlatformConstraint::Linux => "linux".to_string(),
      PlatformConstraint::Darwin => "darwin".to_string(),
      PlatformConstraint::None => "none".to_string(),
    }
  }
}

#[derive(Derivative, Clone, Debug, Eq)]
#[derivative(PartialEq, Hash)]
pub struct RelativePath(PathBuf);

impl RelativePath {
  pub fn new<P: AsRef<Path>>(path: P) -> Result<RelativePath, String> {
    let mut relative_path = PathBuf::new();
    let candidate = path.as_ref();
    for component in candidate.components() {
      match component {
        Component::Prefix(_) => {
          return Err(format!("Windows paths are not allowed: {:?}", candidate))
        }
        Component::RootDir => {
          return Err(format!("Absolute paths are not allowed: {:?}", candidate))
        }
        Component::CurDir => continue,
        Component::ParentDir => {
          if !relative_path.pop() {
            return Err(format!(
              "Relative paths that escape the root are not allowed: {:?}",
              candidate
            ));
          }
        }
        Component::Normal(path) => relative_path.push(path),
      }
    }
    Ok(RelativePath(relative_path))
  }

  pub fn to_str(&self) -> Option<&str> {
    self.0.to_str()
  }
}

impl AsRef<Path> for RelativePath {
  fn as_ref(&self) -> &Path {
    self.0.as_path()
  }
}

///
/// A process to be executed.
///
#[derive(Derivative, Clone, Debug, Eq)]
#[derivative(PartialEq, Hash)]
pub struct Process {
  ///
  /// The arguments to execute.
  ///
  /// The first argument should be an absolute or relative path to the binary to execute.
  ///
  /// No PATH lookup will be performed unless a PATH environment variable is specified.
  ///
  /// No shell expansion will take place.
  ///
  pub argv: Vec<String>,
  ///
  /// The environment variables to set for the execution.
  ///
  /// No other environment variables will be set (except possibly for an empty PATH variable).
  ///
  pub env: BTreeMap<String, String>,

  ///
  /// A relative path to a directory existing in the `input_files` digest to execute the process
  /// from. Defaults to the `input_files` root.
  ///
  pub working_directory: Option<RelativePath>,

  pub input_files: hashing::Digest,

  pub output_files: BTreeSet<PathBuf>,

  pub output_directories: BTreeSet<PathBuf>,

  pub timeout: std::time::Duration,

  #[derivative(PartialEq = "ignore", Hash = "ignore")]
  pub description: String,

  // This will be materialized for local Process only.
  // Eventually we want to remove this.
  // Context: https://github.com/pantsbuild/pants/issues/8314
  // Think twice before using it.
  #[derivative(PartialEq = "ignore", Hash = "ignore")]
  pub unsafe_local_only_files_because_we_favor_speed_over_correctness_for_this_rule:
    hashing::Digest,
  ///
  /// If present, a symlink will be created at .jdk which points to this directory for local
  /// execution, or a system-installed JDK (ignoring the value of the present Some) for remote
  /// execution.
  ///
  /// This is some technical debt we should clean up;
  /// see https://github.com/pantsbuild/pants/issues/6416.
  ///
  pub jdk_home: Option<PathBuf>,
  pub target_platform: PlatformConstraint,

  pub is_nailgunnable: bool,
}

impl TryFrom<MultiPlatformProcess> for Process {
  type Error = String;

  fn try_from(req: MultiPlatformProcess) -> Result<Self, Self::Error> {
    match req
      .0
      .get(&(PlatformConstraint::None, PlatformConstraint::None))
    {
      Some(crossplatform_req) => Ok(crossplatform_req.clone()),
      None => Err(String::from(
        "Cannot coerce to a simple Process, no cross platform request exists.",
      )),
    }
  }
}

///
/// A container of platform constrained processes.
///
#[derive(Derivative, Clone, Debug, Eq, PartialEq, Hash)]
pub struct MultiPlatformProcess(pub BTreeMap<(PlatformConstraint, PlatformConstraint), Process>);

impl MultiPlatformProcess {
  pub fn user_facing_name(&self) -> Option<String> {
    self
      .0
      .iter()
      .next()
      .map(|(_platforms, epr)| format!("Executing process: {}", epr.description))
  }
}

impl From<Process> for MultiPlatformProcess {
  fn from(req: Process) -> Self {
    MultiPlatformProcess(
      vec![((PlatformConstraint::None, PlatformConstraint::None), req)]
        .into_iter()
        .collect(),
    )
  }
}

///
/// Metadata surrounding an Process which factors into its cache key when cached
/// externally from the engine graph (e.g. when using remote execution or an external process
/// cache).
///
#[derive(Clone, Debug)]
pub struct ProcessMetadata {
  pub instance_name: Option<String>,
  pub cache_key_gen_version: Option<String>,
  pub platform_properties: Vec<(String, String)>,
}

///
/// The result of running a process.
///
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FallibleProcessResultWithPlatform {
  pub stdout: Bytes,
  pub stderr: Bytes,
  pub exit_code: i32,
  pub platform: Platform,

  // It's unclear whether this should be a Snapshot or a digest of a Directory. A Directory digest
  // is handy, so let's try that out for now.
  pub output_directory: hashing::Digest,

  pub execution_attempts: Vec<ExecutionStats>,
}

#[cfg(test)]
impl FallibleProcessResultWithPlatform {
  pub fn without_execution_attempts(mut self) -> Self {
    self.execution_attempts = vec![];
    self
  }
}

#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct ExecutionStats {
  uploaded_bytes: usize,
  uploaded_file_count: usize,
  upload: Duration,
  remote_queue: Option<Duration>,
  remote_input_fetch: Option<Duration>,
  remote_execution: Option<Duration>,
  remote_output_store: Option<Duration>,
  was_cache_hit: bool,
}

impl AddAssign<UploadSummary> for ExecutionStats {
  fn add_assign(&mut self, summary: UploadSummary) {
    self.uploaded_file_count += summary.uploaded_file_count;
    self.uploaded_bytes += summary.uploaded_file_bytes;
    self.upload += summary.upload_wall_time;
  }
}

#[derive(Clone, Default)]
pub struct Context {
  pub workunit_store: WorkUnitStore,
  pub build_id: String,
}

pub trait CommandRunner: Send + Sync {
  ///
  /// Submit a request for execution on the underlying runtime, and return
  /// a future for it.
  ///
  fn run(
    &self,
    req: MultiPlatformProcess,
    context: Context,
  ) -> BoxFuture<FallibleProcessResultWithPlatform, String>;

  ///
  /// Given a multi platform request which may have some platform
  /// constraints determine if any of the requests contained within are compatible
  /// with the current command runners platform configuration. If so return the
  /// first candidate that will be run if the multi platform request is submitted to
  /// `fn run(..)`
  fn extract_compatible_request(&self, req: &MultiPlatformProcess) -> Option<Process>;

  fn num_waiters(&self) -> usize {
    panic!("This method is abstract and not implemented for this type")
  }
}

// TODO(#8513) possibly move to the MEPR struct, or to the hashing crate?
pub fn digest(req: MultiPlatformProcess, metadata: &ProcessMetadata) -> Digest {
  let mut hashes: Vec<String> = req
    .0
    .values()
    .map(|ref epr| crate::remote::make_execute_request(epr, metadata.clone()).unwrap())
    .map(|(_a, _b, er)| er.get_action_digest().get_hash().to_string())
    .collect();
  hashes.sort();
  Digest::of_bytes(
    hashes
      .iter()
      .fold(String::new(), |mut acc, hash| {
        acc.push_str(&hash);
        acc
      })
      .as_bytes(),
  )
}

///
/// A CommandRunner wrapper that limits the number of concurrent requests.
///
#[derive(Clone)]
pub struct BoundedCommandRunner {
  inner: Arc<(Box<dyn CommandRunner>, AsyncSemaphore)>,
}

impl BoundedCommandRunner {
  pub fn new(inner: Box<dyn CommandRunner>, bound: usize) -> BoundedCommandRunner {
    BoundedCommandRunner {
      inner: Arc::new((inner, AsyncSemaphore::new(bound))),
    }
  }
}

impl CommandRunner for BoundedCommandRunner {
  fn num_waiters(&self) -> usize {
    self.inner.1.num_waiters()
  }

  fn run(
    &self,
    req: MultiPlatformProcess,
    context: Context,
  ) -> BoxFuture<FallibleProcessResultWithPlatform, String> {
    let inner = self.inner.clone();
    self
      .inner
      .1
      .clone()
      .with_acquired(move || inner.0.run(req, context).compat())
      .boxed()
      .compat()
      .to_boxed()
  }

  fn extract_compatible_request(&self, req: &MultiPlatformProcess) -> Option<Process> {
    self.inner.0.extract_compatible_request(&req)
  }
}

impl From<Box<BoundedCommandRunner>> for Arc<dyn CommandRunner> {
  fn from(command_runner: Box<BoundedCommandRunner>) -> Arc<dyn CommandRunner> {
    Arc::new(*command_runner)
  }
}

#[cfg(test)]
mod tests;
<commit_msg>Remove "Executing process" text from V2 UI (#9568)<commit_after>// Copyright 2017 Pants project contributors (see CONTRIBUTORS.md).
// Licensed under the Apache License, Version 2.0 (see LICENSE).

#![deny(warnings)]
// Enable all clippy lints except for many of the pedantic ones. It's a shame this needs to be copied and pasted across crates, but there doesn't appear to be a way to include inner attributes from a common source.
#![deny(
  clippy::all,
  clippy::default_trait_access,
  clippy::expl_impl_clone_on_copy,
  clippy::if_not_else,
  clippy::needless_continue,
  clippy::unseparated_literal_suffix,
  clippy::used_underscore_binding
)]
// It is often more clear to show that nothing is being moved.
#![allow(clippy::match_ref_pats)]
// Subjective style.
#![allow(
  clippy::len_without_is_empty,
  clippy::redundant_field_names,
  clippy::too_many_arguments
)]
// Default isn't as big a deal as people seem to think it is.
#![allow(clippy::new_without_default, clippy::new_ret_no_self)]
// Arc<Mutex> can be more clear than needing to grok Orderings:
#![allow(clippy::mutex_atomic)]

#[macro_use]
extern crate derivative;

use boxfuture::{BoxFuture, Boxable};
use bytes::Bytes;
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, BTreeSet};
use std::convert::TryFrom;
use std::ops::AddAssign;
use std::path::{Component, Path, PathBuf};
use std::sync::Arc;
use std::time::Duration;
use store::UploadSummary;
use workunit_store::WorkUnitStore;

use futures::compat::Future01CompatExt;
use futures::future::{FutureExt, TryFutureExt};

use async_semaphore::AsyncSemaphore;
use hashing::Digest;

pub mod cache;
#[cfg(test)]
mod cache_tests;

pub mod local;
#[cfg(test)]
mod local_tests;

pub mod remote;
#[cfg(test)]
pub mod remote_tests;

pub mod speculate;
#[cfg(test)]
mod speculate_tests;

pub mod nailgun;

extern crate uname;

#[derive(PartialOrd, Ord, Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum Platform {
  Darwin,
  Linux,
}

impl Platform {
  pub fn current() -> Result<Platform, String> {
    let platform_info =
      uname::uname().map_err(|_| "Failed to get local platform info!".to_string())?;

    match platform_info {
      uname::Info { ref sysname, .. } if sysname.to_lowercase() == "darwin" => Ok(Platform::Darwin),
      uname::Info { ref sysname, .. } if sysname.to_lowercase() == "linux" => Ok(Platform::Linux),
      uname::Info { ref sysname, .. } => Err(format!("Found unknown system name {}", sysname)),
    }
  }
}

#[derive(PartialOrd, Ord, Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum PlatformConstraint {
  Darwin,
  Linux,
  None,
}

impl PlatformConstraint {
  pub fn current_platform_constraint() -> Result<PlatformConstraint, String> {
    Platform::current().map(|p: Platform| p.into())
  }
}

impl From<Platform> for PlatformConstraint {
  fn from(platform: Platform) -> PlatformConstraint {
    match platform {
      Platform::Linux => PlatformConstraint::Linux,
      Platform::Darwin => PlatformConstraint::Darwin,
    }
  }
}

impl TryFrom<&String> for PlatformConstraint {
  type Error = String;
  ///
  /// This is a helper method to convert values from the python/engine/platform.py::PlatformConstraint enum,
  /// which have been serialized, into the rust PlatformConstraint enum.
  ///
  fn try_from(variant_candidate: &String) -> Result<Self, Self::Error> {
    match variant_candidate.as_ref() {
      "darwin" => Ok(PlatformConstraint::Darwin),
      "linux" => Ok(PlatformConstraint::Linux),
      "none" => Ok(PlatformConstraint::None),
      other => Err(format!(
        "Unknown, platform {:?} encountered in parsing",
        other
      )),
    }
  }
}

impl From<Platform> for String {
  fn from(platform: Platform) -> String {
    match platform {
      Platform::Linux => "linux".to_string(),
      Platform::Darwin => "darwin".to_string(),
    }
  }
}

impl From<PlatformConstraint> for String {
  fn from(platform: PlatformConstraint) -> String {
    match platform {
      PlatformConstraint::Linux => "linux".to_string(),
      PlatformConstraint::Darwin => "darwin".to_string(),
      PlatformConstraint::None => "none".to_string(),
    }
  }
}

#[derive(Derivative, Clone, Debug, Eq)]
#[derivative(PartialEq, Hash)]
pub struct RelativePath(PathBuf);

impl RelativePath {
  pub fn new<P: AsRef<Path>>(path: P) -> Result<RelativePath, String> {
    let mut relative_path = PathBuf::new();
    let candidate = path.as_ref();
    for component in candidate.components() {
      match component {
        Component::Prefix(_) => {
          return Err(format!("Windows paths are not allowed: {:?}", candidate))
        }
        Component::RootDir => {
          return Err(format!("Absolute paths are not allowed: {:?}", candidate))
        }
        Component::CurDir => continue,
        Component::ParentDir => {
          if !relative_path.pop() {
            return Err(format!(
              "Relative paths that escape the root are not allowed: {:?}",
              candidate
            ));
          }
        }
        Component::Normal(path) => relative_path.push(path),
      }
    }
    Ok(RelativePath(relative_path))
  }

  pub fn to_str(&self) -> Option<&str> {
    self.0.to_str()
  }
}

impl AsRef<Path> for RelativePath {
  fn as_ref(&self) -> &Path {
    self.0.as_path()
  }
}

///
/// A process to be executed.
///
#[derive(Derivative, Clone, Debug, Eq)]
#[derivative(PartialEq, Hash)]
pub struct Process {
  ///
  /// The arguments to execute.
  ///
  /// The first argument should be an absolute or relative path to the binary to execute.
  ///
  /// No PATH lookup will be performed unless a PATH environment variable is specified.
  ///
  /// No shell expansion will take place.
  ///
  pub argv: Vec<String>,
  ///
  /// The environment variables to set for the execution.
  ///
  /// No other environment variables will be set (except possibly for an empty PATH variable).
  ///
  pub env: BTreeMap<String, String>,

  ///
  /// A relative path to a directory existing in the `input_files` digest to execute the process
  /// from. Defaults to the `input_files` root.
  ///
  pub working_directory: Option<RelativePath>,

  pub input_files: hashing::Digest,

  pub output_files: BTreeSet<PathBuf>,

  pub output_directories: BTreeSet<PathBuf>,

  pub timeout: std::time::Duration,

  #[derivative(PartialEq = "ignore", Hash = "ignore")]
  pub description: String,

  // This will be materialized for local Process only.
  // Eventually we want to remove this.
  // Context: https://github.com/pantsbuild/pants/issues/8314
  // Think twice before using it.
  #[derivative(PartialEq = "ignore", Hash = "ignore")]
  pub unsafe_local_only_files_because_we_favor_speed_over_correctness_for_this_rule:
    hashing::Digest,
  ///
  /// If present, a symlink will be created at .jdk which points to this directory for local
  /// execution, or a system-installed JDK (ignoring the value of the present Some) for remote
  /// execution.
  ///
  /// This is some technical debt we should clean up;
  /// see https://github.com/pantsbuild/pants/issues/6416.
  ///
  pub jdk_home: Option<PathBuf>,
  pub target_platform: PlatformConstraint,

  pub is_nailgunnable: bool,
}

impl TryFrom<MultiPlatformProcess> for Process {
  type Error = String;

  fn try_from(req: MultiPlatformProcess) -> Result<Self, Self::Error> {
    match req
      .0
      .get(&(PlatformConstraint::None, PlatformConstraint::None))
    {
      Some(crossplatform_req) => Ok(crossplatform_req.clone()),
      None => Err(String::from(
        "Cannot coerce to a simple Process, no cross platform request exists.",
      )),
    }
  }
}

///
/// A container of platform constrained processes.
///
#[derive(Derivative, Clone, Debug, Eq, PartialEq, Hash)]
pub struct MultiPlatformProcess(pub BTreeMap<(PlatformConstraint, PlatformConstraint), Process>);

impl MultiPlatformProcess {
  pub fn user_facing_name(&self) -> Option<String> {
    self
      .0
      .iter()
      .next()
      .map(|(_platforms, epr)| epr.description.clone())
  }
}

impl From<Process> for MultiPlatformProcess {
  fn from(req: Process) -> Self {
    MultiPlatformProcess(
      vec![((PlatformConstraint::None, PlatformConstraint::None), req)]
        .into_iter()
        .collect(),
    )
  }
}

///
/// Metadata surrounding an Process which factors into its cache key when cached
/// externally from the engine graph (e.g. when using remote execution or an external process
/// cache).
///
#[derive(Clone, Debug)]
pub struct ProcessMetadata {
  pub instance_name: Option<String>,
  pub cache_key_gen_version: Option<String>,
  pub platform_properties: Vec<(String, String)>,
}

///
/// The result of running a process.
///
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FallibleProcessResultWithPlatform {
  pub stdout: Bytes,
  pub stderr: Bytes,
  pub exit_code: i32,
  pub platform: Platform,

  // It's unclear whether this should be a Snapshot or a digest of a Directory. A Directory digest
  // is handy, so let's try that out for now.
  pub output_directory: hashing::Digest,

  pub execution_attempts: Vec<ExecutionStats>,
}

#[cfg(test)]
impl FallibleProcessResultWithPlatform {
  pub fn without_execution_attempts(mut self) -> Self {
    self.execution_attempts = vec![];
    self
  }
}

#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct ExecutionStats {
  uploaded_bytes: usize,
  uploaded_file_count: usize,
  upload: Duration,
  remote_queue: Option<Duration>,
  remote_input_fetch: Option<Duration>,
  remote_execution: Option<Duration>,
  remote_output_store: Option<Duration>,
  was_cache_hit: bool,
}

impl AddAssign<UploadSummary> for ExecutionStats {
  fn add_assign(&mut self, summary: UploadSummary) {
    self.uploaded_file_count += summary.uploaded_file_count;
    self.uploaded_bytes += summary.uploaded_file_bytes;
    self.upload += summary.upload_wall_time;
  }
}

#[derive(Clone, Default)]
pub struct Context {
  pub workunit_store: WorkUnitStore,
  pub build_id: String,
}

pub trait CommandRunner: Send + Sync {
  ///
  /// Submit a request for execution on the underlying runtime, and return
  /// a future for it.
  ///
  fn run(
    &self,
    req: MultiPlatformProcess,
    context: Context,
  ) -> BoxFuture<FallibleProcessResultWithPlatform, String>;

  ///
  /// Given a multi platform request which may have some platform
  /// constraints determine if any of the requests contained within are compatible
  /// with the current command runners platform configuration. If so return the
  /// first candidate that will be run if the multi platform request is submitted to
  /// `fn run(..)`
  fn extract_compatible_request(&self, req: &MultiPlatformProcess) -> Option<Process>;

  fn num_waiters(&self) -> usize {
    panic!("This method is abstract and not implemented for this type")
  }
}

// TODO(#8513) possibly move to the MEPR struct, or to the hashing crate?
pub fn digest(req: MultiPlatformProcess, metadata: &ProcessMetadata) -> Digest {
  let mut hashes: Vec<String> = req
    .0
    .values()
    .map(|ref epr| crate::remote::make_execute_request(epr, metadata.clone()).unwrap())
    .map(|(_a, _b, er)| er.get_action_digest().get_hash().to_string())
    .collect();
  hashes.sort();
  Digest::of_bytes(
    hashes
      .iter()
      .fold(String::new(), |mut acc, hash| {
        acc.push_str(&hash);
        acc
      })
      .as_bytes(),
  )
}

///
/// A CommandRunner wrapper that limits the number of concurrent requests.
///
#[derive(Clone)]
pub struct BoundedCommandRunner {
  inner: Arc<(Box<dyn CommandRunner>, AsyncSemaphore)>,
}

impl BoundedCommandRunner {
  pub fn new(inner: Box<dyn CommandRunner>, bound: usize) -> BoundedCommandRunner {
    BoundedCommandRunner {
      inner: Arc::new((inner, AsyncSemaphore::new(bound))),
    }
  }
}

impl CommandRunner for BoundedCommandRunner {
  fn num_waiters(&self) -> usize {
    self.inner.1.num_waiters()
  }

  fn run(
    &self,
    req: MultiPlatformProcess,
    context: Context,
  ) -> BoxFuture<FallibleProcessResultWithPlatform, String> {
    let inner = self.inner.clone();
    self
      .inner
      .1
      .clone()
      .with_acquired(move || inner.0.run(req, context).compat())
      .boxed()
      .compat()
      .to_boxed()
  }

  fn extract_compatible_request(&self, req: &MultiPlatformProcess) -> Option<Process> {
    self.inner.0.extract_compatible_request(&req)
  }
}

impl From<Box<BoundedCommandRunner>> for Arc<dyn CommandRunner> {
  fn from(command_runner: Box<BoundedCommandRunner>) -> Arc<dyn CommandRunner> {
    Arc::new(*command_runner)
  }
}

#[cfg(test)]
mod tests;
<|endoftext|>


<commit_before>/*
 * An example redis server accepting GET and SET requests
 * listening on 127.0.0.1:8000.
 *
 * You can test it with "redis-cli -p 8000".
 *
 * Copyright (c) 2014 by Michael Neumann
 *
 */

extern crate redis = "redis#0.1";
extern crate sync = "sync#0.10-pre";

use std::io::net::ip::SocketAddr;
use std::io::net::tcp::{TcpListener,TcpStream};
use std::io::{Listener,Acceptor,Writer};
use std::io::BufferedStream;
use std::task;
use std::hashmap::HashMap;
use sync::RWArc;

fn handle_connection(conn: TcpStream, shared_ht: RWArc<HashMap<~[u8],~[u8]>>) {
    debug!("Got connection");

    let mut io = BufferedStream::new(conn);

    loop {
        match redis::parse(&mut io).unwrap() {
            redis::List(ref lst) => {
                match lst.get(0) {
                    Some(redis::Data(ref command)) {
                        if command == bytes!("GET") {
                            match (lst.len(), lst.get(1)) {
                                (2, Some(redis::Data(key)))  => {
                                    debug!("GET: {:s}", std::str::from_utf8(key).unwrap());
                                    let mut cwr = redis::CommandWriter::new();
                                    shared_ht.read(|ht| {
                                        match ht.find(&key) {
                                            Some(val) => {
                                                cwr.args(1);
                                                cwr.arg_bin(*val);
                                            }
                                            None => {
                                                cwr.nil();
                                            }
                                        }
                                    });
                                    cwr.with_buf(|bytes| {io.write(bytes); io.flush()});
                                    continue;
                                }
                                _ => { /* fallthrough: error */ }
                            }
                        }
                        else if command == bytes!("SET") {
                            match (lst.len(), lst.get(1), lst.get(2)) {
                                (3, redis::Data(key), redis::Data(val)) => {
                                    debug!("SET: {:s} {:?}", std::str::from_utf8(key).unwrap(), val);
                                    shared_ht.write(|ht| ht.insert(key.clone(), val.clone()));
                                    let mut cwr = redis::CommandWriter::new();
                                    cwr.status("OK");
                                    cwr.with_buf(|bytes| {io.write(bytes); io.flush()});
                                    continue;
                                }
                                _ => { /* fallthrough: error */ }
                            }
                        }
                        else {
                            /* fallthrough: error */
                        }
                    }
                    _ => { /* fallthrough: error */ }
                }
            }
            _ => { /* fallthrough: error */ }
        }

        /* error */
        let mut cwr = redis::CommandWriter::new();
        cwr.error("Invalid Command");
        cwr.with_buf(|bytes| {io.write(bytes); io.flush()});
    }
}

fn main() {
    let addr: SocketAddr = from_str("127.0.0.1:8000").unwrap();
    let shared_ht = RWArc::new(HashMap::new());

    match TcpListener::bind(addr) {
        Ok(listener) => {
            match listener.listen() {
                Ok(ref mut acceptor) => {
                    loop {
                        match acceptor.accept() {
                            Ok(conn) => {
                                let ht = shared_ht.clone();
                                task::spawn(proc() {
                                    handle_connection(conn, ht)
                                });
                            }
                            Err(_) => {}
                        }
                    }
                }
                Err(_) => {}
            }
        }
        Err(_) => {}
    }
}
<commit_msg>Fix typo<commit_after>/*
 * An example redis server accepting GET and SET requests
 * listening on 127.0.0.1:8000.
 *
 * You can test it with "redis-cli -p 8000".
 *
 * Copyright (c) 2014 by Michael Neumann
 *
 */

extern crate redis = "redis#0.1";
extern crate sync = "sync#0.10-pre";

use std::io::net::ip::SocketAddr;
use std::io::net::tcp::{TcpListener,TcpStream};
use std::io::{Listener,Acceptor,Writer};
use std::io::BufferedStream;
use std::task;
use std::hashmap::HashMap;
use sync::RWArc;

fn handle_connection(conn: TcpStream, shared_ht: RWArc<HashMap<~[u8],~[u8]>>) {
    debug!("Got connection");

    let mut io = BufferedStream::new(conn);

    loop {
        match redis::parse(&mut io).unwrap() {
            redis::List(ref lst) => {
                match lst.get(0) {
                    Some(redis::Data(ref command)) => {
                        if command == bytes!("GET") {
                            match (lst.len(), lst.get(1)) {
                                (2, Some(redis::Data(key))) => {
                                    debug!("GET: {:s}", std::str::from_utf8(key).unwrap());
                                    let mut cwr = redis::CommandWriter::new();
                                    shared_ht.read(|ht| {
                                        match ht.find(&key) {
                                            Some(val) => {
                                                cwr.args(1);
                                                cwr.arg_bin(*val);
                                            }
                                            None => {
                                                cwr.nil();
                                            }
                                        }
                                    });
                                    cwr.with_buf(|bytes| {io.write(bytes); io.flush()});
                                    continue;
                                }
                                _ => { /* fallthrough: error */ }
                            }
                        }
                        else if command == bytes!("SET") {
                            match (lst.len(), lst.get(1), lst.get(2)) {
                                (3, redis::Data(key), redis::Data(val)) => {
                                    debug!("SET: {:s} {:?}", std::str::from_utf8(key).unwrap(), val);
                                    shared_ht.write(|ht| ht.insert(key.clone(), val.clone()));
                                    let mut cwr = redis::CommandWriter::new();
                                    cwr.status("OK");
                                    cwr.with_buf(|bytes| {io.write(bytes); io.flush()});
                                    continue;
                                }
                                _ => { /* fallthrough: error */ }
                            }
                        }
                        else {
                            /* fallthrough: error */
                        }
                    }
                    _ => { /* fallthrough: error */ }
                }
            }
            _ => { /* fallthrough: error */ }
        }

        /* error */
        let mut cwr = redis::CommandWriter::new();
        cwr.error("Invalid Command");
        cwr.with_buf(|bytes| {io.write(bytes); io.flush()});
    }
}

fn main() {
    let addr: SocketAddr = from_str("127.0.0.1:8000").unwrap();
    let shared_ht = RWArc::new(HashMap::new());

    match TcpListener::bind(addr) {
        Ok(listener) => {
            match listener.listen() {
                Ok(ref mut acceptor) => {
                    loop {
                        match acceptor.accept() {
                            Ok(conn) => {
                                let ht = shared_ht.clone();
                                task::spawn(proc() {
                                    handle_connection(conn, ht)
                                });
                            }
                            Err(_) => {}
                        }
                    }
                }
                Err(_) => {}
            }
        }
        Err(_) => {}
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::hash_map::Keys;
use std::cell::RefCell;
use std::ops::Index;
use std::path::Path;

use super::{Buffer, BufferId};

/// Creates, manages and deletes all the buffers in Qork, maintaining the various invariants that
/// we expect from the buffers. Firstly, if a buffer is backed by a file, a second buffer on that
/// file cannot be created. Secondly, all buffers have unique identity.
///
/// Note that a Buffer is very different from a BufferView.
pub struct BufferCollection {
    current_buffer: BufferId,
    buffers: HashMap<BufferId, RefCell<Buffer>>
}

impl BufferCollection {
    pub fn new() -> BufferCollection {
        BufferCollection {
            current_buffer: -1,
            buffers: HashMap::with_capacity(20)
        }
    }

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

    pub fn current_buffer(&self) -> BufferId {
        self.current_buffer
    }

    pub fn set_current_buffer(&mut self, buffer_id: BufferId) -> bool {
        if self.buffers.contains_key(&buffer_id) {
            self.current_buffer = buffer_id;
            return true;
        } else {
            return false;
        }
    }

    pub fn is_empty(&self) -> bool {
        self.buffers.is_empty()
    }

    pub fn get(&self, buffer_id: BufferId) -> Option<&RefCell<Buffer>> {
         self.buffers.get(&buffer_id)
    }

    pub fn keys(&self) -> Keys<BufferId, RefCell<Buffer>> {
         self.buffers.keys()
    }

    pub fn insert(&mut self, buffer: Buffer) {
        self.buffers.insert(buffer.id(), RefCell::new(buffer));
    }

    pub fn remove(&mut self, buffer_id: BufferId) -> Option<RefCell<Buffer>> {
        self.buffers.remove(&buffer_id)
    }

    pub fn find_by_filename<P : AsRef<Path>>(&mut self, filename: P) -> Option<&RefCell<Buffer>> {
        self.buffers.values().find(|refcell| refcell.borrow().filename.as_ref().map_or(false, |f| f == filename.as_ref()))
    }

    // Needs a buffer factory passed in. Check to see if the file is already open. If it is, return
    // the id of the first buffer rather than creating a new one.
    pub fn open_file() {}
    // Saves a buffer, but only if it already has a filename. Set changed to false.
    pub fn save_buffer() {}
    // Saves a buffer to a specific filename. Might need to allocate a new title. Can change
    // the filename that a buffer is saved to. Set changed to false.
    pub fn save_buffer_as() {}
    // Not sure we need this, it is really just remove disguised.
    pub fn close_buffer() {}

    // We also need a filename pre-processor better than just expand_variables.
    // It should be able to deal with relative names, trying to find a file relative to the
    // current buffer's directory (for working in projects), or failing that, to the cwd.

    /// Title algorithm. We need the ability to uniqueify buffer names. Once a suffix number is
    /// assigned it is never changed. They can be reused, or even not used (we only allocate them
    /// for our convenience, and they do not need to go up monotonically like buffer ids do).
    /// For new buffers not backed by a file "new", then "new 1 " etc.
    /// For buffers backed by a file, the leaf filename, then '1' etc.
    fn get_unique_title(&self, proposed: &str) -> String {
        let prefix = String::from(proposed) + " ";
        let matching_buffers : Vec<String> = self.buffers.values()
            .map(|refcell| refcell.borrow())
            .map(|x| x.title.clone())
            .filter(|title| *title == String::from(proposed) || title.starts_with(&prefix))
            .collect();

        let namer = |n: i32| -> String {
            if n == 0 {
                return String::from(proposed)
            } else {
                return String::from(proposed) + " " + &n.to_string()
            }
        };

        let mut i = 0;
        loop {
            let p = namer(i);
            if !matching_buffers.contains(&p) {
                return p
            } else {
                i += 1
            }
        }
    }
}

impl Index<BufferId> for BufferCollection {
    type Output = RefCell<Buffer>;

    fn index(&self, buffer_id: BufferId) -> &RefCell<Buffer> {
        &self.buffers[&buffer_id]
    }
}

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

    #[test]
    fn get_unique_title_for_empty_collection_returns_proposed() {
        let bc = BufferCollection::new();
        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, proposed);
    }

    #[test]
    fn get_unique_title_for_collection_with_no_matching_buffer_title_returns_proposed() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();

        let mut b = fac.new_empty_buffer();
        b.title = String::from("t1");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("t2");
        bc.insert(b);

        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, proposed);
    }

    #[test]
    fn get_unique_title_for_collection_with_matching_buffer_title_returns_proposed_with_numeral_of_one() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new");
        bc.insert(b);

        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, "new 1");
    }

    #[test]
    fn get_unique_title_for_collection_with_matching_buffer_titles_in_ascending_order_returns_proposed_with_next_free_numeral() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new 1");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new 2");
        bc.insert(b);

        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, "new 3");
    }

    #[test]
    fn get_unique_title_for_collection_with_matching_buffer_titles_with_gap_returns_proposed_with_lowest_free_numeral() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new 1");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new 3");
        bc.insert(b);

        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, "new 2");
    }

    #[test]
    fn is_empty_for_empty_collection_returns_true() {
        let bc = BufferCollection::new();
        assert!(bc.is_empty());
    }

    #[test]
    fn len_for_empty_collection_returns_zero() {
        let bc = BufferCollection::new();
        assert_eq!(0, bc.len());
    }

    #[test]
    fn len_for_non_empty_collection_returns_length() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        bc.insert(b);

        assert_eq!(1, bc.len());
    }

    #[test]
    fn get_for_empty_collection_returns_false() {
        let bc = BufferCollection::new();
        assert!(bc.get(0).is_none());
    }

    #[test]
    fn get_for_id_not_in_collection_returns_none() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);
        assert!(bc.get(id + 1).is_none());
    }

    #[test]
    fn get_for_id_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);

        let result = bc.get(id).unwrap().borrow();
        assert_eq!(id, result.id());

    }

    #[test]
    fn remove_for_non_existent_buffer_returns_none() {
        let mut bc = BufferCollection::new();
        assert_eq!(bc.remove(1), None);
    }

    #[test]
    fn remove_for_buffer_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);

        let b2 = bc.remove(id).unwrap().into_inner();
        assert_eq!(id, b2.id());
        assert_eq!(0, bc.len());
    }

    #[test]
    fn find_by_filename_for_filename_not_in_collection_returns_none() {
        let mut bc = BufferCollection::new();
        let result = bc.find_by_filename("/c/temp/feeeegfxgdg");
        assert_eq!(result, None);
    }

    #[test]
    fn find_by_filename_for_filename_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.open_file("/c/foo.txt");
        let id = b.id;
        bc.insert(b);

        let result = bc.find_by_filename("/c/foo.txt").unwrap();
        assert_eq!(result.borrow().id(), id);
    }
}
<commit_msg>Buffers: get_unique_title split into two functions.<commit_after>use std::collections::HashMap;
use std::collections::hash_map::Keys;
use std::cell::RefCell;
use std::ops::Index;
use std::path::Path;

use super::{Buffer, BufferId};

/// Creates, manages and deletes all the buffers in Qork, maintaining the various invariants that
/// we expect from the buffers. Firstly, if a buffer is backed by a file, a second buffer on that
/// file cannot be created. Secondly, all buffers have unique identity.
///
/// Note that a Buffer is very different from a BufferView.
pub struct BufferCollection {
    current_buffer: BufferId,
    buffers: HashMap<BufferId, RefCell<Buffer>>
}

impl BufferCollection {
    pub fn new() -> BufferCollection {
        BufferCollection {
            current_buffer: -1,
            buffers: HashMap::with_capacity(20)
        }
    }

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

    pub fn current_buffer(&self) -> BufferId {
        self.current_buffer
    }

    pub fn set_current_buffer(&mut self, buffer_id: BufferId) -> bool {
        if self.buffers.contains_key(&buffer_id) {
            self.current_buffer = buffer_id;
            return true;
        } else {
            return false;
        }
    }

    pub fn is_empty(&self) -> bool {
        self.buffers.is_empty()
    }

    pub fn get(&self, buffer_id: BufferId) -> Option<&RefCell<Buffer>> {
         self.buffers.get(&buffer_id)
    }

    pub fn keys(&self) -> Keys<BufferId, RefCell<Buffer>> {
         self.buffers.keys()
    }

    pub fn insert(&mut self, buffer: Buffer) {
        self.buffers.insert(buffer.id(), RefCell::new(buffer));
    }

    pub fn remove(&mut self, buffer_id: BufferId) -> Option<RefCell<Buffer>> {
        self.buffers.remove(&buffer_id)
    }

    pub fn find_by_filename<P : AsRef<Path>>(&mut self, filename: P) -> Option<&RefCell<Buffer>> {
        self.buffers.values().find(|refcell| refcell.borrow().filename.as_ref().map_or(false, |f| f == filename.as_ref()))
    }

    // Needs a buffer factory passed in. Check to see if the file is already open. If it is, return
    // the id of the first buffer rather than creating a new one.
    pub fn open_file() {}
    // Saves a buffer, but only if it already has a filename. Set changed to false.
    pub fn save_buffer() {}
    // Saves a buffer to a specific filename. Might need to allocate a new title. Can change
    // the filename that a buffer is saved to. Set changed to false.
    pub fn save_buffer_as() {}
    // Not sure we need this, it is really just remove disguised.
    pub fn close_buffer() {}

    // We also need a filename pre-processor better than just expand_variables.
    // It should be able to deal with relative names, trying to find a file relative to the
    // current buffer's directory (for working in projects), or failing that, to the cwd.

    /// Title algorithm. We need the ability to uniqueify buffer names. Once a suffix number is
    /// assigned it is never changed. They can be reused, or even not used (we only allocate them
    /// for our convenience, and they do not need to go up monotonically like buffer ids do).
    /// For new buffers not backed by a file "new", then "new 1 " etc.
    /// For buffers backed by a file, the leaf filename, then '1' etc.
    fn get_unique_title(&self, proposed: &str) -> String {
        // let prefix = String::from(proposed) + " ";
        // let matching_buffers : Vec<String> = self.buffers.values()
        //     .map(|refcell| refcell.borrow())
        //     .map(|x| x.title.clone())
        //     .filter(|title| *title == String::from(proposed) || title.starts_with(&prefix))
        //     .collect();

        let titles : Vec<_> = self.buffers.values().map(|refcell| refcell.borrow().title.clone()).collect();

        //let titles2 : Vec<_> = self.buffers.values().map(|refcell| *(refcell.borrow().title)).collect();

        inner_get_unique_title(proposed, &titles)
    }
}

fn inner_get_unique_title(proposed: &str, current_titles: &[String]) -> String {
    let namer = |n: i32| -> String {
        if n == 0 {
            return String::from(proposed)
        } else {
            return String::from(proposed) + " " + &n.to_string()
        }
    };

    let mut i = 0;
    loop {
        let p = namer(i);
        if !current_titles.contains(&p) {
            return p
        } else {
            i += 1
        }
    }
}

impl Index<BufferId> for BufferCollection {
    type Output = RefCell<Buffer>;

    fn index(&self, buffer_id: BufferId) -> &RefCell<Buffer> {
        &self.buffers[&buffer_id]
    }
}

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

    #[test]
    fn get_unique_title_for_empty_collection_returns_proposed() {
        let bc = BufferCollection::new();
        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, proposed);
    }

    #[test]
    fn get_unique_title_for_collection_with_no_matching_buffer_title_returns_proposed() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();

        let mut b = fac.new_empty_buffer();
        b.title = String::from("t1");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("t2");
        bc.insert(b);

        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, proposed);
    }

    #[test]
    fn get_unique_title_for_collection_with_matching_buffer_title_returns_proposed_with_numeral_of_one() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new");
        bc.insert(b);

        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, "new 1");
    }

    #[test]
    fn get_unique_title_for_collection_with_matching_buffer_titles_in_ascending_order_returns_proposed_with_next_free_numeral() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new 1");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new 2");
        bc.insert(b);

        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, "new 3");
    }

    #[test]
    fn get_unique_title_for_collection_with_matching_buffer_titles_with_gap_returns_proposed_with_lowest_free_numeral() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new 1");
        bc.insert(b);

        let mut b = fac.new_empty_buffer();
        b.title = String::from("new 3");
        bc.insert(b);

        let proposed = "new";
        let title = bc.get_unique_title(proposed);
        assert_eq!(title, "new 2");
    }

    #[test]
    fn is_empty_for_empty_collection_returns_true() {
        let bc = BufferCollection::new();
        assert!(bc.is_empty());
    }

    #[test]
    fn len_for_empty_collection_returns_zero() {
        let bc = BufferCollection::new();
        assert_eq!(0, bc.len());
    }

    #[test]
    fn len_for_non_empty_collection_returns_length() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        bc.insert(b);

        assert_eq!(1, bc.len());
    }

    #[test]
    fn get_for_empty_collection_returns_false() {
        let bc = BufferCollection::new();
        assert!(bc.get(0).is_none());
    }

    #[test]
    fn get_for_id_not_in_collection_returns_none() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);
        assert!(bc.get(id + 1).is_none());
    }

    #[test]
    fn get_for_id_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);

        let result = bc.get(id).unwrap().borrow();
        assert_eq!(id, result.id());

    }

    #[test]
    fn remove_for_non_existent_buffer_returns_none() {
        let mut bc = BufferCollection::new();
        assert_eq!(bc.remove(1), None);
    }

    #[test]
    fn remove_for_buffer_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.new_empty_buffer();
        let id = b.id;
        bc.insert(b);

        let b2 = bc.remove(id).unwrap().into_inner();
        assert_eq!(id, b2.id());
        assert_eq!(0, bc.len());
    }

    #[test]
    fn find_by_filename_for_filename_not_in_collection_returns_none() {
        let mut bc = BufferCollection::new();
        let result = bc.find_by_filename("/c/temp/feeeegfxgdg");
        assert_eq!(result, None);
    }

    #[test]
    fn find_by_filename_for_filename_in_collection_returns_buffer() {
        let mut bc = BufferCollection::new();
        let mut fac = BufferFactory::new();
        let b = fac.open_file("/c/foo.txt");
        let id = b.id;
        bc.insert(b);

        let result = bc.find_by_filename("/c/foo.txt").unwrap();
        assert_eq!(result.borrow().id(), id);
    }
}
<|endoftext|>


<commit_before>use std::time::{SystemTime, UNIX_EPOCH, Duration, Instant};
use tokio::timer::Interval;
use tokio::prelude::*;
use std::str::FromStr;
use std::sync::Arc;

use blockchain::*;
use crypto::*;
use asset::*;
use tx::*;

pub struct Producer {
    chain: Arc<Blockchain>,
    minter: KeyPair,
    staker: PublicKey
}

impl Producer {

    pub fn new(chain: Arc<Blockchain>,
                minter: KeyPair,
                staker: PublicKey) -> Producer {
        Producer {
            chain,
            minter,
            staker
        }
    }

    pub fn start_timer(self) {
        let dur = Duration::from_secs(3);
        let at = Instant::now() + dur;
        ::tokio::spawn(Interval::new(at, dur).take_while(|_| {
            Ok(true)
        }).for_each(move |_| {
            Producer::produce(&self);
            Ok(())
        }).map_err(|err| {
            println!("Unknown error in producer: {:?}", err);
        }));
    }

    fn produce(&self) {
        let blockchain = &*self.chain;

        let timestamp = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() as u32;
        let transactions = {
            let mut vec = Vec::new();
            vec.push(TxVariant::RewardTx(RewardTx {
                base: Tx {
                    tx_type: TxType::REWARD,
                    fee: Asset::from_str("0 GOLD").unwrap(),
                    timestamp,
                    signature_pairs: Vec::new()
                },
                to: self.staker.clone(),
                rewards: vec![Asset::from_str("1 GOLD").unwrap()]
            }));
            vec
        };

        let head = blockchain.get_chain_head();
        let block = head.new_child(transactions).sign(&self.minter);

        let height = block.height;
        let tx_len = block.transactions.len();

        blockchain.insert_block(block);
        println!("Produced block at height {} with {} txs", height, tx_len);
    }
}
<commit_msg>Simplify base transactions declaration<commit_after>use std::time::{SystemTime, UNIX_EPOCH, Duration, Instant};
use tokio::timer::Interval;
use tokio::prelude::*;
use std::str::FromStr;
use std::sync::Arc;

use blockchain::*;
use crypto::*;
use asset::*;
use tx::*;

pub struct Producer {
    chain: Arc<Blockchain>,
    minter: KeyPair,
    staker: PublicKey
}

impl Producer {

    pub fn new(chain: Arc<Blockchain>,
                minter: KeyPair,
                staker: PublicKey) -> Producer {
        Producer {
            chain,
            minter,
            staker
        }
    }

    pub fn start_timer(self) {
        let dur = Duration::from_secs(3);
        let at = Instant::now() + dur;
        ::tokio::spawn(Interval::new(at, dur).take_while(|_| {
            Ok(true)
        }).for_each(move |_| {
            Producer::produce(&self);
            Ok(())
        }).map_err(|err| {
            println!("Unknown error in producer: {:?}", err);
        }));
    }

    fn produce(&self) {
        let blockchain = &*self.chain;

        let timestamp = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() as u32;
        let transactions = vec![
            TxVariant::RewardTx(RewardTx {
                base: Tx {
                    tx_type: TxType::REWARD,
                    fee: Asset::from_str("0 GOLD").unwrap(),
                    timestamp,
                    signature_pairs: Vec::new()
                },
                to: self.staker.clone(),
                rewards: vec![Asset::from_str("1 GOLD").unwrap()]
            })
        ];

        let head = blockchain.get_chain_head();
        let block = head.new_child(transactions).sign(&self.minter);

        let height = block.height;
        let tx_len = block.transactions.len();

        blockchain.insert_block(block);
        println!("Produced block at height {} with {} txs", height, tx_len);
    }
}
<|endoftext|>


<commit_before>
use image::{
    ImageBuf,
    MutableRefImage,
    Rgba,
    SubImage,
};

/// Sets colors to hue/saturation image.
/// White is used as color without saturation.
/// This is at the top of the image,
/// while saturated colors are at the bottom.
pub fn hue_saturation_image(
    image: &mut ImageBuf<Rgba<u8>>,
    rect: [u32, ..4]
) {
    let mut sub_image = SubImage::new(image,
        rect[0], rect[1], rect[2], rect[3]);
    let inv_rect_width = 1.0_f64 / rect[2] as f64;
    let half_inv_rect_height = 0.5_f64 / rect[3] as f64;
    let inv60 = 1.0_f64 / 60.0_f64;
    for (x, y, pxl) in sub_image.mut_pixels() {
        let fx = (x - rect[0]) as f64 * inv_rect_width;
        let hue = fx * 360.0_f64;
        // Saturation is 0.5 * fy, so by halving the height we save operations.
        let saturation = (y - rect[1]) as f64 * half_inv_rect_height;
        let hi = (hue * inv60) as int;
        let f = hue * inv60 - hi as f64;
        let hi = hi % 6;
        let v = 255; // use white as color without saturation.
        let p = (255.0 * (1.0 - saturation)) as u8;
        let q = (255.0 * (1.0 - f * saturation)) as u8;
        let t = (255.0 * (1.0 - (1.0 - f) * saturation)) as u8;
        *pxl = Rgba(
            match hi {
                0 | 1 => p,
                2 => t,
                3 | 4 => v,
                _ => q
            },
            match hi {
                0 => t,
                1 | 2 => v,
                3 => q,
                _ => p
            },
            match hi {
                1 => q,
                2 | 3 => p,
                4 => t,
                _ => v
            },
            255
        );
    }
}
<commit_msg>Fixes build error<commit_after>
use image::{
    ImageBuf,
    MutableRefImage,
    Rgba,
    SubImage,
};

/// Sets colors to hue/saturation image.
/// White is used as color without saturation.
/// This is at the top of the image,
/// while saturated colors are at the bottom.
pub fn hue_saturation_image(
    image: &mut ImageBuf<Rgba<u8>>,
    rect: [u32, ..4]
) {
    let mut sub_image = SubImage::new(image,
        rect[0], rect[1], rect[2], rect[3]);
    let inv_rect_width = 1.0_f64 / rect[2] as f64;
    let half_inv_rect_height = 0.5_f64 / rect[3] as f64;
    let inv60 = 1.0_f64 / 60.0_f64;
    for (x, y, pxl) in sub_image.pixels_mut() {
        let fx = (x - rect[0]) as f64 * inv_rect_width;
        let hue = fx * 360.0_f64;
        // Saturation is 0.5 * fy, so by halving the height we save operations.
        let saturation = (y - rect[1]) as f64 * half_inv_rect_height;
        let hi = (hue * inv60) as int;
        let f = hue * inv60 - hi as f64;
        let hi = hi % 6;
        let v = 255; // use white as color without saturation.
        let p = (255.0 * (1.0 - saturation)) as u8;
        let q = (255.0 * (1.0 - f * saturation)) as u8;
        let t = (255.0 * (1.0 - (1.0 - f) * saturation)) as u8;
        *pxl = Rgba(
            match hi {
                0 | 1 => p,
                2 => t,
                3 | 4 => v,
                _ => q
            },
            match hi {
                0 => t,
                1 | 2 => v,
                3 => q,
                _ => p
            },
            match hi {
                1 => q,
                2 | 3 => p,
                4 => t,
                _ => v
            },
            255
        );
    }
}
<|endoftext|>


<commit_before>use token::Token;
use logger::Logger;
use error::{Error, Result, Source};

use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::borrow::Cow;
use std::fs;
use std::io::Read;

use walkdir::WalkDir;
use rustc_serialize::base64::{self, ToBase64};
use mime_guess;

/// Resource Handler.
///
/// Its task is to make sure that some resource (image, link) is available
/// for the book and to list images used in Markdown files so they can be used for the book
#[derive(Debug)]
pub struct ResourceHandler<'r> {
    /// Maps an original url (e.g.) "foo/Readme.md" to a valid link
    /// (e.g.) chapter3.html
    links: HashMap<String, String>,
    map_images: bool,
    logger: &'r Logger,
    base64: bool,

    /// Maps an original (local) file name to a new file name. Allows to
    /// make sure all image files will be included in e.g. the Epub document.
    #[doc(hidden)]
    pub images: HashMap<String, String>,
}

impl<'r> ResourceHandler<'r> {
    /// Creates a new, empty Resource Handler
    pub fn new(logger: &'r Logger) -> ResourceHandler {
        ResourceHandler {
            links: HashMap::new(),
            images: HashMap::new(),
            map_images: false,
            base64: false,
            logger: logger,
        }
    }

    /// Turns on mapping for image files
    ///
    /// # Argument: an offset (should be book.root)
    pub fn set_images_mapping(&mut self, b: bool) {
        self.map_images = b;
    }

    /// Sets base64 mode for image mapping
    ///
    /// If set to true, instead of returning a destination file path,
    /// `map_image` will include the image as base64
    pub fn set_base64(&mut self, b: bool) {
        self.base64 = b;
    }

    /// Add a local image file and get the resulting transformed
    /// file name
    pub fn map_image<'a, S: Into<Cow<'a, str>>>(&'a mut self,
                                                source: &Source,
                                                file: S)
                                                -> Result<Cow<'a, str>> {
        // If image is not local, do nothing much
        let file = file.into();
        if !Self::is_local(file.as_ref()) {
            self.logger
                .warning(lformat!("Resources: book includes non-local image {file}, which might \
                                   cause problem for proper inclusion.",
                                  file = file));
            return Ok(file);
        }

        // Check exisence of the file
        if fs::metadata(file.as_ref()).is_err() {
            return Err(Error::file_not_found(source, lformat!("image"), format!("{}", file)));
        }

        // if image mapping is not activated do nothing else
        if !self.map_images {
            return Ok(file);
        }

        // If this image has already been registered, returns it
        if self.images.contains_key(file.as_ref()) {
            return Ok(Cow::Borrowed(self.images.get(file.as_ref()).unwrap()));
        }

        // Else, create a new file name that has same extension
        // (or a base64 version of the file)
        let dest_file = if !(self.base64) {
            if let Some(extension) = Path::new(file.as_ref()).extension() {
                format!("images/image_{}.{}",
                        self.images.len(),
                        extension.to_string_lossy())
            } else {
                self.logger
                    .warning(lformat!("Resources: book includes image {file} which doesn't have \
                                       an extension",
                                      file = file));
                format!("images/image_{}", self.images.len())
            }
        } else {
            let mut f = match fs::File::open(file.as_ref()) {
                Ok(f) => f,
                Err(_) => {
                    return Err(Error::file_not_found(source,
                                                     lformat!("image"),
                                                     format!("{}", file)));
                }
            };
            let mut content: Vec<u8> = vec![];
            if f.read_to_end(&mut content).is_err() {
                self.logger.error(lformat!("Resources: could not read file {file}", file = file));
                return Ok(file);
            }
            let base64 = content.to_base64(base64::STANDARD);
            match mime_guess::guess_mime_type_opt(file.as_ref()) {
                None => {
                    self.logger
                        .error(lformat!("Resources: could not guess mime type of file {file}",
                                        file = file));
                    return Ok(file);
                }
                Some(s) => format!("data:{};base64,{}", s.to_string(), base64),
            }
        };

        self.images.insert(file.into_owned(), dest_file.clone());
        Ok(Cow::Owned(dest_file))
    }

    /// Returns an iterator the the images files mapping
    #[doc(hidden)]
    pub fn images_mapping(&self) -> &HashMap<String, String> {
        &self.images
    }

    /// Add a match between an original file and a dest file
    pub fn add_link<S: Into<String>>(&mut self, from: S, to: S) {
        self.links.insert(from.into(), to.into());
    }

    /// Get a destination link from an original link
    pub fn get_link<'a>(&'a self, from: &'a str) -> &'a str {
        if let Some(link) = self.links.get(from) {
            link
        } else {
            self.logger.error(lformat!("Resources: could not find a in-book match for link \
                                        {file}",
                                       file = from));
            from
        }
    }

    /// Tell whether a file name is a local resource or net
    pub fn is_local(path: &str) -> bool {
        !path.contains("://") // todo: use better algorithm
    }

    /// Add a path offset to all linked urls and images src
    pub fn add_offset(link_offset: &Path, image_offset: &Path, ast: &mut [Token]) {
        if link_offset == Path::new("") && image_offset == Path::new("") {
            // nothing do to
            return;
        }
        for mut token in ast {
            match *token {
                Token::Link(ref mut url, _, ref mut v) => {
                    if ResourceHandler::is_local(url) {
                        let new_url = format!("{}", link_offset.join(&url).display());
                        *url = new_url;
                    }
                    Self::add_offset(link_offset, image_offset, v);
                }
                Token::Image(ref mut url, _, ref mut v) |
                Token::StandaloneImage(ref mut url, _, ref mut v) => {
                    if ResourceHandler::is_local(url) {
                        let new_url = format!("{}", image_offset.join(&url).display());
                        *url = new_url;
                    }
                    Self::add_offset(link_offset, image_offset, v);
                }
                _ => {
                    if let Some(ref mut inner) = token.inner_mut() {
                        Self::add_offset(link_offset, image_offset, inner);
                    }
                }
            }
        }
    }
}

/// Get the list of all files, walking recursively in directories
///
/// # Arguments
/// - list: a list of files
/// - base: the path where to get them
///
/// # Returns
/// A list of files (relative to `base`), or an error.
pub fn get_files(list: Vec<String>, base: &str) -> Result<Vec<String>> {
    let mut out: Vec<String> = vec![];
    let base = Path::new(base);
    for path in list.into_iter() {
        let abs_path = base.join(&path);
        let res = fs::metadata(&abs_path);
        match res {
            Err(err) => {
                return Err(Error::render(Source::empty(),
                                         lformat!("error reading file {file}: {error}",
                                                  file = abs_path.display(),
                                                  error = err)))
            }
            Ok(metadata) => {
                if metadata.is_file() {
                    out.push(path);
                } else if metadata.is_dir() {
                    let files = WalkDir::new(&abs_path)
                        .follow_links(true)
                        .into_iter()
                        .filter_map(|e| e.ok())
                        .filter(|e| e.file_type().is_file())
                        .map(|e| {
                            PathBuf::from(e.path()
                                .strip_prefix(base)
                                .unwrap())
                        });
                    for file in files {
                        out.push(file.to_string_lossy().into_owned());
                    }
                } else {
                    return Err(Error::render(Source::empty(),
                                             lformat!("error in epub rendering: {path} is \
                                                       neither a file nor a directory",
                                                      path = &path)));
                }
            }
        }
    }
    Ok(out)
}
<commit_msg>Make resource_handler::set_image_mapping return &mut Self<commit_after>use token::Token;
use logger::Logger;
use error::{Error, Result, Source};

use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::borrow::Cow;
use std::fs;
use std::io::Read;

use walkdir::WalkDir;
use rustc_serialize::base64::{self, ToBase64};
use mime_guess;

/// Resource Handler.
///
/// Its task is to make sure that some resource (image, link) is available
/// for the book and to list images used in Markdown files so they can be used for the book
#[derive(Debug)]
pub struct ResourceHandler<'r> {
    /// Maps an original url (e.g.) "foo/Readme.md" to a valid link
    /// (e.g.) chapter3.html
    links: HashMap<String, String>,
    map_images: bool,
    logger: &'r Logger,
    base64: bool,

    /// Maps an original (local) file name to a new file name. Allows to
    /// make sure all image files will be included in e.g. the Epub document.
    #[doc(hidden)]
    pub images: HashMap<String, String>,
}

impl<'r> ResourceHandler<'r> {
    /// Creates a new, empty Resource Handler
    pub fn new(logger: &'r Logger) -> ResourceHandler {
        ResourceHandler {
            links: HashMap::new(),
            images: HashMap::new(),
            map_images: false,
            base64: false,
            logger: logger,
        }
    }

    /// Turns on mapping for image files
    ///
    /// # Argument: an offset (should be book.root)
    pub fn set_images_mapping(&mut self, b: bool) -> &mut Self {
        self.map_images = b;
        self
    }

    /// Sets base64 mode for image mapping
    ///
    /// If set to true, instead of returning a destination file path,
    /// `map_image` will include the image as base64
    pub fn set_base64(&mut self, b: bool) {
        self.base64 = b;
    }

    /// Add a local image file and get the resulting transformed
    /// file name
    pub fn map_image<'a, S: Into<Cow<'a, str>>>(&'a mut self,
                                                source: &Source,
                                                file: S)
                                                -> Result<Cow<'a, str>> {
        // If image is not local, do nothing much
        let file = file.into();
        if !Self::is_local(file.as_ref()) {
            self.logger
                .warning(lformat!("Resources: book includes non-local image {file}, which might \
                                   cause problem for proper inclusion.",
                                  file = file));
            return Ok(file);
        }

        // Check exisence of the file
        if fs::metadata(file.as_ref()).is_err() {
            return Err(Error::file_not_found(source, lformat!("image"), format!("{}", file)));
        }

        // if image mapping is not activated do nothing else
        if !self.map_images {
            return Ok(file);
        }

        // If this image has already been registered, returns it
        if self.images.contains_key(file.as_ref()) {
            return Ok(Cow::Borrowed(self.images.get(file.as_ref()).unwrap()));
        }

        // Else, create a new file name that has same extension
        // (or a base64 version of the file)
        let dest_file = if !(self.base64) {
            if let Some(extension) = Path::new(file.as_ref()).extension() {
                format!("images/image_{}.{}",
                        self.images.len(),
                        extension.to_string_lossy())
            } else {
                self.logger
                    .warning(lformat!("Resources: book includes image {file} which doesn't have \
                                       an extension",
                                      file = file));
                format!("images/image_{}", self.images.len())
            }
        } else {
            let mut f = match fs::File::open(file.as_ref()) {
                Ok(f) => f,
                Err(_) => {
                    return Err(Error::file_not_found(source,
                                                     lformat!("image"),
                                                     format!("{}", file)));
                }
            };
            let mut content: Vec<u8> = vec![];
            if f.read_to_end(&mut content).is_err() {
                self.logger.error(lformat!("Resources: could not read file {file}", file = file));
                return Ok(file);
            }
            let base64 = content.to_base64(base64::STANDARD);
            match mime_guess::guess_mime_type_opt(file.as_ref()) {
                None => {
                    self.logger
                        .error(lformat!("Resources: could not guess mime type of file {file}",
                                        file = file));
                    return Ok(file);
                }
                Some(s) => format!("data:{};base64,{}", s.to_string(), base64),
            }
        };

        self.images.insert(file.into_owned(), dest_file.clone());
        Ok(Cow::Owned(dest_file))
    }

    /// Returns an iterator the the images files mapping
    #[doc(hidden)]
    pub fn images_mapping(&self) -> &HashMap<String, String> {
        &self.images
    }

    /// Add a match between an original file and a dest file
    pub fn add_link<S: Into<String>>(&mut self, from: S, to: S) {
        self.links.insert(from.into(), to.into());
    }

    /// Get a destination link from an original link
    pub fn get_link<'a>(&'a self, from: &'a str) -> &'a str {
        if let Some(link) = self.links.get(from) {
            link
        } else {
            self.logger.error(lformat!("Resources: could not find a in-book match for link \
                                        {file}",
                                       file = from));
            from
        }
    }

    /// Tell whether a file name is a local resource or net
    pub fn is_local(path: &str) -> bool {
        !path.contains("://") // todo: use better algorithm
    }

    /// Add a path offset to all linked urls and images src
    pub fn add_offset(link_offset: &Path, image_offset: &Path, ast: &mut [Token]) {
        if link_offset == Path::new("") && image_offset == Path::new("") {
            // nothing do to
            return;
        }
        for mut token in ast {
            match *token {
                Token::Link(ref mut url, _, ref mut v) => {
                    if ResourceHandler::is_local(url) {
                        let new_url = format!("{}", link_offset.join(&url).display());
                        *url = new_url;
                    }
                    Self::add_offset(link_offset, image_offset, v);
                }
                Token::Image(ref mut url, _, ref mut v) |
                Token::StandaloneImage(ref mut url, _, ref mut v) => {
                    if ResourceHandler::is_local(url) {
                        let new_url = format!("{}", image_offset.join(&url).display());
                        *url = new_url;
                    }
                    Self::add_offset(link_offset, image_offset, v);
                }
                _ => {
                    if let Some(ref mut inner) = token.inner_mut() {
                        Self::add_offset(link_offset, image_offset, inner);
                    }
                }
            }
        }
    }
}

/// Get the list of all files, walking recursively in directories
///
/// # Arguments
/// - list: a list of files
/// - base: the path where to get them
///
/// # Returns
/// A list of files (relative to `base`), or an error.
pub fn get_files(list: Vec<String>, base: &str) -> Result<Vec<String>> {
    let mut out: Vec<String> = vec![];
    let base = Path::new(base);
    for path in list.into_iter() {
        let abs_path = base.join(&path);
        let res = fs::metadata(&abs_path);
        match res {
            Err(err) => {
                return Err(Error::render(Source::empty(),
                                         lformat!("error reading file {file}: {error}",
                                                  file = abs_path.display(),
                                                  error = err)))
            }
            Ok(metadata) => {
                if metadata.is_file() {
                    out.push(path);
                } else if metadata.is_dir() {
                    let files = WalkDir::new(&abs_path)
                        .follow_links(true)
                        .into_iter()
                        .filter_map(|e| e.ok())
                        .filter(|e| e.file_type().is_file())
                        .map(|e| {
                            PathBuf::from(e.path()
                                .strip_prefix(base)
                                .unwrap())
                        });
                    for file in files {
                        out.push(file.to_string_lossy().into_owned());
                    }
                } else {
                    return Err(Error::render(Source::empty(),
                                             lformat!("error in epub rendering: {path} is \
                                                       neither a file nor a directory",
                                                      path = &path)));
                }
            }
        }
    }
    Ok(out)
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_snake_case)]

// Error messages for EXXXX errors.
// Each message should start and end with a new line, and be wrapped to 80 characters.
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
register_long_diagnostics! {

E0001: r##"
This error suggests that the expression arm corresponding to the noted pattern
will never be reached as for all possible values of the expression being
matched, one of the preceding patterns will match.

This means that perhaps some of the preceding patterns are too general, this one
is too specific or the ordering is incorrect.
"##,

E0002: r##"
This error indicates that an empty match expression is illegal because the type
it is matching on is non-empty (there exist values of this type). In safe code
it is impossible to create an instance of an empty type, so empty match
expressions are almost never desired.  This error is typically fixed by adding
one or more cases to the match expression.

An example of an empty type is `enum Empty { }`.
"##,

E0003: r##"
Not-a-Number (NaN) values cannot be compared for equality and hence can never
match the input to a match expression. To match against NaN values, you should
instead use the `is_nan` method in a guard, as in: x if x.is_nan() => ...
"##,

E0004: r##"
This error indicates that the compiler cannot guarantee a matching pattern for
one or more possible inputs to a match expression. Guaranteed matches are
required in order to assign values to match expressions, or alternatively,
determine the flow of execution.

If you encounter this error you must alter your patterns so that every possible
value of the input type is matched. For types with a small number of variants
(like enums) you should probably cover all cases explicitly. Alternatively, the
underscore `_` wildcard pattern can be added after all other patterns to match
"anything else".
"##,

// FIXME: Remove duplication here?
E0005: r##"
Patterns used to bind names must be irrefutable, that is, they must guarantee that a
name will be extracted in all cases. If you encounter this error you probably need
to use a `match` or `if let` to deal with the possibility of failure.
"##,

E0006: r##"
Patterns used to bind names must be irrefutable, that is, they must guarantee that a
name will be extracted in all cases. If you encounter this error you probably need
to use a `match` or `if let` to deal with the possibility of failure.
"##,

E0007: r##"
This error indicates that the bindings in a match arm would require a value to
be moved into more than one location, thus violating unique ownership. Code like
the following is invalid as it requires the entire Option<String> to be moved
into a variable called `op_string` while simultaneously requiring the inner
String to be moved into a variable called `s`.

let x = Some("s".to_string());
match x {
    op_string @ Some(s) => ...
    None => ...
}

See also Error 303.
"##,

E0008: r##"
Names bound in match arms retain their type in pattern guards. As such, if a
name is bound by move in a pattern, it should also be moved to wherever it is
referenced in the pattern guard code. Doing so however would prevent the name
from being available in the body of the match arm. Consider the following:

match Some("hi".to_string()) {
    Some(s) if s.len() == 0 => // use s.
    ...
}

The variable `s` has type String, and its use in the guard is as a variable of
type String. The guard code effectively executes in a separate scope to the body
of the arm, so the value would be moved into this anonymous scope and therefore
become unavailable in the body of the arm. Although this example seems
innocuous, the problem is most clear when considering functions that take their
argument by value.

match Some("hi".to_string()) {
    Some(s) if { drop(s); false } => (),
    Some(s) => // use s.
    ...
}

The value would be dropped in the guard then become unavailable not only in the
body of that arm but also in all subsequent arms! The solution is to bind by
reference when using guards or refactor the entire expression, perhaps by
putting the condition inside the body of the arm.
"##,

E0162: r##"
An if-let pattern attempts to match the pattern, and enters the body if the
match was succesful. If the match is irrefutable (when it cannot fail to match),
use a regular `let`-binding instead. For instance:

struct Irrefutable(i32);
let irr = Irrefutable(0);

// This fails to compile because the match is irrefutable.
if let Irrefutable(x) = irr {
    // This body will always be executed.
    foo(x);
}

// Try this instead:
let Irrefutable(x) = irr;
foo(x);
"##,

E0297: r##"
Patterns used to bind names must be irrefutable. That is, they must guarantee
that a name will be extracted in all cases. Instead of pattern matching the
loop variable, consider using a `match` or `if let` inside the loop body. For
instance:

// This fails because `None` is not covered.
for Some(x) in xs {
    ...
}

// Match inside the loop instead:
for item in xs {
    match item {
        Some(x) => ...
        None => ...
    }
}

// Or use `if let`:
for item in xs {
    if let Some(x) = item {
        ...
    }
}
"##,

E0301: r##"
Mutable borrows are not allowed in pattern guards, because matching cannot have
side effects. Side effects could alter the matched object or the environment
on which the match depends in such a way, that the match would not be
exhaustive. For instance, the following would not match any arm if mutable
borrows were allowed:

match Some(()) {
    None => { },
    option if option.take().is_none() => { /* impossible, option is `Some` */ },
    Some(_) => { } // When the previous match failed, the option became `None`.
}
"##,

E0302: r##"
Assignments are not allowed in pattern guards, because matching cannot have
side effects. Side effects could alter the matched object or the environment
on which the match depends in such a way, that the match would not be
exhaustive. For instance, the following would not match any arm if assignments
were allowed:

match Some(()) {
    None => { },
    option if { option = None; false } { },
    Some(_) => { } // When the previous match failed, the option became `None`.
}
"##,

E0303: r##"
In certain cases it is possible for sub-bindings to violate memory safety.
Updates to the borrow checker in a future version of Rust may remove this
restriction, but for now patterns must be rewritten without sub-bindings.

// Code like this...
match Some(5) {
    ref op_num @ Some(num) => ...
    None => ...
}

// ... should be updated to code like this.
match Some(5) {
    Some(num) => {
        let op_num = &Some(num);
        ...
    }
    None => ...
}

See also https://github.com/rust-lang/rust/issues/14587
"##

}

register_diagnostics! {
    E0009,
    E0010,
    E0011,
    E0012,
    E0013,
    E0014,
    E0015,
    E0016,
    E0017,
    E0018,
    E0019,
    E0020,
    E0022,
    E0079, // enum variant: expected signed integer constant
    E0080, // enum variant: constant evaluation error
    E0109,
    E0110,
    E0133,
    E0134,
    E0135,
    E0136,
    E0137,
    E0138,
    E0139,
    E0152,
    E0158,
    E0161,
    E0165,
    E0170,
    E0261, // use of undeclared lifetime name
    E0262, // illegal lifetime parameter name
    E0263, // lifetime name declared twice in same scope
    E0264, // unknown external lang item
    E0265, // recursive constant
    E0266, // expected item
    E0267, // thing inside of a closure
    E0268, // thing outside of a loop
    E0269, // not all control paths return a value
    E0270, // computation may converge in a function marked as diverging
    E0271, // type mismatch resolving
    E0272, // rustc_on_unimplemented attribute refers to non-existent type parameter
    E0273, // rustc_on_unimplemented must have named format arguments
    E0274, // rustc_on_unimplemented must have a value
    E0275, // overflow evaluating requirement
    E0276, // requirement appears on impl method but not on corresponding trait method
    E0277, // trait is not implemented for type
    E0278, // requirement is not satisfied
    E0279, // requirement is not satisfied
    E0280, // requirement is not satisfied
    E0281, // type implements trait but other trait is required
    E0282, // unable to infer enough type information about
    E0283, // cannot resolve type
    E0284, // cannot resolve type
    E0285, // overflow evaluation builtin bounds
    E0296, // malformed recursion limit attribute
    E0298, // mismatched types between arms
    E0299, // mismatched types between arms
    E0300, // unexpanded macro
    E0304, // expected signed integer constant
    E0305, // expected constant
    E0306, // expected positive integer for repeat count
    E0307, // expected constant integer for repeat count
    E0308,
    E0309, // thing may not live long enough
    E0310, // thing may not live long enough
    E0311, // thing may not live long enough
    E0312, // lifetime of reference outlives lifetime of borrowed content
    E0313, // lifetime of borrowed pointer outlives lifetime of captured variable
    E0314, // closure outlives stack frame
    E0315, // cannot invoke closure outside of its lifetime
    E0316, // nested quantification of lifetimes
    E0370  // discriminant overflow
}

__build_diagnostic_array! { DIAGNOSTICS }
<commit_msg>rustc: Add long diagnostics for E0165<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_snake_case)]

// Error messages for EXXXX errors.
// Each message should start and end with a new line, and be wrapped to 80 characters.
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
register_long_diagnostics! {

E0001: r##"
This error suggests that the expression arm corresponding to the noted pattern
will never be reached as for all possible values of the expression being
matched, one of the preceding patterns will match.

This means that perhaps some of the preceding patterns are too general, this one
is too specific or the ordering is incorrect.
"##,

E0002: r##"
This error indicates that an empty match expression is illegal because the type
it is matching on is non-empty (there exist values of this type). In safe code
it is impossible to create an instance of an empty type, so empty match
expressions are almost never desired.  This error is typically fixed by adding
one or more cases to the match expression.

An example of an empty type is `enum Empty { }`.
"##,

E0003: r##"
Not-a-Number (NaN) values cannot be compared for equality and hence can never
match the input to a match expression. To match against NaN values, you should
instead use the `is_nan` method in a guard, as in: x if x.is_nan() => ...
"##,

E0004: r##"
This error indicates that the compiler cannot guarantee a matching pattern for
one or more possible inputs to a match expression. Guaranteed matches are
required in order to assign values to match expressions, or alternatively,
determine the flow of execution.

If you encounter this error you must alter your patterns so that every possible
value of the input type is matched. For types with a small number of variants
(like enums) you should probably cover all cases explicitly. Alternatively, the
underscore `_` wildcard pattern can be added after all other patterns to match
"anything else".
"##,

// FIXME: Remove duplication here?
E0005: r##"
Patterns used to bind names must be irrefutable, that is, they must guarantee that a
name will be extracted in all cases. If you encounter this error you probably need
to use a `match` or `if let` to deal with the possibility of failure.
"##,

E0006: r##"
Patterns used to bind names must be irrefutable, that is, they must guarantee that a
name will be extracted in all cases. If you encounter this error you probably need
to use a `match` or `if let` to deal with the possibility of failure.
"##,

E0007: r##"
This error indicates that the bindings in a match arm would require a value to
be moved into more than one location, thus violating unique ownership. Code like
the following is invalid as it requires the entire Option<String> to be moved
into a variable called `op_string` while simultaneously requiring the inner
String to be moved into a variable called `s`.

let x = Some("s".to_string());
match x {
    op_string @ Some(s) => ...
    None => ...
}

See also Error 303.
"##,

E0008: r##"
Names bound in match arms retain their type in pattern guards. As such, if a
name is bound by move in a pattern, it should also be moved to wherever it is
referenced in the pattern guard code. Doing so however would prevent the name
from being available in the body of the match arm. Consider the following:

match Some("hi".to_string()) {
    Some(s) if s.len() == 0 => // use s.
    ...
}

The variable `s` has type String, and its use in the guard is as a variable of
type String. The guard code effectively executes in a separate scope to the body
of the arm, so the value would be moved into this anonymous scope and therefore
become unavailable in the body of the arm. Although this example seems
innocuous, the problem is most clear when considering functions that take their
argument by value.

match Some("hi".to_string()) {
    Some(s) if { drop(s); false } => (),
    Some(s) => // use s.
    ...
}

The value would be dropped in the guard then become unavailable not only in the
body of that arm but also in all subsequent arms! The solution is to bind by
reference when using guards or refactor the entire expression, perhaps by
putting the condition inside the body of the arm.
"##,

E0162: r##"
An if-let pattern attempts to match the pattern, and enters the body if the
match was succesful. If the match is irrefutable (when it cannot fail to match),
use a regular `let`-binding instead. For instance:

struct Irrefutable(i32);
let irr = Irrefutable(0);

// This fails to compile because the match is irrefutable.
if let Irrefutable(x) = irr {
    // This body will always be executed.
    foo(x);
}

// Try this instead:
let Irrefutable(x) = irr;
foo(x);
"##,

E0165: r##"
A while-let pattern attempts to match the pattern, and enters the body if the
match was succesful. If the match is irrefutable (when it cannot fail to match),
use a regular `let`-binding inside a `loop` instead. For instance:

struct Irrefutable(i32);
let irr = Irrefutable(0);

// This fails to compile because the match is irrefutable.
while let Irrefutable(x) = irr {
    ...
}

// Try this instead:
loop {
    let Irrefutable(x) = irr;
    ...
}
"##,

E0297: r##"
Patterns used to bind names must be irrefutable. That is, they must guarantee
that a name will be extracted in all cases. Instead of pattern matching the
loop variable, consider using a `match` or `if let` inside the loop body. For
instance:

// This fails because `None` is not covered.
for Some(x) in xs {
    ...
}

// Match inside the loop instead:
for item in xs {
    match item {
        Some(x) => ...
        None => ...
    }
}

// Or use `if let`:
for item in xs {
    if let Some(x) = item {
        ...
    }
}
"##,

E0301: r##"
Mutable borrows are not allowed in pattern guards, because matching cannot have
side effects. Side effects could alter the matched object or the environment
on which the match depends in such a way, that the match would not be
exhaustive. For instance, the following would not match any arm if mutable
borrows were allowed:

match Some(()) {
    None => { },
    option if option.take().is_none() => { /* impossible, option is `Some` */ },
    Some(_) => { } // When the previous match failed, the option became `None`.
}
"##,

E0302: r##"
Assignments are not allowed in pattern guards, because matching cannot have
side effects. Side effects could alter the matched object or the environment
on which the match depends in such a way, that the match would not be
exhaustive. For instance, the following would not match any arm if assignments
were allowed:

match Some(()) {
    None => { },
    option if { option = None; false } { },
    Some(_) => { } // When the previous match failed, the option became `None`.
}
"##,

E0303: r##"
In certain cases it is possible for sub-bindings to violate memory safety.
Updates to the borrow checker in a future version of Rust may remove this
restriction, but for now patterns must be rewritten without sub-bindings.

// Code like this...
match Some(5) {
    ref op_num @ Some(num) => ...
    None => ...
}

// ... should be updated to code like this.
match Some(5) {
    Some(num) => {
        let op_num = &Some(num);
        ...
    }
    None => ...
}

See also https://github.com/rust-lang/rust/issues/14587
"##

}

register_diagnostics! {
    E0009,
    E0010,
    E0011,
    E0012,
    E0013,
    E0014,
    E0015,
    E0016,
    E0017,
    E0018,
    E0019,
    E0020,
    E0022,
    E0079, // enum variant: expected signed integer constant
    E0080, // enum variant: constant evaluation error
    E0109,
    E0110,
    E0133,
    E0134,
    E0135,
    E0136,
    E0137,
    E0138,
    E0139,
    E0152,
    E0158,
    E0161,
    E0170,
    E0261, // use of undeclared lifetime name
    E0262, // illegal lifetime parameter name
    E0263, // lifetime name declared twice in same scope
    E0264, // unknown external lang item
    E0265, // recursive constant
    E0266, // expected item
    E0267, // thing inside of a closure
    E0268, // thing outside of a loop
    E0269, // not all control paths return a value
    E0270, // computation may converge in a function marked as diverging
    E0271, // type mismatch resolving
    E0272, // rustc_on_unimplemented attribute refers to non-existent type parameter
    E0273, // rustc_on_unimplemented must have named format arguments
    E0274, // rustc_on_unimplemented must have a value
    E0275, // overflow evaluating requirement
    E0276, // requirement appears on impl method but not on corresponding trait method
    E0277, // trait is not implemented for type
    E0278, // requirement is not satisfied
    E0279, // requirement is not satisfied
    E0280, // requirement is not satisfied
    E0281, // type implements trait but other trait is required
    E0282, // unable to infer enough type information about
    E0283, // cannot resolve type
    E0284, // cannot resolve type
    E0285, // overflow evaluation builtin bounds
    E0296, // malformed recursion limit attribute
    E0298, // mismatched types between arms
    E0299, // mismatched types between arms
    E0300, // unexpanded macro
    E0304, // expected signed integer constant
    E0305, // expected constant
    E0306, // expected positive integer for repeat count
    E0307, // expected constant integer for repeat count
    E0308,
    E0309, // thing may not live long enough
    E0310, // thing may not live long enough
    E0311, // thing may not live long enough
    E0312, // lifetime of reference outlives lifetime of borrowed content
    E0313, // lifetime of borrowed pointer outlives lifetime of captured variable
    E0314, // closure outlives stack frame
    E0315, // cannot invoke closure outside of its lifetime
    E0316, // nested quantification of lifetimes
    E0370  // discriminant overflow
}

__build_diagnostic_array! { DIAGNOSTICS }
<|endoftext|>