<commit_before>// Copyright 2013-2014 The Rust Project Developers.
// Copyright 2018 The Uuid Project Developers.
//
// See the COPYRIGHT file at the top-level directory of this distribution.
//
// 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.

//! Adapters for various formats for [`Uuid`]s
//!
//! [`Uuid`]: ../struct.Uuid.html

/// The length of a Hyphenated [`Uuid`] string.
///
/// [`Uuid`]: ../struct.Uuid.html
pub const UUID_HYPHENATED_LENGTH: usize = 36;

/// The length of a Simple [`Uuid`] string.
///
/// [`Uuid`]: ../struct.Uuid.html
pub const UUID_SIMPLE_LENGTH: usize = 32;

/// The length of a Urn [`Uuid`] string.
///
/// [`Uuid`]: ../struct.Uuid.html
-pub const UUID_URN_LENGTH: usize = 45;
<commit_msg>allow dead code lint for UUID_URN_LENGTH<commit_after>// Copyright 2013-2014 The Rust Project Developers.
// Copyright 2018 The Uuid Project Developers.
//
// See the COPYRIGHT file at the top-level directory of this distribution.
//
// 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.

//! Adapters for various formats for [`Uuid`]s
//!
//! [`Uuid`]: ../struct.Uuid.html

/// The length of a Hyphenated [`Uuid`] string.
///
/// [`Uuid`]: ../struct.Uuid.html
pub const UUID_HYPHENATED_LENGTH: usize = 36;

/// The length of a Simple [`Uuid`] string.
///
/// [`Uuid`]: ../struct.Uuid.html
pub const UUID_SIMPLE_LENGTH: usize = 32;

/// The length of a Urn [`Uuid`] string.
///
/// [`Uuid`]: ../struct.Uuid.html
// TODO: remove #[allow(dead_code)] lint
// BODY: This only exists to allow compiling the code currently,
#[allow(dead_code)]
pub const UUID_URN_LENGTH: usize = 45;
<|endoftext|>


<commit_before>use clap::{self, Arg, App, SubCommand, AppSettings};
use std::io::{self, Write};
use std::process;
use std::path::PathBuf;
use std::error;
use std::result;
use std::fmt;
use mprovision as mp;

#[derive(Debug, PartialEq)]
pub enum Command {
    List(ListParams),
    ShowUuid(String, Option<PathBuf>),
    ShowPath(PathBuf),
    RemoveUuid(String, Option<PathBuf>),
    RemovePath(PathBuf),
    Cleanup(Option<PathBuf>),
}

#[derive(Debug, Default, PartialEq)]
pub struct ListParams {
    pub filter: Option<String>,
    pub expires_in_days: Option<i64>,
    pub directory: Option<PathBuf>,
}

pub type Result = result::Result<Command, Error>;

#[derive(Debug)]
pub enum Error {
    Lib(mp::Error),
    Clap(clap::Error),
    Custom(String),
}

impl Error {
    pub fn exit(&self) -> ! {
        match *self {
            Error::Clap(ref e) => e.exit(),
            _ => {
                writeln!(&mut io::stderr(), "{}", self).unwrap();
                process::exit(1);
            }
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Lib(ref e) => e.description(),
            Error::Clap(ref e) => e.description(),
            Error::Custom(ref e) => e,
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Lib(ref e) => Some(e),
            Error::Clap(ref e) => Some(e),
            Error::Custom(_) => None,
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Lib(ref e) => error::Error::description(e).fmt(f),
            Error::Clap(ref e) => error::Error::description(e).fmt(f),
            Error::Custom(ref e) => e.fmt(f),
        }
    }
}

impl From<mp::Error> for Error {
    fn from(e: mp::Error) -> Self {
        Error::Lib(e)
    }
}

impl From<clap::Error> for Error {
    fn from(e: clap::Error) -> Self {
        Error::Clap(e)
    }
}

pub fn parse<I, S>(args: I) -> Result
    where I: IntoIterator<Item = S>,
          S: Clone,
          ::std::ffi::OsString: From<S>
{
    let app = App::new("mprovision")
        .about("A tool that helps iOS developers to manage mobileprovision files.")
        .subcommand(SubCommand::with_name("list")
            .about("Lists provisioning profiles")
            .setting(AppSettings::DisableVersion)
            .arg(Arg::with_name("TEXT")
                .long("--filter")
                .required(false)
                .empty_values(false)
                .takes_value(true))
            .arg(Arg::with_name("DAYS")
                .long("--expires-in-days")
                .required(false)
                .empty_values(false)
                .takes_value(true))
            .arg(Arg::with_name("DIRECTORY")
                .required(false)
                .empty_values(false)
                .takes_value(true)))
        .subcommand(SubCommand::with_name("cleanup")
            .about("Removes expired provisioning profiles")
            .setting(AppSettings::DisableVersion)
            .arg(Arg::with_name("DIRECTORY")
                .required(false)
                .empty_values(false)
                .takes_value(true)))
        .subcommand(SubCommand::with_name("show")
            .about("Shows details of a provisioning profile")
            .setting(AppSettings::DisableVersion)
            .arg(Arg::with_name("UUID")
                .long("--uuid")
                .required(true)
                .empty_values(false)
                .takes_value(true)
                .conflicts_with("PATH"))
            .arg(Arg::with_name("DIRECTORY")
                .required(false)
                .empty_values(false)
                .takes_value(true)
                .conflicts_with("PATH"))
            .arg(Arg::with_name("PATH")
                .long("--path")
                .required(true)
                .empty_values(false)
                .takes_value(true)
                .required(true)))
        .subcommand(SubCommand::with_name("remove")
            .about("Removes a provisioning profile")
            .setting(AppSettings::DisableVersion)
            .arg(Arg::with_name("UUID")
                .long("--uuid")
                .required(true)
                .empty_values(false)
                .takes_value(true)
                .conflicts_with("PATH"))
            .arg(Arg::with_name("DIRECTORY")
                .required(false)
                .empty_values(false)
                .takes_value(true)
                .conflicts_with("PATH"))
            .arg(Arg::with_name("PATH")
                .long("--path")
                .required(true)
                .empty_values(false)
                .takes_value(true)
                .required(true)));

    let matches = app.get_matches_from_safe(args)?;
    if let Some(list_matches) = matches.subcommand_matches("list") {
        let mut params = ListParams::default();
        params.filter = list_matches.value_of("TEXT").map(|text| text.to_string());
        if let Some(days) = list_matches.value_of("DAYS")
            .and_then(|days| days.parse::<i64>().ok()) {
            if days < 0 || days > 365 {
                return Err(Error::Custom("DAYS should be between 0 and 365".to_string()));
            }
            params.expires_in_days = Some(days);
        }
        params.directory = list_matches.value_of("DIRECTORY").map(|dir| dir.into());
        Ok(Command::List(params))
    } else if let Some(show_matches) = matches.subcommand_matches("show") {
        if let Some(uuid) = show_matches.value_of("UUID").map(|uuid| uuid.to_string()) {
            let directory = show_matches.value_of("DIRECTORY").map(|dir| dir.into());
            Ok(Command::ShowUuid(uuid, directory))
        } else {
            let path = show_matches.value_of("PATH").map(|path| path.into()).unwrap();
            Ok(Command::ShowPath(path))
        }
    } else if let Some(remove_matches) = matches.subcommand_matches("remove") {
        if let Some(uuid) = remove_matches.value_of("UUID").map(|uuid| uuid.to_string()) {
            let directory = remove_matches.value_of("DIRECTORY").map(|dir| dir.into());
            Ok(Command::RemoveUuid(uuid, directory))
        } else {
            let path = remove_matches.value_of("PATH").map(|path| path.into()).unwrap();
            Ok(Command::RemovePath(path))
        }
    } else if let Some(cleanup_matches) = matches.subcommand_matches("cleanup") {
        let directory = cleanup_matches.value_of("DIRECTORY").map(|dir| dir.into());
        Ok(Command::Cleanup(directory))
    } else {
        Err(Error::Custom("Command isn't implemented".to_string()))
    }
}

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

    #[test]
    fn list_command() {
        expect!(parse(&["mprovision", "list"]))
            .to(be_ok().value(Command::List(ListParams::default())));

        expect!(parse(&["mprovision", "list", "."])).to(be_ok().value(Command::List(ListParams {
            filter: None,
            expires_in_days: None,
            directory: Some(".".into()),
        })));

        expect!(parse(&["mprovision", "list", "--filter", "abc"]))
            .to(be_ok().value(Command::List(ListParams {
                filter: Some("abc".to_string()),
                expires_in_days: None,
                directory: None,
            })));

        expect!(parse(&["mprovision", "list", "--filter", ""])).to(be_err());

        expect!(parse(&["mprovision", "list", "--expires-in-days", "3"]))
            .to(be_ok().value(Command::List(ListParams {
                filter: None,
                expires_in_days: Some(3),
                directory: None,
            })));

        expect!(parse(&["mprovision", "list", "--expires-in-days", "-3"])).to(be_err());
        expect!(parse(&["mprovision", "list", "--expires-in-days", "366"])).to(be_err());

        expect!(parse(&["mprovision", "list", "--filter", "abc", "--expires-in-days", "3", "."]))
            .to(be_ok().value(Command::List(ListParams {
                filter: Some("abc".to_string()),
                expires_in_days: Some(3),
                directory: Some(".".into()),
            })));
    }

    #[test]
    fn show_uuid_command() {
        expect!(parse(&["mprovision", "show", "--uuid", "abcd"]))
            .to(be_ok().value(Command::ShowUuid("abcd".to_string(), None)));

        expect!(parse(&["mprovision", "show", "--uuid", "abcd", "."]))
            .to(be_ok().value(Command::ShowUuid("abcd".to_string(), Some(".".into()))));

        expect!(parse(&["mprovision", "show", "."])).to(be_err());
    }

    #[test]
    fn show_path_command() {
        expect!(parse(&["mprovision", "show", "--path", "file.mprovision"]))
            .to(be_ok().value(Command::ShowPath("file.mprovision".into())));

        expect!(parse(&["mprovision", "show", "--path", "file.mprovision", "."])).to(be_err());
    }

    #[test]
    fn remove_uuid_command() {
        expect!(parse(&["mprovision", "remove", "--uuid", "abcd"]))
            .to(be_ok().value(Command::RemoveUuid("abcd".to_string(), None)));

        expect!(parse(&["mprovision", "remove", "--uuid", "abcd", "."]))
            .to(be_ok().value(Command::RemoveUuid("abcd".to_string(), Some(".".into()))));

        expect!(parse(&["mprovision", "remove", "."])).to(be_err());
    }

    #[test]
    fn remove_path_command() {
        expect!(parse(&["mprovision", "remove", "--path", "file.mprovision"]))
            .to(be_ok().value(Command::RemovePath("file.mprovision".into())));

        expect!(parse(&["mprovision", "remove", "--path", "file.mprovision", "."])).to(be_err());
    }

    #[test]
    fn cleanup_command() {
        expect!(parse(&["mprovision", "cleanup"])).to(be_ok().value(Command::Cleanup(None)));

        expect!(parse(&["mprovision", "cleanup", "."]))
            .to(be_ok().value(Command::Cleanup(Some(".".into()))));
    }
}
<commit_msg>Add display order to subcommands<commit_after>use clap::{self, Arg, App, SubCommand, AppSettings};
use std::io::{self, Write};
use std::process;
use std::path::PathBuf;
use std::error;
use std::result;
use std::fmt;
use mprovision as mp;

