<commit_before>// cargo.rs - Rust package manager

import rustc::syntax::{ast, codemap, visit};
import rustc::syntax::parse::parser;

import std::fs;
import std::generic_os;
import std::io;
import std::option;
import std::option::{none, some};
import std::os;
import std::run;
import std::str;
import std::tempfile;
import std::vec;

type pkg = {
    name: str,
    vers: str,
    uuid: str,
    desc: option::t<str>,
    sigs: option::t<str>,
    crate_type: option::t<str>
};

fn load_link(mis: [@ast::meta_item]) -> (option::t<str>,
                                         option::t<str>,
                                         option::t<str>) {
    let name = none;
    let vers = none;
    let uuid = none;
    for a: @ast::meta_item in mis {
        alt a.node {
            ast::meta_name_value(v, {node: ast::lit_str(s), span: _}) {
                alt v {
                    "name" { name = some(s); }
                    "vers" { vers = some(s); }
                    "uuid" { uuid = some(s); }
                    _ { }
                }
            }
        }
    }
    (name, vers, uuid)
}

fn load_pkg(filename: str) -> option::t<pkg> {
    let sess = @{cm: codemap::new_codemap(), mutable next_id: 0};
    let c = parser::parse_crate_from_crate_file(filename, [], sess);

    let name = none;
    let vers = none;
    let uuid = none;
    let desc = none;
    let sigs = none;
    let crate_type = none;

    for a in c.node.attrs {
        alt a.node.value.node {
            ast::meta_name_value(v, {node: ast::lit_str(s), span: _}) {
                alt v {
                    "desc" { desc = some(v); }
                    "sigs" { sigs = some(v); }
                    "crate_type" { crate_type = some(v); }
                    _ { }
                }
            }
            ast::meta_list(v, mis) {
                if v == "link" {
                    let (n, v, u) = load_link(mis);
                    name = n;
                    vers = v;
                    uuid = u;
                }
            }
        }
    }

    alt (name, vers, uuid) {
        (some(name0), some(vers0), some(uuid0)) {
            some({
                name: name0,
                vers: vers0,
                uuid: uuid0,
                desc: desc,
                sigs: sigs,
                crate_type: crate_type})
        }
        _ { ret none; }
    }
}

fn print(s: str) {
    io::stdout().write_line(s);
}

fn rest(s: str, start: uint) -> str {
    if (start >= str::char_len(s)) {
        ""
    } else {
        str::char_slice(s, start, str::char_len(s))
    }
}

fn need_dir(s: str) {
    if fs::file_is_dir(s) { ret; }
    if !fs::make_dir(s, 0x1c0i32) {
        fail #fmt["can't make_dir %s", s];
    }
}

fn setup_dirs() -> str {
    let p = alt generic_os::getenv("CARGO_ROOT") {
        some(_p) { _p }
        none. {
            alt generic_os::getenv("HOME") {
                some(_q) { fs::connect(_q, "/.cargo") }
                none. { fail "no CARGO_ROOT or HOME"; }
            }
        }
    };

    log #fmt["p: %s", p];

    need_dir(p);
    need_dir(fs::connect(p, "fetch"));
    need_dir(fs::connect(p, "work"));
    need_dir(fs::connect(p, "lib"));
    need_dir(fs::connect(p, "bin"));

    p
}

fn install_one_crate(cargo_root: str, path: str, cf: str, p: pkg) {
    let bindir = fs::connect(cargo_root, "bin");
    let libdir = fs::connect(cargo_root, "lib");
    let name = fs::basename(cf);
    let ri = str::index(name, '.' as u8);
    if ri != -1 {
        name = str::slice(name, 0u, ri as uint);
    }
    log #fmt["Installing: %s", name];
    let old = fs::list_dir(".");
    run::run_program("rustc", [cf]);
    let new = fs::list_dir(".");
    let created = vec::filter::<str>({ |n| !vec::member::<str>(n, old) }, new);
    for c: str in created {
        if str::ends_with(c, os::exec_suffix()) {
            log #fmt["  bin: %s", c];
            // FIXME: need libstd fs::copy or something
            run::run_program("cp", [c, fs::connect(bindir, c)]);
        } else {
            log #fmt["  lib: %s", c];
            run::run_program("cp", [c, fs::connect(libdir, c)]);
        }
    }
}

fn install_source(cargo_root: str, path: str) {
    log #fmt["source: %s", path];
    fs::change_dir(path);
    let contents = fs::list_dir(".");

    log #fmt["contents: %s", str::connect(contents, ", ")];

    let cratefiles = vec::filter::<str>({ |n| str::ends_with(n, ".rc") }, contents);

    if vec::is_empty(cratefiles) {
        fail "This doesn't look like a rust package (no .rc files).";
    }

    for cf: str in cratefiles {
        let p = load_pkg(cf);
        alt p {
            none. { cont; }
            some(_p) {
                install_one_crate(cargo_root, path, cf, _p);
            }
        }
    }
}

fn install_file(cargo_root: str, _path: str) {
    let wd = tempfile::mkdtemp(cargo_root + "/work/", "");
    alt wd {
        some(p) {
            run::run_program("tar", ["-x", "--strip-components=1",
                                     "-C", p, "-f", _path]);
            install_source(cargo_root, p);
        }
        _ { fail "needed temp dir"; }
    }
}

fn cmd_install(cargo_root: str, argv: [str]) {
    // cargo install <pkg>
    if vec::len(argv) < 3u {
        cmd_usage();
        ret;
    }

    if str::starts_with(argv[2], "file:") {
        let path = rest(argv[2], 5u);
        install_file(cargo_root, path);
    }
}

fn cmd_usage() {
    print("Usage: cargo <verb> [args...]");
}

fn main(argv: [str]) {
    if vec::len(argv) < 2u {
        cmd_usage();
        ret;
    }
    let cargo_root = setup_dirs();
    alt argv[1] {
        "install" { cmd_install(cargo_root, argv); }
        "usage" { cmd_usage(); }
        _ { cmd_usage(); }
    }
}
<commit_msg>cargo: refactor a bit<commit_after>// cargo.rs - Rust package manager

import rustc::syntax::{ast, codemap, visit};
import rustc::syntax::parse::parser;

import std::fs;
import std::generic_os;
import std::io;
import std::option;
import std::option::{none, some};
import std::os;
import std::run;
import std::str;
import std::tempfile;
import std::vec;

type cargo = {
    root: str,
    bindir: str,
    libdir: str,
    workdir: str,
    fetchdir: str
};

type pkg = {
    name: str,
    vers: str,
    uuid: str,
    desc: option::t<str>,
    sigs: option::t<str>,
    crate_type: option::t<str>
};

fn load_link(mis: [@ast::meta_item]) -> (option::t<str>,
                                         option::t<str>,
                                         option::t<str>) {
    let name = none;
    let vers = none;
    let uuid = none;
    for a: @ast::meta_item in mis {
        alt a.node {
            ast::meta_name_value(v, {node: ast::lit_str(s), span: _}) {
                alt v {
                    "name" { name = some(s); }
                    "vers" { vers = some(s); }
                    "uuid" { uuid = some(s); }
                    _ { }
                }
            }
        }
    }
    (name, vers, uuid)
}

fn load_pkg(filename: str) -> option::t<pkg> {
    let sess = @{cm: codemap::new_codemap(), mutable next_id: 0};
    let c = parser::parse_crate_from_crate_file(filename, [], sess);

    let name = none;
    let vers = none;
    let uuid = none;
    let desc = none;
    let sigs = none;
    let crate_type = none;

    for a in c.node.attrs {
        alt a.node.value.node {
            ast::meta_name_value(v, {node: ast::lit_str(s), span: _}) {
                alt v {
                    "desc" { desc = some(v); }
                    "sigs" { sigs = some(v); }
                    "crate_type" { crate_type = some(v); }
                    _ { }
                }
            }
            ast::meta_list(v, mis) {
                if v == "link" {
                    let (n, v, u) = load_link(mis);
                    name = n;
                    vers = v;
                    uuid = u;
                }
            }
        }
    }

    alt (name, vers, uuid) {
        (some(name0), some(vers0), some(uuid0)) {
            some({
                name: name0,
                vers: vers0,
                uuid: uuid0,
                desc: desc,
                sigs: sigs,
                crate_type: crate_type})
        }
        _ { ret none; }
    }
}

fn print(s: str) {
    io::stdout().write_line(s);
}

fn rest(s: str, start: uint) -> str {
    if (start >= str::char_len(s)) {
        ""
    } else {
        str::char_slice(s, start, str::char_len(s))
    }
}

fn need_dir(s: str) {
    if fs::file_is_dir(s) { ret; }
    if !fs::make_dir(s, 0x1c0i32) {
        fail #fmt["can't make_dir %s", s];
    }
}

fn configure() -> cargo {
    let p = alt generic_os::getenv("CARGO_ROOT") {
        some(_p) { _p }
        none. {
            alt generic_os::getenv("HOME") {
                some(_q) { fs::connect(_q, "/.cargo") }
                none. { fail "no CARGO_ROOT or HOME"; }
            }
        }
    };

    log #fmt["p: %s", p];

    let c = {
        root: p,
        bindir: fs::connect(p, "bin"),
        libdir: fs::connect(p, "lib"),
        workdir: fs::connect(p, "work"),
        fetchdir: fs::connect(p, "fetch")
    };

    need_dir(c.root);
    need_dir(c.fetchdir);
    need_dir(c.workdir);
    need_dir(c.libdir);
    need_dir(c.bindir);

    c
}

fn install_one_crate(c: cargo, path: str, cf: str, p: pkg) {
    let name = fs::basename(cf);
    let ri = str::index(name, '.' as u8);
    if ri != -1 {
        name = str::slice(name, 0u, ri as uint);
    }
    log #fmt["Installing: %s", name];
    let old = fs::list_dir(".");
    run::run_program("rustc", [cf]);
    let new = fs::list_dir(".");
    let created = vec::filter::<str>({ |n| !vec::member::<str>(n, old) }, new);
    for ct: str in created {
        if str::ends_with(ct, os::exec_suffix()) {
            log #fmt["  bin: %s", ct];
            // FIXME: need libstd fs::copy or something
            run::run_program("cp", [ct, c.bindir]);
        } else {
            log #fmt["  lib: %s", ct];
            run::run_program("cp", [ct, c.libdir]);
        }
    }
}

fn install_source(c: cargo, path: str) {
    log #fmt["source: %s", path];
    fs::change_dir(path);
    let contents = fs::list_dir(".");

    log #fmt["contents: %s", str::connect(contents, ", ")];

    let cratefiles = vec::filter::<str>({ |n| str::ends_with(n, ".rc") }, contents);

    if vec::is_empty(cratefiles) {
        fail "This doesn't look like a rust package (no .rc files).";
    }

    for cf: str in cratefiles {
        let p = load_pkg(cf);
        alt p {
            none. { cont; }
            some(_p) {
                install_one_crate(c, path, cf, _p);
            }
        }
    }
}

fn install_file(c: cargo, _path: str) {
    let wd = tempfile::mkdtemp(c.workdir + fs::path_sep(), "");
    alt wd {
        some(p) {
            run::run_program("tar", ["-x", "--strip-components=1",
                                     "-C", p, "-f", _path]);
            install_source(c, p);
        }
        _ { fail "needed temp dir"; }
    }
}

fn cmd_install(c: cargo, argv: [str]) {
    // cargo install <pkg>
    if vec::len(argv) < 3u {
        cmd_usage();
        ret;
    }

    if str::starts_with(argv[2], "file:") {
        let path = rest(argv[2], 5u);
        install_file(c, path);
    }
}

