<commit_before>#![allow(clippy::large_enum_variant)]
#![allow(deprecated)] // because of `Error::description` deprecation in `error_chain`

use crate::dist::dist::Profile;
use crate::dist::manifest::{Component, Manifest};
use crate::dist::temp;
use crate::{component_for_bin, Toolchain};
use error_chain::error_chain;
use std::ffi::OsString;
use std::io::{self, Write};
use std::path::PathBuf;
use url::Url;

pub const TOOLSTATE_MSG: &str =
    "If you require these components, please install and use the latest successful build version,\n\
     which you can find at <https://rust-lang.github.io/rustup-components-history>.\n\nAfter determining \
     the correct date, install it with a command such as:\n\n    \
     rustup toolchain install nightly-2018-12-27\n\n\
     Then you can use the toolchain with commands such as:\n\n    \
     cargo +nightly-2018-12-27 build";

error_chain! {
    links {
        Download(download::Error, download::ErrorKind);
    }

    foreign_links {
        Temp(temp::Error);
        Io(io::Error);
        Open(opener::OpenError);
        Thread(std::sync::mpsc::RecvError);
    }

    errors {
        LocatingWorkingDir {
            description("Unable to proceed. Could not locate working directory.")
        }
        ReadingFile {
            name: &'static str,
            path: PathBuf,
        } {
            description("could not read file")
            display("could not read {} file: '{}'", name, path.display())
        }
        ReadingDirectory {
            name: &'static str,
            path: PathBuf,
        } {
            description("could not read directory")
            display("could not read {} directory: '{}'", name, path.display())
        }
        WritingFile {
            name: &'static str,
            path: PathBuf,
        } {
            description("could not write file")
            display("could not write {} file: '{}'", name, path.display())
        }
        CreatingDirectory {
            name: &'static str,
            path: PathBuf,
        } {
            description("could not create directory")
            display("could not create {} directory: '{}'", name, path.display())
        }
        ExpectedType(t: &'static str, n: String) {
            description("expected type")
            display("expected type: '{}' for '{}'", t, n)
        }
        FilteringFile {
            name: &'static str,
            src: PathBuf,
            dest: PathBuf,
        } {
            description("could not copy file")
            display("could not copy {} file from '{}' to '{}'", name, src.display(), dest.display())
        }
        RenamingFile {
            name: &'static str,
            src: PathBuf,
            dest: PathBuf,
        } {
            description("could not rename file")
            display("could not rename {} file from '{}' to '{}'",
                name, src.display(), dest.display())
        }
        RenamingDirectory {
            name: &'static str,
            src: PathBuf,
            dest: PathBuf,
        } {
            description("could not rename directory")
            display("could not rename {} directory from '{}' to '{}'", name, src.display(), dest.display())
        }
        DownloadingFile {
            url: Url,
            path: PathBuf,
        } {
            description("could not download file")
            display("could not download file from '{}' to '{}'", url, path.display())
        }
        DownloadNotExists {
            url: Url,
            path: PathBuf,
        } {
            description("could not download file")
            display("could not download file from '{}' to '{}'", url, path.display())
        }
        InvalidUrl {
            url: String,
        } {
            description("invalid url")
            display("invalid url: {}", url)
        }
        RunningCommand {
            name: OsString,
        } {
            description("command failed")
            display("command failed: '{}'", PathBuf::from(name).display())
        }
        NotAFile {
            path: PathBuf,
        } {
            description("not a file")
            display("not a file: '{}'", path.display())
        }
        NotADirectory {
            path: PathBuf,
        } {
            description("not a directory")
            display("not a directory: '{}'", path.display())
        }
        LinkingFile {
            src: PathBuf,
            dest: PathBuf,
        } {
            description("could not link file")
            display("could not create link from '{}' to '{}'", src.display(), dest.display())
        }
        LinkingDirectory {
            src: PathBuf,
            dest: PathBuf,
        } {
            description("could not symlink directory")
            display("could not create link from '{}' to '{}'", src.display(), dest.display())
        }
        CopyingDirectory {
            src: PathBuf,
            dest: PathBuf,
        } {
            description("could not copy directory")
            display("could not copy directory from '{}' to '{}'", src.display(), dest.display())
        }
        CopyingFile {
            src: PathBuf,
            dest: PathBuf,
        } {
            description("could not copy file")
            display("could not copy file from '{}' to '{}'", src.display(), dest.display())
        }
        RemovingFile {
            name: &'static str,
            path: PathBuf,
        } {
            description("could not remove file")
            display("could not remove '{}' file: '{}'", name, path.display())
        }
        RemovingDirectory {
            name: &'static str,
            path: PathBuf,
        } {
            description("could not remove directory")
            display("could not remove '{}' directory: '{}'", name, path.display())
        }
        SettingPermissions {
            path: PathBuf,
        } {
            description("failed to set permissions")
            display("failed to set permissions for '{}'", path.display())
        }
        CargoHome {
            description("couldn't find value of CARGO_HOME")
        }
        RustupHome {
            description("couldn't find value of RUSTUP_HOME")
        }
        InvalidToolchainName(t: String) {
            description("invalid toolchain name")
            display("invalid toolchain name: '{}'", t)
        }
        InvalidProfile(t: String) {
            description("invalid profile name")
            display("invalid profile name: '{}'; valid names are: {}", t, valid_profile_names())
        }
        ChecksumFailed {
            url: String,
            expected: String,
            calculated: String,
        } {
            description("checksum failed")
            display("checksum failed, expected: '{}', calculated: '{}'",
                    expected,
                    calculated)
        }
        SignatureVerificationInternalError(msg: String) {
            description("internal error verifying signature")
            display("internal error verifying signature: {}", msg)
        }
        SignatureVerificationFailed {
            url: String,
        } {
            description("signature verification failed")
            display("signature verification failed for {}", url)
        }
        ComponentConflict {
            name: String,
            path: PathBuf,
        } {
            description("conflicting component")
            display("failed to install component: '{}', detected conflict: '{:?}'",
                    name,
                    path)
        }
        ComponentMissingFile {
            name: String,
            path: PathBuf,
        } {
            description("missing file in component")
            display("failure removing component '{}', directory does not exist: '{:?}'",
                    name,
                    path)
        }
        ComponentMissingDir {
            name: String,
            path: PathBuf,
        } {
            description("missing directory in component")
            display("failure removing component '{}', directory does not exist: '{:?}'",
                    name,
                    path)
        }
        CorruptComponent(name: String) {
            description("corrupt component manifest")
            display("component manifest for '{}' is corrupt", name)
        }
        ExtractingPackage {
            description("failed to extract package (perhaps you ran out of disk space?)")
        }
        BadInstallerVersion(v: String) {
            description("unsupported installer version")
            display("unsupported installer version: {}", v)
        }
        BadInstalledMetadataVersion(v: String) {
            description("unsupported metadata version in existing installation")
            display("unsupported metadata version in existing installation: {}", v)
        }
        ComponentDirPermissionsFailed {
            description("I/O error walking directory during install")
        }
        ComponentFilePermissionsFailed {
            description("error setting file permissions during install")
        }
        ComponentDownloadFailed(c: String) {
            description("component download failed")
            display("component download failed for {}", c)
        }
        Parsing(e: toml::de::Error) {
            description("error parsing manifest")
        }
        UnsupportedVersion(v: String) {
            description("unsupported manifest version")
            display("manifest version '{}' is not supported", v)
        }
        MissingPackageForComponent(name: String) {
            description("missing package for component")
            display("server sent a broken manifest: missing package for component {}", name)
        }
        MissingPackageForRename(name: String) {
            description("missing package for the target of a rename")
            display("server sent a broken manifest: missing package for the target of a rename {}", name)
        }
        MissingReleaseForToolchain(name: String) {
            description("missing release for a toolchain")
            display("no release found for '{}'", name)
        }
        RequestedComponentsUnavailable(c: Vec<Component>, manifest: Manifest, toolchain: String) {
            description("some requested components are unavailable to download")
            display("{}", component_unavailable_msg(&c, &manifest, &toolchain))
        }
        UnknownMetadataVersion(v: String) {
            description("unknown metadata version")
            display("unknown metadata version: '{}'", v)
        }
        ToolchainNotInstalled(t: String) {
            description("toolchain is not installed")
            display("toolchain '{}' is not installed", t)
        }
        ToolchainNotSelected {
            description("toolchain is not selected")
            display("no override and no default toolchain set")
        }
        OverrideToolchainNotInstalled(t: String) {
            description("override toolchain is not installed")
            display("override toolchain '{}' is not installed", t)
        }
        BinaryNotFound(bin: String, t: String, is_default: bool) {
            description("toolchain does not contain binary")
            display("'{}' is not installed for the toolchain '{}'{}", bin, t, install_msg(bin, t, *is_default))
        }
        BinaryProvidedByUnavailableComponent(component: String, bin: String, toolchain: String) {
            description("binary is provided by a component which is not available in current toolchain")
            display("the '{}' component which provides the command '{}' is not available for the '{}' toolchain", component, bin, toolchain)
        }
        BinaryNotProvidedByComponent(component: String, bin: String, toolchain: String) {
            description("binary should be provided by component but isn't in current toolchain")
            display("the '{}' binary, normally provided by the '{}' component, is not applicable to the '{}' toolchain", bin, component, toolchain)
        }
        NeedMetadataUpgrade {
            description("rustup's metadata is out of date. run `rustup self upgrade-data`")
        }
        UpgradeIoError {
            description("I/O error during upgrade")
        }
        BadInstallerType(s: String) {
            description("invalid extension for installer")
            display("invalid extension for installer: '{}'", s)
        }
        ComponentsUnsupported(t: String) {
            description("toolchain does not support components")
            display("toolchain '{}' does not support components", t)
        }
        UnknownComponent(t: String, c: String, s: Option<String>) {
            description("toolchain does not contain component")
            display("toolchain '{}' does not contain component {}{}", t, c, if let Some(suggestion) = s {
                format!("; did you mean '{}'?", suggestion)
            } else {
                "".to_string()
            })
        }
        UnknownProfile(p: String) {
            description("unknown profile name")
            display(
                "unknown profile name: '{}'; valid profile names are {}",
                p,
                valid_profile_names(),
            )
        }
        AddingRequiredComponent(t: String, c: String) {
            description("required component cannot be added")
            display("component {} was automatically added because it is required for toolchain '{}'",
                    c, t)
        }
        ParsingFallbackSettings(e: toml::de::Error) {
            description("error parsing settings")
        }
        ParsingSettings(e: toml::de::Error) {
            description("error parsing settings")
        }
        NoExeName {
            description("couldn't determine self executable name")
        }
        UnsupportedKind(v: String) {
            description("unsupported tar entry")
            display("tar entry kind '{}' is not supported", v)
        }
        BadPath(v: PathBuf) {
            description("bad path in tar")
            display("tar path '{}' is not supported", v.display())
        }
        InvalidPgpKey(v: PathBuf, error: pgp::errors::Error) {
            description("invalid PGP key"),
            display("unable to read the PGP key '{}'", v.display())
        }
        BrokenPartialFile {
            description("partially downloaded file may have been damaged and was removed, please try again")
        }
        EmptyOverrideFile {
            description("empty toolchain override file detected. Please remove it, or else specify the desired toolchain properties in the file")
        }
        InvalidOverrideFile {
            description("missing toolchain properties in toolchain override file")
        }
        ParsingOverrideFile(e: toml::de::Error) {
            description("error parsing override file")
        }
    }
}