#[derive(Debug, PartialEq)]
pub enum Command {
    List(ListParams),
    ShowUuid(String, Option<PathBuf>),
    ShowPath(PathBuf),
    RemoveUuid(String, Option<PathBuf>),
    RemovePath(PathBuf),
    Cleanup(Option<PathBuf>),
}

#[derive(Debug, Default, PartialEq)]
pub struct ListParams {
    pub filter: Option<String>,
    pub expires_in_days: Option<i64>,
    pub directory: Option<PathBuf>,
}

pub type Result = result::Result<Command, Error>;

#[derive(Debug)]
pub enum Error {
    Lib(mp::Error),
    Clap(clap::Error),
    Custom(String),
}

impl Error {
    pub fn exit(&self) -> ! {
        match *self {
            Error::Clap(ref e) => e.exit(),
            _ => {
                writeln!(&mut io::stderr(), "{}", self).unwrap();
                process::exit(1);
            }
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Lib(ref e) => e.description(),
            Error::Clap(ref e) => e.description(),
            Error::Custom(ref e) => e,
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Lib(ref e) => Some(e),
            Error::Clap(ref e) => Some(e),
            Error::Custom(_) => None,
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Lib(ref e) => error::Error::description(e).fmt(f),
            Error::Clap(ref e) => error::Error::description(e).fmt(f),
            Error::Custom(ref e) => e.fmt(f),
        }
    }
}

impl From<mp::Error> for Error {
    fn from(e: mp::Error) -> Self {
        Error::Lib(e)
    }
}

impl From<clap::Error> for Error {
    fn from(e: clap::Error) -> Self {
        Error::Clap(e)
    }
}

pub fn parse<I, S>(args: I) -> Result
    where I: IntoIterator<Item = S>,
          S: Clone,
          ::std::ffi::OsString: From<S>
{
    let app = App::new("mprovision")
        .about("A tool that helps iOS developers to manage mobileprovision files.")
        .subcommand(SubCommand::with_name("list")
            .about("Lists provisioning profiles")
            .display_order(0)
            .setting(AppSettings::DisableVersion)
            .arg(Arg::with_name("TEXT")
                .long("--filter")
                .required(false)
                .empty_values(false)
                .takes_value(true))
            .arg(Arg::with_name("DAYS")
                .long("--expires-in-days")
                .required(false)
                .empty_values(false)
                .takes_value(true))
            .arg(Arg::with_name("DIRECTORY")
                .required(false)
                .empty_values(false)
                .takes_value(true)))
        .subcommand(SubCommand::with_name("show")
            .about("Shows details of a provisioning profile")
            .display_order(1)
            .setting(AppSettings::DisableVersion)
            .arg(Arg::with_name("UUID")
                .long("--uuid")
                .required(true)
                .empty_values(false)
                .takes_value(true)
                .conflicts_with("PATH"))
            .arg(Arg::with_name("DIRECTORY")
                .required(false)
                .empty_values(false)
                .takes_value(true)
                .conflicts_with("PATH"))
            .arg(Arg::with_name("PATH")
                .long("--path")
                .required(true)
                .empty_values(false)
                .takes_value(true)
                .required(true)))
        .subcommand(SubCommand::with_name("remove")
            .about("Removes a provisioning profile")
            .display_order(2)
            .setting(AppSettings::DisableVersion)
            .arg(Arg::with_name("UUID")
                .long("--uuid")
                .required(true)
                .empty_values(false)
                .takes_value(true)
                .conflicts_with("PATH"))
            .arg(Arg::with_name("DIRECTORY")
                .required(false)
                .empty_values(false)
                .takes_value(true)
                .conflicts_with("PATH"))
            .arg(Arg::with_name("PATH")
                .long("--path")
                .required(true)
                .empty_values(false)
                .takes_value(true)
                .required(true)))
        .subcommand(SubCommand::with_name("cleanup")
            .about("Removes expired provisioning profiles")
            .display_order(4)
            .setting(AppSettings::DisableVersion)
            .arg(Arg::with_name("DIRECTORY")
                .required(false)
                .empty_values(false)
                .takes_value(true)));

    let matches = app.get_matches_from_safe(args)?;
    if let Some(list_matches) = matches.subcommand_matches("list") {
        let mut params = ListParams::default();
        params.filter = list_matches.value_of("TEXT").map(|text| text.to_string());
        if let Some(days) = list_matches.value_of("DAYS")
            .and_then(|days| days.parse::<i64>().ok()) {
            if days < 0 || days > 365 {
                return Err(Error::Custom("DAYS should be between 0 and 365".to_string()));
            }
            params.expires_in_days = Some(days);
        }
        params.directory = list_matches.value_of("DIRECTORY").map(|dir| dir.into());
        Ok(Command::List(params))
    } else if let Some(show_matches) = matches.subcommand_matches("show") {
        if let Some(uuid) = show_matches.value_of("UUID").map(|uuid| uuid.to_string()) {
            let directory = show_matches.value_of("DIRECTORY").map(|dir| dir.into());
            Ok(Command::ShowUuid(uuid, directory))
        } else {
            let path = show_matches.value_of("PATH").map(|path| path.into()).unwrap();
            Ok(Command::ShowPath(path))
        }
    } else if let Some(remove_matches) = matches.subcommand_matches("remove") {
        if let Some(uuid) = remove_matches.value_of("UUID").map(|uuid| uuid.to_string()) {
            let directory = remove_matches.value_of("DIRECTORY").map(|dir| dir.into());
            Ok(Command::RemoveUuid(uuid, directory))
        } else {
            let path = remove_matches.value_of("PATH").map(|path| path.into()).unwrap();
            Ok(Command::RemovePath(path))
        }
    } else if let Some(cleanup_matches) = matches.subcommand_matches("cleanup") {
        let directory = cleanup_matches.value_of("DIRECTORY").map(|dir| dir.into());
        Ok(Command::Cleanup(directory))
    } else {
        Err(Error::Custom("Command isn't implemented".to_string()))
    }
}

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

    #[test]
    fn list_command() {
        expect!(parse(&["mprovision", "list"]))
            .to(be_ok().value(Command::List(ListParams::default())));

        expect!(parse(&["mprovision", "list", "."])).to(be_ok().value(Command::List(ListParams {
            filter: None,
            expires_in_days: None,
            directory: Some(".".into()),
        })));

        expect!(parse(&["mprovision", "list", "--filter", "abc"]))
            .to(be_ok().value(Command::List(ListParams {
                filter: Some("abc".to_string()),
                expires_in_days: None,
                directory: None,
            })));

        expect!(parse(&["mprovision", "list", "--filter", ""])).to(be_err());

        expect!(parse(&["mprovision", "list", "--expires-in-days", "3"]))
            .to(be_ok().value(Command::List(ListParams {
                filter: None,
                expires_in_days: Some(3),
                directory: None,
            })));

        expect!(parse(&["mprovision", "list", "--expires-in-days", "-3"])).to(be_err());
        expect!(parse(&["mprovision", "list", "--expires-in-days", "366"])).to(be_err());

        expect!(parse(&["mprovision", "list", "--filter", "abc", "--expires-in-days", "3", "."]))
            .to(be_ok().value(Command::List(ListParams {
                filter: Some("abc".to_string()),
                expires_in_days: Some(3),
                directory: Some(".".into()),
            })));
    }

    #[test]
    fn show_uuid_command() {
        expect!(parse(&["mprovision", "show", "--uuid", "abcd"]))
            .to(be_ok().value(Command::ShowUuid("abcd".to_string(), None)));

        expect!(parse(&["mprovision", "show", "--uuid", "abcd", "."]))
            .to(be_ok().value(Command::ShowUuid("abcd".to_string(), Some(".".into()))));

        expect!(parse(&["mprovision", "show", "."])).to(be_err());
    }

    #[test]
    fn show_path_command() {
        expect!(parse(&["mprovision", "show", "--path", "file.mprovision"]))
            .to(be_ok().value(Command::ShowPath("file.mprovision".into())));

        expect!(parse(&["mprovision", "show", "--path", "file.mprovision", "."])).to(be_err());
    }

    #[test]
    fn remove_uuid_command() {
        expect!(parse(&["mprovision", "remove", "--uuid", "abcd"]))
            .to(be_ok().value(Command::RemoveUuid("abcd".to_string(), None)));

        expect!(parse(&["mprovision", "remove", "--uuid", "abcd", "."]))
            .to(be_ok().value(Command::RemoveUuid("abcd".to_string(), Some(".".into()))));

        expect!(parse(&["mprovision", "remove", "."])).to(be_err());
    }

    #[test]
    fn remove_path_command() {
        expect!(parse(&["mprovision", "remove", "--path", "file.mprovision"]))
            .to(be_ok().value(Command::RemovePath("file.mprovision".into())));

        expect!(parse(&["mprovision", "remove", "--path", "file.mprovision", "."])).to(be_err());
    }

    #[test]
    fn cleanup_command() {
        expect!(parse(&["mprovision", "cleanup"])).to(be_ok().value(Command::Cleanup(None)));

        expect!(parse(&["mprovision", "cleanup", "."]))
            .to(be_ok().value(Command::Cleanup(Some(".".into()))));
    }
}
<|endoftext|>


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

#![forbid(unsafe_code)]

use bytecode_source_map::{
    mapping::SourceMapping,
    source_map::ModuleSourceMap,
    utils::{module_source_map_from_file, remap_owned_loc_to_loc, OwnedLoc},
};
use disassembler::disassembler::{Disassembler, DisassemblerOptions};
use libra_types::transaction::Module;
use move_ir_types::location::Spanned;
use std::{fs, path::Path};
use structopt::StructOpt;
use vm::file_format::{CompiledModule, CompiledScript};

#[derive(Debug, StructOpt)]
#[structopt(
    name = "Move Bytecode Disassembler",
    about = "Move IR bytecode disassembler."
)]
struct Args {
    /// Shows only public functions.
    #[structopt(short = "p", long = "public")]
    pub only_public: bool,

    /// Prints out the disassembled bytecodes for each function.
    #[structopt(short = "c", long = "code")]
    pub print_code: bool,

    /// The path to the bytecode file to disassemble; let's call it file.mv. We assume that two
    /// other files reside under the same directory: a source map file.mvsm (possibly) and the Move
    /// IR source code file.mvir.
    #[structopt(short = "s", long = "script")]
    pub is_script: bool,

    /// The path to the bytecode file.
    #[structopt(short = "b", long = "bytecode")]
    pub bytecode_file_path: String,

    /// Print basic blocks.
    #[structopt(long = "basic-blocks")]
    pub print_basic_blocks: bool,

    /// Print locals within each function.
    #[structopt(long = "locals")]
    pub print_locals: bool,
}

