<commit_before>//
// Copyright (c) 2011-2017, UDI Contributors
// All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
#![deny(warnings)]

extern crate goblin;

use std::collections::HashMap;
use std::fs::File;
use std::io::Write;
use std::io::Read;
use std::path::PathBuf;
use std::process::Command;

const SIMPLE_BINARY: &'static str =
    "simple-debug-noopt-dynamic.cd52194667df0781720ff834a56df134fef7fb51";

const WAITTHREAD_BINARY: &'static str =
    "waitthread-debug-noopt-dynamic.9bb7ace83d00e653b003e05b15ee7f9944c7f261";

pub fn setup(out_path: &PathBuf, url: &str) {
    let dest_path = out_path.join("native-file-tests.zip");

    Command::new("curl").arg("-sSf")
                        .arg("-o")
                        .arg(dest_path.to_str().unwrap())
                        .arg(url)
                        .spawn()
                        .expect("Failed to start download of native file tests zip")
                        .wait()
                        .expect("Failed to download native file tests zip");

    let dest_dir = out_path.join("native-file-tests");
    Command::new("unzip").arg("-j")
                         .arg(dest_path.to_str().unwrap())
                         .arg("-d")
                         .arg(dest_dir.to_str().unwrap())
                         .spawn()
                         .expect("Failed to start extract of native file tests zip")
                         .wait()
                         .expect("Failed to extract native file tests zip");

    let simple_path = dest_dir.join(SIMPLE_BINARY);
    let waitthread_path = dest_dir.join(WAITTHREAD_BINARY);

    let mod_file_path = out_path.join("native_file_tests.rs");
    let mut mod_file = File::create(&mod_file_path).unwrap();

    let symbols = build_symbols(&dest_dir);

    let sym_defs = symbols.iter()
                          .map(|e| format!("pub const {}: u64 = {};\n", e.0, e.1))
                          .fold("".to_owned(), |acc, elem| acc + &elem);

    let mod_file_content = format!("
pub const SIMPLE_EXEC_PATH: &'static str = \"{}\";
pub const WAITTHREAD_EXEC_PATH: &'static str = \"{}\";

{}
",
    simple_path.to_str().unwrap(),
    waitthread_path.to_str().unwrap(),
    sym_defs);

    mod_file.write_all(&mod_file_content.into_bytes())
            .expect("Failed to write native file tests module");
}

fn build_symbols(dest_dir: &PathBuf) -> HashMap<&str, String> {
    let mut symbols = HashMap::new();

    add_simple_binary_symbols(dest_dir, &mut symbols);
    add_waitthread_binary_symbols(dest_dir, &mut symbols);

    symbols
}

fn add_simple_binary_symbols(dest_dir: &PathBuf, symbols: &mut HashMap<&str, String>) {
    let path = dest_dir.join(SIMPLE_BINARY);

    for_each_symbols(&path, |name, value, size| {
        if name == "function1" {
            symbols.insert("SIMPLE_FUNCTION1", format!("0x{:x}", value));
        } else if name == "function2" {
            symbols.insert("SIMPLE_FUNCTION2", format!("0x{:x}", value));
            symbols.insert("SIMPLE_FUNCTION2_LENGTH", size.to_string());
        }
    });
}

fn add_waitthread_binary_symbols(dest_dir: &PathBuf, symbols: &mut HashMap<&str, String>) {
    let path = dest_dir.join(WAITTHREAD_BINARY);

    for_each_symbols(&path, |name, value, _| {
        if name == "breakpoint_func" {
            symbols.insert("THREAD_BREAK_FUNC", format!("0x{:x}", value));
        }
    });
}

fn for_each_symbols<F>(path: &PathBuf, mut func: F)
    where F: FnMut(&String, u64, u64) {

    let mut binary_file = File::open(&path).expect(&format!("Symbol file {:?} error",
                                                           path));
    let mut buffer = vec![];
    binary_file.read_to_end(&mut buffer).unwrap();

    match goblin::parse(&buffer).unwrap() {
        goblin::Object::Elf(elf) => {
            let strtab = &(elf.strtab);
            for sym in &(elf.syms) {
                func(&(strtab.get(sym.st_name).unwrap().to_owned()),
                     sym.st_value,
                     sym.st_size);
            }
        },
        _ => {
            panic!(format!("Unsupported file type"));
        }
    }
}
<commit_msg>Update rust utility to use local copy of zip if available.<commit_after>//
// Copyright (c) 2011-2017, UDI Contributors
// All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
#![deny(warnings)]

extern crate goblin;

use std::collections::HashMap;
use std::fs::File;
use std::io::Write;
use std::io::Read;
use std::path::PathBuf;
use std::process::Command;

const SIMPLE_BINARY: &'static str =
    "simple-debug-noopt-dynamic.cd52194667df0781720ff834a56df134fef7fb51";

const WAITTHREAD_BINARY: &'static str =
    "waitthread-debug-noopt-dynamic.9bb7ace83d00e653b003e05b15ee7f9944c7f261";

const ZIP_NAME: &'static str = "native-file-tests.zip";

pub fn setup(out_path: &PathBuf, manifest_dir: &PathBuf, url: &str) {

    let dest_path = out_path.join(ZIP_NAME);

    // Only download the zip if it's not present in the manifest directory
    let manifest_zip_path = manifest_dir.join(ZIP_NAME);
    if manifest_zip_path.exists() {
        Command::new("cp").arg(manifest_zip_path.to_str().unwrap())
                          .arg(dest_path.to_str().unwrap())
                          .spawn()
                          .expect("Failed to start copy of native file tests zip")
                          .wait()
                          .expect("Failed to copy of native file tests zip");
    } else {
        Command::new("curl").arg("-sSf")
                            .arg("-o")
                            .arg(dest_path.to_str().unwrap())
                            .arg(url)
                            .spawn()
                            .expect("Failed to start download of native file tests zip")
                            .wait()
                            .expect("Failed to download native file tests zip");
    }

    let dest_dir = out_path.join("native-file-tests");
    Command::new("unzip").arg("-j")
                         .arg(dest_path.to_str().unwrap())
                         .arg("-d")
                         .arg(dest_dir.to_str().unwrap())
                         .spawn()
                         .expect("Failed to start extract of native file tests zip")
                         .wait()
                         .expect("Failed to extract native file tests zip");

    let simple_path = dest_dir.join(SIMPLE_BINARY);
    let waitthread_path = dest_dir.join(WAITTHREAD_BINARY);

    let mod_file_path = out_path.join("native_file_tests.rs");
    let mut mod_file = File::create(&mod_file_path).unwrap();

    let symbols = build_symbols(&dest_dir);

    let sym_defs = symbols.iter()
                          .map(|e| format!("pub const {}: u64 = {};\n", e.0, e.1))
                          .fold("".to_owned(), |acc, elem| acc + &elem);

    let mod_file_content = format!("
pub const SIMPLE_EXEC_PATH: &'static str = \"{}\";
pub const WAITTHREAD_EXEC_PATH: &'static str = \"{}\";

{}
",
    simple_path.to_str().unwrap(),
    waitthread_path.to_str().unwrap(),
    sym_defs);

    mod_file.write_all(&mod_file_content.into_bytes())
            .expect("Failed to write native file tests module");
}

fn build_symbols(dest_dir: &PathBuf) -> HashMap<&str, String> {
    let mut symbols = HashMap::new();

    add_simple_binary_symbols(dest_dir, &mut symbols);
    add_waitthread_binary_symbols(dest_dir, &mut symbols);

    symbols
}

fn add_simple_binary_symbols(dest_dir: &PathBuf, symbols: &mut HashMap<&str, String>) {
    let path = dest_dir.join(SIMPLE_BINARY);

    for_each_symbols(&path, |name, value, size| {
        if name == "function1" {
            symbols.insert("SIMPLE_FUNCTION1", format!("0x{:x}", value));
        } else if name == "function2" {
            symbols.insert("SIMPLE_FUNCTION2", format!("0x{:x}", value));
            symbols.insert("SIMPLE_FUNCTION2_LENGTH", size.to_string());
        }
    });
}

fn add_waitthread_binary_symbols(dest_dir: &PathBuf, symbols: &mut HashMap<&str, String>) {
    let path = dest_dir.join(WAITTHREAD_BINARY);

    for_each_symbols(&path, |name, value, _| {
        if name == "breakpoint_func" {
            symbols.insert("THREAD_BREAK_FUNC", format!("0x{:x}", value));
        }
    });
}

fn for_each_symbols<F>(path: &PathBuf, mut func: F)
    where F: FnMut(&String, u64, u64) {

    let mut binary_file = File::open(&path).expect(&format!("Symbol file {:?} error",
                                                           path));
    let mut buffer = vec![];
    binary_file.read_to_end(&mut buffer).unwrap();

    match goblin::parse(&buffer).unwrap() {
        goblin::Object::Elf(elf) => {
            let strtab = &(elf.strtab);
            for sym in &(elf.syms) {
                func(&(strtab.get(sym.st_name).unwrap().to_owned()),
                     sym.st_value,
                     sym.st_size);
            }
        },
        _ => {
            panic!(format!("Unsupported file type"));
        }
    }
}
<|endoftext|>


<commit_before>use formats::FORMATS;
use once_cell::sync::Lazy;
use parser::{
    eyre::{bail, Result},
    graph_triples::{Pairs, Relation},
    Parser, ParserTrait,
};
use std::path::Path;
use std::sync::Arc;

// Re-exports for convenience elsewhere
pub use parser::ParseOptions;

// The following high level functions hide the implementation
// detail of having a static list of parsers. They are intended as the
// only public interface for this crate.

pub fn parse<P: AsRef<Path>>(path: P, code: &str, language: &str) -> Result<Pairs> {
    PARSERS.parse(path, code, language)
}

/// The set of registered parsers in the current process
static PARSERS: Lazy<Arc<Parsers>> = Lazy::new(|| Arc::new(Parsers::new()));

/// A set of registered parsers, either built-in, or provided by plugins
struct Parsers {
    inner: Vec<Parser>,
}

/// A macro to dispatch methods to builtin parsers
///
/// This avoids having to do a search over the parsers's specs for matching `languages`.
macro_rules! dispatch_builtins {
    ($var:expr, $method:ident $(,$arg:expr)*) => {
        match $var.as_str() {
            #[cfg(feature = "calc")]
            "calc" => Some(parser_calc::CalcParser::$method($($arg),*)),
            #[cfg(feature = "js")]
            "js" => Some(parser_js::JsParser::$method($($arg),*)),
            #[cfg(feature = "py")]
            "py" => Some(parser_py::PyParser::$method($($arg),*)),
            #[cfg(feature = "r")]
            "r" => Some(parser_r::RParser::$method($($arg),*)),
            #[cfg(feature = "ts")]
            "ts" => Some(parser_ts::TsParser::$method($($arg),*)),
            _ => None
        }
    };
}

impl Parsers {
    /// Create a set of parsers
    pub fn new() -> Self {
        let inner = vec![
            #[cfg(feature = "calc")]
            parser_calc::CalcParser::spec(),
            #[cfg(feature = "js")]
            parser_js::JsParser::spec(),
            #[cfg(feature = "py")]
            parser_py::PyParser::spec(),
            #[cfg(feature = "r")]
            parser_r::RParser::spec(),
            #[cfg(feature = "ts")]
            parser_ts::TsParser::spec(),
        ];

        Self { inner }
    }

