<commit_before>//! Intermediate representation of a function.
//!
//! The `Function` struct defined in this module owns all of its extended basic blocks and
//! instructions.

use binemit::CodeOffset;
use entity::{EntityMap, PrimaryMap};
use ir;
use ir::{CallConv, DataFlowGraph, ExternalName, Layout, Signature};
use ir::{Ebb, ExtFuncData, FuncRef, GlobalVar, GlobalVarData, Heap, HeapData, JumpTable,
         JumpTableData, SigRef, StackSlot, StackSlotData};
use ir::{EbbOffsets, InstEncodings, JumpTables, SourceLocs, StackSlots, ValueLocations};
use isa::{EncInfo, Legalize, TargetIsa};
use std::fmt;
use write::write_function;

/// A function.
///
/// Functions can be cloned, but it is not a very fast operation.
/// The clone will have all the same entity numbers as the original.
#[derive(Clone)]
pub struct Function {
    /// Name of this function. Mostly used by `.cton` files.
    pub name: ExternalName,

    /// Signature of this function.
    pub signature: Signature,

    /// Stack slots allocated in this function.
    pub stack_slots: StackSlots,

    /// Global variables referenced.
    pub global_vars: PrimaryMap<ir::GlobalVar, ir::GlobalVarData>,

    /// Heaps referenced.
    pub heaps: PrimaryMap<ir::Heap, ir::HeapData>,

    /// Jump tables used in this function.
    pub jump_tables: JumpTables,

    /// Data flow graph containing the primary definition of all instructions, EBBs and values.
    pub dfg: DataFlowGraph,

    /// Layout of EBBs and instructions in the function body.
    pub layout: Layout,

    /// Encoding recipe and bits for the legal instructions.
    /// Illegal instructions have the `Encoding::default()` value.
    pub encodings: InstEncodings,

    /// Location assigned to every value.
    pub locations: ValueLocations,

    /// Code offsets of the EBB headers.
    ///
    /// This information is only transiently available after the `binemit::relax_branches` function
    /// computes it, and it can easily be recomputed by calling that function. It is not included
    /// in the textual IR format.
    pub offsets: EbbOffsets,

    /// Source locations.
    ///
    /// Track the original source location for each instruction. The source locations are not
    /// interpreted by Cretonne, only preserved.
    pub srclocs: SourceLocs,
}

impl Function {
    /// Create a function with the given name and signature.
    pub fn with_name_signature(name: ExternalName, sig: Signature) -> Self {
        Self {
            name,
            signature: sig,
            stack_slots: StackSlots::new(),
            global_vars: PrimaryMap::new(),
            heaps: PrimaryMap::new(),
            jump_tables: PrimaryMap::new(),
            dfg: DataFlowGraph::new(),
            layout: Layout::new(),
            encodings: EntityMap::new(),
            locations: EntityMap::new(),
            offsets: EntityMap::new(),
            srclocs: EntityMap::new(),
        }
    }

    /// Clear all data structures in this function.
    pub fn clear(&mut self) {
        self.signature.clear(ir::CallConv::SystemV);
        self.stack_slots.clear();
        self.global_vars.clear();
        self.heaps.clear();
        self.jump_tables.clear();
        self.dfg.clear();
        self.layout.clear();
        self.encodings.clear();
        self.locations.clear();
        self.offsets.clear();
        self.srclocs.clear();
    }

    /// Create a new empty, anonymous function with a SystemV calling convention.
    pub fn new() -> Self {
        Self::with_name_signature(ExternalName::default(), Signature::new(CallConv::SystemV))
    }

    /// Creates a jump table in the function, to be used by `br_table` instructions.
    pub fn create_jump_table(&mut self, data: JumpTableData) -> JumpTable {
        self.jump_tables.push(data)
    }

    /// Inserts an entry in a previously declared jump table.
    pub fn insert_jump_table_entry(&mut self, jt: JumpTable, index: usize, ebb: Ebb) {
        self.jump_tables[jt].set_entry(index, ebb);
    }

    /// Creates a stack slot in the function, to be used by `stack_load`, `stack_store` and
    /// `stack_addr` instructions.
    pub fn create_stack_slot(&mut self, data: StackSlotData) -> StackSlot {
        self.stack_slots.push(data)
    }

    /// Adds a signature which can later be used to declare an external function import.
    pub fn import_signature(&mut self, signature: Signature) -> SigRef {
        self.dfg.signatures.push(signature)
    }

    /// Declare an external function import.
    pub fn import_function(&mut self, data: ExtFuncData) -> FuncRef {
        self.dfg.ext_funcs.push(data)
    }

    /// Declares a global variable accessible to the function.
    pub fn create_global_var(&mut self, data: GlobalVarData) -> GlobalVar {
        self.global_vars.push(data)
    }

    /// Declares a heap accessible to the function.
    pub fn create_heap(&mut self, data: HeapData) -> Heap {
        self.heaps.push(data)
    }

    /// Return an object that can display this function with correct ISA-specific annotations.
    pub fn display<'a, I: Into<Option<&'a TargetIsa>>>(&'a self, isa: I) -> DisplayFunction<'a> {
        DisplayFunction(self, isa.into())
    }

    /// Find a presumed unique special-purpose function parameter value.
    ///
    /// Returns the value of the last `purpose` parameter, or `None` if no such parameter exists.
    pub fn special_param(&self, purpose: ir::ArgumentPurpose) -> Option<ir::Value> {
        let entry = self.layout.entry_block().expect("Function is empty");
        self.signature.special_param_index(purpose).map(|i| {
            self.dfg.ebb_params(entry)[i]
        })
    }

    /// Get an iterator over the instructions in `ebb`, including offsets and encoded instruction
    /// sizes.
    ///
    /// The iterator returns `(offset, inst, size)` tuples, where `offset` if the offset in bytes
    /// from the beginning of the function to the instruction, and `size` is the size of the
    /// instruction in bytes, or 0 for unencoded instructions.
    ///
    /// This function can only be used after the code layout has been computed by the
    /// `binemit::relax_branches()` function.
    pub fn inst_offsets<'a>(&'a self, ebb: Ebb, encinfo: &EncInfo) -> InstOffsetIter<'a> {
        assert!(
            !self.offsets.is_empty(),
            "Code layout must be computed first"
        );
        InstOffsetIter {
            encinfo: encinfo.clone(),
            encodings: &self.encodings,
            offset: self.offsets[ebb],
            iter: self.layout.ebb_insts(ebb),
        }
    }

    /// Wrapper around `DataFlowGraph::encode` which assigns `inst` the resulting encoding.
    pub fn update_encoding(&mut self, inst: ir::Inst, isa: &TargetIsa) -> Result<(), Legalize> {
        self.dfg.encode(inst, isa).map(
            |e| { self.encodings[inst] = e; },
        )
    }
}

/// Wrapper type capable of displaying a `Function` with correct ISA annotations.
pub struct DisplayFunction<'a>(&'a Function, Option<&'a TargetIsa>);

impl<'a> fmt::Display for DisplayFunction<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write_function(fmt, self.0, self.1)
    }
}

impl fmt::Display for Function {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write_function(fmt, self, None)
    }
}

impl fmt::Debug for Function {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write_function(fmt, self, None)
    }
}

/// Iterator returning instruction offsets and sizes: `(offset, inst, size)`.
pub struct InstOffsetIter<'a> {
    encinfo: EncInfo,
    encodings: &'a InstEncodings,
    offset: CodeOffset,
    iter: ir::layout::Insts<'a>,
}

impl<'a> Iterator for InstOffsetIter<'a> {
    type Item = (CodeOffset, ir::Inst, CodeOffset);

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|inst| {
            let size = self.encinfo.bytes(self.encodings[inst]);
            let offset = self.offset;
            self.offset += size;
            (offset, inst, size)
        })
    }
}
<commit_msg>Minor code cleanup.<commit_after>//! Intermediate representation of a function.
//!
//! The `Function` struct defined in this module owns all of its extended basic blocks and
//! instructions.

use binemit::CodeOffset;
use entity::{EntityMap, PrimaryMap};
use ir;
use ir::{CallConv, DataFlowGraph, ExternalName, Layout, Signature};
use ir::{Ebb, ExtFuncData, FuncRef, GlobalVar, GlobalVarData, Heap, HeapData, JumpTable,
         JumpTableData, SigRef, StackSlot, StackSlotData};
use ir::{EbbOffsets, InstEncodings, JumpTables, SourceLocs, StackSlots, ValueLocations};
use isa::{EncInfo, Legalize, TargetIsa};
use std::fmt;
use write::write_function;

/// A function.
///
/// Functions can be cloned, but it is not a very fast operation.
/// The clone will have all the same entity numbers as the original.
#[derive(Clone)]
pub struct Function {
    /// Name of this function. Mostly used by `.cton` files.
    pub name: ExternalName,

    /// Signature of this function.
    pub signature: Signature,

    /// Stack slots allocated in this function.
    pub stack_slots: StackSlots,

    /// Global variables referenced.
    pub global_vars: PrimaryMap<ir::GlobalVar, ir::GlobalVarData>,

    /// Heaps referenced.
    pub heaps: PrimaryMap<ir::Heap, ir::HeapData>,

    /// Jump tables used in this function.
    pub jump_tables: JumpTables,

    /// Data flow graph containing the primary definition of all instructions, EBBs and values.
    pub dfg: DataFlowGraph,

    /// Layout of EBBs and instructions in the function body.
    pub layout: Layout,

    /// Encoding recipe and bits for the legal instructions.
    /// Illegal instructions have the `Encoding::default()` value.
    pub encodings: InstEncodings,

    /// Location assigned to every value.
    pub locations: ValueLocations,

    /// Code offsets of the EBB headers.
    ///
    /// This information is only transiently available after the `binemit::relax_branches` function
    /// computes it, and it can easily be recomputed by calling that function. It is not included
    /// in the textual IR format.
    pub offsets: EbbOffsets,

    /// Source locations.
    ///
    /// Track the original source location for each instruction. The source locations are not
    /// interpreted by Cretonne, only preserved.
    pub srclocs: SourceLocs,
}

impl Function {
    /// Create a function with the given name and signature.
    pub fn with_name_signature(name: ExternalName, sig: Signature) -> Self {
        Self {
            name,
            signature: sig,
            stack_slots: StackSlots::new(),
            global_vars: PrimaryMap::new(),
            heaps: PrimaryMap::new(),
            jump_tables: PrimaryMap::new(),
            dfg: DataFlowGraph::new(),
            layout: Layout::new(),
            encodings: EntityMap::new(),
            locations: EntityMap::new(),
            offsets: EntityMap::new(),
            srclocs: EntityMap::new(),
        }
    }

    /// Clear all data structures in this function.
    pub fn clear(&mut self) {
        self.signature.clear(ir::CallConv::SystemV);
        self.stack_slots.clear();
        self.global_vars.clear();
        self.heaps.clear();
        self.jump_tables.clear();
        self.dfg.clear();
        self.layout.clear();
        self.encodings.clear();
        self.locations.clear();
        self.offsets.clear();
        self.srclocs.clear();
    }

    /// Create a new empty, anonymous function with a SystemV calling convention.
    pub fn new() -> Self {
        Self::with_name_signature(ExternalName::default(), Signature::new(CallConv::SystemV))
    }

    /// Creates a jump table in the function, to be used by `br_table` instructions.
    pub fn create_jump_table(&mut self, data: JumpTableData) -> JumpTable {
        self.jump_tables.push(data)
    }

    /// Inserts an entry in a previously declared jump table.
    pub fn insert_jump_table_entry(&mut self, jt: JumpTable, index: usize, ebb: Ebb) {
        self.jump_tables[jt].set_entry(index, ebb);
    }