fn valid_profile_names() -> String {
    Profile::names()
        .iter()
        .map(|s| format!("'{}'", s))
        .collect::<Vec<_>>()
        .join(", ")
}

fn remove_component_msg(cs: &Component, manifest: &Manifest, toolchain: &str) -> String {
    if cs.short_name_in_manifest() == "rust-std" {
        // We special-case rust-std as it's the stdlib so really you want to do
        // rustup target remove
        format!(
            "    rustup target remove --toolchain {} {}",
            toolchain,
            cs.target.as_deref().unwrap_or(toolchain)
        )
    } else {
        format!(
            "    rustup component remove --toolchain {}{} {}",
            toolchain,
            if let Some(target) = cs.target.as_ref() {
                format!(" --target {}", target)
            } else {
                String::default()
            },
            cs.short_name(manifest)
        )
    }
}

fn component_unavailable_msg(cs: &[Component], manifest: &Manifest, toolchain: &str) -> String {
    assert!(!cs.is_empty());

    let mut buf = vec![];

    if cs.len() == 1 {
        let _ = write!(
            buf,
            "component {} is unavailable for download for channel {}{}",
            &cs[0].description(manifest),
            toolchain,
            if toolchain.starts_with("nightly") {
                "\nSometimes not all components are available in any given nightly. "
            } else {
                ""
            }
        );

        let _ = write!(
            buf,
            "If you don't need the component, you can remove it with:\n\n{}",
            remove_component_msg(&cs[0], manifest, toolchain)
        );
    } else {
        let same_target = cs
            .iter()
            .all(|c| c.target == cs[0].target || c.target.is_none());
        if same_target {
            let cs_str = cs
                .iter()
                .map(|c| format!("'{}'", c.short_name(manifest)))
                .collect::<Vec<_>>()
                .join(", ");
            let remove_msg = cs
                .iter()
                .map(|c| remove_component_msg(c, manifest, toolchain))
                .collect::<Vec<_>>()
                .join("\n");
            let _ = write!(
                buf,
                "some components unavailable for download for channel {}: {}
                 If you don't need the components, you can remove them with:\n\n{}\n\n{}",
                toolchain, cs_str, remove_msg, TOOLSTATE_MSG,
            );
        } else {
            let cs_str = cs
                .iter()
                .map(|c| c.description(manifest))
                .collect::<Vec<_>>()
                .join(", ");
            let remove_msg = cs
                .iter()
                .map(|c| remove_component_msg(c, manifest, toolchain))
                .collect::<Vec<_>>()
                .join("\n");
            let _ = write!(
                buf,
                "some components unavailable for download for channel {}: {}
                If you don't need the components, you can remove them with:\n{}\n{}",
                toolchain, cs_str, remove_msg, TOOLSTATE_MSG,
            );
        }
    }

    String::from_utf8(buf).unwrap()
}

fn install_msg(bin: &str, toolchain: &str, is_default: bool) -> String {
    if Toolchain::is_custom_name(toolchain) {
        return "\nnote: this is a custom toolchain, which cannot use `rustup component add`\n\
        help: if you built this toolchain from source, and used `rustup toolchain link`, then you may be able to build the component with `x.py`".to_string();
    }
    match component_for_bin(bin) {
        Some(c) => format!("\nTo install, run `rustup component add {}{}`", c, {
            if is_default {
                String::new()
            } else {
                format!(" --toolchain {}", toolchain)
            }
        }),
        None => String::new(),
    }
}
<commit_msg>Add missing space in error message<commit_after>#![allow(clippy::large_enum_variant)]
#![allow(deprecated)] // because of `Error::description` deprecation in `error_chain`

use crate::dist::dist::Profile;
use crate::dist::manifest::{Component, Manifest};
use crate::dist::temp;
use crate::{component_for_bin, Toolchain};
use error_chain::error_chain;
use std::ffi::OsString;
use std::io::{self, Write};
use std::path::PathBuf;
use url::Url;

pub const TOOLSTATE_MSG: &str =
    "If you require these components, please install and use the latest successful build version,\n\
     which you can find at <https://rust-lang.github.io/rustup-components-history>.\n\nAfter determining \
     the correct date, install it with a command such as:\n\n    \
     rustup toolchain install nightly-2018-12-27\n\n\
     Then you can use the toolchain with commands such as:\n\n    \
     cargo +nightly-2018-12-27 build";

error_chain! {
    links {
        Download(download::Error, download::ErrorKind);
    }

    foreign_links {
        Temp(temp::Error);
        Io(io::Error);
        Open(opener::OpenError);
        Thread(std::sync::mpsc::RecvError);
    }

    errors {
        LocatingWorkingDir {
            description("Unable to proceed. Could not locate working directory.")
        }
        ReadingFile {
            name: &'static str,
            path: PathBuf,
        } {
            description("could not read file")
            display("could not read {} file: '{}'", name, path.display())
        }
        ReadingDirectory {
            name: &'static str,
            path: PathBuf,
        } {
            description("could not read directory")
            display("could not read {} directory: '{}'", name, path.display())
        }
        WritingFile {
            name: &'static str,
            path: PathBuf,
        } {
            description("could not write file")
            display("could not write {} file: '{}'", name, path.display())
        }
        CreatingDirectory {
            name: &'static str,
            path: PathBuf,
        } {
            description("could not create directory")
            display("could not create {} directory: '{}'", name, path.display())
        }
        ExpectedType(t: &'static str, n: String) {
            description("expected type")
            display("expected type: '{}' for '{}'", t, n)
        }
        FilteringFile {
            name: &'static str,
            src: PathBuf,
            dest: PathBuf,
        } {
            description("could not copy file")
            display("could not copy {} file from '{}' to '{}'", name, src.display(), dest.display())
        }
        RenamingFile {
            name: &'static str,
            src: PathBuf,
            dest: PathBuf,
        } {
            description("could not rename file")
            display("could not rename {} file from '{}' to '{}'",
                name, src.display(), dest.display())
        }
        RenamingDirectory {
            name: &'static str,
            src: PathBuf,
            dest: PathBuf,
        } {
            description("could not rename directory")
            display("could not rename {} directory from '{}' to '{}'", name, src.display(), dest.display())
        }
        DownloadingFile {
            url: Url,
            path: PathBuf,
        } {
            description("could not download file")
            display("could not download file from '{}' to '{}'", url, path.display())
        }
        DownloadNotExists {
            url: Url,
            path: PathBuf,
        } {
            description("could not download file")
            display("could not download file from '{}' to '{}'", url, path.display())
        }
        InvalidUrl {
            url: String,
        } {
            description("invalid url")
            display("invalid url: {}", url)
        }
        RunningCommand {
            name: OsString,
        } {
            description("command failed")
            display("command failed: '{}'", PathBuf::from(name).display())
        }
        NotAFile {
            path: PathBuf,
        } {
            description("not a file")
            display("not a file: '{}'", path.display())
        }
        NotADirectory {
            path: PathBuf,
        } {
            description("not a directory")
            display("not a directory: '{}'", path.display())
        }
        LinkingFile {
            src: PathBuf,
            dest: PathBuf,
        } {
            description("could not link file")
            display("could not create link from '{}' to '{}'", src.display(), dest.display())
        }
        LinkingDirectory {
            src: PathBuf,
            dest: PathBuf,
        } {
            description("could not symlink directory")
            display("could not create link from '{}' to '{}'", src.display(), dest.display())
        }
        CopyingDirectory {
            src: PathBuf,
            dest: PathBuf,
        } {
            description("could not copy directory")
            display("could not copy directory from '{}' to '{}'", src.display(), dest.display())
        }
        CopyingFile {
            src: PathBuf,
            dest: PathBuf,
        } {
            description("could not copy file")
            display("could not copy file from '{}' to '{}'", src.display(), dest.display())
        }
        RemovingFile {
            name: &'static str,
            path: PathBuf,
        } {
            description("could not remove file")
            display("could not remove '{}' file: '{}'", name, path.display())
        }
        RemovingDirectory {
            name: &'static str,
            path: PathBuf,
        } {
            description("could not remove directory")
            display("could not remove '{}' directory: '{}'", name, path.display())
        }
        SettingPermissions {
            path: PathBuf,
        } {
            description("failed to set permissions")
            display("failed to set permissions for '{}'", path.display())
        }
        CargoHome {
            description("couldn't find value of CARGO_HOME")
        }
        RustupHome {
            description("couldn't find value of RUSTUP_HOME")
        }
        InvalidToolchainName(t: String) {
            description("invalid toolchain name")
            display("invalid toolchain name: '{}'", t)
        }
        InvalidProfile(t: String) {
            description("invalid profile name")
            display("invalid profile name: '{}'; valid names are: {}", t, valid_profile_names())
        }
        ChecksumFailed {
            url: String,
            expected: String,
            calculated: String,
        } {
            description("checksum failed")
            display("checksum failed, expected: '{}', calculated: '{}'",
                    expected,
                    calculated)
        }
        SignatureVerificationInternalError(msg: String) {
            description("internal error verifying signature")
            display("internal error verifying signature: {}", msg)
        }
        SignatureVerificationFailed {
            url: String,
        } {
            description("signature verification failed")
            display("signature verification failed for {}", url)
        }
        ComponentConflict {
            name: String,
            path: PathBuf,
        } {
            description("conflicting component")
            display("failed to install component: '{}', detected conflict: '{:?}'",
                    name,
                    path)
        }
        ComponentMissingFile {
            name: String,
            path: PathBuf,
        } {
            description("missing file in component")
            display("failure removing component '{}', directory does not exist: '{:?}'",
                    name,
                    path)
        }
        ComponentMissingDir {
            name: String,
            path: PathBuf,
        } {
            description("missing directory in component")
            display("failure removing component '{}', directory does not exist: '{:?}'",
                    name,
                    path)
        }
        CorruptComponent(name: String) {
            description("corrupt component manifest")
            display("component manifest for '{}' is corrupt", name)
        }
        ExtractingPackage {
            description("failed to extract package (perhaps you ran out of disk space?)")
        }
        BadInstallerVersion(v: String) {
            description("unsupported installer version")
            display("unsupported installer version: {}", v)
        }
        BadInstalledMetadataVersion(v: String) {
            description("unsupported metadata version in existing installation")
            display("unsupported metadata version in existing installation: {}", v)
        }
        ComponentDirPermissionsFailed {
            description("I/O error walking directory during install")
        }
        ComponentFilePermissionsFailed {
            description("error setting file permissions during install")
        }
        ComponentDownloadFailed(c: String) {
            description("component download failed")
            display("component download failed for {}", c)
        }
        Parsing(e: toml::de::Error) {
            description("error parsing manifest")
        }
        UnsupportedVersion(v: String) {
            description("unsupported manifest version")
            display("manifest version '{}' is not supported", v)
        }
        MissingPackageForComponent(name: String) {
            description("missing package for component")
            display("server sent a broken manifest: missing package for component {}", name)
        }
        MissingPackageForRename(name: String) {
            description("missing package for the target of a rename")
            display("server sent a broken manifest: missing package for the target of a rename {}", name)
        }
        MissingReleaseForToolchain(name: String) {
            description("missing release for a toolchain")
            display("no release found for '{}'", name)
        }
        RequestedComponentsUnavailable(c: Vec<Component>, manifest: Manifest, toolchain: String) {
            description("some requested components are unavailable to download")
            display("{}", component_unavailable_msg(&c, &manifest, &toolchain))
        }
        UnknownMetadataVersion(v: String) {
            description("unknown metadata version")
            display("unknown metadata version: '{}'", v)
        }
        ToolchainNotInstalled(t: String) {
            description("toolchain is not installed")
            display("toolchain '{}' is not installed", t)
        }
        ToolchainNotSelected {
            description("toolchain is not selected")
            display("no override and no default toolchain set")
        }
        OverrideToolchainNotInstalled(t: String) {
            description("override toolchain is not installed")
            display("override toolchain '{}' is not installed", t)
        }
        BinaryNotFound(bin: String, t: String, is_default: bool) {
            description("toolchain does not contain binary")
            display("'{}' is not installed for the toolchain '{}'{}", bin, t, install_msg(bin, t, *is_default))
        }
        BinaryProvidedByUnavailableComponent(component: String, bin: String, toolchain: String) {
            description("binary is provided by a component which is not available in current toolchain")
            display("the '{}' component which provides the command '{}' is not available for the '{}' toolchain", component, bin, toolchain)
        }
        BinaryNotProvidedByComponent(component: String, bin: String, toolchain: String) {
            description("binary should be provided by component but isn't in current toolchain")
            display("the '{}' binary, normally provided by the '{}' component, is not applicable to the '{}' toolchain", bin, component, toolchain)
        }
        NeedMetadataUpgrade {
            description("rustup's metadata is out of date. run `rustup self upgrade-data`")
        }
        UpgradeIoError {
            description("I/O error during upgrade")
        }
        BadInstallerType(s: String) {
            description("invalid extension for installer")
            display("invalid extension for installer: '{}'", s)
        }
        ComponentsUnsupported(t: String) {
            description("toolchain does not support components")
            display("toolchain '{}' does not support components", t)
        }
        UnknownComponent(t: String, c: String, s: Option<String>) {
            description("toolchain does not contain component")
            display("toolchain '{}' does not contain component {}{}", t, c, if let Some(suggestion) = s {
                format!("; did you mean '{}'?", suggestion)
            } else {
                "".to_string()
            })
        }
        UnknownProfile(p: String) {
            description("unknown profile name")
            display(
                "unknown profile name: '{}'; valid profile names are {}",
                p,
                valid_profile_names(),
            )
        }
        AddingRequiredComponent(t: String, c: String) {
            description("required component cannot be added")
            display("component {} was automatically added because it is required for toolchain '{}'",
                    c, t)
        }
        ParsingFallbackSettings(e: toml::de::Error) {
            description("error parsing settings")
        }
        ParsingSettings(e: toml::de::Error) {
            description("error parsing settings")
        }
        NoExeName {
            description("couldn't determine self executable name")
        }
        UnsupportedKind(v: String) {
            description("unsupported tar entry")
            display("tar entry kind '{}' is not supported", v)
        }
        BadPath(v: PathBuf) {
            description("bad path in tar")
            display("tar path '{}' is not supported", v.display())
        }
        InvalidPgpKey(v: PathBuf, error: pgp::errors::Error) {
            description("invalid PGP key"),
            display("unable to read the PGP key '{}'", v.display())
        }
        BrokenPartialFile {
            description("partially downloaded file may have been damaged and was removed, please try again")
        }
        EmptyOverrideFile {
            description("empty toolchain override file detected. Please remove it, or else specify the desired toolchain properties in the file")
        }
        InvalidOverrideFile {
            description("missing toolchain properties in toolchain override file")
        }
        ParsingOverrideFile(e: toml::de::Error) {
            description("error parsing override file")
        }
    }
}

