<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![cfg(not(test))]

extern crate env_logger;
extern crate failure;
extern crate getopts;
extern crate rustfmt_nightly as rustfmt;

use std::env;
use std::fs::File;
use std::io::{self, stdout, Read, Write};
use std::path::{Path, PathBuf};

use failure::err_msg;

use getopts::{Matches, Options};

use rustfmt::{
    emit_post_matter, emit_pre_matter, format_and_emit_report, load_config, CliOptions, Config,
    FileName, FmtResult, Input, Summary, Verbosity, WriteMode, WRITE_MODE_LIST,
};

fn main() {
    env_logger::init();
    let opts = make_opts();

    let exit_code = match execute(&opts) {
        Ok((write_mode, summary)) => {
            if summary.has_operational_errors()
                || summary.has_parsing_errors()
                || (summary.has_diff && write_mode == WriteMode::Check)
            {
                1
            } else {
                0
            }
        }
        Err(e) => {
            eprintln!("{}", e.to_string());
            1
        }
    };
    // Make sure standard output is flushed before we exit.
    std::io::stdout().flush().unwrap();

    // Exit with given exit code.
    //
    // NOTE: This immediately terminates the process without doing any cleanup,
    // so make sure to finish all necessary cleanup before this is called.
    std::process::exit(exit_code);
}

/// Rustfmt operations.
enum Operation {
    /// Format files and their child modules.
    Format {
        files: Vec<PathBuf>,
        minimal_config_path: Option<String>,
    },
    /// Print the help message.
    Help,
    // Print version information
    Version,
    /// Print detailed configuration help.
    ConfigHelp,
    /// Output default config to a file, or stdout if None
    ConfigOutputDefault {
        path: Option<String>,
    },
    /// No file specified, read from stdin
    Stdin {
        input: String,
    },
}

fn make_opts() -> Options {
    let mut opts = Options::new();

    // Sorted in alphabetical order.
    opts.optopt(
        "",
        "color",
        "Use colored output (if supported)",
        "[always|never|auto]",
    );
    opts.optflag(
        "",
        "config-help",
        "Show details of rustfmt configuration options",
    );
    opts.optopt(
        "",
        "config-path",
        "Recursively searches the given path for the rustfmt.toml config file. If not \
         found reverts to the input file path",
        "[Path for the configuration file]",
    );
    opts.opt(
        "",
        "dump-default-config",
        "Dumps default configuration to PATH. PATH defaults to stdout, if omitted.",
        "PATH",
        getopts::HasArg::Maybe,
        getopts::Occur::Optional,
    );
    opts.optopt(
        "",
        "dump-minimal-config",
        "Dumps configuration options that were checked during formatting to a file.",
        "PATH",
    );
    opts.optflag(
        "",
        "error-on-unformatted",
        "Error if unable to get comments or string literals within max_width, \
         or they are left with trailing whitespaces",
    );
    opts.optopt(
        "",
        "file-lines",
        "Format specified line ranges. See README for more detail on the JSON format.",
        "JSON",
    );
    opts.optflag("h", "help", "Show this message");
    opts.optflag("", "skip-children", "Don't reformat child modules");
    opts.optflag(
        "",
        "unstable-features",
        "Enables unstable features. Only available on nightly channel",
    );
    opts.optflag("v", "verbose", "Print verbose output");
    opts.optflag("q", "quiet", "Print less output");
    opts.optflag("V", "version", "Show version information");
    opts.optopt(
        "",
        "write-mode",
        "How to write output (not usable when piping from stdin)",
        WRITE_MODE_LIST,
    );

    opts
}

fn execute(opts: &Options) -> FmtResult<(WriteMode, Summary)> {
    let matches = opts.parse(env::args().skip(1))?;

    match determine_operation(&matches)? {
        Operation::Help => {
            print_usage_to_stdout(opts, "");
            Summary::print_exit_codes();
            Ok((WriteMode::None, Summary::default()))
        }
        Operation::Version => {
            print_version();
            Ok((WriteMode::None, Summary::default()))
        }
        Operation::ConfigHelp => {
            Config::print_docs(&mut stdout(), matches.opt_present("unstable-features"));
            Ok((WriteMode::None, Summary::default()))
        }
        Operation::ConfigOutputDefault { path } => {
            let toml = Config::default().all_options().to_toml().map_err(err_msg)?;
            if let Some(path) = path {
                let mut file = File::create(path)?;
                file.write_all(toml.as_bytes())?;
            } else {
                io::stdout().write_all(toml.as_bytes())?;
            }
            Ok((WriteMode::None, Summary::default()))
        }
        Operation::Stdin { input } => {
            // try to read config from local directory
            let options = CliOptions::from_matches(&matches)?;
            let (mut config, _) = load_config(Some(Path::new(".")), Some(&options))?;

            // write_mode is always Display for Stdin.
            config.set().write_mode(WriteMode::Display);
            config.set().verbose(Verbosity::Quiet);

            // parse file_lines
            if let Some(ref file_lines) = matches.opt_str("file-lines") {
                config
                    .set()
                    .file_lines(file_lines.parse().map_err(err_msg)?);
                for f in config.file_lines().files() {
                    match *f {
                        FileName::Custom(ref f) if f == "stdin" => {}
                        _ => eprintln!("Warning: Extra file listed in file_lines option '{}'", f),
                    }
                }
            }

            let mut error_summary = Summary::default();
            emit_pre_matter(&config)?;
            match format_and_emit_report(Input::Text(input), &config) {
                Ok(summary) => error_summary.add(summary),
                Err(_) => error_summary.add_operational_error(),
            }
            emit_post_matter(&config)?;

            Ok((WriteMode::Display, error_summary))
        }
        Operation::Format {
            files,
            minimal_config_path,
        } => {
            let options = CliOptions::from_matches(&matches)?;
            format(files, minimal_config_path, options)
        }
    }
}

fn format(
    files: Vec<PathBuf>,
    minimal_config_path: Option<String>,
    options: CliOptions,
) -> FmtResult<(WriteMode, Summary)> {
    options.verify_file_lines(&files);
    let (config, config_path) = load_config(None, Some(&options))?;

    if config.verbose() == Verbosity::Verbose {
        if let Some(path) = config_path.as_ref() {
            println!("Using rustfmt config file {}", path.display());
        }
    }

    emit_pre_matter(&config)?;
    let mut error_summary = Summary::default();

    for file in files {
        if !file.exists() {
            eprintln!("Error: file `{}` does not exist", file.to_str().unwrap());
            error_summary.add_operational_error();
        } else if file.is_dir() {
            eprintln!("Error: `{}` is a directory", file.to_str().unwrap());
            error_summary.add_operational_error();
        } else {
            // Check the file directory if the config-path could not be read or not provided
            let local_config = if config_path.is_none() {
                let (local_config, config_path) =
                    load_config(Some(file.parent().unwrap()), Some(&options))?;
                if local_config.verbose() == Verbosity::Verbose {
                    if let Some(path) = config_path {
                        println!(
                            "Using rustfmt config file {} for {}",
                            path.display(),
                            file.display()
                        );
                    }
                }
                local_config
            } else {
                config.clone()
            };

            match format_and_emit_report(Input::File(file), &local_config) {
                Ok(summary) => error_summary.add(summary),
                Err(_) => {
                    error_summary.add_operational_error();
                    break;
                }
            }
        }
    }
    emit_post_matter(&config)?;

    // If we were given a path via dump-minimal-config, output any options
    // that were used during formatting as TOML.
    if let Some(path) = minimal_config_path {
        let mut file = File::create(path)?;
        let toml = config.used_options().to_toml().map_err(err_msg)?;
        file.write_all(toml.as_bytes())?;
    }

    Ok((config.write_mode(), error_summary))
}

fn print_usage_to_stdout(opts: &Options, reason: &str) {
    let sep = if reason.is_empty() {
        String::new()
    } else {
        format!("{}\n\n", reason)
    };
    let msg = format!(
        "{}Format Rust code\n\nusage: {} [options] <file>...",
        sep,
        env::args_os().next().unwrap().to_string_lossy()
    );
    println!("{}", opts.usage(&msg));
}

fn print_version() {
    let version_info = format!(
        "{}-{}",
        option_env!("CARGO_PKG_VERSION").unwrap_or("unknown"),
        include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt"))
    );

    println!("rustfmt {}", version_info);
}

fn determine_operation(matches: &Matches) -> FmtResult<Operation> {
    if matches.opt_present("h") {
        return Ok(Operation::Help);
    }

    if matches.opt_present("config-help") {
        return Ok(Operation::ConfigHelp);
    }

    if matches.opt_present("dump-default-config") {
        // NOTE for some reason when configured with HasArg::Maybe + Occur::Optional opt_default
        // doesn't recognize `--foo bar` as a long flag with an argument but as a long flag with no
        // argument *plus* a free argument. Thus we check for that case in this branch -- this is
        // required for backward compatibility.
        if let Some(path) = matches.free.get(0) {
            return Ok(Operation::ConfigOutputDefault {
                path: Some(path.clone()),
            });
        } else {
            return Ok(Operation::ConfigOutputDefault {
                path: matches.opt_str("dump-default-config"),
            });
        }
    }

    if matches.opt_present("version") {
        return Ok(Operation::Version);
    }

    // If no path is given, we won't output a minimal config.
    let minimal_config_path = matches.opt_str("dump-minimal-config");

    // if no file argument is supplied, read from stdin
    if matches.free.is_empty() {
        let mut buffer = String::new();
        io::stdin().read_to_string(&mut buffer)?;

        return Ok(Operation::Stdin { input: buffer });
    }

    let files: Vec<_> = matches
        .free
        .iter()
        .map(|s| {
            let p = PathBuf::from(s);
            // we will do comparison later, so here tries to canonicalize first
            // to get the expected behavior.
            p.canonicalize().unwrap_or(p)
        })
        .collect();

    Ok(Operation::Format {
        files,
        minimal_config_path,
    })
}
<commit_msg>`--help` options<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![cfg(not(test))]

extern crate env_logger;
extern crate failure;
extern crate getopts;
extern crate rustfmt_nightly as rustfmt;

use std::env;
use std::fs::File;
use std::io::{self, stdout, Read, Write};
use std::path::{Path, PathBuf};

use failure::err_msg;

use getopts::{Matches, Options};

use rustfmt::{
    emit_post_matter, emit_pre_matter, format_and_emit_report, load_config, CliOptions, Config,
    FileName, FmtResult, Input, Summary, Verbosity, WriteMode, WRITE_MODE_LIST,
};

fn main() {
    env_logger::init();
    let opts = make_opts();

    let exit_code = match execute(&opts) {
        Ok((write_mode, summary)) => {
            if summary.has_operational_errors()
                || summary.has_parsing_errors()
                || (summary.has_diff && write_mode == WriteMode::Check)
            {
                1
            } else {
                0
            }
        }
        Err(e) => {
            eprintln!("{}", e.to_string());
            1
        }
    };
    // Make sure standard output is flushed before we exit.
    std::io::stdout().flush().unwrap();

    // Exit with given exit code.
    //
    // NOTE: This immediately terminates the process without doing any cleanup,
    // so make sure to finish all necessary cleanup before this is called.
    std::process::exit(exit_code);
}

