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

use crate::{
    cargo::{CargoArgs, CargoCommand},
    context::XContext,
    utils,
    utils::project_root,
    Result,
};
use anyhow::Error;
use log::info;
use std::{
    ffi::OsString,
    fs::create_dir_all,
    path::PathBuf,
    process::{Command, Stdio},
};
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
pub struct Args {
    #[structopt(long, short, number_of_values = 1)]
    /// Run test on the provided packages
    package: Vec<String>,
    #[structopt(long, short)]
    /// Skip running expensive libra testsuite integration tests
    unit: bool,
    #[structopt(long)]
    /// Test only this package's library unit tests, skipping doctests
    lib: bool,
    #[structopt(long)]
    /// Do not fast fail the run if tests (or test executables) fail
    no_fail_fast: bool,
    #[structopt(long)]
    /// Do not run tests, only compile the test executables
    no_run: bool,
    #[structopt(long, short)]
    /// Number of parallel jobs, defaults to # of CPUs
    jobs: Option<u16>,
    #[structopt(long, parse(from_os_str))]
    /// Directory to output HTML coverage report (using grcov)
    html_cov_dir: Option<PathBuf>,
    #[structopt(long, parse(from_os_str))]
    /// Directory to output lcov coverage html (using grcov -> lcov.info -> html using genhtml).
    /// Only useful if you want the lcov.info file produced in the path.  Requires that lcov be installed and on PATH.
    html_lcov_dir: Option<PathBuf>,
    #[structopt(name = "TESTNAME", parse(from_os_str))]
    testname: Option<OsString>,
    #[structopt(name = "ARGS", parse(from_os_str), last = true)]
    args: Vec<OsString>,
}

pub fn run(mut args: Args, xctx: XContext) -> Result<()> {
    args.args.extend(args.testname.clone());
    let config = xctx.config();

    let generate_coverage = args.html_cov_dir.is_some() || args.html_lcov_dir.is_some();

    let env_vars: &[(&str, &str)] = if generate_coverage {
        info!("Running \"cargo clean\" before collecting coverage");
        let mut clean_cmd = Command::new("cargo");
        clean_cmd.arg("clean");
        clean_cmd.output()?;
        &[
            // A way to use -Z (unstable) flags with the stable compiler. See below.
            ("RUSTC_BOOTSTRAP", "1"),
            // Recommend setting for grcov, avoids using the cargo cache.
            ("CARGO_INCREMENTAL", "0"),
            // Recommend flags for use with grcov, with these flags removed: -Copt-level=0, -Clink-dead-code.
            // for more info see:  https://github.com/mozilla/grcov#example-how-to-generate-gcda-fiels-for-a-rust-project
            (
                "RUSTFLAGS",
                "-Zprofile -Ccodegen-units=1 -Coverflow-checks=off",
            ),
        ]
    } else {
        &[]
    };

    let mut direct_args = Vec::new();
    if args.no_run {
        direct_args.push(OsString::from("--no-run"));
    };
    if args.no_fail_fast {
        direct_args.push(OsString::from("--no-fail-fast"));
    };
    if args.lib {
        direct_args.push(OsString::from("--lib"));
    };

    if let Some(jobs) = args.jobs {
        direct_args.push(OsString::from("--jobs"));
        direct_args.push(OsString::from(jobs.to_string()));
    };

    let cmd = CargoCommand::Test {
        cargo_config: xctx.config().cargo_config(),
        direct_args: direct_args.as_slice(),
        args: &args.args,
        env: &env_vars,
    };

    let cmd_result = if args.unit {
        cmd.run_with_exclusions(
            config.system_tests().iter().map(|(p, _)| p),
            &CargoArgs::default(),
        )
    } else if !args.package.is_empty() {
        cmd.run_on_packages(args.package.iter(), &CargoArgs::default())
    } else if utils::project_is_root(&xctx)? {
        // TODO Maybe only run a subest of tests if we're not inside
        // a package but not at the project root (e.g. language)
        cmd.run_on_all_packages(&CargoArgs::default())
    } else {
        cmd.run_on_local_package(&CargoArgs::default())
    };

    if !args.no_fail_fast && cmd_result.is_err() {
        return cmd_result;
    }

    if let Some(html_cov_dir) = &args.html_cov_dir {
        create_dir_all(&html_cov_dir)?;
        let html_cov_path = &html_cov_dir.canonicalize()?;
        info!("created {}", &html_cov_path.to_string_lossy());
        exec_grcov(&html_cov_path)?;
    }
    if let Some(html_lcov_dir) = &args.html_lcov_dir {
        create_dir_all(&html_lcov_dir)?;
        let html_lcov_path = &html_lcov_dir.canonicalize()?;
        info!("created {}", &html_lcov_path.to_string_lossy());
        exec_lcov(&html_lcov_path)?;
        exec_lcov_genhtml(&html_lcov_path)?;
    }
    cmd_result
}

fn exec_lcov_genhtml(html_lcov_path: &PathBuf) -> Result<()> {
    let mut genhtml = Command::new("genhtml");
    let mut lcov_file_path = PathBuf::new();
    lcov_file_path.push(html_lcov_path);
    lcov_file_path.push("lcov.info");
    genhtml
        .current_dir(project_root())
        .arg("-o")
        .arg(html_lcov_path)
        .arg("--show-details")
        .arg("--highlight")
        .arg("--ignore-errors")
        .arg("source")
        .arg("--legend")
        //TODO: Paths seem to be a thing
        .arg(lcov_file_path);
    info!("Build grcov lcov.info file");
    info!("{:?}", genhtml);
    genhtml.stdout(Stdio::inherit()).stderr(Stdio::inherit());

    if let Some(err) = genhtml.output().err() {
        Err(Error::new(err).context("Failed to generate html output from lcov.info"))
    } else {
        Ok(())
    }
}

fn exec_lcov(html_lcov_path: &PathBuf) -> Result<()> {
    let debug_dir = project_root().join("target/debug/");
    let mut lcov_file_path = PathBuf::new();
    lcov_file_path.push(html_lcov_path);
    lcov_file_path.push("lcov.info");
    let mut lcov_file = Command::new("grcov");
    lcov_file
        .current_dir(project_root())
        //output file from coverage: gcda files
        .arg(debug_dir.as_os_str())
        //source code location
        .arg("-s")
        .arg(project_root().as_os_str())
        //html output
        .arg("-t")
        .arg("lcov")
        .arg("--llvm")
        .arg("--branch")
        .arg("--ignore")
        .arg("/*")
        .arg("--ignore")
        .arg("x/*")
        .arg("--ignore")
        .arg("testsuite/*")
        .arg("--ignore-not-existing")
        .arg("-o")
        //TODO: Paths seem to be a thing
        .arg(lcov_file_path);
    info!("Converting lcov.info file to html");
    info!("{:?}", lcov_file);
    lcov_file.stdout(Stdio::inherit()).stderr(Stdio::inherit());
    if let Some(err) = lcov_file.output().err() {
        Err(Error::new(err).context("Failed to generate lcov.info with grcov"))
    } else {
        Ok(())
    }
}

fn exec_grcov(html_cov_path: &PathBuf) -> Result<()> {
    let debug_dir = project_root().join("target/debug/");
    let mut grcov_html = Command::new("grcov");
    grcov_html
        .current_dir(project_root())
        //output file from coverage: gcda files
        .arg(debug_dir.as_os_str())
        //source code location
        .arg("-s")
        .arg(project_root().as_os_str())
        //html output
        .arg("-t")
        .arg("html")
        .arg("--llvm")
        .arg("--branch")
        .arg("--ignore")
        .arg("/*")
        .arg("--ignore")
        .arg("x/*")
        .arg("--ignore")
        .arg("testsuite/*")
        .arg("--ignore-not-existing")
        .arg("-o")
        .arg(html_cov_path);
    info!("Build grcov Html Coverage Report");
    info!("{:?}", grcov_html);
    grcov_html.stdout(Stdio::inherit()).stderr(Stdio::inherit());
    if let Some(err) = grcov_html.output().err() {
        Err(Error::new(err).context("Failed to generate html output with grcov"))
    } else {
        Ok(())
    }
}
<commit_msg>[coverage] prevent stack overflow in xtest's run of language/ir-testsuite's tests<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    cargo::{CargoArgs, CargoCommand},
    context::XContext,
    utils,
    utils::project_root,
    Result,
};
use anyhow::Error;
use log::info;
use std::{
    ffi::OsString,
    fs::create_dir_all,
    path::PathBuf,
    process::{Command, Stdio},
};
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
pub struct Args {
    #[structopt(long, short, number_of_values = 1)]
    /// Run test on the provided packages
    package: Vec<String>,
    #[structopt(long, short)]
    /// Skip running expensive libra testsuite integration tests
    unit: bool,
    #[structopt(long)]
    /// Test only this package's library unit tests, skipping doctests
    lib: bool,
    #[structopt(long)]
    /// Do not fast fail the run if tests (or test executables) fail
    no_fail_fast: bool,
    #[structopt(long)]
    /// Do not run tests, only compile the test executables
    no_run: bool,
    #[structopt(long, short)]
    /// Number of parallel jobs, defaults to # of CPUs
    jobs: Option<u16>,
    #[structopt(long, parse(from_os_str))]
    /// Directory to output HTML coverage report (using grcov)
    html_cov_dir: Option<PathBuf>,
    #[structopt(long, parse(from_os_str))]
    /// Directory to output lcov coverage html (using grcov -> lcov.info -> html using genhtml).
    /// Only useful if you want the lcov.info file produced in the path.  Requires that lcov be installed and on PATH.
    html_lcov_dir: Option<PathBuf>,
    #[structopt(name = "TESTNAME", parse(from_os_str))]
    testname: Option<OsString>,
    #[structopt(name = "ARGS", parse(from_os_str), last = true)]
    args: Vec<OsString>,
}

pub fn run(mut args: Args, xctx: XContext) -> Result<()> {
    args.args.extend(args.testname.clone());
    let config = xctx.config();

    let generate_coverage = args.html_cov_dir.is_some() || args.html_lcov_dir.is_some();

    let env_vars: &[(&str, &str)] = if generate_coverage {
        info!("Running \"cargo clean\" before collecting coverage");
        let mut clean_cmd = Command::new("cargo");
        clean_cmd.arg("clean");
        clean_cmd.output()?;
        &[
            // A way to use -Z (unstable) flags with the stable compiler. See below.
            ("RUSTC_BOOTSTRAP", "1"),
            // Recommend setting for grcov, avoids using the cargo cache.
            ("CARGO_INCREMENTAL", "0"),
            // language/ir-testsuite's tests will stack overflow without this setting.
            ("RUST_MIN_STACK", "8388608"),
            // Recommend flags for use with grcov, with these flags removed: -Copt-level=0, -Clink-dead-code.
            // for more info see:  https://github.com/mozilla/grcov#example-how-to-generate-gcda-fiels-for-a-rust-project
            (
                "RUSTFLAGS",
                "-Zprofile -Ccodegen-units=1 -Coverflow-checks=off",
            ),
        ]
    } else {
        &[]
    };

    let mut direct_args = Vec::new();
    if args.no_run {
        direct_args.push(OsString::from("--no-run"));
    };
    if args.no_fail_fast {
        direct_args.push(OsString::from("--no-fail-fast"));
    };
    if args.lib {
        direct_args.push(OsString::from("--lib"));
    };

    if let Some(jobs) = args.jobs {
        direct_args.push(OsString::from("--jobs"));
        direct_args.push(OsString::from(jobs.to_string()));
    };

    let cmd = CargoCommand::Test {
        cargo_config: xctx.config().cargo_config(),
        direct_args: direct_args.as_slice(),
        args: &args.args,
        env: &env_vars,
    };

    let cmd_result = if args.unit {
        cmd.run_with_exclusions(
            config.system_tests().iter().map(|(p, _)| p),
            &CargoArgs::default(),
        )
    } else if !args.package.is_empty() {
        cmd.run_on_packages(args.package.iter(), &CargoArgs::default())
    } else if utils::project_is_root(&xctx)? {
        // TODO Maybe only run a subest of tests if we're not inside
        // a package but not at the project root (e.g. language)
        cmd.run_on_all_packages(&CargoArgs::default())
    } else {
        cmd.run_on_local_package(&CargoArgs::default())
    };

    if !args.no_fail_fast && cmd_result.is_err() {
        return cmd_result;
    }

    if let Some(html_cov_dir) = &args.html_cov_dir {
        create_dir_all(&html_cov_dir)?;
        let html_cov_path = &html_cov_dir.canonicalize()?;
        info!("created {}", &html_cov_path.to_string_lossy());
        exec_grcov(&html_cov_path)?;
    }
    if let Some(html_lcov_dir) = &args.html_lcov_dir {
        create_dir_all(&html_lcov_dir)?;
        let html_lcov_path = &html_lcov_dir.canonicalize()?;
        info!("created {}", &html_lcov_path.to_string_lossy());
        exec_lcov(&html_lcov_path)?;
        exec_lcov_genhtml(&html_lcov_path)?;
    }
    cmd_result
}