    /// List the available parsers
    fn list(&self) -> Vec<String> {
        self.inner
            .iter()
            .map(|spec| spec.language.clone())
            .collect()
    }

    /// Get a parser by label
    fn get(&self, label: &str) -> Result<Parser> {
        let index = label.parse::<usize>()?;
        match self.inner.get(index) {
            Some(parser) => Ok(parser.clone()),
            None => bail!("No parser with label `{}`", label),
        }
    }

    /// Parse code in a particular language
    fn parse<P: AsRef<Path>>(&self, path: P, code: &str, language: &str) -> Result<Pairs> {
        let path = path.as_ref();
        let format = FORMATS.match_name(language);

        let pairs = if let Some(result) = dispatch_builtins!(format.name, parse, path, code) {
            result?
        } else {
            bail!(
                "Unable to parse code in language `{}`: no matching parser found",
                format.name
            )
        };

        // Normalize pairs by removing any `Uses` of locally assigned variables
        let mut normalized: Pairs = Vec::with_capacity(pairs.len());
        for (relation, object) in pairs {
            let mut include = true;
            if matches!(relation, Relation::Use(..)) {
                for (other_relation, other_object) in &normalized {
                    if matches!(other_relation, Relation::Assign(..)) && *other_object == object {
                        include = false;
                        break;
                    }
                }
            }
            if !include {
                continue;
            }

            normalized.push((relation, object))
        }
        Ok(normalized)
    }
}

impl Default for Parsers {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(feature = "cli")]
pub mod commands {
    use super::*;
    use cli_utils::{async_trait::async_trait, result, Result, Run};
    use structopt::StructOpt;

    #[derive(Debug, StructOpt)]
    #[structopt(
        about = "Manage parsers",
        setting = structopt::clap::AppSettings::ColoredHelp,
        setting = structopt::clap::AppSettings::VersionlessSubcommands
    )]
    pub struct Command {
        #[structopt(subcommand)]
        pub action: Action,
    }

    #[derive(Debug, StructOpt)]
    #[structopt(
        setting = structopt::clap::AppSettings::DeriveDisplayOrder
    )]
    pub enum Action {
        List(List),
        Show(Show),
    }

    #[async_trait]
    impl Run for Command {
        async fn run(&self) -> Result {
            let Self { action } = self;
            match action {
                Action::List(action) => action.run().await,
                Action::Show(action) => action.run().await,
            }
        }
    }

    /// List the parsers that are available
    ///
    /// The list of available parsers includes those that are built into the Stencila
    /// binary as well as any parsers provided by plugins.
    #[derive(Debug, StructOpt)]
    #[structopt(
        setting = structopt::clap::AppSettings::ColoredHelp
    )]
    pub struct List {}
    #[async_trait]
    impl Run for List {
        async fn run(&self) -> Result {
            let list = PARSERS.list();
            result::value(list)
        }
    }

    /// Show the specifications of a parser
    #[derive(Debug, StructOpt)]
    #[structopt(
        setting = structopt::clap::AppSettings::ColoredHelp
    )]
    pub struct Show {
        /// The label of the parser
        ///
        /// To get the list of parser labels use `stencila parsers list`.
        label: String,
    }
    #[async_trait]
    impl Run for Show {
        async fn run(&self) -> Result {
            let parser = PARSERS.get(&self.label)?;
            result::value(parser)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use parser::graph_triples::{relations, resources};
    use std::path::PathBuf;
    use test_utils::assert_json_eq;

    #[test]
    fn test_parse() -> Result<()> {
        let path = PathBuf::from("<test>");
        let pairs = parse(&path, "a = 1\nb = a * a", "calc")?;
        assert_json_eq!(
            pairs,
            vec![
                (
                    relations::assigns((0, 0, 0, 1)),
                    resources::symbol(&path, "a", "Number")
                ),
                (
                    relations::assigns((1, 0, 1, 1)),
                    resources::symbol(&path, "b", "Number")
                )
            ]
        );
        Ok(())
    }
}
<commit_msg>fix(Parsers): Get parser by label<commit_after>use formats::FORMATS;
use once_cell::sync::Lazy;
use parser::{
    eyre::{bail, Result},
    graph_triples::{Pairs, Relation},
    Parser, ParserTrait,
};
use std::sync::Arc;
use std::{collections::BTreeMap, path::Path};

// Re-exports for convenience elsewhere
pub use parser::ParseOptions;

// The following high level functions hide the implementation
// detail of having a static list of parsers. They are intended as the
// only public interface for this crate.

pub fn parse<P: AsRef<Path>>(path: P, code: &str, language: &str) -> Result<Pairs> {
    PARSERS.parse(path, code, language)
}

/// The set of registered parsers in the current process
static PARSERS: Lazy<Arc<Parsers>> = Lazy::new(|| Arc::new(Parsers::new()));

/// A set of registered parsers, either built-in, or provided by plugins
struct Parsers {
    inner: BTreeMap<String, Parser>,
}

/// A macro to dispatch methods to builtin parsers
///
/// This avoids having to do a search over the parsers's specs for matching `languages`.
macro_rules! dispatch_builtins {
    ($var:expr, $method:ident $(,$arg:expr)*) => {
        match $var.as_str() {
            #[cfg(feature = "calc")]
            "calc" => Some(parser_calc::CalcParser::$method($($arg),*)),
            #[cfg(feature = "js")]
            "js" => Some(parser_js::JsParser::$method($($arg),*)),
            #[cfg(feature = "py")]
            "py" => Some(parser_py::PyParser::$method($($arg),*)),
            #[cfg(feature = "r")]
            "r" => Some(parser_r::RParser::$method($($arg),*)),
            #[cfg(feature = "ts")]
            "ts" => Some(parser_ts::TsParser::$method($($arg),*)),
            _ => None
        }
    };
}

impl Parsers {
    /// Create a set of parsers
    pub fn new() -> Self {
        let inner = vec![
            #[cfg(feature = "calc")]
            ("calc", parser_calc::CalcParser::spec()),
            #[cfg(feature = "js")]
            ("js", parser_js::JsParser::spec()),
            #[cfg(feature = "py")]
            ("py", parser_py::PyParser::spec()),
            #[cfg(feature = "r")]
            ("r", parser_r::RParser::spec()),
            #[cfg(feature = "ts")]
            ("ts", parser_ts::TsParser::spec()),
        ]
        .into_iter()
        .map(|(label, parser)| (label.to_string(), parser))
        .collect();

        Self { inner }
    }

    /// List the available parsers
    fn list(&self) -> Vec<String> {
        self.inner
            .keys()
            .into_iter()
            .cloned()
            .collect::<Vec<String>>()
    }

    /// Get a parser by label
    fn get(&self, label: &str) -> Result<Parser> {
        match self.inner.get(label) {
            Some(parser) => Ok(parser.clone()),
            None => bail!("No parser with label `{}`", label),
        }
    }

    /// Parse code in a particular language
    fn parse<P: AsRef<Path>>(&self, path: P, code: &str, language: &str) -> Result<Pairs> {
        let path = path.as_ref();
        let format = FORMATS.match_name(language);

        let pairs = if let Some(result) = dispatch_builtins!(format.name, parse, path, code) {
            result?
        } else {
            bail!(
                "Unable to parse code in language `{}`: no matching parser found",
                format.name
            )
        };

        // Normalize pairs by removing any `Uses` of locally assigned variables
        let mut normalized: Pairs = Vec::with_capacity(pairs.len());
        for (relation, object) in pairs {
            let mut include = true;
            if matches!(relation, Relation::Use(..)) {
                for (other_relation, other_object) in &normalized {
                    if matches!(other_relation, Relation::Assign(..)) && *other_object == object {
                        include = false;
                        break;
                    }
                }
            }
            if !include {
                continue;
            }

            normalized.push((relation, object))
        }
        Ok(normalized)
    }
}

impl Default for Parsers {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(feature = "cli")]
pub mod commands {
    use super::*;
    use cli_utils::{async_trait::async_trait, result, Result, Run};
    use structopt::StructOpt;

    #[derive(Debug, StructOpt)]
    #[structopt(
        about = "Manage parsers",
        setting = structopt::clap::AppSettings::ColoredHelp,
        setting = structopt::clap::AppSettings::VersionlessSubcommands
    )]
    pub struct Command {
        #[structopt(subcommand)]
        pub action: Action,
    }

    #[derive(Debug, StructOpt)]
    #[structopt(
        setting = structopt::clap::AppSettings::DeriveDisplayOrder
    )]
    pub enum Action {
        List(List),
        Show(Show),
    }

    #[async_trait]
    impl Run for Command {
        async fn run(&self) -> Result {
            let Self { action } = self;
            match action {
                Action::List(action) => action.run().await,
                Action::Show(action) => action.run().await,
            }
        }
    }

    /// List the parsers that are available
    ///
    /// The list of available parsers includes those that are built into the Stencila
    /// binary as well as any parsers provided by plugins.
    #[derive(Debug, StructOpt)]
    #[structopt(
        setting = structopt::clap::AppSettings::ColoredHelp
    )]
    pub struct List {}
    #[async_trait]
    impl Run for List {
        async fn run(&self) -> Result {
            let list = PARSERS.list();
            result::value(list)
        }
    }

    /// Show the specifications of a parser
    #[derive(Debug, StructOpt)]
    #[structopt(
        setting = structopt::clap::AppSettings::ColoredHelp
    )]
    pub struct Show {
        /// The label of the parser
        ///
        /// To get the list of parser labels use `stencila parsers list`.
        label: String,
    }
    #[async_trait]
    impl Run for Show {
        async fn run(&self) -> Result {
            let parser = PARSERS.get(&self.label)?;
            result::value(parser)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use parser::graph_triples::{relations, resources};
    use std::path::PathBuf;
    use test_utils::assert_json_eq;

    #[test]
    fn test_parse() -> Result<()> {
        let path = PathBuf::from("<test>");
        let pairs = parse(&path, "a = 1\nb = a * a", "calc")?;
        assert_json_eq!(
            pairs,
            vec![
                (
                    relations::assigns((0, 0, 0, 1)),
                    resources::symbol(&path, "a", "Number")
                ),
                (
                    relations::assigns((1, 0, 1, 1)),
                    resources::symbol(&path, "b", "Number")
                )
            ]
        );
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! Propagate `Qualif`s between locals and query the results.
//!
//! This also contains the dataflow analysis used to track `Qualif`s on complex control-flow
//! graphs.

use rustc::mir::visit::Visitor;
use rustc::mir::{self, BasicBlock, Local, Location};
use rustc_data_structures::bit_set::BitSet;

use std::cell::RefCell;
use std::marker::PhantomData;

use crate::dataflow::{self as old_dataflow, generic as dataflow};
use super::{Item, Qualif};
use self::old_dataflow::IndirectlyMutableLocals;

/// A `Visitor` that propagates qualifs between locals. This defines the transfer function of
/// `FlowSensitiveAnalysis` as well as the logic underlying `TempPromotionResolver`.
///
/// This transfer does nothing when encountering an indirect assignment. Consumers should rely on
/// the `IndirectlyMutableLocals` dataflow pass to see if a `Local` may have become qualified via
/// an indirect assignment or function call.
struct TransferFunction<'a, 'mir, 'tcx, Q> {
    item: &'a Item<'mir, 'tcx>,
    qualifs_per_local: &'a mut BitSet<Local>,

    _qualif: PhantomData<Q>,
}

impl<Q> TransferFunction<'a, 'mir, 'tcx, Q>
where
    Q: Qualif,
{
    fn new(
        item: &'a Item<'mir, 'tcx>,
        qualifs_per_local: &'a mut BitSet<Local>,
    ) -> Self {
        TransferFunction {
            item,
            qualifs_per_local,
            _qualif: PhantomData,
        }
    }

    fn initialize_state(&mut self) {
        self.qualifs_per_local.clear();

        for arg in self.item.body.args_iter() {
            let arg_ty = self.item.body.local_decls[arg].ty;
            if Q::in_any_value_of_ty(self.item, arg_ty) {
                self.qualifs_per_local.insert(arg);
            }
        }
    }

    fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, value: bool) {
        debug_assert!(!place.is_indirect());

        match (value, place) {
            (true, mir::Place { base: mir::PlaceBase::Local(local), .. }) => {
                self.qualifs_per_local.insert(*local);
            }

            // For now, we do not clear the qualif if a local is overwritten in full by
            // an unqualified rvalue (e.g. `y = 5`). This is to be consistent
            // with aggregates where we overwrite all fields with assignments, which would not
            // get this feature.
            (false, mir::Place { base: mir::PlaceBase::Local(_local), projection: box [] }) => {
                // self.qualifs_per_local.remove(*local);
            }

            _ => {}
        }
    }

    fn apply_call_return_effect(
        &mut self,
        _block: BasicBlock,
        func: &mir::Operand<'tcx>,
        args: &[mir::Operand<'tcx>],
        return_place: &mir::Place<'tcx>,
    ) {
        let return_ty = return_place.ty(self.item.body, self.item.tcx).ty;
        let qualif = Q::in_call(self.item, &mut self.qualifs_per_local, func, args, return_ty);
        if !return_place.is_indirect() {
            self.assign_qualif_direct(return_place, qualif);
        }
    }
}

impl<Q> Visitor<'tcx> for TransferFunction<'_, '_, 'tcx, Q>
where
    Q: Qualif,
{
    fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
        self.super_operand(operand, location);

        if !Q::IS_CLEARED_ON_MOVE {
            return;
        }

        // If a local with no projections is moved from (e.g. `x` in `y = x`), record that
        // it no longer needs to be dropped.
        if let mir::Operand::Move(mir::Place {
            base: mir::PlaceBase::Local(local),
            projection: box [],
        }) = *operand {
            self.qualifs_per_local.remove(local);
        }
    }

    fn visit_assign(
        &mut self,
        place: &mir::Place<'tcx>,
        rvalue: &mir::Rvalue<'tcx>,
        location: Location,
    ) {
        let qualif = Q::in_rvalue(self.item, self.qualifs_per_local, rvalue);
        if !place.is_indirect() {
            self.assign_qualif_direct(place, qualif);
        }

        // We need to assign qualifs to the left-hand side before visiting `rvalue` since
        // qualifs can be cleared on move.
        self.super_assign(place, rvalue, location);
    }

    fn visit_terminator_kind(&mut self, kind: &mir::TerminatorKind<'tcx>, location: Location) {
        // The effect of assignment to the return place in `TerminatorKind::Call` is not applied
        // here; that occurs in `apply_call_return_effect`.

        if let mir::TerminatorKind::DropAndReplace { value, location: dest, .. } = kind {
            let qualif = Q::in_operand(self.item, self.qualifs_per_local, value);
            if !dest.is_indirect() {
                self.assign_qualif_direct(dest, qualif);
            }
        }

        // We need to assign qualifs to the dropped location before visiting the operand that
        // replaces it since qualifs can be cleared on move.
        self.super_terminator_kind(kind, location);
    }
}

/// Types that can compute the qualifs of each local at each location in a `mir::Body`.
///
/// Code that wishes to use a `QualifResolver` must call `visit_{statement,terminator}` for each
/// statement or terminator, processing blocks in reverse post-order beginning from the
/// `START_BLOCK`. Calling code may optionally call `get` after visiting each statement or
/// terminator to query the qualification state immediately before that statement or terminator.
///
/// These conditions are much more restrictive than woud be required by `FlowSensitiveResolver`
/// alone. This is to allow a linear, on-demand `TempPromotionResolver` that can operate
/// efficiently on simple CFGs.
pub trait QualifResolver<Q> {
    /// Get the qualifs of each local at the last location visited.
    ///
    /// This takes `&mut self` so qualifs can be computed lazily.
    fn get(&mut self) -> &BitSet<Local>;

    /// A convenience method for `self.get().contains(local)`.
    fn contains(&mut self, local: Local) -> bool {
        self.get().contains(local)
    }

    /// Resets the resolver to the `START_BLOCK`. This allows a resolver to be reused
    /// for multiple passes over a `mir::Body`.
    fn reset(&mut self);
}

pub type IndirectlyMutableResults<'mir, 'tcx> =
    old_dataflow::DataflowResultsCursor<'mir, 'tcx, IndirectlyMutableLocals<'mir, 'tcx>>;

/// A resolver for qualifs that works on arbitrarily complex CFGs.
///
/// As soon as a `Local` becomes writable through a reference (as determined by the
/// `IndirectlyMutableLocals` dataflow pass), we must assume that it takes on all other qualifs
/// possible for its type. This is because no effort is made to track qualifs across indirect
/// assignments (e.g. `*p = x` or calls to opaque functions).
///
/// It is possible to be more precise here by waiting until an indirect assignment actually occurs
/// before marking a borrowed `Local` as qualified.
pub struct FlowSensitiveResolver<'a, 'mir, 'tcx, Q>
where
    Q: Qualif,
{
    location: Location,
    indirectly_mutable_locals: &'a RefCell<IndirectlyMutableResults<'mir, 'tcx>>,
    cursor: dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q>>,
    qualifs_per_local: BitSet<Local>,
}

impl<Q> FlowSensitiveResolver<'a, 'mir, 'tcx, Q>
where
    Q: Qualif,
{
    pub fn new(
        _: Q,
        item: &'a Item<'mir, 'tcx>,
        indirectly_mutable_locals: &'a RefCell<IndirectlyMutableResults<'mir, 'tcx>>,
        dead_unwinds: &BitSet<BasicBlock>,
    ) -> Self {
        let analysis = FlowSensitiveAnalysis {
            item,
            _qualif: PhantomData,
        };
        let results =
            dataflow::Engine::new(item.body, dead_unwinds, analysis).iterate_to_fixpoint();
        let cursor = dataflow::ResultsCursor::new(item.body, results);

        FlowSensitiveResolver {
            cursor,
            indirectly_mutable_locals,
            qualifs_per_local: BitSet::new_empty(item.body.local_decls.len()),
            location: Location { block: mir::START_BLOCK, statement_index: 0 },
        }
    }
}

impl<Q> Visitor<'tcx> for FlowSensitiveResolver<'_, '_, 'tcx, Q>
where
    Q: Qualif
{
    fn visit_statement(&mut self, _: &mir::Statement<'tcx>, location: Location) {
        self.location = location;
    }

    fn visit_terminator(&mut self, _: &mir::Terminator<'tcx>, location: Location) {
        self.location = location;
    }
}

impl<Q> QualifResolver<Q> for FlowSensitiveResolver<'_, '_, '_, Q>
where
    Q: Qualif
{
    fn get(&mut self) -> &BitSet<Local> {
        let mut indirectly_mutable_locals = self.indirectly_mutable_locals.borrow_mut();

        indirectly_mutable_locals.seek(self.location);
        self.cursor.seek_before(self.location);

        self.qualifs_per_local.overwrite(indirectly_mutable_locals.get());
        self.qualifs_per_local.union(self.cursor.get());
        &self.qualifs_per_local
    }

    fn contains(&mut self, local: Local) -> bool {
        self.cursor.seek_before(self.location);
        if self.cursor.get().contains(local) {
            return true;
        }

        let mut indirectly_mutable_locals = self.indirectly_mutable_locals.borrow_mut();
        indirectly_mutable_locals.seek(self.location);
        indirectly_mutable_locals.get().contains(local)
    }

    fn reset(&mut self)  {
        self.location = Location { block: mir::START_BLOCK, statement_index: 0 };
    }
}

/// The dataflow analysis used to propagate qualifs on arbitrary CFGs.
pub(super) struct FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q> {
    item: &'a Item<'mir, 'tcx>,
    _qualif: PhantomData<Q>,
}

impl<'a, 'mir, 'tcx, Q> FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q>
where
    Q: Qualif,
{
    fn transfer_function(
        &self,
        state: &'a mut BitSet<Local>,
    ) -> TransferFunction<'a, 'mir, 'tcx, Q> {
        TransferFunction::<Q>::new(self.item, state)
    }
}

