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

//! # The VM runtime
//!
//! ## Transaction flow
//!
//! This is the path taken to process a single transaction.
//!
//! ```text
//!                   SignedTransaction
//!                            +
//!                            |
//! +--------------------------|-------------------+
//! | Validate  +--------------+--------------+    |
//! |           |                             |    |
//! |           |       check signature       |    |
//! |           |                             |    |
//! |           +--------------+--------------+    |
//! |                          |                   |
//! |                          |                   |
//! |                          v                   |
//! |           +--------------+--------------+    |
//! |           |                             |    |
//! |           |      check size and gas     |    |
//! |           |                             |    +---------------------------------+
//! |           +--------------+--------------+    |         validation error        |
//! |                          |                   |                                 |
//! |                          |                   |                                 |
//! |                          v                   |                                 |
//! |           +--------------+--------------+    |                                 |
//! |           |                             |    |                                 |
//! |           |         run prologue        |    |                                 |
//! |           |                             |    |                                 |
//! |           +--------------+--------------+    |                                 |
//! |                          |                   |                                 |
//! +--------------------------|-------------------+                                 |
//!                            |                                                     |
//! +--------------------------|-------------------+                                 |
//! |                          v                   |                                 |
//! |  Verify   +--------------+--------------+    |                                 |
//! |           |                             |    |                                 |
//! |           |     deserialize script,     |    |                                 |
//! |           |     verify arguments        |    |                                 |
//! |           |                             |    |                                 |
//! |           +--------------+--------------+    |                                 |
//! |                          |                   |                                 |
//! |                          |                   |                                 v
//! |                          v                   |                    +----------------+------+
//! |           +--------------+--------------+    |                    |                       |
//! |           |                             |    +------------------->+ discard, no write set |
//! |           |     deserialize modules     |    | verification error |                       |
//! |           |                             |    |                    +----------------+------+
//! |           +--------------+--------------+    |                                 ^
//! |                          |                   |                                 |
//! |                          |                   |                                 |
//! |                          v                   |                                 |
//! |           +--------------+--------------+    |                                 |
//! |           |                             |    |                                 |
//! |           | verify scripts and modules  |    |                                 |
//! |           |                             |    |                                 |
//! |           +--------------+--------------+    |                                 |
//! |                          |                   |                                 |
//! +--------------------------|-------------------+                                 |
//!                            |                                                     |
//! +--------------------------|-------------------+                                 |
//! |                          v                   |                                 |
//! | Execute   +--------------+--------------+    |                                 |
//! |           |                             |    |                                 |
//! |           |        execute main         |    |                                 |
//! |           |                             |    |                                 |
//! |           +--------------+--------------+    |                                 |
//! |                          |                   |                                 |
//! |      success or failure  |                   |                                 |
//! |                          v                   |                                 |
//! |           +--------------+--------------+    |                                 |
//! |           |                             |    +---------------------------------+
//! |           |        run epilogue         |    | invariant violation (internal panic)
//! |           |                             |    |
//! |           +--------------+--------------+    |
//! |                          |                   |
//! |                          |                   |
//! |                          v                   |
//! |           +--------------+--------------+    |                    +-----------------------+
//! |           |                             |    | execution failure  |                       |
//! |           |       make write set        +------------------------>+ keep, only charge gas |
//! |           |                             |    |                    |                       |
//! |           +--------------+--------------+    |                    +-----------------------+
//! |                          |                   |
//! +--------------------------|-------------------+
//!                            |
//!                            v
//!             +--------------+--------------+
//!             |                             |
//!             |  keep, transaction executed |
//!             |        + gas charged        |
//!             |                             |
//!             +-----------------------------+
//! ```

#[macro_use]
extern crate vm;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate rental;
#[macro_use]
extern crate mirai_annotations;

mod block_processor;
mod counters;
mod frame;
mod gas_meter;
mod move_vm;
mod process_txn;
mod runtime;

pub mod code_cache;
pub mod data_cache;
pub mod identifier;
pub mod loaded_data;
pub mod txn_executor;

#[cfg(feature = "instruction_synthesis")]
pub mod execution_stack;
#[cfg(not(feature = "instruction_synthesis"))]
mod execution_stack;
#[macro_use]
extern crate mirai_annotations;

pub use move_vm::MoveVM;
pub use process_txn::verify::static_verify_program;
pub use txn_executor::execute_function;

use config::config::VMConfig;
use state_view::StateView;
use types::{
    transaction::{SignedTransaction, TransactionOutput},
    vm_error::VMStatus,
};
use vm::{errors::VMInvariantViolation, IndexKind};

pub(crate) fn bounded_fetch<T>(
    pool: &[T],
    idx: usize,
    bound_type: IndexKind,
) -> Result<&T, VMInvariantViolation> {
    pool.get(idx)
        .ok_or_else(|| VMInvariantViolation::IndexOutOfBounds(bound_type, pool.len(), idx))
}

/// This trait describes the VM's verification interfaces.
pub trait VMVerifier {
    /// Executes the prologue of the Libra Account and verifies that the transaction is valid.
    /// only. Returns `None` if the transaction was validated, or Some(VMStatus) if the transaction
    /// was unable to be validated with status `VMStatus`.
    fn validate_transaction(
        &self,
        transaction: SignedTransaction,
        state_view: &dyn StateView,
    ) -> Option<VMStatus>;
}

/// This trait describes the VM's execution interface.
pub trait VMExecutor {
    // NOTE: At the moment there are no persistent caches that live past the end of a block (that's
    // why execute_block doesn't take &self.)
    // There are some cache invalidation issues around transactions publishing code that need to be
    // sorted out before that's possible.

    /// Executes a block of transactions and returns output for each one of them.
    fn execute_block(
        transactions: Vec<SignedTransaction>,
        config: &VMConfig,
        state_view: &dyn StateView,
    ) -> Vec<TransactionOutput>;
}
<commit_msg>[VM] Remove duplicate MIRAI annotations import<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! # The VM runtime
//!
//! ## Transaction flow
//!
//! This is the path taken to process a single transaction.
//!
//! ```text
//!                   SignedTransaction
//!                            +
//!                            |
//! +--------------------------|-------------------+
//! | Validate  +--------------+--------------+    |
//! |           |                             |    |
//! |           |       check signature       |    |
//! |           |                             |    |
//! |           +--------------+--------------+    |
//! |                          |                   |
//! |                          |                   |
//! |                          v                   |
//! |           +--------------+--------------+    |
//! |           |                             |    |
//! |           |      check size and gas     |    |
//! |           |                             |    +---------------------------------+
//! |           +--------------+--------------+    |         validation error        |
//! |                          |                   |                                 |
//! |                          |                   |                                 |
//! |                          v                   |                                 |
//! |           +--------------+--------------+    |                                 |
//! |           |                             |    |                                 |
//! |           |         run prologue        |    |                                 |
//! |           |                             |    |                                 |
//! |           +--------------+--------------+    |                                 |
//! |                          |                   |                                 |
//! +--------------------------|-------------------+                                 |
//!                            |                                                     |
//! +--------------------------|-------------------+                                 |
//! |                          v                   |                                 |
//! |  Verify   +--------------+--------------+    |                                 |
//! |           |                             |    |                                 |
//! |           |     deserialize script,     |    |                                 |
//! |           |     verify arguments        |    |                                 |
//! |           |                             |    |                                 |
//! |           +--------------+--------------+    |                                 |
//! |                          |                   |                                 |
//! |                          |                   |                                 v
//! |                          v                   |                    +----------------+------+
//! |           +--------------+--------------+    |                    |                       |
//! |           |                             |    +------------------->+ discard, no write set |
//! |           |     deserialize modules     |    | verification error |                       |
//! |           |                             |    |                    +----------------+------+
//! |           +--------------+--------------+    |                                 ^
//! |                          |                   |                                 |
//! |                          |                   |                                 |
//! |                          v                   |                                 |
//! |           +--------------+--------------+    |                                 |
//! |           |                             |    |                                 |
//! |           | verify scripts and modules  |    |                                 |
//! |           |                             |    |                                 |
//! |           +--------------+--------------+    |                                 |
//! |                          |                   |                                 |
//! +--------------------------|-------------------+                                 |
//!                            |                                                     |
//! +--------------------------|-------------------+                                 |
//! |                          v                   |                                 |
//! | Execute   +--------------+--------------+    |                                 |
//! |           |                             |    |                                 |
//! |           |        execute main         |    |                                 |
//! |           |                             |    |                                 |
//! |           +--------------+--------------+    |                                 |
//! |                          |                   |                                 |
//! |      success or failure  |                   |                                 |
//! |                          v                   |                                 |
//! |           +--------------+--------------+    |                                 |
//! |           |                             |    +---------------------------------+
//! |           |        run epilogue         |    | invariant violation (internal panic)
//! |           |                             |    |
//! |           +--------------+--------------+    |
//! |                          |                   |
//! |                          |                   |
//! |                          v                   |
//! |           +--------------+--------------+    |                    +-----------------------+
//! |           |                             |    | execution failure  |                       |
//! |           |       make write set        +------------------------>+ keep, only charge gas |
//! |           |                             |    |                    |                       |
//! |           +--------------+--------------+    |                    +-----------------------+
//! |                          |                   |
//! +--------------------------|-------------------+
//!                            |
//!                            v
//!             +--------------+--------------+
//!             |                             |
//!             |  keep, transaction executed |
//!             |        + gas charged        |
//!             |                             |
//!             +-----------------------------+
//! ```