fn cmd_usage() {
    print("Usage: cargo <verb> [args...]");
}

fn main(argv: [str]) {
    if vec::len(argv) < 2u {
        cmd_usage();
        ret;
    }
    let c = configure();
    alt argv[1] {
        "install" { cmd_install(c, argv); }
        "usage" { cmd_usage(); }
        _ { cmd_usage(); }
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 Google Inc. All rights reserved.
//
// 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.

#![feature(test)]

extern crate test;
extern crate xi_rope;

use test::Bencher;
use xi_rope::tree::*;
use xi_rope::rope::{LinesMetric, Rope};

fn run_down_rope(text: &Rope) {
    let mut cursor = Cursor::new(&text, 0);

    while cursor.pos() < text.len() - 2 {
        cursor.next::<LinesMetric>();
    }
}

fn build_triangle(n: usize) -> String {
    let mut s = String::new();
    let mut line = String::new();
    for _ in 0 .. n {
        s += &line;
        s += "\n";
        line += "a";
    }
    s
}

fn build_short_lines(n: usize) -> String {
    let line = "match s.as_bytes()[minsplit - 1..splitpoint].iter().rposition(|&c| c == b'\n') {";
    let mut s = String::new();
    for _ in 0..n {
        s += line;
    }
    s
}

fn build_few_big_lines(size: usize) -> String {
    let mut s = String::with_capacity(size * 10 + 20);
    for _ in 0 .. 10 {
        for _ in 0..size {
            s += "a";
        }
        s += "\n";
    }
    s
}

#[bench]
fn benchmark_triangle(b: &mut Bencher) {
    let text = Rope::from(build_triangle(50_000));
    b.iter(|| run_down_rope(&text));
}

#[bench]
fn benchmark_short_lines(b: &mut Bencher) {
    let text = Rope::from(build_short_lines(1_000_000));
    b.iter(|| run_down_rope(&text));
}

#[bench]
fn benchmark_few_big_lines(b: &mut Bencher) {
    let text = Rope::from(build_short_lines(1_000_000));
    b.iter(|| run_down_rope(&text));
}
<commit_msg>Fix copy-and-paste error<commit_after>// Copyright 2017 Google Inc. All rights reserved.
//
// 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.

#![feature(test)]

extern crate test;
extern crate xi_rope;

use test::Bencher;
use xi_rope::tree::*;
use xi_rope::rope::{LinesMetric, Rope};

fn run_down_rope(text: &Rope) {
    let mut cursor = Cursor::new(&text, 0);

    while cursor.pos() < text.len() - 2 {
        cursor.next::<LinesMetric>();
    }
}

fn build_triangle(n: usize) -> String {
    let mut s = String::new();
    let mut line = String::new();
    for _ in 0 .. n {
        s += &line;
        s += "\n";
        line += "a";
    }
    s
}

fn build_short_lines(n: usize) -> String {
    let line = "match s.as_bytes()[minsplit - 1..splitpoint].iter().rposition(|&c| c == b'\n') {";
    let mut s = String::new();
    for _ in 0..n {
        s += line;
    }
    s
}

fn build_few_big_lines(size: usize) -> String {
    let mut s = String::with_capacity(size * 10 + 20);
    for _ in 0 .. 10 {
        for _ in 0..size {
            s += "a";
        }
        s += "\n";
    }
    s
}

#[bench]
fn benchmark_triangle(b: &mut Bencher) {
    let text = Rope::from(build_triangle(50_000));
    b.iter(|| run_down_rope(&text));
}

#[bench]
fn benchmark_short_lines(b: &mut Bencher) {
    let text = Rope::from(build_short_lines(1_000_000));
    b.iter(|| run_down_rope(&text));
}

#[bench]
fn benchmark_few_big_lines(b: &mut Bencher) {
    let text = Rope::from(build_few_big_lines(1_000_000));
    b.iter(|| run_down_rope(&text));
}
<|endoftext|>


<commit_before>use std::{
    env,
    fs::File,
    io,
    path::{Path, PathBuf},
};

use anyhow::Result;
use flate2::{write::GzEncoder, Compression};
use xshell::{cmd, cp, mkdir_p, pushd, pushenv, read_file, rm_rf, write_file};

use crate::{date_iso, flags, project_root};

impl flags::Dist {
    pub(crate) fn run(self) -> Result<()> {
        let stable =
            std::env::var("GITHUB_REF").unwrap_or_default().as_str() == "refs/heads/release";

        let dist = project_root().join("dist");
        rm_rf(&dist)?;
        mkdir_p(&dist)?;

        if let Some(patch_version) = self.client_patch_version {
            let version = if stable {
                format!("0.2.{}", patch_version)
            } else {
                // A hack to make VS Code prefer nightly over stable.
                format!("0.3.{}", patch_version)
            };
            let release_tag = if stable { date_iso()? } else { "nightly".to_string() };
            dist_client(&version, &release_tag)?;
        }
        let release_channel = if stable { "stable" } else { "nightly" };
        dist_server(release_channel)?;
        Ok(())
    }
}

fn dist_client(version: &str, release_tag: &str) -> Result<()> {
    let _d = pushd("./editors/code")?;
    let nightly = release_tag == "nightly";

    let mut patch = Patch::new("./package.json")?;

    patch
        .replace(r#""version": "0.4.0-dev""#, &format!(r#""version": "{}""#, version))
        .replace(r#""releaseTag": null"#, &format!(r#""releaseTag": "{}""#, release_tag))
        .replace(r#""$generated-start": false,"#, "")
        .replace(",\n                \"$generated-end\": false", "");

    if nightly {
        patch.replace(
            r#""displayName": "rust-analyzer""#,
            r#""displayName": "rust-analyzer (nightly)""#,
        );
    }
    if !nightly {
        patch.replace(r#""enableProposedApi": true,"#, r#""#);
    }
    patch.commit()?;

    cmd!("npm ci").run()?;
    cmd!("npx vsce package -o ../../dist/rust-analyzer.vsix").run()?;
    Ok(())
}

fn dist_server(release_channel: &str) -> Result<()> {
    let _e = pushenv("RUST_ANALYZER_CHANNEL", release_channel);
    let _e = pushenv("CARGO_PROFILE_RELEASE_LTO", "true");
    let target = get_target();
    if target.contains("-linux-gnu") || target.contains("-linux-musl") {
        env::set_var("CC", "clang");
    }

    cmd!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target} --release").run()?;

    let suffix = exe_suffix(&target);
    let src =
        Path::new("target").join(&target).join("release").join(format!("rust-analyzer{}", suffix));
    let dst = Path::new("dist").join(format!("rust-analyzer-{}{}", target, suffix));
    gzip(&src, &dst.with_extension("gz"))?;

    // FIXME: the old names are temporarily kept for client compatibility, but they should be removed
    // Remove this block after a couple of releases
    match target.as_ref() {
        "x86_64-unknown-linux-gnu" => {
            cp(&src, "dist/rust-analyzer-linux")?;
            gzip(&src, Path::new("dist/rust-analyzer-linux.gz"))?;
        }
        "x86_64-pc-windows-msvc" => {
            cp(&src, "dist/rust-analyzer-windows.exe")?;
            gzip(&src, Path::new("dist/rust-analyzer-windows.gz"))?;
        }
        "x86_64-apple-darwin" => {
            cp(&src, "dist/rust-analyzer-mac")?;
            gzip(&src, Path::new("dist/rust-analyzer-mac.gz"))?;
        }
        _ => {}
    }

    Ok(())
}

fn get_target() -> String {
    match env::var("RA_TARGET") {
        Ok(target) => target,
        _ => {
            if cfg!(target_os = "linux") {
                "x86_64-unknown-linux-gnu".to_string()
            } else if cfg!(target_os = "windows") {
                "x86_64-pc-windows-msvc".to_string()
            } else if cfg!(target_os = "macos") {
                "x86_64-apple-darwin".to_string()
            } else {
                panic!("Unsupported OS, maybe try setting RA_TARGET")
            }
        }
    }
}

fn exe_suffix(target: &str) -> String {
    if target.contains("-windows-") {
        ".exe".into()
    } else {
        "".into()
    }
}

fn gzip(src_path: &Path, dest_path: &Path) -> Result<()> {
    let mut encoder = GzEncoder::new(File::create(dest_path)?, Compression::best());
    let mut input = io::BufReader::new(File::open(src_path)?);
    io::copy(&mut input, &mut encoder)?;
    encoder.finish()?;
    Ok(())
}

struct Patch {
    path: PathBuf,
    original_contents: String,
    contents: String,
}

impl Patch {
    fn new(path: impl Into<PathBuf>) -> Result<Patch> {
        let path = path.into();
        let contents = read_file(&path)?;
        Ok(Patch { path, original_contents: contents.clone(), contents })
    }

    fn replace(&mut self, from: &str, to: &str) -> &mut Patch {
        assert!(self.contents.contains(from));
        self.contents = self.contents.replace(from, to);
        self
    }

    fn commit(&self) -> Result<()> {
        write_file(&self.path, &self.contents)?;
        Ok(())
    }
}

impl Drop for Patch {
    fn drop(&mut self) {
        write_file(&self.path, &self.original_contents).unwrap();
    }
}
<commit_msg>internal: try enabling debug info for releases<commit_after>use std::{
    env,
    fs::File,
    io,
    path::{Path, PathBuf},
};

use anyhow::Result;
use flate2::{write::GzEncoder, Compression};
use xshell::{cmd, cp, mkdir_p, pushd, pushenv, read_file, rm_rf, write_file};

use crate::{date_iso, flags, project_root};

impl flags::Dist {
    pub(crate) fn run(self) -> Result<()> {
        let stable =
            std::env::var("GITHUB_REF").unwrap_or_default().as_str() == "refs/heads/release";

        let dist = project_root().join("dist");
        rm_rf(&dist)?;
        mkdir_p(&dist)?;

        if let Some(patch_version) = self.client_patch_version {
            let version = if stable {
                format!("0.2.{}", patch_version)
            } else {
                // A hack to make VS Code prefer nightly over stable.
                format!("0.3.{}", patch_version)
            };
            let release_tag = if stable { date_iso()? } else { "nightly".to_string() };
            dist_client(&version, &release_tag)?;
        }
        let release_channel = if stable { "stable" } else { "nightly" };
        dist_server(release_channel)?;
        Ok(())
    }
}

fn dist_client(version: &str, release_tag: &str) -> Result<()> {
    let _d = pushd("./editors/code")?;
    let nightly = release_tag == "nightly";

    let mut patch = Patch::new("./package.json")?;

    patch
        .replace(r#""version": "0.4.0-dev""#, &format!(r#""version": "{}""#, version))
        .replace(r#""releaseTag": null"#, &format!(r#""releaseTag": "{}""#, release_tag))
        .replace(r#""$generated-start": false,"#, "")
        .replace(",\n                \"$generated-end\": false", "");

    if nightly {
        patch.replace(
            r#""displayName": "rust-analyzer""#,
            r#""displayName": "rust-analyzer (nightly)""#,
        );
    }
    if !nightly {
        patch.replace(r#""enableProposedApi": true,"#, r#""#);
    }
    patch.commit()?;

    cmd!("npm ci").run()?;
    cmd!("npx vsce package -o ../../dist/rust-analyzer.vsix").run()?;
    Ok(())
}

fn dist_server(release_channel: &str) -> Result<()> {
    let _e = pushenv("RUST_ANALYZER_CHANNEL", release_channel);
    let _e = pushenv("CARGO_PROFILE_RELEASE_LTO", "true");
    let _e = pushenv("CARGO_PROFILE_RELEASE_DEBUG", "1");
    let target = get_target();
    if target.contains("-linux-gnu") || target.contains("-linux-musl") {
        env::set_var("CC", "clang");
    }

    cmd!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target} --release").run()?;

    let suffix = exe_suffix(&target);
    let src =
        Path::new("target").join(&target).join("release").join(format!("rust-analyzer{}", suffix));
    let dst = Path::new("dist").join(format!("rust-analyzer-{}{}", target, suffix));
    gzip(&src, &dst.with_extension("gz"))?;

    // FIXME: the old names are temporarily kept for client compatibility, but they should be removed
    // Remove this block after a couple of releases
    match target.as_ref() {
        "x86_64-unknown-linux-gnu" => {
            cp(&src, "dist/rust-analyzer-linux")?;
            gzip(&src, Path::new("dist/rust-analyzer-linux.gz"))?;
        }
        "x86_64-pc-windows-msvc" => {
            cp(&src, "dist/rust-analyzer-windows.exe")?;
            gzip(&src, Path::new("dist/rust-analyzer-windows.gz"))?;
        }
        "x86_64-apple-darwin" => {
            cp(&src, "dist/rust-analyzer-mac")?;
            gzip(&src, Path::new("dist/rust-analyzer-mac.gz"))?;
        }
        _ => {}
    }

    Ok(())
}

fn get_target() -> String {
    match env::var("RA_TARGET") {
        Ok(target) => target,
        _ => {
            if cfg!(target_os = "linux") {
                "x86_64-unknown-linux-gnu".to_string()
            } else if cfg!(target_os = "windows") {
                "x86_64-pc-windows-msvc".to_string()
            } else if cfg!(target_os = "macos") {
                "x86_64-apple-darwin".to_string()
            } else {
                panic!("Unsupported OS, maybe try setting RA_TARGET")
            }
        }
    }
}

fn exe_suffix(target: &str) -> String {
    if target.contains("-windows-") {
        ".exe".into()
    } else {
        "".into()
    }
}

fn gzip(src_path: &Path, dest_path: &Path) -> Result<()> {
    let mut encoder = GzEncoder::new(File::create(dest_path)?, Compression::best());
    let mut input = io::BufReader::new(File::open(src_path)?);
    io::copy(&mut input, &mut encoder)?;
    encoder.finish()?;
    Ok(())
}

struct Patch {
    path: PathBuf,
    original_contents: String,
    contents: String,
}

impl Patch {
    fn new(path: impl Into<PathBuf>) -> Result<Patch> {
        let path = path.into();
        let contents = read_file(&path)?;
        Ok(Patch { path, original_contents: contents.clone(), contents })
    }

    fn replace(&mut self, from: &str, to: &str) -> &mut Patch {
        assert!(self.contents.contains(from));
        self.contents = self.contents.replace(from, to);
        self
    }

    fn commit(&self) -> Result<()> {
        write_file(&self.path, &self.contents)?;
        Ok(())
    }
}

impl Drop for Patch {
    fn drop(&mut self) {
        write_file(&self.path, &self.original_contents).unwrap();
    }
}
<|endoftext|>


<commit_before>
use std::collections::VecDeque;

//struct Point {
//    x: usize,
//    y: usize,
//    path_length: u32,
//    euclidean_dist: f32,
//}
//fn dist(p1: Point, p2: Point) -> f32 {
//    let dx = p2.x as f32 - p1.x as f32;
//    let dy = p2.x as f32 - p1.x as f32;
//    (dx*dx + dy*dy).sqrt()
//}

// Find x*x + 3*x + 2*x*y + y + y*y.
// Add the office designer's favorite number (your puzzle input).
// Find the binary representation of that sum; count the number of bits that are 1.
// If the number of bits that are 1 is even, it's an open space.
// If the number of bits that are 1 is odd, it's a wall.
fn is_open(target: (i32,i32), magic_number: i32) -> bool {

    let (x,y) = target;
    let set_bits = ((x*x + 3*x + 2*x*y + y + y*y) + magic_number).count_ones();

    let is_even = |x: u32| x & 1 == 0;
    if is_even(set_bits) {true} else {false}
}

fn in_bounds((x,y): (i32, i32), size: i32) -> bool {
    x >= 0 && x < size && y >= 0 && y < size
}

fn search(target: (i32,i32), magic_number: i32) -> Option<i32> {
    let start = (1_i32, 1_i32, 0_i32);
    const SIZE: i32 = 100;
    let mut visited = [[false; SIZE as usize]; SIZE as usize]; // Each cell stores [visited] state.

    // Try a simple BFS search
    let mut shortest_path = SIZE*SIZE;
    let mut queue = VecDeque::new();
    queue.push_back(start); // x,y,path

    while let Some(next) = queue.pop_front() {
        //println!("Checking {:?}", next);
        let pos = (next.0, next.1);
        if in_bounds(pos, SIZE)
            && is_open(pos, magic_number)
            && !visited[pos.0 as usize][pos.1 as usize]
            && next.2 <shortest_path {

            visited[pos.0 as usize][pos.1 as usize] = true;

            if pos == target && next.2 < shortest_path {
                println!("Found new path to target with distance {}", next.2);
                shortest_path = next.2;
            } else {
                let x = next.0;
                let y = next.1;
                let dist = next.2;
                // Generate next states
                queue.push_back((x+1, y, dist+1));
                queue.push_back((x-1, y, dist+1));
                queue.push_back((x, y+1, dist+1));
                queue.push_back((x, y-1, dist+1));
            }
        } // else skip state
    }

    if shortest_path < (SIZE*SIZE) {
        Some(shortest_path)
    } else {
        None
    }
}

fn main() {
    println!("Hello, world!");

    let puzzle_magic_number = 1362_i32;
    let target = (31,39); // (x,y)

    let path = search(target, puzzle_magic_number);
    println!("Part 1: path distance = {:?}", path);
    assert!(path == Some(82));

//    let example_magic = 10;
//    for y in 0..7 {
//        for x in 0..10 {
//            let open = is_open((x,y), example_magic);
//            print!("{}", if open {"."} else {"#"});
//        }
//        println!("");
//    }

}

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

    #[test]
    fn check_open() {
        assert!(is_open((1,1), 10));
    }

    #[test]
    fn test() {
        let dist = search((7,4), 10);
        println!("Test distance = {:?}", dist);
        assert!(dist == Some(11));
    }
}
<commit_msg>Day 13, part 2.<commit_after>
use std::collections::VecDeque;

//struct Point {
//    x: usize,
//    y: usize,
//    path_length: u32,
//    euclidean_dist: f32,
//}
//fn dist(p1: Point, p2: Point) -> f32 {
//    let dx = p2.x as f32 - p1.x as f32;
//    let dy = p2.x as f32 - p1.x as f32;
//    (dx*dx + dy*dy).sqrt()
//}

// Find x*x + 3*x + 2*x*y + y + y*y.
// Add the office designer's favorite number (your puzzle input).
// Find the binary representation of that sum; count the number of bits that are 1.
// If the number of bits that are 1 is even, it's an open space.
// If the number of bits that are 1 is odd, it's a wall.
fn is_open(target: (i32,i32), magic_number: i32) -> bool {

    let (x,y) = target;
    let set_bits = ((x*x + 3*x + 2*x*y + y + y*y) + magic_number).count_ones();

    let is_even = |x: u32| x & 1 == 0;
    if is_even(set_bits) {true} else {false}
}

fn in_bounds((x,y): (i32, i32), size: i32) -> bool {
    x >= 0 && x < size && y >= 0 && y < size
}

fn search(target: (i32,i32), magic_number: i32) -> Option<i32> {
    let start = (1_i32, 1_i32, 0_i32);
    const SIZE: i32 = 100;
    let mut visited = [[false; SIZE as usize]; SIZE as usize]; // Each cell stores [visited] state.

    // Try a simple BFS search
    let mut shortest_path = SIZE*SIZE;
    let mut queue = VecDeque::new();
    queue.push_back(start); // x,y,path

    while let Some(next) = queue.pop_front() {
        //println!("Checking {:?}", next);
        let pos = (next.0, next.1);
        if in_bounds(pos, SIZE)
            && is_open(pos, magic_number)
            && !visited[pos.0 as usize][pos.1 as usize]
            && next.2 <shortest_path {

            visited[pos.0 as usize][pos.1 as usize] = true;

            if pos == target && next.2 < shortest_path {
                println!("Found new path to target with distance {}", next.2);
                shortest_path = next.2;
            } else {
                let x = next.0;
                let y = next.1;
                let dist = next.2;
                // Generate next states
                queue.push_back((x+1, y, dist+1));
                queue.push_back((x-1, y, dist+1));
                queue.push_back((x, y+1, dist+1));
                queue.push_back((x, y-1, dist+1));
            }
        } // else skip state
    }

    if shortest_path < (SIZE*SIZE) {
        Some(shortest_path)
    } else {
        None
    }
}

fn max_within_range(max_path: i32,magic_number: i32) -> i32 {
    let start = (1_i32, 1_i32, 0_i32);
    const SIZE: i32 = 100;
    let mut visited = [[false; SIZE as usize]; SIZE as usize]; // Each cell stores [visited] state.

    // Try a simple BFS search
    let mut visited_states = 0i32;
    let mut queue = VecDeque::new();
    queue.push_back(start); // x,y,path

    while let Some(next) = queue.pop_front() {
        let pos = (next.0, next.1);
        if in_bounds(pos, SIZE)
            && is_open(pos, magic_number)
            && !visited[pos.0 as usize][pos.1 as usize]
            && next.2 <= max_path {

                visited[pos.0 as usize][pos.1 as usize] = true;
                visited_states += 1;

                let x = next.0;
                let y = next.1;
                let dist = next.2;
                // Generate next states
                queue.push_back((x+1, y, dist+1));
                queue.push_back((x-1, y, dist+1));
                queue.push_back((x, y+1, dist+1));
                queue.push_back((x, y-1, dist+1));
        }
    } // else skip state
    visited_states
}

fn main() {
    println!("Hello, world!");

    let puzzle_magic_number = 1362_i32;
    let target = (31,39); // (x,y)

    let path = search(target, puzzle_magic_number);
    println!("Part 1: path distance = {:?}", path);
    assert!(path == Some(82));

    let visited_states = max_within_range(50, puzzle_magic_number);
    println!("Part 2: possible to visit {} states", visited_states);
    assert!(visited_states == 138);

//    let example_magic = 10;
//    for y in 0..7 {
//        for x in 0..10 {
//            let open = is_open((x,y), example_magic);
//            print!("{}", if open {"."} else {"#"});
//        }
//        println!("");
//    }

}

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

    #[test]
    fn check_open() {
        assert!(is_open((1,1), 10));
    }

    #[test]
    fn test() {
        let dist = search((7,4), 10);
        println!("Test distance = {:?}", dist);
        assert!(dist == Some(11));
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use std;
use std::iter::{Iterator, Zip};
use std::mem;
use std::mem::ManuallyDrop;
use std::ptr;
use std::slice;
use std::sync::Arc;

use node;
use node::Node;
use text_info::TextInfo;

const MAX_LEN: usize = node::MAX_CHILDREN;

#[derive(Debug, Clone)]
pub(crate) struct ChildArray {
    nodes: ManuallyDrop<[Arc<Node>; MAX_LEN]>,
    info: [TextInfo; MAX_LEN],
    len: u8,
}

impl ChildArray {
    /// Creates a new empty array.
    pub fn new() -> ChildArray {
        ChildArray {
            nodes: unsafe { std::mem::uninitialized() },
            info: unsafe { std::mem::uninitialized() },
            len: 0,
        }
    }

    /// Current length of the array.
    pub fn len(&self) -> usize {
        self.len as usize
    }

    /// Returns whether the array is full or not.
    pub fn is_full(&self) -> bool {
        (self.len as usize) == MAX_LEN
    }

    /// Returns a slice to the nodes array.
    pub fn nodes(&self) -> &[Arc<Node>] {
        &self.nodes[..(self.len as usize)]
    }

    /// Returns a mutable slice to the nodes array.
    pub fn nodes_mut(&mut self) -> &mut [Arc<Node>] {
        &mut self.nodes[..(self.len as usize)]
    }

    /// Returns a slice to the info array.
    pub fn info(&self) -> &[TextInfo] {
        &self.info[..(self.len as usize)]
    }

    /// Returns a mutable slice to the info array.
    pub fn info_mut(&mut self) -> &mut [TextInfo] {
        &mut self.info[..(self.len as usize)]
    }

    /// Returns mutable slices to both the nodes and info arrays.
    pub fn info_and_nodes_mut(&mut self) -> (&mut [TextInfo], &mut [Arc<Node>]) {
        (
            &mut self.info[..(self.len as usize)],
            &mut self.nodes[..(self.len as usize)],
        )
    }

    /// Pushes an item into the end of the array.
    ///
    /// Increases length by one.  Panics if already full.
    pub fn push(&mut self, item: (TextInfo, Arc<Node>)) {
        assert!((self.len as usize) < MAX_LEN);
        self.info[self.len as usize] = item.0;
        mem::forget(mem::replace(&mut self.nodes[self.len as usize], item.1));
        self.len += 1;
    }

    /// Pushes an element onto the end of the array, and then splits it in half,
    /// returning the right half.
    ///
    /// This works even when the array is full.
    pub fn push_split(&mut self, new_child: (TextInfo, Arc<Node>)) -> ChildArray {
        let mut right = ChildArray::new();

        let r_count = (self.len() + 1) / 2;
        let l_count = (self.len() + 1) - r_count;

        for _ in l_count..self.len() {
            right.push(self.remove(l_count));
        }
        right.push(new_child);

        right
    }

    /// Pops an item off the end of the array and returns it.
    ///
    /// Decreases length by one.  Panics if already empty.
    pub fn pop(&mut self) -> (TextInfo, Arc<Node>) {
        assert!(self.len > 0);
        self.len -= 1;
        let item = (self.info[self.len as usize], unsafe {
            ptr::read(&self.nodes[self.len as usize])
        });
        item
    }

    /// Inserts an item into the the array at the given index.
    ///
    /// Increases length by one.  Panics if already full.  Preserves ordering
    /// of the other items.
    pub fn insert(&mut self, idx: usize, item: (TextInfo, Arc<Node>)) {
        assert!(idx <= (self.len as usize));
        assert!((self.len as usize) < MAX_LEN);

        let len = self.len as usize;
        unsafe {
            ptr::copy(
                self.nodes.as_ptr().offset(idx as isize),
                self.nodes.as_mut_ptr().offset((idx + 1) as isize),
                len - idx,
            );
            ptr::copy(
                self.info.as_ptr().offset(idx as isize),
                self.info.as_mut_ptr().offset((idx + 1) as isize),
                len - idx,
            );
        }

        self.info[idx] = item.0;
        mem::forget(mem::replace(&mut self.nodes[idx], item.1));

        self.len += 1;
    }

    /// Inserts an element into a the array, and then splits it in half, returning
    /// the right half.
    ///
    /// This works even when the array is full.
    pub fn insert_split(&mut self, idx: usize, item: (TextInfo, Arc<Node>)) -> ChildArray {
        assert!(self.len() > 0);
        let extra = if idx < self.len() {
            let extra = self.pop();
            self.insert(idx, item);
            extra
        } else {
            item
        };

        self.push_split(extra)
    }

    /// Removes the at the given index from the the array.
    ///
    /// Decreases length by one.  Preserves ordering of the other items.
    pub fn remove(&mut self, idx: usize) -> (TextInfo, Arc<Node>) {
        assert!(idx < (self.len as usize));

        let item = (self.info[idx], unsafe { ptr::read(&self.nodes[idx]) });

        let len = self.len as usize;
        unsafe {
            ptr::copy(
                self.nodes.as_ptr().offset(idx as isize + 1),
                self.nodes.as_mut_ptr().offset(idx as isize),
                len - idx - 1,
            );
            ptr::copy(
                self.info.as_ptr().offset(idx as isize + 1),
                self.info.as_mut_ptr().offset(idx as isize),
                len - idx - 1,
            );
        }

        self.len -= 1;
        return item;
    }

    /// Gets references to the nth item's node and info.
    pub fn i(&self, n: usize) -> (&TextInfo, &Arc<Node>) {
        assert!(n < self.len as usize);
        (
            &self.info[self.len as usize],
            &self.nodes[self.len as usize],
        )
    }

    /// Gets mut references to the nth item's node and info.
    pub fn i_mut(&mut self, n: usize) -> (&mut TextInfo, &mut Arc<Node>) {
        assert!(n < self.len as usize);
        (
            &mut self.info[self.len as usize],
            &mut self.nodes[self.len as usize],
        )
    }

    /// Creates an iterator over the array's items.
    pub fn iter(&self) -> Zip<slice::Iter<TextInfo>, slice::Iter<Arc<Node>>> {
        Iterator::zip(
            (&self.info[..(self.len as usize)]).iter(),
            (&self.nodes[..(self.len as usize)]).iter(),
        )
    }

    /// Creates an iterator over the array's items.
    pub fn iter_mut(&mut self) -> Zip<slice::IterMut<TextInfo>, slice::IterMut<Arc<Node>>> {
        Iterator::zip(
            (&mut self.info[..(self.len as usize)]).iter_mut(),
            (&mut self.nodes[..(self.len as usize)]).iter_mut(),
        )
    }

    pub fn combined_info(&self) -> TextInfo {
        self.info[..self.len()].iter().fold(
            TextInfo::new(),
            |a, b| a.combine(b),
        )
    }

    pub fn search_combine_info<F: Fn(&TextInfo) -> bool>(&self, pred: F) -> (usize, TextInfo) {
        let mut accum = TextInfo::new();
        for (idx, inf) in self.info[..self.len()].iter().enumerate() {
            if pred(&accum.combine(inf)) {
                return (idx, accum);
            } else {
                accum = accum.combine(inf);
            }
        }
        panic!("Predicate is mal-formed and never evaluated true.")
    }
}

impl Drop for ChildArray {
    fn drop(&mut self) {
        for node in &mut self.nodes[..self.len as usize] {
            let mptr: *mut Arc<Node> = node; // Make sure we have the right dereference
            unsafe { ptr::drop_in_place(mptr) };
        }
    }
}
<commit_msg>Fixed memory safety hole.<commit_after>#![allow(dead_code)]

use std;
use std::iter::{Iterator, Zip};
use std::mem;
use std::mem::ManuallyDrop;
use std::ptr;
use std::slice;
use std::sync::Arc;

use node;
use node::Node;
use text_info::TextInfo;

const MAX_LEN: usize = node::MAX_CHILDREN;

#[derive(Debug)]
pub(crate) struct ChildArray {
    nodes: ManuallyDrop<[Arc<Node>; MAX_LEN]>,
    info: [TextInfo; MAX_LEN],
    len: u8,
}

impl ChildArray {
    /// Creates a new empty array.
    pub fn new() -> ChildArray {
        ChildArray {
            nodes: ManuallyDrop::new(unsafe { std::mem::uninitialized() }),
            info: unsafe { std::mem::uninitialized() },
            len: 0,
        }
    }

    /// Current length of the array.
    pub fn len(&self) -> usize {
        self.len as usize
    }

    /// Returns whether the array is full or not.
    pub fn is_full(&self) -> bool {
        (self.len as usize) == MAX_LEN
    }

    /// Returns a slice to the nodes array.
    pub fn nodes(&self) -> &[Arc<Node>] {
        &self.nodes[..(self.len as usize)]
    }

    /// Returns a mutable slice to the nodes array.
    pub fn nodes_mut(&mut self) -> &mut [Arc<Node>] {
        &mut self.nodes[..(self.len as usize)]
    }

    /// Returns a slice to the info array.
    pub fn info(&self) -> &[TextInfo] {
        &self.info[..(self.len as usize)]
    }

    /// Returns a mutable slice to the info array.
    pub fn info_mut(&mut self) -> &mut [TextInfo] {
        &mut self.info[..(self.len as usize)]
    }

    /// Returns mutable slices to both the nodes and info arrays.
    pub fn info_and_nodes_mut(&mut self) -> (&mut [TextInfo], &mut [Arc<Node>]) {
        (
            &mut self.info[..(self.len as usize)],
            &mut self.nodes[..(self.len as usize)],
        )
    }

    /// Pushes an item into the end of the array.
    ///
    /// Increases length by one.  Panics if already full.
    pub fn push(&mut self, item: (TextInfo, Arc<Node>)) {
        assert!((self.len as usize) < MAX_LEN);
        self.info[self.len as usize] = item.0;
        mem::forget(mem::replace(&mut self.nodes[self.len as usize], item.1));
        self.len += 1;
    }

    /// Pushes an element onto the end of the array, and then splits it in half,
    /// returning the right half.
    ///
    /// This works even when the array is full.
    pub fn push_split(&mut self, new_child: (TextInfo, Arc<Node>)) -> ChildArray {
        let mut right = ChildArray::new();

        let r_count = (self.len() + 1) / 2;
        let l_count = (self.len() + 1) - r_count;

        for _ in l_count..self.len() {
            right.push(self.remove(l_count));
        }
        right.push(new_child);

        right
    }

    /// Pops an item off the end of the array and returns it.
    ///
    /// Decreases length by one.  Panics if already empty.
    pub fn pop(&mut self) -> (TextInfo, Arc<Node>) {
        assert!(self.len > 0);
        self.len -= 1;
        let item = (self.info[self.len as usize], unsafe {
            ptr::read(&self.nodes[self.len as usize])
        });
        item
    }

    /// Inserts an item into the the array at the given index.
    ///
    /// Increases length by one.  Panics if already full.  Preserves ordering
    /// of the other items.
    pub fn insert(&mut self, idx: usize, item: (TextInfo, Arc<Node>)) {
        assert!(idx <= (self.len as usize));
        assert!((self.len as usize) < MAX_LEN);

        let len = self.len as usize;
        unsafe {
            ptr::copy(
                self.nodes.as_ptr().offset(idx as isize),
                self.nodes.as_mut_ptr().offset((idx + 1) as isize),
                len - idx,
            );
            ptr::copy(
                self.info.as_ptr().offset(idx as isize),
                self.info.as_mut_ptr().offset((idx + 1) as isize),
                len - idx,
            );
        }

        self.info[idx] = item.0;
        mem::forget(mem::replace(&mut self.nodes[idx], item.1));

        self.len += 1;
    }

    /// Inserts an element into a the array, and then splits it in half, returning
    /// the right half.
    ///
    /// This works even when the array is full.
    pub fn insert_split(&mut self, idx: usize, item: (TextInfo, Arc<Node>)) -> ChildArray {
        assert!(self.len() > 0);
        let extra = if idx < self.len() {
            let extra = self.pop();
            self.insert(idx, item);
            extra
        } else {
            item
        };

        self.push_split(extra)
    }

    /// Removes the item at the given index from the the array.
    ///
    /// Decreases length by one.  Preserves ordering of the other items.
    pub fn remove(&mut self, idx: usize) -> (TextInfo, Arc<Node>) {
        assert!(idx < (self.len as usize));

        let item = (self.info[idx], unsafe { ptr::read(&self.nodes[idx]) });

        let len = self.len as usize;
        unsafe {
            ptr::copy(
                self.nodes.as_ptr().offset(idx as isize + 1),
                self.nodes.as_mut_ptr().offset(idx as isize),
                len - idx - 1,
            );
            ptr::copy(
                self.info.as_ptr().offset(idx as isize + 1),
                self.info.as_mut_ptr().offset(idx as isize),
                len - idx - 1,
            );
        }

        self.len -= 1;
        return item;
    }

    /// Gets references to the nth item's node and info.
    pub fn i(&self, n: usize) -> (&TextInfo, &Arc<Node>) {
        assert!(n < self.len as usize);
        (
            &self.info[self.len as usize],
            &self.nodes[self.len as usize],
        )
    }

    /// Gets mut references to the nth item's node and info.
    pub fn i_mut(&mut self, n: usize) -> (&mut TextInfo, &mut Arc<Node>) {
        assert!(n < self.len as usize);
        (
            &mut self.info[self.len as usize],
            &mut self.nodes[self.len as usize],
        )
    }

    /// Creates an iterator over the array's items.
    pub fn iter(&self) -> Zip<slice::Iter<TextInfo>, slice::Iter<Arc<Node>>> {
        Iterator::zip(
            (&self.info[..(self.len as usize)]).iter(),
            (&self.nodes[..(self.len as usize)]).iter(),
        )
    }

    /// Creates an iterator over the array's items.
    pub fn iter_mut(&mut self) -> Zip<slice::IterMut<TextInfo>, slice::IterMut<Arc<Node>>> {
        Iterator::zip(
            (&mut self.info[..(self.len as usize)]).iter_mut(),
            (&mut self.nodes[..(self.len as usize)]).iter_mut(),
        )
    }

    pub fn combined_info(&self) -> TextInfo {
        self.info[..self.len()].iter().fold(
            TextInfo::new(),
            |a, b| a.combine(b),
        )
    }

    pub fn search_combine_info<F: Fn(&TextInfo) -> bool>(&self, pred: F) -> (usize, TextInfo) {
        let mut accum = TextInfo::new();
        for (idx, inf) in self.info[..self.len()].iter().enumerate() {
            if pred(&accum.combine(inf)) {
                return (idx, accum);
            } else {
                accum = accum.combine(inf);
            }
        }
        panic!("Predicate is mal-formed and never evaluated true.")
    }
}

impl Drop for ChildArray {
    fn drop(&mut self) {
        for node in &mut self.nodes[..self.len as usize] {
            let mptr: *mut Arc<Node> = node; // Make sure we have the right dereference
            unsafe { ptr::drop_in_place(mptr) };
        }
    }
}

impl Clone for ChildArray {
    fn clone(&self) -> ChildArray {
        let mut clone_array = ChildArray::new();

        // Copy nodes... carefully.
        for (i, arc) in self.nodes[..self.len()].iter().enumerate() {
            mem::forget(mem::replace(&mut clone_array.nodes[i], arc.clone()));
        }

        // Copy TextInfo
        for (clone_info, info) in
            Iterator::zip(
                clone_array.info[..self.len()].iter_mut(),
                self.info[..self.len()].iter(),
            )
        {
            *clone_info = *info;
        }

        // Set length
        clone_array.len = self.len;

        clone_array
    }
}
<|endoftext|>


<commit_before>#![warn(missing_docs)]
//! The module contains Rust representation of Cassandra consistency levels.
use std::io;
use std::convert::From;
use std::default::Default;
use super::{IntoBytes, FromCursor};
use super::types::*;
use super::FromBytes;

/// `Consistency` is an enum which represents Cassandra's consistency levels.
/// To find more details about each consistency level please refer to Cassandra official docs.
#[derive(Debug, PartialEq, Clone)]
pub enum Consistency {
    /// A write must be written to the commit log and memtable on all replica nodes in the cluster
    /// for that partition key.	Provides the highest consistency
    /// and the lowest availability of any other level.
    Any,
    ///
    /// A write must be written to the commit log and memtable of at least one replica node.
    /// Satisfies the needs of most users because consistency requirements are not stringent.
    One,
    /// A write must be written to the commit log and memtable of at least two replica nodes.
    /// Similar to ONE.
    Two,

    /// A write must be written to the commit log and memtable of at least three replica nodes.
    /// Similar to TWO.
    Three,
    /// A write must be written to the commit log and memtable on a quorum of replica nodes.
    /// Provides strong consistency if you can tolerate some level of failure.
    Quorum,
    /// A write must be written to the commit log and memtable on all replica nodes in the cluster
    /// for that partition key.
    /// Provides the highest consistency and the lowest availability of any other level.
    All,
    /// Strong consistency. A write must be written to the commit log and memtable on a quorum
    /// of replica nodes in the same data center as thecoordinator node.
    /// Avoids latency of inter-data center communication.
    /// Used in multiple data center clusters with a rack-aware replica placement strategy,
    /// such as NetworkTopologyStrategy, and a properly configured snitch.
    /// Use to maintain consistency locally (within the single data center).
    /// Can be used with SimpleStrategy.
    LocalQuorum,
    /// Strong consistency. A write must be written to the commit log and memtable on a quorum of
    /// replica nodes in all data center.
    /// Used in multiple data center clusters to strictly maintain consistency at the same level
    /// in each data center. For example, choose this level
    /// if you want a read to fail when a data center is down and the QUORUM
    /// cannot be reached on that data center.
    EachQuorum,
    /// Achieves linearizable consistency for lightweight transactions by preventing unconditional
    /// updates.	You cannot configure this level as a normal consistency level,
    /// configured at the driver level using the consistency level field.
    /// You configure this level using the serial consistency field
    /// as part of the native protocol operation. See failure scenarios.
    Serial,
    /// Same as SERIAL but confined to the data center. A write must be written conditionally
    /// to the commit log and memtable on a quorum of replica nodes in the same data center.
    /// Same as SERIAL. Used for disaster recovery. See failure scenarios.
    LocalSerial,
    /// A write must be sent to, and successfully acknowledged by,
    /// at least one replica node in the local data center.
    /// In a multiple data center clusters, a consistency level of ONE is often desirable,
    /// but cross-DC traffic is not. LOCAL_ONE accomplishes this.
    /// For security and quality reasons, you can use this consistency level
    /// in an offline datacenter to prevent automatic connection
    /// to online nodes in other data centers if an offline node goes down.
    LocalOne,
    /// This is an error scenario either the client code doesn't support it or server is sending
    /// bad headers
    Unknown,
}

impl Default for Consistency {
    fn default() -> Consistency {
        Consistency::One
    }
}

impl IntoBytes for Consistency {
    fn into_cbytes(&self) -> Vec<u8> {
        return match self {
            &Consistency::Any => to_short(0x0000),
            &Consistency::One => to_short(0x0001),
            &Consistency::Two => to_short(0x0002),
            &Consistency::Three => to_short(0x0003),
            &Consistency::Quorum => to_short(0x0004),
            &Consistency::All => to_short(0x0005),
            &Consistency::LocalQuorum => to_short(0x0006),
            &Consistency::EachQuorum => to_short(0x0007),
            &Consistency::Serial => to_short(0x0008),
            &Consistency::LocalSerial => to_short(0x0009),
            &Consistency::LocalOne => to_short(0x000A),
            &Consistency::Unknown => to_short(0x0063),
            //giving Unknown a value of 99
        };
    }
}

impl From<i32> for Consistency {
    fn from(bytes: i32) -> Consistency {
        return match bytes {
            0x0000 => Consistency::Any,
            0x0001 => Consistency::One,
            0x0002 => Consistency::Two,
            0x0003 => Consistency::Three,
            0x0004 => Consistency::Quorum,
            0x0005 => Consistency::All,
            0x0006 => Consistency::LocalQuorum,
            0x0007 => Consistency::EachQuorum,
            0x0008 => Consistency::Serial,
            0x0009 => Consistency::LocalSerial,
            0x000A => Consistency::LocalOne,
            _ => Consistency::Unknown,
        };
    }
}

impl FromBytes for Consistency {
    fn from_bytes(bytes: Vec<u8>) -> Consistency {
        return match from_bytes(bytes.clone()) {
            0x0000 => Consistency::Any,
            0x0001 => Consistency::One,
            0x0002 => Consistency::Two,
            0x0003 => Consistency::Three,
            0x0004 => Consistency::Quorum,
            0x0005 => Consistency::All,
            0x0006 => Consistency::LocalQuorum,
            0x0007 => Consistency::EachQuorum,
            0x0008 => Consistency::Serial,
            0x0009 => Consistency::LocalSerial,
            0x000A => Consistency::LocalOne,
            _ => Consistency::Unknown,
        };
    }
}

impl FromCursor for Consistency {
    fn from_cursor(mut cursor: &mut io::Cursor<Vec<u8>>) -> Consistency {
        let consistency_num = CIntShort::from_cursor(&mut cursor) as i32;
        return Consistency::from(consistency_num);
    }
}

#[cfg(test)]
mod tests {
    use std::io::Cursor;
    use {IntoBytes, FromBytes, FromCursor};
    use super::*;

    #[test]
    fn test_consistency_into_cbytes() {
        assert_eq!(Consistency::Any.into_cbytes(), vec![0, 0]);
        assert_eq!(Consistency::One.into_cbytes(), vec![0, 1]);
        assert_eq!(Consistency::Two.into_cbytes(), vec![0, 2]);
        assert_eq!(Consistency::Three.into_cbytes(), vec![0, 3]);
        assert_eq!(Consistency::Quorum.into_cbytes(), vec![0, 4]);
        assert_eq!(Consistency::All.into_cbytes(), vec![0, 5]);
        assert_eq!(Consistency::LocalQuorum.into_cbytes(), vec![0, 6]);
        assert_eq!(Consistency::EachQuorum.into_cbytes(), vec![0, 7]);
        assert_eq!(Consistency::Serial.into_cbytes(), vec![0, 8]);
        assert_eq!(Consistency::LocalSerial.into_cbytes(), vec![0, 9]);
        assert_eq!(Consistency::LocalOne.into_cbytes(), vec![0, 10]);
    }

    #[test]
    fn test_consistency_from() {
        assert_eq!(Consistency::from(0), Consistency::Any);
        assert_eq!(Consistency::from(1), Consistency::One);
        assert_eq!(Consistency::from(2), Consistency::Two);
        assert_eq!(Consistency::from(3), Consistency::Three);
        assert_eq!(Consistency::from(4), Consistency::Quorum);
        assert_eq!(Consistency::from(5), Consistency::All);
        assert_eq!(Consistency::from(6), Consistency::LocalQuorum);
        assert_eq!(Consistency::from(7), Consistency::EachQuorum);
        assert_eq!(Consistency::from(8), Consistency::Serial);
        assert_eq!(Consistency::from(9), Consistency::LocalSerial);
        assert_eq!(Consistency::from(10), Consistency::LocalOne);
        assert_eq!(Consistency::from(11), Consistency::Unknown);
    }

    #[test]
    fn test_consistency_from_bytes() {
        assert_eq!(Consistency::from_bytes(vec![0, 0]), Consistency::Any);
        assert_eq!(Consistency::from_bytes(vec![0, 1]), Consistency::One);
        assert_eq!(Consistency::from_bytes(vec![0, 2]), Consistency::Two);
        assert_eq!(Consistency::from_bytes(vec![0, 3]), Consistency::Three);
        assert_eq!(Consistency::from_bytes(vec![0, 4]), Consistency::Quorum);
        assert_eq!(Consistency::from_bytes(vec![0, 5]), Consistency::All);
        assert_eq!(Consistency::from_bytes(vec![0, 6]),
                   Consistency::LocalQuorum);
        assert_eq!(Consistency::from_bytes(vec![0, 7]), Consistency::EachQuorum);
        assert_eq!(Consistency::from_bytes(vec![0, 8]), Consistency::Serial);
        assert_eq!(Consistency::from_bytes(vec![0, 9]),
                   Consistency::LocalSerial);
        assert_eq!(Consistency::from_bytes(vec![0, 10]), Consistency::LocalOne);
        assert_eq!(Consistency::from_bytes(vec![0, 11]), Consistency::Unknown);
    }

    #[test]
    fn test_consistency_from_cursor() {
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 0])),
                   Consistency::Any);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 1])),
                   Consistency::One);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 2])),
                   Consistency::Two);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 3])),
                   Consistency::Three);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 4])),
                   Consistency::Quorum);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 5])),
                   Consistency::All);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 6])),
                   Consistency::LocalQuorum);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 7])),
                   Consistency::EachQuorum);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 8])),
                   Consistency::Serial);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 9])),
                   Consistency::LocalSerial);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 10])),
                   Consistency::LocalOne);
    }

}
<commit_msg>added test case for unknown consistency<commit_after>#![warn(missing_docs)]
//! The module contains Rust representation of Cassandra consistency levels.
use std::io;
use std::convert::From;
use std::default::Default;
use super::{IntoBytes, FromCursor};
use super::types::*;
use super::FromBytes;