impl<Q> old_dataflow::BottomValue for FlowSensitiveAnalysis<'_, '_, '_, Q> {
    const BOTTOM_VALUE: bool = false;
}

impl<Q> dataflow::Analysis<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
where
    Q: Qualif,
{
    type Idx = Local;

    const NAME: &'static str = "flow_sensitive_qualif";

    fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize {
        body.local_decls.len()
    }

    fn initialize_start_block(&self, _body: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) {
        self.transfer_function(state).initialize_state();
    }

    fn apply_statement_effect(
        &self,
        state: &mut BitSet<Self::Idx>,
        statement: &mir::Statement<'tcx>,
        location: Location,
    ) {
        self.transfer_function(state).visit_statement(statement, location);
    }

    fn apply_terminator_effect(
        &self,
        state: &mut BitSet<Self::Idx>,
        terminator: &mir::Terminator<'tcx>,
        location: Location,
    ) {
        self.transfer_function(state).visit_terminator(terminator, location);
    }

    fn apply_call_return_effect(
        &self,
        state: &mut BitSet<Self::Idx>,
        block: BasicBlock,
        func: &mir::Operand<'tcx>,
        args: &[mir::Operand<'tcx>],
        return_place: &mir::Place<'tcx>,
    ) {
        self.transfer_function(state).apply_call_return_effect(block, func, args, return_place)
    }
}
<commit_msg>Mask results from flow-sensitive resolver with `in_any_value_of_ty`<commit_after>//! Propagate `Qualif`s between locals and query the results.
//!
//! This also contains the dataflow analysis used to track `Qualif`s on complex control-flow
//! graphs.

use rustc::mir::visit::Visitor;
use rustc::mir::{self, BasicBlock, Local, Location};
use rustc_data_structures::bit_set::BitSet;

use std::cell::RefCell;
use std::marker::PhantomData;

use crate::dataflow::{self as old_dataflow, generic as dataflow};
use super::{Item, Qualif};
use self::old_dataflow::IndirectlyMutableLocals;

/// A `Visitor` that propagates qualifs between locals. This defines the transfer function of
/// `FlowSensitiveAnalysis` as well as the logic underlying `TempPromotionResolver`.
///
/// This transfer does nothing when encountering an indirect assignment. Consumers should rely on
/// the `IndirectlyMutableLocals` dataflow pass to see if a `Local` may have become qualified via
/// an indirect assignment or function call.
struct TransferFunction<'a, 'mir, 'tcx, Q> {
    item: &'a Item<'mir, 'tcx>,
    qualifs_per_local: &'a mut BitSet<Local>,

    _qualif: PhantomData<Q>,
}