fn valid_profile_names() -> String {
    Profile::names()
        .iter()
        .map(|s| format!("'{}'", s))
        .collect::<Vec<_>>()
        .join(", ")
}

fn remove_component_msg(cs: &Component, manifest: &Manifest, toolchain: &str) -> String {
    if cs.short_name_in_manifest() == "rust-std" {
        // We special-case rust-std as it's the stdlib so really you want to do
        // rustup target remove
        format!(
            "    rustup target remove --toolchain {} {}",
            toolchain,
            cs.target.as_deref().unwrap_or(toolchain)
        )
    } else {
        format!(
            "    rustup component remove --toolchain {}{} {}",
            toolchain,
            if let Some(target) = cs.target.as_ref() {
                format!(" --target {}", target)
            } else {
                String::default()
            },
            cs.short_name(manifest)
        )
    }
}

fn component_unavailable_msg(cs: &[Component], manifest: &Manifest, toolchain: &str) -> String {
    assert!(!cs.is_empty());

    let mut buf = vec![];

    if cs.len() == 1 {
        let _ = write!(
            buf,
            "component {} is unavailable for download for channel {}{}",
            &cs[0].description(manifest),
            toolchain,
            if toolchain.starts_with("nightly") {
                "\nSometimes not all components are available in any given nightly. "
            } else {
                " "
            }
        );

        let _ = write!(
            buf,
            "If you don't need the component, you can remove it with:\n\n{}",
            remove_component_msg(&cs[0], manifest, toolchain)
        );
    } else {
        let same_target = cs
            .iter()
            .all(|c| c.target == cs[0].target || c.target.is_none());
        if same_target {
            let cs_str = cs
                .iter()
                .map(|c| format!("'{}'", c.short_name(manifest)))
                .collect::<Vec<_>>()
                .join(", ");
            let remove_msg = cs
                .iter()
                .map(|c| remove_component_msg(c, manifest, toolchain))
                .collect::<Vec<_>>()
                .join("\n");
            let _ = write!(
                buf,
                "some components unavailable for download for channel {}: {}
                 If you don't need the components, you can remove them with:\n\n{}\n\n{}",
                toolchain, cs_str, remove_msg, TOOLSTATE_MSG,
            );
        } else {
            let cs_str = cs
                .iter()
                .map(|c| c.description(manifest))
                .collect::<Vec<_>>()
                .join(", ");
            let remove_msg = cs
                .iter()
                .map(|c| remove_component_msg(c, manifest, toolchain))
                .collect::<Vec<_>>()
                .join("\n");
            let _ = write!(
                buf,
                "some components unavailable for download for channel {}: {}
                If you don't need the components, you can remove them with:\n{}\n{}",
                toolchain, cs_str, remove_msg, TOOLSTATE_MSG,
            );
        }
    }

    String::from_utf8(buf).unwrap()
}

fn install_msg(bin: &str, toolchain: &str, is_default: bool) -> String {
    if Toolchain::is_custom_name(toolchain) {
        return "\nnote: this is a custom toolchain, which cannot use `rustup component add`\n\
        help: if you built this toolchain from source, and used `rustup toolchain link`, then you may be able to build the component with `x.py`".to_string();
    }
    match component_for_bin(bin) {
        Some(c) => format!("\nTo install, run `rustup component add {}{}`", c, {
            if is_default {
                String::new()
            } else {
                format!(" --toolchain {}", toolchain)
            }
        }),
        None => String::new(),
    }
}
<|endoftext|>


<commit_before>//! Representations of various client errors

use hyper::{self, http, StatusCode};
use serde_json::Error as SerdeError;
use std::{error::Error as StdError, fmt, string::FromUtf8Error};

use futures_util::io::Error as IoError;

/// Represents the result of all docker operations
pub type Result<T> = std::result::Result<T, Error>;

#[derive(Debug)]
pub enum Error {
    SerdeJsonError(SerdeError),
    Hyper(hyper::Error),
    Http(hyper::http::Error),
    #[allow(clippy::upper_case_acronyms)]
    IO(IoError),
    Encoding(FromUtf8Error),
    InvalidResponse(String),
    Fault {
        code: StatusCode,
        message: String,
    },
    ConnectionNotUpgraded,
}

impl From<SerdeError> for Error {
    fn from(error: SerdeError) -> Error {
        Error::SerdeJsonError(error)
    }
}

impl From<hyper::Error> for Error {
    fn from(error: hyper::Error) -> Error {
        Error::Hyper(error)
    }
}

impl From<hyper::http::Error> for Error {
    fn from(error: hyper::http::Error) -> Error {
        Error::Http(error)
    }
}

impl From<http::uri::InvalidUri> for Error {
    fn from(error: http::uri::InvalidUri) -> Self {
        let http_error: http::Error = error.into();
        http_error.into()
    }
}

impl From<IoError> for Error {
    fn from(error: IoError) -> Error {
        Error::IO(error)
    }
}

impl From<FromUtf8Error> for Error {
    fn from(error: FromUtf8Error) -> Error {
        Error::Encoding(error)
    }
}

impl fmt::Display for Error {
    fn fmt(
        &self,
        f: &mut fmt::Formatter,
    ) -> fmt::Result {
        write!(f, "Docker Error: ")?;
        match self {
            Error::SerdeJsonError(ref err) => err.fmt(f),
            Error::Http(ref err) => err.fmt(f),
            Error::Hyper(ref err) => err.fmt(f),
            Error::IO(ref err) => err.fmt(f),
            Error::Encoding(ref err) => err.fmt(f),
            Error::InvalidResponse(ref cause) => {
                write!(f, "Response doesn't have the expected format: {}", cause)
            }
            Error::Fault { code, .. } => write!(f, "{}", code),
            Error::ConnectionNotUpgraded => write!(
                f,
                "expected the docker host to upgrade the HTTP connection but it did not"
            ),
        }
    }
}