    /// Creates a stack slot in the function, to be used by `stack_load`, `stack_store` and
    /// `stack_addr` instructions.
    pub fn create_stack_slot(&mut self, data: StackSlotData) -> StackSlot {
        self.stack_slots.push(data)
    }

    /// Adds a signature which can later be used to declare an external function import.
    pub fn import_signature(&mut self, signature: Signature) -> SigRef {
        self.dfg.signatures.push(signature)
    }

    /// Declare an external function import.
    pub fn import_function(&mut self, data: ExtFuncData) -> FuncRef {
        self.dfg.ext_funcs.push(data)
    }

    /// Declares a global variable accessible to the function.
    pub fn create_global_var(&mut self, data: GlobalVarData) -> GlobalVar {
        self.global_vars.push(data)
    }

    /// Declares a heap accessible to the function.
    pub fn create_heap(&mut self, data: HeapData) -> Heap {
        self.heaps.push(data)
    }

    /// Return an object that can display this function with correct ISA-specific annotations.
    pub fn display<'a, I: Into<Option<&'a TargetIsa>>>(&'a self, isa: I) -> DisplayFunction<'a> {
        DisplayFunction(self, isa.into())
    }

    /// Find a presumed unique special-purpose function parameter value.
    ///
    /// Returns the value of the last `purpose` parameter, or `None` if no such parameter exists.
    pub fn special_param(&self, purpose: ir::ArgumentPurpose) -> Option<ir::Value> {
        let entry = self.layout.entry_block().expect("Function is empty");
        self.signature.special_param_index(purpose).map(|i| {
            self.dfg.ebb_params(entry)[i]
        })
    }

    /// Get an iterator over the instructions in `ebb`, including offsets and encoded instruction
    /// sizes.
    ///
    /// The iterator returns `(offset, inst, size)` tuples, where `offset` if the offset in bytes
    /// from the beginning of the function to the instruction, and `size` is the size of the
    /// instruction in bytes, or 0 for unencoded instructions.
    ///
    /// This function can only be used after the code layout has been computed by the
    /// `binemit::relax_branches()` function.
    pub fn inst_offsets<'a>(&'a self, ebb: Ebb, encinfo: &EncInfo) -> InstOffsetIter<'a> {
        assert!(
            !self.offsets.is_empty(),
            "Code layout must be computed first"
        );
        InstOffsetIter {
            encinfo: encinfo.clone(),
            encodings: &self.encodings,
            offset: self.offsets[ebb],
            iter: self.layout.ebb_insts(ebb),
        }
    }

    /// Wrapper around `DataFlowGraph::encode` which assigns `inst` the resulting encoding.
    pub fn update_encoding(&mut self, inst: ir::Inst, isa: &TargetIsa) -> Result<(), Legalize> {
        self.dfg.encode(inst, isa).map(|e| self.encodings[inst] = e)
    }
}

/// Wrapper type capable of displaying a `Function` with correct ISA annotations.
pub struct DisplayFunction<'a>(&'a Function, Option<&'a TargetIsa>);

impl<'a> fmt::Display for DisplayFunction<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write_function(fmt, self.0, self.1)
    }
}

impl fmt::Display for Function {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write_function(fmt, self, None)
    }
}

impl fmt::Debug for Function {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write_function(fmt, self, None)
    }
}

/// Iterator returning instruction offsets and sizes: `(offset, inst, size)`.
pub struct InstOffsetIter<'a> {
    encinfo: EncInfo,
    encodings: &'a InstEncodings,
    offset: CodeOffset,
    iter: ir::layout::Insts<'a>,
}

impl<'a> Iterator for InstOffsetIter<'a> {
    type Item = (CodeOffset, ir::Inst, CodeOffset);

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|inst| {
            let size = self.encinfo.bytes(self.encodings[inst]);
            let offset = self.offset;
            self.offset += size;
            (offset, inst, size)
        })
    }
}
<|endoftext|>


<commit_before>use command_prelude::*;

use cargo::ops;

pub fn cli() -> App {
    subcommand("generate-lockfile")
        .about("Generate the lockfile for a project")
        .arg_manifest_path()
        .after_help(
            "\
If a lockfile is available, this command will ensure that all of the git
dependencies and/or registries dependencies are downloaded and locally
available. The network is never touched after a `cargo fetch` unless
the lockfile changes.

If the lockfile is not available, then this is the equivalent of
`cargo generate-lockfile`. A lockfile is generated and dependencies are also
all updated.
",
        )
}

pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
    let ws = args.workspace(config)?;
    ops::generate_lockfile(&ws)?;
    Ok(())
}
<commit_msg>Drop after_help in generate-lockfile<commit_after>use command_prelude::*;

use cargo::ops;

pub fn cli() -> App {
    subcommand("generate-lockfile")
        .about("Generate the lockfile for a project")
        .arg_manifest_path()
}

pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
    let ws = args.workspace(config)?;
    ops::generate_lockfile(&ws)?;
    Ok(())
}
<|endoftext|>


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

use abitest_grpc::proto::{oak_abi_test_service_client::OakAbiTestServiceClient, AbiTestRequest};
use anyhow::Context;
use assert_matches::assert_matches;
use log::{debug, error, info};
use maplit::hashmap;
use oak_abi::proto::oak::application::ConfigMap;
use serial_test::serial;
use std::{collections::HashMap, sync::Arc};

// Constants for Node config names that should match those in the textproto
// config held in ../../../config.
const FRONTEND_MODULE_NAME: &str = "frontend_module";
const BACKEND_MODULE_NAME: &str = "backend_module";
const LINEAR_HANDLES_MODULE_NAME: &str = "linear_handles_module";
const FRONTEND_ENTRYPOINT_NAME: &str = "frontend_oak_main";

const FRONTEND_MANIFEST: &str = "../../module_0/rust/Cargo.toml";
const BACKEND_MANIFEST: &str = "../../module_1/rust/Cargo.toml";
const LINEAR_HANDLES_MANIFEST: &str = "../../module_linear_handles/rust/Cargo.toml";

fn build_wasm() -> anyhow::Result<HashMap<String, Vec<u8>>> {
    Ok(hashmap! {
        FRONTEND_MODULE_NAME.to_owned() => oak_tests::compile_rust_wasm(FRONTEND_MANIFEST, oak_tests::Profile::Debug).context("could not compile frontend module")?,
        BACKEND_MODULE_NAME.to_owned() => oak_tests::compile_rust_wasm(BACKEND_MANIFEST, oak_tests::Profile::Debug).context("could not compile backend module")?,
        LINEAR_HANDLES_MODULE_NAME.to_owned() => oak_tests::compile_rust_wasm(LINEAR_HANDLES_MANIFEST, oak_tests::Profile::Debug).context("could not compile linear_handles module")?,
    })
}