impl<Q> TransferFunction<'a, 'mir, 'tcx, Q>
where
    Q: Qualif,
{
    fn new(
        item: &'a Item<'mir, 'tcx>,
        qualifs_per_local: &'a mut BitSet<Local>,
    ) -> Self {
        TransferFunction {
            item,
            qualifs_per_local,
            _qualif: PhantomData,
        }
    }

    fn initialize_state(&mut self) {
        self.qualifs_per_local.clear();

        for arg in self.item.body.args_iter() {
            let arg_ty = self.item.body.local_decls[arg].ty;
            if Q::in_any_value_of_ty(self.item, arg_ty) {
                self.qualifs_per_local.insert(arg);
            }
        }
    }

    fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, value: bool) {
        debug_assert!(!place.is_indirect());

        match (value, place) {
            (true, mir::Place { base: mir::PlaceBase::Local(local), .. }) => {
                self.qualifs_per_local.insert(*local);
            }

            // For now, we do not clear the qualif if a local is overwritten in full by
            // an unqualified rvalue (e.g. `y = 5`). This is to be consistent
            // with aggregates where we overwrite all fields with assignments, which would not
            // get this feature.
            (false, mir::Place { base: mir::PlaceBase::Local(_local), projection: box [] }) => {
                // self.qualifs_per_local.remove(*local);
            }

            _ => {}
        }
    }

    fn apply_call_return_effect(
        &mut self,
        _block: BasicBlock,
        func: &mir::Operand<'tcx>,
        args: &[mir::Operand<'tcx>],
        return_place: &mir::Place<'tcx>,
    ) {
        let return_ty = return_place.ty(self.item.body, self.item.tcx).ty;
        let qualif = Q::in_call(self.item, &mut self.qualifs_per_local, func, args, return_ty);
        if !return_place.is_indirect() {
            self.assign_qualif_direct(return_place, qualif);
        }
    }
}

impl<Q> Visitor<'tcx> for TransferFunction<'_, '_, 'tcx, Q>
where
    Q: Qualif,
{
    fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
        self.super_operand(operand, location);

        if !Q::IS_CLEARED_ON_MOVE {
            return;
        }

        // If a local with no projections is moved from (e.g. `x` in `y = x`), record that
        // it no longer needs to be dropped.
        if let mir::Operand::Move(mir::Place {
            base: mir::PlaceBase::Local(local),
            projection: box [],
        }) = *operand {
            self.qualifs_per_local.remove(local);
        }
    }

    fn visit_assign(
        &mut self,
        place: &mir::Place<'tcx>,
        rvalue: &mir::Rvalue<'tcx>,
        location: Location,
    ) {
        let qualif = Q::in_rvalue(self.item, self.qualifs_per_local, rvalue);
        if !place.is_indirect() {
            self.assign_qualif_direct(place, qualif);
        }

        // We need to assign qualifs to the left-hand side before visiting `rvalue` since
        // qualifs can be cleared on move.
        self.super_assign(place, rvalue, location);
    }

    fn visit_terminator_kind(&mut self, kind: &mir::TerminatorKind<'tcx>, location: Location) {
        // The effect of assignment to the return place in `TerminatorKind::Call` is not applied
        // here; that occurs in `apply_call_return_effect`.

        if let mir::TerminatorKind::DropAndReplace { value, location: dest, .. } = kind {
            let qualif = Q::in_operand(self.item, self.qualifs_per_local, value);
            if !dest.is_indirect() {
                self.assign_qualif_direct(dest, qualif);
            }
        }

        // We need to assign qualifs to the dropped location before visiting the operand that
        // replaces it since qualifs can be cleared on move.
        self.super_terminator_kind(kind, location);
    }
}

/// Types that can compute the qualifs of each local at each location in a `mir::Body`.
///
/// Code that wishes to use a `QualifResolver` must call `visit_{statement,terminator}` for each
/// statement or terminator, processing blocks in reverse post-order beginning from the
/// `START_BLOCK`. Calling code may optionally call `get` after visiting each statement or
/// terminator to query the qualification state immediately before that statement or terminator.
///
/// These conditions are much more restrictive than woud be required by `FlowSensitiveResolver`
/// alone. This is to allow a linear, on-demand `TempPromotionResolver` that can operate
/// efficiently on simple CFGs.
pub trait QualifResolver<Q> {
    /// Get the qualifs of each local at the last location visited.
    ///
    /// This takes `&mut self` so qualifs can be computed lazily.
    fn get(&mut self) -> &BitSet<Local>;

    /// A convenience method for `self.get().contains(local)`.
    fn contains(&mut self, local: Local) -> bool {
        self.get().contains(local)
    }

    /// Resets the resolver to the `START_BLOCK`. This allows a resolver to be reused
    /// for multiple passes over a `mir::Body`.
    fn reset(&mut self);
}

pub type IndirectlyMutableResults<'mir, 'tcx> =
    old_dataflow::DataflowResultsCursor<'mir, 'tcx, IndirectlyMutableLocals<'mir, 'tcx>>;

/// A resolver for qualifs that works on arbitrarily complex CFGs.
///
/// As soon as a `Local` becomes writable through a reference (as determined by the
/// `IndirectlyMutableLocals` dataflow pass), we must assume that it takes on all other qualifs
/// possible for its type. This is because no effort is made to track qualifs across indirect
/// assignments (e.g. `*p = x` or calls to opaque functions).
///
/// It is possible to be more precise here by waiting until an indirect assignment actually occurs
/// before marking a borrowed `Local` as qualified.
pub struct FlowSensitiveResolver<'a, 'mir, 'tcx, Q>
where
    Q: Qualif,
{
    location: Location,
    indirectly_mutable_locals: &'a RefCell<IndirectlyMutableResults<'mir, 'tcx>>,
    cursor: dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q>>,
    qualifs_per_local: BitSet<Local>,

    /// The value of `Q::in_any_value_of_ty` for each local.
    qualifs_in_any_value_of_ty: BitSet<Local>,
}

impl<Q> FlowSensitiveResolver<'a, 'mir, 'tcx, Q>
where
    Q: Qualif,
{
    pub fn new(
        _: Q,
        item: &'a Item<'mir, 'tcx>,
        indirectly_mutable_locals: &'a RefCell<IndirectlyMutableResults<'mir, 'tcx>>,
        dead_unwinds: &BitSet<BasicBlock>,
    ) -> Self {
        let analysis = FlowSensitiveAnalysis {
            item,
            _qualif: PhantomData,
        };
        let results =
            dataflow::Engine::new(item.body, dead_unwinds, analysis).iterate_to_fixpoint();
        let cursor = dataflow::ResultsCursor::new(item.body, results);

        let mut qualifs_in_any_value_of_ty = BitSet::new_empty(item.body.local_decls.len());
        for (local, decl) in item.body.local_decls.iter_enumerated() {
            if Q::in_any_value_of_ty(item, decl.ty) {
                qualifs_in_any_value_of_ty.insert(local);
            }
        }

        FlowSensitiveResolver {
            cursor,
            indirectly_mutable_locals,
            qualifs_per_local: BitSet::new_empty(item.body.local_decls.len()),
            qualifs_in_any_value_of_ty,
            location: Location { block: mir::START_BLOCK, statement_index: 0 },
        }
    }
}

impl<Q> Visitor<'tcx> for FlowSensitiveResolver<'_, '_, 'tcx, Q>
where
    Q: Qualif
{
    fn visit_statement(&mut self, _: &mir::Statement<'tcx>, location: Location) {
        self.location = location;
    }

    fn visit_terminator(&mut self, _: &mir::Terminator<'tcx>, location: Location) {
        self.location = location;
    }
}

impl<Q> QualifResolver<Q> for FlowSensitiveResolver<'_, '_, '_, Q>
where
    Q: Qualif
{
    fn get(&mut self) -> &BitSet<Local> {
        let mut indirectly_mutable_locals = self.indirectly_mutable_locals.borrow_mut();

        indirectly_mutable_locals.seek(self.location);
        self.cursor.seek_before(self.location);

        self.qualifs_per_local.overwrite(indirectly_mutable_locals.get());
        self.qualifs_per_local.union(self.cursor.get());
        self.qualifs_per_local.intersect(&self.qualifs_in_any_value_of_ty);
        &self.qualifs_per_local
    }

    fn contains(&mut self, local: Local) -> bool {
        // No need to update the cursor if we know that `Local` cannot possibly be qualified.
        if !self.qualifs_in_any_value_of_ty.contains(local) {
            return false;
        }

        // Otherwise, return `true` if this local is qualified or was indirectly mutable at any
        // point before this statement.
        self.cursor.seek_before(self.location);
        if self.cursor.get().contains(local) {
            return true;
        }

        let mut indirectly_mutable_locals = self.indirectly_mutable_locals.borrow_mut();
        indirectly_mutable_locals.seek(self.location);
        indirectly_mutable_locals.get().contains(local)
    }

    fn reset(&mut self)  {
        self.location = Location { block: mir::START_BLOCK, statement_index: 0 };
    }
}

/// The dataflow analysis used to propagate qualifs on arbitrary CFGs.
pub(super) struct FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q> {
    item: &'a Item<'mir, 'tcx>,
    _qualif: PhantomData<Q>,
}

impl<'a, 'mir, 'tcx, Q> FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q>
where
    Q: Qualif,
{
    fn transfer_function(
        &self,
        state: &'a mut BitSet<Local>,
    ) -> TransferFunction<'a, 'mir, 'tcx, Q> {
        TransferFunction::<Q>::new(self.item, state)
    }
}

impl<Q> old_dataflow::BottomValue for FlowSensitiveAnalysis<'_, '_, '_, Q> {
    const BOTTOM_VALUE: bool = false;
}

impl<Q> dataflow::Analysis<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
where
    Q: Qualif,
{
    type Idx = Local;

    const NAME: &'static str = "flow_sensitive_qualif";

    fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize {
        body.local_decls.len()
    }

    fn initialize_start_block(&self, _body: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) {
        self.transfer_function(state).initialize_state();
    }

    fn apply_statement_effect(
        &self,
        state: &mut BitSet<Self::Idx>,
        statement: &mir::Statement<'tcx>,
        location: Location,
    ) {
        self.transfer_function(state).visit_statement(statement, location);
    }

    fn apply_terminator_effect(
        &self,
        state: &mut BitSet<Self::Idx>,
        terminator: &mir::Terminator<'tcx>,
        location: Location,
    ) {
        self.transfer_function(state).visit_terminator(terminator, location);
    }

    fn apply_call_return_effect(
        &self,
        state: &mut BitSet<Self::Idx>,
        block: BasicBlock,
        func: &mir::Operand<'tcx>,
        args: &[mir::Operand<'tcx>],
        return_place: &mir::Place<'tcx>,
    ) {
        self.transfer_function(state).apply_call_return_effect(block, func, args, return_place)
    }
}
<|endoftext|>


<commit_before>//! AWS API requests.
//!
//! Wraps the Hyper library to send PUT, POST, DELETE and GET requests.

extern crate lazy_static;

use std::env;
use std::io::Read;
use std::io::Error as IoError;
use std::error::Error;
use std::fmt;
use std::collections::HashMap;

use hyper::Client;
use hyper::Error as HyperError;
use hyper::header::{Headers, UserAgent, ContentType};
use hyper::mime::{Mime, TopLevel, SubLevel};
use hyper::status::StatusCode;
use hyper::method::Method;

use log::LogLevel::Debug;

use signature::SignedRequest;

// Pulls in the statically generated rustc version.
include!(concat!(env!("OUT_DIR"), "/user_agent_vars.rs"));

// Use a lazy static to cache the default User-Agent header
// because it never changes once it's been computed.
lazy_static! {
    static ref DEFAULT_USER_AGENT: Vec<Vec<u8>> = vec![format!("rusoto/{} rust/{} {}",
            env!("CARGO_PKG_VERSION"), RUST_VERSION, env::consts::OS).as_bytes().to_vec()];
}
lazy_static! {
    static ref BINARY_RESPONSE_CONTENTS: ContentType = ContentType(Mime(TopLevel::Application, SubLevel::OctetStream, Vec::new()));
}

#[derive(Clone)]
pub struct HttpResponse {
    pub status: StatusCode,
    pub body: String,
    pub raw_body: Vec<u8>,
    pub headers: HashMap<String, String>
}

#[derive(Debug, PartialEq)]
pub struct HttpDispatchError {
    message: String
}

impl Error for HttpDispatchError {
    fn description(&self) -> &str {
        &self.message
    }
}

impl fmt::Display for HttpDispatchError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.message)
    }
}