/// `Consistency` is an enum which represents Cassandra's consistency levels.
/// To find more details about each consistency level please refer to Cassandra official docs.
#[derive(Debug, PartialEq, Clone)]
pub enum Consistency {
    /// A write must be written to the commit log and memtable on all replica nodes in the cluster
    /// for that partition key.	Provides the highest consistency
    /// and the lowest availability of any other level.
    Any,
    ///
    /// A write must be written to the commit log and memtable of at least one replica node.
    /// Satisfies the needs of most users because consistency requirements are not stringent.
    One,
    /// A write must be written to the commit log and memtable of at least two replica nodes.
    /// Similar to ONE.
    Two,

    /// A write must be written to the commit log and memtable of at least three replica nodes.
    /// Similar to TWO.
    Three,
    /// A write must be written to the commit log and memtable on a quorum of replica nodes.
    /// Provides strong consistency if you can tolerate some level of failure.
    Quorum,
    /// A write must be written to the commit log and memtable on all replica nodes in the cluster
    /// for that partition key.
    /// Provides the highest consistency and the lowest availability of any other level.
    All,
    /// Strong consistency. A write must be written to the commit log and memtable on a quorum
    /// of replica nodes in the same data center as thecoordinator node.
    /// Avoids latency of inter-data center communication.
    /// Used in multiple data center clusters with a rack-aware replica placement strategy,
    /// such as NetworkTopologyStrategy, and a properly configured snitch.
    /// Use to maintain consistency locally (within the single data center).
    /// Can be used with SimpleStrategy.
    LocalQuorum,
    /// Strong consistency. A write must be written to the commit log and memtable on a quorum of
    /// replica nodes in all data center.
    /// Used in multiple data center clusters to strictly maintain consistency at the same level
    /// in each data center. For example, choose this level
    /// if you want a read to fail when a data center is down and the QUORUM
    /// cannot be reached on that data center.
    EachQuorum,
    /// Achieves linearizable consistency for lightweight transactions by preventing unconditional
    /// updates.	You cannot configure this level as a normal consistency level,
    /// configured at the driver level using the consistency level field.
    /// You configure this level using the serial consistency field
    /// as part of the native protocol operation. See failure scenarios.
    Serial,
    /// Same as SERIAL but confined to the data center. A write must be written conditionally
    /// to the commit log and memtable on a quorum of replica nodes in the same data center.
    /// Same as SERIAL. Used for disaster recovery. See failure scenarios.
    LocalSerial,
    /// A write must be sent to, and successfully acknowledged by,
    /// at least one replica node in the local data center.
    /// In a multiple data center clusters, a consistency level of ONE is often desirable,
    /// but cross-DC traffic is not. LOCAL_ONE accomplishes this.
    /// For security and quality reasons, you can use this consistency level
    /// in an offline datacenter to prevent automatic connection
    /// to online nodes in other data centers if an offline node goes down.
    LocalOne,
    /// This is an error scenario either the client code doesn't support it or server is sending
    /// bad headers
    Unknown,
}