/// Rustfmt operations.
enum Operation {
    /// Format files and their child modules.
    Format {
        files: Vec<PathBuf>,
        minimal_config_path: Option<String>,
    },
    /// Print the help message.
    Help(HelpOp),
    // Print version information
    Version,
    /// Output default config to a file, or stdout if None
    ConfigOutputDefault {
        path: Option<String>,
    },
    /// No file specified, read from stdin
    Stdin {
        input: String,
    },
}

/// Arguments to `--help`
enum HelpOp {
    None,
    Config,
    FileLines,
}

fn make_opts() -> Options {
    let mut opts = Options::new();

    // Sorted in alphabetical order.
    opts.optopt(
        "",
        "color",
        "Use colored output (if supported)",
        "[always|never|auto]",
    );
    opts.optopt(
        "",
        "config-path",
        "Recursively searches the given path for the rustfmt.toml config file. If not \
         found reverts to the input file path",
        "[Path for the configuration file]",
    );
    opts.opt(
        "",
        "dump-default-config",
        "Dumps default configuration to PATH. PATH defaults to stdout, if omitted.",
        "PATH",
        getopts::HasArg::Maybe,
        getopts::Occur::Optional,
    );
    opts.optopt(
        "",
        "dump-minimal-config",
        "Dumps configuration options that were checked during formatting to a file.",
        "PATH",
    );
    opts.optflag(
        "",
        "error-on-unformatted",
        "Error if unable to get comments or string literals within max_width, \
         or they are left with trailing whitespaces",
    );
    opts.optopt(
        "",
        "file-lines",
        "Format specified line ranges. See README for more detail on the JSON format.",
        "JSON",
    );
    opts.optflagopt(
        "h",
        "help",
        "Show this message or help about a specific topic: config or file-lines",
        "=TOPIC",
    );
    opts.optflag("", "skip-children", "Don't reformat child modules");
    opts.optflag(
        "",
        "unstable-features",
        "Enables unstable features. Only available on nightly channel",
    );
    opts.optflag("v", "verbose", "Print verbose output");
    opts.optflag("q", "quiet", "Print less output");
    opts.optflag("V", "version", "Show version information");
    opts.optopt(
        "",
        "write-mode",
        "How to write output (not usable when piping from stdin)",
        WRITE_MODE_LIST,
    );

    opts
}

fn execute(opts: &Options) -> FmtResult<(WriteMode, Summary)> {
    let matches = opts.parse(env::args().skip(1))?;

    match determine_operation(&matches)? {
        Operation::Help(HelpOp::None) => {
            print_usage_to_stdout(opts, "");
            Summary::print_exit_codes();
            Ok((WriteMode::None, Summary::default()))
        }
        Operation::Help(HelpOp::Config) => {
            Config::print_docs(&mut stdout(), matches.opt_present("unstable-features"));
            Ok((WriteMode::None, Summary::default()))
        }
        Operation::Help(HelpOp::FileLines) => {
            print_help_file_lines();
            Ok((WriteMode::None, Summary::default()))
        }
        Operation::Version => {
            print_version();
            Ok((WriteMode::None, Summary::default()))
        }
        Operation::ConfigOutputDefault { path } => {
            let toml = Config::default().all_options().to_toml().map_err(err_msg)?;
            if let Some(path) = path {
                let mut file = File::create(path)?;
                file.write_all(toml.as_bytes())?;
            } else {
                io::stdout().write_all(toml.as_bytes())?;
            }
            Ok((WriteMode::None, Summary::default()))
        }
        Operation::Stdin { input } => {
            // try to read config from local directory
            let options = CliOptions::from_matches(&matches)?;
            let (mut config, _) = load_config(Some(Path::new(".")), Some(&options))?;

            // write_mode is always Display for Stdin.
            config.set().write_mode(WriteMode::Display);
            config.set().verbose(Verbosity::Quiet);

            // parse file_lines
            if let Some(ref file_lines) = matches.opt_str("file-lines") {
                config
                    .set()
                    .file_lines(file_lines.parse().map_err(err_msg)?);
                for f in config.file_lines().files() {
                    match *f {
                        FileName::Custom(ref f) if f == "stdin" => {}
                        _ => eprintln!("Warning: Extra file listed in file_lines option '{}'", f),
                    }
                }
            }

            let mut error_summary = Summary::default();
            emit_pre_matter(&config)?;
            match format_and_emit_report(Input::Text(input), &config) {
                Ok(summary) => error_summary.add(summary),
                Err(_) => error_summary.add_operational_error(),
            }
            emit_post_matter(&config)?;

            Ok((WriteMode::Display, error_summary))
        }
        Operation::Format {
            files,
            minimal_config_path,
        } => {
            let options = CliOptions::from_matches(&matches)?;
            format(files, minimal_config_path, options)
        }
    }
}

fn format(
    files: Vec<PathBuf>,
    minimal_config_path: Option<String>,
    options: CliOptions,
) -> FmtResult<(WriteMode, Summary)> {
    options.verify_file_lines(&files);
    let (config, config_path) = load_config(None, Some(&options))?;

    if config.verbose() == Verbosity::Verbose {
        if let Some(path) = config_path.as_ref() {
            println!("Using rustfmt config file {}", path.display());
        }
    }

    emit_pre_matter(&config)?;
    let mut error_summary = Summary::default();

    for file in files {
        if !file.exists() {
            eprintln!("Error: file `{}` does not exist", file.to_str().unwrap());
            error_summary.add_operational_error();
        } else if file.is_dir() {
            eprintln!("Error: `{}` is a directory", file.to_str().unwrap());
            error_summary.add_operational_error();
        } else {
            // Check the file directory if the config-path could not be read or not provided
            let local_config = if config_path.is_none() {
                let (local_config, config_path) =
                    load_config(Some(file.parent().unwrap()), Some(&options))?;
                if local_config.verbose() == Verbosity::Verbose {
                    if let Some(path) = config_path {
                        println!(
                            "Using rustfmt config file {} for {}",
                            path.display(),
                            file.display()
                        );
                    }
                }
                local_config
            } else {
                config.clone()
            };

            match format_and_emit_report(Input::File(file), &local_config) {
                Ok(summary) => error_summary.add(summary),
                Err(_) => {
                    error_summary.add_operational_error();
                    break;
                }
            }
        }
    }
    emit_post_matter(&config)?;

    // If we were given a path via dump-minimal-config, output any options
    // that were used during formatting as TOML.
    if let Some(path) = minimal_config_path {
        let mut file = File::create(path)?;
        let toml = config.used_options().to_toml().map_err(err_msg)?;
        file.write_all(toml.as_bytes())?;
    }

    Ok((config.write_mode(), error_summary))
}

fn print_usage_to_stdout(opts: &Options, reason: &str) {
    let sep = if reason.is_empty() {
        String::new()
    } else {
        format!("{}\n\n", reason)
    };
    let msg = format!(
        "{}Format Rust code\n\nusage: {} [options] <file>...",
        sep,
        env::args_os().next().unwrap().to_string_lossy()
    );
    println!("{}", opts.usage(&msg));
}

fn print_help_file_lines() {
    println!("If you want to restrict reformatting to specific sets of lines, you can
use the `--file-lines` option. Its argument is a JSON array of objects
with `file` and `range` properties, where `file` is a file name, and
`range` is an array representing a range of lines like `[7,13]`. Ranges
are 1-based and inclusive of both end points. Specifying an empty array
will result in no files being formatted. For example,

```
rustfmt --file-lines '[
    {{\"file\":\"src/lib.rs\",\"range\":[7,13]}},
    {{\"file\":\"src/lib.rs\",\"range\":[21,29]}},
    {{\"file\":\"src/foo.rs\",\"range\":[10,11]}},
    {{\"file\":\"src/foo.rs\",\"range\":[15,15]}}]'
```

would format lines `7-13` and `21-29` of `src/lib.rs`, and lines `10-11`,
and `15` of `src/foo.rs`. No other files would be formatted, even if they
are included as out of line modules from `src/lib.rs`.");
}

fn print_version() {
    let version_info = format!(
        "{}-{}",
        option_env!("CARGO_PKG_VERSION").unwrap_or("unknown"),
        include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt"))
    );

    println!("rustfmt {}", version_info);
}

fn determine_operation(matches: &Matches) -> FmtResult<Operation> {
    if matches.opt_present("h") {
        let topic = matches.opt_str("h");
        if topic == None {
            return Ok(Operation::Help(HelpOp::None));
        } else if topic == Some("config".to_owned()) {
            return Ok(Operation::Help(HelpOp::Config));
        } else if topic == Some("file-lines".to_owned()) {
            return Ok(Operation::Help(HelpOp::FileLines));
        } else {
            println!("Unknown help topic: `{}`\n", topic.unwrap());
            return Ok(Operation::Help(HelpOp::None));
        }
    }

    if matches.opt_present("dump-default-config") {
        // NOTE for some reason when configured with HasArg::Maybe + Occur::Optional opt_default
        // doesn't recognize `--foo bar` as a long flag with an argument but as a long flag with no
        // argument *plus* a free argument. Thus we check for that case in this branch -- this is
        // required for backward compatibility.
        if let Some(path) = matches.free.get(0) {
            return Ok(Operation::ConfigOutputDefault {
                path: Some(path.clone()),
            });
        } else {
            return Ok(Operation::ConfigOutputDefault {
                path: matches.opt_str("dump-default-config"),
            });
        }
    }

    if matches.opt_present("version") {
        return Ok(Operation::Version);
    }

    // If no path is given, we won't output a minimal config.
    let minimal_config_path = matches.opt_str("dump-minimal-config");

    // if no file argument is supplied, read from stdin
    if matches.free.is_empty() {
        let mut buffer = String::new();
        io::stdin().read_to_string(&mut buffer)?;

        return Ok(Operation::Stdin { input: buffer });
    }

    let files: Vec<_> = matches
        .free
        .iter()
        .map(|s| {
            let p = PathBuf::from(s);
            // we will do comparison later, so here tries to canonicalize first
            // to get the expected behavior.
            p.canonicalize().unwrap_or(p)
        })
        .collect();

    Ok(Operation::Format {
        files,
        minimal_config_path,
    })
}
<|endoftext|>


<commit_before>//
// MSX CAS Packager
// Copyright (c) 2015 Alvaro Polo
//
// 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/.

use std::io::Read;
use std::io::Error as IoError;
use std::str::from_utf8;

#[derive(Debug)]
pub struct Block { data: Vec<u8>, }

impl Block {

    pub fn from_bytes(bytes: &[u8]) -> Block {
        Block { data: Vec::from(bytes) }
    }

    pub fn is_bin_header(&self) -> bool {
        self.data.len() >= 16 &&
            self.data[..10] == [0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0]
    }

    pub fn file_name(&self) -> Option<&str> {
        if self.is_bin_header() {
            let name = &self.data[10..16];
            let mut last = 6;
            for i in (0..6).rev() {
                if name[i] == 0 { last = i }
            }
            from_utf8(&name[..last]).ok()
        }
        else { None }
    }
}

#[derive(Debug, PartialEq)]
pub enum File<'a> {
	Bin(String, usize, usize, usize, &'a[u8]),
    Custom(&'a[u8])
}

pub struct Files<'a> {
    tape: &'a Tape,
    i: usize,
}

impl<'a> Iterator for Files<'a> {

    type Item = File<'a>;

    fn next(&mut self) -> Option<File<'a>> {
        while self.i < self.tape.blocks.len() {
            let block = &self.tape.blocks[self.i];
            if block.is_bin_header() {
                let name = block.file_name().unwrap().to_string();
                let content = &self.tape.blocks[self.i+1].data;
                let begin = (content[0] as usize) | (content[1] as usize) << 8;
                let end = (content[2] as usize) | (content[3] as usize) << 8;
                let start = (content[4] as usize) | (content[5] as usize) << 8;
                let data = &content[6..];
                self.i = self.i + 2;
                return Some(File::Bin(name, begin, end, start, data));
            } else {
                self.i = self.i + 1;
                return Some(File::Custom(&block.data[..]));
            }
        }
        None
    }
}