impl StdError for Error {
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        match self {
            Error::SerdeJsonError(ref err) => Some(err),
            Error::Http(ref err) => Some(err),
            Error::IO(ref err) => Some(err),
            Error::Encoding(e) => Some(e),
            _ => None,
        }
    }
}
<commit_msg>Display error message for `Error::Fault` (#292)<commit_after>//! Representations of various client errors

use hyper::{self, http, StatusCode};
use serde_json::Error as SerdeError;
use std::{error::Error as StdError, fmt, string::FromUtf8Error};

use futures_util::io::Error as IoError;

/// Represents the result of all docker operations
pub type Result<T> = std::result::Result<T, Error>;

#[derive(Debug)]
pub enum Error {
    SerdeJsonError(SerdeError),
    Hyper(hyper::Error),
    Http(hyper::http::Error),
    #[allow(clippy::upper_case_acronyms)]
    IO(IoError),
    Encoding(FromUtf8Error),
    InvalidResponse(String),
    Fault {
        code: StatusCode,
        message: String,
    },
    ConnectionNotUpgraded,
}

impl From<SerdeError> for Error {
    fn from(error: SerdeError) -> Error {
        Error::SerdeJsonError(error)
    }
}

impl From<hyper::Error> for Error {
    fn from(error: hyper::Error) -> Error {
        Error::Hyper(error)
    }
}

impl From<hyper::http::Error> for Error {
    fn from(error: hyper::http::Error) -> Error {
        Error::Http(error)
    }
}

impl From<http::uri::InvalidUri> for Error {
    fn from(error: http::uri::InvalidUri) -> Self {
        let http_error: http::Error = error.into();
        http_error.into()
    }
}

impl From<IoError> for Error {
    fn from(error: IoError) -> Error {
        Error::IO(error)
    }
}

impl From<FromUtf8Error> for Error {
    fn from(error: FromUtf8Error) -> Error {
        Error::Encoding(error)
    }
}

impl fmt::Display for Error {
    fn fmt(
        &self,
        f: &mut fmt::Formatter,
    ) -> fmt::Result {
        write!(f, "Docker Error: ")?;
        match self {
            Error::SerdeJsonError(ref err) => err.fmt(f),
            Error::Http(ref err) => err.fmt(f),
            Error::Hyper(ref err) => err.fmt(f),
            Error::IO(ref err) => err.fmt(f),
            Error::Encoding(ref err) => err.fmt(f),
            Error::InvalidResponse(ref cause) => {
                write!(f, "Response doesn't have the expected format: {}", cause)
            }
            Error::Fault { code, message } => write!(f, "{}: {}", code, message),
            Error::ConnectionNotUpgraded => write!(
                f,
                "expected the docker host to upgrade the HTTP connection but it did not"
            ),
        }
    }
}

impl StdError for Error {
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        match self {
            Error::SerdeJsonError(ref err) => Some(err),
            Error::Http(ref err) => Some(err),
            Error::IO(ref err) => Some(err),
            Error::Encoding(e) => Some(e),
            _ => None,
        }
    }
}
<|endoftext|>


<commit_before>use std::path::PathBuf;

#[derive(Clone, Debug)]
pub enum Event {
    /// The size of the window has changed.
    Resized(u32, u32),

    /// The position of the window has changed.
    Moved(i32, i32),

    /// The window has been closed.
    Closed,

    /// A file has been dropped into the window.
    DroppedFile(PathBuf),

    /// The window received a unicode character.
    ReceivedCharacter(char),

    /// The window gained or lost focus.
    ///
    /// The parameter is true if the window has gained focus, and false if it has lost focus.
    Focused(bool),

    /// An event from the keyboard has been received.
    KeyboardInput(ElementState, ScanCode, Option<VirtualKeyCode>),

    /// The cursor has moved on the window.
    ///
    /// The parameter are the (x,y) coords in pixels relative to the top-left corner of the window.
    MouseMoved((i32, i32)),

    /// A mouse wheel movement or touchpad scroll occurred.
    MouseWheel(MouseScrollDelta),

    /// An event from the mouse has been received.
    MouseInput(ElementState, MouseButton),

    /// The event loop was woken up by another thread.
    Awakened,

    /// The window needs to be redrawn.
    Refresh,

    /// App has been suspended or resumed.
    ///
    /// The parameter is true if app was suspended, and false if it has been resumed.
    Suspended(bool),

    /// Touch event has been received
    Touch(Touch)
}

#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum TouchPhase {
    Started,
    Moved,
    Ended,
    Cancelled
}

#[derive(Debug, Clone, Copy)]
/// Represents touch event
///
/// Every time user touches screen new Start event with some finger id is generated.
/// When the finger is removed from the screen End event with same id is generated.
///
/// For every id there will be at least 2 events with phases Start and End (or Cancelled).
/// There may be 0 or more Move events.
///
///
/// Depending on platform implementation id may or may not be reused by system after End event.
///
/// Gesture regonizer using this event should assume that Start event received with same id
/// as previously received End event is a new finger and has nothing to do with an old one.
///
/// Touch may be cancelled if for example window lost focus.
pub struct Touch {
    pub phase: TouchPhase,
    pub location: (f64,f64),
    /// unique identifier of a finger.
    pub id: u64
}

pub type ScanCode = u8;

#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum ElementState {
    Pressed,
    Released,
}

#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum MouseButton {
    Left,
    Right,
    Middle,
    Other(u8),
}

#[derive(Debug, Clone, Copy)]
pub enum MouseScrollDelta {
	/// Amount in lines or rows to scroll in the horizontal
	/// and vertical directions.
	///
	/// Positive values indicate movement forward
	/// (away from the user) or rightwards.
	LineDelta(f32, f32),
	/// Amount in pixels to scroll in the horizontal and
	/// vertical direction.
	///
	/// Scroll events are expressed as a PixelDelta if
	/// supported by the device (eg. a touchpad) and
	/// platform.
	PixelDelta(f32, f32)
}

#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum VirtualKeyCode {
    /// The '1' key over the letters.
    Key1,
    /// The '2' key over the letters.
    Key2,
    /// The '3' key over the letters.
    Key3,
    /// The '4' key over the letters.
    Key4,
    /// The '5' key over the letters.
    Key5,
    /// The '6' key over the letters.
    Key6,
    /// The '7' key over the letters.
    Key7,
    /// The '8' key over the letters.
    Key8,
    /// The '9' key over the letters.
    Key9,
    /// The '0' key over the 'O' and 'P' keys.
    Key0,

    A,
    B,
    C,
    D,
    E,
    F,
    G,
    H,
    I,
    J,
    K,
    L,
    M,
    N,
    O,
    P,
    Q,
    R,
    S,
    T,
    U,
    V,
    W,
    X,
    Y,
    Z,

    /// The Escape key, next to F1.
    Escape,

    F1,
    F2,
    F3,
    F4,
    F5,
    F6,
    F7,
    F8,
    F9,
    F10,
    F11,
    F12,
    F13,
    F14,
    F15,

    /// Print Screen/SysRq.
    Snapshot,
    /// Scroll Lock.
    Scroll,
    /// Pause/Break key, next to Scroll lock.
    Pause,

    /// `Insert`, next to Backspace.
    Insert,
    Home,
    Delete,
    End,
    PageDown,
    PageUp,

    Left,
    Up,
    Right,
    Down,

    /// The Backspace key, right over Enter.
    // TODO: rename
    Back,
    /// The Enter key.
    Return,
    /// The space bar.
    Space,

    Numlock,
    Numpad0,
    Numpad1,
    Numpad2,
    Numpad3,
    Numpad4,
    Numpad5,
    Numpad6,
    Numpad7,
    Numpad8,
    Numpad9,

    AbntC1,
    AbntC2,
    Add,
    Apostrophe,
    Apps,
    At,
    Ax,
    Backslash,
    Calculator,
    Capital,
    Colon,
    Comma,
    Convert,
    Decimal,
    Divide,
    Equals,
    Grave,
    Kana,
    Kanji,
    LAlt,
    LBracket,
    LControl,
    LMenu,
    LShift,
    LWin,
    Mail,
    MediaSelect,
    MediaStop,
    Minus,
    Multiply,
    Mute,
    MyComputer,
    NextTrack,
    NoConvert,
    NumpadComma,
    NumpadEnter,
    NumpadEquals,
    OEM102,
    Period,
    PlayPause,
    Power,
    PrevTrack,
    RAlt,
    RBracket,
    RControl,
    RMenu,
    RShift,
    RWin,
    Semicolon,
    Slash,
    Sleep,
    Stop,
    Subtract,
    Sysrq,
    Tab,
    Underline,
    Unlabeled,
    VolumeDown,
    VolumeUp,
    Wake,
    WebBack,
    WebFavorites,
    WebForward,
    WebHome,
    WebRefresh,
    WebSearch,
    WebStop,
    Yen,
}
<commit_msg>Update events.rs<commit_after>use std::path::PathBuf;

#[derive(Clone, Debug)]
pub enum Event {
    /// The size of the window has changed.
    Resized(u32, u32),

    /// The position of the window has changed.
    Moved(i32, i32),

    /// The window has been closed.
    Closed,

    /// A file has been dropped into the window.
    DroppedFile(PathBuf),

    /// The window received a unicode character.
    ReceivedCharacter(char),

    /// The window gained or lost focus.
    ///
    /// The parameter is true if the window has gained focus, and false if it has lost focus.
    Focused(bool),

    /// An event from the keyboard has been received.
    KeyboardInput(ElementState, ScanCode, Option<VirtualKeyCode>),

    /// The cursor has moved on the window.
    ///
    /// The parameter are the (x,y) coords in pixels relative to the top-left corner of the window.
    MouseMoved((i32, i32)),

    /// A mouse wheel movement or touchpad scroll occurred.
    MouseWheel(MouseScrollDelta),

    /// An event from the mouse has been received.
    MouseInput(ElementState, MouseButton),

    /// The event loop was woken up by another thread.
    Awakened,

    /// The window needs to be redrawn.
    Refresh,

    /// App has been suspended or resumed.
    ///
    /// The parameter is true if app was suspended, and false if it has been resumed.
    Suspended(bool),

    /// Touch event has been received
    Touch(Touch)
}

#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum TouchPhase {
    Started,
    Moved,
    Ended,
    Cancelled
}

#[derive(Debug, Clone, Copy)]
/// Represents touch event
///
/// Every time user touches screen new Start event with some finger id is generated.
/// When the finger is removed from the screen End event with same id is generated.
///
/// For every id there will be at least 2 events with phases Start and End (or Cancelled).
/// There may be 0 or more Move events.
///
///
/// Depending on platform implementation id may or may not be reused by system after End event.
///
/// Gesture regonizer using this event should assume that Start event received with same id
/// as previously received End event is a new finger and has nothing to do with an old one.
///
/// Touch may be cancelled if for example window lost focus.
pub struct Touch {
    pub phase: TouchPhase,
    pub location: (f64,f64),
    /// unique identifier of a finger.
    pub id: u64
}

pub type ScanCode = u8;

#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum ElementState {
    Pressed,
    Released,
}

#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum MouseButton {
    Left,
    Right,
    Middle,
    Other(u8),
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum MouseScrollDelta {
	/// Amount in lines or rows to scroll in the horizontal
	/// and vertical directions.
	///
	/// Positive values indicate movement forward
	/// (away from the user) or rightwards.
	LineDelta(f32, f32),
	/// Amount in pixels to scroll in the horizontal and
	/// vertical direction.
	///
	/// Scroll events are expressed as a PixelDelta if
	/// supported by the device (eg. a touchpad) and
	/// platform.
	PixelDelta(f32, f32)
}