impl Default for Consistency {
    fn default() -> Consistency {
        Consistency::One
    }
}

impl IntoBytes for Consistency {
    fn into_cbytes(&self) -> Vec<u8> {
        return match self {
            &Consistency::Any => to_short(0x0000),
            &Consistency::One => to_short(0x0001),
            &Consistency::Two => to_short(0x0002),
            &Consistency::Three => to_short(0x0003),
            &Consistency::Quorum => to_short(0x0004),
            &Consistency::All => to_short(0x0005),
            &Consistency::LocalQuorum => to_short(0x0006),
            &Consistency::EachQuorum => to_short(0x0007),
            &Consistency::Serial => to_short(0x0008),
            &Consistency::LocalSerial => to_short(0x0009),
            &Consistency::LocalOne => to_short(0x000A),
            &Consistency::Unknown => to_short(0x0063),
            //giving Unknown a value of 99
        };
    }
}

impl From<i32> for Consistency {
    fn from(bytes: i32) -> Consistency {
        return match bytes {
            0x0000 => Consistency::Any,
            0x0001 => Consistency::One,
            0x0002 => Consistency::Two,
            0x0003 => Consistency::Three,
            0x0004 => Consistency::Quorum,
            0x0005 => Consistency::All,
            0x0006 => Consistency::LocalQuorum,
            0x0007 => Consistency::EachQuorum,
            0x0008 => Consistency::Serial,
            0x0009 => Consistency::LocalSerial,
            0x000A => Consistency::LocalOne,
            _ => Consistency::Unknown,
        };
    }
}