impl From<HyperError> for HttpDispatchError {
    fn from(err: HyperError) -> HttpDispatchError {
        HttpDispatchError { message: err.description().to_string() }
    }
}

impl From<IoError> for HttpDispatchError {
    fn from(err: IoError) -> HttpDispatchError {
        HttpDispatchError { message: err.description().to_string() }
    }
}

pub trait DispatchSignedRequest {
    fn dispatch(&self, request: &SignedRequest) -> Result<HttpResponse, HttpDispatchError>;
}

impl DispatchSignedRequest for Client {
    fn dispatch(&self, request: &SignedRequest) -> Result<HttpResponse, HttpDispatchError> {
        let hyper_method = match request.method().as_ref() {
            "POST" => Method::Post,
            "PUT" => Method::Put,
            "DELETE" => Method::Delete,
            "GET" => Method::Get,
            "HEAD" => Method::Head,
            v => return Err(HttpDispatchError { message: format!("Unsupported HTTP verb {}", v) })
        };

        // translate the headers map to a format Hyper likes
        let mut hyper_headers = Headers::new();
        for h in request.headers().iter() {
            hyper_headers.set_raw(h.0.to_owned(), h.1.to_owned());
        }

        // Add a default user-agent header if one is not already present.
        if !hyper_headers.has::<UserAgent>() {
            hyper_headers.set_raw("user-agent".to_owned(), DEFAULT_USER_AGENT.clone());
        }

        let mut final_uri = format!("https://{}{}", request.hostname(), request.canonical_path());
        if !request.canonical_query_string().is_empty() {
            final_uri = final_uri + &format!("?{}", request.canonical_query_string());
        }

        if log_enabled!(Debug) {
            let payload = request.payload().map(|mut payload_bytes| {
                let mut payload_string = String::new();

                payload_bytes.read_to_string(&mut payload_string)
                    .map(|_| payload_string)
                    .unwrap_or_else(|_| String::from("<non-UTF-8 data>"))
            });

            debug!("Full request: \n method: {}\n final_uri: {}\n payload: {}\nHeaders:\n", hyper_method, final_uri, payload.unwrap_or("".to_owned()));
            for h in hyper_headers.iter() {
                debug!("{}:{}", h.name(), h.value_string());
            }
        }
        let mut hyper_response = match request.payload() {
            None => try!(self.request(hyper_method, &final_uri).headers(hyper_headers).body("").send()),
            Some(payload_contents) => try!(self.request(hyper_method, &final_uri).headers(hyper_headers).body(payload_contents).send()),
        };
        let mut body = String::new();
        let mut body_as_bytes : Vec<u8> = Vec::new();
        let response_is_binary = match hyper_response.headers.get::<ContentType>() {
            Some(content_type) => content_type.eq(&BINARY_RESPONSE_CONTENTS),
            None => false,
        };
        match response_is_binary {
            true => try!(hyper_response.read_to_end(&mut body_as_bytes)),
            false => try!(hyper_response.read_to_string(&mut body)),
        };

        if log_enabled!(Debug) {
            debug!("Response body:\n{}", body);
            debug!("Response raw_body:\n{:?}", body_as_bytes);
        }

        let mut headers: HashMap<String, String> = HashMap::new();

        for header in hyper_response.headers.iter() {
            headers.insert(header.name().to_string(), header.value_string());
        }

        Ok(HttpResponse {
            status: hyper_response.status.clone(),
            body: body,
            raw_body: body_as_bytes,
            headers: headers
        })

    }
}
<commit_msg>Extracts checking if response is binary.<commit_after>//! AWS API requests.
//!
//! Wraps the Hyper library to send PUT, POST, DELETE and GET requests.

extern crate lazy_static;

use std::env;
use std::io::Read;
use std::io::Error as IoError;
use std::error::Error;
use std::fmt;
use std::collections::HashMap;

use hyper::Client;
use hyper::Error as HyperError;
use hyper::header::{Headers, UserAgent, ContentType};
use hyper::mime::{Mime, TopLevel, SubLevel};
use hyper::status::StatusCode;
use hyper::method::Method;

use log::LogLevel::Debug;

use signature::SignedRequest;

// Pulls in the statically generated rustc version.
include!(concat!(env!("OUT_DIR"), "/user_agent_vars.rs"));

// Use a lazy static to cache the default User-Agent header
// because it never changes once it's been computed.
lazy_static! {
    static ref DEFAULT_USER_AGENT: Vec<Vec<u8>> = vec![format!("rusoto/{} rust/{} {}",
            env!("CARGO_PKG_VERSION"), RUST_VERSION, env::consts::OS).as_bytes().to_vec()];
}
lazy_static! {
    static ref BINARY_RESPONSE_CONTENTS: ContentType = ContentType(Mime(TopLevel::Application, SubLevel::OctetStream, Vec::new()));
}

#[derive(Clone)]
pub struct HttpResponse {
    pub status: StatusCode,
    pub body: String,
    pub raw_body: Vec<u8>,
    pub headers: HashMap<String, String>
}

#[derive(Debug, PartialEq)]
pub struct HttpDispatchError {
    message: String
}

impl Error for HttpDispatchError {
    fn description(&self) -> &str {
        &self.message
    }
}

impl fmt::Display for HttpDispatchError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.message)
    }
}

impl From<HyperError> for HttpDispatchError {
    fn from(err: HyperError) -> HttpDispatchError {
        HttpDispatchError { message: err.description().to_string() }
    }
}

impl From<IoError> for HttpDispatchError {
    fn from(err: IoError) -> HttpDispatchError {
        HttpDispatchError { message: err.description().to_string() }
    }
}

pub trait DispatchSignedRequest {
    fn dispatch(&self, request: &SignedRequest) -> Result<HttpResponse, HttpDispatchError>;
}

impl DispatchSignedRequest for Client {
    fn dispatch(&self, request: &SignedRequest) -> Result<HttpResponse, HttpDispatchError> {
        let hyper_method = match request.method().as_ref() {
            "POST" => Method::Post,
            "PUT" => Method::Put,
            "DELETE" => Method::Delete,
            "GET" => Method::Get,
            "HEAD" => Method::Head,
            v => return Err(HttpDispatchError { message: format!("Unsupported HTTP verb {}", v) })
        };

        // translate the headers map to a format Hyper likes
        let mut hyper_headers = Headers::new();
        for h in request.headers().iter() {
            hyper_headers.set_raw(h.0.to_owned(), h.1.to_owned());
        }

        // Add a default user-agent header if one is not already present.
        if !hyper_headers.has::<UserAgent>() {
            hyper_headers.set_raw("user-agent".to_owned(), DEFAULT_USER_AGENT.clone());
        }

        let mut final_uri = format!("https://{}{}", request.hostname(), request.canonical_path());
        if !request.canonical_query_string().is_empty() {
            final_uri = final_uri + &format!("?{}", request.canonical_query_string());
        }

        if log_enabled!(Debug) {
            let payload = request.payload().map(|mut payload_bytes| {
                let mut payload_string = String::new();

                payload_bytes.read_to_string(&mut payload_string)
                    .map(|_| payload_string)
                    .unwrap_or_else(|_| String::from("<non-UTF-8 data>"))
            });

            debug!("Full request: \n method: {}\n final_uri: {}\n payload: {}\nHeaders:\n", hyper_method, final_uri, payload.unwrap_or("".to_owned()));
            for h in hyper_headers.iter() {
                debug!("{}:{}", h.name(), h.value_string());
            }
        }
        let mut hyper_response = match request.payload() {
            None => try!(self.request(hyper_method, &final_uri).headers(hyper_headers).body("").send()),
            Some(payload_contents) => try!(self.request(hyper_method, &final_uri).headers(hyper_headers).body(payload_contents).send()),
        };
        let mut body = String::new();
        let mut body_as_bytes : Vec<u8> = Vec::new();

        match is_binary(&hyper_response.headers) {
            true => try!(hyper_response.read_to_end(&mut body_as_bytes)),
            false => try!(hyper_response.read_to_string(&mut body)),
        };

        if log_enabled!(Debug) {
            debug!("Response body:\n{}", body);
            debug!("Response raw_body:\n{:?}", body_as_bytes);
        }

        let mut headers: HashMap<String, String> = HashMap::new();

        for header in hyper_response.headers.iter() {
            headers.insert(header.name().to_string(), header.value_string());
        }

        Ok(HttpResponse {
            status: hyper_response.status.clone(),
            body: body,
            raw_body: body_as_bytes,
            headers: headers
        })

    }
}

fn is_binary(headers: &Headers) -> bool {
    match headers.get::<ContentType>() {
        Some(content_type) => content_type.eq(&BINARY_RESPONSE_CONTENTS),
        None => false,
    }
}
<|endoftext|>


<commit_before>// SPDX-License-Identifier: MIT
// Copyright (C) 2018-present iced project and contributors

//! Easier creating of instructions (eg. `a.mov(eax, ecx)`) than using `Instruction::with*()` functions.
//!
//! This requires the `code_asm` feature to use (not enabled by default). Add it to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies.iced-x86]
//! version = "1.16.0"
//! features = ["code_asm"]
//! ```
//!
//! See [`CodeAssembler`] docs for usage.
//!
//! [`CodeAssembler`]: struct.CodeAssembler.html

pub mod asm_traits;
mod code_asm_methods;
mod fn_asm_impl;
mod fn_asm_pub;
mod mem;
mod op_state;
mod reg;
pub mod registers;
#[cfg(test)]
mod tests;

pub use crate::code_asm::mem::*;
pub use crate::code_asm::reg::*;
pub use crate::code_asm::registers::*;
pub use crate::IcedError;
use crate::{BlockEncoderResult, Instruction};
use alloc::vec::Vec;
use core::hash::{Hash, Hasher};

struct PrefixFlags;
impl PrefixFlags {
	const NONE: u8 = 0x00;
	const LOCK: u8 = 0x01;
	const REPE: u8 = 0x02;
	const REPNE: u8 = 0x04;
	const NOTRACK: u8 = 0x08;
	const PREFER_VEX: u8 = 0x10;
	const PREFER_EVEX: u8 = 0x20;
}