#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum VirtualKeyCode {
    /// The '1' key over the letters.
    Key1,
    /// The '2' key over the letters.
    Key2,
    /// The '3' key over the letters.
    Key3,
    /// The '4' key over the letters.
    Key4,
    /// The '5' key over the letters.
    Key5,
    /// The '6' key over the letters.
    Key6,
    /// The '7' key over the letters.
    Key7,
    /// The '8' key over the letters.
    Key8,
    /// The '9' key over the letters.
    Key9,
    /// The '0' key over the 'O' and 'P' keys.
    Key0,

    A,
    B,
    C,
    D,
    E,
    F,
    G,
    H,
    I,
    J,
    K,
    L,
    M,
    N,
    O,
    P,
    Q,
    R,
    S,
    T,
    U,
    V,
    W,
    X,
    Y,
    Z,

    /// The Escape key, next to F1.
    Escape,

    F1,
    F2,
    F3,
    F4,
    F5,
    F6,
    F7,
    F8,
    F9,
    F10,
    F11,
    F12,
    F13,
    F14,
    F15,

    /// Print Screen/SysRq.
    Snapshot,
    /// Scroll Lock.
    Scroll,
    /// Pause/Break key, next to Scroll lock.
    Pause,

    /// `Insert`, next to Backspace.
    Insert,
    Home,
    Delete,
    End,
    PageDown,
    PageUp,

    Left,
    Up,
    Right,
    Down,

    /// The Backspace key, right over Enter.
    // TODO: rename
    Back,
    /// The Enter key.
    Return,
    /// The space bar.
    Space,

    Numlock,
    Numpad0,
    Numpad1,
    Numpad2,
    Numpad3,
    Numpad4,
    Numpad5,
    Numpad6,
    Numpad7,
    Numpad8,
    Numpad9,

    AbntC1,
    AbntC2,
    Add,
    Apostrophe,
    Apps,
    At,
    Ax,
    Backslash,
    Calculator,
    Capital,
    Colon,
    Comma,
    Convert,
    Decimal,
    Divide,
    Equals,
    Grave,
    Kana,
    Kanji,
    LAlt,
    LBracket,
    LControl,
    LMenu,
    LShift,
    LWin,
    Mail,
    MediaSelect,
    MediaStop,
    Minus,
    Multiply,
    Mute,
    MyComputer,
    NextTrack,
    NoConvert,
    NumpadComma,
    NumpadEnter,
    NumpadEquals,
    OEM102,
    Period,
    PlayPause,
    Power,
    PrevTrack,
    RAlt,
    RBracket,
    RControl,
    RMenu,
    RShift,
    RWin,
    Semicolon,
    Slash,
    Sleep,
    Stop,
    Subtract,
    Sysrq,
    Tab,
    Underline,
    Unlabeled,
    VolumeDown,
    VolumeUp,
    Wake,
    WebBack,
    WebFavorites,
    WebForward,
    WebHome,
    WebRefresh,
    WebSearch,
    WebStop,
    Yen,
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};

// We first look for corners that are connected by a straight uninterrupted line.
// At the same time we make a note for each corner in which direction it's connected.
//
// Later we simply scan over the corners, pairing each top-left with each right-bottom corner
// (provided it's to the right and below the top-left corner) and look if all four lines
// of the rectangle exist.
//
// To simplify scanning for lines and points we run the horizontal lines algorithm on a
// seemingly transposed version of the input and later transpose the results again.

// Note: values of these constants are used in transposition, they're not random.
const CONN_LEFT: u8 = 0x1;
const CONN_RIGHT: u8 = 0x2;
const CONN_UP: u8 = 0x4;
const CONN_DOWN: u8 = 0x8;

#[derive(PartialEq, Eq, Hash)]
struct Point {
    x: usize,
    y: usize
}

#[derive(PartialEq, Eq, Hash)]
struct Line {
    x1: usize,
    y1: usize,
    x2: usize,
    y2: usize
}

#[derive(PartialEq, Eq, Clone, Copy)]
enum Symbol {
    Corner, // '+'
    Connect, // '|' or '-' depending on direction
    Other // ' ', or anything really
}

// The input area.
struct RealArea {
    width: usize,
    height: usize,
    chars: Vec<Vec<char>>
}

trait Area {
    fn width(&self) -> usize;
    fn height(&self) -> usize;
    fn symbol_at(&self, x: usize, y: usize) -> Symbol;
}

// For horizontal scanning
impl Area for RealArea {
    fn width(&self) -> usize { self.width }
    fn height(&self) -> usize { self.height }
    fn symbol_at(&self, x: usize, y: usize) -> Symbol {
        match self.chars[y][x] {
            '+' => Symbol::Corner,
            '-' => Symbol::Connect,
            _ => Symbol::Other
        }
    }
}

struct TransposedArea<'a>(&'a RealArea);

// For vertical scanning
impl<'a> Area for TransposedArea<'a> {
    fn width(&self) -> usize { self.0.height }
    fn height(&self) -> usize { self.0.width }
    fn symbol_at(&self, x: usize, y: usize) -> Symbol {
        match self.0.chars[x][y] {
            '+' => Symbol::Corner,
            '|' => Symbol::Connect,
            _ => Symbol::Other
        }
    }
}

// Information about connections.
struct Connections {
    lines: HashSet<Line>,
    points: HashMap<Point, u8>
}

pub fn count(lines: &Vec<&str>) -> usize {
    if lines.len() == 0 {
        return 0
    } else if lines[0].len() == 0 {
        return 0
    }
    let area = RealArea {
        width: lines[0].len(),
        height: lines.len(),
        chars: lines.iter().map(|line| line.chars().collect()).collect()
    };
    let area_transposed = TransposedArea(&area);
    let mut conns = scan_connected(&area);
    let conns_transposed = scan_connected(&area_transposed);

    // The transposed connections have their coordinate system wrong,
    // correct this.
    for l in conns_transposed.lines {
        conns.lines.insert(Line{x1: l.y1, y1: l.x1, x2: l.y2, y2: l.x2});
    }
    for (p, tcf) in conns_transposed.points {
        let cf = conns.points.entry(Point{x: p.y, y: p.x}).or_insert(0);
        *cf = *cf | (tcf << 2)
    }

    let mut total = 0;
    for (tl_p, tl_cf) in conns.points.iter() { // top left point and connection flags
        if tl_cf & (CONN_RIGHT|CONN_DOWN) == CONN_RIGHT|CONN_DOWN {
            for (br_p, br_cf) in conns.points.iter() {
                // left, right, top, bottom of potential rectangle
                let l = tl_p.x;
                let r = br_p.x;
                let t = tl_p.y;
                let b = br_p.y;
                let is_rect =
                    br_cf & (CONN_LEFT|CONN_UP) == CONN_LEFT|CONN_UP &&
                    r > l && b > t &&
                    conns.lines.contains(&Line{x1: l, y1: t, x2: l, y2: b}) &&
                    conns.lines.contains(&Line{x1: l, y1: t, x2: r, y2: t}) &&
                    conns.lines.contains(&Line{x1: l, y1: b, x2: r, y2: b}) &&
                    conns.lines.contains(&Line{x1: r, y1: t, x2: r, y2: b});
                if is_rect {
                    total += 1
                }
            }
        }
    }
    return total;
}

fn scan_connected(area: &Area) -> Connections {
    let mut conns = Connections{
        lines: HashSet::new(),
        points: HashMap::new()
    };
    let mut connected: Vec<usize> = vec![];
    for y in 0..area.height() {
        connected.clear();
        for x in 0..area.width() {
            let sym = area.symbol_at(x, y);
            if sym == Symbol::Corner {
                for prev in connected.iter() {
                    conns.lines.insert(Line{x1: prev.clone(), y1: y, x2: x, y2: y});
                }
                if let Some(last) = connected.last() {
                    let cf = conns.points.get_mut(&Point{x: last.clone(), y: y}).unwrap();
                    *cf = *cf | CONN_RIGHT;
                }
                let cf = conns.points.entry(Point{x: x, y: y}).or_insert(0);
                if connected.len() > 0 {
                    *cf = *cf | CONN_LEFT;
                }
                connected.push(x);
            } else if sym != Symbol::Connect {
                connected.clear(); // End of connected bit.
            }
        }
    }
    conns
}
<commit_msg>rectangles: Use &[T] instead of &Vec<T> for signatures<commit_after>use std::collections::{HashMap, HashSet};

// We first look for corners that are connected by a straight uninterrupted line.
// At the same time we make a note for each corner in which direction it's connected.
//
// Later we simply scan over the corners, pairing each top-left with each right-bottom corner
// (provided it's to the right and below the top-left corner) and look if all four lines
// of the rectangle exist.
//
// To simplify scanning for lines and points we run the horizontal lines algorithm on a
// seemingly transposed version of the input and later transpose the results again.

// Note: values of these constants are used in transposition, they're not random.
const CONN_LEFT: u8 = 0x1;
const CONN_RIGHT: u8 = 0x2;
const CONN_UP: u8 = 0x4;
const CONN_DOWN: u8 = 0x8;

#[derive(PartialEq, Eq, Hash)]
struct Point {
    x: usize,
    y: usize
}

#[derive(PartialEq, Eq, Hash)]
struct Line {
    x1: usize,
    y1: usize,
    x2: usize,
    y2: usize
}

#[derive(PartialEq, Eq, Clone, Copy)]
enum Symbol {
    Corner, // '+'
    Connect, // '|' or '-' depending on direction
    Other // ' ', or anything really
}

// The input area.
struct RealArea {
    width: usize,
    height: usize,
    chars: Vec<Vec<char>>
}

trait Area {
    fn width(&self) -> usize;
    fn height(&self) -> usize;
    fn symbol_at(&self, x: usize, y: usize) -> Symbol;
}

// For horizontal scanning
impl Area for RealArea {
    fn width(&self) -> usize { self.width }
    fn height(&self) -> usize { self.height }
    fn symbol_at(&self, x: usize, y: usize) -> Symbol {
        match self.chars[y][x] {
            '+' => Symbol::Corner,
            '-' => Symbol::Connect,
            _ => Symbol::Other
        }
    }
}

struct TransposedArea<'a>(&'a RealArea);

// For vertical scanning
impl<'a> Area for TransposedArea<'a> {
    fn width(&self) -> usize { self.0.height }
    fn height(&self) -> usize { self.0.width }
    fn symbol_at(&self, x: usize, y: usize) -> Symbol {
        match self.0.chars[x][y] {
            '+' => Symbol::Corner,
            '|' => Symbol::Connect,
            _ => Symbol::Other
        }
    }
}

// Information about connections.
struct Connections {
    lines: HashSet<Line>,
    points: HashMap<Point, u8>
}

pub fn count(lines: &[&str]) -> usize {
    if lines.len() == 0 {
        return 0
    } else if lines[0].len() == 0 {
        return 0
    }
    let area = RealArea {
        width: lines[0].len(),
        height: lines.len(),
        chars: lines.iter().map(|line| line.chars().collect()).collect()
    };
    let area_transposed = TransposedArea(&area);
    let mut conns = scan_connected(&area);
    let conns_transposed = scan_connected(&area_transposed);

    // The transposed connections have their coordinate system wrong,
    // correct this.
    for l in conns_transposed.lines {
        conns.lines.insert(Line{x1: l.y1, y1: l.x1, x2: l.y2, y2: l.x2});
    }
    for (p, tcf) in conns_transposed.points {
        let cf = conns.points.entry(Point{x: p.y, y: p.x}).or_insert(0);
        *cf = *cf | (tcf << 2)
    }

    let mut total = 0;
    for (tl_p, tl_cf) in conns.points.iter() { // top left point and connection flags
        if tl_cf & (CONN_RIGHT|CONN_DOWN) == CONN_RIGHT|CONN_DOWN {
            for (br_p, br_cf) in conns.points.iter() {
                // left, right, top, bottom of potential rectangle
                let l = tl_p.x;
                let r = br_p.x;
                let t = tl_p.y;
                let b = br_p.y;
                let is_rect =
                    br_cf & (CONN_LEFT|CONN_UP) == CONN_LEFT|CONN_UP &&
                    r > l && b > t &&
                    conns.lines.contains(&Line{x1: l, y1: t, x2: l, y2: b}) &&
                    conns.lines.contains(&Line{x1: l, y1: t, x2: r, y2: t}) &&
                    conns.lines.contains(&Line{x1: l, y1: b, x2: r, y2: b}) &&
                    conns.lines.contains(&Line{x1: r, y1: t, x2: r, y2: b});
                if is_rect {
                    total += 1
                }
            }
        }
    }
    return total;
}