impl FromBytes for Consistency {
    fn from_bytes(bytes: Vec<u8>) -> Consistency {
        return match from_bytes(bytes.clone()) {
            0x0000 => Consistency::Any,
            0x0001 => Consistency::One,
            0x0002 => Consistency::Two,
            0x0003 => Consistency::Three,
            0x0004 => Consistency::Quorum,
            0x0005 => Consistency::All,
            0x0006 => Consistency::LocalQuorum,
            0x0007 => Consistency::EachQuorum,
            0x0008 => Consistency::Serial,
            0x0009 => Consistency::LocalSerial,
            0x000A => Consistency::LocalOne,
            _ => Consistency::Unknown,
        };
    }
}

impl FromCursor for Consistency {
    fn from_cursor(mut cursor: &mut io::Cursor<Vec<u8>>) -> Consistency {
        let consistency_num = CIntShort::from_cursor(&mut cursor) as i32;
        return Consistency::from(consistency_num);
    }
}

#[cfg(test)]
mod tests {
    use std::io::Cursor;
    use {IntoBytes, FromBytes, FromCursor};
    use super::*;

    #[test]
    fn test_consistency_into_cbytes() {
        assert_eq!(Consistency::Any.into_cbytes(), vec![0, 0]);
        assert_eq!(Consistency::One.into_cbytes(), vec![0, 1]);
        assert_eq!(Consistency::Two.into_cbytes(), vec![0, 2]);
        assert_eq!(Consistency::Three.into_cbytes(), vec![0, 3]);
        assert_eq!(Consistency::Quorum.into_cbytes(), vec![0, 4]);
        assert_eq!(Consistency::All.into_cbytes(), vec![0, 5]);
        assert_eq!(Consistency::LocalQuorum.into_cbytes(), vec![0, 6]);
        assert_eq!(Consistency::EachQuorum.into_cbytes(), vec![0, 7]);
        assert_eq!(Consistency::Serial.into_cbytes(), vec![0, 8]);
        assert_eq!(Consistency::LocalSerial.into_cbytes(), vec![0, 9]);
        assert_eq!(Consistency::LocalOne.into_cbytes(), vec![0, 10]);
        assert_eq!(Consistency::Unknown.into_cbytes(), vec![0, 99]);
    }