fn exec_lcov_genhtml(html_lcov_path: &PathBuf) -> Result<()> {
    let mut genhtml = Command::new("genhtml");
    let mut lcov_file_path = PathBuf::new();
    lcov_file_path.push(html_lcov_path);
    lcov_file_path.push("lcov.info");
    genhtml
        .current_dir(project_root())
        .arg("-o")
        .arg(html_lcov_path)
        .arg("--show-details")
        .arg("--highlight")
        .arg("--ignore-errors")
        .arg("source")
        .arg("--legend")
        //TODO: Paths seem to be a thing
        .arg(lcov_file_path);
    info!("Build grcov lcov.info file");
    info!("{:?}", genhtml);
    genhtml.stdout(Stdio::inherit()).stderr(Stdio::inherit());

    if let Some(err) = genhtml.output().err() {
        Err(Error::new(err).context("Failed to generate html output from lcov.info"))
    } else {
        Ok(())
    }
}

fn exec_lcov(html_lcov_path: &PathBuf) -> Result<()> {
    let debug_dir = project_root().join("target/debug/");
    let mut lcov_file_path = PathBuf::new();
    lcov_file_path.push(html_lcov_path);
    lcov_file_path.push("lcov.info");
    let mut lcov_file = Command::new("grcov");
    lcov_file
        .current_dir(project_root())
        //output file from coverage: gcda files
        .arg(debug_dir.as_os_str())
        //source code location
        .arg("-s")
        .arg(project_root().as_os_str())
        //html output
        .arg("-t")
        .arg("lcov")
        .arg("--llvm")
        .arg("--branch")
        .arg("--ignore")
        .arg("/*")
        .arg("--ignore")
        .arg("x/*")
        .arg("--ignore")
        .arg("testsuite/*")
        .arg("--ignore-not-existing")
        .arg("-o")
        //TODO: Paths seem to be a thing
        .arg(lcov_file_path);
    info!("Converting lcov.info file to html");
    info!("{:?}", lcov_file);
    lcov_file.stdout(Stdio::inherit()).stderr(Stdio::inherit());
    if let Some(err) = lcov_file.output().err() {
        Err(Error::new(err).context("Failed to generate lcov.info with grcov"))
    } else {
        Ok(())
    }
}

fn exec_grcov(html_cov_path: &PathBuf) -> Result<()> {
    let debug_dir = project_root().join("target/debug/");
    let mut grcov_html = Command::new("grcov");
    grcov_html
        .current_dir(project_root())
        //output file from coverage: gcda files
        .arg(debug_dir.as_os_str())
        //source code location
        .arg("-s")
        .arg(project_root().as_os_str())
        //html output
        .arg("-t")
        .arg("html")
        .arg("--llvm")
        .arg("--branch")
        .arg("--ignore")
        .arg("/*")
        .arg("--ignore")
        .arg("x/*")
        .arg("--ignore")
        .arg("testsuite/*")
        .arg("--ignore-not-existing")
        .arg("-o")
        .arg(html_cov_path);
    info!("Build grcov Html Coverage Report");
    info!("{:?}", grcov_html);
    grcov_html.stdout(Stdio::inherit()).stderr(Stdio::inherit());
    if let Some(err) = grcov_html.output().err() {
        Err(Error::new(err).context("Failed to generate html output with grcov"))
    } else {
        Ok(())
    }
}
<|endoftext|>


<commit_before>use diesel::backend::Backend;
use diesel::deserialize::{FromSqlRow, Queryable};
use std::fmt;
use std::str::FromStr;

use super::data_structures::ColumnDefinition;
use super::inference;

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct TableName {
    pub sql_name: String,
    pub schema: Option<String>,
    pub rust_name: Option<String>,
}

impl TableName {
    pub fn from_name<T: Into<String>>(name: T) -> Self {
        let name = name.into();

        TableName {
            rust_name: inference::rust_name_for_sql_name(&name),
            sql_name: name,
            schema: None,
        }
    }

    pub fn new<T, U>(name: T, schema: U) -> Self
    where
        T: Into<String>,
        U: Into<String>,
    {
        let name = name.into();

        TableName {
            rust_name: inference::rust_name_for_sql_name(&name),
            sql_name: name,
            schema: Some(schema.into()),
        }
    }

    #[cfg(feature = "uses_information_schema")]
    pub fn strip_schema_if_matches(&mut self, schema: &str) {
        if self.schema.as_ref().map(|s| &**s) == Some(schema) {
            self.schema = None;
        }
    }

    pub fn full_sql_name(&self) -> String {
        match self.schema {
            Some(ref schema_name) => format!("{}.{}", schema_name, self.sql_name),
            None => format!("{}", self.sql_name),
        }
    }
}

impl<ST, DB> Queryable<ST, DB> for TableName
where
    DB: Backend,
    (String, String): FromSqlRow<ST, DB>,
{
    type Row = (String, String);

    fn build((name, schema): Self::Row) -> Self {
        TableName::new(name, schema)
    }
}

impl fmt::Display for TableName {
    fn fmt(&self, out: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let name = if let Some(ref rust_name) = &self.rust_name {
            rust_name
        } else {
            &self.sql_name
        };

        match self.schema {
            Some(ref schema_name) => write!(out, "{}.{}", schema_name, name),
            None => write!(out, "{}", name),
        }
    }
}

#[derive(Debug)]
#[allow(missing_copy_implementations)]
pub enum Never {}

impl FromStr for TableName {
    type Err = Never;

    fn from_str(table_name: &str) -> Result<Self, Self::Err> {
        let mut parts = table_name.split('.');
        match (parts.next(), parts.next()) {
            (Some(schema), Some(name)) => Ok(TableName::new(name, schema)),
            _ => Ok(TableName::from_name(table_name)),
        }
    }
}

#[derive(Debug)]
pub struct TableData {
    pub name: TableName,
    pub primary_key: Vec<String>,
    pub column_data: Vec<ColumnDefinition>,
    pub docs: String,
}

mod serde_impls {
    extern crate serde;

    use self::serde::de::Visitor;
    use self::serde::{de, Deserialize, Deserializer};
    use super::TableName;
    use std::fmt;

    impl<'de> Deserialize<'de> for TableName {
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where
            D: Deserializer<'de>,
        {
            struct TableNameVisitor;

            impl<'de> Visitor<'de> for TableNameVisitor {
                type Value = TableName;

                fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                    formatter.write_str("A valid table name")
                }

                fn visit_str<E>(self, value: &str) -> Result<TableName, E>
                where
                    E: de::Error,
                {
                    value.parse().map_err(|_| unreachable!())
                }
            }

            deserializer.deserialize_string(TableNameVisitor)
        }
    }
}
<commit_msg>Clippy fix, to_string over format!<commit_after>use diesel::backend::Backend;
use diesel::deserialize::{FromSqlRow, Queryable};
use std::fmt;
use std::str::FromStr;

use super::data_structures::ColumnDefinition;
use super::inference;

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct TableName {
    pub sql_name: String,
    pub schema: Option<String>,
    pub rust_name: Option<String>,
}

impl TableName {
    pub fn from_name<T: Into<String>>(name: T) -> Self {
        let name = name.into();

        TableName {
            rust_name: inference::rust_name_for_sql_name(&name),
            sql_name: name,
            schema: None,
        }
    }

    pub fn new<T, U>(name: T, schema: U) -> Self
    where
        T: Into<String>,
        U: Into<String>,
    {
        let name = name.into();

        TableName {
            rust_name: inference::rust_name_for_sql_name(&name),
            sql_name: name,
            schema: Some(schema.into()),
        }
    }

    #[cfg(feature = "uses_information_schema")]
    pub fn strip_schema_if_matches(&mut self, schema: &str) {
        if self.schema.as_ref().map(|s| &**s) == Some(schema) {
            self.schema = None;
        }
    }

    pub fn full_sql_name(&self) -> String {
        match self.schema {
            Some(ref schema_name) => format!("{}.{}", schema_name, self.sql_name),
            None => self.sql_name.to_string(),
        }
    }
}

impl<ST, DB> Queryable<ST, DB> for TableName
where
    DB: Backend,
    (String, String): FromSqlRow<ST, DB>,
{
    type Row = (String, String);

    fn build((name, schema): Self::Row) -> Self {
        TableName::new(name, schema)
    }
}

impl fmt::Display for TableName {
    fn fmt(&self, out: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let name = if let Some(ref rust_name) = &self.rust_name {
            rust_name
        } else {
            &self.sql_name
        };

        match self.schema {
            Some(ref schema_name) => write!(out, "{}.{}", schema_name, name),
            None => write!(out, "{}", name),
        }
    }
}

#[derive(Debug)]
#[allow(missing_copy_implementations)]
pub enum Never {}

impl FromStr for TableName {
    type Err = Never;

    fn from_str(table_name: &str) -> Result<Self, Self::Err> {
        let mut parts = table_name.split('.');
        match (parts.next(), parts.next()) {
            (Some(schema), Some(name)) => Ok(TableName::new(name, schema)),
            _ => Ok(TableName::from_name(table_name)),
        }
    }
}

#[derive(Debug)]
pub struct TableData {
    pub name: TableName,
    pub primary_key: Vec<String>,
    pub column_data: Vec<ColumnDefinition>,
    pub docs: String,
}

mod serde_impls {
    extern crate serde;

    use self::serde::de::Visitor;
    use self::serde::{de, Deserialize, Deserializer};
    use super::TableName;
    use std::fmt;

    impl<'de> Deserialize<'de> for TableName {
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where
            D: Deserializer<'de>,
        {
            struct TableNameVisitor;

            impl<'de> Visitor<'de> for TableNameVisitor {
                type Value = TableName;

                fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                    formatter.write_str("A valid table name")
                }

                fn visit_str<E>(self, value: &str) -> Result<TableName, E>
                where
                    E: de::Error,
                {
                    value.parse().map_err(|_| unreachable!())
                }
            }