fn scan_connected(area: &Area) -> Connections {
    let mut conns = Connections{
        lines: HashSet::new(),
        points: HashMap::new()
    };
    let mut connected: Vec<usize> = vec![];
    for y in 0..area.height() {
        connected.clear();
        for x in 0..area.width() {
            let sym = area.symbol_at(x, y);
            if sym == Symbol::Corner {
                for prev in connected.iter() {
                    conns.lines.insert(Line{x1: prev.clone(), y1: y, x2: x, y2: y});
                }
                if let Some(last) = connected.last() {
                    let cf = conns.points.get_mut(&Point{x: last.clone(), y: y}).unwrap();
                    *cf = *cf | CONN_RIGHT;
                }
                let cf = conns.points.entry(Point{x: x, y: y}).or_insert(0);
                if connected.len() > 0 {
                    *cf = *cf | CONN_LEFT;
                }
                connected.push(x);
            } else if sym != Symbol::Connect {
                connected.clear(); // End of connected bit.
            }
        }
    }
    conns
}
<|endoftext|>


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

use crypto::Hash;
use messages::{Precommit, RawMessage};
use storage::{Fork, ListIndex, MapIndex, MapProof, ProofListIndex, ProofMapIndex, Snapshot,
              StorageKey, StorageValue};
use helpers::Height;
use super::{Block, BlockProof, Blockchain};
use super::config::StoredConfiguration;

/// Generates an array of bytes from the `prefix`.
pub fn gen_prefix<K: StorageKey>(prefix: &K) -> Vec<u8> {
    let mut res = vec![0; prefix.size()];
    prefix.write(&mut res[..]);
    res
}

encoding_struct! (
    /// Configuration index.
    struct ConfigReference {
        const SIZE = 40;
        /// The height, starting from which this configuration becomes actual.
        field actual_from: Height [00 => 08]
        /// Hash of the configuration contents that serialized as raw bytes vec.
        field cfg_hash:    &Hash  [08 => 40]
    }
);

encoding_struct! (
    /// Transaction location in block.
    struct TxLocation {
        const SIZE = 16;
        /// Height of block in the blockchain.
        field block_height:         Height  [00 => 08]
        /// Index in block.
        field position_in_block:    u64     [08 => 16]
    }
);

/// Information schema for `exonum-core`.
#[derive(Debug)]
pub struct Schema<T> {
    view: T,
}

impl<T> Schema<T>
where
    T: AsRef<Snapshot>,
{
    /// Constructs information schema for the given `snapshot`.
    pub fn new(snapshot: T) -> Schema<T> {
        Schema { view: snapshot }
    }

    /// Returns table that represents a map from transaction hash into raw transaction message.
    pub fn transactions(&self) -> MapIndex<&T, Hash, RawMessage> {
        MapIndex::new("core.transactions", &self.view)
    }

    /// Returns table that keeps the block height and tx position inside block for every
    /// transaction hash.
    pub fn tx_location_by_tx_hash(&self) -> MapIndex<&T, Hash, TxLocation> {
        MapIndex::new("core.tx_location_by_tx_hash", &self.view)
    }

    /// Returns table that stores block object for every block height.
    pub fn blocks(&self) -> MapIndex<&T, Hash, Block> {
        MapIndex::new("core.blocks", &self.view)
    }

    /// Returns table that keeps block hash for the corresponding height.
    pub fn block_hashes_by_height(&self) -> ListIndex<&T, Hash> {
        ListIndex::new("core.block_hashes_by_height", &self.view)
    }

    /// Returns table that keeps a list of transactions for the each block.
    pub fn block_txs(&self, height: Height) -> ProofListIndex<&T, Hash> {
        let height: u64 = height.into();
        ProofListIndex::with_prefix("core.block_txs", gen_prefix(&height), &self.view)
    }

    /// Returns table that saves a list of precommits for block with given hash.
    pub fn precommits(&self, hash: &Hash) -> ListIndex<&T, Precommit> {
        ListIndex::with_prefix("core.precommits", gen_prefix(hash), &self.view)
    }

    /// Returns table that represents a map from configuration hash into contents.
    pub fn configs(&self) -> ProofMapIndex<&T, Hash, StoredConfiguration> {
        // configs patricia merkletree <block height> json
        ProofMapIndex::new("core.configs", &self.view)
    }

    /// Returns auxiliary table that keeps hash references to configurations in order
    /// of increasing their `actual_from` height.
    pub fn configs_actual_from(&self) -> ListIndex<&T, ConfigReference> {
        ListIndex::new("core.configs_actual_from", &self.view)
    }

    /// Returns the accessory `ProofMapIndex` for calculating
    /// patches in the DBView layer.
    ///
    /// Table calculates "aggregation" of root hashes of individual
    /// service tables, in effect summing the state of various entities,
    /// scattered across distinct services and their tables. Sum is performed by
    /// means of computing root hash of this table.
    ///
    /// - Table **key** is 32 bytes of normalized coordinates of a service
    /// table, as returned by `service_table_unique_key` helper function.
    /// - Table **value** is root hash of a service table, which contributes
    /// to the resulting block's `state_hash`.
    ///
    /// Core tables participate in resulting state_hash with `CORE_SERVICE`
    /// service_id. Their vector is returned by `core_state_hash` method.
    pub fn state_hash_aggregator(&self) -> ProofMapIndex<&T, Hash, Hash> {
        ProofMapIndex::new("core.state_hash_aggregator", &self.view)
    }

    /// Returns block hash for the given height.
    pub fn block_hash_by_height(&self, height: Height) -> Option<Hash> {
        self.block_hashes_by_height().get(height.into())
    }

    /// Returns the block for the given height with the proof of its inclusion.
    pub fn block_and_precommits(&self, height: Height) -> Option<BlockProof> {
        let block_hash = match self.block_hash_by_height(height) {
            None => return None,
            Some(block_hash) => block_hash,
        };
        let block = self.blocks().get(&block_hash).unwrap();
        let precommits_table = self.precommits(&block_hash);
        let precommits = precommits_table.iter().collect();
        let res = BlockProof { block, precommits };
        Some(res)
    }

    /// Returns latest committed block.
    ///
    /// # Panics
    /// - If the "genesis block" was not created.
    pub fn last_block(&self) -> Block {
        let hash = self.block_hashes_by_height().last().expect(
            "An attempt to get the `last_block` during creating the genesis block.",
        );
        self.blocks().get(&hash).unwrap()
    }

    /// Returns height of the latest committed block.
    ///
    /// # Panics
    /// - If the "genesis block" was not created.
    pub fn height(&self) -> Height {
        let len = self.block_hashes_by_height().len();
        assert!(
            len > 0,
            "An attempt to get the actual `height` during creating the genesis block."
        );
        Height(len - 1)
    }

    /// Returns configuration for the latest height of blockchain.
    ///
    /// # Panics
    /// - If the "genesis block" was not created.
    pub fn actual_configuration(&self) -> StoredConfiguration {
        let next_height = self.next_height();
        let res = self.configuration_by_height(next_height);
        trace!("Retrieved actual_config: {:?}", res);
        res
    }

    /// Returns the nearest following configuration if it exists.
    pub fn following_configuration(&self) -> Option<StoredConfiguration> {
        let next_height = self.next_height();
        let idx = self.find_configurations_index_by_height(next_height);
        match self.configs_actual_from().get(idx + 1) {
            Some(cfg_ref) => {
                let cfg_hash = cfg_ref.cfg_hash();
                let cfg = self.configuration_by_hash(cfg_hash).expect(&format!(
                    "Config with hash {:?} is absent in configs table",
                    cfg_hash
                ));
                Some(cfg)
            }
            None => None,
        }
    }

    /// Returns the previous configuration if it exists.
    pub fn previous_configuration(&self) -> Option<StoredConfiguration> {
        let next_height = self.next_height();
        let idx = self.find_configurations_index_by_height(next_height);
        if idx > 0 {
            let cfg_ref = self.configs_actual_from().get(idx - 1).expect(&format!(
                "Configuration at index {} not found",
                idx
            ));
            let cfg_hash = cfg_ref.cfg_hash();
            let cfg = self.configuration_by_hash(cfg_hash).expect(&format!(
                "Config with hash {:?} is absent in configs table",
                cfg_hash
            ));
            Some(cfg)
        } else {
            None
        }
    }

    /// Returns the configuration that is the actual for the given height.
    pub fn configuration_by_height(&self, height: Height) -> StoredConfiguration {
        let idx = self.find_configurations_index_by_height(height);
        let cfg_ref = self.configs_actual_from().get(idx).expect(&format!(
            "Configuration at index {} not found",
            idx
        ));
        let cfg_hash = cfg_ref.cfg_hash();
        self.configuration_by_hash(cfg_hash).expect(&format!(
            "Config with hash {:?} is absent in configs table",
            cfg_hash
        ))
    }

    /// Returns configuration for given configuration hash.
    pub fn configuration_by_hash(&self, hash: &Hash) -> Option<StoredConfiguration> {
        self.configs().get(hash)
    }

    /// Returns the `state_hash` table for core tables.
    pub fn core_state_hash(&self) -> Vec<Hash> {
        vec![self.configs().root_hash()]
    }

    /// Constructs a proof of inclusion of root hash of a specific service
    /// table into block's `state_hash`.
    ///
    /// Searched key for proof is uniquely identified by (`u16`, `u16`) tuple
    /// of table's coordinates.
    ///
    /// If found, root hash is returned as a value of proof's leaf
    /// corresponding to searched key. Otherwise, partial path to searched key
    /// is returned, which proves its exclusion.
    ///
    /// The returned proof is used as a component of proof of state of any
    /// entity, stored in `exonum` db at specific height, as identified
    /// by corresponding block's `state_hash`. State of some meta tables
    /// of core and services isn't tracked.
    ///
    /// # Arguments
    ///
    /// * `service_id` - `service_id` as returned by instance of type of
    /// `Service` trait
    /// * `table_idx` - index of service table in `Vec`, returned by
    /// `state_hash` method of instance of type of `Service` trait
    pub fn get_proof_to_service_table(&self, service_id: u16, table_idx: usize) -> MapProof<Hash> {
        let key = Blockchain::service_table_unique_key(service_id, table_idx);
        let sum_table = self.state_hash_aggregator();
        sum_table.get_proof(&key)
    }

    fn find_configurations_index_by_height(&self, height: Height) -> u64 {
        let actual_from = self.configs_actual_from();
        for i in (0..actual_from.len()).rev() {
            if actual_from.get(i).unwrap().actual_from() <= height {
                return i as u64;
            }
        }
        panic!(
            "Couldn't not find any config for height {}, \
             that means that genesis block was created incorrectly.",
            height
        )
    }

    fn next_height(&self) -> Height {
        Height(self.block_hashes_by_height().len())
    }
}