fn main() {
    let args = Args::from_args();

    let mvir_extension = "mvir";
    let mv_bytecode_extension = "mv";
    let source_map_extension = "mvsm";

    let source_path = Path::new(&args.bytecode_file_path);
    let extension = source_path
        .extension()
        .expect("Missing file extension for bytecode file");
    if extension != mv_bytecode_extension {
        println!(
            "Bad source file extension {:?}; expected {}",
            extension, mv_bytecode_extension
        );
        std::process::exit(1);
    }

    let bytecode_source =
        fs::read_to_string(args.bytecode_file_path.clone()).expect("Unable to read bytecode file");
    let module_bytes: Module = serde_json::from_str(bytecode_source.as_str())
        .expect("Unable to deserialize bytecode file");

    let ir_source_path = Path::new(&args.bytecode_file_path).with_extension(mvir_extension);
    let ir_source = fs::read_to_string(&ir_source_path).ok();
    let source_map = module_source_map_from_file::<OwnedLoc>(
        &Path::new(&args.bytecode_file_path).with_extension(source_map_extension),
    )
    .map(remap_owned_loc_to_loc);

    let mut disassembler_options = DisassemblerOptions::new();
    disassembler_options.print_code = args.print_code | args.print_basic_blocks;
    disassembler_options.only_public = args.only_public;
    disassembler_options.print_basic_blocks = args.print_basic_blocks;
    disassembler_options.print_locals = args.print_locals;

    let no_loc = Spanned::unsafe_no_loc(()).loc;
    let mut source_mapping = if args.is_script {
        let compiled_script = CompiledScript::deserialize(module_bytes.code())
            .expect("Script blob can't be deserialized");
        source_map
            .or_else(|_| ModuleSourceMap::dummy_from_script(&compiled_script, no_loc))
            .and_then(|source_map| Ok(SourceMapping::new_from_script(source_map, compiled_script)))
            .expect("Unable to build source mapping for compiled script")
    } else {
        let compiled_module = CompiledModule::deserialize(module_bytes.code())
            .expect("Module blob can't be deserialized");
        source_map
            .or_else(|_| ModuleSourceMap::dummy_from_module(&compiled_module, no_loc))
            .and_then(|source_map| Ok(SourceMapping::new(source_map, compiled_module)))
            .expect("Unable to build source mapping for compiled module")
    };

    if let Some(source_code) = ir_source {
        source_mapping
            .with_source_code((ir_source_path.to_str().unwrap().to_string(), source_code));
    }

    let disassembler = Disassembler::new(source_mapping, disassembler_options);

    let dissassemble_string = disassembler.disassemble().expect("Unable to dissassemble");

    println!("{}", dissassemble_string);
}
<commit_msg>[move tools][dissassembler] Make disassembler accept raw bytecode<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

use bytecode_source_map::{
    mapping::SourceMapping,
    source_map::ModuleSourceMap,
    utils::{module_source_map_from_file, remap_owned_loc_to_loc, OwnedLoc},
};
use disassembler::disassembler::{Disassembler, DisassemblerOptions};
use move_ir_types::location::Spanned;
use std::{fs, path::Path};
use structopt::StructOpt;
use vm::file_format::{CompiledModule, CompiledScript};

#[derive(Debug, StructOpt)]
#[structopt(
    name = "Move Bytecode Disassembler",
    about = "Print a human-readable version of Move bytecode (.mv files)"
)]
struct Args {
    /// Skip printing of private functions.
    #[structopt(long = "skip-private")]
    pub skip_private: bool,

    /// Do not print the disassembled bytecodes of each function.
    #[structopt(long = "skip-code")]
    pub skip_code: bool,

    /// Do not print locals of each function.
    #[structopt(long = "skip-locals")]
    pub skip_locals: bool,

    /// Do not print the basic blocks of each function.
    #[structopt(long = "skip-basic-blocks")]
    pub skip_basic_blocks: bool,

    /// The path to the bytecode file to disassemble; let's call it file.mv. We assume that two
    /// other files reside under the same directory: a source map file.mvsm (possibly) and the Move
    /// source code file.move.
    #[structopt(short = "s", long = "script")]
    pub is_script: bool,

    /// The path to the bytecode file.
    #[structopt(short = "b", long = "bytecode")]
    pub bytecode_file_path: String,
}

fn main() {
    let args = Args::from_args();

    let move_extension = "move";
    let mv_bytecode_extension = "mv";
    let source_map_extension = "mvsm";

    let source_path = Path::new(&args.bytecode_file_path);
    let extension = source_path
        .extension()
        .expect("Missing file extension for bytecode file");
    if extension != mv_bytecode_extension {
        println!(
            "Bad source file extension {:?}; expected {}",
            extension, mv_bytecode_extension
        );
        std::process::exit(1);
    }

    let bytecode_bytes = fs::read(&args.bytecode_file_path).expect("Unable to read bytecode file");

    let source_path = Path::new(&args.bytecode_file_path).with_extension(move_extension);
    let source = fs::read_to_string(&source_path).ok();
    let source_map = module_source_map_from_file::<OwnedLoc>(
        &Path::new(&args.bytecode_file_path).with_extension(source_map_extension),
    )
    .map(remap_owned_loc_to_loc);

    let mut disassembler_options = DisassemblerOptions::new();
    disassembler_options.print_code = !args.skip_code;
    disassembler_options.only_public = !args.skip_private;
    disassembler_options.print_basic_blocks = !args.skip_basic_blocks;
    disassembler_options.print_locals = !args.skip_locals;

    // TODO: make source mapping work with the move source language
    let no_loc = Spanned::unsafe_no_loc(()).loc;
    let mut source_mapping = if args.is_script {
        let compiled_script = CompiledScript::deserialize(&bytecode_bytes)
            .expect("Script blob can't be deserialized");
        source_map
            .or_else(|_| ModuleSourceMap::dummy_from_script(&compiled_script, no_loc))
            .and_then(|source_map| Ok(SourceMapping::new_from_script(source_map, compiled_script)))
            .expect("Unable to build source mapping for compiled script")
    } else {
        let compiled_module = CompiledModule::deserialize(&bytecode_bytes)
            .expect("Module blob can't be deserialized");
        source_map
            .or_else(|_| ModuleSourceMap::dummy_from_module(&compiled_module, no_loc))
            .and_then(|source_map| Ok(SourceMapping::new(source_map, compiled_module)))
            .expect("Unable to build source mapping for compiled module")
    };

    if let Some(source_code) = source {
        source_mapping.with_source_code((source_path.to_str().unwrap().to_string(), source_code));
    }

    let disassembler = Disassembler::new(source_mapping, disassembler_options);

    let dissassemble_string = disassembler.disassemble().expect("Unable to dissassemble");

    println!("{}", dissassemble_string);
}
<|endoftext|>


<commit_before>use std::env;
use std::io::Write;
use std::time::Instant;

use atty;
use chrono::Duration;
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};

use errors::Error;
use site::Site;

lazy_static! {
    /// Termcolor color choice.
    /// We do not rely on ColorChoice::Auto behavior
    /// as the check is already performed by has_color.
    static ref COLOR_CHOICE: ColorChoice =
        if has_color() {
            ColorChoice::Always
        } else {
            ColorChoice::Never
        };
}

pub fn info(message: &str) {
    colorize(message, ColorSpec::new().set_bold(true));
}

pub fn warn(message: &str) {
    colorize(message, ColorSpec::new().set_bold(true).set_fg(Some(Color::Yellow)));
}

pub fn success(message: &str) {
    colorize(message, ColorSpec::new().set_bold(true).set_fg(Some(Color::Green)));
}

pub fn error(message: &str) {
    colorize(message, ColorSpec::new().set_bold(true).set_fg(Some(Color::Red)));
}

/// Print a colorized message to stdout
fn colorize(message: &str, color: &ColorSpec) {
    let mut stdout = StandardStream::stdout(*COLOR_CHOICE);
    stdout.set_color(color).unwrap();
    writeln!(&mut stdout, "{}", message).unwrap();
}

/// Display in the console the number of pages/sections in the site
pub fn notify_site_size(site: &Site) {
    println!(
        "-> Creating {} pages ({} orphan), {} sections, and processing {} images",
        site.library.pages().len(),
        site.get_all_orphan_pages().len(),
        site.library.sections().len() - 1, // -1 since we do not the index as a section
        site.num_img_ops(),
    );
}

/// Display a warning in the console if there are ignored pages in the site
pub fn warn_about_ignored_pages(site: &Site) {
    let ignored_pages: Vec<_> = site
        .library
        .sections_values()
        .iter()
        .flat_map(|s| {
            s.ignored_pages.iter().map(|k| site.library.get_page_by_key(*k).file.path.clone())
        })
        .collect();

    if !ignored_pages.is_empty() {
        warn(&format!(
            "{} page(s) ignored (missing date or weight in a sorted section):",
            ignored_pages.len()
        ));
        for path in ignored_pages {
            warn(&format!("- {}", path.display()));
        }
    }
}

/// Print the time elapsed rounded to 1 decimal
pub fn report_elapsed_time(instant: Instant) {
    let duration_ms = Duration::from_std(instant.elapsed()).unwrap().num_milliseconds() as f64;

    if duration_ms < 1000.0 {
        success(&format!("Done in {}ms.\n", duration_ms));
    } else {
        let duration_sec = duration_ms / 1000.0;
        success(&format!("Done in {:.1}s.\n", ((duration_sec * 10.0).round() / 10.0)));
    }
}

/// Display an error message and the actual error(s)
pub fn unravel_errors(message: &str, error: &Error) {
    if !message.is_empty() {
        self::error(message);
    }
    self::error(&format!("Error: {}", error));
    for e in error.iter().skip(1) {
        self::error(&format!("Reason: {}", e));
    }
}

/// Check whether to output colors
fn has_color() -> bool {
    let use_colors = env::var("CLICOLOR").unwrap_or_else(|_| "1".to_string()) != "0"
        && env::var("NO_COLOR").is_err();
    let force_colors = env::var("CLICOLOR_FORCE").unwrap_or_else(|_| "0".to_string()) != "0";

    force_colors || use_colors && atty::is(atty::Stream::Stdout)
}
<commit_msg>reset color in colorize<commit_after>use std::env;
use std::io::Write;
use std::time::Instant;

use atty;
use chrono::Duration;
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};

use errors::Error;
use site::Site;

lazy_static! {
    /// Termcolor color choice.
    /// We do not rely on ColorChoice::Auto behavior
    /// as the check is already performed by has_color.
    static ref COLOR_CHOICE: ColorChoice =
        if has_color() {
            ColorChoice::Always
        } else {
            ColorChoice::Never
        };
}

pub fn info(message: &str) {
    colorize(message, ColorSpec::new().set_bold(true));
}

pub fn warn(message: &str) {
    colorize(message, ColorSpec::new().set_bold(true).set_fg(Some(Color::Yellow)));
}

pub fn success(message: &str) {
    colorize(message, ColorSpec::new().set_bold(true).set_fg(Some(Color::Green)));
}

pub fn error(message: &str) {
    colorize(message, ColorSpec::new().set_bold(true).set_fg(Some(Color::Red)));
}

/// Print a colorized message to stdout
fn colorize(message: &str, color: &ColorSpec) {
    let mut stdout = StandardStream::stdout(*COLOR_CHOICE);
    stdout.set_color(color).unwrap();
    writeln!(&mut stdout, "{}", message).unwrap();
    stdout.set_color(&ColorSpec::new()).unwrap();
}

/// Display in the console the number of pages/sections in the site
pub fn notify_site_size(site: &Site) {
    println!(
        "-> Creating {} pages ({} orphan), {} sections, and processing {} images",
        site.library.pages().len(),
        site.get_all_orphan_pages().len(),
        site.library.sections().len() - 1, // -1 since we do not the index as a section
        site.num_img_ops(),
    );
}

/// Display a warning in the console if there are ignored pages in the site
pub fn warn_about_ignored_pages(site: &Site) {
    let ignored_pages: Vec<_> = site
        .library
        .sections_values()
        .iter()
        .flat_map(|s| {
            s.ignored_pages.iter().map(|k| site.library.get_page_by_key(*k).file.path.clone())
        })
        .collect();

    if !ignored_pages.is_empty() {
        warn(&format!(
            "{} page(s) ignored (missing date or weight in a sorted section):",
            ignored_pages.len()
        ));
        for path in ignored_pages {
            warn(&format!("- {}", path.display()));
        }
    }
}