#[macro_use]
extern crate vm;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate rental;
#[macro_use]
extern crate mirai_annotations;

mod block_processor;
mod counters;
mod frame;
mod gas_meter;
mod move_vm;
mod process_txn;
mod runtime;

pub mod code_cache;
pub mod data_cache;
pub mod identifier;
pub mod loaded_data;
pub mod txn_executor;

#[cfg(feature = "instruction_synthesis")]
pub mod execution_stack;
#[cfg(not(feature = "instruction_synthesis"))]
mod execution_stack;

pub use move_vm::MoveVM;
pub use process_txn::verify::static_verify_program;
pub use txn_executor::execute_function;

use config::config::VMConfig;
use state_view::StateView;
use types::{
    transaction::{SignedTransaction, TransactionOutput},
    vm_error::VMStatus,
};
use vm::{errors::VMInvariantViolation, IndexKind};

pub(crate) fn bounded_fetch<T>(
    pool: &[T],
    idx: usize,
    bound_type: IndexKind,
) -> Result<&T, VMInvariantViolation> {
    pool.get(idx)
        .ok_or_else(|| VMInvariantViolation::IndexOutOfBounds(bound_type, pool.len(), idx))
}

/// This trait describes the VM's verification interfaces.
pub trait VMVerifier {
    /// Executes the prologue of the Libra Account and verifies that the transaction is valid.
    /// only. Returns `None` if the transaction was validated, or Some(VMStatus) if the transaction
    /// was unable to be validated with status `VMStatus`.
    fn validate_transaction(
        &self,
        transaction: SignedTransaction,
        state_view: &dyn StateView,
    ) -> Option<VMStatus>;
}

/// This trait describes the VM's execution interface.
pub trait VMExecutor {
    // NOTE: At the moment there are no persistent caches that live past the end of a block (that's
    // why execute_block doesn't take &self.)
    // There are some cache invalidation issues around transactions publishing code that need to be
    // sorted out before that's possible.

    /// Executes a block of transactions and returns output for each one of them.
    fn execute_block(
        transactions: Vec<SignedTransaction>,
        config: &VMConfig,
        state_view: &dyn StateView,
    ) -> Vec<TransactionOutput>;
}
<|endoftext|>


<commit_before>//! Helper functions and structures for the translation.
use cranelift_codegen::ir;
use std::u32;
use wasmparser;

/// Index type of a function (imported or defined) inside the WebAssembly module.
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct FuncIndex(u32);
entity_impl!(FuncIndex);

/// Index type of a defined function inside the WebAssembly module.
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct DefinedFuncIndex(u32);
entity_impl!(DefinedFuncIndex);

/// Index of a table (imported or defined) inside the WebAssembly module.
pub type TableIndex = usize;
/// Index of a global variable (imported or defined) inside the WebAssembly module.
pub type GlobalIndex = usize;
/// Index of a linear memory (imported or defined) inside the WebAssembly module.
pub type MemoryIndex = usize;
/// Index of a signature (imported or defined) inside the WebAssembly module.
pub type SignatureIndex = usize;

/// WebAssembly global.
#[derive(Debug, Clone, Copy)]
pub struct Global {
    /// The type of the value stored in the global.
    pub ty: ir::Type,
    /// A flag indicating whether the value may change at runtime.
    pub mutability: bool,
    /// The source of the initial value.
    pub initializer: GlobalInit,
}

/// Globals are initialized via the four `const` operators or by referring to another import.
#[derive(Debug, Clone, Copy)]
pub enum GlobalInit {
    /// An `i32.const`.
    I32Const(i32),
    /// An `i64.const`.
    I64Const(i64),
    /// An `f32.const`.
    F32Const(u32),
    /// An `f64.const`.
    F64Const(u64),
    /// A `get_global` of another global.
    GlobalRef(GlobalIndex),
    ///< The global is imported from, and thus initialized by, a different module.
    Import(),
}

/// WebAssembly table.
#[derive(Debug, Clone, Copy)]
pub struct Table {
    /// The type of data stored in elements of the table.
    pub ty: TableElementType,
    /// The minimum number of elements in the table.
    pub size: usize,
    /// The maximum number of elements in the table.
    pub maximum: Option<usize>,
}

/// WebAssembly table element. Can be a function or a scalar type.
#[derive(Debug, Clone, Copy)]
pub enum TableElementType {
    Val(ir::Type),
    Func(),
}

/// WebAssembly linear memory.
#[derive(Debug, Clone, Copy)]
pub struct Memory {
    /// The minimum number of pages in the memory.
    pub pages_count: usize,
    /// The maximum number of pages in the memory.
    pub maximum: Option<usize>,
    /// Whether the memory may be shared between multiple threads.
    pub shared: bool,
}

/// Helper function translating wasmparser types to Cranelift types when possible.
pub fn type_to_type(ty: wasmparser::Type) -> Result<ir::Type, ()> {
    match ty {
        wasmparser::Type::I32 => Ok(ir::types::I32),
        wasmparser::Type::I64 => Ok(ir::types::I64),
        wasmparser::Type::F32 => Ok(ir::types::F32),
        wasmparser::Type::F64 => Ok(ir::types::F64),
        _ => Err(()),
    }
}

/// Turns a `wasmparser` `f32` into a `Cranelift` one.
pub fn f32_translation(x: wasmparser::Ieee32) -> ir::immediates::Ieee32 {
    ir::immediates::Ieee32::with_bits(x.bits())
}

/// Turns a `wasmparser` `f64` into a `Cranelift` one.
pub fn f64_translation(x: wasmparser::Ieee64) -> ir::immediates::Ieee64 {
    ir::immediates::Ieee64::with_bits(x.bits())
}

/// Translate a `wasmparser` type into its `Cranelift` equivalent, when possible
pub fn num_return_values(ty: wasmparser::Type) -> usize {
    match ty {
        wasmparser::Type::EmptyBlockType => 0,
        wasmparser::Type::I32
        | wasmparser::Type::F32
        | wasmparser::Type::I64
        | wasmparser::Type::F64 => 1,
        _ => panic!("unsupported return value type"),
    }
}
<commit_msg>Make FuncIndex and DefinedFuncIndex implement the Debug trait.<commit_after>//! Helper functions and structures for the translation.
use cranelift_codegen::ir;
use std::u32;
use wasmparser;

/// Index type of a function (imported or defined) inside the WebAssembly module.
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub struct FuncIndex(u32);
entity_impl!(FuncIndex);

/// Index type of a defined function inside the WebAssembly module.
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub struct DefinedFuncIndex(u32);
entity_impl!(DefinedFuncIndex);

/// Index of a table (imported or defined) inside the WebAssembly module.
pub type TableIndex = usize;
/// Index of a global variable (imported or defined) inside the WebAssembly module.
pub type GlobalIndex = usize;
/// Index of a linear memory (imported or defined) inside the WebAssembly module.
pub type MemoryIndex = usize;
/// Index of a signature (imported or defined) inside the WebAssembly module.
pub type SignatureIndex = usize;

/// WebAssembly global.
#[derive(Debug, Clone, Copy)]
pub struct Global {
    /// The type of the value stored in the global.
    pub ty: ir::Type,
    /// A flag indicating whether the value may change at runtime.
    pub mutability: bool,
    /// The source of the initial value.
    pub initializer: GlobalInit,
}

/// Globals are initialized via the four `const` operators or by referring to another import.
#[derive(Debug, Clone, Copy)]
pub enum GlobalInit {
    /// An `i32.const`.
    I32Const(i32),
    /// An `i64.const`.
    I64Const(i64),
    /// An `f32.const`.
    F32Const(u32),
    /// An `f64.const`.
    F64Const(u64),
    /// A `get_global` of another global.
    GlobalRef(GlobalIndex),
    ///< The global is imported from, and thus initialized by, a different module.
    Import(),
}

/// WebAssembly table.
#[derive(Debug, Clone, Copy)]
pub struct Table {
    /// The type of data stored in elements of the table.
    pub ty: TableElementType,
    /// The minimum number of elements in the table.
    pub size: usize,
    /// The maximum number of elements in the table.
    pub maximum: Option<usize>,
}

/// WebAssembly table element. Can be a function or a scalar type.
#[derive(Debug, Clone, Copy)]
pub enum TableElementType {
    Val(ir::Type),
    Func(),
}

/// WebAssembly linear memory.
#[derive(Debug, Clone, Copy)]
pub struct Memory {
    /// The minimum number of pages in the memory.
    pub pages_count: usize,
    /// The maximum number of pages in the memory.
    pub maximum: Option<usize>,
    /// Whether the memory may be shared between multiple threads.
    pub shared: bool,
}