impl<'a> Schema<&'a mut Fork> {
    /// Mutable reference to the [`transactions`][1] index.
    ///
    /// [1]: struct.Schema.html#method.transactions
    pub fn transactions_mut(&mut self) -> MapIndex<&mut Fork, Hash, RawMessage> {
        MapIndex::new("core.transactions", &mut self.view)
    }

    /// Mutable reference to the [`tx_location_by_tx_hash`][1] index.
    ///
    /// [1]: struct.Schema.html#method.tx_location_by_tx_hash
    pub fn tx_location_by_tx_hash_mut(&mut self) -> MapIndex<&mut Fork, Hash, TxLocation> {
        MapIndex::new("core.tx_location_by_tx_hash", &mut self.view)
    }

    /// Mutable reference to the [`blocks][1] index.
    ///
    /// [1]: struct.Schema.html#method.blocks
    pub fn blocks_mut(&mut self) -> MapIndex<&mut Fork, Hash, Block> {
        MapIndex::new("core.blocks", &mut self.view)
    }

    /// Mutable reference to the [`block_hashes_by_height_mut`][1] index.
    ///
    /// [1]: struct.Schema.html#method.block_hashes_by_height_mut
    pub fn block_hashes_by_height_mut(&mut self) -> ListIndex<&mut Fork, Hash> {
        ListIndex::new("core.block_hashes_by_height", &mut self.view)
    }

    /// Mutable reference to the [`block_hash_by_height`][1] index.
    ///
    /// [1]: struct.Schema.html#method.block_hash_by_height
    pub fn block_hash_by_height_mut(&mut self, height: Height) -> Option<Hash> {
        self.block_hashes_by_height().get(height.into())
    }

    /// Mutable reference to the [`block_txs`][1] index.
    ///
    /// [1]: struct.Schema.html#method.block_txs
    pub fn block_txs_mut(&mut self, height: Height) -> ProofListIndex<&mut Fork, Hash> {
        let height: u64 = height.into();
        ProofListIndex::with_prefix("core.block_txs", gen_prefix(&height), &mut self.view)
    }

    /// Mutable reference to the [`precommits`][1] index.
    ///
    /// [1]: struct.Schema.html#method.precommits
    pub fn precommits_mut(&mut self, hash: &Hash) -> ListIndex<&mut Fork, Precommit> {
        ListIndex::with_prefix("core.precommits", gen_prefix(hash), &mut self.view)
    }

    /// Mutable reference to the [`configs`][1] index.
    ///
    /// [1]: struct.Schema.html#method.configs
    pub fn configs_mut(&mut self) -> ProofMapIndex<&mut Fork, Hash, StoredConfiguration> {
        ProofMapIndex::new("core.configs", &mut self.view)
    }

    /// Mutable reference to the [`configs_actual_from`][1] index.
    ///
    /// [1]: struct.Schema.html#method.configs_actual_from
    pub fn configs_actual_from_mut(&mut self) -> ListIndex<&mut Fork, ConfigReference> {
        ListIndex::new("core.configs_actual_from", &mut self.view)
    }

    /// Mutable reference to the [`state_hash_aggregator`][1] index.
    ///
    /// [1]: struct.Schema.html#method.state_hash_aggregator
    pub fn state_hash_aggregator_mut(&mut self) -> ProofMapIndex<&mut Fork, Hash, Hash> {
        ProofMapIndex::new("core.state_hash_aggregator", &mut self.view)
    }

    /// Adds a new configuration to the blockchain, which will become an actual at
    /// the `actual_from` height in `config_data`.
    pub fn commit_configuration(&mut self, config_data: StoredConfiguration) {
        let actual_from = config_data.actual_from;
        if let Some(last_cfg) = self.configs_actual_from().last() {
            if last_cfg.cfg_hash() != &config_data.previous_cfg_hash {
                // TODO: Replace panic with errors (ECR-123).
                panic!(
                    "Attempting to commit configuration with incorrect previous hash: {:?}, \
                     expected: {:?}",
                    config_data.previous_cfg_hash,
                    last_cfg.cfg_hash()
                );
            }

            if actual_from <= last_cfg.actual_from() {
                panic!(
                    "Attempting to commit configuration with actual_from {} less than the last \
                     committed the last committed actual_from {}",
                    actual_from,
                    last_cfg.actual_from()
                );
            }
        }

        info!(
            "Scheduled the following configuration for acceptance: {:?}",
            &config_data
        );

        let cfg_hash = config_data.hash();
        self.configs_mut().put(&cfg_hash, config_data);

        let cfg_ref = ConfigReference::new(actual_from, &cfg_hash);
        self.configs_actual_from_mut().push(cfg_ref);
        // TODO: clear storages
    }
}
<commit_msg>Rephrase doc comment<commit_after>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crypto::Hash;
use messages::{Precommit, RawMessage};
use storage::{Fork, ListIndex, MapIndex, MapProof, ProofListIndex, ProofMapIndex, Snapshot,
              StorageKey, StorageValue};
use helpers::Height;
use super::{Block, BlockProof, Blockchain};
use super::config::StoredConfiguration;

/// Generates an array of bytes from the `prefix`.
pub fn gen_prefix<K: StorageKey>(prefix: &K) -> Vec<u8> {
    let mut res = vec![0; prefix.size()];
    prefix.write(&mut res[..]);
    res
}

encoding_struct! (
    /// Configuration index.
    struct ConfigReference {
        const SIZE = 40;
        /// The height, starting from which this configuration becomes actual.
        field actual_from: Height [00 => 08]
        /// Hash of the configuration contents that serialized as raw bytes vec.
        field cfg_hash:    &Hash  [08 => 40]
    }
);

encoding_struct! (
    /// Transaction location in block.
    struct TxLocation {
        const SIZE = 16;
        /// Height of block in the blockchain.
        field block_height:         Height  [00 => 08]
        /// Index in block.
        field position_in_block:    u64     [08 => 16]
    }
);

/// Information schema for `exonum-core`.
#[derive(Debug)]
pub struct Schema<T> {
    view: T,
}

impl<T> Schema<T>
where
    T: AsRef<Snapshot>,
{
    /// Constructs information schema for the given `snapshot`.
    pub fn new(snapshot: T) -> Schema<T> {
        Schema { view: snapshot }
    }

    /// Returns table that represents a map from transaction hash into raw transaction message.
    pub fn transactions(&self) -> MapIndex<&T, Hash, RawMessage> {
        MapIndex::new("core.transactions", &self.view)
    }

    /// Returns table that keeps the block height and tx position inside block for every
    /// transaction hash.
    pub fn tx_location_by_tx_hash(&self) -> MapIndex<&T, Hash, TxLocation> {
        MapIndex::new("core.tx_location_by_tx_hash", &self.view)
    }

    /// Returns table that stores block object for every block height.
    pub fn blocks(&self) -> MapIndex<&T, Hash, Block> {
        MapIndex::new("core.blocks", &self.view)
    }

    /// Returns table that keeps block hash for the corresponding height.
    pub fn block_hashes_by_height(&self) -> ListIndex<&T, Hash> {
        ListIndex::new("core.block_hashes_by_height", &self.view)
    }

    /// Returns table that keeps a list of transactions for the each block.
    pub fn block_txs(&self, height: Height) -> ProofListIndex<&T, Hash> {
        let height: u64 = height.into();
        ProofListIndex::with_prefix("core.block_txs", gen_prefix(&height), &self.view)
    }

    /// Returns table that saves a list of precommits for block with given hash.
    pub fn precommits(&self, hash: &Hash) -> ListIndex<&T, Precommit> {
        ListIndex::with_prefix("core.precommits", gen_prefix(hash), &self.view)
    }

    /// Returns table that represents a map from configuration hash into contents.
    pub fn configs(&self) -> ProofMapIndex<&T, Hash, StoredConfiguration> {
        // configs patricia merkletree <block height> json
        ProofMapIndex::new("core.configs", &self.view)
    }

    /// Returns auxiliary table that keeps hash references to configurations in order
    /// of increasing their `actual_from` height.
    pub fn configs_actual_from(&self) -> ListIndex<&T, ConfigReference> {
        ListIndex::new("core.configs_actual_from", &self.view)
    }

    /// Returns the accessory `ProofMapIndex` for calculating
    /// patches in the DBView layer.
    ///
    /// Table calculates "aggregation" of root hashes of individual
    /// service tables, in effect summing the state of various entities,
    /// scattered across distinct services and their tables. Sum is performed by
    /// means of computing root hash of this table.
    ///
    /// - Table **key** is 32 bytes of normalized coordinates of a service
    /// table, as returned by `service_table_unique_key` helper function.
    /// - Table **value** is root hash of a service table, which contributes
    /// to the resulting block's `state_hash`.
    ///
    /// Core tables participate in resulting state_hash with `CORE_SERVICE`
    /// service_id. Their vector is returned by `core_state_hash` method.
    pub fn state_hash_aggregator(&self) -> ProofMapIndex<&T, Hash, Hash> {
        ProofMapIndex::new("core.state_hash_aggregator", &self.view)
    }

    /// Returns block hash for the given height.
    pub fn block_hash_by_height(&self, height: Height) -> Option<Hash> {
        self.block_hashes_by_height().get(height.into())
    }

    /// Returns the block for the given height with the proof of its inclusion.
    pub fn block_and_precommits(&self, height: Height) -> Option<BlockProof> {
        let block_hash = match self.block_hash_by_height(height) {
            None => return None,
            Some(block_hash) => block_hash,
        };
        let block = self.blocks().get(&block_hash).unwrap();
        let precommits_table = self.precommits(&block_hash);
        let precommits = precommits_table.iter().collect();
        let res = BlockProof { block, precommits };
        Some(res)
    }

    /// Returns latest committed block.
    ///
    /// # Panics
    /// - If the "genesis block" was not created.
    pub fn last_block(&self) -> Block {
        let hash = self.block_hashes_by_height().last().expect(
            "An attempt to get the `last_block` during creating the genesis block.",
        );
        self.blocks().get(&hash).unwrap()
    }

    /// Returns height of the latest committed block.
    ///
    /// # Panics
    ///
    /// Panics if the "genesis block" was not created.
    pub fn height(&self) -> Height {
        let len = self.block_hashes_by_height().len();
        assert!(
            len > 0,
            "An attempt to get the actual `height` during creating the genesis block."
        );
        Height(len - 1)
    }

    /// Returns configuration for the latest height of blockchain.
    ///
    /// # Panics
    ///
    /// Panics if the "genesis block" was not created.
    pub fn actual_configuration(&self) -> StoredConfiguration {
        let next_height = self.next_height();
        let res = self.configuration_by_height(next_height);
        trace!("Retrieved actual_config: {:?}", res);
        res
    }

    /// Returns the nearest following configuration if it exists.
    pub fn following_configuration(&self) -> Option<StoredConfiguration> {
        let next_height = self.next_height();
        let idx = self.find_configurations_index_by_height(next_height);
        match self.configs_actual_from().get(idx + 1) {
            Some(cfg_ref) => {
                let cfg_hash = cfg_ref.cfg_hash();
                let cfg = self.configuration_by_hash(cfg_hash).expect(&format!(
                    "Config with hash {:?} is absent in configs table",
                    cfg_hash
                ));
                Some(cfg)
            }
            None => None,
        }
    }

    /// Returns the previous configuration if it exists.
    pub fn previous_configuration(&self) -> Option<StoredConfiguration> {
        let next_height = self.next_height();
        let idx = self.find_configurations_index_by_height(next_height);
        if idx > 0 {
            let cfg_ref = self.configs_actual_from().get(idx - 1).expect(&format!(
                "Configuration at index {} not found",
                idx
            ));
            let cfg_hash = cfg_ref.cfg_hash();
            let cfg = self.configuration_by_hash(cfg_hash).expect(&format!(
                "Config with hash {:?} is absent in configs table",
                cfg_hash
            ));
            Some(cfg)
        } else {
            None
        }
    }

    /// Returns the configuration that is the actual for the given height.
    pub fn configuration_by_height(&self, height: Height) -> StoredConfiguration {
        let idx = self.find_configurations_index_by_height(height);
        let cfg_ref = self.configs_actual_from().get(idx).expect(&format!(
            "Configuration at index {} not found",
            idx
        ));
        let cfg_hash = cfg_ref.cfg_hash();
        self.configuration_by_hash(cfg_hash).expect(&format!(
            "Config with hash {:?} is absent in configs table",
            cfg_hash
        ))
    }

    /// Returns configuration for given configuration hash.
    pub fn configuration_by_hash(&self, hash: &Hash) -> Option<StoredConfiguration> {
        self.configs().get(hash)
    }

    /// Returns the `state_hash` table for core tables.
    pub fn core_state_hash(&self) -> Vec<Hash> {
        vec![self.configs().root_hash()]
    }

    /// Constructs a proof of inclusion of root hash of a specific service
    /// table into block's `state_hash`.
    ///
    /// Searched key for proof is uniquely identified by (`u16`, `u16`) tuple
    /// of table's coordinates.
    ///
    /// If found, root hash is returned as a value of proof's leaf
    /// corresponding to searched key. Otherwise, partial path to searched key
    /// is returned, which proves its exclusion.
    ///
    /// The returned proof is used as a component of proof of state of any
    /// entity, stored in `exonum` db at specific height, as identified
    /// by corresponding block's `state_hash`. State of some meta tables
    /// of core and services isn't tracked.
    ///
    /// # Arguments
    ///
    /// * `service_id` - `service_id` as returned by instance of type of
    /// `Service` trait
    /// * `table_idx` - index of service table in `Vec`, returned by
    /// `state_hash` method of instance of type of `Service` trait
    pub fn get_proof_to_service_table(&self, service_id: u16, table_idx: usize) -> MapProof<Hash> {
        let key = Blockchain::service_table_unique_key(service_id, table_idx);
        let sum_table = self.state_hash_aggregator();
        sum_table.get_proof(&key)
    }

    fn find_configurations_index_by_height(&self, height: Height) -> u64 {
        let actual_from = self.configs_actual_from();
        for i in (0..actual_from.len()).rev() {
            if actual_from.get(i).unwrap().actual_from() <= height {
                return i as u64;
            }
        }
        panic!(
            "Couldn't not find any config for height {}, \
             that means that genesis block was created incorrectly.",
            height
        )
    }

    fn next_height(&self) -> Height {
        Height(self.block_hashes_by_height().len())
    }
}