/// Print the time elapsed rounded to 1 decimal
pub fn report_elapsed_time(instant: Instant) {
    let duration_ms = Duration::from_std(instant.elapsed()).unwrap().num_milliseconds() as f64;

    if duration_ms < 1000.0 {
        success(&format!("Done in {}ms.\n", duration_ms));
    } else {
        let duration_sec = duration_ms / 1000.0;
        success(&format!("Done in {:.1}s.\n", ((duration_sec * 10.0).round() / 10.0)));
    }
}

/// Display an error message and the actual error(s)
pub fn unravel_errors(message: &str, error: &Error) {
    if !message.is_empty() {
        self::error(message);
    }
    self::error(&format!("Error: {}", error));
    for e in error.iter().skip(1) {
        self::error(&format!("Reason: {}", e));
    }
}

/// Check whether to output colors
fn has_color() -> bool {
    let use_colors = env::var("CLICOLOR").unwrap_or_else(|_| "1".to_string()) != "0"
        && env::var("NO_COLOR").is_err();
    let force_colors = env::var("CLICOLOR_FORCE").unwrap_or_else(|_| "0".to_string()) != "0";

    force_colors || use_colors && atty::is(atty::Stream::Stdout)
}
<|endoftext|>


<commit_before>use {AsRaw, Device, Event, FromRaw, ffi};

use libc;
use std::mem;
use std::ffi::{CStr, CString};
use std::io::{Error as IoError, Result as IoResult};
use std::iter::Iterator;
use std::path::Path;
use std::os::unix::io::RawFd;

#[cfg(feature = "udev")]
use udev::{AsRaw as UdevAsRaw, Context as UdevContext};

/// libinput does not open file descriptors to devices directly,
/// instead `open_restricted` and `close_restricted` are called for
/// each path that must be opened.
///
/// Implementations are of course permitted to just use `open` and
/// `close` respectively, but doing so would require root permissions
/// to open devices. This interface provides an api agnostic way to
/// use ConsoleKit or similar endpoints to open devices without
/// direct priviledge escalation.
pub trait LibinputInterface {
    /// Open the device at the given path with the flags provided and
	/// return the fd.
	///
    /// ## Paramater
	/// - `path` - The device path to open
    /// - `flags` Flags as defined by open(2)
    ///
    /// ## Returns
    /// The file descriptor, or a negative errno on failure.
    fn open_restricted(&mut self, path: &Path, flags: i32) -> Result<RawFd, i32>;

    /// Close the file descriptor.
	///
    /// ## Parameter
	/// `fd` - The file descriptor to close
    fn close_restricted(&mut self, fd: RawFd);
}

unsafe extern "C" fn open_restricted<I: LibinputInterface + 'static>(path: *const libc::c_char,
                                                                    flags: libc::c_int,
                                                                    user_data: *mut libc::c_void)
                                                                    -> libc::c_int
{
    use std::borrow::Cow;

    if let Some(ref mut interface) = (user_data as *mut I).as_mut() {
        let path_str = CStr::from_ptr(path).to_string_lossy();
        let res = match path_str {
            Cow::Borrowed(string) => interface.open_restricted(Path::new(string), flags),
            Cow::Owned(string) => interface.open_restricted(Path::new(&string), flags),
        };
        match res {
            Ok(fd) => fd,
            Err(errno) => errno,
        }
    } else { -1 }
}

unsafe extern "C" fn close_restricted<I: LibinputInterface + 'static>(fd: libc::c_int, user_data: *mut libc::c_void)
{
    if let Some(ref mut interface) = (user_data as *mut I).as_mut() {
        interface.close_restricted(fd)
    }
}

/// Libinput context
///
/// Contexts can be used to track input devices and receive events from them.
/// You can use either `new_from_udev` to create a context tracking all devices on a specific seat,
/// or use `new_from_path` to track input devices manually.
///
/// Either way you then have to use `dispatch()` and `next()` (provided by the `Iterator` trait) to
/// receive events.
#[derive(Eq)]
pub struct Libinput
{
    ffi: *mut ffi::libinput,
}

impl ::std::fmt::Debug for Libinput {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "Libinput @{:p}", self.as_raw())
    }
}

impl FromRaw<ffi::libinput> for Libinput
{
    unsafe fn from_raw(ffi: *mut ffi::libinput) -> Self {
        Libinput {
            ffi: ffi::libinput_ref(ffi),
        }
    }
}

impl AsRaw<ffi::libinput> for Libinput
{
    fn as_raw(&self) -> *const ffi::libinput {
        self.ffi as *const _
    }
}

impl Clone for Libinput {
    fn clone(&self) -> Self {
        unsafe { Libinput::from_raw(self.as_raw_mut()) }
    }
}

impl Drop for Libinput
{
    fn drop(&mut self) {
        unsafe {
            let userdata_ref = ffi::libinput_get_user_data(self.as_raw_mut());
            if ffi::libinput_unref(self.ffi).is_null() {
                let _ = Box::from_raw(userdata_ref);
            }
        }
    }
}

impl PartialEq for Libinput {
    fn eq(&self, other: &Self) -> bool {
        self.as_raw() == other.as_raw()
    }
}

impl ::std::hash::Hash for Libinput {
    fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
        self.as_raw().hash(state);
    }
}

impl Iterator for Libinput {
    type Item = Event;
    fn next(&mut self) -> Option<Self::Item> {
        let ptr = unsafe { ffi::libinput_get_event(self.as_raw_mut()) };
        if ptr.is_null() {
            None
        } else {
            unsafe { Some(Event::from_raw(ptr)) }
        }
    }
}

impl Libinput {
    /// Create a new libinput context using a udev context.
    ///
    /// This context is inactive until `udev_assign_seat` is called.
    ///
    /// ## Arguments
    ///
    /// - interface - A `LibinputInterface` providing functions to open and close devices.
    /// - userdata - Optionally some userdata attached to the newly created context (see [`Userdata`](./trait.Userdata.html))
    /// - udev_context - Raw pointer to a valid udev context.
    ///
    /// ## Unsafety
    ///
    /// This function is unsafe, because there is no way to verify that `udev_context` is indeed a valid udev context or even points to valid memory.
    #[cfg(feature = "udev")]
    pub fn new_from_udev<I: LibinputInterface + 'static>(interface: I,
                                                         udev_context: &UdevContext)
                                                         -> Libinput
    {
        let mut boxed_userdata = Box::new(interface);
        let boxed_interface = Box::new(ffi::libinput_interface {
            open_restricted: Some(open_restricted::<I>),
            close_restricted: Some(close_restricted::<I>),
        });

        let context = Libinput {
            ffi: unsafe {
                ffi::libinput_udev_create_context(&*boxed_interface as *const _,
                                                  &mut *boxed_userdata as *mut I as *mut libc::c_void,
                                                  udev_context.as_raw() as *mut _)
            },
        };

        mem::forget(boxed_interface);
        mem::forget(boxed_userdata);

        context
    }

    /// Create a new libinput context that requires the caller to manually add or remove devices.
    ///
    /// The returned context is active, but will not yield any events
    /// until at least one device is added.
    ///
    /// Devices can be added and removed by calling `path_add_device` and `path_remove_device` respectively.
    ///
    /// ## Arguments
    ///
    /// - interface - A `LibinputInterface` providing functions to open and close devices.
    /// - userdata - Optionally some userdata attached to the newly created context (see [`Userdata`](./trait.Userdata.html))
    ///
    pub fn new_from_path<I: 'static + LibinputInterface>(interface: I) -> Libinput {
        let mut boxed_userdata = Box::new(interface);
        let boxed_interface = Box::new(ffi::libinput_interface {
            open_restricted: Some(open_restricted::<I>),
            close_restricted: Some(close_restricted::<I>),
        });

        let context = Libinput {
            ffi: unsafe {
                ffi::libinput_path_create_context(&*boxed_interface as *const _,
                                                  &mut *boxed_userdata as *mut I as *mut libc::c_void)
            },
        };

        mem::forget(boxed_interface);
        mem::forget(boxed_userdata);

        context
    }

    /// Add a device to a libinput context initialized with
    /// `new_from_context`.
    ///
    /// If successful, the device will be added to the internal list
    /// and re-opened on `resume`. The device can be removed with
    /// `path_remove_device()`.
    ///
    /// If the device was successfully initialized, it is returned.
    ///
    /// ## Warning
    ///
    /// It is an application bug to call this function on a context
    /// initialized with `new_from_udev`.
    pub fn path_add_device(&mut self, path: &str) -> Option<Device> {
        let path = CString::new(path).expect("Device Path contained a null-byte");
        unsafe {
            let ptr = ffi::libinput_path_add_device(self.as_raw_mut(), path.as_ptr());
            if ptr.is_null() {
                None
            } else {
                Some(Device::from_raw(ptr))
            }
        }
    }

    /// Remove a device from a libinput context initialized with
    /// `new_from_path` and added to such a context with
    /// `path_add_device`.
    ///
    /// Events already processed from this input device are kept in
    /// the queue, the `DeviceRemovedEvent` event marks the end of
    /// events for this device.
    ///
    /// ## Warning
    ///
    /// It is an application bug to call this function on a context
    /// initialized with `new_from_udev`.
    pub fn path_remove_device(&mut self, device: Device) {
        unsafe { ffi::libinput_path_remove_device(device.as_raw_mut()) }
    }

    /// Assign a seat to this libinput context.
    ///
    /// New devices or the removal of existing devices will appear as
    /// events during `dispatch`.
    ///
    /// `udev_assign_seat` succeeds even if no input devices are
    /// currently available on this seat, or if devices are available
    /// but fail to open in `LibinputInterface::open_restricted`.
    ///
    /// Devices that do not have the minimum capabilities to be
    /// recognized as pointer, keyboard or touch device are ignored. /// Such devices and those that failed to open ignored until the
    /// next call to `resume`.
    ///
    /// ## Warning
    ///
    /// This function may only be called once per context.
    #[cfg(feature = "udev")]
    pub fn udev_assign_seat(&mut self, seat_id: &str) -> Result<(), ()> {
        let id = CString::new(seat_id).expect("Seat Id contained a null-byte");
        unsafe {
            match ffi::libinput_udev_assign_seat(self.as_raw_mut(), id.as_ptr()) {
                0 => Ok(()),
                -1 => Err(()),
                _ => unreachable!(),
            }
        }
    }

    ffi_func!(
    /// Suspend monitoring for new devices and close existing
    /// devices.
    ///
    /// This closes all open devices and terminates libinput but
    /// does keep the context valid to be resumed with `resume`.
    pub fn suspend, ffi::libinput_suspend, ());

    /// Resume a suspended libinput context.
    ///
    /// This re-enables device monitoring and adds existing devices.
    pub fn resume(&mut self) -> Result<(), ()> {
        unsafe {
            match ffi::libinput_resume(self.as_raw_mut()) {
                0 => Ok(()),
                -1 => Err(()),
                _ => unreachable!(),
            }
        }
    }

    /// Main event dispatchment function.
    ///
    /// Reads events of the file descriptors and processes them
    /// internally. Use `next` or any other function provided by the
    /// `Iterator` trait to retrieve the events until `None` is
    /// returned.
    ///
    /// Dispatching does not necessarily queue libinput events. This
    /// function should be called immediately once data is available
    /// on the file descriptor returned by `fd`. libinput has a number
    /// of timing-sensitive features (e.g. tap-to-click), any delay in
    /// calling `dispatch` may prevent these features from working
    /// correctly.
    pub fn dispatch(&mut self) -> IoResult<()> {
        unsafe {
            match ffi::libinput_dispatch(self.as_raw_mut()) {
                0 => Ok(()),
                x if x < 0 => Err(IoError::from_raw_os_error(x)),
                _ => unreachable!(),
            }
        }
    }

    /// libinput keeps a single file descriptor for all events.
    ///
    /// Call into `dispatch` if any events become available on this fd.
    ///
    /// The most simple variant to check for available bytes is to use
    /// the `libc`:
    ///
    ///     loop {
    ///         let mut count = 0i32;
    ///         libc::ioctl(context.fd(), libc::FIONREAD, &mut count);
    ///         if (count > 0) {
    ///             context.dispatch().unwrap();
    ///             for event in context {
    ///                 // do some processing...
    ///             }
    ///         }
    ///     }
    ///
    /// For more complex operations you may wish to use other approches
    /// as event loops e.g. in the `wayland-server` or the `tokio`
    /// crates to wait for data to become available on this file
    /// descriptor.
    pub unsafe fn fd(&self) -> RawFd {
        ffi::libinput_get_fd(self.as_raw_mut())
    }
}
<commit_msg>Fix negativ errno<commit_after>use {AsRaw, Device, Event, FromRaw, ffi};