            deserializer.deserialize_string(TableNameVisitor)
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::env;
use std::fmt::{self, Display};
use std::fs;
use std::io::{self, Read, Write};
use std::ops::BitOrAssign;
use std::path::PathBuf;
use std::thread;

use base::{error, Event, PollToken, RawDescriptor, WaitContext};
use vm_memory::GuestMemory;

use super::{
    DescriptorChain, DescriptorError, Interrupt, Queue, Reader, SignalableInterrupt, VirtioDevice,
    Writer, TYPE_TPM,
};

// A single queue of size 2. The guest kernel driver will enqueue a single
// descriptor chain containing one command buffer and one response buffer at a
// time.
const QUEUE_SIZE: u16 = 2;
const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE];

// Maximum command or response message size permitted by this device
// implementation. Named to match the equivalent constant in Linux's tpm.h.
// There is no hard requirement that the value is the same but it makes sense.
const TPM_BUFSIZE: usize = 4096;

struct Worker {
    interrupt: Interrupt,
    queue: Queue,
    mem: GuestMemory,
    queue_evt: Event,
    kill_evt: Event,
    device: Device,
}

struct Device {
    simulator: tpm2::Simulator,
}

impl Device {
    fn perform_work(&mut self, mem: &GuestMemory, desc: DescriptorChain) -> Result<u32> {
        let mut reader = Reader::new(mem.clone(), desc.clone()).map_err(Error::Descriptor)?;
        let mut writer = Writer::new(mem.clone(), desc).map_err(Error::Descriptor)?;

        let available_bytes = reader.available_bytes();
        if available_bytes > TPM_BUFSIZE {
            return Err(Error::CommandTooLong {
                size: available_bytes,
            });
        }

        let mut command = vec![0u8; available_bytes];
        reader.read_exact(&mut command).map_err(Error::Read)?;

        let response = self.simulator.execute_command(&command);

        if response.len() > TPM_BUFSIZE {
            return Err(Error::ResponseTooLong {
                size: response.len(),
            });
        }

        let writer_len = writer.available_bytes();
        if response.len() > writer_len {
            return Err(Error::BufferTooSmall {
                size: writer_len,
                required: response.len(),
            });
        }

        writer.write_all(&response).map_err(Error::Write)?;

        Ok(writer.bytes_written() as u32)
    }
}

impl Worker {
    fn process_queue(&mut self) -> NeedsInterrupt {
        let avail_desc = match self.queue.pop(&self.mem) {
            Some(avail_desc) => avail_desc,
            None => return NeedsInterrupt::No,
        };

        let index = avail_desc.index;

        let len = match self.device.perform_work(&self.mem, avail_desc) {
            Ok(len) => len,
            Err(err) => {
                error!("{}", err);
                0
            }
        };

        self.queue.add_used(&self.mem, index, len);
        NeedsInterrupt::Yes
    }

    fn run(mut self) {
        #[derive(PollToken, Debug)]
        enum Token {
            // A request is ready on the queue.
            QueueAvailable,
            // Check if any interrupts need to be re-asserted.
            InterruptResample,
            // The parent thread requested an exit.
            Kill,
        }

        let wait_ctx = match WaitContext::build_with(&[
            (&self.queue_evt, Token::QueueAvailable),
            (&self.kill_evt, Token::Kill),
        ])
        .and_then(|wc| {
            if let Some(resample_evt) = self.interrupt.get_resample_evt() {
                wc.add(resample_evt, Token::InterruptResample)?;
            }
            Ok(wc)
        }) {
            Ok(pc) => pc,
            Err(e) => {
                error!("vtpm failed creating WaitContext: {}", e);
                return;
            }
        };

        'wait: loop {
            let events = match wait_ctx.wait() {
                Ok(v) => v,
                Err(e) => {
                    error!("vtpm failed polling for events: {}", e);
                    break;
                }
            };

            let mut needs_interrupt = NeedsInterrupt::No;
            for event in events.iter().filter(|e| e.is_readable) {
                match event.token {
                    Token::QueueAvailable => {
                        if let Err(e) = self.queue_evt.read() {
                            error!("vtpm failed reading queue Event: {}", e);
                            break 'wait;
                        }
                        needs_interrupt |= self.process_queue();
                    }
                    Token::InterruptResample => {
                        self.interrupt.interrupt_resample();
                    }
                    Token::Kill => break 'wait,
                }
            }
            if needs_interrupt == NeedsInterrupt::Yes {
                self.queue.trigger_interrupt(&self.mem, &self.interrupt);
            }
        }
    }
}

/// Virtio vTPM device.
pub struct Tpm {
    storage: PathBuf,
    kill_evt: Option<Event>,
    worker_thread: Option<thread::JoinHandle<()>>,
}

impl Tpm {
    pub fn new(storage: PathBuf) -> Tpm {
        Tpm {
            storage,
            kill_evt: None,
            worker_thread: None,
        }
    }
}

impl Drop for Tpm {
    fn drop(&mut self) {
        if let Some(kill_evt) = self.kill_evt.take() {
            let _ = kill_evt.write(1);
        }

        if let Some(worker_thread) = self.worker_thread.take() {
            let _ = worker_thread.join();
        }
    }
}

impl VirtioDevice for Tpm {
    fn keep_rds(&self) -> Vec<RawDescriptor> {
        Vec::new()
    }

    fn device_type(&self) -> u32 {
        TYPE_TPM
    }

    fn queue_max_sizes(&self) -> &[u16] {
        QUEUE_SIZES
    }

    fn activate(
        &mut self,
        mem: GuestMemory,
        interrupt: Interrupt,
        mut queues: Vec<Queue>,
        mut queue_evts: Vec<Event>,
    ) {
        if queues.len() != 1 || queue_evts.len() != 1 {
            return;
        }
        let queue = queues.remove(0);
        let queue_evt = queue_evts.remove(0);

        if let Err(err) = fs::create_dir_all(&self.storage) {
            error!("vtpm failed to create directory for simulator: {}", err);
            return;
        }
        if let Err(err) = env::set_current_dir(&self.storage) {
            error!("vtpm failed to change into simulator directory: {}", err);
            return;
        }
        let simulator = tpm2::Simulator::singleton_in_current_directory();

        let (self_kill_evt, kill_evt) = match Event::new().and_then(|e| Ok((e.try_clone()?, e))) {
            Ok(v) => v,
            Err(err) => {
                error!("vtpm failed to create kill Event pair: {}", err);
                return;
            }
        };
        self.kill_evt = Some(self_kill_evt);

        let worker = Worker {
            interrupt,
            queue,
            mem,
            queue_evt,
            kill_evt,
            device: Device { simulator },
        };

        let worker_result = thread::Builder::new()
            .name("virtio_tpm".to_string())
            .spawn(|| worker.run());

        match worker_result {
            Err(e) => {
                error!("vtpm failed to spawn virtio_tpm worker: {}", e);
            }
            Ok(join_handle) => {
                self.worker_thread = Some(join_handle);
            }
        }
    }
}

#[derive(PartialEq)]
enum NeedsInterrupt {
    Yes,
    No,
}

impl BitOrAssign for NeedsInterrupt {
    fn bitor_assign(&mut self, rhs: NeedsInterrupt) {
        if rhs == NeedsInterrupt::Yes {
            *self = NeedsInterrupt::Yes;
        }
    }
}

type Result<T> = std::result::Result<T, Error>;

enum Error {
    CommandTooLong { size: usize },
    Descriptor(DescriptorError),
    Read(io::Error),
    ResponseTooLong { size: usize },
    BufferTooSmall { size: usize, required: usize },
    Write(io::Error),
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match self {
            CommandTooLong { size } => write!(
                f,
                "vtpm command is too long: {} > {} bytes",
                size, TPM_BUFSIZE
            ),
            Descriptor(e) => write!(f, "virtio descriptor error: {}", e),
            Read(e) => write!(f, "vtpm failed to read from guest memory: {}", e),
            ResponseTooLong { size } => write!(
                f,
                "vtpm simulator generated a response that is unexpectedly long: {} > {} bytes",
                size, TPM_BUFSIZE
            ),
            BufferTooSmall { size, required } => write!(
                f,
                "vtpm response buffer is too small: {} < {} bytes",
                size, required
            ),
            Write(e) => write!(f, "vtpm failed to write to guest memory: {}", e),
        }
    }
}
<commit_msg>tpm: Process all descriptors when notified<commit_after>// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::env;
use std::fmt::{self, Display};
use std::fs;
use std::io::{self, Read, Write};
use std::ops::BitOrAssign;
use std::path::PathBuf;
use std::thread;

use base::{error, Event, PollToken, RawDescriptor, WaitContext};
use vm_memory::GuestMemory;

use super::{
    DescriptorChain, DescriptorError, Interrupt, Queue, Reader, SignalableInterrupt, VirtioDevice,
    Writer, TYPE_TPM,
};

// A single queue of size 2. The guest kernel driver will enqueue a single
// descriptor chain containing one command buffer and one response buffer at a
// time.
const QUEUE_SIZE: u16 = 2;
const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE];

// Maximum command or response message size permitted by this device
// implementation. Named to match the equivalent constant in Linux's tpm.h.
// There is no hard requirement that the value is the same but it makes sense.
const TPM_BUFSIZE: usize = 4096;

struct Worker {
    interrupt: Interrupt,
    queue: Queue,
    mem: GuestMemory,
    queue_evt: Event,
    kill_evt: Event,
    device: Device,
}

struct Device {
    simulator: tpm2::Simulator,
}

impl Device {
    fn perform_work(&mut self, mem: &GuestMemory, desc: DescriptorChain) -> Result<u32> {
        let mut reader = Reader::new(mem.clone(), desc.clone()).map_err(Error::Descriptor)?;
        let mut writer = Writer::new(mem.clone(), desc).map_err(Error::Descriptor)?;

        let available_bytes = reader.available_bytes();
        if available_bytes > TPM_BUFSIZE {
            return Err(Error::CommandTooLong {
                size: available_bytes,
            });
        }

        let mut command = vec![0u8; available_bytes];
        reader.read_exact(&mut command).map_err(Error::Read)?;

        let response = self.simulator.execute_command(&command);

        if response.len() > TPM_BUFSIZE {
            return Err(Error::ResponseTooLong {
                size: response.len(),
            });
        }

        let writer_len = writer.available_bytes();
        if response.len() > writer_len {
            return Err(Error::BufferTooSmall {
                size: writer_len,
                required: response.len(),
            });
        }

        writer.write_all(&response).map_err(Error::Write)?;

        Ok(writer.bytes_written() as u32)
    }
}

impl Worker {
    fn process_queue(&mut self) -> NeedsInterrupt {
        let mut needs_interrupt = NeedsInterrupt::No;
        while let Some(avail_desc) = self.queue.pop(&self.mem) {
            let index = avail_desc.index;

            let len = match self.device.perform_work(&self.mem, avail_desc) {
                Ok(len) => len,
                Err(err) => {
                    error!("{}", err);
                    0
                }
            };

            self.queue.add_used(&self.mem, index, len);
            needs_interrupt = NeedsInterrupt::Yes;
        }

        needs_interrupt
    }

    fn run(mut self) {
        #[derive(PollToken, Debug)]
        enum Token {
            // A request is ready on the queue.
            QueueAvailable,
            // Check if any interrupts need to be re-asserted.
            InterruptResample,
            // The parent thread requested an exit.
            Kill,
        }

        let wait_ctx = match WaitContext::build_with(&[
            (&self.queue_evt, Token::QueueAvailable),
            (&self.kill_evt, Token::Kill),
        ])
        .and_then(|wc| {
            if let Some(resample_evt) = self.interrupt.get_resample_evt() {
                wc.add(resample_evt, Token::InterruptResample)?;
            }
            Ok(wc)
        }) {
            Ok(pc) => pc,
            Err(e) => {
                error!("vtpm failed creating WaitContext: {}", e);
                return;
            }
        };

        'wait: loop {
            let events = match wait_ctx.wait() {
                Ok(v) => v,
                Err(e) => {
                    error!("vtpm failed polling for events: {}", e);
                    break;
                }
            };

            let mut needs_interrupt = NeedsInterrupt::No;
            for event in events.iter().filter(|e| e.is_readable) {
                match event.token {
                    Token::QueueAvailable => {
                        if let Err(e) = self.queue_evt.read() {
                            error!("vtpm failed reading queue Event: {}", e);
                            break 'wait;
                        }
                        needs_interrupt |= self.process_queue();
                    }
                    Token::InterruptResample => {
                        self.interrupt.interrupt_resample();
                    }
                    Token::Kill => break 'wait,
                }
            }
            if needs_interrupt == NeedsInterrupt::Yes {
                self.queue.trigger_interrupt(&self.mem, &self.interrupt);
            }
        }
    }
}