/// Helper function translating wasmparser types to Cranelift types when possible.
pub fn type_to_type(ty: wasmparser::Type) -> Result<ir::Type, ()> {
    match ty {
        wasmparser::Type::I32 => Ok(ir::types::I32),
        wasmparser::Type::I64 => Ok(ir::types::I64),
        wasmparser::Type::F32 => Ok(ir::types::F32),
        wasmparser::Type::F64 => Ok(ir::types::F64),
        _ => Err(()),
    }
}

/// Turns a `wasmparser` `f32` into a `Cranelift` one.
pub fn f32_translation(x: wasmparser::Ieee32) -> ir::immediates::Ieee32 {
    ir::immediates::Ieee32::with_bits(x.bits())
}

/// Turns a `wasmparser` `f64` into a `Cranelift` one.
pub fn f64_translation(x: wasmparser::Ieee64) -> ir::immediates::Ieee64 {
    ir::immediates::Ieee64::with_bits(x.bits())
}

/// Translate a `wasmparser` type into its `Cranelift` equivalent, when possible
pub fn num_return_values(ty: wasmparser::Type) -> usize {
    match ty {
        wasmparser::Type::EmptyBlockType => 0,
        wasmparser::Type::I32
        | wasmparser::Type::F32
        | wasmparser::Type::I64
        | wasmparser::Type::F64 => 1,
        _ => panic!("unsupported return value type"),
    }
}
<|endoftext|>


<commit_before>// This file is part of the uutils coreutils package.
//
// (c) Jian Zeng <anonymousknight96@gmail.com>
//
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.
//

use crate::common::util::*;

#[test]
fn test_encode() {
    let input = "Hello, World!";
    new_ucmd!()
        .pipe_in(input)
        .succeeds()
        .stdout_only("JBSWY3DPFQQFO33SNRSCC===\n"); // spell-checker:disable-line

    // Using '-' as our file
    new_ucmd!()
        .arg("-")
        .pipe_in(input)
        .succeeds()
        .stdout_only("JBSWY3DPFQQFO33SNRSCC===\n"); // spell-checker:disable-line
}

#[test]
fn test_base32_encode_file() {
    new_ucmd!()
        .arg("input-simple.txt")
        .succeeds()
        .stdout_only("JBSWY3DPFQQFO33SNRSCCCQ=\n"); // spell-checker:disable-line
}

#[test]
fn test_decode() {
    for decode_param in &["-d", "--decode"] {
        let input = "JBSWY3DPFQQFO33SNRSCC===\n"; // spell-checker:disable-line
        new_ucmd!()
            .arg(decode_param)
            .pipe_in(input)
            .succeeds()
            .stdout_only("Hello, World!");
    }
}

#[test]
fn test_garbage() {
    let input = "aGVsbG8sIHdvcmxkIQ==\0"; // spell-checker:disable-line
    new_ucmd!()
        .arg("-d")
        .pipe_in(input)
        .fails()
        .stderr_only("base32: error: invalid input\n");
}

#[test]
fn test_ignore_garbage() {
    for ignore_garbage_param in &["-i", "--ignore-garbage"] {
        let input = "JBSWY\x013DPFQ\x02QFO33SNRSCC===\n"; // spell-checker:disable-line
        new_ucmd!()
            .arg("-d")
            .arg(ignore_garbage_param)
            .pipe_in(input)
            .succeeds()
            .stdout_only("Hello, World!");
    }
}

#[test]
fn test_wrap() {
    for wrap_param in &["-w", "--wrap"] {
        let input = "The quick brown fox jumps over the lazy dog.";
        new_ucmd!()
            .arg(wrap_param)
            .arg("20")
            .pipe_in(input)
            .succeeds()
            .stdout_only(
                "KRUGKIDROVUWG2ZAMJZG\n653OEBTG66BANJ2W24DT\nEBXXMZLSEB2GQZJANRQX\nU6JAMRXWOLQ=\n", // spell-checker:disable-line
            );
    }
}

#[test]
fn test_wrap_no_arg() {
    for wrap_param in &["-w", "--wrap"] {
        let ts = TestScenario::new(util_name!());
        let expected_stderr = &format!(
            "error: The argument '--wrap <wrap>\' requires a value but none was \
                               supplied\n\nUSAGE:\n    {1} {0} [OPTION]... [FILE]\n\nFor more \
                               information try --help",
            ts.util_name,
            ts.bin_path.to_string_lossy()
        );
        ts.ucmd()
            .arg(wrap_param)
            .fails()
            .stderr_only(expected_stderr);
    }
}

#[test]
fn test_wrap_bad_arg() {
    for wrap_param in &["-w", "--wrap"] {
        new_ucmd!()
            .arg(wrap_param)
            .arg("b")
            .fails()
            .stderr_only("base32: invalid wrap size: 'b'\n");
    }
}

#[test]
fn test_base32_extra_operand() {
    // Expect a failure when multiple files are specified.
    new_ucmd!()
        .arg("a.txt")
        .arg("b.txt")
        .fails()
        .stderr_only("base32: extra operand 'b.txt'\nTry 'base32 --help' for more information.");
}

#[test]
fn test_base32_file_not_found() {
    new_ucmd!()
        .arg("a.txt")
        .fails()
        .stderr_only("base32: a.txt: No such file or directory");
}
<commit_msg>tests/base32: update test<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Jian Zeng <anonymousknight96@gmail.com>
//
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.
//

use crate::common::util::*;

#[test]
fn test_encode() {
    let input = "Hello, World!";
    new_ucmd!()
        .pipe_in(input)
        .succeeds()
        .stdout_only("JBSWY3DPFQQFO33SNRSCC===\n"); // spell-checker:disable-line

    // Using '-' as our file
    new_ucmd!()
        .arg("-")
        .pipe_in(input)
        .succeeds()
        .stdout_only("JBSWY3DPFQQFO33SNRSCC===\n"); // spell-checker:disable-line
}

#[test]
fn test_base32_encode_file() {
    new_ucmd!()
        .arg("input-simple.txt")
        .succeeds()
        .stdout_only("JBSWY3DPFQQFO33SNRSCCCQ=\n"); // spell-checker:disable-line
}

#[test]
fn test_decode() {
    for decode_param in &["-d", "--decode"] {
        let input = "JBSWY3DPFQQFO33SNRSCC===\n"; // spell-checker:disable-line
        new_ucmd!()
            .arg(decode_param)
            .pipe_in(input)
            .succeeds()
            .stdout_only("Hello, World!");
    }
}

#[test]
fn test_garbage() {
    let input = "aGVsbG8sIHdvcmxkIQ==\0"; // spell-checker:disable-line
    new_ucmd!()
        .arg("-d")
        .pipe_in(input)
        .fails()
        .stderr_only("base32: error: invalid input\n");
}

#[test]
fn test_ignore_garbage() {
    for ignore_garbage_param in &["-i", "--ignore-garbage"] {
        let input = "JBSWY\x013DPFQ\x02QFO33SNRSCC===\n"; // spell-checker:disable-line
        new_ucmd!()
            .arg("-d")
            .arg(ignore_garbage_param)
            .pipe_in(input)
            .succeeds()
            .stdout_only("Hello, World!");
    }
}

#[test]
fn test_wrap() {
    for wrap_param in &["-w", "--wrap"] {
        let input = "The quick brown fox jumps over the lazy dog.";
        new_ucmd!()
            .arg(wrap_param)
            .arg("20")
            .pipe_in(input)
            .succeeds()
            .stdout_only(
                "KRUGKIDROVUWG2ZAMJZG\n653OEBTG66BANJ2W24DT\nEBXXMZLSEB2GQZJANRQX\nU6JAMRXWOLQ=\n", // spell-checker:disable-line
            );
    }
}

#[test]
fn test_wrap_no_arg() {
    for wrap_param in &["-w", "--wrap"] {
        let ts = TestScenario::new(util_name!());
        let expected_stderr = &format!(
            "error: The argument '--wrap <wrap>\' requires a value but none was \
                               supplied\n\nUSAGE:\n    {1} {0} [OPTION]... [FILE]\n\nFor more \
                               information try --help",
            ts.util_name,
            ts.bin_path.to_string_lossy()
        );
        ts.ucmd()
            .arg(wrap_param)
            .fails()
            .stderr_only(expected_stderr);
    }
}

#[test]
fn test_wrap_bad_arg() {
    for wrap_param in &["-w", "--wrap"] {
        new_ucmd!()
            .arg(wrap_param)
            .arg("b")
            .fails()
            .stderr_only("base32: invalid wrap size: 'b'\n");
    }
}

#[test]
fn test_base32_extra_operand() {
    let ts = TestScenario::new(util_name!());

    // Expect a failure when multiple files are specified.
    ts.ucmd()
        .arg("a.txt")
        .arg("b.txt")
        .fails()
        .stderr_only(format!(
            "{0}: extra operand 'b.txt'\nTry '{1} {0} --help' for more information.",
            ts.util_name,
            ts.bin_path.to_string_lossy()
        ));
}