use libc;
use std::mem;
use std::ffi::{CStr, CString};
use std::io::{Error as IoError, Result as IoResult};
use std::iter::Iterator;
use std::path::Path;
use std::os::unix::io::RawFd;

#[cfg(feature = "udev")]
use udev::{AsRaw as UdevAsRaw, Context as UdevContext};

/// libinput does not open file descriptors to devices directly,
/// instead `open_restricted` and `close_restricted` are called for
/// each path that must be opened.
///
/// Implementations are of course permitted to just use `open` and
/// `close` respectively, but doing so would require root permissions
/// to open devices. This interface provides an api agnostic way to
/// use ConsoleKit or similar endpoints to open devices without
/// direct priviledge escalation.
pub trait LibinputInterface {
    /// Open the device at the given path with the flags provided and
	/// return the fd.
	///
    /// ## Paramater
	/// - `path` - The device path to open
    /// - `flags` Flags as defined by open(2)
    ///
    /// ## Returns
    /// The file descriptor, or a negative errno on failure.
    fn open_restricted(&mut self, path: &Path, flags: i32) -> Result<RawFd, i32>;

    /// Close the file descriptor.
	///
    /// ## Parameter
	/// `fd` - The file descriptor to close
    fn close_restricted(&mut self, fd: RawFd);
}

unsafe extern "C" fn open_restricted<I: LibinputInterface + 'static>(path: *const libc::c_char,
                                                                    flags: libc::c_int,
                                                                    user_data: *mut libc::c_void)
                                                                    -> libc::c_int
{
    use std::borrow::Cow;

    if let Some(ref mut interface) = (user_data as *mut I).as_mut() {
        let path_str = CStr::from_ptr(path).to_string_lossy();
        let res = match path_str {
            Cow::Borrowed(string) => interface.open_restricted(Path::new(string), flags),
            Cow::Owned(string) => interface.open_restricted(Path::new(&string), flags),
        };
        match res {
            Ok(fd) => fd,
            Err(errno) => if errno > 0 { -errno } else { errno },
        }
    } else { -1 }
}

unsafe extern "C" fn close_restricted<I: LibinputInterface + 'static>(fd: libc::c_int, user_data: *mut libc::c_void)
{
    if let Some(ref mut interface) = (user_data as *mut I).as_mut() {
        interface.close_restricted(fd)
    }
}

/// Libinput context
///
/// Contexts can be used to track input devices and receive events from them.
/// You can use either `new_from_udev` to create a context tracking all devices on a specific seat,
/// or use `new_from_path` to track input devices manually.
///
/// Either way you then have to use `dispatch()` and `next()` (provided by the `Iterator` trait) to
/// receive events.
#[derive(Eq)]
pub struct Libinput
{
    ffi: *mut ffi::libinput,
}

impl ::std::fmt::Debug for Libinput {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "Libinput @{:p}", self.as_raw())
    }
}

impl FromRaw<ffi::libinput> for Libinput
{
    unsafe fn from_raw(ffi: *mut ffi::libinput) -> Self {
        Libinput {
            ffi: ffi::libinput_ref(ffi),
        }
    }
}

impl AsRaw<ffi::libinput> for Libinput
{
    fn as_raw(&self) -> *const ffi::libinput {
        self.ffi as *const _
    }
}

impl Clone for Libinput {
    fn clone(&self) -> Self {
        unsafe { Libinput::from_raw(self.as_raw_mut()) }
    }
}

impl Drop for Libinput
{
    fn drop(&mut self) {
        unsafe {
            let userdata_ref = ffi::libinput_get_user_data(self.as_raw_mut());
            if ffi::libinput_unref(self.ffi).is_null() {
                let _ = Box::from_raw(userdata_ref);
            }
        }
    }
}

impl PartialEq for Libinput {
    fn eq(&self, other: &Self) -> bool {
        self.as_raw() == other.as_raw()
    }
}

impl ::std::hash::Hash for Libinput {
    fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
        self.as_raw().hash(state);
    }
}

impl Iterator for Libinput {
    type Item = Event;
    fn next(&mut self) -> Option<Self::Item> {
        let ptr = unsafe { ffi::libinput_get_event(self.as_raw_mut()) };
        if ptr.is_null() {
            None
        } else {
            unsafe { Some(Event::from_raw(ptr)) }
        }
    }
}

impl Libinput {
    /// Create a new libinput context using a udev context.
    ///
    /// This context is inactive until `udev_assign_seat` is called.
    ///
    /// ## Arguments
    ///
    /// - interface - A `LibinputInterface` providing functions to open and close devices.
    /// - userdata - Optionally some userdata attached to the newly created context (see [`Userdata`](./trait.Userdata.html))
    /// - udev_context - Raw pointer to a valid udev context.
    ///
    /// ## Unsafety
    ///
    /// This function is unsafe, because there is no way to verify that `udev_context` is indeed a valid udev context or even points to valid memory.
    #[cfg(feature = "udev")]
    pub fn new_from_udev<I: LibinputInterface + 'static>(interface: I,
                                                         udev_context: &UdevContext)
                                                         -> Libinput
    {
        let mut boxed_userdata = Box::new(interface);
        let boxed_interface = Box::new(ffi::libinput_interface {
            open_restricted: Some(open_restricted::<I>),
            close_restricted: Some(close_restricted::<I>),
        });

        let context = Libinput {
            ffi: unsafe {
                ffi::libinput_udev_create_context(&*boxed_interface as *const _,
                                                  &mut *boxed_userdata as *mut I as *mut libc::c_void,
                                                  udev_context.as_raw() as *mut _)
            },
        };

        mem::forget(boxed_interface);
        mem::forget(boxed_userdata);

        context
    }

    /// Create a new libinput context that requires the caller to manually add or remove devices.
    ///
    /// The returned context is active, but will not yield any events
    /// until at least one device is added.
    ///
    /// Devices can be added and removed by calling `path_add_device` and `path_remove_device` respectively.
    ///
    /// ## Arguments
    ///
    /// - interface - A `LibinputInterface` providing functions to open and close devices.
    /// - userdata - Optionally some userdata attached to the newly created context (see [`Userdata`](./trait.Userdata.html))
    ///
    pub fn new_from_path<I: 'static + LibinputInterface>(interface: I) -> Libinput {
        let mut boxed_userdata = Box::new(interface);
        let boxed_interface = Box::new(ffi::libinput_interface {
            open_restricted: Some(open_restricted::<I>),
            close_restricted: Some(close_restricted::<I>),
        });

        let context = Libinput {
            ffi: unsafe {
                ffi::libinput_path_create_context(&*boxed_interface as *const _,
                                                  &mut *boxed_userdata as *mut I as *mut libc::c_void)
            },
        };

        mem::forget(boxed_interface);
        mem::forget(boxed_userdata);

        context
    }

    /// Add a device to a libinput context initialized with
    /// `new_from_context`.
    ///
    /// If successful, the device will be added to the internal list
    /// and re-opened on `resume`. The device can be removed with
    /// `path_remove_device()`.
    ///
    /// If the device was successfully initialized, it is returned.
    ///
    /// ## Warning
    ///
    /// It is an application bug to call this function on a context
    /// initialized with `new_from_udev`.
    pub fn path_add_device(&mut self, path: &str) -> Option<Device> {
        let path = CString::new(path).expect("Device Path contained a null-byte");
        unsafe {
            let ptr = ffi::libinput_path_add_device(self.as_raw_mut(), path.as_ptr());
            if ptr.is_null() {
                None
            } else {
                Some(Device::from_raw(ptr))
            }
        }
    }

    /// Remove a device from a libinput context initialized with
    /// `new_from_path` and added to such a context with
    /// `path_add_device`.
    ///
    /// Events already processed from this input device are kept in
    /// the queue, the `DeviceRemovedEvent` event marks the end of
    /// events for this device.
    ///
    /// ## Warning
    ///
    /// It is an application bug to call this function on a context
    /// initialized with `new_from_udev`.
    pub fn path_remove_device(&mut self, device: Device) {
        unsafe { ffi::libinput_path_remove_device(device.as_raw_mut()) }
    }

    /// Assign a seat to this libinput context.
    ///
    /// New devices or the removal of existing devices will appear as
    /// events during `dispatch`.
    ///
    /// `udev_assign_seat` succeeds even if no input devices are
    /// currently available on this seat, or if devices are available
    /// but fail to open in `LibinputInterface::open_restricted`.
    ///
    /// Devices that do not have the minimum capabilities to be
    /// recognized as pointer, keyboard or touch device are ignored. /// Such devices and those that failed to open ignored until the
    /// next call to `resume`.
    ///
    /// ## Warning
    ///
    /// This function may only be called once per context.
    #[cfg(feature = "udev")]
    pub fn udev_assign_seat(&mut self, seat_id: &str) -> Result<(), ()> {
        let id = CString::new(seat_id).expect("Seat Id contained a null-byte");
        unsafe {
            match ffi::libinput_udev_assign_seat(self.as_raw_mut(), id.as_ptr()) {
                0 => Ok(()),
                -1 => Err(()),
                _ => unreachable!(),
            }
        }
    }

    ffi_func!(
    /// Suspend monitoring for new devices and close existing
    /// devices.
    ///
    /// This closes all open devices and terminates libinput but
    /// does keep the context valid to be resumed with `resume`.
    pub fn suspend, ffi::libinput_suspend, ());

    /// Resume a suspended libinput context.
    ///
    /// This re-enables device monitoring and adds existing devices.
    pub fn resume(&mut self) -> Result<(), ()> {
        unsafe {
            match ffi::libinput_resume(self.as_raw_mut()) {
                0 => Ok(()),
                -1 => Err(()),
                _ => unreachable!(),
            }
        }
    }

    /// Main event dispatchment function.
    ///
    /// Reads events of the file descriptors and processes them
    /// internally. Use `next` or any other function provided by the
    /// `Iterator` trait to retrieve the events until `None` is
    /// returned.
    ///
    /// Dispatching does not necessarily queue libinput events. This
    /// function should be called immediately once data is available
    /// on the file descriptor returned by `fd`. libinput has a number
    /// of timing-sensitive features (e.g. tap-to-click), any delay in
    /// calling `dispatch` may prevent these features from working
    /// correctly.
    pub fn dispatch(&mut self) -> IoResult<()> {
        unsafe {
            match ffi::libinput_dispatch(self.as_raw_mut()) {
                0 => Ok(()),
                x if x < 0 => Err(IoError::from_raw_os_error(x)),
                _ => unreachable!(),
            }
        }
    }

    /// libinput keeps a single file descriptor for all events.
    ///
    /// Call into `dispatch` if any events become available on this fd.
    ///
    /// The most simple variant to check for available bytes is to use
    /// the `libc`:
    ///
    ///     loop {
    ///         let mut count = 0i32;
    ///         libc::ioctl(context.fd(), libc::FIONREAD, &mut count);
    ///         if (count > 0) {
    ///             context.dispatch().unwrap();
    ///             for event in context {
    ///                 // do some processing...
    ///             }
    ///         }
    ///     }
    ///
    /// For more complex operations you may wish to use other approches
    /// as event loops e.g. in the `wayland-server` or the `tokio`
    /// crates to wait for data to become available on this file
    /// descriptor.
    pub unsafe fn fd(&self) -> RawFd {
        ffi::libinput_get_fd(self.as_raw_mut())
    }
}
<|endoftext|>