/// Virtio vTPM device.
pub struct Tpm {
    storage: PathBuf,
    kill_evt: Option<Event>,
    worker_thread: Option<thread::JoinHandle<()>>,
}

impl Tpm {
    pub fn new(storage: PathBuf) -> Tpm {
        Tpm {
            storage,
            kill_evt: None,
            worker_thread: None,
        }
    }
}

impl Drop for Tpm {
    fn drop(&mut self) {
        if let Some(kill_evt) = self.kill_evt.take() {
            let _ = kill_evt.write(1);
        }

        if let Some(worker_thread) = self.worker_thread.take() {
            let _ = worker_thread.join();
        }
    }
}

impl VirtioDevice for Tpm {
    fn keep_rds(&self) -> Vec<RawDescriptor> {
        Vec::new()
    }

    fn device_type(&self) -> u32 {
        TYPE_TPM
    }

    fn queue_max_sizes(&self) -> &[u16] {
        QUEUE_SIZES
    }

    fn activate(
        &mut self,
        mem: GuestMemory,
        interrupt: Interrupt,
        mut queues: Vec<Queue>,
        mut queue_evts: Vec<Event>,
    ) {
        if queues.len() != 1 || queue_evts.len() != 1 {
            return;
        }
        let queue = queues.remove(0);
        let queue_evt = queue_evts.remove(0);

        if let Err(err) = fs::create_dir_all(&self.storage) {
            error!("vtpm failed to create directory for simulator: {}", err);
            return;
        }
        if let Err(err) = env::set_current_dir(&self.storage) {
            error!("vtpm failed to change into simulator directory: {}", err);
            return;
        }
        let simulator = tpm2::Simulator::singleton_in_current_directory();

        let (self_kill_evt, kill_evt) = match Event::new().and_then(|e| Ok((e.try_clone()?, e))) {
            Ok(v) => v,
            Err(err) => {
                error!("vtpm failed to create kill Event pair: {}", err);
                return;
            }
        };
        self.kill_evt = Some(self_kill_evt);

        let worker = Worker {
            interrupt,
            queue,
            mem,
            queue_evt,
            kill_evt,
            device: Device { simulator },
        };

        let worker_result = thread::Builder::new()
            .name("virtio_tpm".to_string())
            .spawn(|| worker.run());

        match worker_result {
            Err(e) => {
                error!("vtpm failed to spawn virtio_tpm worker: {}", e);
            }
            Ok(join_handle) => {
                self.worker_thread = Some(join_handle);
            }
        }
    }
}

#[derive(PartialEq)]
enum NeedsInterrupt {
    Yes,
    No,
}

impl BitOrAssign for NeedsInterrupt {
    fn bitor_assign(&mut self, rhs: NeedsInterrupt) {
        if rhs == NeedsInterrupt::Yes {
            *self = NeedsInterrupt::Yes;
        }
    }
}

type Result<T> = std::result::Result<T, Error>;

enum Error {
    CommandTooLong { size: usize },
    Descriptor(DescriptorError),
    Read(io::Error),
    ResponseTooLong { size: usize },
    BufferTooSmall { size: usize, required: usize },
    Write(io::Error),
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match self {
            CommandTooLong { size } => write!(
                f,
                "vtpm command is too long: {} > {} bytes",
                size, TPM_BUFSIZE
            ),
            Descriptor(e) => write!(f, "virtio descriptor error: {}", e),
            Read(e) => write!(f, "vtpm failed to read from guest memory: {}", e),
            ResponseTooLong { size } => write!(
                f,
                "vtpm simulator generated a response that is unexpectedly long: {} > {} bytes",
                size, TPM_BUFSIZE
            ),
            BufferTooSmall { size, required } => write!(
                f,
                "vtpm response buffer is too small: {} < {} bytes",
                size, required
            ),
            Write(e) => write!(f, "vtpm failed to write to guest memory: {}", e),
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Clear the whole target window on screen refresh<commit_after><|endoftext|>


<commit_before>extern crate quickcheck;
#[macro_use] extern crate assert_matches;
#[macro_use] extern crate diesel;
#[macro_use] extern crate diesel_codegen;
extern crate dotenv;

#[cfg(not(feature = "sqlite"))]
mod annotations;
mod associations;
mod boxed_queries;
mod connection;
#[cfg(feature = "postgres")]
mod custom_schemas;
#[cfg(feature = "postgres")]
mod custom_types;
mod debug;
mod delete;
mod deserialization;
mod errors;
mod expressions;
mod filter;
mod filter_operators;
mod find;
mod group_by;
mod insert;
mod internal_details;
mod joins;
mod macros;
mod order;
mod perf_details;
#[cfg(feature = "postgres")]
mod postgres_types;
mod schema;
mod schema_dsl;
mod schema_inference;
mod select;
#[cfg(not(feature="mysql"))] // FIXME: Figure out how to handle tests that modify schema
mod transactions;
mod types;
mod types_roundtrip;
mod update;
<commit_msg>Bump recursion limit in diesel_tests<commit_after>#![recursion_limit="1024"]

extern crate quickcheck;
#[macro_use] extern crate assert_matches;
#[macro_use] extern crate diesel;
#[macro_use] extern crate diesel_codegen;
extern crate dotenv;

#[cfg(not(feature = "sqlite"))]
mod annotations;
mod associations;
mod boxed_queries;
mod connection;
#[cfg(feature = "postgres")]
mod custom_schemas;
#[cfg(feature = "postgres")]
mod custom_types;
mod debug;
mod delete;
mod deserialization;
mod errors;
mod expressions;
mod filter;
mod filter_operators;
mod find;
mod group_by;
mod insert;
mod internal_details;
mod joins;
mod macros;
mod order;
mod perf_details;
#[cfg(feature = "postgres")]
mod postgres_types;
mod schema;
mod schema_dsl;
mod schema_inference;
mod select;
#[cfg(not(feature="mysql"))] // FIXME: Figure out how to handle tests that modify schema
mod transactions;
mod types;
mod types_roundtrip;
mod update;
<|endoftext|>


<commit_before>// The Computer Language Benchmarks Game
// http://benchmarksgame.alioth.debian.org/
//
// contributed by the Rust Project Developers

// Copyright (c) 2013-2014 The Rust Project Developers
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// - Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
//
// - Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in
//   the documentation and/or other materials provided with the
//   distribution.
//
// - Neither the name of "The Computer Language Benchmarks Game" nor
//   the name of "The Computer Language Shootout Benchmarks" nor the
//   names of its contributors may be used to endorse or promote
//   products derived from this software without specific prior
//   written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.

// ignore-android doesn't terminate?

#![feature(slicing_syntax, asm, if_let, tuple_indexing)]

extern crate libc;

use std::io::stdio::{stdin_raw, stdout_raw};
use std::sync::{Future};
use std::num::{div_rem};
use std::ptr::{copy_memory};
use std::io::{IoResult, EndOfFile};
use std::slice::raw::{mut_buf_as_slice};

use shared_memory::{SharedMemory};

mod tables {
    use std::sync::{Once, ONCE_INIT};

    /// Lookup tables.
    static mut CPL16: [u16, ..1 << 16] = [0, ..1 << 16];
    static mut CPL8:  [u8,  ..1 << 8]  = [0, ..1 << 8];

    /// Generates the tables.
    pub fn get() -> Tables {
        /// To make sure we initialize the tables only once.
        static INIT: Once = ONCE_INIT;
        INIT.doit(|| {
            unsafe {
                for i in range(0, 1 << 8) {
                    CPL8[i] = match i as u8 {
                        b'A' | b'a' => b'T',
                        b'C' | b'c' => b'G',
                        b'G' | b'g' => b'C',
                        b'T' | b't' => b'A',
                        b'U' | b'u' => b'A',
                        b'M' | b'm' => b'K',
                        b'R' | b'r' => b'Y',
                        b'W' | b'w' => b'W',
                        b'S' | b's' => b'S',
                        b'Y' | b'y' => b'R',
                        b'K' | b'k' => b'M',
                        b'V' | b'v' => b'B',
                        b'H' | b'h' => b'D',
                        b'D' | b'd' => b'H',
                        b'B' | b'b' => b'V',
                        b'N' | b'n' => b'N',
                        i => i,
                    };
                }

                for (i, v) in CPL16.iter_mut().enumerate() {
                    *v = *CPL8.unsafe_get(i & 255) as u16 << 8 |
                         *CPL8.unsafe_get(i >> 8)  as u16;
                }
            }
        });
        Tables { _dummy: () }
    }

    /// Accessor for the static arrays.
    ///
    /// To make sure that the tables can't be accessed without having been initialized.
    pub struct Tables {
        _dummy: ()
    }

    impl Tables {
        /// Retreives the complement for `i`.
        pub fn cpl8(self, i: u8) -> u8 {
            // Not really unsafe.
            unsafe { CPL8[i as uint] }
        }

        /// Retreives the complement for `i`.
        pub fn cpl16(self, i: u16) -> u16 {
            unsafe { CPL16[i as uint] }
        }
    }
}

mod shared_memory {
    use std::sync::{Arc};
    use std::mem::{transmute};
    use std::raw::{Slice};

    /// Structure for sharing disjoint parts of a vector mutably across tasks.
    pub struct SharedMemory {
        ptr: Arc<Vec<u8>>,
        start: uint,
        len: uint,
    }

    impl SharedMemory {
        pub fn new(ptr: Vec<u8>) -> SharedMemory {
            let len = ptr.len();
            SharedMemory {
                ptr: Arc::new(ptr),
                start: 0,
                len: len,
            }
        }

        pub fn as_mut_slice(&mut self) -> &mut [u8] {
            unsafe {
                transmute(Slice {
                    data: self.ptr.as_ptr().offset(self.start as int) as *const u8,
                    len: self.len,
                })
            }
        }

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

        pub fn split_at(self, mid: uint) -> (SharedMemory, SharedMemory) {
            assert!(mid <= self.len);
            let left = SharedMemory {
                ptr: self.ptr.clone(),
                start: self.start,
                len: mid,
            };
            let right = SharedMemory {
                ptr: self.ptr,
                start: self.start + mid,
                len: self.len - mid,
            };
            (left, right)
        }

        /// Resets the object so that it covers the whole range of the contained vector.
        ///
        /// You must not call this method if `self` is not the only reference to the
        /// shared memory.
        ///
        /// FIXME: If `Arc` had a method to check if the reference is unique, then we
        /// wouldn't need the `unsafe` here.
        ///
        /// FIXME: If `Arc` had a method to unwrap the contained value, then we could
        /// simply unwrap here.
        pub unsafe fn reset(self) -> SharedMemory {
            let len = self.ptr.len();
            SharedMemory {
                ptr: self.ptr,
                start: 0,
                len: len,
            }
        }
    }
}

/// Reads all remaining bytes from the stream.
fn read_to_end<R: Reader>(r: &mut R) -> IoResult<Vec<u8>> {
    const CHUNK: uint = 64 * 1024;

    let mut vec = Vec::with_capacity(1024 * 1024);
    loop {
        if vec.capacity() - vec.len() < CHUNK {
            let cap = vec.capacity();
            let mult = if cap < 256 * 1024 * 1024 {
                // FIXME (mahkoh): Temporary workaround for jemalloc on linux. Replace
                // this by 2x once the jemalloc preformance issue has been fixed.
                16
            } else {
                2
            };
            vec.reserve_exact(mult * cap);
        }
        unsafe {
            let ptr = vec.as_mut_ptr().offset(vec.len() as int);
            match mut_buf_as_slice(ptr, CHUNK, |s| r.read(s)) {
                Ok(n) => {
                    let len = vec.len();
                    vec.set_len(len + n);
                },
                Err(ref e) if e.kind == EndOfFile => break,
                Err(e) => return Err(e),
            }
        }
    }
    Ok(vec)
}

/// Finds the first position at which `b` occurs in `s`.
fn memchr(h: &[u8], n: u8) -> Option<uint> {
    use libc::{c_void, c_int, size_t};
    extern {
        fn memchr(h: *const c_void, n: c_int, s: size_t) -> *mut c_void;
    }
    let res = unsafe {
        memchr(h.as_ptr() as *const c_void, n as c_int, h.len() as size_t)
    };
    if res.is_null() {
        None
    } else {
        Some(res as uint - h.as_ptr() as uint)
    }
}

/// Length of a normal line without the terminating \n.
const LINE_LEN: uint = 60;

/// Compute the reverse complement.
fn reverse_complement(mut view: SharedMemory, tables: tables::Tables) {
    // Drop the last newline
    let seq = view.as_mut_slice().init_mut();
    let len = seq.len();
    let off = LINE_LEN - len % (LINE_LEN + 1);
    let mut i = LINE_LEN;
    while i < len {
        unsafe {
            copy_memory(seq.as_mut_ptr().offset((i - off + 1) as int),
                        seq.as_ptr().offset((i - off) as int), off);
            *seq.unsafe_mut(i - off) = b'\n';
        }
        i += LINE_LEN + 1;
    }

    let (div, rem) = div_rem(len, 4);
    unsafe {
        let mut left = seq.as_mut_ptr() as *mut u16;
        // This is slow if len % 2 != 0 but still faster than bytewise operations.
        let mut right = seq.as_mut_ptr().offset(len as int - 2) as *mut u16;
        let end = left.offset(div as int);
        while left != end {
            let tmp = tables.cpl16(*left);
            *left = tables.cpl16(*right);
            *right = tmp;
            left = left.offset(1);
            right = right.offset(-1);
        }

        let end = end as *mut u8;
        match rem {
            1 => *end = tables.cpl8(*end),
            2 => {
                let tmp = tables.cpl8(*end);
                *end = tables.cpl8(*end.offset(1));
                *end.offset(1) = tmp;
            },
            3 => {
                *end.offset(1) = tables.cpl8(*end.offset(1));
                let tmp = tables.cpl8(*end);
                *end = tables.cpl8(*end.offset(2));
                *end.offset(2) = tmp;
            },
            _ => { },
        }
    }
}

fn main() {
    let mut data = SharedMemory::new(read_to_end(&mut stdin_raw()).unwrap());
    let tables = tables::get();

    let mut futures = vec!();
    loop {
        let (_, mut tmp_data) = match memchr(data.as_mut_slice(), b'\n') {
            Some(i) => data.split_at(i + 1),
            _ => break,
        };
        let (view, tmp_data) = match memchr(tmp_data.as_mut_slice(), b'>') {
            Some(i) => tmp_data.split_at(i),
            None => {
                let len = tmp_data.len();
                tmp_data.split_at(len)
            },
        };
        futures.push(Future::spawn(proc() reverse_complement(view, tables)));
        data = tmp_data;
    }

    for f in futures.iter_mut() {
        f.get();
    }

    // Not actually unsafe. If Arc had a way to check uniqueness then we could do that in
    // `reset` and it would tell us that, yes, it is unique at this point.
    data = unsafe { data.reset() };

    stdout_raw().write(data.as_mut_slice()).unwrap();
}
<commit_msg>auto merge of #18357 : TeXitoi/rust/simplify-reverse-complement, r=alexcrichton<commit_after>// The Computer Language Benchmarks Game
// http://benchmarksgame.alioth.debian.org/
//
// contributed by the Rust Project Developers

// Copyright (c) 2013-2014 The Rust Project Developers
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// - Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
//
// - Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in
//   the documentation and/or other materials provided with the
//   distribution.
//
// - Neither the name of "The Computer Language Benchmarks Game" nor
//   the name of "The Computer Language Shootout Benchmarks" nor the
//   names of its contributors may be used to endorse or promote
//   products derived from this software without specific prior
//   written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.

// ignore-android see #10393 #13206

#![feature(slicing_syntax, unboxed_closures, overloaded_calls)]

extern crate libc;

use std::io::stdio::{stdin_raw, stdout_raw};
use std::num::{div_rem};
use std::ptr::{copy_memory};
use std::io::{IoResult, EndOfFile};

struct Tables {
    table8: [u8, ..1 << 8],
    table16: [u16, ..1 << 16]
}

impl Tables {
    fn new() -> Tables {
        let mut table8 = [0, ..1 << 8];
        for (i, v) in table8.iter_mut().enumerate() {
            *v = Tables::computed_cpl8(i as u8);
        }
        let mut table16 = [0, ..1 << 16];
        for (i, v) in table16.iter_mut().enumerate() {
            *v = table8[i & 255] as u16 << 8 |
                 table8[i >> 8]  as u16;
        }
        Tables { table8: table8, table16: table16 }
    }

    fn computed_cpl8(c: u8) -> u8 {
        match c {
            b'A' | b'a' => b'T',
            b'C' | b'c' => b'G',
            b'G' | b'g' => b'C',
            b'T' | b't' => b'A',
            b'U' | b'u' => b'A',
            b'M' | b'm' => b'K',
            b'R' | b'r' => b'Y',
            b'W' | b'w' => b'W',
            b'S' | b's' => b'S',
            b'Y' | b'y' => b'R',
            b'K' | b'k' => b'M',
            b'V' | b'v' => b'B',
            b'H' | b'h' => b'D',
            b'D' | b'd' => b'H',
            b'B' | b'b' => b'V',
            b'N' | b'n' => b'N',
            i => i,
        }
    }

    /// Retreives the complement for `i`.
    fn cpl8(&self, i: u8) -> u8 {
        self.table8[i as uint]
    }

    /// Retreives the complement for `i`.
    fn cpl16(&self, i: u16) -> u16 {
        self.table16[i as uint]
    }
}

/// Reads all remaining bytes from the stream.
fn read_to_end<R: Reader>(r: &mut R) -> IoResult<Vec<u8>> {
    // As reading the input stream in memory is a bottleneck, we tune
    // Reader::read_to_end() with a fast growing policy to limit
    // recopies.  If MREMAP_RETAIN is implemented in the linux kernel
    // and jemalloc use it, this trick will become useless.
    const CHUNK: uint = 64 * 1024;

    let mut vec = Vec::with_capacity(CHUNK);
    loop {
        // workaround: very fast growing
        if vec.capacity() - vec.len() < CHUNK {
            let cap = vec.capacity();
            let mult = if cap < 256 * 1024 * 1024 {
                16
            } else {
                2
            };
            vec.reserve_exact(mult * cap);
        }
        match r.push_at_least(1, CHUNK, &mut vec) {
            Ok(_) => {}
            Err(ref e) if e.kind == EndOfFile => break,
            Err(e) => return Err(e)
        }
    }
    Ok(vec)
}

/// Finds the first position at which `b` occurs in `s`.
fn memchr(h: &[u8], n: u8) -> Option<uint> {
    use libc::{c_void, c_int, size_t};
    let res = unsafe {
        libc::memchr(h.as_ptr() as *const c_void, n as c_int, h.len() as size_t)
    };
    if res.is_null() {
        None
    } else {
        Some(res as uint - h.as_ptr() as uint)
    }
}

/// A mutable iterator over DNA sequences
struct MutDnaSeqs<'a> { s: &'a mut [u8] }
fn mut_dna_seqs<'a>(s: &'a mut [u8]) -> MutDnaSeqs<'a> {
    MutDnaSeqs { s: s }
}
impl<'a> Iterator<&'a mut [u8]> for MutDnaSeqs<'a> {
    fn next(&mut self) -> Option<&'a mut [u8]> {
        let tmp = std::mem::replace(&mut self.s, &mut []);
        let tmp = match memchr(tmp, b'\n') {
            Some(i) => tmp.slice_from_mut(i + 1),
            None => return None,
        };
        let (seq, tmp) = match memchr(tmp, b'>') {
            Some(i) => tmp.split_at_mut(i),
            None => {
                let len = tmp.len();
                tmp.split_at_mut(len)
            }
        };
        self.s = tmp;
        Some(seq)
    }
}