#[test]
fn test_base32_file_not_found() {
    new_ucmd!()
        .arg("a.txt")
        .fails()
        .stderr_only("base32: a.txt: No such file or directory");
}
<|endoftext|>


<commit_before>// Kevin Cantu
// Boyer-Moore string searching

use std;

// Function: findn
//
// Boyer-Moore string search, which returns
// up to `nn` byte positions of matched substrings
fn findn (needle: str, haystack: str, nn: uint) -> [uint] {

   let results = [];

   let nlen = str::len(needle);
   let hlen = str::len(haystack);

   // empty haystack
   if hlen == 0u {
      ret results;
   }

   // empty needle
   if nlen == 0u {
      vec::push(results, 0u);
      ret results;
   }

   // needle too large
   if hlen < nlen {
      ret results;
   }

   // generate the tables
   let ct = char_table(needle);
   let pt = prefix_table(needle);

   // simplify the table referencing
   let getShift = fn@(pos: uint) -> uint {
      let charShift, prefShift; // also: ct, pt, needle

      assert needle != "";
      assert pos >= 0u;
      assert pos < nlen;

      alt ct.find(needle[pos] as uint) {
         option::none    { charShift = nlen;}
         option::some(x) { charShift = x;}
      }

      let offset = nlen - pos;

      assert offset >= 0u;
      assert offset < nlen;

      alt pt.find(offset) {
         option::none { fail "something is out of range" }
         option::some(x) { prefShift = x;}
      }

      //std::io::println(#fmt("<charShift: %u, prefShift: %u>", charShift, prefShift));
      ret greaterOf(charShift, prefShift);
   };

   // step up through the haystack
   let outerii = 0u;
   while outerii < hlen - nlen + 1u {

      // step back through needle
      let windowii = nlen;
      while 0u < windowii
            && (outerii + (windowii - 1u)) < hlen  // don't exceed haystack
      {
         windowii -= 1u;

         //std::io::println(#fmt("%02x.@%u =? %02x.@%u",
         //                 needle[windowii] as uint,
         //                 windowii,
         //                 haystack[outerii+windowii] as uint,
         //                 outerii + windowii));

         // if still matching
         if needle[windowii] == haystack[outerii+windowii] {

            // if full match
            if windowii == 0u {
               //std::io::println(#fmt("[pushing %u]", outerii));
               vec::push(results, outerii);

               if vec::len(results) >= nn {
                  ret results;
               } else {
                  outerii += nlen;
               }
            }
         } else {
            outerii +=
               if windowii == nlen - 1u {
                  // not matching yet
                  1u
               } else {
                  // was partial match
                  getShift(nlen - windowii)
               };

            break;
         }
      }
   }

   ret results;
}

fn char_table (needle: str) -> std::map::map<uint, uint> {
   let mm: std::map::map<uint, uint> = std::map::new_uint_hash();
   let len = str::len(needle);

   let jj = len - 1u; // drop the last byte

   assert jj >= 0u;
   assert jj < str::len(needle);

   // from last-1 to first
   while jj > 0u {
      jj -= 1u;
      if ! mm.contains_key(needle[jj] as uint) {
         // store reverse indexes
         mm.insert(needle[jj] as uint, len - 1u - jj);
      }
   }

   ret mm;
}

#[test]
fn test_char_table () {
   let ct = char_table("ANPANMAN");
   assert 1u == ct.get('A' as uint);
   assert 2u == ct.get('M' as uint);
   assert 3u == ct.get('N' as uint);
   assert 5u == ct.get('P' as uint);
   assert option::none == ct.find('z' as uint);
}

// FIXME: generalize this beyond strings
fn prefix_table (needle: str) -> std::map::map<uint, uint> unsafe {
   let mm: std::map::map<uint, uint> = std::map::new_uint_hash();

   // WAIT, HOW IS THIS ALLOWED TO MUTATE mm?
   let fill = fn@(kk: uint, vv: uint) {
      if ! mm.contains_key(kk) {
         mm.insert(kk, vv);
         //std::io::println(#fmt("%u => %u", kk, vv));
      }
   };

   let lim   = str::len(needle);
   assert 0u < lim;

   // step to larger suffixes
   let sii = 0u;
   while sii < lim {

      // tail of the needle we seek
      let suffix      = str::unsafe::slice_bytes(needle, lim - sii,      lim);
      let suffix_plus = str::unsafe::slice_bytes(needle, lim - sii - 1u, lim);
      let slen = str::len(suffix);

      // step to smaller prefixes
      let pii = lim - 1u;
      while pii > 0u {

         // a prefix of the needle that might be matched by
         // a partial match of a suffix
         // (which we might want to jump to)
         let prefix = str::unsafe::slice_bytes(needle, 0u, pii);

         //let msg  = "<"+suffix+"("+#fmt("%u",sii)+")";
         //let msg2 = prefix+"("+#fmt("%u",pii)+")>";
         //let msg  = "<suf("+#fmt("%u",sii)+")";
         //let msg2 = "pref("+#fmt("%u",pii)+")>";
         //std::io::println(msg + " × " + msg2);

         // suffix might be fully matched
         let is_suffix_matched =
            str::ends_with(prefix, suffix)
            && !str::ends_with(prefix, suffix_plus)
            &&  slen < str::len(prefix);

         // prefix is bigger than suffix, only tail can match
         let is_suffix_partially_matched =
            str::len(prefix) <= str::len(suffix)
            && str::ends_with(suffix, prefix);

         if is_suffix_matched || is_suffix_partially_matched {
            fill(sii, lim-pii);
         }

         pii -= 1u;
      }

      // no matching prefix
      fill(sii, lim-pii);

      sii += 1u;
   }

   ret mm;
}

#[test]
fn test_prefix_table_ascii() {
   let pt = prefix_table("ANPANMAN");
                            //      ... 8

   assert 1u == pt.get(0u); //        (n)
   assert 8u == pt.get(1u); //       (a)n
   assert 3u == pt.get(2u); //      (m)an
   assert 6u == pt.get(3u); //     (n)man
   assert 6u == pt.get(4u); //    (a)nman
   assert 6u == pt.get(5u); //   (p)anman
   assert 6u == pt.get(6u); //  (n)panman
   assert 6u == pt.get(7u); // (a)npanman
   //assert 0u == pt.get(8u); // fail
}

#[test]
fn test_prefix_table_utf8() {
   let pt = prefix_table("ประเ");

   assert  1u == pt.get(0u);
   assert 12u == pt.get(3u);
   assert 12u == pt.get(6u);
   assert 12u == pt.get(9u);
}

////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////

// prefixes, smallest first
fn prefixes(ss: str) -> [str] unsafe {
   let vv = [];

   vec::push(vv, "");
   str::chars_iteri(ss) {|ii, _bb|
      vec::push(vv, str::slice(ss, 0u, ii+1u));
   }

   ret vv;
}

#[test]
fn test_prefs() {
   assert ["", "a", "ab", "abc", "abcd"] == prefixes("abcd");
   assert [""] == prefixes("");
}

// suffixes, largest first
fn suffixes(ss: str) -> [str] unsafe {
   let vv = [];
   let lim = str::len(ss);

   str::chars_iteri(ss) {|ii, _bb|
      vec::push(vv, str::slice(ss, ii, lim));
   }
   vec::push(vv, "");

   ret vv;
}

#[test]
fn test_sufs() {
   assert ["abcd", "bcd", "cd", "d", ""] == suffixes("abcd");
   assert [""] == suffixes("");
}

fn greaterOf(a: uint, b: uint) -> uint {
   if a > b { ret a; } else { ret b; }
}

#[test]
fn test_greaterOf() {
   assert greaterOf(15u, 17u) == 17u;
   assert greaterOf(17u, 15u) == 17u;
}

fn find_(needle: str, haystack: str) -> option<uint> {
   let found = findn(needle, haystack, 1u);

   alt vec::len(found) {
      0u { option::none }
      xx { option::some(found[0u]) }
   }
}

#[test]
fn test_findn() {
   assert [] == findn("banana", "apple pie", 1u);
   assert (findn("abc", "abcxxxxxx", 1u) == [0u]);
   assert (findn("abc", "xxxabcxxx", 1u) == [3u]);
   assert (findn("abc", "xxxxxxabc", 1u) == [6u]);
   assert (findn("abc", "xxxabcabc", 1u) == [3u]);
   assert (findn("abc", "xxxabcabc", 5u) == [3u, 6u]);
   assert (findn("abc", "xxxabcxabc", 5u) == [3u, 7u]);
   assert (findn("abc", "xxxabcxxabc", 5u) == [3u, 8u]);
}

#[test]
fn test_find_ascii() {
  assert (find_("banana", "apple pie") == option::none);
  assert (find_("", "") == option::none);
  assert (find_("abc", "abcxxxxxx") == option::some(0u));
  assert (find_("abc", "xxxabcxxx") == option::some(3u));
  assert (find_("abc", "xxxxxxabc") == option::some(6u));
}