    #[test]
    fn test_consistency_from() {
        assert_eq!(Consistency::from(0), Consistency::Any);
        assert_eq!(Consistency::from(1), Consistency::One);
        assert_eq!(Consistency::from(2), Consistency::Two);
        assert_eq!(Consistency::from(3), Consistency::Three);
        assert_eq!(Consistency::from(4), Consistency::Quorum);
        assert_eq!(Consistency::from(5), Consistency::All);
        assert_eq!(Consistency::from(6), Consistency::LocalQuorum);
        assert_eq!(Consistency::from(7), Consistency::EachQuorum);
        assert_eq!(Consistency::from(8), Consistency::Serial);
        assert_eq!(Consistency::from(9), Consistency::LocalSerial);
        assert_eq!(Consistency::from(10), Consistency::LocalOne);
        assert_eq!(Consistency::from(11), Consistency::Unknown);
    }

    #[test]
    fn test_consistency_from_bytes() {
        assert_eq!(Consistency::from_bytes(vec![0, 0]), Consistency::Any);
        assert_eq!(Consistency::from_bytes(vec![0, 1]), Consistency::One);
        assert_eq!(Consistency::from_bytes(vec![0, 2]), Consistency::Two);
        assert_eq!(Consistency::from_bytes(vec![0, 3]), Consistency::Three);
        assert_eq!(Consistency::from_bytes(vec![0, 4]), Consistency::Quorum);
        assert_eq!(Consistency::from_bytes(vec![0, 5]), Consistency::All);
        assert_eq!(Consistency::from_bytes(vec![0, 6]),
                   Consistency::LocalQuorum);
        assert_eq!(Consistency::from_bytes(vec![0, 7]), Consistency::EachQuorum);
        assert_eq!(Consistency::from_bytes(vec![0, 8]), Consistency::Serial);
        assert_eq!(Consistency::from_bytes(vec![0, 9]),
                   Consistency::LocalSerial);
        assert_eq!(Consistency::from_bytes(vec![0, 10]), Consistency::LocalOne);
        assert_eq!(Consistency::from_bytes(vec![0, 11]), Consistency::Unknown);
    }

    #[test]
    fn test_consistency_from_cursor() {
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 0])),
                   Consistency::Any);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 1])),
                   Consistency::One);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 2])),
                   Consistency::Two);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 3])),
                   Consistency::Three);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 4])),
                   Consistency::Quorum);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 5])),
                   Consistency::All);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 6])),
                   Consistency::LocalQuorum);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 7])),
                   Consistency::EachQuorum);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 8])),
                   Consistency::Serial);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 9])),
                   Consistency::LocalSerial);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 10])),
                   Consistency::LocalOne);
    }

}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use util::errors::{
    Result,
    Error,
};

use term::terminfo::TermInfo;
use term::terminfo::parm;
use term::terminfo::parm::{
    Param,
    Variables,
};