/// Length of a normal line without the terminating \n.
const LINE_LEN: uint = 60;

/// Compute the reverse complement.
fn reverse_complement(seq: &mut [u8], tables: &Tables) {
    let seq = seq.init_mut();// Drop the last newline
    let len = seq.len();
    let off = LINE_LEN - len % (LINE_LEN + 1);
    let mut i = LINE_LEN;
    while i < len {
        unsafe {
            copy_memory(seq.as_mut_ptr().offset((i - off + 1) as int),
                        seq.as_ptr().offset((i - off) as int), off);
            *seq.unsafe_mut(i - off) = b'\n';
        }
        i += LINE_LEN + 1;
    }

    let (div, rem) = div_rem(len, 4);
    unsafe {
        let mut left = seq.as_mut_ptr() as *mut u16;
        // This is slow if len % 2 != 0 but still faster than bytewise operations.
        let mut right = seq.as_mut_ptr().offset(len as int - 2) as *mut u16;
        let end = left.offset(div as int);
        while left != end {
            let tmp = tables.cpl16(*left);
            *left = tables.cpl16(*right);
            *right = tmp;
            left = left.offset(1);
            right = right.offset(-1);
        }

        let end = end as *mut u8;
        match rem {
            1 => *end = tables.cpl8(*end),
            2 => {
                let tmp = tables.cpl8(*end);
                *end = tables.cpl8(*end.offset(1));
                *end.offset(1) = tmp;
            },
            3 => {
                *end.offset(1) = tables.cpl8(*end.offset(1));
                let tmp = tables.cpl8(*end);
                *end = tables.cpl8(*end.offset(2));
                *end.offset(2) = tmp;
            },
            _ => { },
        }
    }
}

/// Executes a closure in parallel over the given iterator over mutable slice.
/// The closure `f` is run in parallel with an element of `iter`.
fn parallel<'a, I, T, F>(mut iter: I, f: F)
        where T: Send + Sync,
              I: Iterator<&'a mut [T]>,
              F: Fn(&'a mut [T]) + Sync {
    use std::mem;
    use std::raw::Repr;

    let (tx, rx) = channel();
    for chunk in iter {
        let tx = tx.clone();

        // Need to convert `f` and `chunk` to something that can cross the task
        // boundary.
        let f = &f as *const F as *const uint;
        let raw = chunk.repr();
        spawn(proc() {
            let f = f as *const F;
            unsafe { (*f)(mem::transmute(raw)) }
            drop(tx)
        });
    }
    drop(tx);
    for () in rx.iter() {}
}

fn main() {
    let mut data = read_to_end(&mut stdin_raw()).unwrap();
    let tables = &Tables::new();
    parallel(mut_dna_seqs(data[mut]), |&: seq| reverse_complement(seq, tables));
    stdout_raw().write(data.as_mut_slice()).unwrap();
}
<|endoftext|>


<commit_before>//! Thread safe communication channel implementing `Evented`

extern crate mio;
extern crate lazycell;

use mio::{Evented, Ready, Poll, PollOpt, Registration, SetReadiness, Token};
use lazycell::{LazyCell, AtomicLazyCell};
use std::any::Any;
use std::fmt;
use std::error;
use std::io;
use std::sync::{mpsc, Arc};
use std::sync::atomic::{AtomicUsize, Ordering};

/// Creates a new asynchronous channel, where the `Receiver` can be registered
/// with `Poll`.
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
    let (tx_ctl, rx_ctl) = ctl_pair();
    let (tx, rx) = mpsc::channel();

    let tx = Sender {
        tx: tx,
        ctl: tx_ctl,
    };

    let rx = Receiver {
        rx: rx,
        ctl: rx_ctl,
    };

    (tx, rx)
}