#[test]
fn test_find_utf8() {
  let data = "ประเทศไทย中华Việt Nam";
  assert (find_("ไท华", data) == option::none);
  assert (find_("", data)     == option::some( 0u));
  assert (find_("ประเ", data) == option::some( 0u));
  assert (find_("ะเ", data)   == option::some( 6u));
  assert (find_("ระ", data) == option::some(3u));
  assert (find_("ศไทย中华", data) == option::some(15u));
  assert (find_("ไทย中华", data) == option::some(18u));
  assert (find_("ย中华", data) == option::some(24u));
  assert (find_("中华", data) == option::some(27u));
}

<commit_msg>stopped using unsafe slice<commit_after>// Kevin Cantu
// Boyer-Moore string searching

use std;

// Function: findn
//
// Boyer-Moore string search, which returns
// up to `nn` byte positions of matched substrings
fn findn (needle: str, haystack: str, nn: uint) -> [uint] {

   let results = [];

   let nlen = str::len(needle);
   let hlen = str::len(haystack);

   // empty haystack
   if hlen == 0u {
      ret results;
   }

   // empty needle
   if nlen == 0u {
      vec::push(results, 0u);
      ret results;
   }

   // needle too large
   if hlen < nlen {
      ret results;
   }

   // generate the tables
   let ct = char_table(needle);
   let pt = prefix_table(needle);

   // simplify the table referencing
   let getShift = fn@(pos: uint) -> uint {
      let charShift, prefShift; // also: ct, pt, needle

      assert needle != "";
      assert pos >= 0u;
      assert pos < nlen;

      alt ct.find(needle[pos] as uint) {
         option::none    { charShift = nlen;}
         option::some(x) { charShift = x;}
      }

      let offset = nlen - pos;

      assert offset >= 0u;
      assert offset < nlen;

      alt pt.find(offset) {
         option::none { fail "something is out of range" }
         option::some(x) { prefShift = x;}
      }

      //std::io::println(#fmt("<charShift: %u, prefShift: %u>", charShift, prefShift));
      ret greaterOf(charShift, prefShift);
   };

   // step up through the haystack
   let outerii = 0u;
   while outerii < hlen - nlen + 1u {

      // step back through needle
      let windowii = nlen;
      while 0u < windowii
            && (outerii + (windowii - 1u)) < hlen  // don't exceed haystack
      {
         windowii -= 1u;

         //std::io::println(#fmt("%02x.@%u =? %02x.@%u",
         //                 needle[windowii] as uint,
         //                 windowii,
         //                 haystack[outerii+windowii] as uint,
         //                 outerii + windowii));

         // if still matching
         if needle[windowii] == haystack[outerii+windowii] {

            // if full match
            if windowii == 0u {
               //std::io::println(#fmt("[pushing %u]", outerii));
               vec::push(results, outerii);

               if vec::len(results) >= nn {
                  ret results;
               } else {
                  outerii += nlen;
               }
            }
         } else {
            outerii +=
               if windowii == nlen - 1u {
                  // not matching yet
                  1u
               } else {
                  // was partial match
                  getShift(nlen - windowii)
               };

            break;
         }
      }
   }

   ret results;
}

fn char_table (needle: str) -> std::map::map<uint, uint> {
   let mm: std::map::map<uint, uint> = std::map::new_uint_hash();
   let len = str::len(needle);

   let jj = len - 1u; // drop the last byte

   assert jj >= 0u;
   assert jj < str::len(needle);

   // from last-1 to first
   while jj > 0u {
      jj -= 1u;
      if ! mm.contains_key(needle[jj] as uint) {
         // store reverse indexes
         mm.insert(needle[jj] as uint, len - 1u - jj);
      }
   }

   ret mm;
}

#[test]
fn test_char_table () {
   let ct = char_table("ANPANMAN");
   assert 1u == ct.get('A' as uint);
   assert 2u == ct.get('M' as uint);
   assert 3u == ct.get('N' as uint);
   assert 5u == ct.get('P' as uint);
   assert option::none == ct.find('z' as uint);
}

fn prefix_table (needle: str) -> std::map::map<uint, uint> {
   let needle_ = str::bytes(needle);
   let mm: std::map::map<uint, uint> = std::map::new_uint_hash();

   // WAIT, HOW IS THIS ALLOWED TO MUTATE mm?
   let fill = fn@(kk: uint, vv: uint) {
      if ! mm.contains_key(kk) {
         mm.insert(kk, vv);
         //std::io::println(#fmt("%u => %u", kk, vv));
      }
   };

   let lim   = vec::len(needle_);
   assert 0u < lim;

   // step to larger suffixes
   let sii = 0u;
   while sii < lim {

      // tail of the needle we seek
      let suffix      = vec::slice(needle_, lim - sii,      lim);
      let suffix_plus = vec::slice(needle_, lim - sii - 1u, lim);
      let slen = vec::len(suffix);

      // step to smaller prefixes
      let pii = lim - 1u;
      while pii > 0u {

         // a prefix of the needle that might be matched by
         // a partial match of a suffix
         // (which we might want to jump to)
         let prefix = vec::slice(needle_, 0u, pii);
         let plen = vec::len(prefix);

         //let msg  = "<"+suffix+"("+#fmt("%u",sii)+")";
         //let msg2 = prefix+"("+#fmt("%u",pii)+")>";
         //let msg  = "<suf("+#fmt("%u",sii)+")";
         //let msg2 = "pref("+#fmt("%u",pii)+")>";
         //std::io::println(msg + " × " + msg2);

         // suffix might be fully matched
         let is_suffix_matched =
            vec::ends_with(prefix, suffix)
            && !vec::ends_with(prefix, suffix_plus)
            &&  slen < plen;

         // prefix is bigger than suffix, only tail can match
         let is_suffix_partially_matched =
            plen <= slen
            && vec::ends_with(suffix, prefix);

         if is_suffix_matched || is_suffix_partially_matched {
            fill(sii, lim-pii);
         }

         pii -= 1u;
      }

      // no matching prefix
      fill(sii, lim-pii);

      sii += 1u;
   }

   ret mm;
}

#[test]
fn test_prefix_table_ascii() {
   let pt = prefix_table("ANPANMAN");
                            //      ... 8

   assert 1u == pt.get(0u); //        (n)
   assert 8u == pt.get(1u); //       (a)n
   assert 3u == pt.get(2u); //      (m)an
   assert 6u == pt.get(3u); //     (n)man
   assert 6u == pt.get(4u); //    (a)nman
   assert 6u == pt.get(5u); //   (p)anman
   assert 6u == pt.get(6u); //  (n)panman
   assert 6u == pt.get(7u); // (a)npanman
   //assert 0u == pt.get(8u); // fail
}

#[test]
fn test_prefix_table_utf8() {
   let pt = prefix_table("ประเ");

   assert  1u == pt.get(0u);
   assert 12u == pt.get(3u);
   assert 12u == pt.get(6u);
   assert 12u == pt.get(9u);
}

fn greaterOf(a: uint, b: uint) -> uint {
   if a > b { ret a; } else { ret b; }
}

#[test]
fn test_greaterOf() {
   assert greaterOf(15u, 17u) == 17u;
   assert greaterOf(17u, 15u) == 17u;
}

fn find_(needle: str, haystack: str) -> option<uint> {
   let found = findn(needle, haystack, 1u);

   alt vec::len(found) {
      0u { option::none }
      xx { option::some(found[0u]) }
   }
}

#[test]
fn test_findn() {
   assert [] == findn("banana", "apple pie", 1u);
   assert (findn("abc", "abcxxxxxx", 1u) == [0u]);
   assert (findn("abc", "xxxabcxxx", 1u) == [3u]);
   assert (findn("abc", "xxxxxxabc", 1u) == [6u]);
   assert (findn("abc", "xxxabcabc", 1u) == [3u]);
   assert (findn("abc", "xxxabcabc", 5u) == [3u, 6u]);
   assert (findn("abc", "xxxabcxabc", 5u) == [3u, 7u]);
   assert (findn("abc", "xxxabcxxabc", 5u) == [3u, 8u]);
}

#[test]
fn test_find_ascii() {
  assert (find_("banana", "apple pie") == option::none);
  assert (find_("", "") == option::none);
  assert (find_("abc", "abcxxxxxx") == option::some(0u));
  assert (find_("abc", "xxxabcxxx") == option::some(3u));
  assert (find_("abc", "xxxxxxabc") == option::some(6u));
}

#[test]
fn test_find_utf8() {
  let data = "ประเทศไทย中华Việt Nam";
  assert (find_("ไท华", data) == option::none);
  assert (find_("", data)     == option::some( 0u));
  assert (find_("ประเ", data) == option::some( 0u));
  assert (find_("ะเ", data)   == option::some( 6u));
  assert (find_("ระ", data) == option::some(3u));
  assert (find_("ศไทย中华", data) == option::some(15u));
  assert (find_("ไทย中华", data) == option::some(18u));
  assert (find_("ย中华", data) == option::some(24u));
  assert (find_("中华", data) == option::some(27u));
}