// String constants correspond to terminfo capnames and are used inside the module for convenience.
const ENTER_CA: &'static str = "smcup";
const EXIT_CA: &'static str = "rmcup";
const SHOW_CURSOR: &'static str = "cnorm";
const HIDE_CURSOR: &'static str = "civis";
const SET_CURSOR: &'static str = "cup";
const CLEAR: &'static str = "clear";
const RESET: &'static str = "sgr0";
const UNDERLINE: &'static str = "smul";
const BOLD: &'static str = "bold";
const BLINK: &'static str = "blink";
const REVERSE: &'static str = "rev";
const SETFG: &'static str = "setaf";
const SETBG: &'static str = "setab";

// Terminfo keys. These are arrays because the terminfo database from the `term` crate sometimes
// uses the variable name and othertimes the capname.
//
// Arrays are formatted as ["variable_name", "cap_name"].
const KEY_F1: &'static [&'static str] = &["key_f1", "kf1"];
const KEY_F2: &'static [&'static str] = &["key_f2", "kf2"];
const KEY_F3: &'static [&'static str] = &["key_f3", "kf3"];
const KEY_F4: &'static [&'static str] = &["key_f4", "kf4"];
const KEY_F5: &'static [&'static str] = &["key_f5", "kf5"];
const KEY_F6: &'static [&'static str] = &["key_f6", "kf6"];
const KEY_F7: &'static [&'static str] = &["key_f7", "kf7"];
const KEY_F8: &'static [&'static str] = &["key_f8", "kf8"];
const KEY_F9: &'static [&'static str] = &["key_f9", "kf9"];
const KEY_F10: &'static [&'static str] = &["key_f10", "kf10"];
const KEY_F11: &'static [&'static str] = &["key_f11", "kf11"];
const KEY_F12: &'static [&'static str] = &["key_f12", "kf12"];
const KEY_UP: &'static [&'static str] = &["key_up", "kcuu1"];
const KEY_DOWN: &'static [&'static str] = &["key_down", "kcud1"];
const KEY_LEFT: &'static [&'static str] = &["key_left", "kcub1"];
const KEY_RIGHT: &'static [&'static str] = &["key_right", "kcuf1"];

// Array of terminal keys.
const KEYS: &'static [&'static [&'static str]] = &[
    KEY_F1,
    KEY_F2,
    KEY_F3,
    KEY_F4,
    KEY_F5,
    KEY_F6,
    KEY_F7,
    KEY_F8,
    KEY_F9,
    KEY_F10,
    KEY_F11,
    KEY_F12,
    KEY_UP,
    KEY_DOWN,
    KEY_LEFT,
    KEY_RIGHT,
];

// Array of terminal capabilities. Used as an iterator to test for functionality.
//
// At the moment all functionality is required, however in the future we should implement optional
// functionality checks so the absence of underlining or reverse video doesn't cause initialization
// to fail.
//
// TODO: Optional functionality testing.
const CAPABILITIES: &'static [&'static str] = &[
    ENTER_CA,
    EXIT_CA,
    SHOW_CURSOR,
    HIDE_CURSOR,
    SET_CURSOR,
    CLEAR,
    RESET,
    UNDERLINE,
    BOLD,
    REVERSE,
    SETFG,
    SETBG,
];

// Driver capabilities are an enum instead of string constants (there are string constants private
// to the module however, those are only used for naming convenience and disambiguation)
// to take advantage of compile-time type-checking instead of hoping invalid strings aren't passed.
// This allows us to guarantee that driver accesses will succeed. In addition, using an enum means
// Driver doesn't need hard-coded methods for each capability we want to use.
#[allow(dead_code)]
pub enum DevFn {
    EnterCa,
    ExitCa,
    ShowCursor,
    HideCursor,
    SetCursor(usize, usize),
    Clear,
    Reset,
    Underline,
    Bold,
    Blink,
    Reverse,
    SetFg(u8),
    SetBg(u8),
}

impl DevFn {
    fn as_str(&self) -> &'static str {
        match *self {
            DevFn::EnterCa => ENTER_CA,
            DevFn::ExitCa => EXIT_CA,
            DevFn::ShowCursor => SHOW_CURSOR,
            DevFn::HideCursor => HIDE_CURSOR,
            DevFn::SetCursor(..) => SET_CURSOR,
            DevFn::Clear => CLEAR,
            DevFn::Reset => RESET,
            DevFn::Underline => UNDERLINE,
            DevFn::Bold => BOLD,
            DevFn::Blink => BLINK,
            DevFn::Reverse => REVERSE,
            DevFn::SetFg(..) => SETFG,
            DevFn::SetBg(..) => SETBG,
        }
    }
}

pub struct Driver {
    tinfo: &'static TermInfo,
}

// We will never need to mutate the terminfo database, and it is only used internally as a lookup
// table for the driver. `lazy_static` seems to be the best approach at the moment.
lazy_static! {
    static ref TINFO: TermInfo = {
        TermInfo::from_env().unwrap_or({
            TermInfo {
                names: Default::default(),
                bools: Default::default(),
                numbers: Default::default(),
                strings: Default::default(),
            }
        })
    };
}

// Validates and returns a reference to the terminfo database.
//
// If this function returns Ok(..), the contained terminfo database is guaranteed to have the
// functionality found in CAPABILITIES.
//
// If this function returns Err(..), the terminfo database did not contain all the required
// functionality; the error returned will provide more specific detail.
fn get_tinfo() -> Result<&'static TermInfo> {
    let tinfo = &*TINFO;

    for capname in CAPABILITIES {
        if !tinfo.strings.contains_key(*capname) {
            return Err(Error::new(format!("terminal missing capability: '{}'", capname)));
        }
    }
    Ok(tinfo)
}

impl Driver {
    // Creates a new `Driver`
    //
    // If successful, the terminfo database is guaranteed to contain all capabilities we support.
    pub fn new() -> Result<Driver> {
        let tinfo = try!(get_tinfo());
        Ok(Driver {
            tinfo: tinfo,
        })
    }

    // Returns the device specific escape sequence for the given `DevFn`.
    //
    // get() will not return an error, and (in theory) should never panic. The `DevFn` enum
    // restricts possible inputs to a subset that will not fail when passed to `parm::expand()`.
    // This can be verified by examining the source of the `parm::expand()` function in the `term`
    // crate.
    //
    // Furthermore, the pre-flight checks on initialization of `Driver` ensure that every
    // capability is present, thus the call to `Hashmap::get()` should never fail.
    pub fn get(&self, dfn: DevFn) -> Vec<u8> {
        let capname = dfn.as_str();
        let cap = self.tinfo.strings.get(capname).unwrap();

        match dfn {
            DevFn::SetFg(attr) | DevFn::SetBg(attr) => {
                let params = &[Param::Number(attr as i16)];
                let mut vars = Variables::new();
                parm::expand(cap, params, &mut vars).unwrap()
            },
            DevFn::SetCursor(x, y) => {
                let params = &[Param::Number(y as i16), Param::Number(x as i16)];
                let mut vars = Variables::new();
                parm::expand(cap, params, &mut vars).unwrap()
            },
            _ => {
                cap.clone()
            },
        }
    }
}

<commit_msg>Fix merge conflict<commit_after>#![allow(dead_code)]

use util::errors::{
    Result,
    Error,
};

use term::terminfo::TermInfo;
use term::terminfo::parm;
use term::terminfo::parm::{
    Param,
    Variables,
};

// String constants correspond to terminfo capnames and are used inside the module for convenience.
const ENTER_CA: &'static str = "smcup";
const EXIT_CA: &'static str = "rmcup";
const SHOW_CURSOR: &'static str = "cnorm";
const HIDE_CURSOR: &'static str = "civis";
const SET_CURSOR: &'static str = "cup";
const CLEAR: &'static str = "clear";
const RESET: &'static str = "sgr0";
const UNDERLINE: &'static str = "smul";
const BOLD: &'static str = "bold";
const BLINK: &'static str = "blink";
const REVERSE: &'static str = "rev";
const SETFG: &'static str = "setaf";
const SETBG: &'static str = "setab";

// Terminfo keys. These are arrays because the terminfo database from the `term` crate sometimes
// uses the variable name and othertimes the capname.
//
// Arrays are formatted as ["variable_name", "cap_name"].
const KEY_F1: &'static [&'static str] = &["key_f1", "kf1"];
const KEY_F2: &'static [&'static str] = &["key_f2", "kf2"];
const KEY_F3: &'static [&'static str] = &["key_f3", "kf3"];
const KEY_F4: &'static [&'static str] = &["key_f4", "kf4"];
const KEY_F5: &'static [&'static str] = &["key_f5", "kf5"];
const KEY_F6: &'static [&'static str] = &["key_f6", "kf6"];
const KEY_F7: &'static [&'static str] = &["key_f7", "kf7"];
const KEY_F8: &'static [&'static str] = &["key_f8", "kf8"];
const KEY_F9: &'static [&'static str] = &["key_f9", "kf9"];
const KEY_F10: &'static [&'static str] = &["key_f10", "kf10"];
const KEY_F11: &'static [&'static str] = &["key_f11", "kf11"];
const KEY_F12: &'static [&'static str] = &["key_f12", "kf12"];
const KEY_UP: &'static [&'static str] = &["key_up", "kcuu1"];
const KEY_DOWN: &'static [&'static str] = &["key_down", "kcud1"];
const KEY_LEFT: &'static [&'static str] = &["key_left", "kcub1"];
const KEY_RIGHT: &'static [&'static str] = &["key_right", "kcuf1"];

// Array of terminal keys.
const KEYS: &'static [&'static [&'static str]] = &[
    KEY_F1,
    KEY_F2,
    KEY_F3,
    KEY_F4,
    KEY_F5,
    KEY_F6,
    KEY_F7,
    KEY_F8,
    KEY_F9,
    KEY_F10,
    KEY_F11,
    KEY_F12,
    KEY_UP,
    KEY_DOWN,
    KEY_LEFT,
    KEY_RIGHT,
];

// Array of terminal capabilities. Used as an iterator to test for functionality.
//
// At the moment all functionality is required, however in the future we should implement optional
// functionality checks so the absence of underlining or reverse video doesn't cause initialization
// to fail.
//
// TODO: Optional functionality testing.
const CAPABILITIES: &'static [&'static str] = &[
    ENTER_CA,
    EXIT_CA,
    SHOW_CURSOR,
    HIDE_CURSOR,
    SET_CURSOR,
    CLEAR,
    RESET,
    UNDERLINE,
    BOLD,
    REVERSE,
    SETFG,
    SETBG,
];

// Driver capabilities are an enum instead of string constants (there are string constants private
// to the module however, those are only used for naming convenience and disambiguation)
// to take advantage of compile-time type-checking instead of hoping invalid strings aren't passed.
// This allows us to guarantee that driver accesses will succeed. In addition, using an enum means
// Driver doesn't need hard-coded methods for each capability we want to use.
#[allow(dead_code)]
pub enum DevFn {
    EnterCa,
    ExitCa,
    ShowCursor,
    HideCursor,
    SetCursor(usize, usize),
    Clear,
    Reset,
    Underline,
    Bold,
    Blink,
    Reverse,
    SetFg(u8),
    SetBg(u8),
}

impl DevFn {
    fn as_str(&self) -> &'static str {
        match *self {
            DevFn::EnterCa => ENTER_CA,
            DevFn::ExitCa => EXIT_CA,
            DevFn::ShowCursor => SHOW_CURSOR,
            DevFn::HideCursor => HIDE_CURSOR,
            DevFn::SetCursor(..) => SET_CURSOR,
            DevFn::Clear => CLEAR,
            DevFn::Reset => RESET,
            DevFn::Underline => UNDERLINE,
            DevFn::Bold => BOLD,
            DevFn::Blink => BLINK,
            DevFn::Reverse => REVERSE,
            DevFn::SetFg(..) => SETFG,
            DevFn::SetBg(..) => SETBG,
        }
    }
}