/// Creates a new synchronous, bounded channel where the `Receiver` can be
/// registered with `Poll`.
pub fn sync_channel<T>(bound: usize) -> (SyncSender<T>, Receiver<T>) {
    let (tx_ctl, rx_ctl) = ctl_pair();
    let (tx, rx) = mpsc::sync_channel(bound);

    let tx = SyncSender {
        tx: tx,
        ctl: tx_ctl,
    };

    let rx = Receiver {
        rx: rx,
        ctl: rx_ctl,
    };

    (tx, rx)
}

pub fn ctl_pair() -> (SenderCtl, ReceiverCtl) {
    let inner = Arc::new(Inner {
        pending: AtomicUsize::new(0),
        senders: AtomicUsize::new(1),
        set_readiness: AtomicLazyCell::new(),
    });

    let tx = SenderCtl {
        inner: inner.clone(),
    };

    let rx = ReceiverCtl {
        registration: LazyCell::new(),
        inner: inner,
    };

    (tx, rx)
}

/// Tracks messages sent on a channel in order to update readiness.
pub struct SenderCtl {
    inner: Arc<Inner>,
}

/// Tracks messages received on a channel in order to track readiness.
pub struct ReceiverCtl {
    registration: LazyCell<Registration>,
    inner: Arc<Inner>,
}

pub struct Sender<T> {
    tx: mpsc::Sender<T>,
    ctl: SenderCtl,
}

pub struct SyncSender<T> {
    tx: mpsc::SyncSender<T>,
    ctl: SenderCtl,
}

pub struct Receiver<T> {
    rx: mpsc::Receiver<T>,
    ctl: ReceiverCtl,
}

pub enum SendError<T> {
    Io(io::Error),
    Disconnected(T),
}

pub enum TrySendError<T> {
    Io(io::Error),
    Full(T),
    Disconnected(T),
}

struct Inner {
    // The number of outstanding messages for the receiver to read
    pending: AtomicUsize,
    // The number of sender handles
    senders: AtomicUsize,
    // The set readiness handle
    set_readiness: AtomicLazyCell<SetReadiness>,
}

impl<T> Sender<T> {
    pub fn send(&self, t: T) -> Result<(), SendError<T>> {
        self.tx.send(t)
            .map_err(SendError::from)
            .and_then(|_| {
                try!(self.ctl.inc());
                Ok(())
            })
    }
}

impl<T> Clone for Sender<T> {
    fn clone(&self) -> Sender<T> {
        Sender {
            tx: self.tx.clone(),
            ctl: self.ctl.clone(),
        }
    }
}

impl<T> SyncSender<T> {
    pub fn send(&self, t: T) -> Result<(), SendError<T>> {
        self.tx.send(t)
            .map_err(From::from)
            .and_then(|_| {
                try!(self.ctl.inc());
                Ok(())
            })
    }

    pub fn try_send(&self, t: T) -> Result<(), TrySendError<T>> {
        self.tx.try_send(t)
            .map_err(From::from)
            .and_then(|_| {
                try!(self.ctl.inc());
                Ok(())
            })
    }
}

impl<T> Clone for SyncSender<T> {
    fn clone(&self) -> SyncSender<T> {
        SyncSender {
            tx: self.tx.clone(),
            ctl: self.ctl.clone(),
        }
    }
}

impl<T> Receiver<T> {
    pub fn try_recv(&self) -> Result<T, mpsc::TryRecvError> {
        self.rx.try_recv().and_then(|res| {
            let _ = self.ctl.dec();
            Ok(res)
        })
    }
}

impl<T> Evented for Receiver<T> {
    fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
        self.ctl.register(poll, token, interest, opts)
    }

    fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
        self.ctl.reregister(poll, token, interest, opts)
    }

    fn deregister(&self, poll: &Poll) -> io::Result<()> {
        self.ctl.deregister(poll)
    }
}

/*
 *
 * ===== SenderCtl / ReceiverCtl =====
 *
 */

impl SenderCtl {
    /// Call to track that a message has been sent
    pub fn inc(&self) -> io::Result<()> {
        let cnt = self.inner.pending.fetch_add(1, Ordering::Acquire);

        if 0 == cnt {
            // Toggle readiness to readable
            if let Some(set_readiness) = self.inner.set_readiness.borrow() {
                try!(set_readiness.set_readiness(Ready::readable()));
            }
        }

        Ok(())
    }
}

impl Clone for SenderCtl {
    fn clone(&self) -> SenderCtl {
        self.inner.senders.fetch_add(1, Ordering::Relaxed);
        SenderCtl { inner: self.inner.clone() }
    }
}

impl Drop for SenderCtl {
    fn drop(&mut self) {
        if self.inner.senders.fetch_sub(1, Ordering::Release) == 1 {
            let _ = self.inc();
        }
    }
}

impl ReceiverCtl {
    pub fn dec(&self) -> io::Result<()> {
        let first = self.inner.pending.load(Ordering::Acquire);

        if first == 1 {
            // Unset readiness
            if let Some(set_readiness) = self.inner.set_readiness.borrow() {
                try!(set_readiness.set_readiness(Ready::empty()));
            }
        }

        // Decrement
        let second = self.inner.pending.fetch_sub(1, Ordering::AcqRel);

        if first == 1 && second > 1 {
            // There are still pending messages. Since readiness was
            // previously unset, it must be reset here
            if let Some(set_readiness) = self.inner.set_readiness.borrow() {
                try!(set_readiness.set_readiness(Ready::readable()));
            }
        }

        Ok(())
    }
}

impl Evented for ReceiverCtl {
    fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
        if self.registration.borrow().is_some() {
            return Err(io::Error::new(io::ErrorKind::Other, "receiver already registered"));
        }

        let (registration, set_readiness) = Registration::new2();
        poll.register(&registration, token, interest, opts)?;

        if self.inner.pending.load(Ordering::Relaxed) > 0 {
            // TODO: Don't drop readiness
            let _ = set_readiness.set_readiness(Ready::readable());
        }

        self.registration.fill(registration).ok().expect("unexpected state encountered");
        self.inner.set_readiness.fill(set_readiness).ok().expect("unexpected state encountered");

        Ok(())
    }

    fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
        match self.registration.borrow() {
            Some(registration) => poll.reregister(registration, token, interest, opts),
            None => Err(io::Error::new(io::ErrorKind::Other, "receiver not registered")),
        }
    }

    fn deregister(&self, poll: &Poll) -> io::Result<()> {
        match self.registration.borrow() {
            Some(registration) => poll.deregister(registration),
            None => Err(io::Error::new(io::ErrorKind::Other, "receiver not registered")),
        }
    }
}

/*
 *
 * ===== Error conversions =====
 *
 */

impl<T> From<mpsc::SendError<T>> for SendError<T> {
    fn from(src: mpsc::SendError<T>) -> SendError<T> {
        SendError::Disconnected(src.0)
    }
}

impl<T> From<io::Error> for SendError<T> {
    fn from(src: io::Error) -> SendError<T> {
        SendError::Io(src)
    }
}

impl<T> From<mpsc::TrySendError<T>> for TrySendError<T> {
    fn from(src: mpsc::TrySendError<T>) -> TrySendError<T> {
        match src {
            mpsc::TrySendError::Full(v) => TrySendError::Full(v),
            mpsc::TrySendError::Disconnected(v) => TrySendError::Disconnected(v),
        }
    }
}

impl<T> From<mpsc::SendError<T>> for TrySendError<T> {
    fn from(src: mpsc::SendError<T>) -> TrySendError<T> {
        TrySendError::Disconnected(src.0)
    }
}

impl<T> From<io::Error> for TrySendError<T> {
    fn from(src: io::Error) -> TrySendError<T> {
        TrySendError::Io(src)
    }
}

/*
 *
 * ===== Implement Error, Debug and Display for Errors =====
 *
 */

impl<T: Any> error::Error for SendError<T> {
    fn description(&self) -> &str {
        match self {
            &SendError::Io(ref io_err) => io_err.description(),
            &SendError::Disconnected(..) => "Disconnected",
        }
    }
}

impl<T: Any> error::Error for TrySendError<T> {
    fn description(&self) -> &str {
        match self {
            &TrySendError::Io(ref io_err) => io_err.description(),
            &TrySendError::Full(..) => "Full",
            &TrySendError::Disconnected(..) => "Disconnected",
        }
    }
}

impl<T> fmt::Debug for SendError<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        format_send_error(self, f)
    }
}

impl<T> fmt::Display for SendError<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        format_send_error(self, f)
    }
}

impl<T> fmt::Debug for TrySendError<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        format_try_send_error(self, f)
    }
}

impl<T> fmt::Display for TrySendError<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        format_try_send_error(self, f)
    }
}

#[inline]
fn format_send_error<T>(e: &SendError<T>, f: &mut fmt::Formatter) -> fmt::Result {
    match e {
        &SendError::Io(ref io_err) => write!(f, "{}", io_err),
        &SendError::Disconnected(..) => write!(f, "Disconnected"),
    }
}

#[inline]
fn format_try_send_error<T>(e: &TrySendError<T>, f: &mut fmt::Formatter) -> fmt::Result {
    match e {
        &TrySendError::Io(ref io_err) => write!(f, "{}", io_err),
        &TrySendError::Full(..) => write!(f, "Full"),
        &TrySendError::Disconnected(..) => write!(f, "Disconnected"),
    }
}<commit_msg>Use ? instead of try!<commit_after>//! Thread safe communication channel implementing `Evented`

extern crate mio;
extern crate lazycell;

use mio::{Evented, Ready, Poll, PollOpt, Registration, SetReadiness, Token};
use lazycell::{LazyCell, AtomicLazyCell};
use std::any::Any;
use std::fmt;
use std::error;
use std::io;
use std::sync::{mpsc, Arc};
use std::sync::atomic::{AtomicUsize, Ordering};

/// Creates a new asynchronous channel, where the `Receiver` can be registered
/// with `Poll`.
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
    let (tx_ctl, rx_ctl) = ctl_pair();
    let (tx, rx) = mpsc::channel();

    let tx = Sender {
        tx: tx,
        ctl: tx_ctl,
    };

    let rx = Receiver {
        rx: rx,
        ctl: rx_ctl,
    };

    (tx, rx)
}

/// Creates a new synchronous, bounded channel where the `Receiver` can be
/// registered with `Poll`.
pub fn sync_channel<T>(bound: usize) -> (SyncSender<T>, Receiver<T>) {
    let (tx_ctl, rx_ctl) = ctl_pair();
    let (tx, rx) = mpsc::sync_channel(bound);

    let tx = SyncSender {
        tx: tx,
        ctl: tx_ctl,
    };

    let rx = Receiver {
        rx: rx,
        ctl: rx_ctl,
    };

    (tx, rx)
}

pub fn ctl_pair() -> (SenderCtl, ReceiverCtl) {
    let inner = Arc::new(Inner {
        pending: AtomicUsize::new(0),
        senders: AtomicUsize::new(1),
        set_readiness: AtomicLazyCell::new(),
    });

    let tx = SenderCtl {
        inner: inner.clone(),
    };

    let rx = ReceiverCtl {
        registration: LazyCell::new(),
        inner: inner,
    };

    (tx, rx)
}

/// Tracks messages sent on a channel in order to update readiness.
pub struct SenderCtl {
    inner: Arc<Inner>,
}

/// Tracks messages received on a channel in order to track readiness.
pub struct ReceiverCtl {
    registration: LazyCell<Registration>,
    inner: Arc<Inner>,
}

pub struct Sender<T> {
    tx: mpsc::Sender<T>,
    ctl: SenderCtl,
}

pub struct SyncSender<T> {
    tx: mpsc::SyncSender<T>,
    ctl: SenderCtl,
}

pub struct Receiver<T> {
    rx: mpsc::Receiver<T>,
    ctl: ReceiverCtl,
}