<|endoftext|>


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

pub struct Dict<T> {
    root : *mut T,
}

pub struct DictNode<K, V> {
    pub key : K,
    left : *mut V,
    right : *mut V,
}

impl<K,V> DictNode<K,V> {
    pub fn new(key : K) -> DictNode<K, V> {
        DictNode { key : key, left : null(), right : null() }
    }
}

pub trait DictItem<K> {
    fn node<'a>(&'a mut self) -> &'a mut DictNode<K, Self>;
    // Figure out a way to implement a node->item function, then we can remove
    // "T" from the nodes, do links between nodes instead of items, and use a
    // single copy of the linking code.
}

fn null<T>() -> *mut T { RawPtr::null() }
fn node<'a, K, T : DictItem<K>>(p : *mut T) -> &'a mut DictNode<K, T> {
    unsafe { (*p).node() }
}

impl<K : Ord + Copy, V : DictItem<K>> Dict<V> {
    pub fn empty() -> Dict<V> {
        Dict { root : null() }
    }

    // Return the greatest item with key <= key
    #[inline(never)]
    pub fn find<'a>(&mut self, key : K) -> Option<&'a mut V> {
        let mut item = self.root;
        let mut max = null();
        while item.is_not_null() {
            let ikey : K = node(item).key;
            if ikey <= key {
                if max.is_null() {
                    max = item;
                } else {
                    let maxKey : K = node(max).key;
                    if maxKey < ikey {
                        max = item;
                    }
                }
            }
            item = node(item).right;
        }
        if max.is_null() { None } else { unsafe { Some(&mut *max) } }
    }

    #[inline(never)]
    pub fn insert<'a>(&mut self, item : *mut V) -> &'a mut V {
        node(item).left = null();
        node(item).right = self.root;
        self.root = item;
        unsafe { &mut *item }
    }
}
<commit_msg>Iterator for dictionaries<commit_after>use core::prelude::*;

pub struct Dict<T> {
    root : *mut T,
}

pub struct DictNode<K, V> {
    pub key : K,
    left : *mut V,
    right : *mut V,
}

impl<K,V> DictNode<K,V> {
    pub fn new(key : K) -> DictNode<K, V> {
        DictNode { key : key, left : null(), right : null() }
    }
}

pub trait DictItem<K> {
    fn node<'a>(&'a mut self) -> &'a mut DictNode<K, Self>;
    // Figure out a way to implement a node->item function, then we can remove
    // "T" from the nodes, do links between nodes instead of items, and use a
    // single copy of the linking code.
}

fn null<T>() -> *mut T { RawPtr::null() }
fn node<'a, K, T : DictItem<K>>(p : *mut T) -> &'a mut DictNode<K, T> {
    unsafe { (*p).node() }
}

impl<K : Ord + Copy, V : DictItem<K>> Dict<V> {
    pub fn empty() -> Dict<V> {
        Dict { root : null() }
    }

    // Return the greatest item with key <= key
    #[inline(never)]
    pub fn find<'a>(&mut self, key : K) -> Option<&'a mut V> {
        let mut item = self.root;
        let mut max = null();
        while item.is_not_null() {
            let ikey : K = node(item).key;
            if ikey <= key {
                if max.is_null() {
                    max = item;
                } else {
                    let maxKey : K = node(max).key;
                    if maxKey < ikey {
                        max = item;
                    }
                }
            }
            item = node(item).right;
        }
        if max.is_null() { None } else { unsafe { Some(&mut *max) } }
    }

    #[inline(never)]
    pub fn insert<'a>(&mut self, item : *mut V) -> &'a mut V {
        node(item).left = null();
        node(item).right = self.root;
        self.root = item;
        unsafe { &mut *item }
    }

    pub fn iter<'a>(&'a self) -> DictIter<'a, V> {
        DictIter { p: self.root }
    }
}

struct DictIter<'a, T> {
    p : *mut T,
}

impl<'a, K : Copy, V : DictItem<K>> Iterator<(K, &'a mut V)> for DictIter<'a, V> {
    fn next(&mut self) -> Option<(K, &'a mut V)> {
        if self.p.is_not_null() {
            let res = self.p;
            self.p = node(res).right;
            unsafe { Some((node(res).key, &mut *res)) }
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Location in memory that contains data.
//!
//! All buffers are guaranteed to be accessible from the GPU.
//!
//! The `Buffer` struct has two template parameters:
//!
//! - `T` is the type of data that is contained in the buffer. It can be a struct
//!   (eg. `Foo`), an array (eg. `[u16; 1024]` or `[Foo; 1024]`), or an unsized array (eg. `[u16]`).
//!
//! - `M` is the object that provides memory and handles synchronization for the buffer.
//!   If the `CpuAccessible` and/or `CpuWriteAccessible` traits are implemented on `M`, then you
//!   can access the buffer's content from your program.
//!
//!
//! # Strong typing
//!
//! All buffers take a template parameter that indicates their content.
//!
//! # Memory
//!
//! Creating a buffer requires passing an object that will be used by this library to provide
//! memory to the buffer.
//!
//! All accesses to the memory are done through the `Buffer` object.
//!
//! TODO: proof read this section
//!
use std::marker::PhantomData;
use std::mem;
use std::sync::Arc;

pub use self::sys::Usage;
pub use self::traits::Buffer;
pub use self::traits::TypedBuffer;
pub use self::view::BufferView;

pub mod cpu_access;
pub mod immutable;
pub mod sys;
pub mod traits;
pub mod view;

/// A subpart of a buffer.
///
/// This object doesn't correspond to any Vulkan object. It exists for the programmer's
/// convenience.
///
/// # Example
///
/// TODO: example
///
#[derive(Clone)]
pub struct BufferSlice<'a, T: ?Sized, B: 'a> {
    marker: PhantomData<T>,
    resource: &'a Arc<B>,
    offset: usize,
    size: usize,
}

impl<'a, T: ?Sized, B: 'a> BufferSlice<'a, T, B> {
    /// Returns the buffer that this slice belongs to.
    pub fn buffer(&self) -> &'a Arc<B> {
        &self.resource
    }

    /// Returns the offset of that slice within the buffer.
    #[inline]
    pub fn offset(&self) -> usize {
        self.offset
    }

    /// Returns the size of that slice in bytes.
    #[inline]
    pub fn size(&self) -> usize {
        self.size
    }
}

impl<'a, T, B: 'a> BufferSlice<'a, [T], B> {
    /// Returns the number of elements in this slice.
    #[inline]
    pub fn len(&self) -> usize {
        self.size() / mem::size_of::<T>()
    }
}