impl<'a> Schema<&'a mut Fork> {
    /// Mutable reference to the [`transactions`][1] index.
    ///
    /// [1]: struct.Schema.html#method.transactions
    pub fn transactions_mut(&mut self) -> MapIndex<&mut Fork, Hash, RawMessage> {
        MapIndex::new("core.transactions", &mut self.view)
    }

    /// Mutable reference to the [`tx_location_by_tx_hash`][1] index.
    ///
    /// [1]: struct.Schema.html#method.tx_location_by_tx_hash
    pub fn tx_location_by_tx_hash_mut(&mut self) -> MapIndex<&mut Fork, Hash, TxLocation> {
        MapIndex::new("core.tx_location_by_tx_hash", &mut self.view)
    }

    /// Mutable reference to the [`blocks][1] index.
    ///
    /// [1]: struct.Schema.html#method.blocks
    pub fn blocks_mut(&mut self) -> MapIndex<&mut Fork, Hash, Block> {
        MapIndex::new("core.blocks", &mut self.view)
    }

    /// Mutable reference to the [`block_hashes_by_height_mut`][1] index.
    ///
    /// [1]: struct.Schema.html#method.block_hashes_by_height_mut
    pub fn block_hashes_by_height_mut(&mut self) -> ListIndex<&mut Fork, Hash> {
        ListIndex::new("core.block_hashes_by_height", &mut self.view)
    }

    /// Mutable reference to the [`block_hash_by_height`][1] index.
    ///
    /// [1]: struct.Schema.html#method.block_hash_by_height
    pub fn block_hash_by_height_mut(&mut self, height: Height) -> Option<Hash> {
        self.block_hashes_by_height().get(height.into())
    }

    /// Mutable reference to the [`block_txs`][1] index.
    ///
    /// [1]: struct.Schema.html#method.block_txs
    pub fn block_txs_mut(&mut self, height: Height) -> ProofListIndex<&mut Fork, Hash> {
        let height: u64 = height.into();
        ProofListIndex::with_prefix("core.block_txs", gen_prefix(&height), &mut self.view)
    }

    /// Mutable reference to the [`precommits`][1] index.
    ///
    /// [1]: struct.Schema.html#method.precommits
    pub fn precommits_mut(&mut self, hash: &Hash) -> ListIndex<&mut Fork, Precommit> {
        ListIndex::with_prefix("core.precommits", gen_prefix(hash), &mut self.view)
    }

    /// Mutable reference to the [`configs`][1] index.
    ///
    /// [1]: struct.Schema.html#method.configs
    pub fn configs_mut(&mut self) -> ProofMapIndex<&mut Fork, Hash, StoredConfiguration> {
        ProofMapIndex::new("core.configs", &mut self.view)
    }

    /// Mutable reference to the [`configs_actual_from`][1] index.
    ///
    /// [1]: struct.Schema.html#method.configs_actual_from
    pub fn configs_actual_from_mut(&mut self) -> ListIndex<&mut Fork, ConfigReference> {
        ListIndex::new("core.configs_actual_from", &mut self.view)
    }

    /// Mutable reference to the [`state_hash_aggregator`][1] index.
    ///
    /// [1]: struct.Schema.html#method.state_hash_aggregator
    pub fn state_hash_aggregator_mut(&mut self) -> ProofMapIndex<&mut Fork, Hash, Hash> {
        ProofMapIndex::new("core.state_hash_aggregator", &mut self.view)
    }

    /// Adds a new configuration to the blockchain, which will become an actual at
    /// the `actual_from` height in `config_data`.
    pub fn commit_configuration(&mut self, config_data: StoredConfiguration) {
        let actual_from = config_data.actual_from;
        if let Some(last_cfg) = self.configs_actual_from().last() {
            if last_cfg.cfg_hash() != &config_data.previous_cfg_hash {
                // TODO: Replace panic with errors (ECR-123).
                panic!(
                    "Attempting to commit configuration with incorrect previous hash: {:?}, \
                     expected: {:?}",
                    config_data.previous_cfg_hash,
                    last_cfg.cfg_hash()
                );
            }

            if actual_from <= last_cfg.actual_from() {
                panic!(
                    "Attempting to commit configuration with actual_from {} less than the last \
                     committed the last committed actual_from {}",
                    actual_from,
                    last_cfg.actual_from()
                );
            }
        }

        info!(
            "Scheduled the following configuration for acceptance: {:?}",
            &config_data
        );

        let cfg_hash = config_data.hash();
        self.configs_mut().put(&cfg_hash, config_data);

        let cfg_ref = ConfigReference::new(actual_from, &cfg_hash);
        self.configs_actual_from_mut().push(cfg_ref);
        // TODO: clear storages
    }
}
<|endoftext|>


<commit_before>use ::log::warn;
use ::nix::{
    sys::signal::{self, Signal},
    unistd::Pid,
};
use psutil::process::{processes, Process};

/// Get all children of a specific process
pub fn get_children(pid: i32) -> Vec<Process> {
    let all_processes = match processes() {
        Err(error) => {
            warn!("Failed to get full process list: {}", error);
            return;
        }
        Ok(processes) => processes,
    };
    all_processes
        .into_iter()
        .filter(|result| result.is_ok())
        .map(|result| result.unwrap())
        .filter(|process| {
            if let Ok(ppid) = process.ppid() {
                if let Some(ppid) = ppid {
                    return ppid as i32 == pid;
                }
            }
            false
        })
}

/// Send a signal to a list of processes
pub fn send_signal_to_processes(processes: Vec<Process>, signal: Signal) {
    for process in processes {
        let pid = Pid::from_raw(process.pid() as i32);

        // Process is no longer alive, skip this.
        if !process.is_running {
            continue;
        }

        if let Err(error) = signal::kill(pid, signal) {
            warn!(
                "Failed send signal {:?} to Pid {}: {:?}",
                signal,
                process.pid(),
                error
            );
        }
    }
}

/// A small helper to send a signal to all direct child processes of a specific task.
pub fn send_signal_to_children(pid: i32, signal: Signal) {
    send_signal_to_processes(get_children(pid), signal);
}
<commit_msg>Probably fix macos process handling?<commit_after>use ::log::warn;
use ::nix::{
    sys::signal::{self, Signal},
    unistd::Pid,
};
use psutil::process::{processes, Process};

/// Get all children of a specific process
pub fn get_children(pid: i32) -> Vec<Process> {
    let all_processes = match processes() {
        Err(error) => {
            warn!("Failed to get full process list: {}", error);
            return;
        }
        Ok(processes) => processes,
    };
    all_processes
        .into_iter()
        .filter(|result| result.is_ok())
        .map(|result| result.unwrap())
        .filter(|process| {
            if let Ok(ppid) = process.ppid() {
                if let Some(ppid) = ppid {
                    return ppid as i32 == pid;
                }
            }
            false
        })
        .collect()
}

/// Send a signal to a list of processes
pub fn send_signal_to_processes(processes: Vec<Process>, signal: Signal) {
    for process in processes {
        let pid = Pid::from_raw(process.pid() as i32);

        // Process is no longer alive, skip this.
        if !process.is_running() {
            continue;
        }

        if let Err(error) = signal::kill(pid, signal) {
            warn!(
                "Failed send signal {:?} to Pid {}: {:?}",
                signal,
                process.pid(),
                error
            );
        }
    }
}

/// A small helper to send a signal to all direct child processes of a specific task.
pub fn send_signal_to_children(pid: i32, signal: Signal) {
    send_signal_to_processes(get_children(pid), signal);
}
<|endoftext|>