pub enum SendError<T> {
    Io(io::Error),
    Disconnected(T),
}

pub enum TrySendError<T> {
    Io(io::Error),
    Full(T),
    Disconnected(T),
}

struct Inner {
    // The number of outstanding messages for the receiver to read
    pending: AtomicUsize,
    // The number of sender handles
    senders: AtomicUsize,
    // The set readiness handle
    set_readiness: AtomicLazyCell<SetReadiness>,
}

impl<T> Sender<T> {
    pub fn send(&self, t: T) -> Result<(), SendError<T>> {
        self.tx.send(t)
            .map_err(SendError::from)
            .and_then(|_| {
                try!(self.ctl.inc());
                Ok(())
            })
    }
}

impl<T> Clone for Sender<T> {
    fn clone(&self) -> Sender<T> {
        Sender {
            tx: self.tx.clone(),
            ctl: self.ctl.clone(),
        }
    }
}

impl<T> SyncSender<T> {
    pub fn send(&self, t: T) -> Result<(), SendError<T>> {
        self.tx.send(t)
            .map_err(From::from)
            .and_then(|_| {
                try!(self.ctl.inc());
                Ok(())
            })
    }

    pub fn try_send(&self, t: T) -> Result<(), TrySendError<T>> {
        self.tx.try_send(t)
            .map_err(From::from)
            .and_then(|_| {
                try!(self.ctl.inc());
                Ok(())
            })
    }
}

impl<T> Clone for SyncSender<T> {
    fn clone(&self) -> SyncSender<T> {
        SyncSender {
            tx: self.tx.clone(),
            ctl: self.ctl.clone(),
        }
    }
}

impl<T> Receiver<T> {
    pub fn try_recv(&self) -> Result<T, mpsc::TryRecvError> {
        self.rx.try_recv().and_then(|res| {
            let _ = self.ctl.dec();
            Ok(res)
        })
    }
}

impl<T> Evented for Receiver<T> {
    fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
        self.ctl.register(poll, token, interest, opts)
    }

    fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
        self.ctl.reregister(poll, token, interest, opts)
    }

    fn deregister(&self, poll: &Poll) -> io::Result<()> {
        self.ctl.deregister(poll)
    }
}

/*
 *
 * ===== SenderCtl / ReceiverCtl =====
 *
 */

impl SenderCtl {
    /// Call to track that a message has been sent
    pub fn inc(&self) -> io::Result<()> {
        let cnt = self.inner.pending.fetch_add(1, Ordering::Acquire);

        if 0 == cnt {
            // Toggle readiness to readable
            if let Some(set_readiness) = self.inner.set_readiness.borrow() {
                set_readiness.set_readiness(Ready::readable())?;
            }
        }

        Ok(())
    }
}

impl Clone for SenderCtl {
    fn clone(&self) -> SenderCtl {
        self.inner.senders.fetch_add(1, Ordering::Relaxed);
        SenderCtl { inner: self.inner.clone() }
    }
}

impl Drop for SenderCtl {
    fn drop(&mut self) {
        if self.inner.senders.fetch_sub(1, Ordering::Release) == 1 {
            let _ = self.inc();
        }
    }
}

impl ReceiverCtl {
    pub fn dec(&self) -> io::Result<()> {
        let first = self.inner.pending.load(Ordering::Acquire);

        if first == 1 {
            // Unset readiness
            if let Some(set_readiness) = self.inner.set_readiness.borrow() {
                try!(set_readiness.set_readiness(Ready::empty()));
            }
        }

        // Decrement
        let second = self.inner.pending.fetch_sub(1, Ordering::AcqRel);

        if first == 1 && second > 1 {
            // There are still pending messages. Since readiness was
            // previously unset, it must be reset here
            if let Some(set_readiness) = self.inner.set_readiness.borrow() {
                try!(set_readiness.set_readiness(Ready::readable()));
            }
        }

        Ok(())
    }
}

impl Evented for ReceiverCtl {
    fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
        if self.registration.borrow().is_some() {
            return Err(io::Error::new(io::ErrorKind::Other, "receiver already registered"));
        }

        let (registration, set_readiness) = Registration::new2();
        poll.register(&registration, token, interest, opts)?;

        if self.inner.pending.load(Ordering::Relaxed) > 0 {
            // TODO: Don't drop readiness
            let _ = set_readiness.set_readiness(Ready::readable());
        }

        self.registration.fill(registration).ok().expect("unexpected state encountered");
        self.inner.set_readiness.fill(set_readiness).ok().expect("unexpected state encountered");

        Ok(())
    }

    fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
        match self.registration.borrow() {
            Some(registration) => poll.reregister(registration, token, interest, opts),
            None => Err(io::Error::new(io::ErrorKind::Other, "receiver not registered")),
        }
    }

    fn deregister(&self, poll: &Poll) -> io::Result<()> {
        match self.registration.borrow() {
            Some(registration) => poll.deregister(registration),
            None => Err(io::Error::new(io::ErrorKind::Other, "receiver not registered")),
        }
    }
}

/*
 *
 * ===== Error conversions =====
 *
 */

impl<T> From<mpsc::SendError<T>> for SendError<T> {
    fn from(src: mpsc::SendError<T>) -> SendError<T> {
        SendError::Disconnected(src.0)
    }
}

impl<T> From<io::Error> for SendError<T> {
    fn from(src: io::Error) -> SendError<T> {
        SendError::Io(src)
    }
}

impl<T> From<mpsc::TrySendError<T>> for TrySendError<T> {
    fn from(src: mpsc::TrySendError<T>) -> TrySendError<T> {
        match src {
            mpsc::TrySendError::Full(v) => TrySendError::Full(v),
            mpsc::TrySendError::Disconnected(v) => TrySendError::Disconnected(v),
        }
    }
}

impl<T> From<mpsc::SendError<T>> for TrySendError<T> {
    fn from(src: mpsc::SendError<T>) -> TrySendError<T> {
        TrySendError::Disconnected(src.0)
    }
}

impl<T> From<io::Error> for TrySendError<T> {
    fn from(src: io::Error) -> TrySendError<T> {
        TrySendError::Io(src)
    }
}

/*
 *
 * ===== Implement Error, Debug and Display for Errors =====
 *
 */

impl<T: Any> error::Error for SendError<T> {
    fn description(&self) -> &str {
        match self {
            &SendError::Io(ref io_err) => io_err.description(),
            &SendError::Disconnected(..) => "Disconnected",
        }
    }
}

impl<T: Any> error::Error for TrySendError<T> {
    fn description(&self) -> &str {
        match self {
            &TrySendError::Io(ref io_err) => io_err.description(),
            &TrySendError::Full(..) => "Full",
            &TrySendError::Disconnected(..) => "Disconnected",
        }
    }
}

impl<T> fmt::Debug for SendError<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        format_send_error(self, f)
    }
}

impl<T> fmt::Display for SendError<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        format_send_error(self, f)
    }
}

impl<T> fmt::Debug for TrySendError<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        format_try_send_error(self, f)
    }
}

impl<T> fmt::Display for TrySendError<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        format_try_send_error(self, f)
    }
}

#[inline]
fn format_send_error<T>(e: &SendError<T>, f: &mut fmt::Formatter) -> fmt::Result {
    match e {
        &SendError::Io(ref io_err) => write!(f, "{}", io_err),
        &SendError::Disconnected(..) => write!(f, "Disconnected"),
    }
}

#[inline]
fn format_try_send_error<T>(e: &TrySendError<T>, f: &mut fmt::Formatter) -> fmt::Result {
    match e {
        &TrySendError::Io(ref io_err) => write!(f, "{}", io_err),
        &TrySendError::Full(..) => write!(f, "Full"),
        &TrySendError::Disconnected(..) => write!(f, "Disconnected"),
    }
}<|endoftext|>


<commit_before>//////////// Brush cache boilerplate ////////////

use std::cell::{RefCell};
use calx::{ImageStore, IndexCache};
use calx::backend::{CanvasBuilder, Image};

#[macro_export]
macro_rules! brush {
    {
        $enumname:ident {
            // Image file to load brushes from.
            $([$filename:expr]
              // Named brushes
              $($brushname:ident:
                  // Frames for the named brush as rectangles in the current
                  // image file.
                  $($xoff:expr, $yoff:expr, $xdim:expr, $ydim:expr, $x:expr, $y:expr;)+
              )+
            )+
        }
    } =>
    {
#[derive(Copy, Clone, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)]
        pub enum $enumname {
            $(
                $($brushname,)*
            )*
        }

        cache_key!($enumname);

        impl $enumname {
            /// Get the sprite image.
            pub fn get(self, idx: usize) -> Image {
                BRUSH_CACHE.with(|c| c.borrow().get(self).expect("Brush not initialized")[idx])
            }

            /// Build the actual sprites in a canvas for the enum set.
            pub fn init(builder: &mut CanvasBuilder) {
                BRUSH_CACHE.with(|c| { *c.borrow_mut() = build_brushes(builder); });
            }
        }

        thread_local!(static BRUSH_CACHE: RefCell<IndexCache<Brush, Vec<Image>>> = RefCell::new(IndexCache::new()));

        fn build_brushes(builder: &mut CanvasBuilder) -> IndexCache<Brush, Vec<Image>> {
            use image;
            use calx::{V2, color_key, color, Rgba};

            let mut ret = IndexCache::new();

            fn load(data: &'static [u8]) -> image::ImageBuffer<image::Rgba<u8>, Vec<u8>> {
                // XXX: Shouldn't hardcode the color::CYAN part, factor out
                // the loader?
                color_key(&image::load_from_memory(data).unwrap(), color::CYAN)
            }

            $({
                let mut sheet = load(include_bytes!($filename));

                $({
                    let mut frames = Vec::new();

                    $({
                        frames.push(builder.add_image(
                                V2($xoff, $yoff),
                                &image::SubImage::new(&mut sheet, $x, $y, $xdim, $ydim)));
                    })*

                    ret.insert($enumname::$brushname, frames);
                })*

            })*

            ret
        }
    }
}

/*
cache_key!(Brush);

impl Brush {
    /// Get the sprite image.
    pub fn get(self, idx: usize) -> Image {
        BRUSH_CACHE.with(|c| c.borrow().get(self).expect("Brush not found")[idx])
    }

    /// Build the actual sprites in a canvas for the enum set.
    pub fn init(builder: &mut CanvasBuilder) {
        BRUSH_CACHE.with(|c| { *c.borrow_mut() = build_brushes(builder); });
    }
}

thread_local!(static BRUSH_CACHE: RefCell<IndexCache<Brush, Vec<Image>>> = RefCell::new(IndexCache::new()));
*/

brush!(Brush {
    ["../assets/logo.png"]
    Logo:
        0, 0, 92, 24, 0, 0;

    /*
    IconHeart,
    IconHalfHeart,
    IconNoHeart,
    IconShard,
    IconHalfShard,
    IconNoShard,

    BlockRear,
    BlockRock,

    BrickWall,
    BrickWindowWall,
    BrickOpenWall,
    DoorWall,
    BarsWall,
    FenceWall,
    HouseWall,
    RockWall,

    BlankFloor,
    Floor,
    Grass,
    Water,
    Shallows,

    Human,
    Snake,
    Dreg,
    Ogre,
    Wraith,
    Octopus,
    Bug,
    Ooze,
    Efreet,
    Serpent,
    SerpentMound,

    CursorBottom,
    CursorTop,
    Table,
    Stone,
    Fountain,
    Altar,
    Barrell,
    Stalagmite,
    Pillar,
    Grave,
    Crystal,
    Menhir,
    Sword,
    Helmet,
    Potion,
    Wand,
    Health,
    Knives,
    Armor,
    Ring,
    StairsDown,
    TreeTrunk,
    TreeFoliage,
    */
});

//////////// Custom definitions start here ////////////