impl<'a, T: ?Sized, B: 'a> From<&'a Arc<B>> for BufferSlice<'a, T, B>
    where B: TypedBuffer<Content = T>, T: 'static
{
    #[inline]
    fn from(r: &'a Arc<B>) -> BufferSlice<'a, T, B> {
        BufferSlice {
            marker: PhantomData,
            resource: r,
            offset: 0,
            size: r.size(),
        }
    }
}

impl<'a, T, B: 'a> From<BufferSlice<'a, T, B>> for BufferSlice<'a, [T], B>
    where T: 'static
{
    #[inline]
    fn from(r: BufferSlice<'a, T, B>) -> BufferSlice<'a, [T], B> {
        BufferSlice {
            marker: PhantomData,
            resource: r.resource,
            offset: r.offset,
            size: r.size,
        }
    }
}

#[cfg(test)]
mod tests {
    // TODO: restore these tests
    /*use std::mem;

    use buffer::Usage;
    use buffer::Buffer;
    use buffer::BufferView;
    use buffer::BufferViewCreationError;
    use memory::DeviceLocal;

    #[test]
    fn create() {
        let (device, queue) = gfx_dev_and_queue!();

        let _ = Buffer::<[i8; 16], _>::new(&device, &Usage::all(), DeviceLocal, &queue).unwrap();
    }

    #[test]
    fn array_len() {
        let (device, queue) = gfx_dev_and_queue!();

        let b = Buffer::<[i16], _>::array(&device, 12, &Usage::all(),
                                          DeviceLocal, &queue).unwrap();
        assert_eq!(b.len(), 12);
        assert_eq!(b.size(), 12 * mem::size_of::<i16>());
    }*/
}
<commit_msg>Rework docs of buffer module<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Location in memory that contains data.
//!
//! All buffers are guaranteed to be accessible from the GPU.
//!
//! # High-level wrappers
//!
//! The low level implementation of a buffer is `UnsafeBuffer`. However, the vulkano library
//! provides high-level wrappers around that type that are specialized depending on the way you
//! are going to use it:
//!
//! - `CpuAccessBuffer` designates a buffer located in RAM and whose content can be written by
//!   your application.
//! - `ImmutableBuffer` designates a buffer in video memory and whose content can only be
//!   written once.
//!
//! If are a beginner, you are strongly encouraged to use one of these wrappers.
//!
//! # Buffers usage
//!
//! Buffers have the following usages:
//!
//! - Can contain arbitrary data that can be copied from/to other buffers and images.
//! - Can be read and modified from a shader.
//! - Can be used as a source of vertices and indices.
//! - Can be used as a source of list of models for draw indirect commands.
//!
//! The correct `Usage` flags have to be passed when you create a buffer. Trying to use a buffer
//! in a way that wasn't specified when you created it will result in an error.
//!
//! Accessing a buffer from a shader can be done in the following ways:
//!
//! - As a uniform buffer. Uniform buffers are read-only.
//! - As a storage buffer. Storage buffers can be read and written.
//! - As a uniform texel buffer. Contrary to a uniform buffer, the data is interpreted by the
//!   GPU and can be for example normalized.
//! - As a storage texel buffer. Additionnally, some data formats can be modified with atomic
//!   operations.
//!
//! Using uniform/storage texel buffers requires creating a *buffer view*. See the `view` module
//! for how to create a buffer view.
//!
//! # Data uploads
//!
//! One of the major usages of buffers is to upload data to other buffers and to images. When you
//! create a buffer or an image in non-host-visible memory, one of the only way to upload data to
//! it is write the data in a temporary buffer and ask the device to copy from the temporary buffer
//! to the real buffer.
//!
//! TODO: add example of this
//!
use std::marker::PhantomData;
use std::mem;
use std::sync::Arc;

pub use self::sys::Usage;
pub use self::traits::Buffer;
pub use self::traits::TypedBuffer;
pub use self::view::BufferView;

pub mod cpu_access;
pub mod immutable;
pub mod sys;
pub mod traits;
pub mod view;

/// A subpart of a buffer.
///
/// This object doesn't correspond to any Vulkan object. It exists for the programmer's
/// convenience.
///
/// # Example
///
/// TODO: example
///
#[derive(Clone)]
pub struct BufferSlice<'a, T: ?Sized, B: 'a> {
    marker: PhantomData<T>,
    resource: &'a Arc<B>,
    offset: usize,
    size: usize,
}

impl<'a, T: ?Sized, B: 'a> BufferSlice<'a, T, B> {
    /// Returns the buffer that this slice belongs to.
    pub fn buffer(&self) -> &'a Arc<B> {
        &self.resource
    }

    /// Returns the offset of that slice within the buffer.
    #[inline]
    pub fn offset(&self) -> usize {
        self.offset
    }

    /// Returns the size of that slice in bytes.
    #[inline]
    pub fn size(&self) -> usize {
        self.size
    }
}

impl<'a, T, B: 'a> BufferSlice<'a, [T], B> {
    /// Returns the number of elements in this slice.
    #[inline]
    pub fn len(&self) -> usize {
        self.size() / mem::size_of::<T>()
    }
}

impl<'a, T: ?Sized, B: 'a> From<&'a Arc<B>> for BufferSlice<'a, T, B>
    where B: TypedBuffer<Content = T>, T: 'static
{
    #[inline]
    fn from(r: &'a Arc<B>) -> BufferSlice<'a, T, B> {
        BufferSlice {
            marker: PhantomData,
            resource: r,
            offset: 0,
            size: r.size(),
        }
    }
}

impl<'a, T, B: 'a> From<BufferSlice<'a, T, B>> for BufferSlice<'a, [T], B>
    where T: 'static
{
    #[inline]
    fn from(r: BufferSlice<'a, T, B>) -> BufferSlice<'a, [T], B> {
        BufferSlice {
            marker: PhantomData,
            resource: r.resource,
            offset: r.offset,
            size: r.size,
        }
    }
}

#[cfg(test)]
mod tests {
    // TODO: restore these tests
    /*use std::mem;

    use buffer::Usage;
    use buffer::Buffer;
    use buffer::BufferView;
    use buffer::BufferViewCreationError;
    use memory::DeviceLocal;

    #[test]
    fn create() {
        let (device, queue) = gfx_dev_and_queue!();

        let _ = Buffer::<[i8; 16], _>::new(&device, &Usage::all(), DeviceLocal, &queue).unwrap();
    }

    #[test]
    fn array_len() {
        let (device, queue) = gfx_dev_and_queue!();

        let b = Buffer::<[i16], _>::array(&device, 12, &Usage::all(),
                                          DeviceLocal, &queue).unwrap();
        assert_eq!(b.len(), 12);
        assert_eq!(b.size(), 12 * mem::size_of::<i16>());
    }*/
}
<|endoftext|>


<commit_before>mod thread_guard;

use std::fmt;
use std::io;
use std::io::prelude::*;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Sender, Receiver, TryRecvError};
use std::thread;
use std::time::{Duration, Instant};
use std::ops::Deref;

use serial::prelude::*;
use serial;
use self::thread_guard::*;
use super::Packet;

pub enum ConnectionEvent {
    Packet(Packet),
    InvalidPacket(Packet),
    ReadError(io::Error),
    WriteError(io::Error),
    Heartbeat
}

impl fmt::Display for ConnectionEvent {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &ConnectionEvent::Packet(ref p) => write!(f, "{}", p),
            &ConnectionEvent::InvalidPacket(ref p) => write!(f, "Invalid! {}", p),
            &ConnectionEvent::ReadError(ref err) => write!(f, "READ ERROR! [{:?}]", err),
            &ConnectionEvent::WriteError(ref err) => write!(f, "WRITE ERROR! [{:?}]", err),
            &ConnectionEvent::Heartbeat => write!(f, "Tick Tock")
        }
    }
}

pub struct Connection {
    pub tty_path: String,
    event_receiver: Receiver<ConnectionEvent>,
    packet_sender: Sender<Packet>,
    kill_thread_signal: Arc<Mutex<bool>>,
    reader_thread_handle: Option<ThreadHandle<()>>,
}

impl Connection {
    pub fn new(tty_path: &str, heartbeat_milliseconds: Option<u64>) -> io::Result<Connection> {
        let (event_sender, event_receiver) = channel::<ConnectionEvent>();
        let (packet_sender, packet_receiver) = channel::<Packet>();

        let kill_signal = Arc::new(Mutex::new(false));

        let reader_thread = build_connection_read_thread(tty_path.to_string(), event_sender, packet_receiver, heartbeat_milliseconds, kill_signal.clone());

        Ok(Connection {
            tty_path: tty_path.to_string(),
            event_receiver: event_receiver,
            packet_sender: packet_sender,
            kill_thread_signal: kill_signal,
            reader_thread_handle: Some(reader_thread)
        })
    }

    pub fn send(&mut self, p: Packet) -> io::Result<()> {
        match self.is_ok() {
            true => {
                self.packet_sender.send(p).unwrap();
                Ok(())
            },
            false => Err(io::Error::new(io::ErrorKind::ConnectionAborted, "worker threads have stopped"))
        }
    }

    pub fn wait(&self) -> io::Result<ConnectionEvent> {
        match self.is_ok() {
            false => Err(io::Error::new(io::ErrorKind::ConnectionAborted, "worker threads have stopped")),
            true => {
                Ok(self.event_receiver.recv().unwrap())
            }
        }
    }

    pub fn get_events(&self) -> io::Result<Vec<ConnectionEvent>> {
        match self.is_ok() {
            false => Err(io::Error::new(io::ErrorKind::ConnectionAborted, "worker threads have stopped")),
            true => {
                let mut data: Vec<ConnectionEvent> = vec!();

                loop {
                    match self.event_receiver.try_recv() {
                        Ok(evt) => { data.push(evt) },
                        Err(TryRecvError::Empty) => { break; },
                        Err(TryRecvError::Disconnected) => { panic!("channels should not disconnect") }
                    }
                }

                Ok(data)
            }
        }
    }

    pub fn is_ok(&self) -> bool {
        let mut ret = true;

        match &self.reader_thread_handle {
            &Some(ref h) => {
                ret = ret && match h.status.lock().unwrap().deref() {
                    &ThreadStatus::Ok => true,
                    _ => false
                }
            },
            _ => {}
        }
        ret
    }
}

impl Drop for Connection {
    fn drop(&mut self) {

        {
            *self.kill_thread_signal.lock().unwrap() = true;
        }

        match self.reader_thread_handle.take() {
            Some(th) => {
                th.handle.join().unwrap();
            },
            None => {}
        }
    }
}