<commit_before>use std::thread::{self, Thread};
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use std::collections::VecDeque;
use std::time::Duration;
use std::fs;
use modular_flow::graph::*;
use modular_flow::context::Context;
use plugin_loader::{self, NodeLibrary};

pub struct Instance {
    pub ctx: Arc<Context>,
    pub nodes: NodeInstances,
    pub types: NodeDescriptors,
}

impl Instance {
    pub fn new() -> Instance {
        Instance {
            ctx: Arc::new(Context::new(Graph::new())),
            nodes: NodeInstances::new(),
            types: NodeDescriptors::new(),
        }
    }
    pub fn load_lib(&self, path: &str) {
        {
            let libs = self.types.libs();
            let old_lib = libs.iter().find(|lib| lib.path == path);
            if let Some(old_lib) = old_lib {
                for node in self.nodes.nodes() {
                    if old_lib.nodes.iter().find(|desc| desc.name == node.type_name).is_some() {
                        self.stop_node(node.ctl.node().id()).unwrap();
                    }
                }
            }
        }
        let lib = self.types.load_library(path).unwrap();
        for node in self.nodes.nodes() {
            if let Some(node_desc) = lib.nodes.iter().find(|desc| desc.name == node.type_name) {
                self.nodes.remove(node.ctl.node().id());
                let ctl = (node_desc.new)(self.ctx.clone(), NewNodeConfig { node: Some(node.ctl.node().id()) });
                self.nodes.insert(NodeInstance {
                    ctl,
                    type_name: node.type_name.clone(),
                });
            }
        }
    }
    pub fn kill_node(&self, id: NodeID) -> Result<()> {
        self.stop_node(id)?;
        self.ctx
            .graph()
            .remove_node(id)?;
        self.nodes.remove(id);
        Ok(())
    }
    pub fn stop_node(&self, id: NodeID) -> Result<Arc<NodeInstance>> {
        let node = self.nodes.node(id).ok_or(Error::InvalidNode)?;
        node.ctl.stop();
        node.ctl.node().subscribe();
        while node.ctl.node().attached() {
            node.ctl.node().notify();
            thread::sleep(Duration::from_millis(25));
        }
        node.ctl.node().unsubscribe();
        node.ctl.node().flush()?;
        Ok(node)
    }
}

#[derive(Clone)]
pub struct NodeInstance {
    pub ctl: Arc<RemoteControl>,
    pub type_name: String,
}

pub struct NodeInstances {
    list: Mutex<Vec<Arc<NodeInstance>>>,
}

impl NodeInstances {
    pub fn new() -> NodeInstances {
        NodeInstances {
            list: Mutex::new(Vec::new()),
        }
    }
    pub fn insert(&self, inst: NodeInstance) {
        self.list.lock().unwrap().push(Arc::new(inst));
    }
    pub fn remove(&self, id: NodeID) {
        self.list.lock().unwrap().retain(|node| node.ctl.node().id() != id);
    }
    pub fn node(&self, id: NodeID) -> Option<Arc<NodeInstance>> {
        self.list.lock().unwrap().iter().cloned().find(|node| node.ctl.node().id() == id)
    }
    pub fn nodes(&self) -> Vec<Arc<NodeInstance>> {
        self.list.lock().unwrap().clone()
    }
}

pub struct NewNodeConfig {
    pub node: Option<NodeID>, // node id to attach to
}

#[derive(Clone)]
pub struct NodeDescriptor {
    pub name: String,
    pub new: Arc<Fn(Arc<Context>, NewNodeConfig) -> Arc<RemoteControl> + Send + Sync + 'static>,
}

impl NodeDescriptor {
    pub fn new<S: Into<String>, F: Fn(Arc<Context>, NewNodeConfig) -> Arc<RemoteControl> + Send + Sync + 'static>(name: S, new: F) -> NodeDescriptor {
        NodeDescriptor {
            name: name.into(),
            new: Arc::new(new),
        }
    }
}

pub struct NodeDescriptors {
    load_count: AtomicUsize,
    libs: Mutex<Vec<Arc<NodeLibrary>>>,
    old_libs: Mutex<Vec<Arc<NodeLibrary>>>,
}

impl NodeDescriptors {
    pub fn new() -> NodeDescriptors {
        NodeDescriptors {
            load_count: AtomicUsize::new(0),
            libs: Mutex::new(vec![]),
            old_libs: Mutex::new(vec![]),
        }
    }
    pub fn libs(&self) -> Vec<Arc<NodeLibrary>> {
        self.libs.lock().unwrap().clone()
    }
    /// Replaces existing library with the same path if it exists
    pub fn load_library(&self, path: &str) -> plugin_loader::Result<Arc<NodeLibrary>> {
        let mut libs = self.libs.lock().unwrap();
        let new_path = path.to_string() + &usize::to_string(&self.load_count.fetch_add(1, Ordering::SeqCst));
        fs::copy(path, &new_path).unwrap();
        let new_lib = Arc::new(NodeLibrary::load(path, &new_path)?);
        if let Some(old_lib_idx) = libs.iter_mut().position(|lib| lib.path == path) {
            let old_lib = libs.swap_remove(old_lib_idx);
            self.old_libs.lock().unwrap().push(old_lib);
            //fs::remove_file(&old_lib.file_path).unwrap();
        }
        libs.push(new_lib.clone());
        Ok(new_lib)
    }
    pub fn node(&self, name: &str) -> Option<NodeDescriptor> {
        self.nodes().iter().cloned().find(|node| node.name == name)
    }
    pub fn nodes(&self) -> Vec<NodeDescriptor> {
        self.libs.lock().unwrap().iter().flat_map(|lib| lib.nodes.clone()).collect()
    }
}

pub mod message {
    #[derive(Clone, Debug)]
    pub enum Type {
        Bool,
        Int,
        Float,
        String,
    }
    #[derive(Clone, Debug)]
    pub enum Value {
        Bool(bool),
        Int(i64),
        Float(f64),
        String(String),
    }
    #[derive(Clone, Debug)]
    pub struct ArgDesc {
        pub name: String,
        pub ty: Type,
    }
    #[derive(Clone, Debug)]
    pub struct Desc {
        pub name: String,
        pub args: Vec<ArgDesc>,
    }
    #[derive(Clone, Debug)]
    pub struct Message {
        pub desc: Desc,
        pub args: Vec<Value>,
    }
}

pub struct RemoteControl {
    ctx: Arc<Context>,
    node: Arc<Node>,
    stop_thread: Mutex<Option<Thread>>,
    stopped: AtomicBool,
    messages: Vec<message::Desc>,
    msg_queue: Mutex<VecDeque<message::Message>>,
}
impl RemoteControl {
    pub fn new(ctx: Arc<Context>, node: Arc<Node>, messages: Vec<message::Desc>) -> RemoteControl {
        RemoteControl {
            ctx,
            node,
            stop_thread: Mutex::new(None),
            stopped: AtomicBool::new(false),
            messages,
            msg_queue: Mutex::new(VecDeque::new()),
        }
    }
    pub fn message_descriptors(&self) -> &[message::Desc] {
        &self.messages
    }
    pub fn send_message(&self, msg: message::Message) {
        self.msg_queue.lock().unwrap().push_back(msg);
        self.node.set_aborting(true);
        self.node.notify();
    }
    pub fn recv_message(&self) -> Option<message::Message> {
        self.msg_queue.lock().unwrap().pop_front()
    }
    /// dangerous, assumes only one thread!! FIXME
    pub fn block_until_stopped(&self) {
        *self.stop_thread.lock().unwrap() = Some(thread::current());
        while !self.stopped.load(Ordering::Acquire) {
            thread::park();
        }
    }
    pub fn stop(&self) {
        self.node.set_aborting(true);
        self.stopped.store(true, Ordering::Release);
        self.stop_thread.lock().unwrap().as_ref().map(|thread| thread.unpark());
    }
    pub fn stopped(&self) -> bool {
        self.stopped.load(Ordering::Acquire)
    }
    pub fn node(&self) -> &Node {
        &*self.node
    }
    pub fn context(&self) -> Arc<Context> {
        self.ctx.clone()
    }
}
<commit_msg>fix deadlocks<commit_after>use std::thread::{self, Thread};
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use std::collections::VecDeque;
use std::time::Duration;
use std::fs;
use modular_flow::graph::*;
use modular_flow::context::Context;
use plugin_loader::{self, NodeLibrary};

pub struct Instance {
    pub ctx: Arc<Context>,
    pub nodes: NodeInstances,
    pub types: NodeDescriptors,
}

impl Instance {
    pub fn new() -> Instance {
        Instance {
            ctx: Arc::new(Context::new(Graph::new())),
            nodes: NodeInstances::new(),
            types: NodeDescriptors::new(),
        }
    }
    pub fn load_lib(&self, path: &str) {
        {
            let libs = self.types.libs();
            let old_lib = libs.iter().find(|lib| lib.path == path);
            if let Some(old_lib) = old_lib {
                for node in self.nodes.nodes() {
                    if old_lib.nodes.iter().find(|desc| desc.name == node.type_name).is_some() {
                        println!("try stop {} {:?}", node.type_name, node.ctl.node().id());
                        self.stop_node(node.ctl.node().id()).unwrap();
                        println!("stopped {} {:?}", node.type_name, node.ctl.node().id());
                    }
                }
            }
        }
        let lib = self.types.load_library(path).unwrap();
        for node in self.nodes.nodes() {
            if let Some(node_desc) = lib.nodes.iter().find(|desc| desc.name == node.type_name) {
                self.nodes.remove(node.ctl.node().id());
                let ctl = (node_desc.new)(self.ctx.clone(), NewNodeConfig { node: Some(node.ctl.node().id()) });
                self.nodes.insert(NodeInstance {
                    ctl,
                    type_name: node.type_name.clone(),
                });
            }
        }
    }
    pub fn kill_node(&self, id: NodeID) -> Result<()> {
        self.stop_node(id)?;
        self.ctx
            .graph()
            .remove_node(id)?;
        self.nodes.remove(id);
        Ok(())
    }
    pub fn stop_node(&self, id: NodeID) -> Result<Arc<NodeInstance>> {
        let node = self.nodes.node(id).ok_or(Error::InvalidNode)?;
        node.ctl.stop();
        while node.ctl.node().attached() {
            node.ctl.node().notify(&*self.ctx.graph());
            thread::sleep(Duration::from_millis(25));
        }
        node.ctl.node().flush(&*self.ctx.graph())?;
        Ok(node)
    }
}

#[derive(Clone)]
pub struct NodeInstance {
    pub ctl: Arc<RemoteControl>,
    pub type_name: String,
}

pub struct NodeInstances {
    list: Mutex<Vec<Arc<NodeInstance>>>,
}