#[derive(Debug)]
pub struct Tape {
    blocks: Vec<Block>,
}

#[derive(Debug)]
pub enum LoadError {
	Io(IoError),
}

impl From<IoError> for LoadError {
	fn from(e: IoError) -> LoadError { LoadError::Io(e) }
}

impl Tape {

	#[allow(dead_code)]
	pub fn read(input: &mut Read) -> Result<Tape, LoadError> {
		let mut bytes: Vec<u8> = vec![];
		try!(input.read_to_end(&mut bytes));
		Tape::from_bytes(&bytes[..])
	}

	pub fn from_bytes(bytes: &[u8]) -> Result<Tape, LoadError> {
		Ok(Tape { blocks: Tape::parse_blocks(bytes) })
	}

    pub fn files(&self) -> Files { Files { tape: self, i: 0 } }

    fn parse_blocks(bytes: &[u8]) -> Vec<Block> {
        let mut blocks: Vec<Block> = vec![];
        let mut hindex: Vec<usize> = vec![];
        let mut i = 0;

        // First of all, we compute the indices of all block headers.
        for win in bytes.windows(8) {
            if win == [0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74] {
                hindex.push(i);
            }
            i = i + 1;
        }

        // Now we use the block header indices to generate the blocks
        for i in 0..hindex.len() {
            let from = hindex[i] + 8;
            let to = if i == hindex.len() - 1 { bytes.len() } else { hindex[i+1] };
            let block = Block::from_bytes(&bytes[from..to]);
            blocks.push(block);
        }
        blocks
    }
}

#[cfg(test)]
mod test {

    use super::*;

    macro_rules! assert_bin {
        ($f:expr, $n:expr, $b:expr, $e:expr, $s:expr, $d:expr) => {
            match $f {
            &File::Bin(ref name, begin, end, start, data) => {
                assert_eq!($n, name);
                assert_eq!($b, begin);
                assert_eq!($e, end);
                assert_eq!($s, start);
                assert_eq!($d, &data[..]);
            },
            _ => panic!("unexpected file"),
        }
        }
    }

    #[test]
    fn should_detect_bin_header_block() {
        let bytes: Vec<u8> = vec![
            0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0,
            0x46, 0x4f, 0x4f, 0x42, 0x41, 0x52,
            0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74,
            0x00, 0x80, 0x08, 0x80, 0x00, 0x00,
            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
        ];
        let block = Block::from_bytes(&bytes);
        assert!(block.is_bin_header());
        assert_eq!("FOOBAR", block.file_name().unwrap());
    }

    #[test]
    fn should_detect_block_with_short_name() {
        let bytes: Vec<u8> = vec![
            0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0,
            0x46, 0x4f, 0x4f, 0x00, 0x00, 0x00,
            0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74,
            0x00, 0x80, 0x08, 0x80, 0x00, 0x00,
            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
        ];
        let block = Block::from_bytes(&bytes);
        assert!(block.is_bin_header());
        assert_eq!("FOO", block.file_name().unwrap());
    }

    #[test]
    fn should_load_empty_tape() {
    	let bytes: Vec<u8> = vec![];
    	let tape = Tape::from_bytes(&bytes);
        assert!(tape.is_ok());
        assert_eq!(None, tape.unwrap().files().next());
    }

    #[test]
    fn should_load_bin_file() {
        let bytes: Vec<u8> = vec![
            0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74,
            0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0,
            0x46, 0x4f, 0x4f, 0x42, 0x41, 0x52,
            0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74,
            0x00, 0x80, 0x08, 0x80, 0x00, 0x00,
            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
        ];
        let tape = Tape::from_bytes(&bytes).unwrap();
        for f in tape.files() {
            assert_bin!(&f,
                "FOOBAR", 0x8000, 0x8008, 0x0000, &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]);
        }
    }
}
<commit_msg>Remove useless `LoadError` from `tape`<commit_after>//
// MSX CAS Packager
// Copyright (c) 2015 Alvaro Polo
//
// 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/.

use std::io::Read;
use std::io::Error as IoError;
use std::str::from_utf8;

#[derive(Debug)]
pub struct Block { data: Vec<u8>, }

impl Block {

    pub fn from_bytes(bytes: &[u8]) -> Block {
        Block { data: Vec::from(bytes) }
    }

    pub fn is_bin_header(&self) -> bool {
        self.data.len() >= 16 &&
            self.data[..10] == [0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0]
    }

    pub fn file_name(&self) -> Option<&str> {
        if self.is_bin_header() {
            let name = &self.data[10..16];
            let mut last = 6;
            for i in (0..6).rev() {
                if name[i] == 0 { last = i }
            }
            from_utf8(&name[..last]).ok()
        }
        else { None }
    }
}

#[derive(Debug, PartialEq)]
pub enum File<'a> {
	Bin(String, usize, usize, usize, &'a[u8]),
    Custom(&'a[u8])
}

pub struct Files<'a> {
    tape: &'a Tape,
    i: usize,
}

impl<'a> Iterator for Files<'a> {

    type Item = File<'a>;

    fn next(&mut self) -> Option<File<'a>> {
        while self.i < self.tape.blocks.len() {
            let block = &self.tape.blocks[self.i];
            if block.is_bin_header() {
                let name = block.file_name().unwrap().to_string();
                let content = &self.tape.blocks[self.i+1].data;
                let begin = (content[0] as usize) | (content[1] as usize) << 8;
                let end = (content[2] as usize) | (content[3] as usize) << 8;
                let start = (content[4] as usize) | (content[5] as usize) << 8;
                let data = &content[6..];
                self.i = self.i + 2;
                return Some(File::Bin(name, begin, end, start, data));
            } else {
                self.i = self.i + 1;
                return Some(File::Custom(&block.data[..]));
            }
        }
        None
    }
}

#[derive(Debug)]
pub struct Tape {
    blocks: Vec<Block>,
}

impl Tape {

	#[allow(dead_code)]
	pub fn read(input: &mut Read) -> Result<Tape, IoError> {
		let mut bytes: Vec<u8> = vec![];
		try!(input.read_to_end(&mut bytes));
		Ok(Tape::from_bytes(&bytes[..]))
	}

	pub fn from_bytes(bytes: &[u8]) -> Tape {
		Tape { blocks: Tape::parse_blocks(bytes) }
	}

    pub fn files(&self) -> Files { Files { tape: self, i: 0 } }

    fn parse_blocks(bytes: &[u8]) -> Vec<Block> {
        let mut blocks: Vec<Block> = vec![];
        let mut hindex: Vec<usize> = vec![];
        let mut i = 0;

        // First of all, we compute the indices of all block headers.
        for win in bytes.windows(8) {
            if win == [0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74] {
                hindex.push(i);
            }
            i = i + 1;
        }

        // Now we use the block header indices to generate the blocks
        for i in 0..hindex.len() {
            let from = hindex[i] + 8;
            let to = if i == hindex.len() - 1 { bytes.len() } else { hindex[i+1] };
            let block = Block::from_bytes(&bytes[from..to]);
            blocks.push(block);
        }
        blocks
    }
}

#[cfg(test)]
mod test {

    use super::*;

    macro_rules! assert_bin {
        ($f:expr, $n:expr, $b:expr, $e:expr, $s:expr, $d:expr) => {
            match $f {
            &File::Bin(ref name, begin, end, start, data) => {
                assert_eq!($n, name);
                assert_eq!($b, begin);
                assert_eq!($e, end);
                assert_eq!($s, start);
                assert_eq!($d, &data[..]);
            },
            _ => panic!("unexpected file"),
        }
        }
    }

    #[test]
    fn should_detect_bin_header_block() {
        let bytes: Vec<u8> = vec![
            0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0,
            0x46, 0x4f, 0x4f, 0x42, 0x41, 0x52,
            0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74,
            0x00, 0x80, 0x08, 0x80, 0x00, 0x00,
            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
        ];
        let block = Block::from_bytes(&bytes);
        assert!(block.is_bin_header());
        assert_eq!("FOOBAR", block.file_name().unwrap());
    }

    #[test]
    fn should_detect_block_with_short_name() {
        let bytes: Vec<u8> = vec![
            0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0,
            0x46, 0x4f, 0x4f, 0x00, 0x00, 0x00,
            0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74,
            0x00, 0x80, 0x08, 0x80, 0x00, 0x00,
            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
        ];
        let block = Block::from_bytes(&bytes);
        assert!(block.is_bin_header());
        assert_eq!("FOO", block.file_name().unwrap());
    }

    #[test]
    fn should_load_empty_tape() {
    	let bytes: Vec<u8> = vec![];
    	let tape = Tape::from_bytes(&bytes);
        assert_eq!(None, tape.files().next());
    }

    #[test]
    fn should_load_bin_file() {
        let bytes: Vec<u8> = vec![
            0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74,
            0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0,
            0x46, 0x4f, 0x4f, 0x42, 0x41, 0x52,
            0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74,
            0x00, 0x80, 0x08, 0x80, 0x00, 0x00,
            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
        ];
        let tape = Tape::from_bytes(&bytes);
        for f in tape.files() {
            assert_bin!(&f,
                "FOOBAR", 0x8000, 0x8008, 0x0000, &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]);
        }
    }
}
<|endoftext|>


<commit_before>// option1.rs
// This example panics because the second time it calls `pop`, the `vec`
// is empty, so `pop` returns `None`, and `unwrap` panics if it's called
// on `None`. Handle this in a more graceful way than calling `unwrap`!
// Scroll down for hints :)