fn build_connection_read_thread(tty_path: String, event_sender: Sender<ConnectionEvent>, packet_receiver: Receiver<Packet>, heartbeat: Option<u64>, kill_signal: Arc<Mutex<bool>>) -> ThreadHandle<()> {
    guard_thread("reader_thread", move || {
        let mut serial = match serial::open(&tty_path) {
            Err(e) => {panic!(format!("Unable to create serial port: {}", e)) },
            Ok(s) => s
        };

        match serial.set_timeout(Duration::from_millis(2000)) {
            Err(e) => { panic!(format!("Unable to set serial timeout: {}", e)) },
            Ok(_) => {}
        };

        let mut packet_buffer: Vec<u8> = Vec::new();
        let mut read_buffer: Vec<u8> = Vec::new();
        let mut last_read = Instant::now();
        let mut last_heartbeat = Instant::now();

        while !*kill_signal.lock().unwrap() {

            if packet_buffer.len() > 0 && last_read.elapsed().as_secs() > 2 {
                let evt = ConnectionEvent::ReadError(io::Error::new(io::ErrorKind::InvalidData, format!("Invalid packet data: {:?}", packet_buffer.clone())));
                event_sender.send(evt).unwrap();
                packet_buffer.clear();
            };

            match packet_receiver.try_recv() {
                Ok(p) => {
                    println!("going to write...");
                    match serial.write_all(&p.data) {
                        Ok(_) => {},
                        Err(e) => {
                            let evt = ConnectionEvent::WriteError(e);
                            event_sender.send(evt).unwrap();
                        }
                    }
                },
                Err(TryRecvError::Empty) => {  },
                Err(TryRecvError::Disconnected) => { panic!("channels should not disconnect") }
            }

            match serial.read(&mut read_buffer) {
                Err(e) => {
                    let evt = ConnectionEvent::ReadError(e);
                    event_sender.send(evt).unwrap();
                },
                Ok(bytes) if bytes > 0 => {
                    last_read = Instant::now();
                    for x in 0 .. bytes {
                        packet_buffer.push(read_buffer[x]);
                    }
                },
                Ok(_) => {} // do nothing for 0 bytes read
            };

            while packet_buffer.len() >= 128 {
                let data: Vec<u8> = packet_buffer.drain(0..128).collect();
                let p = Packet::from_bytes(&data);

                if p.is_checksum_valid() {
                    let evt = ConnectionEvent::Packet(p);
                    event_sender.send(evt).unwrap();
                } else {
                    let evt = ConnectionEvent::InvalidPacket(p);
                    event_sender.send(evt).unwrap();
                }
            }

            match heartbeat {
                Some(ms) => {
                    if last_heartbeat.elapsed() >= Duration::from_millis(ms) {
                        let evt = ConnectionEvent::Heartbeat;
                        event_sender.send(evt).unwrap();
                        last_heartbeat = Instant::now();
                    }
                },
                None => {}
            }

            thread::sleep(Duration::from_millis(250));
        }
        ()
    })
}
<commit_msg>debug<commit_after>mod thread_guard;

use std::fmt;
use std::io;
use std::io::prelude::*;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Sender, Receiver, TryRecvError};
use std::thread;
use std::time::{Duration, Instant};
use std::ops::Deref;

use serial::prelude::*;
use serial;
use self::thread_guard::*;
use super::Packet;

pub enum ConnectionEvent {
    Packet(Packet),
    InvalidPacket(Packet),
    ReadError(io::Error),
    WriteError(io::Error),
    Heartbeat
}

impl fmt::Display for ConnectionEvent {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &ConnectionEvent::Packet(ref p) => write!(f, "{}", p),
            &ConnectionEvent::InvalidPacket(ref p) => write!(f, "Invalid! {}", p),
            &ConnectionEvent::ReadError(ref err) => write!(f, "READ ERROR! [{:?}]", err),
            &ConnectionEvent::WriteError(ref err) => write!(f, "WRITE ERROR! [{:?}]", err),
            &ConnectionEvent::Heartbeat => write!(f, "Tick Tock")
        }
    }
}

pub struct Connection {
    pub tty_path: String,
    event_receiver: Receiver<ConnectionEvent>,
    packet_sender: Sender<Packet>,
    kill_thread_signal: Arc<Mutex<bool>>,
    reader_thread_handle: Option<ThreadHandle<()>>,
}

impl Connection {
    pub fn new(tty_path: &str, heartbeat_milliseconds: Option<u64>) -> io::Result<Connection> {
        let (event_sender, event_receiver) = channel::<ConnectionEvent>();
        let (packet_sender, packet_receiver) = channel::<Packet>();

        let kill_signal = Arc::new(Mutex::new(false));

        let reader_thread = build_connection_read_thread(tty_path.to_string(), event_sender, packet_receiver, heartbeat_milliseconds, kill_signal.clone());

        Ok(Connection {
            tty_path: tty_path.to_string(),
            event_receiver: event_receiver,
            packet_sender: packet_sender,
            kill_thread_signal: kill_signal,
            reader_thread_handle: Some(reader_thread)
        })
    }

    pub fn send(&mut self, p: Packet) -> io::Result<()> {
        match self.is_ok() {
            true => {
                self.packet_sender.send(p).unwrap();
                Ok(())
            },
            false => Err(io::Error::new(io::ErrorKind::ConnectionAborted, "worker threads have stopped"))
        }
    }

    pub fn wait(&self) -> io::Result<ConnectionEvent> {
        match self.is_ok() {
            false => Err(io::Error::new(io::ErrorKind::ConnectionAborted, "worker threads have stopped")),
            true => {
                Ok(self.event_receiver.recv().unwrap())
            }
        }
    }

    pub fn get_events(&self) -> io::Result<Vec<ConnectionEvent>> {
        match self.is_ok() {
            false => Err(io::Error::new(io::ErrorKind::ConnectionAborted, "worker threads have stopped")),
            true => {
                let mut data: Vec<ConnectionEvent> = vec!();

                loop {
                    match self.event_receiver.try_recv() {
                        Ok(evt) => { data.push(evt) },
                        Err(TryRecvError::Empty) => { break; },
                        Err(TryRecvError::Disconnected) => { panic!("channels should not disconnect") }
                    }
                }

                Ok(data)
            }
        }
    }

    pub fn is_ok(&self) -> bool {
        let mut ret = true;

        match &self.reader_thread_handle {
            &Some(ref h) => {
                ret = ret && match h.status.lock().unwrap().deref() {
                    &ThreadStatus::Ok => true,
                    _ => false
                }
            },
            _ => {}
        }
        ret
    }
}

impl Drop for Connection {
    fn drop(&mut self) {

        {
            *self.kill_thread_signal.lock().unwrap() = true;
        }

        match self.reader_thread_handle.take() {
            Some(th) => {
                th.handle.join().unwrap();
            },
            None => {}
        }
    }
}

fn build_connection_read_thread(tty_path: String, event_sender: Sender<ConnectionEvent>, packet_receiver: Receiver<Packet>, heartbeat: Option<u64>, kill_signal: Arc<Mutex<bool>>) -> ThreadHandle<()> {
    guard_thread("reader_thread", move || {
        let mut serial = match serial::open(&tty_path) {
            Err(e) => {panic!(format!("Unable to create serial port: {}", e)) },
            Ok(s) => s
        };

        match serial.set_timeout(Duration::from_millis(500)) {
            Err(e) => { panic!(format!("Unable to set serial timeout: {}", e)) },
            Ok(_) => {}
        };

        let mut packet_buffer: Vec<u8> = Vec::new();
        let mut read_buffer: Vec<u8> = Vec::new();
        let mut last_read = Instant::now();
        let mut last_heartbeat = Instant::now();

        while !*kill_signal.lock().unwrap() {

            if packet_buffer.len() > 0 && last_read.elapsed().as_secs() > 2 {
                let evt = ConnectionEvent::ReadError(io::Error::new(io::ErrorKind::InvalidData, format!("Invalid packet data: {:?}", packet_buffer.clone())));
                event_sender.send(evt).unwrap();
                packet_buffer.clear();
            };

            match packet_receiver.try_recv() {
                Ok(p) => {
                    println!("going to write...");
                    match serial.write_all(&p.data) {
                        Ok(_) => {},
                        Err(e) => {
                            let evt = ConnectionEvent::WriteError(e);
                            event_sender.send(evt).unwrap();
                        }
                    }
                },
                Err(TryRecvError::Empty) => {  },
                Err(TryRecvError::Disconnected) => { panic!("channels should not disconnect") }
            }

            match serial.read(&mut read_buffer) {
                Err(e) => {
                    let evt = ConnectionEvent::ReadError(e);
                    event_sender.send(evt).unwrap();
                },
                Ok(bytes) if bytes > 0 => {
                    last_read = Instant::now();
                    for x in 0 .. bytes {
                        packet_buffer.push(read_buffer[x]);
                    }
                },
                Ok(_) => {} // do nothing for 0 bytes read
            };

            while packet_buffer.len() >= 128 {
                let data: Vec<u8> = packet_buffer.drain(0..128).collect();
                let p = Packet::from_bytes(&data);

                if p.is_checksum_valid() {
                    let evt = ConnectionEvent::Packet(p);
                    event_sender.send(evt).unwrap();
                } else {
                    let evt = ConnectionEvent::InvalidPacket(p);
                    event_sender.send(evt).unwrap();
                }
            }

            match heartbeat {
                Some(ms) => {
                    if last_heartbeat.elapsed() >= Duration::from_millis(ms) {
                        let evt = ConnectionEvent::Heartbeat;
                        event_sender.send(evt).unwrap();
                        last_heartbeat = Instant::now();
                    }
                },
                None => {}
            }

            thread::sleep(Duration::from_millis(250));
        }
        ()
    })
}
<|endoftext|>