async fn setup() -> (
    Arc<oak_runtime::Runtime>,
    OakAbiTestServiceClient<tonic::transport::Channel>,
) {
    let _ = env_logger::builder().is_test(true).try_init();
    let permissions = oak_runtime::permissions::PermissionsConfiguration {
        allow_grpc_server_nodes: true,
        allow_http_server_nodes: true,
        allow_log_nodes: true,
        allow_insecure_http_egress: true,
        allow_egress_https_authorities: vec!["localhost:7856".to_string()],
    };

    let wasm_modules = build_wasm().expect("failed to build wasm modules");
    let config = oak_tests::runtime_config_wasm(
        wasm_modules,
        FRONTEND_MODULE_NAME,
        FRONTEND_ENTRYPOINT_NAME,
        ConfigMap::default(),
        permissions,
        oak_runtime::SignatureTable::default(),
    );
    let runtime =
        oak_runtime::configure_and_run(config).expect("unable to configure runtime with test wasm");

    let (channel, interceptor) = oak_tests::public_channel_and_interceptor().await;
    let client = OakAbiTestServiceClient::with_interceptor(channel, interceptor);

    (runtime, client)
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
#[serial]
async fn test_abi() {
    let (runtime, mut client) = setup().await;
    {
        // Skip tests that require the existence of an external service.
        //  - storage and gRPC client test require details of a gRPC service to connect to
        //  - Roughtime tests connect to the internet.
        let mut req = AbiTestRequest::default();
        req.exclude = "(Storage|GrpcClient|Roughtime)".to_string();

        info!("Sending request: {:?}", req);
        let result = client.run_tests(req).await;
        assert_matches!(result, Ok(_));

        info!("Runtime graph at exit is:\n{}", runtime.graph());

        let mut disabled = 0;
        let mut success = true;
        let results = result.unwrap().into_inner().results;
        for result in results {
            if result.disabled {
                disabled += 1;
                continue;
            }
            info!(
                "[ {} ] {}",
                if result.success { " OK " } else { "FAIL" },
                result.name
            );
            if !result.success {
                error!("Failure details: {}", result.details);
                success = false;
            }
        }
        if disabled > 0 {
            info!("YOU HAVE {} DISABLED TESTS", disabled);
        }
        assert_eq!(true, success);
    } // ensure futures are all dropped
    drop(client);
    runtime.stop();
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
#[serial]
async fn test_leaks() {
    let (runtime, mut client) = setup().await;

    {
        let (before_nodes, before_channels) = runtime.object_counts();
        info!(
            "Counts before test: Nodes={}, Channels={}",
            before_nodes, before_channels
        );

        // Run tests that are supposed to leave Node/channel counts in a known state.
        // Skip tests that require the existence of an external service.
        //  - storage and gRPC client test require details of a gRPC service to connect to
        //  - Roughtime tests connect to the internet.
        let mut req = AbiTestRequest::default();
        req.exclude = "(Storage|GrpcClient|Roughtime)".to_string();
        req.predictable_counts = true;

        debug!("Sending request: {:?}", req);
        let result = client.run_tests(req).await;
        assert_matches!(result, Ok(_));
        let results = result.unwrap().into_inner().results;

        let (after_nodes, after_channels) = runtime.object_counts();
        info!(
            "Counts change from test: Nodes={} => {}, Channels={} => {}",
            before_nodes, after_nodes, before_channels, after_channels
        );

        // Calculate the expected change in Node and channel counts for
        // these tests.
        let mut want_nodes = before_nodes;
        let mut want_channels = before_channels;
        for result in &results {
            assert_eq!(result.predictable_counts, true);
            if result.disabled {
                continue;
            }
            want_nodes += result.node_change;
            want_channels += result.channel_change;
        }

        if after_nodes != want_nodes || after_channels != want_channels {
            error!(
                "Batch test showed unexpected count change: got: node_delta={} channel_delta={}, want node_delta={} channel_delta={}",
                (after_nodes-before_nodes), (after_channels-before_channels),
                (want_nodes-before_nodes), (want_channels-before_channels),
            );
            // One of the batch of tests has triggered an unexpected object count.
            // Repeat the tests one by one to find out which.
            let mut details = Vec::new();
            for result in results {
                if result.disabled {
                    continue;
                }

                let (before_nodes, before_channels) = runtime.object_counts();
                let (want_nodes, want_channels) = (
                    before_nodes + result.node_change,
                    before_channels + result.channel_change,
                );

                let mut req = AbiTestRequest::default();
                req.include = format!("^{}$", result.name);
                debug!("Sending request: {:?}", req);
                let this_result = client.run_tests(req).await;
                assert_matches!(this_result, Ok(_));
                let (after_nodes, after_channels) = runtime.object_counts();

                if after_nodes != want_nodes || after_channels != want_channels {
                    details.push(format!(
                    "[ LEAK ] {} (got {}=>{} nodes, {}=>{} channels, want {}=>{} nodes, {}=>{} channels)",
                    result.name, before_nodes, after_nodes, before_channels, after_channels,
                    before_nodes, want_nodes, before_channels, want_channels,
                ));
                } else {
                    details.push(format!(
                        "[ OK ] {} ({}=>{} nodes, {}=>{} channels, as expected)",
                        result.name, before_nodes, after_nodes, before_channels, after_channels,
                    ));
                }
            }
            for detail in details {
                info!("{}", detail);
            }
            panic!("Leak of Nodes or channels found");
        }
    } // ensure futures are all dropped
    drop(client);
    runtime.stop();
}
<commit_msg>Add logic to retry counts in case of possible leak (#2019)<commit_after>//
// Copyright 2019 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use abitest_grpc::proto::{oak_abi_test_service_client::OakAbiTestServiceClient, AbiTestRequest};
use anyhow::Context;
use assert_matches::assert_matches;
use log::{debug, error, info};
use maplit::hashmap;
use oak_abi::proto::oak::application::ConfigMap;
use serial_test::serial;
use std::{collections::HashMap, sync::Arc};
use tokio::time::{sleep, Duration};

// Constants for Node config names that should match those in the textproto
// config held in ../../../config.
const FRONTEND_MODULE_NAME: &str = "frontend_module";
const BACKEND_MODULE_NAME: &str = "backend_module";
const LINEAR_HANDLES_MODULE_NAME: &str = "linear_handles_module";
const FRONTEND_ENTRYPOINT_NAME: &str = "frontend_oak_main";

const FRONTEND_MANIFEST: &str = "../../module_0/rust/Cargo.toml";
const BACKEND_MANIFEST: &str = "../../module_1/rust/Cargo.toml";
const LINEAR_HANDLES_MANIFEST: &str = "../../module_linear_handles/rust/Cargo.toml";

fn build_wasm() -> anyhow::Result<HashMap<String, Vec<u8>>> {
    Ok(hashmap! {
        FRONTEND_MODULE_NAME.to_owned() => oak_tests::compile_rust_wasm(FRONTEND_MANIFEST, oak_tests::Profile::Debug).context("could not compile frontend module")?,
        BACKEND_MODULE_NAME.to_owned() => oak_tests::compile_rust_wasm(BACKEND_MANIFEST, oak_tests::Profile::Debug).context("could not compile backend module")?,
        LINEAR_HANDLES_MODULE_NAME.to_owned() => oak_tests::compile_rust_wasm(LINEAR_HANDLES_MANIFEST, oak_tests::Profile::Debug).context("could not compile linear_handles module")?,
    })
}

async fn setup() -> (
    Arc<oak_runtime::Runtime>,
    OakAbiTestServiceClient<tonic::transport::Channel>,
) {
    let _ = env_logger::builder().is_test(true).try_init();
    let permissions = oak_runtime::permissions::PermissionsConfiguration {
        allow_grpc_server_nodes: true,
        allow_http_server_nodes: true,
        allow_log_nodes: true,
        allow_insecure_http_egress: true,
        allow_egress_https_authorities: vec!["localhost:7856".to_string()],
    };

    let wasm_modules = build_wasm().expect("failed to build wasm modules");
    let config = oak_tests::runtime_config_wasm(
        wasm_modules,
        FRONTEND_MODULE_NAME,
        FRONTEND_ENTRYPOINT_NAME,
        ConfigMap::default(),
        permissions,
        oak_runtime::SignatureTable::default(),
    );
    let runtime =
        oak_runtime::configure_and_run(config).expect("unable to configure runtime with test wasm");

    let (channel, interceptor) = oak_tests::public_channel_and_interceptor().await;
    let client = OakAbiTestServiceClient::with_interceptor(channel, interceptor);

    (runtime, client)
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
#[serial]
async fn test_abi() {
    let (runtime, mut client) = setup().await;
    {
        // Skip tests that require the existence of an external service.
        //  - storage and gRPC client test require details of a gRPC service to connect to
        //  - Roughtime tests connect to the internet.
        let mut req = AbiTestRequest::default();
        req.exclude = "(Storage|GrpcClient|Roughtime)".to_string();

        info!("Sending request: {:?}", req);
        let result = client.run_tests(req).await;
        assert_matches!(result, Ok(_));

        info!("Runtime graph at exit is:\n{}", runtime.graph());

        let mut disabled = 0;
        let mut success = true;
        let results = result.unwrap().into_inner().results;
        for result in results {
            if result.disabled {
                disabled += 1;
                continue;
            }
            info!(
                "[ {} ] {}",
                if result.success { " OK " } else { "FAIL" },
                result.name
            );
            if !result.success {
                error!("Failure details: {}", result.details);
                success = false;
            }
        }
        if disabled > 0 {
            info!("YOU HAVE {} DISABLED TESTS", disabled);
        }
        assert_eq!(true, success);
    } // ensure futures are all dropped
    drop(client);
    runtime.stop();
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
#[serial]
async fn test_leaks() {
    let (runtime, mut client) = setup().await;

    {
        let (before_nodes, before_channels) = runtime.object_counts();
        info!(
            "Counts before test: Nodes={}, Channels={}",
            before_nodes, before_channels
        );

        // Run tests that are supposed to leave Node/channel counts in a known state.
        // Skip tests that require the existence of an external service.
        //  - storage and gRPC client test require details of a gRPC service to connect to
        //  - Roughtime tests connect to the internet.
        let mut req = AbiTestRequest::default();
        req.exclude = "(Storage|GrpcClient|Roughtime)".to_string();
        req.predictable_counts = true;

        debug!("Sending request: {:?}", req);
        let result = client.run_tests(req).await;
        assert_matches!(result, Ok(_));
        let results = result.unwrap().into_inner().results;

        // Calculate the expected change in Node and channel counts for
        // these tests.
        let mut want_nodes = before_nodes;
        let mut want_channels = before_channels;
        for result in &results {
            assert_eq!(result.predictable_counts, true);
            if result.disabled {
                continue;
            }
            want_nodes += result.node_change;
            want_channels += result.channel_change;
        }

        let (after_nodes, after_channels) = runtime.object_counts();
        // If the values don't match the expected values it could be due to a race condition where a
        // backend node closed its orphaned channeal a bit later than expected, so we wait 5 seconds
        // and calculate the values again.
        let (after_nodes, after_channels) =
            if after_nodes != want_nodes || after_channels != want_channels {
                sleep(Duration::from_secs(5)).await;
                runtime.object_counts()
            } else {
                (after_nodes, after_channels)
            };

        info!(
            "Counts change from test: Nodes={} => {}, Channels={} => {}",
            before_nodes, after_nodes, before_channels, after_channels
        );

        if after_nodes != want_nodes || after_channels != want_channels {
            error!(
                "Batch test showed unexpected count change: got: node_delta={} channel_delta={}, want node_delta={} channel_delta={}",
                (after_nodes-before_nodes), (after_channels-before_channels),
                (want_nodes-before_nodes), (want_channels-before_channels),
            );
            // One of the batch of tests has triggered an unexpected object count.
            // Repeat the tests one by one to find out which.
            let mut details = Vec::new();
            for result in results {
                if result.disabled {
                    continue;
                }

                let (before_nodes, before_channels) = runtime.object_counts();
                let (want_nodes, want_channels) = (
                    before_nodes + result.node_change,
                    before_channels + result.channel_change,
                );

                let mut req = AbiTestRequest::default();
                req.include = format!("^{}$", result.name);
                debug!("Sending request: {:?}", req);
                let this_result = client.run_tests(req).await;
                assert_matches!(this_result, Ok(_));
                let (after_nodes, after_channels) = runtime.object_counts();

                if after_nodes != want_nodes || after_channels != want_channels {
                    details.push(format!(
                    "[ LEAK ] {} (got {}=>{} nodes, {}=>{} channels, want {}=>{} nodes, {}=>{} channels)",
                    result.name, before_nodes, after_nodes, before_channels, after_channels,
                    before_nodes, want_nodes, before_channels, want_channels,
                ));
                } else {
                    details.push(format!(
                        "[ OK ] {} ({}=>{} nodes, {}=>{} channels, as expected)",
                        result.name, before_nodes, after_nodes, before_channels, after_channels,
                    ));
                }
            }
            for detail in details {
                info!("{}", detail);
            }
            panic!("Leak of Nodes or channels found");
        }
    } // ensure futures are all dropped
    drop(client);
    runtime.stop();
}
<|endoftext|>


<commit_before>use rpn_calculator::*;

fn calculator_input(s: &str) -> Vec<CalculatorInput> {
    s.split_whitespace()
        .map(|s| match s {
            "+" => CalculatorInput::Add,
            "-" => CalculatorInput::Subtract,
            "*" => CalculatorInput::Multiply,
            "/" => CalculatorInput::Divide,
            n => CalculatorInput::Value(n.parse().unwrap()),
        })
        .collect()
}

#[test]
fn test_empty_input_returns_none() {
    let input = calculator_input("");
    assert_eq!(evaluate(&input), None);
}

#[test]
#[ignore]
fn test_simple_value() {
    let input = calculator_input("10");
    assert_eq!(evaluate(&input), Some(10));
}

#[test]
#[ignore]
fn test_simple_addition() {
    let input = calculator_input("2 2 +");
    assert_eq!(evaluate(&input), Some(4));
}

#[test]
#[ignore]
fn test_simple_subtraction() {
    let input = calculator_input("7 11 -");
    assert_eq!(evaluate(&input), Some(-4));
}

#[test]
#[ignore]
fn test_simple_multiplication() {
    let input = calculator_input("6 9 *");
    assert_eq!(evaluate(&input), Some(54));
}

#[test]
#[ignore]
fn test_simple_division() {
    let input = calculator_input("57 19 /");
    assert_eq!(evaluate(&input), Some(3));
}

#[test]
#[ignore]
fn test_complex_operation() {
    let input = calculator_input("4 8 + 7 5 - /");
    assert_eq!(evaluate(&input), Some(6));
}

#[test]
#[ignore]
fn test_too_few_operands_returns_none() {
    let input = calculator_input("2 +");
    assert_eq!(evaluate(&input), None);
}

#[test]
#[ignore]
fn test_too_many_operands_returns_none() {
    let input = calculator_input("2 2");
    assert_eq!(evaluate(&input), None);
}
<commit_msg>rpn-calculator: Test missing operands & intermediate error (#1403)<commit_after>use rpn_calculator::*;

fn calculator_input(s: &str) -> Vec<CalculatorInput> {
    s.split_whitespace()
        .map(|s| match s {
            "+" => CalculatorInput::Add,
            "-" => CalculatorInput::Subtract,
            "*" => CalculatorInput::Multiply,
            "/" => CalculatorInput::Divide,
            n => CalculatorInput::Value(n.parse().unwrap()),
        })
        .collect()
}

#[test]
fn test_empty_input_returns_none() {
    let input = calculator_input("");
    assert_eq!(evaluate(&input), None);
}

#[test]
#[ignore]
fn test_simple_value() {
    let input = calculator_input("10");
    assert_eq!(evaluate(&input), Some(10));
}

#[test]
#[ignore]
fn test_simple_addition() {
    let input = calculator_input("2 2 +");
    assert_eq!(evaluate(&input), Some(4));
}

#[test]
#[ignore]
fn test_simple_subtraction() {
    let input = calculator_input("7 11 -");
    assert_eq!(evaluate(&input), Some(-4));
}

#[test]
#[ignore]
fn test_simple_multiplication() {
    let input = calculator_input("6 9 *");
    assert_eq!(evaluate(&input), Some(54));
}

#[test]
#[ignore]
fn test_simple_division() {
    let input = calculator_input("57 19 /");
    assert_eq!(evaluate(&input), Some(3));
}

#[test]
#[ignore]
fn test_complex_operation() {
    let input = calculator_input("4 8 + 7 5 - /");
    assert_eq!(evaluate(&input), Some(6));
}

#[test]
#[ignore]
fn test_too_few_operands_returns_none() {
    let input = calculator_input("2 +");
    assert_eq!(evaluate(&input), None);
}

#[test]
#[ignore]
fn test_too_many_operands_returns_none() {
    let input = calculator_input("2 2");
    assert_eq!(evaluate(&input), None);
}

#[test]
#[ignore]
fn test_zero_operands_returns_none() {
    let input = calculator_input("+");
    assert_eq!(evaluate(&input), None);
}

#[test]
#[ignore]
fn test_intermediate_error_returns_none() {
    let input = calculator_input("+ 2 2 *");
    assert_eq!(evaluate(&input), None);
}
<|endoftext|>


<commit_before>//! Legalization of heaps.
//!
//! This module exports the `expand_heap_addr` function which transforms a `heap_addr`
//! instruction into code that depends on the kind of heap referenced.

use cursor::{Cursor, FuncCursor};
use flowgraph::ControlFlowGraph;
use ir::{self, InstBuilder, MemFlags};
use ir::condcodes::IntCC;

/// Expand a `heap_addr` instruction according to the definition of the heap.
pub fn expand_heap_addr(inst: ir::Inst, func: &mut ir::Function, _cfg: &mut ControlFlowGraph) {
    // Unpack the instruction.
    let (heap, offset, size) = match func.dfg[inst] {
        ir::InstructionData::HeapAddr {
            opcode,
            heap,
            arg,
            imm,
        } => {
            assert_eq!(opcode, ir::Opcode::HeapAddr);
            (heap, arg, imm.into())
        }
        _ => panic!("Wanted heap_addr: {}", func.dfg.display_inst(inst, None)),
    };

    match func.heaps[heap].style {
        ir::HeapStyle::Dynamic { bound_gv } => {
            dynamic_addr(inst, heap, offset, size, bound_gv, func)
        }
        ir::HeapStyle::Static { bound } => {
            static_addr(inst, heap, offset, size, bound.into(), func)
        }
    }
}

/// Expand a `heap_addr` for a dynamic heap.
fn dynamic_addr(
    inst: ir::Inst,
    heap: ir::Heap,
    offset: ir::Value,
    size: u32,
    bound_gv: ir::GlobalVar,
    func: &mut ir::Function,
) {
    let size = i64::from(size);
    let offset_ty = func.dfg.value_type(offset);
    let addr_ty = func.dfg.value_type(func.dfg.first_result(inst));
    let min_size = func.heaps[heap].min_size.into();
    let mut pos = FuncCursor::new(func).at_inst(inst);
    pos.use_srcloc(inst);

    // Start with the bounds check. Trap if `offset + size > bound`.
    let bound_addr = pos.ins().global_addr(addr_ty, bound_gv);
    let bound = pos.ins().load(offset_ty, MemFlags::new(), bound_addr, 0);

    let oob;
    if size == 1 {
        // `offset > bound - 1` is the same as `offset >= bound`.
        oob = pos.ins().icmp(
            IntCC::UnsignedGreaterThanOrEqual,
            offset,
            bound,
        );
    } else if size <= min_size {
        // We know that bound >= min_size, so here we can compare `offset > bound - size` without
        // wrapping.
        let adj_bound = pos.ins().iadd_imm(bound, -size);
        oob = pos.ins().icmp(
            IntCC::UnsignedGreaterThan,
            offset,
            adj_bound,
        );
    } else {
        // We need an overflow check for the adjusted offset.
        let size_val = pos.ins().iconst(offset_ty, size);
        let (adj_offset, overflow) = pos.ins().iadd_cout(offset, size_val);
        pos.ins().trapnz(overflow, ir::TrapCode::HeapOutOfBounds);
        oob = pos.ins().icmp(
            IntCC::UnsignedGreaterThan,
            adj_offset,
            bound,
        );
    }
    pos.ins().trapnz(oob, ir::TrapCode::HeapOutOfBounds);

    offset_addr(inst, heap, addr_ty, offset, offset_ty, pos.func);
}

/// Expand a `heap_addr` for a static heap.
fn static_addr(
    inst: ir::Inst,
    heap: ir::Heap,
    offset: ir::Value,
    size: u32,
    bound: i64,
    func: &mut ir::Function,
) {
    let size = i64::from(size);
    let offset_ty = func.dfg.value_type(offset);
    let addr_ty = func.dfg.value_type(func.dfg.first_result(inst));
    let mut pos = FuncCursor::new(func).at_inst(inst);
    pos.use_srcloc(inst);

    // Start with the bounds check. Trap if `offset + size > bound`.
    if size > bound {
        // This will simply always trap since `offset >= 0`.
        pos.ins().trap(ir::TrapCode::HeapOutOfBounds);
        pos.func.dfg.replace(inst).iconst(addr_ty, 0);
        return;
    }

    // Check `offset > limit` which is now known non-negative.
    let limit = bound - size;

    // We may be able to omit the check entirely for 32-bit offsets if the heap bound is 4 GB or
    // more.
    if offset_ty != ir::types::I32 || limit < 0xffff_ffff {
        let oob = if limit & 1 == 1 {
            // Prefer testing `offset >= limit - 1` when limit is odd because an even number is
            // likely to be a convenient constant on ARM and other RISC architectures.
            pos.ins().icmp_imm(
                IntCC::UnsignedGreaterThanOrEqual,
                offset,
                limit - 1,
            )
        } else {
            pos.ins().icmp_imm(
                IntCC::UnsignedGreaterThan,
                offset,
                limit,
            )
        };
        pos.ins().trapnz(oob, ir::TrapCode::HeapOutOfBounds);
    }

    offset_addr(inst, heap, addr_ty, offset, offset_ty, pos.func);
}

/// Emit code for the base address computation of a `heap_addr` instruction.
///
///
fn offset_addr(
    inst: ir::Inst,
    heap: ir::Heap,
    addr_ty: ir::Type,
    mut offset: ir::Value,
    offset_ty: ir::Type,
    func: &mut ir::Function,
) {
    let mut pos = FuncCursor::new(func).at_inst(inst);
    pos.use_srcloc(inst);

    // Convert `offset` to `addr_ty`.
    if offset_ty != addr_ty {
        offset = pos.ins().uextend(addr_ty, offset);
    }

    // Add the heap base address base
    match pos.func.heaps[heap].base {
        ir::HeapBase::ReservedReg => unimplemented!(),
        ir::HeapBase::GlobalVar(base_gv) => {
            let base_addr = pos.ins().global_addr(addr_ty, base_gv);
            let base = pos.ins().load(addr_ty, MemFlags::new(), base_addr, 0);
            pos.func.dfg.replace(inst).iadd(base, offset);
        }
    }
}
<commit_msg>On finding an static OOB heap addr, split the Ebb and recompute the CFG.<commit_after>//! Legalization of heaps.
//!
//! This module exports the `expand_heap_addr` function which transforms a `heap_addr`
//! instruction into code that depends on the kind of heap referenced.

use cursor::{Cursor, FuncCursor};
use flowgraph::ControlFlowGraph;
use ir::{self, InstBuilder, MemFlags};
use ir::condcodes::IntCC;

/// Expand a `heap_addr` instruction according to the definition of the heap.
pub fn expand_heap_addr(inst: ir::Inst, func: &mut ir::Function, cfg: &mut ControlFlowGraph) {
    // Unpack the instruction.
    let (heap, offset, size) = match func.dfg[inst] {
        ir::InstructionData::HeapAddr {
            opcode,
            heap,
            arg,
            imm,
        } => {
            assert_eq!(opcode, ir::Opcode::HeapAddr);
            (heap, arg, imm.into())
        }
        _ => panic!("Wanted heap_addr: {}", func.dfg.display_inst(inst, None)),
    };

    match func.heaps[heap].style {
        ir::HeapStyle::Dynamic { bound_gv } => {
            dynamic_addr(inst, heap, offset, size, bound_gv, func)
        }
        ir::HeapStyle::Static { bound } => {
            static_addr(inst, heap, offset, size, bound.into(), func, cfg)
        }
    }
}

/// Expand a `heap_addr` for a dynamic heap.
fn dynamic_addr(
    inst: ir::Inst,
    heap: ir::Heap,
    offset: ir::Value,
    size: u32,
    bound_gv: ir::GlobalVar,
    func: &mut ir::Function,
) {
    let size = i64::from(size);
    let offset_ty = func.dfg.value_type(offset);
    let addr_ty = func.dfg.value_type(func.dfg.first_result(inst));
    let min_size = func.heaps[heap].min_size.into();
    let mut pos = FuncCursor::new(func).at_inst(inst);
    pos.use_srcloc(inst);

    // Start with the bounds check. Trap if `offset + size > bound`.
    let bound_addr = pos.ins().global_addr(addr_ty, bound_gv);
    let bound = pos.ins().load(offset_ty, MemFlags::new(), bound_addr, 0);

    let oob;
    if size == 1 {
        // `offset > bound - 1` is the same as `offset >= bound`.
        oob = pos.ins().icmp(
            IntCC::UnsignedGreaterThanOrEqual,
            offset,
            bound,
        );
    } else if size <= min_size {
        // We know that bound >= min_size, so here we can compare `offset > bound - size` without
        // wrapping.
        let adj_bound = pos.ins().iadd_imm(bound, -size);
        oob = pos.ins().icmp(
            IntCC::UnsignedGreaterThan,
            offset,
            adj_bound,
        );
    } else {
        // We need an overflow check for the adjusted offset.
        let size_val = pos.ins().iconst(offset_ty, size);
        let (adj_offset, overflow) = pos.ins().iadd_cout(offset, size_val);
        pos.ins().trapnz(overflow, ir::TrapCode::HeapOutOfBounds);
        oob = pos.ins().icmp(
            IntCC::UnsignedGreaterThan,
            adj_offset,
            bound,
        );
    }
    pos.ins().trapnz(oob, ir::TrapCode::HeapOutOfBounds);

    offset_addr(inst, heap, addr_ty, offset, offset_ty, pos.func);
}

/// Expand a `heap_addr` for a static heap.
fn static_addr(
    inst: ir::Inst,
    heap: ir::Heap,
    offset: ir::Value,
    size: u32,
    bound: i64,
    func: &mut ir::Function,
    cfg: &mut ControlFlowGraph,
) {
    let size = i64::from(size);
    let offset_ty = func.dfg.value_type(offset);
    let addr_ty = func.dfg.value_type(func.dfg.first_result(inst));
    let mut pos = FuncCursor::new(func).at_inst(inst);
    pos.use_srcloc(inst);

    // Start with the bounds check. Trap if `offset + size > bound`.
    if size > bound {
        // This will simply always trap since `offset >= 0`.
        pos.ins().trap(ir::TrapCode::HeapOutOfBounds);
        pos.func.dfg.replace(inst).iconst(addr_ty, 0);

        // Split Ebb, as the trap is a terminator instruction.
        let curr_ebb = pos.current_ebb().expect("Cursor is not in an ebb");
        let new_ebb = pos.func.dfg.make_ebb();
        pos.insert_ebb(new_ebb);
        cfg.recompute_ebb(pos.func, curr_ebb);
        cfg.recompute_ebb(pos.func, new_ebb);
        return;
    }

    // Check `offset > limit` which is now known non-negative.
    let limit = bound - size;

    // We may be able to omit the check entirely for 32-bit offsets if the heap bound is 4 GB or
    // more.
    if offset_ty != ir::types::I32 || limit < 0xffff_ffff {
        let oob = if limit & 1 == 1 {
            // Prefer testing `offset >= limit - 1` when limit is odd because an even number is
            // likely to be a convenient constant on ARM and other RISC architectures.
            pos.ins().icmp_imm(
                IntCC::UnsignedGreaterThanOrEqual,
                offset,
                limit - 1,
            )
        } else {
            pos.ins().icmp_imm(
                IntCC::UnsignedGreaterThan,
                offset,
                limit,
            )
        };
        pos.ins().trapnz(oob, ir::TrapCode::HeapOutOfBounds);
    }

    offset_addr(inst, heap, addr_ty, offset, offset_ty, pos.func);
}

/// Emit code for the base address computation of a `heap_addr` instruction.
///
///
fn offset_addr(
    inst: ir::Inst,
    heap: ir::Heap,
    addr_ty: ir::Type,
    mut offset: ir::Value,
    offset_ty: ir::Type,
    func: &mut ir::Function,
) {
    let mut pos = FuncCursor::new(func).at_inst(inst);
    pos.use_srcloc(inst);

    // Convert `offset` to `addr_ty`.
    if offset_ty != addr_ty {
        offset = pos.ins().uextend(addr_ty, offset);
    }

    // Add the heap base address base
    match pos.func.heaps[heap].base {
        ir::HeapBase::ReservedReg => unimplemented!(),
        ir::HeapBase::GlobalVar(base_gv) => {
            let base_addr = pos.ins().global_addr(addr_ty, base_gv);
            let base = pos.ins().load(addr_ty, MemFlags::new(), base_addr, 0);
            pos.func.dfg.replace(inst).iadd(base, offset);
        }
    }
}
<|endoftext|>


<commit_before>use std::ops::{Mul, MulAssign};
use std::f32::consts::PI;

use vector::Vector3;
use matrix::*;
use super::{IsZero, Clamp, Dot};

#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Quaternion {
    pub w: f32,
    pub x: f32,
    pub y: f32,
    pub z: f32,
}

impl Quaternion {
    /// Creates an identity quaternion.
    ///
    /// The identity quaternion is the quaternion that can be multiplied into any other quaternion
    /// without changing it.
    pub fn identity() -> Quaternion {
        Quaternion {
            w: 1.0,
            x: 0.0,
            y: 0.0,
            z: 0.0,
        }
    }

    /// Creates a quaternion from an axis and a rotation around that axis.
    ///
    /// # Params
    ///
    /// - axis - The axis being used to represent the rotation. This should
    ///   be normalized before being passed into `axis_angle()`.
    pub fn axis_angle(axis: Vector3, angle: f32) -> Quaternion {
        assert!(axis.is_normalized());

        let s = (angle * 0.5).sin();
        Quaternion {
            w: (angle * 0.5).cos(),
            x: s * axis.x,
            y: s * axis.y,
            z: s * axis.z,
        }.normalized()
    }

    /// Creates a quaternion that rotates an object to look in the specified direction.
    pub fn look_rotation(forward: Vector3, up: Vector3) -> Quaternion {
        assert!(!forward.is_zero());
        assert!(!up.is_zero());

        let source = Vector3::forward();
        let forward = forward.normalized();
        let up = up.normalized();

        let dot = source.dot(forward);

        if (dot + 1.0).is_zero() {
            // vector a and b point exactly in the opposite direction,
            // so it is a 180 degrees turn around the up-axis
            return Quaternion::axis_angle(up, PI)
        }

        if (dot - 1.0).is_zero() {
            // Vector a and b point exactly in the same direction
            // so we return the identity quaternion.
            return Quaternion::identity()
        }

        let rot_angle = dot.acos();
        let rot_axis = Vector3::cross(source, forward).normalized();// source.cross(forward).normalized();
        return Quaternion::axis_angle(rot_axis, rot_angle)

        // TODO: Correctly take the up vector into account.
    }

    /// Creates a quaternion from a set of euler angles.
    pub fn from_eulers(x: f32, y: f32, z: f32) -> Quaternion {
        Quaternion::axis_angle(Vector3::new(1.0, 0.0, 0.0), x)
      * Quaternion::axis_angle(Vector3::new(0.0, 1.0, 0.0), y)
      * Quaternion::axis_angle(Vector3::new(0.0, 0.0, 1.0), z)
    }

    pub fn from_vector3(angles: Vector3) -> Quaternion {
        Quaternion::from_eulers(angles.x, angles.y, angles.z)
    }

    /// Converts the quaternion to the corresponding rotation matrix.
    pub fn as_matrix4(self) -> Matrix4 {
        Matrix4::from_quaternion(self)
    }

    pub fn as_matrix3(self) -> Matrix3 {
        Matrix3::from_quaternion(self)
    }

    /// Retrieves the rotation represented by the quaternion as a rotation about an axis.
    ///
    /// The returned axis will always be normalized.
    pub fn as_axis_angle(&self) -> (Vector3, f32) {
        assert!(self.is_normalized());

        let angle = 2.0 * self.w.acos();
        let s = (1.0 - self.w * self.w).sqrt();
        if s.is_zero() {
            // If s is 0, axis is arbitrary.
            (Vector3::new(1.0, 0.0, 0.0), angle)
        } else {
            (Vector3::new(self.x / s, self.y / s, self.z / s).normalized(), angle)
        }
    }

    /// Retrieves the rotation represented by the quaternion as euler angles.
    pub fn as_eulers(&self) -> Vector3 {
        assert!(self.is_normalized());

        let x = f32::atan2(
            2.0 * (self.w * self.x + self.y * self.z),
            1.0 - 2.0 * (self.x * self.x + self.y * self.y));
        let y = (2.0 * (self.w * self.y - self.z * self.x)).asin();
        let z = f32::atan2(
            2.0 * (self.w * self.z + self.x * self.y),
            1.0 - 2.0 * (self.y * self.y + self.z * self.z));

        Vector3::new(x, y, z)
    }

    /// Normalizes the quaternion to unit length.
    ///
    /// The quaternion must not have a length of zero when calling this method.
    pub fn normalize(&mut self) {
        assert!(!self.is_zero());

        let length = (self.w * self.w
                    + self.x * self.x
                    + self.y * self.y
                    + self.z * self.z).sqrt();

        self.w /= length;
        self.x /= length;
        self.y /= length;
        self.z /= length;
    }

    /// Creates a normalized copy of the quaternion.
    ///
    /// The quaternion must not have a length of zero when calling this method.
    pub fn normalized(&self) -> Quaternion {
        let mut temp = *self;
        temp.normalize();
        temp
    }

    /// Determines if the quaternion is normalized (has a length of 1.0).
    pub fn is_normalized(&self) -> bool {
        let mag_sqrd = Quaternion::dot(*self, *self);
        (mag_sqrd - 1.0).is_zero()
    }

    pub fn repeat(&self, repeat: f32) -> Quaternion {
        let (axis, angle) = self.as_axis_angle();
        Quaternion::axis_angle(axis, angle * repeat)
    }

    /// Calculates the dot product of two quaternions.
    pub fn dot(first: Quaternion, second: Quaternion) -> f32 {
        (first.w * second.w
       + first.x * second.x
       + first.y * second.y
       + first.z * second.z)
    }

    /// Interpolates linearly between two quaternions.
    ///
    /// # Remarks
    ///
    /// This method does not necessarily result in a normalized Quaternion, so the result should
    /// not be used directly to represent a rotation. If you would like to lerp two rotation
    /// quaternions use `Quaternion::nlerp()`.
    pub fn lerp(first: Quaternion, second: Quaternion, t: f32) -> Quaternion {
        // first + t * (second - first)
        second.sub(first).mul(t).add(first)
    }

    /// Interpolates linearly between two quaternions using a normalized lerp.
    pub fn nlerp(first: Quaternion, second: Quaternion, t: f32) -> Quaternion {
        Quaternion::lerp(first, second, t).normalized()
    }

    /// Calculates the spherical linear interpolation between two quaternions.
    ///
    /// # Remarks
    ///
    /// While slerp is generally the go-to method for interpolating quaternions, it's computationaly
    /// expensive and has some undesirable properties. `Quaternion::nlerp()` is often more appropriate unless it's
    /// absolutely necessary that the interpolation have a constant velocity. For a better discussion
    /// of the different methods of interpolating quaternions see [this article by Jonathan Blow]
    /// (http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/).
    pub fn slerp(first: Quaternion, second: Quaternion, t: f32) -> Quaternion {
        assert!(first.is_normalized());
        assert!(second.is_normalized());

        // Compute the cosine of the angle between the two vectors.
        let dot = Quaternion::dot(first, second);

        const DOT_THRESHOLD: f32 = 0.9995;
        if dot > DOT_THRESHOLD {
            // If the inputs are too close for comfort, linearly interpolate
            // and normalize the result.
            return Quaternion::nlerp(first, second, t);
        }

        dot.clamp(-1.0, 1.0);     // Robustness: Stay within domain of acos()
        let theta_0 = dot.acos(); // theta_0 = angle between input vectors
        let theta = theta_0 * t;  // theta = angle between first and result

        let normal = (second.sub(first).mul(dot)).normalized(); // { first, normal } is now an orthonormal basis

        // TODO: We shouldn't need to normalize here since both inputs are normalized,
        //       the result was introducing error. Figure out if there's something else we
        //       can do to improve accuracy.
        //      first *   theta.cos()  +   normal *   theta.sin()
        return (first.mul(theta.cos()).add(normal.mul(theta.sin()))).normalized();
    }

    fn mul(self, rhs: f32) -> Quaternion {
        Quaternion {
            w: self.w * rhs,
            x: self.x * rhs,
            y: self.y * rhs,
            z: self.z * rhs,
        }
    }

    fn sub(self, rhs: Quaternion) -> Quaternion {
        Quaternion {
            w: self.w - rhs.w,
            x: self.x - rhs.x,
            y: self.y - rhs.y,
            z: self.z - rhs.z,
        }
    }

    fn add(self, rhs: Quaternion) -> Quaternion {
        Quaternion {
            w: self.w + rhs.w,
            x: self.x + rhs.x,
            y: self.y + rhs.y,
            z: self.z + rhs.z,
        }
    }
}

impl Default for Quaternion {
    fn default() -> Quaternion {
        Quaternion::identity()
    }
}

impl Mul<Quaternion> for Quaternion {
    type Output = Quaternion;

    fn mul(self, rhs: Quaternion) -> Quaternion {
        assert!(self.is_normalized());
        assert!(rhs.is_normalized());

        Quaternion {
            w: (self.w * rhs.w) - (self.x * rhs.x) - (self.y * rhs.y) - (self.z * rhs.z),
            x: (self.w * rhs.x) + (self.x * rhs.w) + (self.y * rhs.z) - (self.z * rhs.y),
            y: (self.w * rhs.y) - (self.x * rhs.z) + (self.y * rhs.w) + (self.z * rhs.x),
            z: (self.w * rhs.z) + (self.x * rhs.y) - (self.y * rhs.x) + (self.z * rhs.w),
        }.normalized()
    }
}

impl MulAssign<Quaternion> for Quaternion {
    fn mul_assign(&mut self, rhs: Quaternion) {
        *self = *self * rhs; // TODO: No temp object? We'll have to see if LLVM can optimize it away.
    }
}

// TODO: impl Mul<Vector3> for Quaternion (or maybe other way around).

impl IsZero for Quaternion {
    fn is_zero(self) -> bool {
        (self.w * self.w
       + self.x * self.x
       + self.y * self.y
       + self.z * self.z).is_zero()
    }
}
<commit_msg>Implement quaternion * vector multiplication<commit_after>/// Quaternion math used to represent orientation/rotation in 3D space.
///
/// TODO: Expand on the mathy stuff:
/// - "Quaternion" really means "unit quaternion", since that's the only case we care about.
/// - Multiplication means composing two rotations.
/// - "Grassman product" is technically the type of multiplication used.
/// - Multiplying by a `Vector3` rotates the vector.
/// - Concatenation happens left-to-right, e.g. `v * q1 * q2 * q3` rotates `v` by `q1`, then `q2`,
///   then `q3`. In theory that order shouldn't really matter, right? Rotation is commutative?

use std::ops::{Mul, MulAssign};
use std::f32::consts::PI;

use vector::Vector3;
use matrix::*;
use super::{IsZero, Clamp, Dot};

#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Quaternion {
    pub w: f32,
    pub x: f32,
    pub y: f32,
    pub z: f32,
}

impl Quaternion {
    /// Creates an identity quaternion.
    ///
    /// The identity quaternion is the quaternion that can be multiplied into any other quaternion
    /// without changing it.
    pub fn identity() -> Quaternion {
        Quaternion {
            w: 1.0,
            x: 0.0,
            y: 0.0,
            z: 0.0,
        }
    }

    /// Creates a quaternion from an axis and a rotation around that axis.
    ///
    /// # Params
    ///
    /// - axis - The axis being used to represent the rotation. This should
    ///   be normalized before being passed into `axis_angle()`.
    pub fn axis_angle(axis: Vector3, angle: f32) -> Quaternion {
        assert!(axis.is_normalized());

        let s = (angle * 0.5).sin();
        Quaternion {
            w: (angle * 0.5).cos(),
            x: s * axis.x,
            y: s * axis.y,
            z: s * axis.z,
        }.normalized()
    }

    /// Creates a quaternion that rotates an object to look in the specified direction.
    pub fn look_rotation(forward: Vector3, up: Vector3) -> Quaternion {
        assert!(!forward.is_zero());
        assert!(!up.is_zero());

        let source = Vector3::forward();
        let forward = forward.normalized();
        let up = up.normalized();

        let dot = source.dot(forward);

        if (dot + 1.0).is_zero() {
            // vector a and b point exactly in the opposite direction,
            // so it is a 180 degrees turn around the up-axis
            return Quaternion::axis_angle(up, PI)
        }

        if (dot - 1.0).is_zero() {
            // Vector a and b point exactly in the same direction
            // so we return the identity quaternion.
            return Quaternion::identity()
        }

        let rot_angle = dot.acos();
        let rot_axis = Vector3::cross(source, forward).normalized();// source.cross(forward).normalized();
        return Quaternion::axis_angle(rot_axis, rot_angle)

        // TODO: Correctly take the up vector into account.
    }

    /// Creates a quaternion from a set of euler angles.
    pub fn from_eulers(x: f32, y: f32, z: f32) -> Quaternion {
        Quaternion::axis_angle(Vector3::new(1.0, 0.0, 0.0), x)
      * Quaternion::axis_angle(Vector3::new(0.0, 1.0, 0.0), y)
      * Quaternion::axis_angle(Vector3::new(0.0, 0.0, 1.0), z)
    }

    pub fn from_vector3(angles: Vector3) -> Quaternion {
        Quaternion::from_eulers(angles.x, angles.y, angles.z)
    }

    /// Converts the quaternion to the corresponding rotation matrix.
    pub fn as_matrix4(self) -> Matrix4 {
        Matrix4::from_quaternion(self)
    }

    pub fn as_matrix3(self) -> Matrix3 {
        Matrix3::from_quaternion(self)
    }

    /// Retrieves the rotation represented by the quaternion as a rotation about an axis.
    ///
    /// The returned axis will always be normalized.
    pub fn as_axis_angle(&self) -> (Vector3, f32) {
        assert!(self.is_normalized());

        let angle = 2.0 * self.w.acos();
        let s = (1.0 - self.w * self.w).sqrt();
        if s.is_zero() {
            // If s is 0, axis is arbitrary.
            (Vector3::new(1.0, 0.0, 0.0), angle)
        } else {
            (Vector3::new(self.x / s, self.y / s, self.z / s).normalized(), angle)
        }
    }

    /// Retrieves the rotation represented by the quaternion as euler angles.
    pub fn as_eulers(&self) -> Vector3 {
        assert!(self.is_normalized());

        let x = f32::atan2(
            2.0 * (self.w * self.x + self.y * self.z),
            1.0 - 2.0 * (self.x * self.x + self.y * self.y));
        let y = (2.0 * (self.w * self.y - self.z * self.x)).asin();
        let z = f32::atan2(
            2.0 * (self.w * self.z + self.x * self.y),
            1.0 - 2.0 * (self.y * self.y + self.z * self.z));

        Vector3::new(x, y, z)
    }

    /// Normalizes the quaternion to unit length.
    ///
    /// The quaternion must not have a length of zero when calling this method.
    pub fn normalize(&mut self) {
        assert!(!self.is_zero());

        let length = (self.w * self.w
                    + self.x * self.x
                    + self.y * self.y
                    + self.z * self.z).sqrt();

        self.w /= length;
        self.x /= length;
        self.y /= length;
        self.z /= length;
    }

    /// Creates a normalized copy of the quaternion.
    ///
    /// The quaternion must not have a length of zero when calling this method.
    pub fn normalized(&self) -> Quaternion {
        let mut temp = *self;
        temp.normalize();
        temp
    }

    /// Determines if the quaternion is normalized (has a length of 1.0).
    pub fn is_normalized(&self) -> bool {
        let mag_sqrd = Quaternion::dot(*self, *self);
        (mag_sqrd - 1.0).is_zero()
    }

    pub fn repeat(&self, repeat: f32) -> Quaternion {
        let (axis, angle) = self.as_axis_angle();
        Quaternion::axis_angle(axis, angle * repeat)
    }

    /// Calculates the dot product of two quaternions.
    pub fn dot(first: Quaternion, second: Quaternion) -> f32 {
        (first.w * second.w
       + first.x * second.x
       + first.y * second.y
       + first.z * second.z)
    }

    /// Interpolates linearly between two quaternions.
    ///
    /// # Remarks
    ///
    /// This method does not necessarily result in a normalized Quaternion, so the result should
    /// not be used directly to represent a rotation. If you would like to lerp two rotation
    /// quaternions use `Quaternion::nlerp()`.
    pub fn lerp(first: Quaternion, second: Quaternion, t: f32) -> Quaternion {
        // first + t * (second - first)
        second.sub(first).mul(t).add(first)
    }

    /// Interpolates linearly between two quaternions using a normalized lerp.
    pub fn nlerp(first: Quaternion, second: Quaternion, t: f32) -> Quaternion {
        Quaternion::lerp(first, second, t).normalized()
    }

    /// Calculates the spherical linear interpolation between two quaternions.
    ///
    /// # Remarks
    ///
    /// While slerp is generally the go-to method for interpolating quaternions, it's computationaly
    /// expensive and has some undesirable properties. `Quaternion::nlerp()` is often more appropriate unless it's
    /// absolutely necessary that the interpolation have a constant velocity. For a better discussion
    /// of the different methods of interpolating quaternions see [this article by Jonathan Blow]
    /// (http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/).
    pub fn slerp(first: Quaternion, second: Quaternion, t: f32) -> Quaternion {
        assert!(first.is_normalized());
        assert!(second.is_normalized());

        // Compute the cosine of the angle between the two vectors.
        let dot = Quaternion::dot(first, second);

        const DOT_THRESHOLD: f32 = 0.9995;
        if dot > DOT_THRESHOLD {
            // If the inputs are too close for comfort, linearly interpolate
            // and normalize the result.
            return Quaternion::nlerp(first, second, t);
        }

        dot.clamp(-1.0, 1.0);     // Robustness: Stay within domain of acos()
        let theta_0 = dot.acos(); // theta_0 = angle between input vectors
        let theta = theta_0 * t;  // theta = angle between first and result

        let normal = (second.sub(first).mul(dot)).normalized(); // { first, normal } is now an orthonormal basis

        // TODO: We shouldn't need to normalize here since both inputs are normalized,
        //       the result was introducing error. Figure out if there's something else we
        //       can do to improve accuracy.
        //      first *   theta.cos()  +   normal *   theta.sin()
        return (first.mul(theta.cos()).add(normal.mul(theta.sin()))).normalized();
    }

    /// Calculates the quaternion representing the opposite rotation.
    pub fn inverse(self) -> Quaternion {
        Quaternion {
            w: self.w,
            x: -self.x,
            y: -self.y,
            z: -self.z,
        }
    }

    fn mul(self, rhs: f32) -> Quaternion {
        Quaternion {
            w: self.w * rhs,
            x: self.x * rhs,
            y: self.y * rhs,
            z: self.z * rhs,
        }
    }

    fn sub(self, rhs: Quaternion) -> Quaternion {
        Quaternion {
            w: self.w - rhs.w,
            x: self.x - rhs.x,
            y: self.y - rhs.y,
            z: self.z - rhs.z,
        }
    }

    fn add(self, rhs: Quaternion) -> Quaternion {
        Quaternion {
            w: self.w + rhs.w,
            x: self.x + rhs.x,
            y: self.y + rhs.y,
            z: self.z + rhs.z,
        }
    }
}

impl Default for Quaternion {
    fn default() -> Quaternion {
        Quaternion::identity()
    }
}

impl Mul<Quaternion> for Quaternion {
    type Output = Quaternion;

    fn mul(self, rhs: Quaternion) -> Quaternion {
        assert!(self.is_normalized());
        assert!(rhs.is_normalized());

        Quaternion {
            w: (self.w * rhs.w) - (self.x * rhs.x) - (self.y * rhs.y) - (self.z * rhs.z),
            x: (self.w * rhs.x) + (self.x * rhs.w) + (self.y * rhs.z) - (self.z * rhs.y),
            y: (self.w * rhs.y) - (self.x * rhs.z) + (self.y * rhs.w) + (self.z * rhs.x),
            z: (self.w * rhs.z) + (self.x * rhs.y) - (self.y * rhs.x) + (self.z * rhs.w),
        }.normalized()
    }
}

impl MulAssign<Quaternion> for Quaternion {
    fn mul_assign(&mut self, rhs: Quaternion) {
        *self = *self * rhs; // TODO: No temp object? We'll have to see if LLVM can optimize it away.
    }
}

impl Mul<Vector3> for Quaternion {
    type Output = Vector3;

    fn mul(self, rhs: Vector3) -> Vector3 {
        let rhs_quat = Quaternion::from_vector3(rhs);
        let result_quat = self * rhs_quat * self.inverse();
        Vector3::new(result_quat.x, result_quat.y, result_quat.z)
    }
}

// TODO: impl Mul<Vector3> for Quaternion (or maybe other way around).

impl From<Vector3> for Quaternion {
    fn from(from: Vector3) -> Quaternion {
        Quaternion::from_vector3(from)
    }
}

impl IsZero for Quaternion {
    fn is_zero(self) -> bool {
        (self.w * self.w
       + self.x * self.x
       + self.y * self.y
       + self.z * self.z).is_zero()
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use std::fs;
use std::io::{BufRead, BufReader, Write};
use std::iter::Enumerate;
use std::path::{Path, PathBuf};

use super::{print_mismatches, write_message, DIFF_CONTEXT_SIZE};
use crate::config::{Config, EmitMode, Verbosity};
use crate::rustfmt_diff::{make_diff, Mismatch};
use crate::{Input, Session};

const CONFIGURATIONS_FILE_NAME: &str = "Configurations.md";

// This enum is used to represent one of three text features in Configurations.md: a block of code
// with its starting line number, the name of a rustfmt configuration option, or the value of a
// rustfmt configuration option.
enum ConfigurationSection {
    CodeBlock((String, u32)), // (String: block of code, u32: line number of code block start)
    ConfigName(String),
    ConfigValue(String),
}

impl ConfigurationSection {
    fn get_section<I: Iterator<Item = String>>(
        file: &mut Enumerate<I>,
    ) -> Option<ConfigurationSection> {
        lazy_static! {
            static ref CONFIG_NAME_REGEX: regex::Regex =
                regex::Regex::new(r"^## `([^`]+)`").expect("failed creating configuration pattern");
            static ref CONFIG_VALUE_REGEX: regex::Regex =
                regex::Regex::new(r#"^#### `"?([^`"]+)"?`"#)
                    .expect("failed creating configuration value pattern");
        }

        loop {
            match file.next() {
                Some((i, line)) => {
                    if line.starts_with("```rust") {
                        // Get the lines of the code block.
                        let lines: Vec<String> = file
                            .map(|(_i, l)| l)
                            .take_while(|l| !l.starts_with("```"))
                            .collect();
                        let block = format!("{}\n", lines.join("\n"));

                        // +1 to translate to one-based indexing
                        // +1 to get to first line of code (line after "```")
                        let start_line = (i + 2) as u32;

                        return Some(ConfigurationSection::CodeBlock((block, start_line)));
                    } else if let Some(c) = CONFIG_NAME_REGEX.captures(&line) {
                        return Some(ConfigurationSection::ConfigName(String::from(&c[1])));
                    } else if let Some(c) = CONFIG_VALUE_REGEX.captures(&line) {
                        return Some(ConfigurationSection::ConfigValue(String::from(&c[1])));
                    }
                }
                None => return None, // reached the end of the file
            }
        }
    }
}

// This struct stores the information about code blocks in the configurations
// file, formats the code blocks, and prints formatting errors.
struct ConfigCodeBlock {
    config_name: Option<String>,
    config_value: Option<String>,
    code_block: Option<String>,
    code_block_start: Option<u32>,
}

impl ConfigCodeBlock {
    fn new() -> ConfigCodeBlock {
        ConfigCodeBlock {
            config_name: None,
            config_value: None,
            code_block: None,
            code_block_start: None,
        }
    }

    fn set_config_name(&mut self, name: Option<String>) {
        self.config_name = name;
        self.config_value = None;
    }

    fn set_config_value(&mut self, value: Option<String>) {
        self.config_value = value;
    }

    fn set_code_block(&mut self, code_block: String, code_block_start: u32) {
        self.code_block = Some(code_block);
        self.code_block_start = Some(code_block_start);
    }

    fn get_block_config(&self) -> Config {
        let mut config = Config::default();
        config.set().verbose(Verbosity::Quiet);
        if self.config_name.is_some() && self.config_value.is_some() {
            config.override_value(
                self.config_name.as_ref().unwrap(),
                self.config_value.as_ref().unwrap(),
            );
        }
        config
    }

    fn code_block_valid(&self) -> bool {
        // We never expect to not have a code block.
        assert!(self.code_block.is_some() && self.code_block_start.is_some());

        // See if code block begins with #![rustfmt::skip].
        let fmt_skip = self.fmt_skip();

        if self.config_name.is_none() && !fmt_skip {
            write_message(&format!(
                "No configuration name for {}:{}",
                CONFIGURATIONS_FILE_NAME,
                self.code_block_start.unwrap()
            ));
            return false;
        }
        if self.config_value.is_none() && !fmt_skip {
            write_message(&format!(
                "No configuration value for {}:{}",
                CONFIGURATIONS_FILE_NAME,
                self.code_block_start.unwrap()
            ));
            return false;
        }
        true
    }

    /// True if the code block starts with #![rustfmt::skip]
    fn fmt_skip(&self) -> bool {
        self.code_block
            .as_ref()
            .unwrap()
            .lines()
            .nth(0)
            .unwrap_or("")
            == "#![rustfmt::skip]"
    }

    fn has_parsing_errors<T: Write>(&self, session: &Session<'_, T>) -> bool {
        if session.has_parsing_errors() {
            write_message(&format!(
                "\u{261d}\u{1f3fd} Cannot format {}:{}",
                CONFIGURATIONS_FILE_NAME,
                self.code_block_start.unwrap()
            ));
            return true;
        }

        false
    }

    fn print_diff(&self, compare: Vec<Mismatch>) {
        let mut mismatches = HashMap::new();
        mismatches.insert(PathBuf::from(CONFIGURATIONS_FILE_NAME), compare);
        print_mismatches(mismatches, |line_num| {
            format!(
                "\nMismatch at {}:{}:",
                CONFIGURATIONS_FILE_NAME,
                line_num + self.code_block_start.unwrap() - 1
            )
        });
    }

    fn formatted_has_diff(&self, text: &str) -> bool {
        let compare = make_diff(self.code_block.as_ref().unwrap(), text, DIFF_CONTEXT_SIZE);
        if !compare.is_empty() {
            self.print_diff(compare);
            return true;
        }

        false
    }

    // Return a bool indicating if formatting this code block is an idempotent
    // operation. This function also triggers printing any formatting failure
    // messages.
    fn formatted_is_idempotent(&self) -> bool {
        // Verify that we have all of the expected information.
        if !self.code_block_valid() {
            return false;
        }

        let input = Input::Text(self.code_block.as_ref().unwrap().to_owned());
        let mut config = self.get_block_config();
        config.set().emit_mode(EmitMode::Stdout);
        let mut buf: Vec<u8> = vec![];

        {
            let mut session = Session::new(config, Some(&mut buf));
            session.format(input).unwrap();
            if self.has_parsing_errors(&session) {
                return false;
            }
        }

        !self.formatted_has_diff(&String::from_utf8(buf).unwrap())
    }

    // Extract a code block from the iterator. Behavior:
    // - Rust code blocks are identifed by lines beginning with "```rust".
    // - One explicit configuration setting is supported per code block.
    // - Rust code blocks with no configuration setting are illegal and cause an
    //   assertion failure, unless the snippet begins with #![rustfmt::skip].
    // - Configuration names in Configurations.md must be in the form of
    //   "## `NAME`".
    // - Configuration values in Configurations.md must be in the form of
    //   "#### `VALUE`".
    fn extract<I: Iterator<Item = String>>(
        file: &mut Enumerate<I>,
        prev: Option<&ConfigCodeBlock>,
        hash_set: &mut HashSet<String>,
    ) -> Option<ConfigCodeBlock> {
        let mut code_block = ConfigCodeBlock::new();
        code_block.config_name = prev.and_then(|cb| cb.config_name.clone());

        loop {
            match ConfigurationSection::get_section(file) {
                Some(ConfigurationSection::CodeBlock((block, start_line))) => {
                    code_block.set_code_block(block, start_line);
                    break;
                }
                Some(ConfigurationSection::ConfigName(name)) => {
                    assert!(
                        Config::is_valid_name(&name),
                        "an unknown configuration option was found: {}",
                        name
                    );
                    assert!(
                        hash_set.remove(&name),
                        "multiple configuration guides found for option {}",
                        name
                    );
                    code_block.set_config_name(Some(name));
                }
                Some(ConfigurationSection::ConfigValue(value)) => {
                    code_block.set_config_value(Some(value));
                }
                None => return None, // end of file was reached
            }
        }

        Some(code_block)
    }
}

#[test]
fn configuration_snippet_tests() {
    super::init_log();
    let blocks = get_code_blocks();
    let failures = blocks
        .iter()
        .filter(|block| !block.fmt_skip())
        .map(ConfigCodeBlock::formatted_is_idempotent)
        .fold(0, |acc, r| acc + (!r as u32));

    // Display results.
    println!("Ran {} configurations tests.", blocks.len());
    assert_eq!(failures, 0, "{} configurations tests failed", failures);
}

// Read Configurations.md and build a `Vec` of `ConfigCodeBlock` structs with one
// entry for each Rust code block found.
fn get_code_blocks() -> Vec<ConfigCodeBlock> {
    let mut file_iter = BufReader::new(
        fs::File::open(Path::new(CONFIGURATIONS_FILE_NAME))
            .unwrap_or_else(|_| panic!("couldn't read file {}", CONFIGURATIONS_FILE_NAME)),
    )
    .lines()
    .map(Result::unwrap)
    .enumerate();
    let mut code_blocks: Vec<ConfigCodeBlock> = Vec::new();
    let mut hash_set = Config::hash_set();

    while let Some(cb) = ConfigCodeBlock::extract(&mut file_iter, code_blocks.last(), &mut hash_set)
    {
        code_blocks.push(cb);
    }

    for name in hash_set {
        if !Config::is_hidden_option(&name) {
            panic!("{} does not have a configuration guide", name);
        }
    }

    code_blocks
}
<commit_msg>Add test to verify tracking issue links<commit_after>use std::collections::{HashMap, HashSet};
use std::fs;
use std::io::{BufRead, BufReader, Write};
use std::iter::Enumerate;
use std::path::{Path, PathBuf};

use super::{print_mismatches, write_message, DIFF_CONTEXT_SIZE};
use crate::config::{Config, EmitMode, Verbosity};
use crate::rustfmt_diff::{make_diff, Mismatch};
use crate::{Input, Session};

const CONFIGURATIONS_FILE_NAME: &str = "Configurations.md";

// This enum is used to represent one of three text features in Configurations.md: a block of code
// with its starting line number, the name of a rustfmt configuration option, or the value of a
// rustfmt configuration option.
enum ConfigurationSection {
    CodeBlock((String, u32)), // (String: block of code, u32: line number of code block start)
    ConfigName(String),
    ConfigValue(String),
}

impl ConfigurationSection {
    fn get_section<I: Iterator<Item = String>>(
        file: &mut Enumerate<I>,
    ) -> Option<ConfigurationSection> {
        lazy_static! {
            static ref CONFIG_NAME_REGEX: regex::Regex =
                regex::Regex::new(r"^## `([^`]+)`").expect("failed creating configuration pattern");
            static ref CONFIG_VALUE_REGEX: regex::Regex =
                regex::Regex::new(r#"^#### `"?([^`"]+)"?`"#)
                    .expect("failed creating configuration value pattern");
        }

        loop {
            match file.next() {
                Some((i, line)) => {
                    if line.starts_with("```rust") {
                        // Get the lines of the code block.
                        let lines: Vec<String> = file
                            .map(|(_i, l)| l)
                            .take_while(|l| !l.starts_with("```"))
                            .collect();
                        let block = format!("{}\n", lines.join("\n"));

                        // +1 to translate to one-based indexing
                        // +1 to get to first line of code (line after "```")
                        let start_line = (i + 2) as u32;

                        return Some(ConfigurationSection::CodeBlock((block, start_line)));
                    } else if let Some(c) = CONFIG_NAME_REGEX.captures(&line) {
                        return Some(ConfigurationSection::ConfigName(String::from(&c[1])));
                    } else if let Some(c) = CONFIG_VALUE_REGEX.captures(&line) {
                        return Some(ConfigurationSection::ConfigValue(String::from(&c[1])));
                    }
                }
                None => return None, // reached the end of the file
            }
        }
    }
}

// This struct stores the information about code blocks in the configurations
// file, formats the code blocks, and prints formatting errors.
struct ConfigCodeBlock {
    config_name: Option<String>,
    config_value: Option<String>,
    code_block: Option<String>,
    code_block_start: Option<u32>,
}

impl ConfigCodeBlock {
    fn new() -> ConfigCodeBlock {
        ConfigCodeBlock {
            config_name: None,
            config_value: None,
            code_block: None,
            code_block_start: None,
        }
    }

    fn set_config_name(&mut self, name: Option<String>) {
        self.config_name = name;
        self.config_value = None;
    }

    fn set_config_value(&mut self, value: Option<String>) {
        self.config_value = value;
    }

    fn set_code_block(&mut self, code_block: String, code_block_start: u32) {
        self.code_block = Some(code_block);
        self.code_block_start = Some(code_block_start);
    }

    fn get_block_config(&self) -> Config {
        let mut config = Config::default();
        config.set().verbose(Verbosity::Quiet);
        if self.config_name.is_some() && self.config_value.is_some() {
            config.override_value(
                self.config_name.as_ref().unwrap(),
                self.config_value.as_ref().unwrap(),
            );
        }
        config
    }

    fn code_block_valid(&self) -> bool {
        // We never expect to not have a code block.
        assert!(self.code_block.is_some() && self.code_block_start.is_some());

        // See if code block begins with #![rustfmt::skip].
        let fmt_skip = self.fmt_skip();

        if self.config_name.is_none() && !fmt_skip {
            write_message(&format!(
                "No configuration name for {}:{}",
                CONFIGURATIONS_FILE_NAME,
                self.code_block_start.unwrap()
            ));
            return false;
        }
        if self.config_value.is_none() && !fmt_skip {
            write_message(&format!(
                "No configuration value for {}:{}",
                CONFIGURATIONS_FILE_NAME,
                self.code_block_start.unwrap()
            ));
            return false;
        }
        true
    }

    /// True if the code block starts with #![rustfmt::skip]
    fn fmt_skip(&self) -> bool {
        self.code_block
            .as_ref()
            .unwrap()
            .lines()
            .nth(0)
            .unwrap_or("")
            == "#![rustfmt::skip]"
    }

    fn has_parsing_errors<T: Write>(&self, session: &Session<'_, T>) -> bool {
        if session.has_parsing_errors() {
            write_message(&format!(
                "\u{261d}\u{1f3fd} Cannot format {}:{}",
                CONFIGURATIONS_FILE_NAME,
                self.code_block_start.unwrap()
            ));
            return true;
        }

        false
    }

    fn print_diff(&self, compare: Vec<Mismatch>) {
        let mut mismatches = HashMap::new();
        mismatches.insert(PathBuf::from(CONFIGURATIONS_FILE_NAME), compare);
        print_mismatches(mismatches, |line_num| {
            format!(
                "\nMismatch at {}:{}:",
                CONFIGURATIONS_FILE_NAME,
                line_num + self.code_block_start.unwrap() - 1
            )
        });
    }

    fn formatted_has_diff(&self, text: &str) -> bool {
        let compare = make_diff(self.code_block.as_ref().unwrap(), text, DIFF_CONTEXT_SIZE);
        if !compare.is_empty() {
            self.print_diff(compare);
            return true;
        }

        false
    }

    // Return a bool indicating if formatting this code block is an idempotent
    // operation. This function also triggers printing any formatting failure
    // messages.
    fn formatted_is_idempotent(&self) -> bool {
        // Verify that we have all of the expected information.
        if !self.code_block_valid() {
            return false;
        }

        let input = Input::Text(self.code_block.as_ref().unwrap().to_owned());
        let mut config = self.get_block_config();
        config.set().emit_mode(EmitMode::Stdout);
        let mut buf: Vec<u8> = vec![];

        {
            let mut session = Session::new(config, Some(&mut buf));
            session.format(input).unwrap();
            if self.has_parsing_errors(&session) {
                return false;
            }
        }

        !self.formatted_has_diff(&String::from_utf8(buf).unwrap())
    }

    // Extract a code block from the iterator. Behavior:
    // - Rust code blocks are identifed by lines beginning with "```rust".
    // - One explicit configuration setting is supported per code block.
    // - Rust code blocks with no configuration setting are illegal and cause an
    //   assertion failure, unless the snippet begins with #![rustfmt::skip].
    // - Configuration names in Configurations.md must be in the form of
    //   "## `NAME`".
    // - Configuration values in Configurations.md must be in the form of
    //   "#### `VALUE`".
    fn extract<I: Iterator<Item = String>>(
        file: &mut Enumerate<I>,
        prev: Option<&ConfigCodeBlock>,
        hash_set: &mut HashSet<String>,
    ) -> Option<ConfigCodeBlock> {
        let mut code_block = ConfigCodeBlock::new();
        code_block.config_name = prev.and_then(|cb| cb.config_name.clone());

        loop {
            match ConfigurationSection::get_section(file) {
                Some(ConfigurationSection::CodeBlock((block, start_line))) => {
                    code_block.set_code_block(block, start_line);
                    break;
                }
                Some(ConfigurationSection::ConfigName(name)) => {
                    assert!(
                        Config::is_valid_name(&name),
                        "an unknown configuration option was found: {}",
                        name
                    );
                    assert!(
                        hash_set.remove(&name),
                        "multiple configuration guides found for option {}",
                        name
                    );
                    code_block.set_config_name(Some(name));
                }
                Some(ConfigurationSection::ConfigValue(value)) => {
                    code_block.set_config_value(Some(value));
                }
                None => return None, // end of file was reached
            }
        }

        Some(code_block)
    }
}

#[test]
fn configuration_snippet_tests() {
    super::init_log();
    let blocks = get_code_blocks();
    let failures = blocks
        .iter()
        .filter(|block| !block.fmt_skip())
        .map(ConfigCodeBlock::formatted_is_idempotent)
        .fold(0, |acc, r| acc + (!r as u32));

    // Display results.
    println!("Ran {} configurations tests.", blocks.len());
    assert_eq!(failures, 0, "{} configurations tests failed", failures);
}

// Read Configurations.md and build a `Vec` of `ConfigCodeBlock` structs with one
// entry for each Rust code block found.
fn get_code_blocks() -> Vec<ConfigCodeBlock> {
    let mut file_iter = BufReader::new(
        fs::File::open(Path::new(CONFIGURATIONS_FILE_NAME))
            .unwrap_or_else(|_| panic!("couldn't read file {}", CONFIGURATIONS_FILE_NAME)),
    )
    .lines()
    .map(Result::unwrap)
    .enumerate();
    let mut code_blocks: Vec<ConfigCodeBlock> = Vec::new();
    let mut hash_set = Config::hash_set();

    while let Some(cb) = ConfigCodeBlock::extract(&mut file_iter, code_blocks.last(), &mut hash_set)
    {
        code_blocks.push(cb);
    }

    for name in hash_set {
        if !Config::is_hidden_option(&name) {
            panic!("{} does not have a configuration guide", name);
        }
    }

    code_blocks
}

#[test]
fn check_unstable_option_tracking_issue_numbers() {
    // Ensure that tracking issue links point to the correct issue number
    let tracking_issue =
        regex::Regex::new(r"\(tracking issue: \[#(?P<number>\d+)\]\((?P<link>\S+)\)\)")
            .expect("failed creating configuration pattern");

    let lines = BufReader::new(
        fs::File::open(Path::new(CONFIGURATIONS_FILE_NAME))
            .unwrap_or_else(|_| panic!("couldn't read file {}", CONFIGURATIONS_FILE_NAME)),
    )
    .lines()
    .map(Result::unwrap)
    .enumerate();

    for (idx, line) in lines {
        if let Some(capture) = tracking_issue.captures(&line) {
            let number = capture.name("number").unwrap().as_str();
            let link = capture.name("link").unwrap().as_str();
            assert!(
                link.ends_with(number),
                "{} on line {} does not point to issue #{}",
                link,
                idx + 1,
                number,
            );
        }
    }
}
<|endoftext|>


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

//! Consensus for the Libra Core blockchain
//!
//! Encapsulates public consensus traits and any implementations of those traits.
//! Currently, the only consensus protocol supported is LibraBFT (based on
//! [HotStuff](https://arxiv.org/pdf/1803.05069.pdf)).

#![deny(missing_docs)]
#![feature(async_await, slice_patterns)]
#![feature(checked_duration_since)]
#![recursion_limit = "128"]
#[macro_use]
extern crate failure;

mod chained_bft;
mod util;

/// Defines the public consensus provider traits to implement for
/// use in the Libra Core blockchain.
pub mod consensus_provider;

mod counters;

mod state_computer;
mod state_replication;
mod state_synchronizer;
mod txn_manager;
<commit_msg>[consensus] remove slice_patterns feature<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! Consensus for the Libra Core blockchain
//!
//! Encapsulates public consensus traits and any implementations of those traits.
//! Currently, the only consensus protocol supported is LibraBFT (based on
//! [HotStuff](https://arxiv.org/pdf/1803.05069.pdf)).

#![deny(missing_docs)]
#![feature(async_await)]
#![feature(checked_duration_since)]
#![recursion_limit = "128"]
#[macro_use]
extern crate failure;

mod chained_bft;
mod util;

/// Defines the public consensus provider traits to implement for
/// use in the Libra Core blockchain.
pub mod consensus_provider;

mod counters;

mod state_computer;
mod state_replication;
mod state_synchronizer;
mod txn_manager;
<|endoftext|>


<commit_before>// Test for for diagnostic improvement issue #76547
// edition:2018

use std::{
    future::Future,
    task::{Context, Poll}
};
use std::pin::Pin;

pub struct ListFut<'a>(&'a mut [&'a mut [u8]]);
impl<'a> Future for ListFut<'a> {
    type Output = ();

    fn poll(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<Self::Output> {
        unimplemented!()
    }
}

async fn fut(bufs: &mut [&mut [u8]]) {
    ListFut(bufs).await
    //~^ ERROR lifetime mismatch
}

pub struct ListFut2<'a>(&'a mut [&'a mut [u8]]);
impl<'a> Future for ListFut2<'a> {
    type Output = i32;

    fn poll(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<Self::Output> {
        unimplemented!()
    }
}

async fn fut2(bufs: &mut [&mut [u8]]) -> i32 {
    ListFut2(bufs).await
    //~^ ERROR lifetime mismatch
}

fn main() {}
<commit_msg>Update src/test/ui/issues/issue-76547.rs<commit_after>// Test for diagnostic improvement issue #76547
// edition:2018

use std::{
    future::Future,
    task::{Context, Poll}
};
use std::pin::Pin;

pub struct ListFut<'a>(&'a mut [&'a mut [u8]]);
impl<'a> Future for ListFut<'a> {
    type Output = ();

    fn poll(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<Self::Output> {
        unimplemented!()
    }
}

async fn fut(bufs: &mut [&mut [u8]]) {
    ListFut(bufs).await
    //~^ ERROR lifetime mismatch
}

pub struct ListFut2<'a>(&'a mut [&'a mut [u8]]);
impl<'a> Future for ListFut2<'a> {
    type Output = i32;

    fn poll(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<Self::Output> {
        unimplemented!()
    }
}

async fn fut2(bufs: &mut [&mut [u8]]) -> i32 {
    ListFut2(bufs).await
    //~^ ERROR lifetime mismatch
}

fn main() {}
<|endoftext|>


<commit_before>extern crate sysfs_gpio;
extern crate sysfs_pwm;

use self::sysfs_gpio::{Direction, Pin};
use self::sysfs_pwm::{Pwm};
use ::std::error::Error;

#[test]
fn it_works() {
    assert_eq!(1, 0+1);
}

//http://www.jumpnowtek.com/rpi/Using-the-Raspberry-Pi-Hardware-PWM-timers.html
//https://github.com/rust-embedded/rust-sysfs-pwm/blob/master/examples/breathe.rs
#[test]
#[ignore]
fn test_pwm() {
    let pwm = Pwm::new(0, 0).unwrap();
    pwm.export().unwrap();
    pwm.enable(true).unwrap();
    pwm.set_period_ns(10000000).unwrap();
    pwm.set_duty_cycle_ns(8000000).unwrap();
    pwm.enable(false).unwrap();
    pwm.unexport().unwrap()
}<commit_msg>asserts<commit_after>extern crate sysfs_gpio;
extern crate sysfs_pwm;

use self::sysfs_gpio::{Direction, Pin};
use self::sysfs_pwm::{Pwm};
use ::std::error::Error;

#[test]
fn it_works() {
    assert_eq!(1, 0+1);
}

//http://www.jumpnowtek.com/rpi/Using-the-Raspberry-Pi-Hardware-PWM-timers.html
//https://github.com/rust-embedded/rust-sysfs-pwm/blob/master/examples/breathe.rs
#[test]
#[ignore]
fn test_pwm() {
    let pwm = Pwm::new(0, 0).unwrap();
    assert!(pwm.export().unwrap().is_ok());
    assert!(pwm.enable(true).unwrap().is_ok());
    assert!(pwm.set_period_ns(10000000).unwrap().is_ok());
    assert!(pwm.set_duty_cycle_ns(8000000).unwrap().is_ok());
    assert!(pwm.enable(false).unwrap().is_ok());
    assert!(pwm.unexport().unwrap().is_ok());
}<|endoftext|>