struct CodeAssemblerOptions;
impl CodeAssemblerOptions {
	const PREFER_VEX: u8 = 0x01;
	const PREFER_SHORT_BRANCH: u8 = 0x02;
}

/// Creates and encodes instructions. It's easier to use this struct than to call `Instruction::with*()` functions.
///
/// This requires the `code_asm` feature to use (not enabled by default). Add it to your `Cargo.toml`:
///
/// ```toml
/// [dependencies.iced-x86]
/// version = "1.16.0"
/// features = ["code_asm"]
/// ```
///
/// # Examples
///
/// ```
/// use iced_x86::code_asm::*;
///
/// # fn main() -> Result<(), IcedError> {
/// let mut a = CodeAssembler::new(64)?;
///
/// // Anytime you add something to a register (or subtract from it), you create a
/// // memory operand. You can also call word_ptr(), dword_bcst() etc to create memory
/// // operands.
/// let _ = rax; // register
/// let _ = rax + 0; // memory with no size hint
/// let _ = ptr(rax); // memory with no size hint
/// let _ = rax + rcx * 4 - 123; // memory with no size hint
/// // To create a memory operand with only a displacement or only a base register,
/// // you can call one of the memory fns:
/// let _ = qword_ptr(123); // memory with a qword size hint
/// let _ = dword_bcst(rcx); // memory (broadcast) with a dword size hint
/// // To add a segment override, call the segment methods:
/// let _ = ptr(rax).fs(); // fs:[rax]
///
/// // Each mnemonic is a method
/// a.push(rcx)?;
/// // There are a few exceptions where you must append `_<opcount>` to the mnemonic to
/// // get the instruction you need:
/// a.ret()?;
/// a.ret_1(123)?;
/// // Use byte_ptr(), word_bcst(), etc to force the arg to a memory operand and to add a
/// // size hint
/// a.xor(byte_ptr(rdx+r14*4+123), 0x10)?;
/// // Prefixes are also methods
/// a.rep().stosd()?;
/// // Sometimes, you must add an integer suffix to help the compiler:
/// a.mov(rax, 0x1234_5678_9ABC_DEF0u64)?;
///
/// // Create labels that can be referenced by code
/// let mut loop_lbl1 = a.create_label();
/// let mut after_loop1 = a.create_label();
/// a.mov(ecx, 10)?;
/// a.set_label(&mut loop_lbl1)?;
/// a.dec(ecx)?;
/// a.jp(after_loop1)?;
/// a.jne(loop_lbl1)?;
/// a.set_label(&mut after_loop1)?;
///
/// // It's possible to reference labels with RIP-relative addressing
/// let mut skip_data = a.create_label();
/// let mut data = a.create_label();
/// a.jmp(skip_data)?;
/// a.set_label(&mut data)?;
/// a.db(b"\x90\xCC\xF1\x90")?;
/// a.set_label(&mut skip_data)?;
/// a.lea(rax, ptr(data))?;
///
/// // AVX512 opmasks, {z}, {sae}, {er} and broadcasting are also supported:
/// a.vsqrtps(zmm16.k2().z(), dword_bcst(rcx))?;
/// a.vsqrtps(zmm1.k2().z(), zmm23.rd_sae())?;
/// // Sometimes, the encoder doesn't know if you want VEX or EVEX encoding.
/// // You can force EVEX globally like so:
/// a.set_prefer_vex(false);
/// a.vucomiss(xmm31, xmm15.sae())?;
/// a.vucomiss(xmm31, ptr(rcx))?;
/// // or call vex()/evex() to override the encoding option:
/// a.evex().vucomiss(xmm31, xmm15.sae())?;
/// a.vex().vucomiss(xmm15, xmm14)?;
///
/// // Encode all added instructions
/// let bytes = a.assemble(0x1234_5678)?;
/// assert_eq!(bytes.len(), 82);
/// // If you don't want to encode them, you can get all instructions by calling
/// // one of these methods:
/// let instrs = a.instructions(); // Get a reference to the internal vec
/// assert_eq!(instrs.len(), 19);
/// let instrs = a.take_instructions(); // Take ownership of the vec with all instructions
/// assert_eq!(instrs.len(), 19);
/// assert_eq!(a.instructions().len(), 0);
/// # Ok(())
/// # }
/// ```
#[allow(missing_debug_implementations)]
pub struct CodeAssembler {
	bitness: u32,
	instructions: Vec<Instruction>,
	current_label_id: u64,
	current_label: CodeLabel,
	current_anon_label: CodeLabel,
	next_anon_label: CodeLabel,
	defined_anon_label: bool,
	prefix_flags: u8,
	options: u8,
}

/// A label created by [`CodeAssembler`]
///
/// [`CodeAssembler`]: struct.CodeAssembler.html
#[derive(Debug, Default, Copy, Clone)]
pub struct CodeLabel {
	id: u64,
	instruction_index: usize,
}

impl Eq for CodeLabel {}

impl PartialEq for CodeLabel {
	#[inline]
	fn eq(&self, other: &CodeLabel) -> bool {
		self.id == other.id
	}
}

impl Hash for CodeLabel {
	#[inline]
	fn hash<H: Hasher>(&self, state: &mut H) {
		self.id.hash(state);
	}
}

impl CodeLabel {
	#[must_use]
	#[inline]
	pub(crate) fn new(id: u64) -> Self {
		Self { id, instruction_index: usize::MAX }
	}

	#[must_use]
	#[inline]
	pub(crate) fn is_empty(&self) -> bool {
		self.id == 0
	}

	#[must_use]
	#[inline]
	pub(crate) fn has_instruction_index(&self) -> bool {
		self.instruction_index != usize::MAX
	}

	#[must_use]
	#[inline]
	pub(crate) fn id(&self) -> u64 {
		self.id
	}
}

/// Result of assembling the instructions
#[derive(Debug)]
pub struct CodeAssemblerResult {
	/// Inner `BlockEncoder` result
	pub inner: BlockEncoderResult,
}

impl CodeAssemblerResult {
	/// Gets the address of a label
	///
	/// # Notes
	///
	/// You should pass [`BlockEncoderOptions::RETURN_NEW_INSTRUCTION_OFFSETS`] to [`CodeAssembler::assemble_options()`] or this method will fail.
	///
	/// # Arguments
	///
	/// * `label`: The label
	///
	/// # Errors
	///
	/// Fails if the label is invalid
	///
	/// [`BlockEncoderOptions::RETURN_NEW_INSTRUCTION_OFFSETS`]: struct.BlockEncoderOptions.html#associatedconstant.RETURN_NEW_INSTRUCTION_OFFSETS
	/// [`CodeAssembler::assemble_options()`]: struct.CodeAssembler.html#method.assemble_options
	#[allow(clippy::missing_inline_in_public_items)]
	pub fn label_ip(&self, label: &CodeLabel) -> Result<u64, IcedError> {
		if label.is_empty() {
			return Err(IcedError::new("Invalid label. Must be created via `CodeAssembler::create_label()`."));
		}
		if !label.has_instruction_index() {
			return Err(IcedError::new(
				"The label is not associated with an instruction index. It must be emitted via `CodeAssembler::set_label()`.",
			));
		}
		let new_offset = if let Some(new_offset) = self.inner.new_instruction_offsets.get(label.instruction_index) {
			*new_offset
		} else {
			return Err(IcedError::new(
				"Invalid label instruction index or `BlockEncoderOptions::RETURN_NEW_INSTRUCTION_OFFSETS` option was not enabled when calling `assemble_options()`.",
			));
		};
		if new_offset == u32::MAX {
			Err(IcedError::new("The instruction was re-written to a longer instruction (eg. JE NEAR -> JE FAR) and there's no instruction offset. Consider using a `zero_bytes()` instruction as a label instead of a normal instruction or disable branch optimizations."))
		} else {
			Ok(self.inner.rip.wrapping_add(new_offset as u64))
		}
	}
}
<commit_msg>Add `#[non_exhaustive]`<commit_after>// SPDX-License-Identifier: MIT
// Copyright (C) 2018-present iced project and contributors

//! Easier creating of instructions (eg. `a.mov(eax, ecx)`) than using `Instruction::with*()` functions.
//!
//! This requires the `code_asm` feature to use (not enabled by default). Add it to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies.iced-x86]
//! version = "1.16.0"
//! features = ["code_asm"]
//! ```
//!
//! See [`CodeAssembler`] docs for usage.
//!
//! [`CodeAssembler`]: struct.CodeAssembler.html

pub mod asm_traits;
mod code_asm_methods;
mod fn_asm_impl;
mod fn_asm_pub;
mod mem;
mod op_state;
mod reg;
pub mod registers;
#[cfg(test)]
mod tests;

pub use crate::code_asm::mem::*;
pub use crate::code_asm::reg::*;
pub use crate::code_asm::registers::*;
pub use crate::IcedError;
use crate::{BlockEncoderResult, Instruction};
use alloc::vec::Vec;
use core::hash::{Hash, Hasher};

struct PrefixFlags;
impl PrefixFlags {
	const NONE: u8 = 0x00;
	const LOCK: u8 = 0x01;
	const REPE: u8 = 0x02;
	const REPNE: u8 = 0x04;
	const NOTRACK: u8 = 0x08;
	const PREFER_VEX: u8 = 0x10;
	const PREFER_EVEX: u8 = 0x20;
}

struct CodeAssemblerOptions;
impl CodeAssemblerOptions {
	const PREFER_VEX: u8 = 0x01;
	const PREFER_SHORT_BRANCH: u8 = 0x02;
}