pub struct Driver {
    tinfo: &'static TermInfo,
}

// We will never need to mutate the terminfo database, and it is only used internally as a lookup
// table for the driver. `lazy_static` seems to be the best approach at the moment.
lazy_static! {
    static ref TINFO: TermInfo = {
        TermInfo::from_env().unwrap_or({
            TermInfo {
                names: Default::default(),
                bools: Default::default(),
                numbers: Default::default(),
                strings: Default::default(),
            }
        })
    };
}

// Validates and returns a reference to the terminfo database.
//
// If this function returns Ok(..), the contained terminfo database is guaranteed to have the
// functionality found in CAPABILITIES.
//
// If this function returns Err(..), the terminfo database did not contain all the required
// functionality; the error returned will provide more specific detail.
fn get_tinfo() -> Result<&'static TermInfo> {
    let tinfo = &*TINFO;

    for capname in CAPABILITIES {
        if !tinfo.strings.contains_key(*capname) {
            return Err(Error::new(format!("terminal missing capability: '{}'", capname)));
        }
    }
    Ok(tinfo)
}

impl Driver {
    // Creates a new `Driver`
    //
    // If successful, the terminfo database is guaranteed to contain all capabilities we support.
    pub fn new() -> Result<Driver> {
        let tinfo = try!(get_tinfo());
        Ok(Driver {
            tinfo: tinfo,
        })
    }

    // Returns the device specific escape sequence for the given `DevFn`.
    //
    // get() will not return an error, and (in theory) should never panic. The `DevFn` enum
    // restricts possible inputs to a subset that will not fail when passed to `parm::expand()`.
    // This can be verified by examining the source of the `parm::expand()` function in the `term`
    // crate.
    //
    // Furthermore, the pre-flight checks on initialization of `Driver` ensure that every
    // capability is present, thus the call to `Hashmap::get()` should never fail.
    pub fn get(&self, dfn: DevFn) -> Vec<u8> {
        let capname = dfn.as_str();
        let cap = self.tinfo.strings.get(capname).unwrap();

        match dfn {
            DevFn::SetFg(attr) | DevFn::SetBg(attr) => {
                let params = &[Param::Number(attr as i32)];
                let mut vars = Variables::new();
                parm::expand(cap, params, &mut vars).unwrap()
            },
            DevFn::SetCursor(x, y) => {
                let params = &[Param::Number(y as i32), Param::Number(x as i32)];
                let mut vars = Variables::new();
                parm::expand(cap, params, &mut vars).unwrap()
            },
            _ => {
                cap.clone()
            },
        }
    }
}

<|endoftext|>


<commit_before>use {
    crate::{
        core::{
            cache::{AsCacheRef, CacheRead, CacheWrite, DeserCache},
            primitive::CommitLog,
            storage,
            workspace::{self, AsWorkspaceRef, Guard, Status, Workspace},
            Bytes, Map,
        },
        Addr, Error, Path,
    },
    tokio::io,
};
pub struct Fixity<C, W> {
    storage: C,
    workspace: W,
}
impl<C, W> Fixity<C, W> {
    /// Create a fixity instance from the provided workspace and storage.
    ///
    /// If you're not intending to provide your own cache / workspace,
    /// see also [`crate::Fixity::builder`].
    pub fn new(storage: C, workspace: W) -> Self {
        Self { storage, workspace }
    }
    /// Take ownership of the underlying cache.
    ///
    /// Useful for interacting directly with underlying [Primitives](crate::core::primitive).
    pub fn into_cache(self) -> C {
        self.storage
    }
}
impl Fixity<DeserCache<()>, workspace::Memory> {
    /// Create a **testing focused** instance of Fixity, with in-memory storage
    /// and workspace.
    ///
    /// # IMPORTANT
    ///
    /// This instance does not save data. Both the storage and the workspace are
    /// in-memory only, and **will be lost** when this instance is dropped.
    pub fn memory() -> Self {
        Self {
            storage: DeserCache::new(()),
            workspace: workspace::Memory::new("default".to_owned()),
        }
    }
}
impl<C, W> Fixity<C, W>
where
    C: CacheRead + CacheWrite,
{
    pub fn map(&self, path: Path) -> Map<'_, C, W> {
        Map::new(&self.storage, &self.workspace, path)
    }
    pub fn bytes(&self, path: Path) -> Result<Bytes<'_, C, W>, Error> {
        if path.is_empty() {
            return Err(Error::CannotReplaceRootMap);
        }
        if !path.is_root_map() {
            return Err(Error::CannotReplaceRootMap);
        }
        Ok(Bytes::new(&self.storage, &self.workspace, path))
    }
}
#[derive(Debug, thiserror::Error)]
pub enum InitError {
    #[error("failed creating fixity directory: `{source}`")]
    CreateDir { source: io::Error },
    #[error("failed creating new storage: `{source}`")]
    Storage {
        #[from]
        source: storage::Error,
    },
}
impl<C, W> AsWorkspaceRef for Fixity<C, W>
where
    W: Workspace,
{
    type Workspace = W;
    fn as_workspace_ref(&self) -> &Self::Workspace {
        &self.workspace
    }
}
impl<C, W> AsCacheRef for Fixity<C, W>
where
    C: CacheRead + CacheWrite,
{
    type Cache = C;
    fn as_cache_ref(&self) -> &Self::Cache {
        &self.storage
    }
}
/// A trait to describe a `T` that can write a new commit log to storage, and
/// update the workspace pointer to the newly writen commit log.
///
/// This trait is usually implemented on core `Fixity` interfaces, such as
/// [`Map`] and [`Bytes`], along with [`Fixity`] itself.
#[async_trait::async_trait]
pub trait Commit {
    /// Commit any staged changes to storage, and update the workspace pointer
    /// to match.
    async fn commit(&self) -> Result<Addr, Error>;
}
#[async_trait::async_trait]
impl<T> Commit for T
where
    T: AsWorkspaceRef + AsCacheRef + Sync,
{
    async fn commit(&self) -> Result<Addr, Error> {
        let storage = self.as_cache_ref();
        let workspace = self.as_workspace_ref();
        let workspace_guard = workspace.lock().await?;
        let (commit_addr, staged_content) = match workspace_guard.status().await? {
            Status::InitStaged { staged_content, .. } => (None, staged_content),
            Status::Staged {
                commit,
                staged_content,
                ..
            } => (Some(commit), staged_content),
            Status::Detached(_) => return Err(Error::DetachedHead),
            Status::Init { .. } | Status::Clean { .. } => {
                return Err(Error::NoStageToCommit);
            },
        };
        let mut commit_log = CommitLog::new(storage, commit_addr);
        let commit_addr = commit_log.append(staged_content).await?;
        workspace_guard.commit(commit_addr.clone()).await?;
        Ok(commit_addr)
    }
}
<commit_msg>feat: core::fixity::into_cw<commit_after>use {
    crate::{
        core::{
            cache::{AsCacheRef, CacheRead, CacheWrite, DeserCache},
            primitive::CommitLog,
            storage,
            workspace::{self, AsWorkspaceRef, Guard, Status, Workspace},
            Bytes, Map,
        },
        Addr, Error, Path,
    },
    tokio::io,
};
pub struct Fixity<C, W> {
    storage: C,
    workspace: W,
}
impl<C, W> Fixity<C, W> {
    /// Create a fixity instance from the provided workspace and storage.
    ///
    /// If you're not intending to provide your own cache / workspace,
    /// see also [`crate::Fixity::builder`].
    pub fn new(storage: C, workspace: W) -> Self {
        Self { storage, workspace }
    }
    /// Take ownership of the underlying cache.
    ///
    /// Useful for interacting directly with underlying [Primitives](crate::core::primitive).
    pub fn into_cache(self) -> C {
        self.into_cw().0
    }
    /// Take ownership of the underlying cache/workspace.
    ///
    /// Useful for interacting directly with underlying [Primitives](crate::core::primitive).
    pub fn into_cw(self) -> (C, W) {
        (self.storage, self.workspace)
    }
}
impl Fixity<DeserCache<()>, workspace::Memory> {
    /// Create a **testing focused** instance of Fixity, with in-memory storage
    /// and workspace.
    ///
    /// # IMPORTANT
    ///
    /// This instance does not save data. Both the storage and the workspace are
    /// in-memory only, and **will be lost** when this instance is dropped.
    pub fn memory() -> Self {
        Self {
            storage: DeserCache::new(()),
            workspace: workspace::Memory::new("default".to_owned()),
        }
    }
}
impl<C, W> Fixity<C, W>
where
    C: CacheRead + CacheWrite,
{
    pub fn map(&self, path: Path) -> Map<'_, C, W> {
        Map::new(&self.storage, &self.workspace, path)
    }
    pub fn bytes(&self, path: Path) -> Result<Bytes<'_, C, W>, Error> {
        if path.is_empty() {
            return Err(Error::CannotReplaceRootMap);
        }
        if !path.is_root_map() {
            return Err(Error::CannotReplaceRootMap);
        }
        Ok(Bytes::new(&self.storage, &self.workspace, path))
    }
}
#[derive(Debug, thiserror::Error)]
pub enum InitError {
    #[error("failed creating fixity directory: `{source}`")]
    CreateDir { source: io::Error },
    #[error("failed creating new storage: `{source}`")]
    Storage {
        #[from]
        source: storage::Error,
    },
}
impl<C, W> AsWorkspaceRef for Fixity<C, W>
where
    W: Workspace,
{
    type Workspace = W;
    fn as_workspace_ref(&self) -> &Self::Workspace {
        &self.workspace
    }
}
impl<C, W> AsCacheRef for Fixity<C, W>
where
    C: CacheRead + CacheWrite,
{
    type Cache = C;
    fn as_cache_ref(&self) -> &Self::Cache {
        &self.storage
    }
}
/// A trait to describe a `T` that can write a new commit log to storage, and
/// update the workspace pointer to the newly writen commit log.
///
/// This trait is usually implemented on core `Fixity` interfaces, such as
/// [`Map`] and [`Bytes`], along with [`Fixity`] itself.
#[async_trait::async_trait]
pub trait Commit {
    /// Commit any staged changes to storage, and update the workspace pointer
    /// to match.
    async fn commit(&self) -> Result<Addr, Error>;
}
#[async_trait::async_trait]
impl<T> Commit for T
where
    T: AsWorkspaceRef + AsCacheRef + Sync,
{
    async fn commit(&self) -> Result<Addr, Error> {
        let storage = self.as_cache_ref();
        let workspace = self.as_workspace_ref();
        let workspace_guard = workspace.lock().await?;
        let (commit_addr, staged_content) = match workspace_guard.status().await? {
            Status::InitStaged { staged_content, .. } => (None, staged_content),
            Status::Staged {
                commit,
                staged_content,
                ..
            } => (Some(commit), staged_content),
            Status::Detached(_) => return Err(Error::DetachedHead),
            Status::Init { .. } | Status::Clean { .. } => {
                return Err(Error::NoStageToCommit);
            },
        };
        let mut commit_log = CommitLog::new(storage, commit_addr);
        let commit_addr = commit_log.append(staged_content).await?;
        workspace_guard.commit(commit_addr.clone()).await?;
        Ok(commit_addr)
    }
}
<|endoftext|>