pub fn pop_too_much() -> bool {
    let mut list = vec![3];

    let last = list.pop().unwrap();
    println!("The last item in the list is {:?}", last);

    let second_to_last = list.pop().unwrap();
    println!(
        "The second-to-last item in the list is {:?}",
        second_to_last
    );
    true
}

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

    #[test]
    fn should_not_panic() {
        assert!(pop_too_much(), true);
    }
}

// Try using a `match` statement where the arms are `Some(thing)` and `None`.
// Or set a default value to print out if you get `None` by using the
// function `unwrap_or`.
// Or use an `if let` statement on the result of `pop()` to both destructure
// a `Some` value and only print out something if we have a value!
<commit_msg>fix(option1): Fix arguments passed to assert! macro<commit_after>// option1.rs
// This example panics because the second time it calls `pop`, the `vec`
// is empty, so `pop` returns `None`, and `unwrap` panics if it's called
// on `None`. Handle this in a more graceful way than calling `unwrap`!
// Scroll down for hints :)

pub fn pop_too_much() -> bool {
    let mut list = vec![3];

    let last = list.pop().unwrap();
    println!("The last item in the list is {:?}", last);

    let second_to_last = list.pop().unwrap();
    println!(
        "The second-to-last item in the list is {:?}",
        second_to_last
    );
    true
}

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

    #[test]
    fn should_not_panic() {
        assert!(pop_too_much());
    }
}

// Try using a `match` statement where the arms are `Some(thing)` and `None`.
// Or set a default value to print out if you get `None` by using the
// function `unwrap_or`.
// Or use an `if let` statement on the result of `pop()` to both destructure
// a `Some` value and only print out something if we have a value!
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::vec::Vec;
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use std::cell::Cell;

use variable::{TVar};
use res::{StmResult};

static GLOBAL_SEQ_LOCK: AtomicUsize = ATOMIC_USIZE_INIT;

pub struct Transaction {
    snapshot : usize,
    writeSet: HashMap<&mut TVar<T>, u32>,
    readSet: Vec<(&mut TVar<T>, u32)>,
}

impl Transaction {
    fn new(ss: usize) -> Transaction {
        Transaction {
            snapShot: ss,
            writeSet: BTreeMap::new(),
            readSet: Vec::new(),
        }
    }

    pub fn run<T, F>(f: F) -> T
    where F: Fn(&mut Transaction) -> StmResult<T>,
    {
        let mut ss = GLOBAL_SEQ_LOCK.load(Ordering::SeqCst);
        while (ss & 1) != 0 {
            ss = GLOBAL_SEQ_LOCK.load(Ordering::SeqCst);
        }
        let mut transaction = Transaction::new(ss);
        loop {
            match f(&mut transaction) {
                Ok(t) => {
                    if transaction.commit() {
                        return t;
                    }
                }
                Err(_) => { }
            }
            transaction.clear();
        }
    }

    pub fn read<T>(&mut self, var: &mut TVar<T>) -> StmResult<T> {
        match self.writeSet.get(&var) {
            Some(&val) => { return Ok(val) }
            None => {}
        };
        let mut val = (*var).value;
        while self.snapshot != GLOBAL_SEQ_LOCK.load(Ordering::SeqCst) {
            self.snapshot = self.validate();
            val = (*var).value;
            if self.snapshot < 0 {
                return Err(Retry);
            }
        }
        self.readset.push((addr, val));
        Ok(val)
    }

    pub fn write<T>(&mut self, var: &mut TVar<T>, value: T) -> StmResult<()> {
        self.writeSet.insert(var, value);
        Ok(())

    }

    fn clear(&mut self) {
        self.readSet.clear();
        self.writeSet.clear();
    }

    fn validate(&mut self) -> usize {
        loop {
            let mut time : usize = GLOBAL_SEQ_LOCK.load(Ordering::SeqCst);
            if (time & 1) != 0 {
                continue;
            }
            for (addr, val) in self.readSet {
                if (*addr).value != val {
                    return -1;
                }
            }
            if time == lock.load(Ordering::SeqCst) {
                return time;
            }
        }
    }

    fn commit(&mut self) -> bool {
        if self.writeSet.len() == 0 {
            return true;
        }
        while GLOBAL_SEQ_LOCK.compare_and_swap(self.snapshot, self.snapshot+1, Ordering::SeqCst) != self.snapshot {
            self.snapshot = self.validate();
            if self.snapshot < 0 {
                return false;
            }
        }
        for (addr, val) in self.writeSet.iter() {
            (*addr).value = val;
        }
        GLOBAL_SEQ_LOCK.store(self.snapshot + 2, Ordering::SeqCst);
        return true;
    }
}

<commit_msg>slowly making it compile<commit_after>use std::collections::HashMap;
use std::vec::Vec;
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use std::cell::Cell;

use variable::{TVar};
use res::{StmResult};

static GLOBAL_SEQ_LOCK: AtomicUsize = ATOMIC_USIZE_INIT;

struct Address(pub usize);
struct Value(pub usize);

pub struct Transaction {
    snapshot : usize,
    writeSet: HashMap<Address, Value>,
    readSet: Vec<(Address, Value)>,
}

impl Transaction {
    // XXX what is this ss???
    fn new(ss: usize) -> Transaction {
        Transaction {
            snapShot: ss,
            writeSet: HashMap::new(),
            readSet: Vec::new(),
        }
    }

    pub fn run<T, F>(f: F) -> T
    where F: Fn(&mut Transaction) -> StmResult<T>,
    {
        let mut ss = GLOBAL_SEQ_LOCK.load(Ordering::SeqCst);
        while (ss & 1) != 0 {
            ss = GLOBAL_SEQ_LOCK.load(Ordering::SeqCst);
        }
        let mut transaction = Transaction::new(ss);
        loop {
            match f(&mut transaction) {
                Ok(t) => {
                    if transaction.commit() {
                        return t;
                    }
                }
                Err(_) => { }
            }
            transaction.clear();
        }
    }

    pub fn read<T>(&mut self, var: &mut TVar<T>) -> StmResult<T> {
        match self.writeSet.get(&var) {
            Some(&val) => { return Ok(val) }
            None => {}
        };
        let mut val = (*var).value;
        while self.snapshot != GLOBAL_SEQ_LOCK.load(Ordering::SeqCst) {
            self.snapshot = self.validate();
            val = (*var).value;
            if self.snapshot < 0 {
                return Err(Retry);
            }
        }
        self.readset.push((addr, val));
        Ok(val)
    }

    pub fn write<T>(&mut self, var: &mut TVar<T>, value: T) -> StmResult<()> {
        self.writeSet.insert(var, value);
        Ok(())

    }

    fn clear(&mut self) {
        self.readSet.clear();
        self.writeSet.clear();
    }

    fn validate(&self) -> Option<usize> {
        loop {
            let time = GLOBAL_SEQ_LOCK.load(Ordering::SeqCst);
            if time & 1 != 0 {
                continue;
            }
            for (addr, val) in self.readSet {
                if (*addr).value != val {
                    // XXX this should handle aborts more... "gracefully"?
                    return None;
                }
            }
            if time == GLOBAL_SEQ_LOCK.load(Ordering::SeqCst) {
                return Some(time);
            }
        }
    }

    fn commit(&mut self) -> bool {
        if self.writeSet.is_empty() {
            return true;
        }
        while GLOBAL_SEQ_LOCK.compare_and_swap(self.snapshot, self.snapshot+1, Ordering::SeqCst) != self.snapshot {
            self.snapshot = self.validate();
            if self.snapshot < 0 {
                // XXX I'm sorry, why is this bailing?
                return false;
            }
        }
        for (addr, val) in self.writeSet.iter() {
            (*addr).value = val;
        }
        // XXX is this really just a plain store? seems sketchy
        GLOBAL_SEQ_LOCK.store(self.snapshot + 2, Ordering::SeqCst);
        return true;
    }
}

<|endoftext|>


<commit_before>// Copyright (C) 2020 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use common::{
    create_mock_server, format_output_client_log, format_output_server, get_output_server,
    remove_carriage_newline_characters, run_client_log, run_client_probe, FakeServer, Polling,
    Server, Settings, StopMessage,
};

pub mod common;