/// Creates and encodes instructions. It's easier to use this struct than to call `Instruction::with*()` functions.
///
/// This requires the `code_asm` feature to use (not enabled by default). Add it to your `Cargo.toml`:
///
/// ```toml
/// [dependencies.iced-x86]
/// version = "1.16.0"
/// features = ["code_asm"]
/// ```
///
/// # Examples
///
/// ```
/// use iced_x86::code_asm::*;
///
/// # fn main() -> Result<(), IcedError> {
/// let mut a = CodeAssembler::new(64)?;
///
/// // Anytime you add something to a register (or subtract from it), you create a
/// // memory operand. You can also call word_ptr(), dword_bcst() etc to create memory
/// // operands.
/// let _ = rax; // register
/// let _ = rax + 0; // memory with no size hint
/// let _ = ptr(rax); // memory with no size hint
/// let _ = rax + rcx * 4 - 123; // memory with no size hint
/// // To create a memory operand with only a displacement or only a base register,
/// // you can call one of the memory fns:
/// let _ = qword_ptr(123); // memory with a qword size hint
/// let _ = dword_bcst(rcx); // memory (broadcast) with a dword size hint
/// // To add a segment override, call the segment methods:
/// let _ = ptr(rax).fs(); // fs:[rax]
///
/// // Each mnemonic is a method
/// a.push(rcx)?;
/// // There are a few exceptions where you must append `_<opcount>` to the mnemonic to
/// // get the instruction you need:
/// a.ret()?;
/// a.ret_1(123)?;
/// // Use byte_ptr(), word_bcst(), etc to force the arg to a memory operand and to add a
/// // size hint
/// a.xor(byte_ptr(rdx+r14*4+123), 0x10)?;
/// // Prefixes are also methods
/// a.rep().stosd()?;
/// // Sometimes, you must add an integer suffix to help the compiler:
/// a.mov(rax, 0x1234_5678_9ABC_DEF0u64)?;
///
/// // Create labels that can be referenced by code
/// let mut loop_lbl1 = a.create_label();
/// let mut after_loop1 = a.create_label();
/// a.mov(ecx, 10)?;
/// a.set_label(&mut loop_lbl1)?;
/// a.dec(ecx)?;
/// a.jp(after_loop1)?;
/// a.jne(loop_lbl1)?;
/// a.set_label(&mut after_loop1)?;
///
/// // It's possible to reference labels with RIP-relative addressing
/// let mut skip_data = a.create_label();
/// let mut data = a.create_label();
/// a.jmp(skip_data)?;
/// a.set_label(&mut data)?;
/// a.db(b"\x90\xCC\xF1\x90")?;
/// a.set_label(&mut skip_data)?;
/// a.lea(rax, ptr(data))?;
///
/// // AVX512 opmasks, {z}, {sae}, {er} and broadcasting are also supported:
/// a.vsqrtps(zmm16.k2().z(), dword_bcst(rcx))?;
/// a.vsqrtps(zmm1.k2().z(), zmm23.rd_sae())?;
/// // Sometimes, the encoder doesn't know if you want VEX or EVEX encoding.
/// // You can force EVEX globally like so:
/// a.set_prefer_vex(false);
/// a.vucomiss(xmm31, xmm15.sae())?;
/// a.vucomiss(xmm31, ptr(rcx))?;
/// // or call vex()/evex() to override the encoding option:
/// a.evex().vucomiss(xmm31, xmm15.sae())?;
/// a.vex().vucomiss(xmm15, xmm14)?;
///
/// // Encode all added instructions
/// let bytes = a.assemble(0x1234_5678)?;
/// assert_eq!(bytes.len(), 82);
/// // If you don't want to encode them, you can get all instructions by calling
/// // one of these methods:
/// let instrs = a.instructions(); // Get a reference to the internal vec
/// assert_eq!(instrs.len(), 19);
/// let instrs = a.take_instructions(); // Take ownership of the vec with all instructions
/// assert_eq!(instrs.len(), 19);
/// assert_eq!(a.instructions().len(), 0);
/// # Ok(())
/// # }
/// ```
#[allow(missing_debug_implementations)]
pub struct CodeAssembler {
	bitness: u32,
	instructions: Vec<Instruction>,
	current_label_id: u64,
	current_label: CodeLabel,
	current_anon_label: CodeLabel,
	next_anon_label: CodeLabel,
	defined_anon_label: bool,
	prefix_flags: u8,
	options: u8,
}

/// A label created by [`CodeAssembler`]
///
/// [`CodeAssembler`]: struct.CodeAssembler.html
#[derive(Debug, Default, Copy, Clone)]
pub struct CodeLabel {
	id: u64,
	instruction_index: usize,
}

impl Eq for CodeLabel {}

impl PartialEq for CodeLabel {
	#[inline]
	fn eq(&self, other: &CodeLabel) -> bool {
		self.id == other.id
	}
}

impl Hash for CodeLabel {
	#[inline]
	fn hash<H: Hasher>(&self, state: &mut H) {
		self.id.hash(state);
	}
}

impl CodeLabel {
	#[must_use]
	#[inline]
	pub(crate) fn new(id: u64) -> Self {
		Self { id, instruction_index: usize::MAX }
	}

	#[must_use]
	#[inline]
	pub(crate) fn is_empty(&self) -> bool {
		self.id == 0
	}

	#[must_use]
	#[inline]
	pub(crate) fn has_instruction_index(&self) -> bool {
		self.instruction_index != usize::MAX
	}

	#[must_use]
	#[inline]
	pub(crate) fn id(&self) -> u64 {
		self.id
	}
}

/// Result of assembling the instructions
#[derive(Debug)]
#[cfg_attr(not(feature = "exhaustive_enums"), non_exhaustive)]
pub struct CodeAssemblerResult {
	/// Inner `BlockEncoder` result
	pub inner: BlockEncoderResult,
}

impl CodeAssemblerResult {
	/// Gets the address of a label
	///
	/// # Notes
	///
	/// You should pass [`BlockEncoderOptions::RETURN_NEW_INSTRUCTION_OFFSETS`] to [`CodeAssembler::assemble_options()`] or this method will fail.
	///
	/// # Arguments
	///
	/// * `label`: The label
	///
	/// # Errors
	///
	/// Fails if the label is invalid
	///
	/// [`BlockEncoderOptions::RETURN_NEW_INSTRUCTION_OFFSETS`]: struct.BlockEncoderOptions.html#associatedconstant.RETURN_NEW_INSTRUCTION_OFFSETS
	/// [`CodeAssembler::assemble_options()`]: struct.CodeAssembler.html#method.assemble_options
	#[allow(clippy::missing_inline_in_public_items)]
	pub fn label_ip(&self, label: &CodeLabel) -> Result<u64, IcedError> {
		if label.is_empty() {
			return Err(IcedError::new("Invalid label. Must be created via `CodeAssembler::create_label()`."));
		}
		if !label.has_instruction_index() {
			return Err(IcedError::new(
				"The label is not associated with an instruction index. It must be emitted via `CodeAssembler::set_label()`.",
			));
		}
		let new_offset = if let Some(new_offset) = self.inner.new_instruction_offsets.get(label.instruction_index) {
			*new_offset
		} else {
			return Err(IcedError::new(
				"Invalid label instruction index or `BlockEncoderOptions::RETURN_NEW_INSTRUCTION_OFFSETS` option was not enabled when calling `assemble_options()`.",
			));
		};
		if new_offset == u32::MAX {
			Err(IcedError::new("The instruction was re-written to a longer instruction (eg. JE NEAR -> JE FAR) and there's no instruction offset. Consider using a `zero_bytes()` instruction as a label instead of a normal instruction or disable branch optimizations."))
		} else {
			Ok(self.inner.rip.wrapping_add(new_offset as u64))
		}
	}
}
<|endoftext|>


<commit_before>pub mod builtins;

use std::env;
use std::path::PathBuf;

use std::io;
use std::io::{Read, Write};

use std::collections::HashMap;
use std::collections::hash_map::Entry;

#[derive(Debug, Clone)]
pub struct State {
    cwd: PathBuf,
    environment: HashMap<String, String>,
    aliases: HashMap<String, String>,
    argv: Vec<String>,
    argc: usize,
    exit_status: i32,
}

impl State {
    pub fn new(cwd: String) -> State {
        State {
            cwd: PathBuf::from(cwd),
            environment: HashMap::new(),
            aliases: HashMap::new(),
            argv: Vec::new(),
            argc: 0,
            exit_status: 0,
        }
    }

    pub fn default() -> State {
        match env::current_dir() {
            Ok(cwd) => {
                State {
                    cwd: cwd,
                    environment: HashMap::new(),
                    aliases: HashMap::new(),
                    argv: Vec::new(),
                    argc: 0,
                    exit_status: 0,
                }
            }
            Err(e) => panic!(e),
        }
    }

    pub fn env<'a>(&'a mut self, key: String, value: String) -> &'a mut State {
        self.environment.insert(key, value);
        self
    }

    pub fn alias<'a>(&'a mut self, alias: String, value: String) -> &'a mut State {
        self.aliases.insert(alias, value);
        self
    }
}

pub fn run(initial_state: State) {
    let mut builtins = builtins::load();
    let mut s = initial_state.clone();

    println!("Welcome to rsh! {:?}", s);

    loop {

        print!("\n");
        print!("{} -> ", s.cwd.to_str().unwrap());

        // this forces the prompt to print
        io::stdout()
            .flush()
            .expect("unable to flush stdout");

        // read the user input
        let mut input = String::new();
        io::stdin()
            .read_line(&mut input)
            .expect("unable to read line from stdin");

        s.argv = parse_args(&input);
        s.argc = s.argv.len();

        print!("\n");
        println!("Input: {}\nState: {:?}", input, s);

        let first_arg = s.argv.get(0).unwrap().clone();
        if let Entry::Occupied(f) = builtins.entry(String::from(first_arg)) {
            let bn = f.get();
            s.exit_status = bn(&mut s);
            // prompt for input again.
            continue;
        }
    }
}

fn parse_args(args: &String) -> Vec<String> {
    let mut result: Vec<String> = Vec::new();

    if args.len() == 0 {
        return result;
    }

    let mut building_string: bool = false;
    let mut build_string: String = String::from("");
    for string in args.split_whitespace() {
        if string.starts_with("\"") {
            // the string is surrounded by quotes - "word"
            if string.ends_with("\"") {
                build_string.push_str(string);
                result.push(build_string);

                building_string = false;
                build_string = String::from("");
                // the string only begins with quote - "word
            } else {
                building_string = true;

                build_string.push_str(string);
                build_string.push(' ');
            }
            // the string ends with quote - word"
        } else if string.ends_with("\"") {
            build_string.push_str(string);
            result.push(build_string);

            building_string = false;
            build_string = String::from("");
        } else {
            // the string is inside a quote section
            if building_string {
                build_string.push_str(string);
                build_string.push(' ');
                // the string is not inside a quote section
            } else {
                result.push(string.to_string());
            }
        }
    }

    result
}

#[test]
fn parse_args_test() {
    // parse empty string
    {
        let expected: Vec<String> = Vec::new();
        let result = parse_args(&String::from(""));
        assert_eq!(result, expected);
    }

    // parse single-word string
    {
        let expected: Vec<String> = vec!["echo".to_string()];
        let result = parse_args(&String::from("echo"));
        assert_eq!(result, expected);
    }

    // parse single-word string inside parens
    {
        let expected = vec!["\"echo\"".to_string()];
        let result = parse_args(&String::from("\"echo\""));
        assert_eq!(result, expected);
    }

    // parse multi-word string with closed parens section
    {
        let expected = vec!["echo".to_string(), "-n".into(), "\"Hello Dear World\"".into()];
        let result = parse_args(&String::from("echo -n \"Hello Dear World\""));
        assert_eq!(result, expected);
    }

    // parse multi-word string with multiple closed parents sections
    {
        let expected = vec!["echo".to_string(), "\"Hello\"".into(), "\"Dear World\"".into()];
        let result = parse_args(&String::from("echo \"Hello\" \"Dear World\""));
        assert_eq!(result, expected);
    }
}
<commit_msg>rename environment to variables<commit_after>pub mod builtins;
pub mod utils;

use std::env;
use std::path::PathBuf;

use std::io;
use std::io::Write;

use std::collections::HashMap;
use std::collections::hash_map::Entry;

#[derive(Debug, Clone)]
pub struct State {
    cwd: PathBuf,
    variables: HashMap<String, String>,
    aliases: HashMap<String, String>,
    argv: Vec<String>,
    argc: usize,
    exit_status: i32,
}

impl State {
    pub fn new(cwd: String) -> State {
        State {
            cwd: utils::make_absolute(PathBuf::from(cwd)).unwrap(),
            variables: HashMap::new(),
            aliases: HashMap::new(),
            argv: Vec::new(),
            argc: 0,
            exit_status: 0,
        }
    }