impl NodeInstances {
    pub fn new() -> NodeInstances {
        NodeInstances {
            list: Mutex::new(Vec::new()),
        }
    }
    pub fn insert(&self, inst: NodeInstance) {
        self.list.lock().unwrap().push(Arc::new(inst));
    }
    pub fn remove(&self, id: NodeID) {
        self.list.lock().unwrap().retain(|node| node.ctl.node().id() != id);
    }
    pub fn node(&self, id: NodeID) -> Option<Arc<NodeInstance>> {
        self.list.lock().unwrap().iter().cloned().find(|node| node.ctl.node().id() == id)
    }
    pub fn nodes(&self) -> Vec<Arc<NodeInstance>> {
        self.list.lock().unwrap().clone()
    }
}

pub struct NewNodeConfig {
    pub node: Option<NodeID>, // node id to attach to
}

#[derive(Clone)]
pub struct NodeDescriptor {
    pub name: String,
    pub new: Arc<Fn(Arc<Context>, NewNodeConfig) -> Arc<RemoteControl> + Send + Sync + 'static>,
}

impl NodeDescriptor {
    pub fn new<S: Into<String>, F: Fn(Arc<Context>, NewNodeConfig) -> Arc<RemoteControl> + Send + Sync + 'static>(name: S, new: F) -> NodeDescriptor {
        NodeDescriptor {
            name: name.into(),
            new: Arc::new(new),
        }
    }
}

pub struct NodeDescriptors {
    load_count: AtomicUsize,
    libs: Mutex<Vec<Arc<NodeLibrary>>>,
    old_libs: Mutex<Vec<Arc<NodeLibrary>>>,
}

impl NodeDescriptors {
    pub fn new() -> NodeDescriptors {
        NodeDescriptors {
            load_count: AtomicUsize::new(0),
            libs: Mutex::new(vec![]),
            old_libs: Mutex::new(vec![]),
        }
    }
    pub fn libs(&self) -> Vec<Arc<NodeLibrary>> {
        self.libs.lock().unwrap().clone()
    }
    /// Replaces existing library with the same path if it exists
    pub fn load_library(&self, path: &str) -> plugin_loader::Result<Arc<NodeLibrary>> {
        let mut libs = self.libs.lock().unwrap();
        let new_path = path.to_string() + &usize::to_string(&self.load_count.fetch_add(1, Ordering::SeqCst));
        fs::copy(path, &new_path).unwrap();
        let new_lib = Arc::new(NodeLibrary::load(path, &new_path)?);
        if let Some(old_lib_idx) = libs.iter_mut().position(|lib| lib.path == path) {
            let old_lib = libs.swap_remove(old_lib_idx);
            self.old_libs.lock().unwrap().push(old_lib);
            //fs::remove_file(&old_lib.file_path).unwrap();
        }
        libs.push(new_lib.clone());
        Ok(new_lib)
    }
    pub fn node(&self, name: &str) -> Option<NodeDescriptor> {
        self.nodes().iter().cloned().find(|node| node.name == name)
    }
    pub fn nodes(&self) -> Vec<NodeDescriptor> {
        self.libs.lock().unwrap().iter().flat_map(|lib| lib.nodes.clone()).collect()
    }
}

pub mod message {
    #[derive(Clone, Debug)]
    pub enum Type {
        Bool,
        Int,
        Float,
        String,
    }
    #[derive(Clone, Debug)]
    pub enum Value {
        Bool(bool),
        Int(i64),
        Float(f64),
        String(String),
    }
    #[derive(Clone, Debug)]
    pub struct ArgDesc {
        pub name: String,
        pub ty: Type,
    }
    #[derive(Clone, Debug)]
    pub struct Desc {
        pub name: String,
        pub args: Vec<ArgDesc>,
    }
    #[derive(Clone, Debug)]
    pub struct Message {
        pub desc: Desc,
        pub args: Vec<Value>,
    }
}

pub struct RemoteControl {
    ctx: Arc<Context>,
    node: Arc<Node>,
    stop_thread: Mutex<Option<Thread>>,
    stopped: AtomicBool,
    messages: Vec<message::Desc>,
    msg_queue: Mutex<VecDeque<message::Message>>,
}
impl RemoteControl {
    pub fn new(ctx: Arc<Context>, node: Arc<Node>, messages: Vec<message::Desc>) -> RemoteControl {
        RemoteControl {
            ctx,
            node,
            stop_thread: Mutex::new(None),
            stopped: AtomicBool::new(false),
            messages,
            msg_queue: Mutex::new(VecDeque::new()),
        }
    }
    pub fn message_descriptors(&self) -> &[message::Desc] {
        &self.messages
    }
    pub fn send_message(&self, msg: message::Message) {
        self.msg_queue.lock().unwrap().push_back(msg);
        self.node.set_aborting(true, self.ctx.graph());
        self.node.notify(self.ctx.graph());
    }
    pub fn recv_message(&self) -> Option<message::Message> {
        self.msg_queue.lock().unwrap().pop_front()
    }
    /// dangerous, assumes only one thread!! FIXME
    pub fn block_until_stopped(&self) {
        *self.stop_thread.lock().unwrap() = Some(thread::current());
        while !self.stopped.load(Ordering::Acquire) {
            thread::park();
        }
    }
    pub fn stop(&self) {
        self.node.set_aborting(true, &*self.ctx.graph());
        self.stopped.store(true, Ordering::Release);
        self.stop_thread.lock().unwrap().as_ref().map(|thread| thread.unpark());
    }
    pub fn stopped(&self) -> bool {
        self.stopped.load(Ordering::Acquire)
    }
    pub fn node(&self) -> &Node {
        &*self.node
    }
    pub fn context(&self) -> Arc<Context> {
        self.ctx.clone()
    }
}
<|endoftext|>


<commit_before>#![crate_name = "uu_fmt"]
#![feature(str_char, unicode)]

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

extern crate getopts;
extern crate rustc_unicode;
extern crate unicode_width;

#[macro_use]
extern crate uucore;

use std::cmp;
use std::io::{Read, BufReader, BufWriter};
use std::fs::File;
use std::io::{stdin, stdout, Write};
use linebreak::break_lines;
use parasplit::ParagraphStream;

macro_rules! silent_unwrap(
    ($exp:expr) => (
        match $exp {
            Ok(_) => (),
            Err(_) => ::std::process::exit(1),
        }
    )
);

mod linebreak;
mod parasplit;

// program's NAME and VERSION are used for -V and -h
static NAME: &'static str = "fmt";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

pub type FileOrStdReader = BufReader<Box<Read+'static>>;
pub struct FmtOptions {
    crown           : bool,
    tagged          : bool,
    mail            : bool,
    split_only      : bool,
    use_prefix      : bool,
    prefix          : String,
    xprefix         : bool,
    use_anti_prefix : bool,
    anti_prefix     : String,
    xanti_prefix    : bool,
    uniform         : bool,
    quick           : bool,
    width           : usize,
    goal            : usize,
    tabwidth        : usize,
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = getopts::Options::new();

    opts.optflag("c", "crown-margin", "First and second line of paragraph may have different indentations, in which case the first line's indentation is preserved, and each subsequent line's indentation matches the second line.");
    opts.optflag("t", "tagged-paragraph", "Like -c, except that the first and second line of a paragraph *must* have different indentation or they are treated as separate paragraphs.");
    opts.optflag("m", "preserve-headers", "Attempt to detect and preserve mail headers in the input. Be careful when combining this flag with -p.");
    opts.optflag("s", "split-only", "Split lines only, do not reflow.");
    opts.optflag("u", "uniform-spacing", "Insert exactly one space between words, and two between sentences. Sentence breaks in the input are detected as [?!.] followed by two spaces or a newline; other punctuation is not interpreted as a sentence break.");

    opts.optopt("p", "prefix", "Reformat only lines beginning with PREFIX, reattaching PREFIX to reformatted lines. Unless -x is specified, leading whitespace will be ignored when matching PREFIX.", "PREFIX");
    opts.optopt("P", "skip-prefix", "Do not reformat lines beginning with PSKIP. Unless -X is specified, leading whitespace will be ignored when matching PSKIP", "PSKIP");

    opts.optflag("x", "exact-prefix", "PREFIX must match at the beginning of the line with no preceding whitespace.");
    opts.optflag("X", "exact-skip-prefix", "PSKIP must match at the beginning of the line with no preceding whitespace.");

    opts.optopt("w", "width", "Fill output lines up to a maximum of WIDTH columns, default 79.", "WIDTH");
    opts.optopt("g", "goal", "Goal width, default ~0.94*WIDTH. Must be less than WIDTH.", "GOAL");

    opts.optflag("q", "quick", "Break lines more quickly at the expense of a potentially more ragged appearance.");

    opts.optopt("T", "tab-width", "Treat tabs as TABWIDTH spaces for determining line length, default 8. Note that this is used only for calculating line lengths; tabs are preserved in the output.", "TABWIDTH");