/*
#[derive(Copy, Clone, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)]
pub enum Brush {
    Logo,

    IconHeart,
    IconHalfHeart,
    IconNoHeart,
    IconShard,
    IconHalfShard,
    IconNoShard,

    BlockRear,
    BlockRock,

    BrickWall,
    BrickWindowWall,
    BrickOpenWall,
    DoorWall,
    BarsWall,
    FenceWall,
    HouseWall,
    RockWall,

    BlankFloor,
    Floor,
    Grass,
    Water,
    Shallows,

    Human,
    Snake,
    Dreg,
    Ogre,
    Wraith,
    Octopus,
    Bug,
    Ooze,
    Efreet,
    Serpent,
    SerpentMound,

    CursorBottom,
    CursorTop,
    Table,
    Stone,
    Fountain,
    Altar,
    Barrell,
    Stalagmite,
    Pillar,
    Grave,
    Crystal,
    Menhir,
    Sword,
    Helmet,
    Potion,
    Wand,
    Health,
    Knives,
    Armor,
    Ring,
    StairsDown,
    TreeTrunk,
    TreeFoliage,
}

fn build_brushes(builder: &mut CanvasBuilder) -> IndexCache<Brush, Vec<Image>> {
    use image;
    use calx::{V2, IterTiles, color_key, color, Rgba};
    use self::Brush::*;

    fn load(data: &'static [u8]) -> image::ImageBuffer<image::Rgba<u8>, Vec<u8>> {
        color_key(&image::load_from_memory(data).unwrap(), color::CYAN)
    }

    let offset = V2(-16, -16);
    let size = V2(32, 32);

    let mut ret = IndexCache::new();

    for (k, img) in vec![
        BlankFloor,
        Floor,
        Grass,
        Water,
        Shallows,
    ].into_iter().zip(
        builder.batch_add(offset, size, &mut load(include_bytes!("../assets/floors.png")))) {
        ret.insert(k, vec![img]);
    }

    for (k, img) in vec![
        Human,
        Snake,
        Dreg,
        Ogre,
        Wraith,
        Octopus,
        Bug,
        Ooze,
        Efreet,
        Serpent,
        SerpentMound,
    ].into_iter().zip(
        builder.batch_add(offset, size, &mut load(include_bytes!("../assets/mobs.png")))) {
        ret.insert(k, vec![img]);
    }

    for (k, img) in vec![
        CursorBottom,
        CursorTop,
        Table,
        Stone,
        Fountain,
        Altar,
        Barrell,
        Stalagmite,
        Pillar,
        Grave,
        Crystal,
        Menhir,
        Sword,
        Helmet,
        Potion,
        Wand,
        Health,
        Knives,
        Armor,
        Ring,
        StairsDown,
        TreeTrunk,
        TreeFoliage,
    ].into_iter().zip(
        builder.batch_add(offset, size, &mut load(include_bytes!("../assets/props.png")))) {
        ret.insert(k, vec![img]);
    }

    // Wall tiles.
    {
        let mut wall_images = Vec::new();
        let mut wall_sheet = load(include_bytes!("../assets/walls.png"));
        // Can't use batch_add for walls because the offsets alternate.
        for (i, rect) in wall_sheet.tiles(V2(16, 32)).take(28).enumerate() {
            let offset = V2(if i % 2 == 0 { -16 } else { 0 }, -16);
            let image = image::SubImage::new(&mut wall_sheet, rect.mn().0, rect.mn().1, rect.dim().0, rect.dim().1);
            wall_images.push(builder.add_image(offset, &image));
        }

        // Also I'm reusing the center wall piece a bit so I can't generalize
        // these either.

        ret.insert(BrickWall, vec![0, 1, 2, 3]          .into_iter().map(|x| wall_images[x]).collect());
        ret.insert(BrickWindowWall, vec![0, 1, 4, 5]    .into_iter().map(|x| wall_images[x]).collect());
        ret.insert(BrickOpenWall, vec![0, 1, 6, 7]      .into_iter().map(|x| wall_images[x]).collect());
        ret.insert(DoorWall, vec![8, 9, 10, 11]         .into_iter().map(|x| wall_images[x]).collect());
        ret.insert(BarsWall, vec![12, 13, 14, 15]       .into_iter().map(|x| wall_images[x]).collect());
        ret.insert(FenceWall, vec![16, 17, 18, 19]      .into_iter().map(|x| wall_images[x]).collect());
        ret.insert(HouseWall, vec![20, 21, 22, 23]      .into_iter().map(|x| wall_images[x]).collect());
        ret.insert(RockWall, vec![24, 25, 26, 27]       .into_iter().map(|x| wall_images[x]).collect());
    }

    // Block tiles
    {
        let mut block_sheet = load(include_bytes!("../assets/blocks.png"));

        for (y, brush) in vec![
            BlockRear,
            BlockRock,
        ].into_iter().enumerate() {
            // Another tricky setup. The first three tiles are 32x32 brushes,
            // the last four are 16x32.
            let mut frames = Vec::new();
            let y = y as u32;
            let mut x = 0u32;
            for &width in &[32, 32, 32, 16, 16, 16, 16] {
                let offset = (x as i32 % 32) - 16;
                frames.push(builder.add_image(V2(offset, -16),
                    &image::SubImage::new(&mut block_sheet, x, y * 32, width, 32)));
                x += width;
            }

            ret.insert(brush, frames)
        }
    }

    ret.insert(Logo, vec![builder.add_image(V2(0, 0), &load(include_bytes!("../assets/logo.png")))]);

    for (k, img) in vec![
        IconHeart,
        IconHalfHeart,
        IconNoHeart,
        IconShard,
        IconHalfShard,
        IconNoShard,
    ].into_iter().zip(
        builder.batch_add(V2(0, -8), V2(8, 8), &mut load(include_bytes!("../assets/icon.png")))) {
        ret.insert(k, vec![img]);
    }

    ret
}
*/
<commit_msg>Enter frame coordinates manually<commit_after>//////////// Brush cache boilerplate ////////////

use std::cell::{RefCell};
use calx::{ImageStore, IndexCache};
use calx::backend::{CanvasBuilder, Image};

brush!(Brush {
    ["../assets/logo.png",
        [Logo,
        0, 0, 92, 24, 0, 0]
    ]

    ["../assets/icon.png",
        [IconHeart,
            0, 8, 8, 8, 0, 0]
        [IconHalfHeart,
            0, 8, 8, 8, 8, 0]
        [IconNoHeart,
            0, 8, 8, 8, 16, 0]
        [IconShard,
            0, 8, 8, 8, 24, 0]
        [IconHalfShard,
            0, 8, 8, 8, 32, 0]
        [IconNoShard,
            0, 8, 8, 8, 40, 0]
    ]

    ["../assets/blocks.png",
        [BlockRear,
            16, 16, 32, 32,   0,   0,
            16, 16, 32, 32,  32,   0,
            16, 16, 32, 32,  64,   0,
            16, 16, 32, 16,  96,   0,
             0, 16, 32, 16, 112,   0,
            16, 16, 32, 16, 128,   0,
             0, 16, 32, 16, 144,   0]
        [BlockRock,
            16, 16, 32, 32,   0,  32,
            16, 16, 32, 32,  32,  32,
            16, 16, 32, 32,  64,  32,
            16, 16, 32, 16,  96,  32,
             0, 16, 32, 16, 112,  32,
            16, 16, 32, 16, 128,  32,
             0, 16, 32, 16, 144,  32]
    ]

    ["../assets/walls.png",
        [BrickWall,
            16, 16, 32, 16,   0,   0,
             0, 16, 32, 16,  16,   0,
            16, 16, 32, 16,  32,   0,
             0, 16, 32, 16,  48,   0]
        [BrickWindowWall,
            16, 16, 32, 16,   0,   0,
             0, 16, 32, 16,  16,   0,
            16, 16, 32, 16,  64,   0,
             0, 16, 32, 16,  80,   0]
        [BrickOpenWall,
            16, 16, 32, 16,   0,   0,
             0, 16, 32, 16,  16,   0,
            16, 16, 32, 16,  96,   0,
             0, 16, 32, 16, 112,   0]
        [DoorWall,
            16, 16, 32, 16, 128,   0,
             0, 16, 32, 16, 144,   0,
            16, 16, 32, 16, 160,   0,
             0, 16, 32, 16, 176,   0]
        [BarsWall,
            16, 16, 32, 16, 192,   0,
             0, 16, 32, 16, 208,   0,
            16, 16, 32, 16, 224,   0,
             0, 16, 32, 16, 240,   0]
        [FenceWall,
            16, 16, 32, 16,   0,  32,
             0, 16, 32, 16,  16,  32,
            16, 16, 32, 16,  32,  32,
             0, 16, 32, 16,  48,  32]
        [HouseWall,
            16, 16, 32, 16,  64,  32,
             0, 16, 32, 16,  80,  32,
            16, 16, 32, 16,  96,  32,
             0, 16, 32, 16, 112,  32]
        [RockWall,
            16, 16, 32, 16, 128,  32,
             0, 16, 32, 16, 144,  32,
            16, 16, 32, 16, 160,  32,
             0, 16, 32, 16, 176,  32]
    ]

    ["../assets/floors.png",
        [BlankFloor,
            16, 16, 32, 32,   0,   0]
        [Floor,
            16, 16, 32, 32,  32,   0]
        [Grass,
            16, 16, 32, 32,  64,   0]
        [Water,
            16, 16, 32, 32,  96,   0]
        [Shallows,
            16, 16, 32, 32, 128,   0]
    ]

    ["../assets/mobs.png",
        [Human,
            16, 16, 32, 32,   0,   0]
        [Snake,
            16, 16, 32, 32,  32,   0]
        [Dreg,
            16, 16, 32, 32,  64,   0]
        [Ogre,
            16, 16, 32, 32,  96,   0]
        [Wraith,
            16, 16, 32, 32, 128,   0]
        [Octopus,
            16, 16, 32, 32, 160,   0]
        [Bug,
            16, 16, 32, 32, 192,   0]
        [Ooze,
            16, 16, 32, 32, 224,   0]
        [Efreet,
            16, 16, 32, 32,   0,  32]
        [Serpent,
            // Head
            16, 16, 32, 32,  32,  32,
            // Burrow mound
            16, 16, 32, 32,  64,  32]
    ]

    ["../assets/props.png",
        [CursorBottom,
            16, 16, 32, 32,   0,   0]
        [CursorTop,
            16, 16, 32, 32,  32,   0]
        [Table,
            16, 16, 32, 32,  64,   0]
        [Stone,
            16, 16, 32, 32,  96,   0]
        [Fountain,
            16, 16, 32, 32, 128,   0]
        [Altar,
            16, 16, 32, 32, 160,   0]
        [Barrell,
            16, 16, 32, 32, 192,   0]
        [Stalagmite,
            16, 16, 32, 32, 224,   0]
        [Pillar,
            16, 16, 32, 32,   0,  32]
        [Grave,
            16, 16, 32, 32,  32,  32]
        [Crystal,
            16, 16, 32, 32,  64,  32]
        [Menhir,
            16, 16, 32, 32,  96,  32]
        [Sword,
            16, 16, 32, 32, 128,  32]
        [Helmet,
            16, 16, 32, 32, 160,  32]
        [Potion,
            16, 16, 32, 32, 192,  32]
        [Wand,
            16, 16, 32, 32, 224,  32]
        [Health,
            16, 16, 32, 32,   0,  64]
        [Knives,
            16, 16, 32, 32,  32,  64]
        [Armor,
            16, 16, 32, 32,  64,  64]
        [Ring,
            16, 16, 32, 32,  96,  64]
        [StairsDown,
            16, 16, 32, 32, 128,  64]
        [TreeTrunk,
            16, 16, 32, 32, 160,  64]
        [TreeFoliage,
            16, 16, 32, 32, 192,  64]
    ]
});
<|endoftext|>