#[test]
fn failing_invalid_download_dir() {
    let tmp_dir = tempfile::tempdir().unwrap();
    let mut perms = std::fs::metadata(tmp_dir.path()).unwrap().permissions();
    perms.set_readonly(true);
    std::fs::set_permissions(tmp_dir.path(), perms).unwrap();

    let setup = Settings::default();
    let (mut session, setup) =
        setup.download_dir(tmp_dir.path().to_path_buf()).timeout(300).init_server();
    let _mocks = create_mock_server(FakeServer::HasUpdate(setup.firmware.data.product_uid.clone()));
    let output_server_1 = get_output_server(&mut session, StopMessage::Polling(Polling::Disable));

    let output_client = run_client_probe(Server::Standard);
    let output_server_2 = get_output_server(&mut session, StopMessage::Polling(Polling::Disable));
    let output_log = run_client_log();

    let (output_server_trce, output_server_info) = format_output_server(output_server_1);

    insta::assert_snapshot!(output_server_info, @r###"
    <timestamp> INFO starting UpdateHub Agent <version>
    "###);

    insta::assert_snapshot!(output_server_trce, @r###"
    <timestamp> INFO starting UpdateHub Agent <version>
    <timestamp> DEBG loading system settings from "<file>"...
    <timestamp> DEBG runtime settings file "<file>" does not exists, using default settings...
    <timestamp> DEBG polling is disabled, parking the state machine.
    <timestamp> DEBG staying on Park state.
    "###);

    insta::assert_snapshot!(format_output_server(output_server_2).0.trim(), @r###"
    <timestamp> DEBG receiving probe request
    <timestamp> TRCE Received external request: Probe(None)
    <timestamp> DEBG saving runtime settings from "<file>"...
    <timestamp> TRCE moving to Download state to process the update package.
    <timestamp> ERRO error state reached: Permission denied (os error 13)
    <timestamp> INFO returning to machine's entry point
    <timestamp> DEBG polling is disabled, parking the state machine.
    <timestamp> DEBG staying on Park state.
    "###);

    insta::assert_snapshot!(remove_carriage_newline_characters(output_client), @r###"
    Ok(
        Response {
            update_available: true,
            try_again_in: None,
        },
    )
    "###);

    insta::assert_snapshot!(format_output_client_log(output_log), @r###"
    Ok(
        [
            Entry {
                level: Debug,
                message: "loading system settings from "<file>",
                time: "<timestamp>",
                data: {},
            },
            Entry {
                level: Debug,
                message: "runtime settings file "<file>",
                time: "<timestamp>",
                data: {},
            },
            Entry {
                level: Debug,
                message: "polling is disabled, parking the state machine.",
                time: "<timestamp>",
                data: {},
            },
            Entry {
                level: Debug,
                message: "staying on Park state.",
                time: "<timestamp>",
                data: {},
            },
        ],
    )"###);
}

#[test]
#[cfg(not(feature = "v1-parsing"))]
fn failing_invalid_file_config() {
    use std::io::Write;

    let setup = Settings::default();
    let mut file = tempfile::NamedTempFile::new().unwrap();
    let file_path = file.path().to_owned();

    write!(
        file,
        r#"[network]
    server_address=https://api.updatehub.io, listen_socket=localhost:8080;"#
    )
    .unwrap();

    let (mut session, _setup) = setup.config_file(file_path).init_server();
    let output_server = session.exp_eof().unwrap();
    let (output_server_trce, ..) = format_output_server(output_server);

    insta::assert_snapshot!(output_server_trce, @r###"
    <timestamp> INFO starting UpdateHub Agent <version>
    <timestamp> DEBG loading system settings from "<file>"...
    unexpected character found: `/` at line 2 column 26
    "###);
}

#[test]
#[cfg(feature = "v1-parsing")]
fn failing_invalid_file_config() {
    use std::io::Write;

    let setup = Settings::default();
    let mut file = tempfile::NamedTempFile::new().unwrap();
    let file_path = file.path().to_owned();

    write!(
        file,
        r#"[network]
    server_address=https://api.updatehub.io, listen_socket=localhost:8080;"#
    )
    .unwrap();

    let (mut session, _setup) = setup.config_file(file_path).init_server();
    let output_server = session.exp_eof().unwrap();
    let (output_server_trce, ..) = format_output_server(output_server);

    insta::assert_snapshot!(output_server_trce, @r###"
    <timestamp> INFO starting UpdateHub Agent <version>
    <timestamp> DEBG loading system settings from "<file>"...
    Custom("missing field `Network`")
    "###);
}

#[test]
fn failing_invalid_server_address() {
    let setup = Settings::default();
    let (mut session, _setup) = setup.timeout(300).init_server();
    let _mocks = create_mock_server(FakeServer::NoUpdate);
    let output_server_1 = get_output_server(&mut session, StopMessage::Polling(Polling::Disable));

    let output_client = run_client_probe(Server::Custom("http://foo:--".to_string()));
    let output_server_2 = get_output_server(
        &mut session,
        StopMessage::Custom(
            "\r\n.* TRCE Received external request: Probe\\(Some\\(\"http://foo:--\"\\)\\).*"
                .to_string(),
        ),
    );
    let output_log = run_client_log();

    let (output_server_trce_1, output_server_info_1) = format_output_server(output_server_1);
    let (output_server_trce_2, ..) = format_output_server(output_server_2);

    insta::assert_snapshot!(output_server_info_1, @r###"
    <timestamp> INFO starting UpdateHub Agent <version>
    "###);

    insta::assert_snapshot!(output_server_trce_1, @r###"
    <timestamp> INFO starting UpdateHub Agent <version>
    <timestamp> DEBG loading system settings from "<file>"...
    <timestamp> DEBG runtime settings file "<file>" does not exists, using default settings...
    <timestamp> DEBG polling is disabled, parking the state machine.
    <timestamp> DEBG staying on Park state.
    "###);

    insta::assert_snapshot!(output_server_trce_2.trim(), @r###"
    <timestamp> DEBG receiving probe request
    "###);

    insta::assert_snapshot!(remove_carriage_newline_characters(output_client), @r###"
    Err(
        UnexpectedResponse(
            InternalServerError,
        ),
    )
    "###);
    insta::assert_snapshot!(format_output_client_log(output_log), @r###"
    Ok(
        [
            Entry {
                level: Debug,
                message: "loading system settings from "<file>",
                time: "<timestamp>",
                data: {},
            },
            Entry {
                level: Debug,
                message: "runtime settings file "<file>",
                time: "<timestamp>",
                data: {},
            },
            Entry {
                level: Debug,
                message: "polling is disabled, parking the state machine.",
                time: "<timestamp>",
                data: {},
            },
            Entry {
                level: Debug,
                message: "staying on Park state.",
                time: "<timestamp>",
                data: {},
            },
        ],
    )"###);
}

#[test]
fn failing_fail_check_requirements() {
    let setup = Settings::default();

    let (mut session, setup) = setup.timeout(300).init_server();
    let _mocks = create_mock_server(FakeServer::CheckRequirementsTest(
        setup.firmware.data.product_uid.clone(),
    ));
    let output_server_1 = get_output_server(&mut session, StopMessage::Polling(Polling::Disable));

    let output_client = run_client_probe(Server::Standard);
    let output_server_2 = get_output_server(&mut session, StopMessage::Polling(Polling::Disable));
    let output_log = run_client_log();

    let (output_server_trce_1, output_server_info_1) = format_output_server(output_server_1);
    let (output_server_trce_2, output_server_info_2) = format_output_server(output_server_2);

    insta::assert_snapshot!(output_server_info_1, @r###"
    <timestamp> INFO starting UpdateHub Agent <version>
    "###);

    insta::assert_snapshot!(output_server_trce_1, @r###"
    <timestamp> INFO starting UpdateHub Agent <version>
    <timestamp> DEBG loading system settings from "<file>"...
    <timestamp> DEBG runtime settings file "<file>" does not exists, using default settings...
    <timestamp> DEBG polling is disabled, parking the state machine.
    <timestamp> DEBG staying on Park state.
    "###);

    insta::assert_snapshot!(output_server_info_2.trim(), @r###"
    <timestamp> INFO installing update: fb21b217cb83e8af368c773eb13bad0a94e1b0088c6bf561072decf3c1ae9df3
    <timestamp> INFO using installation set as target 1
    <timestamp> ERRO error state reached: fail to check the requirements
    <timestamp> INFO returning to machine's entry point
    "###);

    insta::assert_snapshot!(output_server_info_2.trim(), @r###"
    <timestamp> INFO installing update: fb21b217cb83e8af368c773eb13bad0a94e1b0088c6bf561072decf3c1ae9df3
    <timestamp> INFO using installation set as target 1
    <timestamp> ERRO error state reached: fail to check the requirements
    <timestamp> INFO returning to machine's entry point
    "###);

    insta::assert_snapshot!(output_server_trce_2.trim(), @r###"
    <timestamp> DEBG receiving probe request
    <timestamp> TRCE Received external request: Probe(None)
    <timestamp> DEBG saving runtime settings from "<file>"...
    <timestamp> TRCE moving to Download state to process the update package.
    <timestamp> DEBG <percentage>% of the file has been downloaded
    <timestamp> DEBG <percentage>% of the file has been downloaded
    <timestamp> DEBG <percentage>% of the file has been downloaded
    <timestamp> DEBG <percentage>% of the file has been downloaded
    <timestamp> DEBG <percentage>% of the file has been downloaded
    <timestamp> DEBG 100% of the file has been downloaded
    <timestamp> INFO installing update: fb21b217cb83e8af368c773eb13bad0a94e1b0088c6bf561072decf3c1ae9df3
    <timestamp> INFO using installation set as target 1
    <timestamp> ERRO error state reached: fail to check the requirements
    <timestamp> INFO returning to machine's entry point
    <timestamp> DEBG polling is disabled, parking the state machine.
    <timestamp> DEBG staying on Park state.
    "###);

    insta::assert_snapshot!(remove_carriage_newline_characters(output_client), @r###"
    Ok(
        Response {
            update_available: true,
            try_again_in: None,
        },
    )
    "###);
    insta::assert_snapshot!(format_output_client_log(output_log), @r###"
    Ok(
        [
            Entry {
                level: Debug,
                message: "loading system settings from "<file>",
                time: "<timestamp>",
                data: {},
            },
            Entry {
                level: Debug,
                message: "runtime settings file "<file>",
                time: "<timestamp>",
                data: {},
            },
            Entry {
                level: Debug,
                message: "polling is disabled, parking the state machine.",
                time: "<timestamp>",
                data: {},
            },
            Entry {
                level: Debug,
                message: "staying on Park state.",
                time: "<timestamp>",
                data: {},
            },
        ],
    )"###);
}
<commit_msg>updatehub: Simplify regex on failing_invalid_server_address<commit_after>// Copyright (C) 2020 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use common::{
    create_mock_server, format_output_client_log, format_output_server, get_output_server,
    remove_carriage_newline_characters, run_client_log, run_client_probe, FakeServer, Polling,
    Server, Settings, StopMessage,
};

pub mod common;

#[test]
fn failing_invalid_download_dir() {
    let tmp_dir = tempfile::tempdir().unwrap();
    let mut perms = std::fs::metadata(tmp_dir.path()).unwrap().permissions();
    perms.set_readonly(true);
    std::fs::set_permissions(tmp_dir.path(), perms).unwrap();

    let setup = Settings::default();
    let (mut session, setup) =
        setup.download_dir(tmp_dir.path().to_path_buf()).timeout(300).init_server();
    let _mocks = create_mock_server(FakeServer::HasUpdate(setup.firmware.data.product_uid.clone()));
    let output_server_1 = get_output_server(&mut session, StopMessage::Polling(Polling::Disable));

    let output_client = run_client_probe(Server::Standard);
    let output_server_2 = get_output_server(&mut session, StopMessage::Polling(Polling::Disable));
    let output_log = run_client_log();

    let (output_server_trce, output_server_info) = format_output_server(output_server_1);

    insta::assert_snapshot!(output_server_info, @r###"
    <timestamp> INFO starting UpdateHub Agent <version>
    "###);

    insta::assert_snapshot!(output_server_trce, @r###"
    <timestamp> INFO starting UpdateHub Agent <version>
    <timestamp> DEBG loading system settings from "<file>"...
    <timestamp> DEBG runtime settings file "<file>" does not exists, using default settings...
    <timestamp> DEBG polling is disabled, parking the state machine.
    <timestamp> DEBG staying on Park state.
    "###);

    insta::assert_snapshot!(format_output_server(output_server_2).0.trim(), @r###"
    <timestamp> DEBG receiving probe request
    <timestamp> TRCE Received external request: Probe(None)
    <timestamp> DEBG saving runtime settings from "<file>"...
    <timestamp> TRCE moving to Download state to process the update package.
    <timestamp> ERRO error state reached: Permission denied (os error 13)
    <timestamp> INFO returning to machine's entry point
    <timestamp> DEBG polling is disabled, parking the state machine.
    <timestamp> DEBG staying on Park state.
    "###);

    insta::assert_snapshot!(remove_carriage_newline_characters(output_client), @r###"
    Ok(
        Response {
            update_available: true,
            try_again_in: None,
        },
    )
    "###);

    insta::assert_snapshot!(format_output_client_log(output_log), @r###"
    Ok(
        [
            Entry {
                level: Debug,
                message: "loading system settings from "<file>",
                time: "<timestamp>",
                data: {},
            },
            Entry {
                level: Debug,
                message: "runtime settings file "<file>",
                time: "<timestamp>",
                data: {},
            },
            Entry {
                level: Debug,
                message: "polling is disabled, parking the state machine.",
                time: "<timestamp>",
                data: {},
            },
            Entry {
                level: Debug,
                message: "staying on Park state.",
                time: "<timestamp>",
                data: {},
            },
        ],
    )"###);
}

#[test]
#[cfg(not(feature = "v1-parsing"))]
fn failing_invalid_file_config() {
    use std::io::Write;

    let setup = Settings::default();
    let mut file = tempfile::NamedTempFile::new().unwrap();
    let file_path = file.path().to_owned();

    write!(
        file,
        r#"[network]
    server_address=https://api.updatehub.io, listen_socket=localhost:8080;"#
    )
    .unwrap();

    let (mut session, _setup) = setup.config_file(file_path).init_server();
    let output_server = session.exp_eof().unwrap();
    let (output_server_trce, ..) = format_output_server(output_server);

    insta::assert_snapshot!(output_server_trce, @r###"
    <timestamp> INFO starting UpdateHub Agent <version>
    <timestamp> DEBG loading system settings from "<file>"...
    unexpected character found: `/` at line 2 column 26
    "###);
}

#[test]
#[cfg(feature = "v1-parsing")]
fn failing_invalid_file_config() {
    use std::io::Write;

    let setup = Settings::default();
    let mut file = tempfile::NamedTempFile::new().unwrap();
    let file_path = file.path().to_owned();

    write!(
        file,
        r#"[network]
    server_address=https://api.updatehub.io, listen_socket=localhost:8080;"#
    )
    .unwrap();

    let (mut session, _setup) = setup.config_file(file_path).init_server();
    let output_server = session.exp_eof().unwrap();
    let (output_server_trce, ..) = format_output_server(output_server);

    insta::assert_snapshot!(output_server_trce, @r###"
    <timestamp> INFO starting UpdateHub Agent <version>
    <timestamp> DEBG loading system settings from "<file>"...
    Custom("missing field `Network`")
    "###);
}

#[test]
fn failing_invalid_server_address() {
    let setup = Settings::default();
    let (mut session, _setup) = setup.timeout(300).init_server();
    let _mocks = create_mock_server(FakeServer::NoUpdate);
    let output_server_1 = get_output_server(&mut session, StopMessage::Polling(Polling::Disable));

    let output_client = run_client_probe(Server::Custom("http://foo:--".to_string()));
    let output_server_2 = get_output_server(
        &mut session,
        StopMessage::Custom(
            r#"\r\n.* TRCE Received external request: Probe\(Some\("http://foo:--"\)\).*"#
                .to_string(),
        ),
    );
    let output_log = run_client_log();

    let (output_server_trce_1, output_server_info_1) = format_output_server(output_server_1);
    let (output_server_trce_2, ..) = format_output_server(output_server_2);

    insta::assert_snapshot!(output_server_info_1, @r###"
    <timestamp> INFO starting UpdateHub Agent <version>
    "###);

    insta::assert_snapshot!(output_server_trce_1, @r###"
    <timestamp> INFO starting UpdateHub Agent <version>
    <timestamp> DEBG loading system settings from "<file>"...
    <timestamp> DEBG runtime settings file "<file>" does not exists, using default settings...
    <timestamp> DEBG polling is disabled, parking the state machine.
    <timestamp> DEBG staying on Park state.
    "###);

    insta::assert_snapshot!(output_server_trce_2.trim(), @r###"
    <timestamp> DEBG receiving probe request
    "###);

    insta::assert_snapshot!(remove_carriage_newline_characters(output_client), @r###"
    Err(
        UnexpectedResponse(
            InternalServerError,
        ),
    )
    "###);
    insta::assert_snapshot!(format_output_client_log(output_log), @r###"
    Ok(
        [
            Entry {
                level: Debug,
                message: "loading system settings from "<file>",
                time: "<timestamp>",
                data: {},
            },
            Entry {
                level: Debug,
                message: "runtime settings file "<file>",
                time: "<timestamp>",
                data: {},
            },
            Entry {
                level: Debug,
                message: "polling is disabled, parking the state machine.",
                time: "<timestamp>",
                data: {},
            },
            Entry {
                level: Debug,
                message: "staying on Park state.",
                time: "<timestamp>",
                data: {},
            },
        ],
    )"###);
}

#[test]
fn failing_fail_check_requirements() {
    let setup = Settings::default();

    let (mut session, setup) = setup.timeout(300).init_server();
    let _mocks = create_mock_server(FakeServer::CheckRequirementsTest(
        setup.firmware.data.product_uid.clone(),
    ));
    let output_server_1 = get_output_server(&mut session, StopMessage::Polling(Polling::Disable));

    let output_client = run_client_probe(Server::Standard);
    let output_server_2 = get_output_server(&mut session, StopMessage::Polling(Polling::Disable));
    let output_log = run_client_log();

    let (output_server_trce_1, output_server_info_1) = format_output_server(output_server_1);
    let (output_server_trce_2, output_server_info_2) = format_output_server(output_server_2);

    insta::assert_snapshot!(output_server_info_1, @r###"
    <timestamp> INFO starting UpdateHub Agent <version>
    "###);

    insta::assert_snapshot!(output_server_trce_1, @r###"
    <timestamp> INFO starting UpdateHub Agent <version>
    <timestamp> DEBG loading system settings from "<file>"...
    <timestamp> DEBG runtime settings file "<file>" does not exists, using default settings...
    <timestamp> DEBG polling is disabled, parking the state machine.
    <timestamp> DEBG staying on Park state.
    "###);

    insta::assert_snapshot!(output_server_info_2.trim(), @r###"
    <timestamp> INFO installing update: fb21b217cb83e8af368c773eb13bad0a94e1b0088c6bf561072decf3c1ae9df3
    <timestamp> INFO using installation set as target 1
    <timestamp> ERRO error state reached: fail to check the requirements
    <timestamp> INFO returning to machine's entry point
    "###);

    insta::assert_snapshot!(output_server_info_2.trim(), @r###"
    <timestamp> INFO installing update: fb21b217cb83e8af368c773eb13bad0a94e1b0088c6bf561072decf3c1ae9df3
    <timestamp> INFO using installation set as target 1
    <timestamp> ERRO error state reached: fail to check the requirements
    <timestamp> INFO returning to machine's entry point
    "###);

    insta::assert_snapshot!(output_server_trce_2.trim(), @r###"
    <timestamp> DEBG receiving probe request
    <timestamp> TRCE Received external request: Probe(None)
    <timestamp> DEBG saving runtime settings from "<file>"...
    <timestamp> TRCE moving to Download state to process the update package.
    <timestamp> DEBG <percentage>% of the file has been downloaded
    <timestamp> DEBG <percentage>% of the file has been downloaded
    <timestamp> DEBG <percentage>% of the file has been downloaded
    <timestamp> DEBG <percentage>% of the file has been downloaded
    <timestamp> DEBG <percentage>% of the file has been downloaded
    <timestamp> DEBG 100% of the file has been downloaded
    <timestamp> INFO installing update: fb21b217cb83e8af368c773eb13bad0a94e1b0088c6bf561072decf3c1ae9df3
    <timestamp> INFO using installation set as target 1
    <timestamp> ERRO error state reached: fail to check the requirements
    <timestamp> INFO returning to machine's entry point
    <timestamp> DEBG polling is disabled, parking the state machine.
    <timestamp> DEBG staying on Park state.
    "###);

    insta::assert_snapshot!(remove_carriage_newline_characters(output_client), @r###"
    Ok(
        Response {
            update_available: true,
            try_again_in: None,
        },
    )
    "###);
    insta::assert_snapshot!(format_output_client_log(output_log), @r###"
    Ok(
        [
            Entry {
                level: Debug,
                message: "loading system settings from "<file>",
                time: "<timestamp>",
                data: {},
            },
            Entry {
                level: Debug,
                message: "runtime settings file "<file>",
                time: "<timestamp>",
                data: {},
            },
            Entry {
                level: Debug,
                message: "polling is disabled, parking the state machine.",
                time: "<timestamp>",
                data: {},
            },
            Entry {
                level: Debug,
                message: "staying on Park state.",
                time: "<timestamp>",
                data: {},
            },
        ],
    )"###);
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(clippy)]

extern crate core;

use std::mem::transmute as my_transmute;
use std::vec::Vec as MyVec;

fn my_vec() -> MyVec<i32> {
    vec![]
}

#[allow(needless_lifetimes)]
#[deny(useless_transmute)]
unsafe fn _generic<'a, T, U: 'a>(t: &'a T) {
    let _: &'a T = core::intrinsics::transmute(t);
    //~^ ERROR transmute from a type (`&'a T`) to itself

    let _: &'a U = core::intrinsics::transmute(t);
}

#[deny(transmute_ptr_to_ref)]
unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
    let _: &T = std::mem::transmute(p);
    //~^ ERROR transmute from a pointer type (`*const T`) to a reference type (`&T`)
    //~| HELP try
    //~| SUGGESTION = &*p;
    let _: &T = &*p;

    let _: &mut T = std::mem::transmute(m);
    //~^ ERROR transmute from a pointer type (`*mut T`) to a reference type (`&mut T`)
    //~| HELP try
    //~| SUGGESTION = &mut *m;
    let _: &mut T = &mut *m;

    let _: &T = std::mem::transmute(m);
    //~^ ERROR transmute from a pointer type (`*mut T`) to a reference type (`&T`)
    //~| HELP try
    //~| SUGGESTION = &*m;
    let _: &T = &*m;

    let _: &T = std::mem::transmute(o);
    //~^ ERROR transmute from a pointer type (`*const U`) to a reference type (`&T`)
    //~| HELP try
    //~| SUGGESTION = &*(o as *const T);
    let _: &T = &*(o as *const T);

    let _: &mut T = std::mem::transmute(om);
    //~^ ERROR transmute from a pointer type (`*mut U`) to a reference type (`&mut T`)
    //~| HELP try
    //~| SUGGESTION = &mut *(om as *mut T);
    let _: &mut T = &mut *(om as *mut T);

    let _: &T = std::mem::transmute(om);
    //~^ ERROR transmute from a pointer type (`*mut U`) to a reference type (`&T`)
    //~| HELP try
    //~| SUGGESTION = &*(om as *const T);
    let _: &T = &*(om as *const T);
}

#[deny(useless_transmute)]
fn useless() {
    unsafe {
        let _: Vec<i32> = core::intrinsics::transmute(my_vec());
        //~^ ERROR transmute from a type (`collections::vec::Vec<i32>`) to itself

        let _: Vec<i32> = core::mem::transmute(my_vec());
        //~^ ERROR transmute from a type (`collections::vec::Vec<i32>`) to itself

        let _: Vec<i32> = std::intrinsics::transmute(my_vec());
        //~^ ERROR transmute from a type (`collections::vec::Vec<i32>`) to itself

        let _: Vec<i32> = std::mem::transmute(my_vec());
        //~^ ERROR transmute from a type (`collections::vec::Vec<i32>`) to itself

        let _: Vec<i32> = my_transmute(my_vec());
        //~^ ERROR transmute from a type (`collections::vec::Vec<i32>`) to itself

        let _: Vec<u32> = core::intrinsics::transmute(my_vec());
        let _: Vec<u32> = core::mem::transmute(my_vec());
        let _: Vec<u32> = std::intrinsics::transmute(my_vec());
        let _: Vec<u32> = std::mem::transmute(my_vec());
        let _: Vec<u32> = my_transmute(my_vec());
    }
}

#[deny(crosspointer_transmute)]
fn crosspointer() {
    let mut vec: Vec<i32> = vec![];
    let vec_const_ptr: *const Vec<i32> = &vec as *const Vec<i32>;
    let vec_mut_ptr: *mut Vec<i32> = &mut vec as *mut Vec<i32>;

    unsafe {
        let _: Vec<i32> = core::intrinsics::transmute(vec_const_ptr);
        //~^ ERROR transmute from a type (`*const collections::vec::Vec<i32>`) to the type that it points to (`collections::vec::Vec<i32>`)

        let _: Vec<i32> = core::intrinsics::transmute(vec_mut_ptr);
        //~^ ERROR transmute from a type (`*mut collections::vec::Vec<i32>`) to the type that it points to (`collections::vec::Vec<i32>`)

        let _: *const Vec<i32> = core::intrinsics::transmute(my_vec());
        //~^ ERROR transmute from a type (`collections::vec::Vec<i32>`) to a pointer to that type (`*const collections::vec::Vec<i32>`)

        let _: *mut Vec<i32> = core::intrinsics::transmute(my_vec());
        //~^ ERROR transmute from a type (`collections::vec::Vec<i32>`) to a pointer to that type (`*mut collections::vec::Vec<i32>`)
    }
}

fn main() {
    useless();
    crosspointer();
}
<commit_msg>Rustup to 1.9.0-nightly (e1195c24b 2016-03-31)<commit_after>#![feature(plugin)]
#![plugin(clippy)]

extern crate core;

use std::mem::transmute as my_transmute;
use std::vec::Vec as MyVec;

fn my_vec() -> MyVec<i32> {
    vec![]
}

#[allow(needless_lifetimes)]
#[deny(useless_transmute)]
unsafe fn _generic<'a, T, U: 'a>(t: &'a T) {
    let _: &'a T = core::intrinsics::transmute(t);
    //~^ ERROR transmute from a type (`&'a T`) to itself

    let _: &'a U = core::intrinsics::transmute(t);
}

#[deny(transmute_ptr_to_ref)]
unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
    let _: &T = std::mem::transmute(p);
    //~^ ERROR transmute from a pointer type (`*const T`) to a reference type (`&T`)
    //~| HELP try
    //~| SUGGESTION = &*p;
    let _: &T = &*p;

    let _: &mut T = std::mem::transmute(m);
    //~^ ERROR transmute from a pointer type (`*mut T`) to a reference type (`&mut T`)
    //~| HELP try
    //~| SUGGESTION = &mut *m;
    let _: &mut T = &mut *m;

    let _: &T = std::mem::transmute(m);
    //~^ ERROR transmute from a pointer type (`*mut T`) to a reference type (`&T`)
    //~| HELP try
    //~| SUGGESTION = &*m;
    let _: &T = &*m;

    let _: &T = std::mem::transmute(o);
    //~^ ERROR transmute from a pointer type (`*const U`) to a reference type (`&T`)
    //~| HELP try
    //~| SUGGESTION = &*(o as *const T);
    let _: &T = &*(o as *const T);

    let _: &mut T = std::mem::transmute(om);
    //~^ ERROR transmute from a pointer type (`*mut U`) to a reference type (`&mut T`)
    //~| HELP try
    //~| SUGGESTION = &mut *(om as *mut T);
    let _: &mut T = &mut *(om as *mut T);

    let _: &T = std::mem::transmute(om);
    //~^ ERROR transmute from a pointer type (`*mut U`) to a reference type (`&T`)
    //~| HELP try
    //~| SUGGESTION = &*(om as *const T);
    let _: &T = &*(om as *const T);
}

#[deny(useless_transmute)]
fn useless() {
    unsafe {
        let _: Vec<i32> = core::intrinsics::transmute(my_vec());
        //~^ ERROR transmute from a type (`std::vec::Vec<i32>`) to itself

        let _: Vec<i32> = core::mem::transmute(my_vec());
        //~^ ERROR transmute from a type (`std::vec::Vec<i32>`) to itself

        let _: Vec<i32> = std::intrinsics::transmute(my_vec());
        //~^ ERROR transmute from a type (`std::vec::Vec<i32>`) to itself

        let _: Vec<i32> = std::mem::transmute(my_vec());
        //~^ ERROR transmute from a type (`std::vec::Vec<i32>`) to itself

        let _: Vec<i32> = my_transmute(my_vec());
        //~^ ERROR transmute from a type (`std::vec::Vec<i32>`) to itself

        let _: Vec<u32> = core::intrinsics::transmute(my_vec());
        let _: Vec<u32> = core::mem::transmute(my_vec());
        let _: Vec<u32> = std::intrinsics::transmute(my_vec());
        let _: Vec<u32> = std::mem::transmute(my_vec());
        let _: Vec<u32> = my_transmute(my_vec());
    }
}

#[deny(crosspointer_transmute)]
fn crosspointer() {
    let mut vec: Vec<i32> = vec![];
    let vec_const_ptr: *const Vec<i32> = &vec as *const Vec<i32>;
    let vec_mut_ptr: *mut Vec<i32> = &mut vec as *mut Vec<i32>;

    unsafe {
        let _: Vec<i32> = core::intrinsics::transmute(vec_const_ptr);
        //~^ ERROR transmute from a type (`*const std::vec::Vec<i32>`) to the type that it points to (`std::vec::Vec<i32>`)

        let _: Vec<i32> = core::intrinsics::transmute(vec_mut_ptr);
        //~^ ERROR transmute from a type (`*mut std::vec::Vec<i32>`) to the type that it points to (`std::vec::Vec<i32>`)

        let _: *const Vec<i32> = core::intrinsics::transmute(my_vec());
        //~^ ERROR transmute from a type (`std::vec::Vec<i32>`) to a pointer to that type (`*const std::vec::Vec<i32>`)

        let _: *mut Vec<i32> = core::intrinsics::transmute(my_vec());
        //~^ ERROR transmute from a type (`std::vec::Vec<i32>`) to a pointer to that type (`*mut std::vec::Vec<i32>`)
    }
}

fn main() {
    useless();
    crosspointer();
}
<|endoftext|>


<commit_before>use libc;
use std::ptr;
use std::ffi::CStr;
use error::*;
use capstone_sys::*;
use capstone_sys::cs_arch::*;
use capstone_sys::cs_mode::*;
use capstone_sys;
use instruction::Instructions;

/// An instance of the capstone disassembler
pub struct Capstone {
    csh: capstone_sys::csh,
    _arch: Arch,
}

/// Architectures for the disassembler
#[derive(Clone, Debug, PartialEq, Copy)]
pub enum Arch {
    ARM,
    ARM64,
    MIPS,
    X86,
    PPC,
    SPARC,
    SYSZ,
    XCORE,
    MAX,
    /// used for `cs_support()`
    ALL,
}

impl Arch {
    pub fn to_cs_arch(&self) -> cs_arch {
        use Arch::*;
        match *self {
            ARM => CS_ARCH_ARM,
            ARM64 => CS_ARCH_ARM64,
            MIPS => CS_ARCH_MIPS,
            X86 => CS_ARCH_X86,
            PPC => CS_ARCH_PPC,
            SPARC => CS_ARCH_SPARC,
            SYSZ => CS_ARCH_SYSZ,
            XCORE => CS_ARCH_XCORE,
            MAX => CS_ARCH_MAX,
            ALL => CS_ARCH_ALL,
        }
    }
}

/// Disassembler modes
#[derive(Debug, Clone, PartialEq, Copy)]
pub enum Mode {
    /// little-endian mode (default mode)
    LittleEndian,
    /// 32-bit ARM
    Arm32,
    /// 16-bit mode (X86)
    Mode16,
    /// 32-bit mode (X86)
    Mode32,
    /// 64-bit mode (X86, PPC)
    Mode64,
    /// ARM's Thumb mode, including Thumb-2
    Thumb,
    /// ARM's Cortex-M series
    MClass,
    /// ARMv8 A32 encodings for ARM
    V8,
    /// MicroMips mode (MIPS)
    Micro,
    /// Mips III ISA
    Mips3,
    /// Mips32r6 ISA
    Mips32R6,
    /// General Purpose Registers are 64-bit wide (MIPS)
    MipsGP64,
    /// SparcV9 mode (Sparc)
    V9,
    /// big-endian mode
    BigEndian,
    /// Mips32 ISA (Mips)
    Mips32,
    /// Mips64 ISA (Mips)
    Mips64,
}

impl Mode {
    pub fn to_cs_mode(&self) -> capstone_sys::cs_mode {
        use Mode::*;
        match *self {
            LittleEndian => CS_MODE_LITTLE_ENDIAN,
            Arm32 => CS_MODE_ARM,
            Mode16 => CS_MODE_16,
            Mode32 => CS_MODE_32,
            Mode64 => CS_MODE_64,
            Thumb => CS_MODE_THUMB,
            MClass => CS_MODE_MCLASS,
            V8 => CS_MODE_V8,
            Micro => CS_MODE_MICRO,
            Mips3 => CS_MODE_MIPS3,
            Mips32R6 => CS_MODE_MIPS32R6,
            MipsGP64 => CS_MODE_MIPSGP64,
            V9 => CS_MODE_V9,
            BigEndian => CS_MODE_BIG_ENDIAN,
            Mips32 => CS_MODE_MIPS32,
            Mips64 => CS_MODE_MIPS64,
        }
    }
}

impl Capstone {
    /// Create a new instance of the decompiler. Defaults to 64-bit little-endian mode.
    ///
    /// ```
    /// use capstone3::{Arch, Capstone};
    /// let cs = Capstone::new(Arch::X86);
    /// assert!(cs.is_ok());
    /// ```
    pub fn new(arch: Arch) -> Result<Capstone> {
        let mut handle: capstone_sys::csh = 0;
        let csarch = arch.to_cs_arch();
        let csmode = CS_MODE_LITTLE_ENDIAN;
        let err = unsafe { cs_open(csarch, csmode, &mut handle) };
        // this can be put into a macro, cs_try, but i guess who cares
        if cs_err::CS_ERR_OK == err {
            Ok(Capstone { csh: handle, _arch: arch })
        } else {
            Err(Error::from(err))
        }
    }

    #[inline]
    fn set_option(&self, opt_type: cs_opt_type, value: usize) -> Result<()> {
        let err = unsafe {
            cs_option(self.csh, opt_type, value)
        };
        if cs_err::CS_ERR_OK == err {
            Ok(())
        } else {
            Err(Error::from(err))
        }
    }

    /// Set the disassembly engine to use detail mode
    pub fn detail(&self) -> Result<()> {
        self.set_option(cs_opt_type::CS_OPT_DETAIL, cs_opt_value::CS_OPT_ON as libc::size_t)
    }

    /// Sets the engine's disassembly mode.
    /// Be careful, various combinations of modes aren't supported
    /// See the capstone-sys documentation for more information.
    pub fn mode(&mut self, modes: &[Mode]) -> Result<()> {
        let mut value: usize = 0;
        for mode in modes {
            value |= mode.to_cs_mode() as usize;
        }
        self.set_option(cs_opt_type::CS_OPT_MODE, value)
    }

    /// Set the X86 assembly to AT&T style (has no effect on other platforms)
    pub fn att(&self) {
        self.set_option(cs_opt_type::CS_OPT_SYNTAX, cs_opt_value::CS_OPT_SYNTAX_ATT as usize).unwrap()
    }

    /// Set the X86 assembly to Intel style (default)
    pub fn intel(&self) {
        self.set_option(cs_opt_type::CS_OPT_SYNTAX, cs_opt_value::CS_OPT_SYNTAX_INTEL as usize).unwrap()
    }

    /// Disassemble a &[u8] `buffer` full of instructions
    ///
    /// Disassembles all instructions in `code`. If you want to disassemble less, then pass a smaller slice :]
    pub fn disassemble(&self, buffer: &[u8], addr: u64) -> Result<Instructions> {
        let mut ptr: *mut capstone_sys::cs_insn = ptr::null_mut();
        let insn_count = unsafe {
            cs_disasm(self.csh,
                      buffer.as_ptr(),
                      buffer.len() as libc::size_t,
                      addr,
                      0 as libc::size_t,
                      &mut ptr)
        };
        if insn_count == 0 {
            // we can just simply not have found instructions in the buffer; this isn't an error
            // so we just return an empty instructions
            // I worry this will explode when freeing, we need a better api to just convert to a
            // straight vector
            let err = unsafe { cs_errno(self.csh) };
            if err != cs_err::CS_ERR_OK {
                return Err(Error::from(err))
            }
        }
        Ok(unsafe { Instructions::from_raw_parts(ptr, insn_count as isize) })
    }

    /// Convert a reg_id to a String naming the register
    pub fn reg_name(&self, reg_id: u64) -> Option<String> {
        let reg_name = unsafe {
            let _reg_name = cs_reg_name(self.csh, reg_id as libc::c_uint);
            if _reg_name == ptr::null() {
                return None
            }

            CStr::from_ptr(_reg_name).to_string_lossy().into_owned()
        };

        Some(reg_name)
    }

    /// Convert an instruction_id to a String naming the instruction
    pub fn insn_name(&self, insn_id: u64) -> Option<String> {
        let insn_name = unsafe {
            let _insn_name = cs_insn_name(self.csh, insn_id as libc::c_uint);
            if _insn_name == ptr::null() {
                return None
            }
            CStr::from_ptr(_insn_name).to_string_lossy().into_owned()
        };

        Some(insn_name)
    }
}

impl Drop for Capstone {
    fn drop(&mut self) {
        unsafe { cs_close(&mut self.csh) };
    }
}
<commit_msg>Add standard trait derives<commit_after>use libc;
use std::ptr;
use std::ffi::CStr;
use error::*;
use capstone_sys::*;
use capstone_sys::cs_arch::*;
use capstone_sys::cs_mode::*;
use capstone_sys;
use instruction::Instructions;

/// An instance of the capstone disassembler
pub struct Capstone {
    csh: capstone_sys::csh,
    _arch: Arch,
}

/// Architectures for the disassembler
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub enum Arch {
    ARM,
    ARM64,
    MIPS,
    X86,
    PPC,
    SPARC,
    SYSZ,
    XCORE,
    MAX,
    /// used for `cs_support()`
    ALL,
}

impl Arch {
    pub fn to_cs_arch(&self) -> cs_arch {
        use Arch::*;
        match *self {
            ARM => CS_ARCH_ARM,
            ARM64 => CS_ARCH_ARM64,
            MIPS => CS_ARCH_MIPS,
            X86 => CS_ARCH_X86,
            PPC => CS_ARCH_PPC,
            SPARC => CS_ARCH_SPARC,
            SYSZ => CS_ARCH_SYSZ,
            XCORE => CS_ARCH_XCORE,
            MAX => CS_ARCH_MAX,
            ALL => CS_ARCH_ALL,
        }
    }
}

/// Disassembler modes
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub enum Mode {
    /// little-endian mode (default mode)
    LittleEndian,
    /// 32-bit ARM
    Arm32,
    /// 16-bit mode (X86)
    Mode16,
    /// 32-bit mode (X86)
    Mode32,
    /// 64-bit mode (X86, PPC)
    Mode64,
    /// ARM's Thumb mode, including Thumb-2
    Thumb,
    /// ARM's Cortex-M series
    MClass,
    /// ARMv8 A32 encodings for ARM
    V8,
    /// MicroMips mode (MIPS)
    Micro,
    /// Mips III ISA
    Mips3,
    /// Mips32r6 ISA
    Mips32R6,
    /// General Purpose Registers are 64-bit wide (MIPS)
    MipsGP64,
    /// SparcV9 mode (Sparc)
    V9,
    /// big-endian mode
    BigEndian,
    /// Mips32 ISA (Mips)
    Mips32,
    /// Mips64 ISA (Mips)
    Mips64,
}

impl Mode {
    pub fn to_cs_mode(&self) -> capstone_sys::cs_mode {
        use Mode::*;
        match *self {
            LittleEndian => CS_MODE_LITTLE_ENDIAN,
            Arm32 => CS_MODE_ARM,
            Mode16 => CS_MODE_16,
            Mode32 => CS_MODE_32,
            Mode64 => CS_MODE_64,
            Thumb => CS_MODE_THUMB,
            MClass => CS_MODE_MCLASS,
            V8 => CS_MODE_V8,
            Micro => CS_MODE_MICRO,
            Mips3 => CS_MODE_MIPS3,
            Mips32R6 => CS_MODE_MIPS32R6,
            MipsGP64 => CS_MODE_MIPSGP64,
            V9 => CS_MODE_V9,
            BigEndian => CS_MODE_BIG_ENDIAN,
            Mips32 => CS_MODE_MIPS32,
            Mips64 => CS_MODE_MIPS64,
        }
    }
}

impl Capstone {
    /// Create a new instance of the decompiler. Defaults to 64-bit little-endian mode.
    ///
    /// ```
    /// use capstone3::{Arch, Capstone};
    /// let cs = Capstone::new(Arch::X86);
    /// assert!(cs.is_ok());
    /// ```
    pub fn new(arch: Arch) -> Result<Capstone> {
        let mut handle: capstone_sys::csh = 0;
        let csarch = arch.to_cs_arch();
        let csmode = CS_MODE_LITTLE_ENDIAN;
        let err = unsafe { cs_open(csarch, csmode, &mut handle) };
        // this can be put into a macro, cs_try, but i guess who cares
        if cs_err::CS_ERR_OK == err {
            Ok(Capstone { csh: handle, _arch: arch })
        } else {
            Err(Error::from(err))
        }
    }

    #[inline]
    fn set_option(&self, opt_type: cs_opt_type, value: usize) -> Result<()> {
        let err = unsafe {
            cs_option(self.csh, opt_type, value)
        };
        if cs_err::CS_ERR_OK == err {
            Ok(())
        } else {
            Err(Error::from(err))
        }
    }

    /// Set the disassembly engine to use detail mode
    pub fn detail(&self) -> Result<()> {
        self.set_option(cs_opt_type::CS_OPT_DETAIL, cs_opt_value::CS_OPT_ON as libc::size_t)
    }

    /// Sets the engine's disassembly mode.
    /// Be careful, various combinations of modes aren't supported
    /// See the capstone-sys documentation for more information.
    pub fn mode(&mut self, modes: &[Mode]) -> Result<()> {
        let mut value: usize = 0;
        for mode in modes {
            value |= mode.to_cs_mode() as usize;
        }
        self.set_option(cs_opt_type::CS_OPT_MODE, value)
    }

    /// Set the X86 assembly to AT&T style (has no effect on other platforms)
    pub fn att(&self) {
        self.set_option(cs_opt_type::CS_OPT_SYNTAX, cs_opt_value::CS_OPT_SYNTAX_ATT as usize).unwrap()
    }

    /// Set the X86 assembly to Intel style (default)
    pub fn intel(&self) {
        self.set_option(cs_opt_type::CS_OPT_SYNTAX, cs_opt_value::CS_OPT_SYNTAX_INTEL as usize).unwrap()
    }

    /// Disassemble a &[u8] `buffer` full of instructions
    ///
    /// Disassembles all instructions in `code`. If you want to disassemble less, then pass a smaller slice :]
    pub fn disassemble(&self, buffer: &[u8], addr: u64) -> Result<Instructions> {
        let mut ptr: *mut capstone_sys::cs_insn = ptr::null_mut();
        let insn_count = unsafe {
            cs_disasm(self.csh,
                      buffer.as_ptr(),
                      buffer.len() as libc::size_t,
                      addr,
                      0 as libc::size_t,
                      &mut ptr)
        };
        if insn_count == 0 {
            // we can just simply not have found instructions in the buffer; this isn't an error
            // so we just return an empty instructions
            // I worry this will explode when freeing, we need a better api to just convert to a
            // straight vector
            let err = unsafe { cs_errno(self.csh) };
            if err != cs_err::CS_ERR_OK {
                return Err(Error::from(err))
            }
        }
        Ok(unsafe { Instructions::from_raw_parts(ptr, insn_count as isize) })
    }

    /// Convert a reg_id to a String naming the register
    pub fn reg_name(&self, reg_id: u64) -> Option<String> {
        let reg_name = unsafe {
            let _reg_name = cs_reg_name(self.csh, reg_id as libc::c_uint);
            if _reg_name == ptr::null() {
                return None
            }

            CStr::from_ptr(_reg_name).to_string_lossy().into_owned()
        };

        Some(reg_name)
    }

    /// Convert an instruction_id to a String naming the instruction
    pub fn insn_name(&self, insn_id: u64) -> Option<String> {
        let insn_name = unsafe {
            let _insn_name = cs_insn_name(self.csh, insn_id as libc::c_uint);
            if _insn_name == ptr::null() {
                return None
            }
            CStr::from_ptr(_insn_name).to_string_lossy().into_owned()
        };

        Some(insn_name)
    }
}

impl Drop for Capstone {
    fn drop(&mut self) {
        unsafe { cs_close(&mut self.csh) };
    }
}
<|endoftext|>