    opts.optflag("V", "version", "Output version information and exit.");
    opts.optflag("h", "help", "Display this help message and exit.");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "{}\nTry `{} --help' for more information.", f, NAME)
    };

    if matches.opt_present("h") {
        println!("Usage: {} [OPTION]... [FILE]...\n\n{}", NAME, opts.usage("Reformat paragraphs from input files (or stdin) to stdout."));
    }

    if matches.opt_present("V") || matches.opt_present("h") {
        println!("{} {}", NAME, VERSION);
        return 0
    }

    let mut fmt_opts = FmtOptions {
        crown           : false,
        tagged          : false,
        mail            : false,
        uniform         : false,
        quick           : false,
        split_only      : false,
        use_prefix      : false,
        prefix          : String::new(),
        xprefix         : false,
        use_anti_prefix : false,
        anti_prefix     : String::new(),
        xanti_prefix    : false,
        width           : 79,
        goal            : 74,
        tabwidth        : 8,
    };

    if matches.opt_present("t") { fmt_opts.tagged       = true; }
    if matches.opt_present("c") { fmt_opts.crown        = true; fmt_opts.tagged = false; }
    if matches.opt_present("m") { fmt_opts.mail         = true; }
    if matches.opt_present("u") { fmt_opts.uniform      = true; }
    if matches.opt_present("q") { fmt_opts.quick        = true; }
    if matches.opt_present("s") { fmt_opts.split_only   = true; fmt_opts.crown  = false; fmt_opts.tagged = false; }
    if matches.opt_present("x") { fmt_opts.xprefix      = true; }
    if matches.opt_present("X") { fmt_opts.xanti_prefix = true; }

    match matches.opt_str("p") {
        Some(s) => {
            fmt_opts.prefix = s;
            fmt_opts.use_prefix = true;
        }
        None => ()
    };

    match matches.opt_str("P") {
        Some(s) => {
            fmt_opts.anti_prefix = s;
            fmt_opts.use_anti_prefix = true;
        }
        None => ()
    };

    match matches.opt_str("w") {
        Some(s) => {
            fmt_opts.width =
                match s.parse::<usize>() {
                    Ok(t) => t,
                    Err(e) => { crash!(1, "Invalid WIDTH specification: `{}': {}", s, e); }
                };
            fmt_opts.goal = cmp::min(fmt_opts.width * 94 / 100, fmt_opts.width - 3);
        }
        None => ()
    };

    match matches.opt_str("g") {
        Some(s) => {
            fmt_opts.goal =
                match s.parse::<usize>() {
                    Ok(t) => t,
                    Err(e) => { crash!(1, "Invalid GOAL specification: `{}': {}", s, e); }
                };
            if !matches.opt_present("w") {
                fmt_opts.width = cmp::max(fmt_opts.goal * 100 / 94, fmt_opts.goal + 3);
            } else if fmt_opts.goal > fmt_opts.width {
                crash!(1, "GOAL cannot be greater than WIDTH.");
            }
        }
        None => ()
    };

    match matches.opt_str("T") {
        Some(s) => {
            fmt_opts.tabwidth =
                match s.parse::<usize>() {
                    Ok(t) => t,
                    Err(e) => { crash!(1, "Invalid TABWIDTH specification: `{}': {}", s, e); }
                };
        }
        None => ()
    };

    if fmt_opts.tabwidth < 1 {
        fmt_opts.tabwidth = 1;
    }

    // immutable now
    let fmt_opts = fmt_opts;

    let mut files = matches.free;
    if files.is_empty() {
        files.push("-".to_owned());
    }

    let mut ostream = BufWriter::new(stdout());

    for i in files.iter().map(|x| &x[..]) {
        let mut fp = match i {
            "-" => BufReader::new(Box::new(stdin()) as Box<Read+'static>),
            _ => match File::open(i) {
                Ok(f) => BufReader::new(Box::new(f) as Box<Read+'static>),
                Err(e) => {
                    show_warning!("{}: {}", i, e);
                    continue;
                },
            },
        };
        let p_stream = ParagraphStream::new(&fmt_opts, &mut fp);
        for para_result in p_stream {
            match para_result {
                Err(s) => silent_unwrap!(ostream.write_all(s.as_bytes())),
                Ok(para) => break_lines(&para, &fmt_opts, &mut ostream)
            }
        }

        // flush the output after each file
        silent_unwrap!(ostream.flush());
    }

    0
}
<commit_msg>Remove rustc_unicode dependency<commit_after>#![crate_name = "uu_fmt"]
#![feature(str_char)]

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

extern crate getopts;
extern crate unicode_width;

#[macro_use]
extern crate uucore;

use std::cmp;
use std::io::{Read, BufReader, BufWriter};
use std::fs::File;
use std::io::{stdin, stdout, Write};
use linebreak::break_lines;
use parasplit::ParagraphStream;

macro_rules! silent_unwrap(
    ($exp:expr) => (
        match $exp {
            Ok(_) => (),
            Err(_) => ::std::process::exit(1),
        }
    )
);

mod linebreak;
mod parasplit;

// program's NAME and VERSION are used for -V and -h
static NAME: &'static str = "fmt";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

pub type FileOrStdReader = BufReader<Box<Read+'static>>;
pub struct FmtOptions {
    crown           : bool,
    tagged          : bool,
    mail            : bool,
    split_only      : bool,
    use_prefix      : bool,
    prefix          : String,
    xprefix         : bool,
    use_anti_prefix : bool,
    anti_prefix     : String,
    xanti_prefix    : bool,
    uniform         : bool,
    quick           : bool,
    width           : usize,
    goal            : usize,
    tabwidth        : usize,
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = getopts::Options::new();

    opts.optflag("c", "crown-margin", "First and second line of paragraph may have different indentations, in which case the first line's indentation is preserved, and each subsequent line's indentation matches the second line.");
    opts.optflag("t", "tagged-paragraph", "Like -c, except that the first and second line of a paragraph *must* have different indentation or they are treated as separate paragraphs.");
    opts.optflag("m", "preserve-headers", "Attempt to detect and preserve mail headers in the input. Be careful when combining this flag with -p.");
    opts.optflag("s", "split-only", "Split lines only, do not reflow.");
    opts.optflag("u", "uniform-spacing", "Insert exactly one space between words, and two between sentences. Sentence breaks in the input are detected as [?!.] followed by two spaces or a newline; other punctuation is not interpreted as a sentence break.");

    opts.optopt("p", "prefix", "Reformat only lines beginning with PREFIX, reattaching PREFIX to reformatted lines. Unless -x is specified, leading whitespace will be ignored when matching PREFIX.", "PREFIX");
    opts.optopt("P", "skip-prefix", "Do not reformat lines beginning with PSKIP. Unless -X is specified, leading whitespace will be ignored when matching PSKIP", "PSKIP");

    opts.optflag("x", "exact-prefix", "PREFIX must match at the beginning of the line with no preceding whitespace.");
    opts.optflag("X", "exact-skip-prefix", "PSKIP must match at the beginning of the line with no preceding whitespace.");

    opts.optopt("w", "width", "Fill output lines up to a maximum of WIDTH columns, default 79.", "WIDTH");
    opts.optopt("g", "goal", "Goal width, default ~0.94*WIDTH. Must be less than WIDTH.", "GOAL");

    opts.optflag("q", "quick", "Break lines more quickly at the expense of a potentially more ragged appearance.");

    opts.optopt("T", "tab-width", "Treat tabs as TABWIDTH spaces for determining line length, default 8. Note that this is used only for calculating line lengths; tabs are preserved in the output.", "TABWIDTH");

    opts.optflag("V", "version", "Output version information and exit.");
    opts.optflag("h", "help", "Display this help message and exit.");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "{}\nTry `{} --help' for more information.", f, NAME)
    };

    if matches.opt_present("h") {
        println!("Usage: {} [OPTION]... [FILE]...\n\n{}", NAME, opts.usage("Reformat paragraphs from input files (or stdin) to stdout."));
    }

    if matches.opt_present("V") || matches.opt_present("h") {
        println!("{} {}", NAME, VERSION);
        return 0
    }

    let mut fmt_opts = FmtOptions {
        crown           : false,
        tagged          : false,
        mail            : false,
        uniform         : false,
        quick           : false,
        split_only      : false,
        use_prefix      : false,
        prefix          : String::new(),
        xprefix         : false,
        use_anti_prefix : false,
        anti_prefix     : String::new(),
        xanti_prefix    : false,
        width           : 79,
        goal            : 74,
        tabwidth        : 8,
    };

    if matches.opt_present("t") { fmt_opts.tagged       = true; }
    if matches.opt_present("c") { fmt_opts.crown        = true; fmt_opts.tagged = false; }
    if matches.opt_present("m") { fmt_opts.mail         = true; }
    if matches.opt_present("u") { fmt_opts.uniform      = true; }
    if matches.opt_present("q") { fmt_opts.quick        = true; }
    if matches.opt_present("s") { fmt_opts.split_only   = true; fmt_opts.crown  = false; fmt_opts.tagged = false; }
    if matches.opt_present("x") { fmt_opts.xprefix      = true; }
    if matches.opt_present("X") { fmt_opts.xanti_prefix = true; }

    match matches.opt_str("p") {
        Some(s) => {
            fmt_opts.prefix = s;
            fmt_opts.use_prefix = true;
        }
        None => ()
    };

    match matches.opt_str("P") {
        Some(s) => {
            fmt_opts.anti_prefix = s;
            fmt_opts.use_anti_prefix = true;
        }
        None => ()
    };

    match matches.opt_str("w") {
        Some(s) => {
            fmt_opts.width =
                match s.parse::<usize>() {
                    Ok(t) => t,
                    Err(e) => { crash!(1, "Invalid WIDTH specification: `{}': {}", s, e); }
                };
            fmt_opts.goal = cmp::min(fmt_opts.width * 94 / 100, fmt_opts.width - 3);
        }
        None => ()
    };

    match matches.opt_str("g") {
        Some(s) => {
            fmt_opts.goal =
                match s.parse::<usize>() {
                    Ok(t) => t,
                    Err(e) => { crash!(1, "Invalid GOAL specification: `{}': {}", s, e); }
                };
            if !matches.opt_present("w") {
                fmt_opts.width = cmp::max(fmt_opts.goal * 100 / 94, fmt_opts.goal + 3);
            } else if fmt_opts.goal > fmt_opts.width {
                crash!(1, "GOAL cannot be greater than WIDTH.");
            }
        }
        None => ()
    };

    match matches.opt_str("T") {
        Some(s) => {
            fmt_opts.tabwidth =
                match s.parse::<usize>() {
                    Ok(t) => t,
                    Err(e) => { crash!(1, "Invalid TABWIDTH specification: `{}': {}", s, e); }
                };
        }
        None => ()
    };

    if fmt_opts.tabwidth < 1 {
        fmt_opts.tabwidth = 1;
    }

    // immutable now
    let fmt_opts = fmt_opts;

    let mut files = matches.free;
    if files.is_empty() {
        files.push("-".to_owned());
    }

    let mut ostream = BufWriter::new(stdout());

    for i in files.iter().map(|x| &x[..]) {
        let mut fp = match i {
            "-" => BufReader::new(Box::new(stdin()) as Box<Read+'static>),
            _ => match File::open(i) {
                Ok(f) => BufReader::new(Box::new(f) as Box<Read+'static>),
                Err(e) => {
                    show_warning!("{}: {}", i, e);
                    continue;
                },
            },
        };
        let p_stream = ParagraphStream::new(&fmt_opts, &mut fp);
        for para_result in p_stream {
            match para_result {
                Err(s) => silent_unwrap!(ostream.write_all(s.as_bytes())),
                Ok(para) => break_lines(&para, &fmt_opts, &mut ostream)
            }
        }

        // flush the output after each file
        silent_unwrap!(ostream.flush());
    }

    0
}
<|endoftext|>


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

/*!
HAL provides abstractions for specific MCU hardware.

Each peripheral in `hal` has a `xxxConf` struct that can be defined statically,
and each such struct has a `setup()` method that configures the hardware
(returning the object to interact with it where applicable).
*/

#[cfg(feature = "mcu_lpc11xx")]
pub mod lpc11xx;
#[cfg(feature = "mcu_lpc17xx")]
pub mod lpc17xx;
#[cfg(feature = "mcu_stm32f4")]
pub mod stm32f4;
#[cfg(feature = "mcu_stm32l1")]
pub mod stm32l1;
#[cfg(feature = "mcu_k20")]
pub mod k20;
#[cfg(feature = "mcu_tiva_c")]
pub mod tiva_c;

#[cfg(any(feature = "cpu_cortex-m3",
          feature = "cpu_cortex-m4"))]
mod cortex_common;
#[cfg(feature = "cpu_cortex-m3")]
pub mod cortex_m3;
#[cfg(feature = "cpu_cortex-m4")]
pub mod cortex_m4;

pub mod mem_init;
pub mod pin;
pub mod spi;
pub mod stack;
pub mod timer;
pub mod uart;

#[cfg(target_os = "none")]
pub mod isr;
<commit_msg>Remove feature guard from lpc11xx hal<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/*!
HAL provides abstractions for specific MCU hardware.

Each peripheral in `hal` has a `xxxConf` struct that can be defined statically,
and each such struct has a `setup()` method that configures the hardware
(returning the object to interact with it where applicable).
*/

pub mod lpc11xx;
#[cfg(feature = "mcu_lpc17xx")]
pub mod lpc17xx;
#[cfg(feature = "mcu_stm32f4")]
pub mod stm32f4;
#[cfg(feature = "mcu_stm32l1")]
pub mod stm32l1;
#[cfg(feature = "mcu_k20")]
pub mod k20;
#[cfg(feature = "mcu_tiva_c")]
pub mod tiva_c;

#[cfg(any(feature = "cpu_cortex-m3",
          feature = "cpu_cortex-m4"))]
mod cortex_common;
#[cfg(feature = "cpu_cortex-m3")]
pub mod cortex_m3;
#[cfg(feature = "cpu_cortex-m4")]
pub mod cortex_m4;

pub mod mem_init;
pub mod pin;
pub mod spi;
pub mod stack;
pub mod timer;
pub mod uart;

#[cfg(target_os = "none")]
pub mod isr;
<|endoftext|>