    pub fn default() -> State {
        match env::current_dir() {
            Ok(cwd) => {
                State {
                    cwd: cwd,
                    variables: HashMap::new(),
                    aliases: HashMap::new(),
                    argv: Vec::new(),
                    argc: 0,
                    exit_status: 0,
                }
            }
            Err(e) => panic!(e),
        }
    }

    pub fn env<'a>(&'a mut self, key: String, value: String) -> &'a mut State {
        self.variables.insert(key, value);
        self
    }

    pub fn alias<'a>(&'a mut self, alias: String, value: String) -> &'a mut State {
        self.aliases.insert(alias, value);
        self
    }
}

pub fn run(initial_state: State) {
    let mut builtins = builtins::load();
    let mut s = initial_state.clone();

    println!("Welcome to rsh! {:?}", s);

    loop {

        print!("\n");
        print!("{} -> ", s.cwd.to_str().unwrap());

        // this forces the prompt to print
        io::stdout()
            .flush()
            .expect("unable to flush stdout");

        // read the user input
        let mut input = String::new();
        io::stdin()
            .read_line(&mut input)
            .expect("unable to read line from stdin");

        s.argv = parse_args(&input);
        s.argc = s.argv.len();

        print!("\n");
        println!("Input: {}\nState: {:?}", input, s);

        let first_arg = s.argv.get(0).unwrap().clone();
        if let Entry::Occupied(f) = builtins.entry(String::from(first_arg)) {
            let bn = f.get();
            s.exit_status = bn(&mut s);
            // prompt for input again.
            continue;
        }
    }
}

fn parse_args(args: &String) -> Vec<String> {
    let mut result: Vec<String> = Vec::new();

    if args.len() == 0 {
        return result;
    }

    let mut building_string: bool = false;
    let mut build_string: String = String::from("");
    for string in args.split_whitespace() {
        if string.starts_with("\"") {
            // the string is surrounded by quotes - "word"
            if string.ends_with("\"") {
                build_string.push_str(string);
                result.push(build_string);

                building_string = false;
                build_string = String::from("");
                // the string only begins with quote - "word
            } else {
                building_string = true;

                build_string.push_str(string);
                build_string.push(' ');
            }
            // the string ends with quote - word"
        } else if string.ends_with("\"") {
            build_string.push_str(string);
            result.push(build_string);

            building_string = false;
            build_string = String::from("");
        } else {
            // the string is inside a quote section
            if building_string {
                build_string.push_str(string);
                build_string.push(' ');
                // the string is not inside a quote section
            } else {
                result.push(string.to_string());
            }
        }
    }

    result
}

#[test]
fn parse_args_test() {
    // parse empty string
    {
        let expected: Vec<String> = Vec::new();
        let result = parse_args(&String::from(""));
        assert_eq!(result, expected);
    }

    // parse single-word string
    {
        let expected: Vec<String> = vec!["echo".to_string()];
        let result = parse_args(&String::from("echo"));
        assert_eq!(result, expected);
    }

    // parse single-word string inside parens
    {
        let expected = vec!["\"echo\"".to_string()];
        let result = parse_args(&String::from("\"echo\""));
        assert_eq!(result, expected);
    }

    // parse multi-word string with closed parens section
    {
        let expected = vec!["echo".to_string(), "-n".into(), "\"Hello Dear World\"".into()];
        let result = parse_args(&String::from("echo -n \"Hello Dear World\""));
        assert_eq!(result, expected);
    }

    // parse multi-word string with multiple closed parents sections
    {
        let expected = vec!["echo".to_string(), "\"Hello\"".into(), "\"Dear World\"".into()];
        let result = parse_args(&String::from("echo \"Hello\" \"Dear World\""));
        assert_eq!(result, expected);
    }
}
<|endoftext|>


<commit_before>use cmd;
use client;
use channel;
use msg::RawMessage;
use msg::util;

use server::{Server};
use client::SharedClient;

/// Handles the quit/part event
pub fn do_quit_leave(channel: &mut channel::Channel, client: client::ClientProxy,
                    command: cmd::Command, reason: Option<Vec<u8>>) {
    let nick = channel.member_with_id(client.id()).map(|v| v.nick().to_string());
    match nick {
        Some(nick) => {
            let msg = {
                let payload = match reason {
                    None => vec![channel.name().as_bytes()],
                    Some(ref reason) => vec![channel.name().as_bytes(), reason.as_slice()],
                    };
                RawMessage::new_raw(
                    command, payload.as_slice(), Some(nick.as_bytes())
                )
            };
            channel.broadcast(msg);
            channel.remove_member(&client.id());
        },
        None => channel.send_response(&client, cmd::ERR_NOTONCHANNEL,
            [channel.name(), "You are not on this channel."]
        )
    }
}
/// Handles the PART command
pub struct Part {
    raw: RawMessage,
    channels: Vec<String>,
    reason: Option<Vec<u8>>
}
impl super::MessageHandler for Part {
    fn from_message(message: RawMessage) -> Result<Box<Part>, RawMessage> {
        let params = message.params();
        let mut channels = Vec::new();
        if params.len() > 0 {
            for channel_name in params[0].as_slice().split(|c| *c == b',') {
                match util::verify_channel(channel_name) {
                    Some(channel) => {
                        channels.push(channel.to_string());
                    },
                    None => return Err(RawMessage::new(cmd::REPLY(cmd::ERR_NOSUCHCHANNEL), [
                        "*", String::from_utf8_lossy(channel_name).as_slice(),
                        "Invalid channel name."
                    ], None))
                }
            }
            Ok(box Part {
                raw: message.clone(),
                channels: channels,
                reason: params.as_slice().get(1).map(|v| v.to_vec())
            })
        } else {
             Err(RawMessage::new(cmd::REPLY(cmd::ERR_NEEDMOREPARAMS), [
                "*", message.command().to_string().as_slice(),
                "no params given"
            ], None))
        }
    }
    fn invoke(self, server: &mut Server, origin: SharedClient) {
        for channel_name in self.channels.iter() {
            match server.channels.find_mut(channel_name) {
                Some(channel) => {
                    let reason = self.reason.clone();
                    let proxy = origin.borrow().proxy();
                    channel.send(channel::HandleMut(proc(channel) {
                        do_quit_leave(channel, proxy, cmd::PART, reason)
                    }))
                },
                None => origin
                    .borrow_mut().send_response(cmd::ERR_NOSUCHCHANNEL,
                        Some(channel_name.as_slice()), Some("No such channel"))

            }
        }
    }
    fn raw_message(&self) -> &RawMessage {
        &self.raw
    }
}

/// Handles the QUIT command
pub struct Quit {
    raw: RawMessage,
    reason: Option<Vec<u8>>
}
impl super::MessageHandler for Quit {
    fn from_message(message: RawMessage) -> Result<Box<Quit>, RawMessage> {
        let reason = message.params().as_slice().get(0).map(
            |&v| v.to_vec());
        Ok(box Quit {
            raw: message, reason: reason
        })
    }
    fn invoke(self, server: &mut Server, origin: SharedClient) {
        let mut client = origin.borrow_mut();
        client.close_connection();
        server.remove_client(&origin);
        for (_, channel) in server.channels.iter() {
            // TODO make this more performant, cache channels in user?
            let reason = self.reason.clone();
            let proxy = origin.borrow().proxy();
            channel.send(channel::HandleMut(proc(channel) {
                do_quit_leave(channel, proxy, cmd::QUIT, reason)
            }))
        }
    }
    fn raw_message(&self) -> &RawMessage {
        &self.raw
    }
}<commit_msg>Prevent failure of main thread<commit_after>use cmd;
use client;
use channel;
use msg::RawMessage;
use msg::util;

use server::{Server};
use client::SharedClient;

/// Handles the quit/part event
pub fn do_quit_leave(channel: &mut channel::Channel, client: client::ClientProxy,
                    command: cmd::Command, reason: Option<Vec<u8>>) {
    let nick = channel.member_with_id(client.id()).map(|v| v.nick().to_string());
    match nick {
        Some(nick) => {
            let msg = {
                let payload = match reason {
                    None => vec![channel.name().as_bytes()],
                    Some(ref reason) => vec![channel.name().as_bytes(), reason.as_slice()],
                    };
                RawMessage::new_raw(
                    command, payload.as_slice(), Some(nick.as_bytes())
                )
            };
            channel.broadcast(msg);
            channel.remove_member(&client.id());
        },
        None => channel.send_response(&client, cmd::ERR_NOTONCHANNEL,
            [channel.name(), "You are not on this channel."]
        )
    }
}
/// Handles the PART command
pub struct Part {
    raw: RawMessage,
    channels: Vec<String>,
    reason: Option<Vec<u8>>
}
impl super::MessageHandler for Part {
    fn from_message(message: RawMessage) -> Result<Box<Part>, RawMessage> {
        let params = message.params();
        let mut channels = Vec::new();
        if params.len() > 0 {
            for channel_name in params[0].as_slice().split(|c| *c == b',') {
                match util::verify_channel(channel_name) {
                    Some(channel) => {
                        channels.push(channel.to_string());
                    },
                    None => return Err(RawMessage::new(cmd::REPLY(cmd::ERR_NOSUCHCHANNEL), [
                        "*", String::from_utf8_lossy(channel_name).as_slice(),
                        "Invalid channel name."
                    ], None))
                }
            }
            Ok(box Part {
                raw: message.clone(),
                channels: channels,
                reason: params.as_slice().get(1).map(|v| v.to_vec())
            })
        } else {
             Err(RawMessage::new(cmd::REPLY(cmd::ERR_NEEDMOREPARAMS), [
                "*", message.command().to_string().as_slice(),
                "no params given"
            ], None))
        }
    }
    fn invoke(self, server: &mut Server, origin: SharedClient) {
        for channel_name in self.channels.iter() {
            match server.channels.find_mut(channel_name) {
                Some(channel) => {
                    let reason = self.reason.clone();
                    let proxy = origin.borrow().proxy();
                    channel.send(channel::HandleMut(proc(channel) {
                        do_quit_leave(channel, proxy, cmd::PART, reason)
                    }))
                },
                None => origin
                    .borrow_mut().send_response(cmd::ERR_NOSUCHCHANNEL,
                        Some(channel_name.as_slice()), Some("No such channel"))

            }
        }
    }
    fn raw_message(&self) -> &RawMessage {
        &self.raw
    }
}

/// Handles the QUIT command
pub struct Quit {
    raw: RawMessage,
    reason: Option<Vec<u8>>
}
impl super::MessageHandler for Quit {
    fn from_message(message: RawMessage) -> Result<Box<Quit>, RawMessage> {
        let reason = message.params().as_slice().get(0).map(
            |&v| v.to_vec());
        Ok(box Quit {
            raw: message, reason: reason
        })
    }
    fn invoke(self, server: &mut Server, origin: SharedClient) {
        origin.borrow_mut().close_connection();
        server.remove_client(&origin);
        for (_, channel) in server.channels.iter() {
            // TODO make this more performant, cache channels in user?
            let reason = self.reason.clone();
            let proxy = origin.borrow().proxy();
            channel.send(channel::HandleMut(proc(channel) {
                do_quit_leave(channel, proxy, cmd::QUIT, reason)
            }))
        }
    }
    fn raw_message(&self) -> &RawMessage {
        &self.raw
    }
}<|endoftext|>


<commit_before><commit_msg>[Test] Implement tests for Config.set()<commit_after><|endoftext|>