<commit_before>// re-export types that should only be used for testing
pub use lucet_runtime_internals::module::{HeapSpec, MockModuleBuilder};
#[allow(deprecated)]
pub use lucet_runtime_internals::vmctx::vmctx_from_mock_instance;

use lazy_static::lazy_static;
use lucet_runtime_internals::error::Error;
use lucet_runtime_internals::module::DlModule;
use std::env;
use std::path::{Path, PathBuf};
use std::sync::{Arc, RwLock};

lazy_static! {
    static ref EXCLUSIVE_TEST: RwLock<()> = RwLock::default();
}

/// Run a test non-exclusively with other `test_nonex` tests.
///
/// This function _must_ wrap any uses of `DlModule` or `Instance::run()`.
#[allow(dead_code)]
pub fn test_nonex<F, R>(f: F) -> R
where
    F: FnOnce() -> R,
{
    let lock = EXCLUSIVE_TEST.read().unwrap();
    let r = f();
    drop(lock);
    r
}

/// Run a test exclusively, so that no other `test_nonex` or `test_ex` tests will run concurrently.
///
/// This function _must_ wrap any tests that use `fork` or that set a custom `sigaction`.
#[allow(dead_code)]
pub fn test_ex<F, R>(f: F) -> R
where
    F: FnOnce() -> R,
{
    let lock = EXCLUSIVE_TEST.write().unwrap();
    let r = f();
    drop(lock);
    r
}
<commit_msg>lucet-runtime-tests: cleanup<commit_after>// re-export types that should only be used for testing
pub use lucet_runtime_internals::module::{HeapSpec, MockModuleBuilder};
#[allow(deprecated)]
pub use lucet_runtime_internals::vmctx::vmctx_from_mock_instance;

use lazy_static::lazy_static;
use std::sync::RwLock;

lazy_static! {
    static ref EXCLUSIVE_TEST: RwLock<()> = RwLock::default();
}

/// Run a test non-exclusively with other `test_nonex` tests.
///
/// This function _must_ wrap any uses of `DlModule` or `Instance::run()`.
#[allow(dead_code)]
pub fn test_nonex<F, R>(f: F) -> R
where
    F: FnOnce() -> R,
{
    let lock = EXCLUSIVE_TEST.read().unwrap();
    let r = f();
    drop(lock);
    r
}

/// Run a test exclusively, so that no other `test_nonex` or `test_ex` tests will run concurrently.
///
/// This function _must_ wrap any tests that use `fork` or that set a custom `sigaction`.
#[allow(dead_code)]
pub fn test_ex<F, R>(f: F) -> R
where
    F: FnOnce() -> R,
{
    let lock = EXCLUSIVE_TEST.write().unwrap();
    let r = f();
    drop(lock);
    r
}
<|endoftext|>


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

//! Structured representation of a plugin's features and capabilities.

use std::path::PathBuf;

use serde::Serialize;
use serde_json::{self, Value};

use crate::syntax::{LanguageDefinition, LanguageId};

/// Describes attributes and capabilities of a plugin.
///
/// Note: - these will eventually be loaded from manifest files.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct PluginDescription {
    pub name: String,
    pub version: String,
    #[serde(default)]
    pub scope: PluginScope,
    // more metadata ...
    /// path to plugin executable
    pub exec_path: PathBuf,
    /// Events that cause this plugin to run
    #[serde(default)]
    pub activations: Vec<PluginActivation>,
    #[serde(default)]
    pub commands: Vec<Command>,
    #[serde(default)]
    pub languages: Vec<LanguageDefinition>,
}

/// `PluginActivation`s represent events that trigger running a plugin.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PluginActivation {
    /// Always run this plugin, when available.
    Autorun,
    /// Run this plugin if the provided SyntaxDefinition is active.
    #[allow(dead_code)]
    OnSyntax(LanguageId),
    /// Run this plugin in response to a given command.
    #[allow(dead_code)]
    OnCommand,
}

/// Describes the scope of events a plugin receives.
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PluginScope {
    /// The plugin receives events from multiple buffers.
    Global,
    /// The plugin receives events for a single buffer.
    BufferLocal,
    /// The plugin is launched in response to a command, and receives no
    /// further updates.
    SingleInvocation,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
/// Represents a custom command provided by a plugin.
pub struct Command {
    /// Human readable title, for display in (for example) a menu.
    pub title: String,
    /// A short description of the command.
    pub description: String,
    /// Template of the command RPC as it should be sent to the plugin.
    pub rpc_cmd: PlaceholderRpc,
    /// A list of `CommandArgument`s, which the client should use to build the RPC.
    pub args: Vec<CommandArgument>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
/// A user provided argument to a plugin command.
pub struct CommandArgument {
    /// A human readable name for this argument, for use as placeholder
    /// text or equivelant.
    pub title: String,
    /// A short (single sentence) description of this argument's use.
    pub description: String,
    pub key: String,
    pub arg_type: ArgumentType,
    #[serde(skip_serializing_if = "Option::is_none")]
    /// If `arg_type` is `Choice`, `options` must contain a list of options.
    pub options: Option<Vec<ArgumentOption>>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum ArgumentType {
    Number,
    Int,
    PosInt,
    Bool,
    String,
    Choice,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
/// Represents an option for a user-selectable argument.
pub struct ArgumentOption {
    pub title: String,
    pub value: Value,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
/// A placeholder type which can represent a generic RPC.
///
/// This is the type used for custom plugin commands, which may have arbitrary
/// method names and parameters.
pub struct PlaceholderRpc {
    pub method: String,
    pub params: Value,
    pub rpc_type: RpcType,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum RpcType {
    Notification,
    Request,
}

impl Command {
    pub fn new<S, V>(title: S, description: S, rpc_cmd: PlaceholderRpc, args: V) -> Self
    where
        S: AsRef<str>,
        V: Into<Option<Vec<CommandArgument>>>,
    {
        let title = title.as_ref().to_owned();
        let description = description.as_ref().to_owned();
        let args = args.into().unwrap_or_else(Vec::new);
        Command { title, description, rpc_cmd, args }
    }
}

impl CommandArgument {
    pub fn new<S: AsRef<str>>(
        title: S,
        description: S,
        key: S,
        arg_type: ArgumentType,
        options: Option<Vec<ArgumentOption>>,
    ) -> Self {
        let key = key.as_ref().to_owned();
        let title = title.as_ref().to_owned();
        let description = description.as_ref().to_owned();
        if arg_type == ArgumentType::Choice {
            assert!(options.is_some())
        }
        CommandArgument { title, description, key, arg_type, options }
    }
}

impl ArgumentOption {
    pub fn new<S: AsRef<str>, V: Serialize>(title: S, value: V) -> Self {
        let title = title.as_ref().to_owned();
        let value = serde_json::to_value(value).unwrap();
        ArgumentOption { title, value }
    }
}

impl PlaceholderRpc {
    pub fn new<S, V>(method: S, params: V, request: bool) -> Self
    where
        S: AsRef<str>,
        V: Into<Option<Value>>,
    {
        let method = method.as_ref().to_owned();
        let params = params.into().unwrap_or(json!({}));
        let rpc_type = if request { RpcType::Request } else { RpcType::Notification };

        PlaceholderRpc { method, params, rpc_type }
    }

    pub fn is_request(&self) -> bool {
        self.rpc_type == RpcType::Request
    }

    /// Returns a reference to the placeholder's params.
    pub fn params_ref(&self) -> &Value {
        &self.params
    }

    /// Returns a mutable reference to the placeholder's params.
    pub fn params_ref_mut(&mut self) -> &mut Value {
        &mut self.params
    }

    /// Returns a reference to the placeholder's method.
    pub fn method_ref(&self) -> &str {
        &self.method
    }
}

impl PluginDescription {
    /// Returns `true` if this plugin is globally scoped, else `false`.
    pub fn is_global(&self) -> bool {
        match self.scope {
            PluginScope::Global => true,
            _ => false,
        }
    }
}

impl Default for PluginScope {
    fn default() -> Self {
        PluginScope::BufferLocal
    }
}

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

    #[test]
    fn test_serde_command() {
        let json = r#"
    {
        "title": "Test Command",
        "description": "Passes the current test",
        "rpc_cmd": {
            "rpc_type": "notification",
            "method": "test.cmd",
            "params": {
                "view": "",
                "non_arg": "plugin supplied value",
                "arg_one": "",
                "arg_two": ""
            }
        },
        "args": [
            {
                "title": "First argument",
                "description": "Indicates something",
                "key": "arg_one",
                "arg_type": "Bool"
            },
            {
                "title": "Favourite Number",
                "description": "A number used in a test.",
                "key": "arg_two",
                "arg_type": "Choice",
                "options": [
                    {"title": "Five", "value": 5},
                    {"title": "Ten", "value": 10}
                ]
            }
        ]
    }
        "#;

        let command: Command = serde_json::from_str(&json).unwrap();
        assert_eq!(command.title, "Test Command");
        assert_eq!(command.args[0].arg_type, ArgumentType::Bool);
        assert_eq!(command.rpc_cmd.params_ref()["non_arg"], "plugin supplied value");
        assert_eq!(command.args[1].options.clone().unwrap()[1].value, json!(10));
    }
}
<commit_msg>fix: ensure exec_path appends .exe on windows<commit_after>// Copyright 2017 The xi-editor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Structured representation of a plugin's features and capabilities.

use std::path::PathBuf;

use serde::{Deserialize, Deserializer, Serialize};
use serde_json::{self, Value};

use crate::syntax::{LanguageDefinition, LanguageId};

/// Describes attributes and capabilities of a plugin.
///
/// Note: - these will eventually be loaded from manifest files.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct PluginDescription {
    pub name: String,
    pub version: String,
    #[serde(default)]
    pub scope: PluginScope,
    // more metadata ...
    /// path to plugin executable
    #[serde(deserialize_with = "platform_exec_path")]
    pub exec_path: PathBuf,
    /// Events that cause this plugin to run
    #[serde(default)]
    pub activations: Vec<PluginActivation>,
    #[serde(default)]
    pub commands: Vec<Command>,
    #[serde(default)]
    pub languages: Vec<LanguageDefinition>,
}

fn platform_exec_path<'de, D: Deserializer<'de>>(deserializer: D) -> Result<PathBuf, D::Error> {
    let exec_path = PathBuf::deserialize(deserializer)?;
    if cfg!(windows) {
        Ok(exec_path.with_extension("txt"))
    } else {
        Ok(exec_path)
    }
}

/// `PluginActivation`s represent events that trigger running a plugin.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PluginActivation {
    /// Always run this plugin, when available.
    Autorun,
    /// Run this plugin if the provided SyntaxDefinition is active.
    #[allow(dead_code)]
    OnSyntax(LanguageId),
    /// Run this plugin in response to a given command.
    #[allow(dead_code)]
    OnCommand,
}

/// Describes the scope of events a plugin receives.
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum PluginScope {
    /// The plugin receives events from multiple buffers.
    Global,
    /// The plugin receives events for a single buffer.
    BufferLocal,
    /// The plugin is launched in response to a command, and receives no
    /// further updates.
    SingleInvocation,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
/// Represents a custom command provided by a plugin.
pub struct Command {
    /// Human readable title, for display in (for example) a menu.
    pub title: String,
    /// A short description of the command.
    pub description: String,
    /// Template of the command RPC as it should be sent to the plugin.
    pub rpc_cmd: PlaceholderRpc,
    /// A list of `CommandArgument`s, which the client should use to build the RPC.
    pub args: Vec<CommandArgument>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
/// A user provided argument to a plugin command.
pub struct CommandArgument {
    /// A human readable name for this argument, for use as placeholder
    /// text or equivelant.
    pub title: String,
    /// A short (single sentence) description of this argument's use.
    pub description: String,
    pub key: String,
    pub arg_type: ArgumentType,
    #[serde(skip_serializing_if = "Option::is_none")]
    /// If `arg_type` is `Choice`, `options` must contain a list of options.
    pub options: Option<Vec<ArgumentOption>>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum ArgumentType {
    Number,
    Int,
    PosInt,
    Bool,
    String,
    Choice,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
/// Represents an option for a user-selectable argument.
pub struct ArgumentOption {
    pub title: String,
    pub value: Value,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
/// A placeholder type which can represent a generic RPC.
///
/// This is the type used for custom plugin commands, which may have arbitrary
/// method names and parameters.
pub struct PlaceholderRpc {
    pub method: String,
    pub params: Value,
    pub rpc_type: RpcType,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum RpcType {
    Notification,
    Request,
}

impl Command {
    pub fn new<S, V>(title: S, description: S, rpc_cmd: PlaceholderRpc, args: V) -> Self
    where
        S: AsRef<str>,
        V: Into<Option<Vec<CommandArgument>>>,
    {
        let title = title.as_ref().to_owned();
        let description = description.as_ref().to_owned();
        let args = args.into().unwrap_or_else(Vec::new);
        Command { title, description, rpc_cmd, args }
    }
}

impl CommandArgument {
    pub fn new<S: AsRef<str>>(
        title: S,
        description: S,
        key: S,
        arg_type: ArgumentType,
        options: Option<Vec<ArgumentOption>>,
    ) -> Self {
        let key = key.as_ref().to_owned();
        let title = title.as_ref().to_owned();
        let description = description.as_ref().to_owned();
        if arg_type == ArgumentType::Choice {
            assert!(options.is_some())
        }
        CommandArgument { title, description, key, arg_type, options }
    }
}

impl ArgumentOption {
    pub fn new<S: AsRef<str>, V: Serialize>(title: S, value: V) -> Self {
        let title = title.as_ref().to_owned();
        let value = serde_json::to_value(value).unwrap();
        ArgumentOption { title, value }
    }
}

impl PlaceholderRpc {
    pub fn new<S, V>(method: S, params: V, request: bool) -> Self
    where
        S: AsRef<str>,
        V: Into<Option<Value>>,
    {
        let method = method.as_ref().to_owned();
        let params = params.into().unwrap_or(json!({}));
        let rpc_type = if request { RpcType::Request } else { RpcType::Notification };

        PlaceholderRpc { method, params, rpc_type }
    }

    pub fn is_request(&self) -> bool {
        self.rpc_type == RpcType::Request
    }

    /// Returns a reference to the placeholder's params.
    pub fn params_ref(&self) -> &Value {
        &self.params
    }

    /// Returns a mutable reference to the placeholder's params.
    pub fn params_ref_mut(&mut self) -> &mut Value {
        &mut self.params
    }

    /// Returns a reference to the placeholder's method.
    pub fn method_ref(&self) -> &str {
        &self.method
    }
}

impl PluginDescription {
    /// Returns `true` if this plugin is globally scoped, else `false`.
    pub fn is_global(&self) -> bool {
        match self.scope {
            PluginScope::Global => true,
            _ => false,
        }
    }
}

impl Default for PluginScope {
    fn default() -> Self {
        PluginScope::BufferLocal
    }
}

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

    #[test]
    fn test_serde_command() {
        let json = r#"
    {
        "title": "Test Command",
        "description": "Passes the current test",
        "rpc_cmd": {
            "rpc_type": "notification",
            "method": "test.cmd",
            "params": {
                "view": "",
                "non_arg": "plugin supplied value",
                "arg_one": "",
                "arg_two": ""
            }
        },
        "args": [
            {
                "title": "First argument",
                "description": "Indicates something",
                "key": "arg_one",
                "arg_type": "Bool"
            },
            {
                "title": "Favourite Number",
                "description": "A number used in a test.",
                "key": "arg_two",
                "arg_type": "Choice",
                "options": [
                    {"title": "Five", "value": 5},
                    {"title": "Ten", "value": 10}
                ]
            }
        ]
    }
        "#;

        let command: Command = serde_json::from_str(&json).unwrap();
        assert_eq!(command.title, "Test Command");
        assert_eq!(command.args[0].arg_type, ArgumentType::Bool);
        assert_eq!(command.rpc_cmd.params_ref()["non_arg"], "plugin supplied value");
        assert_eq!(command.args[1].options.clone().unwrap()[1].value, json!(10));
    }
}
<|endoftext|>


<commit_before>//! The `pact_mock_server` crate provides the CLI for the pact mock server for mocking HTTP requests
//! and generating responses based on a pact file. It implements the V1.1 Pact specification
//! (https://github.com/pact-foundation/pact-specification/tree/version-1.1).

#![warn(missing_docs)]

#[macro_use] extern crate clap;
#[macro_use] extern crate pact_matching;
extern crate pact_mock_server;
#[macro_use] extern crate p_macro;
#[macro_use] extern crate log;
#[macro_use] extern crate maplit;
extern crate simplelog;
extern crate uuid;
extern crate rustc_serialize;
#[macro_use] extern crate hyper;
extern crate rand;
extern crate webmachine_rust;
extern crate regex;
#[macro_use] extern crate lazy_static;

#[cfg(test)]
extern crate quickcheck;

#[cfg(test)]
#[macro_use(expect)]
extern crate expectest;

use clap::{Arg, App, SubCommand, AppSettings, ErrorKind, ArgMatches};
use std::env;
use std::str::FromStr;
use std::fs;
use std::io;
use log::{LogLevelFilter};
use simplelog::{CombinedLogger, TermLogger, FileLogger};
use std::path::PathBuf;
use std::fs::OpenOptions;
use uuid::Uuid;
use pact_matching::models::PactSpecification;

fn display_error(error: String, matches: &ArgMatches) -> ! {
    println!("ERROR: {}", error);
    println!("");
    println!("{}", matches.usage());
    panic!("{}", error)
}

mod server;
mod create_mock;
mod list;
mod verify;
mod shutdown;

fn print_version() {
    println!("\npact mock server version  : v{}", crate_version!());
    println!("pact specification version: v{}", PactSpecification::V1_1.version_str());
}

fn setup_loggers(level: &str, command: &str, output: Option<&str>) -> Result<(), io::Error> {
    let log_level = match level {
        "none" => LogLevelFilter::Off,
        _ => LogLevelFilter::from_str(level).unwrap()
    };
    if command == "start" {
        let log_file = match output {
            Some(p) => {
                try!(fs::create_dir_all(p));
                let mut path = PathBuf::from(p);
                path.push("pact_mock_server.log");
                path
            },
            None => PathBuf::from("pact_mock_server.log")
        };
        let file = try!(OpenOptions::new()
            .read(false)
            .write(true)
            .append(true)
            .create(true)
            .open(log_file));
        CombinedLogger::init(
            vec![
                TermLogger::new(log_level),
                FileLogger::new(log_level, file)
            ]
        ).unwrap();
    } else {
        TermLogger::init(log_level).unwrap();
    }
    Ok(())
}

fn lookup_global_option<'a>(option: &str, matches: &'a ArgMatches<'a>) -> Option<&'a str> {
    let global_value = matches.value_of(option);
    let command_value = matches.subcommand().1.unwrap().value_of(option);
    match (global_value, command_value) {
        (Some(v), None) => Some(v),
        (None, Some(v)) => Some(v),
        (Some(_), Some(v)) => {
            println!("WARNING: The value for '{}' has been provided twice, defaulting to the second value '{}'",
                option, v);
            Some(v)
        },
        (None, None) => None
    }
}

fn integer_value(v: String) -> Result<(), String> {
    v.parse::<u16>().map(|_| ()).map_err(|e| format!("'{}' is not a valid port value: {}", v, e) )
}

fn uuid_value(v: String) -> Result<(), String> {
    Uuid::parse_str(v.as_str()).map(|_| ()).map_err(|e| format!("'{}' is not a valid UUID value: {}", v, e) )
}

fn main() {
    match handle_command_args() {
        Ok(_) => (),
        Err(err) => std::process::exit(err)
    }
}

fn handle_command_args() -> Result<(), i32> {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let version = format!("v{}", crate_version!());
    let app = App::new(program)
        .version(version.as_str())
        .about("Standalone Pact mock server")
        .version_short("v")
        .setting(AppSettings::ArgRequiredElseHelp)
        .setting(AppSettings::SubcommandRequired)
        .setting(AppSettings::GlobalVersion)
        .setting(AppSettings::VersionlessSubcommands)
        .setting(AppSettings::ColoredHelp)
        .arg(Arg::with_name("port")
            .short("p")
            .long("port")
            .takes_value(true)
            .use_delimiter(false)
            .global(true)
            .help("port the master mock server runs on (defaults to 8080)"))
        .arg(Arg::with_name("host")
            .short("h")
            .long("host")
            .takes_value(true)
            .use_delimiter(false)
            .global(true)
            .help("hostname the master mock server runs on (defaults to localhost)"))
        .arg(Arg::with_name("loglevel")
            .short("l")
            .long("loglevel")
            .takes_value(true)
            .use_delimiter(false)
            .global(true)
            .possible_values(&["error", "warn", "info", "debug", "trace", "none"])
            .help("Log level for mock servers to write to the log file (defaults to info)"))
        .subcommand(SubCommand::with_name("start")
                .about("Starts the master mock server")
                .setting(AppSettings::ColoredHelp)
                .arg(Arg::with_name("output")
                      .short("o")
                      .long("output")
                      .takes_value(true)
                      .use_delimiter(false)
                      .help("the directory where to write files to (defaults to current directory)")))
        .subcommand(SubCommand::with_name("list")
                .about("Lists all the running mock servers")
                .setting(AppSettings::ColoredHelp))
        .subcommand(SubCommand::with_name("create")
                .about("Creates a new mock server from a pact file")
                .arg(Arg::with_name("file")
                    .short("f")
                    .long("file")
                    .takes_value(true)
                    .use_delimiter(false)
                    .required(true)
                    .help("the pact file to define the mock server"))
                .setting(AppSettings::ColoredHelp))
        .subcommand(SubCommand::with_name("verify")
                .about("Verify the mock server by id or port number, and generate a pact file if all ok")
                .arg(Arg::with_name("mock-server-id")
                    .short("i")
                    .long("mock-server-id")
                    .takes_value(true)
                    .use_delimiter(false)
                    .required_unless("mock-server-port")
                    .conflicts_with("mock-server-port")
                    .help("the ID of the mock server")
                    .validator(uuid_value))
                .arg(Arg::with_name("mock-server-port")
                    .short("m")
                    .long("mock-server-port")
                    .takes_value(true)
                    .use_delimiter(false)
                    .required_unless("mock-server-host")
                    .help("the port number of the mock server")
                    .validator(integer_value))
                .setting(AppSettings::ColoredHelp))
        .subcommand(SubCommand::with_name("shutdown")
                .about("Shutdown the mock server by id or port number, releasing all its resources")
                .arg(Arg::with_name("mock-server-id")
                    .short("i")
                    .long("mock-server-id")
                    .takes_value(true)
                    .use_delimiter(false)
                    .required_unless("mock-server-port")
                    .conflicts_with("mock-server-port")
                    .help("the ID of the mock server")
                    .validator(uuid_value))
                .arg(Arg::with_name("mock-server-port")
                    .short("m")
                    .long("mock-server-port")
                    .takes_value(true)
                    .use_delimiter(false)
                    .required_unless("mock-server-host")
                    .help("the port number of the mock server")
                    .validator(integer_value))
                .setting(AppSettings::ColoredHelp));

    let matches = app.get_matches_safe();
    match matches {
        Ok(ref matches) => {
            let log_level = lookup_global_option("loglevel", matches);
            if let Err(err) = setup_loggers(log_level.unwrap_or("info"),
                matches.subcommand_name().unwrap(),
                matches.subcommand().1.unwrap().value_of("output")) {
                display_error(format!("Could not setup loggers: {}", err), matches);
            }
            let port = lookup_global_option("port", matches).unwrap_or("8080");
            let host = lookup_global_option("host", matches).unwrap_or("localhost");
            match port.parse::<u16>() {
                Ok(p) => {
                    match matches.subcommand() {
                        ("start", Some(sub_matches)) => {
                            server::start_server(p, sub_matches.value_of("output").map(|s| s.to_owned()))
                        },
                        ("list", Some(sub_matches)) => list::list_mock_servers(host, p, sub_matches),
                        ("create", Some(sub_matches)) => create_mock::create_mock_server(host, p, sub_matches),
                        ("verify", Some(sub_matches)) => verify::verify_mock_server(host, p, sub_matches),
                        ("shutdown", Some(sub_matches)) => shutdown::shutdown_mock_server(host, p, sub_matches),
                        _ => Err(3)
                    }
                },
                Err(_) => display_error(format!("{} is not a valid port number", port), matches)
            }
        },
        Err(ref err) => {
            match err.kind {
                ErrorKind::HelpDisplayed => {
                    println!("");
                    Ok(())
                },
                ErrorKind::VersionDisplayed => {
                    print_version();
                    println!("");
                    Ok(())
                },
                _ => {
                    println!("");
                    err.exit()
                }
            }
        }
    }
}

#[cfg(test)]
mod test {

    use quickcheck::{TestResult, quickcheck};
    use rand::Rng;
    use super::{integer_value, uuid_value};
    use expectest::prelude::*;

    #[test]
    fn validates_integer_value() {
        fn prop(s: String) -> TestResult {
            let mut rng = ::rand::thread_rng();
            if rng.gen() && s.chars().any(|ch| !ch.is_numeric()) {
                TestResult::discard()
            } else {
                let validation = integer_value(s.clone());
                match validation {
                    Ok(_) => TestResult::from_bool(!s.is_empty() && s.chars().all(|ch| ch.is_numeric() )),
                    Err(_) => TestResult::from_bool(s.is_empty() || s.chars().find(|ch| !ch.is_numeric() ).is_some())
                }
            }
        }
        quickcheck(prop as fn(_) -> _);

        expect!(integer_value(s!("1234"))).to(be_ok());
        expect!(integer_value(s!("1234x"))).to(be_err());
    }

    #[test]
    fn validates_uuid_value() {
        fn prop(s: String) -> TestResult {
            let mut rng = ::rand::thread_rng();
            if rng.gen() && s.chars().any(|ch| !ch.is_digit(16)) {
                TestResult::discard()
            } else {
                let validation = uuid_value(s.clone());
                match validation {
                    Ok(_) => TestResult::from_bool(!s.is_empty() && s.len() == 32 && s.chars().all(|ch| ch.is_digit(16) )),
                    Err(_) => TestResult::from_bool(s.is_empty() || s.len() != 32 || s.chars().find(|ch| !ch.is_digit(16) ).is_some())
                }
            }
        }
        quickcheck(prop as fn(_) -> _);

        expect!(uuid_value(s!("5159135ceb064af8a6baa447d81e4fbd"))).to(be_ok());
        expect!(uuid_value(s!("1234x"))).to(be_err());
    }

}
<commit_msg>correct the displayed help for the pact_mock_server_cli<commit_after>//! The `pact_mock_server` crate provides the CLI for the pact mock server for mocking HTTP requests
//! and generating responses based on a pact file. It implements the V1.1 Pact specification
//! (https://github.com/pact-foundation/pact-specification/tree/version-1.1).

#![warn(missing_docs)]

#[macro_use] extern crate clap;
#[macro_use] extern crate pact_matching;
extern crate pact_mock_server;
#[macro_use] extern crate p_macro;
#[macro_use] extern crate log;
#[macro_use] extern crate maplit;
extern crate simplelog;
extern crate uuid;
extern crate rustc_serialize;
#[macro_use] extern crate hyper;
extern crate rand;
extern crate webmachine_rust;
extern crate regex;
#[macro_use] extern crate lazy_static;

#[cfg(test)]
extern crate quickcheck;

#[cfg(test)]
#[macro_use(expect)]
extern crate expectest;

use clap::{Arg, App, SubCommand, AppSettings, ErrorKind, ArgMatches};
use std::env;
use std::str::FromStr;
use std::fs;
use std::io;
use log::{LogLevelFilter};
use simplelog::{CombinedLogger, TermLogger, FileLogger};
use std::path::PathBuf;
use std::fs::OpenOptions;
use uuid::Uuid;
use pact_matching::models::PactSpecification;

fn display_error(error: String, matches: &ArgMatches) -> ! {
    println!("ERROR: {}", error);
    println!("");
    println!("{}", matches.usage());
    panic!("{}", error)
}

mod server;
mod create_mock;
mod list;
mod verify;
mod shutdown;

fn print_version() {
    println!("\npact mock server version  : v{}", crate_version!());
    println!("pact specification version: v{}", PactSpecification::V1_1.version_str());
}

fn setup_loggers(level: &str, command: &str, output: Option<&str>) -> Result<(), io::Error> {
    let log_level = match level {
        "none" => LogLevelFilter::Off,
        _ => LogLevelFilter::from_str(level).unwrap()
    };
    if command == "start" {
        let log_file = match output {
            Some(p) => {
                try!(fs::create_dir_all(p));
                let mut path = PathBuf::from(p);
                path.push("pact_mock_server.log");
                path
            },
            None => PathBuf::from("pact_mock_server.log")
        };
        let file = try!(OpenOptions::new()
            .read(false)
            .write(true)
            .append(true)
            .create(true)
            .open(log_file));
        CombinedLogger::init(
            vec![
                TermLogger::new(log_level),
                FileLogger::new(log_level, file)
            ]
        ).unwrap();
    } else {
        TermLogger::init(log_level).unwrap();
    }
    Ok(())
}

fn lookup_global_option<'a>(option: &str, matches: &'a ArgMatches<'a>) -> Option<&'a str> {
    let global_value = matches.value_of(option);
    let command_value = matches.subcommand().1.unwrap().value_of(option);
    match (global_value, command_value) {
        (Some(v), None) => Some(v),
        (None, Some(v)) => Some(v),
        (Some(_), Some(v)) => {
            println!("WARNING: The value for '{}' has been provided twice, defaulting to the second value '{}'",
                option, v);
            Some(v)
        },
        (None, None) => None
    }
}

fn integer_value(v: String) -> Result<(), String> {
    v.parse::<u16>().map(|_| ()).map_err(|e| format!("'{}' is not a valid port value: {}", v, e) )
}

fn uuid_value(v: String) -> Result<(), String> {
    Uuid::parse_str(v.as_str()).map(|_| ()).map_err(|e| format!("'{}' is not a valid UUID value: {}", v, e) )
}

fn main() {
    match handle_command_args() {
        Ok(_) => (),
        Err(err) => std::process::exit(err)
    }
}

fn handle_command_args() -> Result<(), i32> {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let version = format!("v{}", crate_version!());
    let app = App::new(program)
        .version(version.as_str())
        .about("Standalone Pact mock server")
        .version_short("v")
        .setting(AppSettings::ArgRequiredElseHelp)
        .setting(AppSettings::SubcommandRequired)
        .setting(AppSettings::GlobalVersion)
        .setting(AppSettings::VersionlessSubcommands)
        .setting(AppSettings::ColoredHelp)
        .arg(Arg::with_name("port")
            .short("p")
            .long("port")
            .takes_value(true)
            .use_delimiter(false)
            .global(true)
            .help("port the master mock server runs on (defaults to 8080)"))
        .arg(Arg::with_name("host")
            .short("h")
            .long("host")
            .takes_value(true)
            .use_delimiter(false)
            .global(true)
            .help("hostname the master mock server runs on (defaults to localhost)"))
        .arg(Arg::with_name("loglevel")
            .short("l")
            .long("loglevel")
            .takes_value(true)
            .use_delimiter(false)
            .global(true)
            .possible_values(&["error", "warn", "info", "debug", "trace", "none"])
            .help("Log level for mock servers to write to the log file (defaults to info)"))
        .subcommand(SubCommand::with_name("start")
                .about("Starts the master mock server")
                .setting(AppSettings::ColoredHelp)
                .arg(Arg::with_name("output")
                      .short("o")
                      .long("output")
                      .takes_value(true)
                      .use_delimiter(false)
                      .help("the directory where to write files to (defaults to current directory)")))
        .subcommand(SubCommand::with_name("list")
                .about("Lists all the running mock servers")
                .setting(AppSettings::ColoredHelp))
        .subcommand(SubCommand::with_name("create")
                .about("Creates a new mock server from a pact file")
                .arg(Arg::with_name("file")
                    .short("f")
                    .long("file")
                    .takes_value(true)
                    .use_delimiter(false)
                    .required(true)
                    .help("the pact file to define the mock server"))
                .setting(AppSettings::ColoredHelp))
        .subcommand(SubCommand::with_name("verify")
                .about("Verify the mock server by id or port number, and generate a pact file if all ok")
                .arg(Arg::with_name("mock-server-id")
                    .short("i")
                    .long("mock-server-id")
                    .takes_value(true)
                    .use_delimiter(false)
                    .required_unless("mock-server-port")
                    .conflicts_with("mock-server-port")
                    .help("the ID of the mock server")
                    .validator(uuid_value))
                .arg(Arg::with_name("mock-server-port")
                    .short("m")
                    .long("mock-server-port")
                    .takes_value(true)
                    .use_delimiter(false)
                    .required_unless("mock-server-host")
                    .help("the port number of the mock server")
                    .validator(integer_value))
                .setting(AppSettings::ColoredHelp))
        .subcommand(SubCommand::with_name("shutdown")
                .about("Shutdown the mock server by id or port number, releasing all its resources")
                .arg(Arg::with_name("mock-server-id")
                    .short("i")
                    .long("mock-server-id")
                    .takes_value(true)
                    .use_delimiter(false)
                    .required_unless("mock-server-port")
                    .conflicts_with("mock-server-port")
                    .help("the ID of the mock server")
                    .validator(uuid_value))
                .arg(Arg::with_name("mock-server-port")
                    .short("m")
                    .long("mock-server-port")
                    .takes_value(true)
                    .use_delimiter(false)
                    .required_unless("mock-server-host")
                    .help("the port number of the mock server")
                    .validator(integer_value))
                .setting(AppSettings::ColoredHelp));

    let matches = app.get_matches_safe();
    match matches {
        Ok(ref matches) => {
            let log_level = lookup_global_option("loglevel", matches);
            if let Err(err) = setup_loggers(log_level.unwrap_or("info"),
                matches.subcommand_name().unwrap(),
                matches.subcommand().1.unwrap().value_of("output")) {
                display_error(format!("Could not setup loggers: {}", err), matches);
            }
            let port = lookup_global_option("port", matches).unwrap_or("8080");
            let host = lookup_global_option("host", matches).unwrap_or("localhost");
            match port.parse::<u16>() {
                Ok(p) => {
                    match matches.subcommand() {
                        ("start", Some(sub_matches)) => {
                            server::start_server(p, sub_matches.value_of("output").map(|s| s.to_owned()))
                        },
                        ("list", Some(sub_matches)) => list::list_mock_servers(host, p, sub_matches),
                        ("create", Some(sub_matches)) => create_mock::create_mock_server(host, p, sub_matches),
                        ("verify", Some(sub_matches)) => verify::verify_mock_server(host, p, sub_matches),
                        ("shutdown", Some(sub_matches)) => shutdown::shutdown_mock_server(host, p, sub_matches),
                        _ => Err(3)
                    }
                },
                Err(_) => display_error(format!("{} is not a valid port number", port), matches)
            }
        },
        Err(ref err) => {
            match err.kind {
                ErrorKind::HelpDisplayed => {
                    println!("{}", err.message);
                    Ok(())
                },
                ErrorKind::VersionDisplayed => {
                    print_version();
                    println!("");
                    Ok(())
                },
                _ => {
                    println!("{}", err.message);
                    err.exit()
                }
            }
        }
    }
}

#[cfg(test)]
mod test {

    use quickcheck::{TestResult, quickcheck};
    use rand::Rng;
    use super::{integer_value, uuid_value};
    use expectest::prelude::*;

    #[test]
    fn validates_integer_value() {
        fn prop(s: String) -> TestResult {
            let mut rng = ::rand::thread_rng();
            if rng.gen() && s.chars().any(|ch| !ch.is_numeric()) {
                TestResult::discard()
            } else {
                let validation = integer_value(s.clone());
                match validation {
                    Ok(_) => TestResult::from_bool(!s.is_empty() && s.chars().all(|ch| ch.is_numeric() )),
                    Err(_) => TestResult::from_bool(s.is_empty() || s.chars().find(|ch| !ch.is_numeric() ).is_some())
                }
            }
        }
        quickcheck(prop as fn(_) -> _);

        expect!(integer_value(s!("1234"))).to(be_ok());
        expect!(integer_value(s!("1234x"))).to(be_err());
    }

    #[test]
    fn validates_uuid_value() {
        fn prop(s: String) -> TestResult {
            let mut rng = ::rand::thread_rng();
            if rng.gen() && s.chars().any(|ch| !ch.is_digit(16)) {
                TestResult::discard()
            } else {
                let validation = uuid_value(s.clone());
                match validation {
                    Ok(_) => TestResult::from_bool(!s.is_empty() && s.len() == 32 && s.chars().all(|ch| ch.is_digit(16) )),
                    Err(_) => TestResult::from_bool(s.is_empty() || s.len() != 32 || s.chars().find(|ch| !ch.is_digit(16) ).is_some())
                }
            }
        }
        quickcheck(prop as fn(_) -> _);

        expect!(uuid_value(s!("5159135ceb064af8a6baa447d81e4fbd"))).to(be_ok());
        expect!(uuid_value(s!("1234x"))).to(be_err());
    }

}
<|endoftext|>


<commit_before>#![allow(const_err)] // don't warn about truncating casts. FIXME: remove this, the error shouldn't even be shown

enum Foo {
    Bar = 42,
    Baz,
    Quux = 100,
}

enum Signed {
    Bar = -42,
    Baz,
    Quux = 100,
}

fn foo() -> [u8; 3] {
    let baz = Foo::Baz; // let-expansion changes the MIR significantly
    [Foo::Bar as u8, baz as u8, Foo::Quux as u8]
}

fn signed() -> [i8; 3] {
    let baz = Signed::Baz; // let-expansion changes the MIR significantly
    [Signed::Bar as i8, baz as i8, Signed::Quux as i8]
}

fn unsafe_match() -> bool {
    match unsafe { std::mem::transmute::<u8, Foo>(43) } {
        Foo::Baz => true,
        _ => false,
    }
}

fn main() {
    assert_eq!(foo(), [42, 43, 100]);
    assert_eq!(signed(), [-42, -41, 100]);
    assert!(unsafe_match());
}
<commit_msg>remove no-longer-needed allow(const_err)<commit_after>enum Foo {
    Bar = 42,
    Baz,
    Quux = 100,
}

enum Signed {
    Bar = -42,
    Baz,
    Quux = 100,
}

fn foo() -> [u8; 3] {
    let baz = Foo::Baz; // let-expansion changes the MIR significantly
    [Foo::Bar as u8, baz as u8, Foo::Quux as u8]
}

fn signed() -> [i8; 3] {
    let baz = Signed::Baz; // let-expansion changes the MIR significantly
    [Signed::Bar as i8, baz as i8, Signed::Quux as i8]
}

fn unsafe_match() -> bool {
    match unsafe { std::mem::transmute::<u8, Foo>(43) } {
        Foo::Baz => true,
        _ => false,
    }
}

fn main() {
    assert_eq!(foo(), [42, 43, 100]);
    assert_eq!(signed(), [-42, -41, 100]);
    assert!(unsafe_match());
}
<|endoftext|>


<commit_before>/* Exposes datatypes and functionaly of the VR4300 CPU. */

/*

CPU0

  00h = r0/reg0     08h = t0/reg8     10h = s0/reg16    18h = t8/reg24
  01h = at/reg1     09h = t1/reg9     11h = s1/reg17    19h = t9/reg25
  02h = v0/reg2     0Ah = t2/reg10    12h = s2/reg18    1Ah = k0/reg26
  03h = v1/reg3     0Bh = t3/reg11    13h = s3/reg19    1Bh = k1/reg27
  04h = a0/reg4     0Ch = t4/reg12    14h = s4/reg20    1Ch = gp/reg28
  05h = a1/reg5     0Dh = t5/reg13    15h = s5/reg21    1Dh = sp/reg29
  06h = a2/reg6     0Eh = t6/reg14    16h = s6/reg22    1Eh = s8/reg30
  07h = a3/reg7     0Fh = t7/reg15    17h = s7/reg23    1Fh = ra/reg31

COP0

  00h = Index       08h = BadVAddr    10h = Config      18h = *RESERVED*
  01h = Random      09h = Count       11h = LLAddr      19h = *RESERVED*
  02h = EntryLo0    0Ah = EntryHi     12h = WatchLo     1Ah = PErr
  03h = EntryLo1    0Bh = Compare     13h = WatchHi     1Bh = CacheErr
  04h = Context     0Ch = Status      14h = XContext    1Ch = TagLo
  05h = PageMask    0Dh = Cause       15h = *RESERVED*  1Dh = TagHi
  06h = Wired       0Eh = EPC         16h = *RESERVED*  1Eh = ErrorEPC
  07h = *RESERVED*  0Fh = PRevID      17h = *RESERVED*  1Fh = *RESERVED*

 */

 use n64::N64;
 use n64::mc;

/* Size of the general purpose register file. */
const GPR_SIZE: usize = 32;

pub struct CPU {

	/* The CPU's register file. */
	gpr: [u32; GPR_SIZE],

	/* The program counter. */
	pc: u32
}

impl CPU {
	pub fn new(pc: u32) -> CPU {
		CPU {
			/* Zero-initialize the general purpose registers. */
			gpr: [0; GPR_SIZE],
			/* Initialize the program counter. */
			pc: pc
		}
	}
}

/* Executes a single instruction on the given N64. */
pub fn cycle(n64: &mut N64) {
	/* Fetch the next instrution from memory. */
	let inst = mc::read(n64, n64.cpu.pc as usize);
	println!("Cycle. Read raw instruction {:#x}.", inst);
	/* Execute the instrution. */

	/* Increment the program counter. */
	n64.cpu.pc += 4;
}
<commit_msg>Added instruction extension to u32.<commit_after>/* Exposes datatypes and functionaly of the VR4300 CPU. */

/*

CPU0

  00h = r0/reg0     08h = t0/reg8     10h = s0/reg16    18h = t8/reg24
  01h = at/reg1     09h = t1/reg9     11h = s1/reg17    19h = t9/reg25
  02h = v0/reg2     0Ah = t2/reg10    12h = s2/reg18    1Ah = k0/reg26
  03h = v1/reg3     0Bh = t3/reg11    13h = s3/reg19    1Bh = k1/reg27
  04h = a0/reg4     0Ch = t4/reg12    14h = s4/reg20    1Ch = gp/reg28
  05h = a1/reg5     0Dh = t5/reg13    15h = s5/reg21    1Dh = sp/reg29
  06h = a2/reg6     0Eh = t6/reg14    16h = s6/reg22    1Eh = s8/reg30
  07h = a3/reg7     0Fh = t7/reg15    17h = s7/reg23    1Fh = ra/reg31

COP0

  00h = Index       08h = BadVAddr    10h = Config      18h = *RESERVED*
  01h = Random      09h = Count       11h = LLAddr      19h = *RESERVED*
  02h = EntryLo0    0Ah = EntryHi     12h = WatchLo     1Ah = PErr
  03h = EntryLo1    0Bh = Compare     13h = WatchHi     1Bh = CacheErr
  04h = Context     0Ch = Status      14h = XContext    1Ch = TagLo
  05h = PageMask    0Dh = Cause       15h = *RESERVED*  1Dh = TagHi
  06h = Wired       0Eh = EPC         16h = *RESERVED*  1Eh = ErrorEPC
  07h = *RESERVED*  0Fh = PRevID      17h = *RESERVED*  1Fh = *RESERVED*

 */

 use n64::N64;
 use n64::mc;

/* Size of the general purpose register file. */
const GPR_SIZE: usize = 32;

pub struct CPU {

	/* The CPU's register file. */
	gpr: [u32; GPR_SIZE],

	/* The program counter. */
	pc: u32
}

impl CPU {
	pub fn new(pc: u32) -> CPU {
		CPU {
			/* Zero-initialize the general purpose registers. */
			gpr: [0; GPR_SIZE],
			/* Initialize the program counter. */
			pc: pc
		}
	}
}

struct Inst(pub u32);

impl Inst {
	/* Returns the instruction's opcode. */
	pub fn op(&self) -> u8{
		((self.0 >> 26) & 0b111111) as u8
	}
	/* Returns the instruction's source register. */
	pub fn rs(&self) -> u8{
		((self.0 >> 21) & 0b11111) as u8
	}
	/* Returns the instruction's target register. */
	pub fn rt(&self) -> u8 {
		((self.0 >> 16) & 0b11111) as u8
	}
	/* Returns the instruciton's destination register. */
	pub fn rd(&self) -> u8 {
		((self.0 >> 11) & 0b11111) as u8
	}
	/* Returns the instruction's shift amount. */
	pub fn sa(&self) -> u8 {
		((self.0 >> 6) & 0b11111) as u8
	}
	/* Returns the instruction's immediate value. */
	pub fn imm(&self) -> u32 {
		self.0 & 0xffff
	}
	/* Return's the function's funct field. */
	pub fn funct(&self) -> u8 {
		0
	}
	/* Return's the instruction's target field. */
	pub fn target(&self) -> u32 {
		0
	}
}

/* Executes a single instruction on the given N64. */
pub fn cycle(n64: &mut N64) {
	/* Fetch the next instrution from memory. */
	let inst = Inst(mc::read(n64, n64.cpu.pc as usize));
	println!("Cycle. Read raw instruction {:#x}.", inst.0);
	/* Execute the instrution. */
	match inst.op() {
		_ => return
	}
	/* Increment the program counter. */
	n64.cpu.pc += 4;
}
<|endoftext|>


<commit_before>/**
Katy Williamson kcw4sn
Ben Terner bt3ze
@virginia.edu

Final Project for CS4414 - Operating Systems
A parallel MST implementation on images in Rust

*/

/*
some documentation:
Pixel object is composed of r,g,b values, a color, and an x,y index that takes the place of its adjacency list
Point is just an (x,y) value to denote a pixel's location
Edge contains two points: source and dest, along with the edge cost between them

*/

extern mod extra;
use std::{os, num, hashmap} ;
use extra::{arc,priority_queue};
use std::comm::*;

struct Pixel{
    r: int,
    b: int,
    g: int,
    color: int,
    x: int,
    y: int
}

impl Pixel {
    fn new(red: int, blue: int, green: int, x: int, y: int) -> Pixel {
        Pixel{
            r: red,
            b: blue,
            g: green,
            color: -1,
            x: x,
            y: y
        }
    }
}

impl Clone for Pixel{
    fn clone(&self) -> Pixel {
        Pixel{
            r: self.r,
            b: self.b,
            g: self.g,
            color: self.color,
            x: self.x,
            y: self.y
        }
    }
}

struct Point {
    x: int,
    y: int
}

impl Point{
    fn new(x: int, y: int)-> Point {
        Point {
            x: x,
            y: y
        }
    }
}

struct Edge {
    source: Point,
    dest: Point,
    cost: float
}

impl Edge {
    fn new(s: Point, d: Point, cost: float) -> Edge {
        Edge {
            source: s,
            dest: d,
            cost: cost
        }
    }
}

impl Ord for Edge {
    fn lt(&self, other: &Edge) -> bool {
        self.cost > other.cost
    }
}

fn edgeCost(a: &Pixel, b: &Pixel) -> float {
    num::sqrt( (
            (a.r-b.r)*(a.r-b.r) + (a.g-b.g)*(a.g-b.g) + (a.b-b.b)*(a.b-b.b) ) as float)
}

fn findParent(map: &~[int], a: int) -> int {
 //   do map.read() |colors| {
        if map[a] < 0 {
            a
        } else {
            findParent(map, map[a])
        }
  //  }
}

fn setParent(colors: &mut ~[int], ind: int, val: int) {
    let mut tmp: int = -1;
 //   do map.write() |colors| {
    tmp = colors[ind];
    colors[ind] = val;
  //  }
    if tmp >= 0 {
        setParent(colors, tmp, val);
    }
}

fn readImage( filename: &~str) -> ~ [ ~[Pixel]] {
    let mut retval: ~[~[Pixel]] = ~[];

    let file: &str = filename.to_owned();
//    let file2: ~str = file.to_owned();
    let split_filename: ~[&str] = file.split_iter('.').collect();
    let file_data: &str = split_filename[0] + ".txt";

    println(fmt!("The image name is [%?]", file));
//    println(fmt!("The image data will be stored at [%?]", file_data));

    //read in the .txt associated with the file title
    let path = &PosixPath(file_data);

    match std::io::file_reader(path) {
	Ok(reader) => {
	    //run the java program to process the image
/*	    let program: &str = "java ImageReader";
	    let argv: ~[~str] = ~[file2];
	    let mut prog = std::run::Process::new(program, argv,
		std::run::ProcessOptions {
			env: None,
			dir: None,
			in_fd: None,
			out_fd: None,
			err_fd: None
		}
	    );
	    prog.finish();
*/
	    //parse out the array dimensions
    	    let dimensions_str: &str = reader.read_line();
   	    println(fmt!("dimensons: %s",dimensions_str));
	    let mut h: int = 0;
	    let mut w: int = 0;
	    match dimensions_str[0] as char {
		'H' => {
		    let split_dim: ~[&str] = dimensions_str.split_iter('W').collect();
		    h = from_str(split_dim[0].slice(1,split_dim[0].len())).unwrap();
		    w = from_str(split_dim[1]).unwrap();
		//    println(fmt!("Dimensions passed: H %? W %?",h,w));
		    //let retval: ~[ ~[Pixel, ..w], ..h];
		}
		_ => {println("Dimensions corrupted! Abort");}
	    }

	    //fill in the retVal array with pixel data
            //let mut rowfirst = false;
	    for row in range(0,h){
//                if(!rowfirst) {
                retval.push(~[]);
                //rowfirst = true; }
		for col in range(0,w){
	    	    if !reader.eof() {
			let line: &str = reader.read_line();
			//println(line);
			let rpos:uint = match line.find('R') { Some(n)=>n,None=>line.len() };
			let gpos:uint = match line.find('G') { Some(n)=>n,None=>line.len() };
			let bpos:uint = match line.find('B') { Some(n)=>n,None=>line.len() };

			if rpos == line.len() || gpos == line.len() || bpos == line.len() {
			    println("Pixel data corrupted! Abort");
			}

			let R:int = from_str(line.slice(rpos+1,gpos)).unwrap();
			let G:int = from_str(line.slice(gpos+1,bpos)).unwrap();
			let B:int = from_str(line.slice(bpos+1,line.len())).unwrap();

			//println(fmt!("R %? G %? B %?",R,G,B));

			//fn new(red: int, blue: int, green: int, x: int, y: int) -> Pixel {
			retval[row].push(Pixel::new(R,G,B,col,row));

		    }
		    else {
			println("Data file corrupted! Abort");
		    }
		}
	    }
	},
	Err(err)   => { fail!(err) }
    }

    retval
}

fn main(){
    let argv =  os::args();
 //   println(argv.to_str());

    let pixels: ~[ ~[Pixel] ] = readImage(&argv[1]);
    let height = pixels.len() as int;
    let width = pixels[0].len() as int;

    println(fmt!("Dimensions received: H %? W %?",height,width));

    let mut find_arcs: ~[ ~[arc::RWArc<Pixel>] ] =  ~[];
    for h in range(0,height){
	find_arcs.push(~[]);
        for w in range(0,width){
 //           println(fmt!("pix %?",pixels[h][w]));
	    find_arcs[h].push(arc::RWArc::new(pixels[h][w]));
	}
    }

    let arcs = find_arcs; // now we have an immutable array that can be shared

    let mut colormap: ~[int] = ~[];
    let nodes = [ (0,0),(width-1,0),(0,height-1),(width-1,height-1) ];
    let numnodes: uint = nodes.len();
    println(fmt!("number of nodes: %u",numnodes));

    let mut color_index = 0;
    for &node in nodes.iter(){
        let (a,b) = node;
        do arcs[b][a].write |pix| {
            pix.color = color_index;
        }
        color_index+=1;
        colormap.push(-1);
    }

//    let colormap_arc: arc::RWArc<~[int]> =  arc::RWArc::new(colormap);
    let boundaryqueue: priority_queue::PriorityQueue<Edge> =  priority_queue::PriorityQueue::new();
    let boundary_arc: arc::RWArc<priority_queue::PriorityQueue<Edge>> = arc::RWArc::new(boundaryqueue);

    let (port, chan) = stream();
    let chan = SharedChan::new(chan);

    for &node in nodes.iter() {
        let (a,b) = node;
        let shared_arcs = arcs.clone();
        let shared_boundaries = boundary_arc.clone();
        let child_chan = chan.clone();
        do spawn { // split into threads here
//            let c = a;
//            let d = b;
            let mut x=a;
            let mut y=b;
            let mut queue: priority_queue::PriorityQueue<Edge> =  priority_queue::PriorityQueue::new();
            let mut visited: hashmap::HashMap<(int,int),bool> = hashmap::HashMap::new();
            let mut newvisit: bool = true;
            let mut boundaries: priority_queue::PriorityQueue<Edge> =  priority_queue::PriorityQueue::new();
            let mut color: int = -1;
            do shared_arcs[b][a].read |pix| {
                color = pix.color;
            }

//            println(fmt!("start at (%i,%i): color = %i",c,d,color));

            loop {
                //  at most once each:
                //   visit the next vertex (determined by the last edge we chose or the starting vertex) to claim its neighbors and add its edges to our queue
                //   pop the next edge off the queue, which contains all of the edges between vertices claimed by the local thread

                if(newvisit){ // if the next vertex has not previously been visited to claim neighbors and add edges
                    let neighbors = [ (x,y-1),(x+1,y), (x,y+1), (x-1,y)]; // potential neighbors
                    for &coord in neighbors.iter() {
                        let (w,z) = coord;
                        if w >=0 && w < width && z >=0 && z < height { // bounds checking on neighbors to only select valid edges
                            let mut newvertex = false;
                            let mut colored = false;
                            do shared_arcs[z][w].read |dest| {
                                if dest.color >= 0 {
                                    colored = true; //vertex has been previously claimed
                                }
                            }
                            if !colored { // this thread will claim the unclaimed vertex
                                do shared_arcs[z][w].write |dest| {
                                    if dest.color < 0 {
                                        dest.color = color;
                                        newvertex = true;
                                    } else {
                                        // edge has been claimed during a race since we last checked. add to supervertex boundary
                                        colored = true;
                                    }
                                }
                            }
                            if colored {
                                // we have found an edge that crosses a cut!
                                // here, somehow collect these edges for contraction later
                                do shared_arcs[y][x].read |src| {
                                    do shared_arcs[z][w].read |dest| {
                                        if dest.color != color {
                                            boundaries.push( Edge::new(Point::new(x,y),Point::new(w,z),edgeCost(src,dest)));
                                            // println(fmt!("%?\n-->%?",src,dest));
                                        }
                                    }
                                }
                            }
                            if newvertex { // we have an unvisited but previously claimed vertex
                                // add the edge to our local edges queue
                                do shared_arcs[y][x].read |src| {
                                    do shared_arcs[z][w].read |dest| {
                                        queue.push( Edge::new(Point::new(x,y),Point::new(w,z),edgeCost(src,dest)));
                                    }
                                }
                            }
                        }
                    }
                }

                let edge = queue.maybe_pop(); // should fail only when we've exhausted all the edges in our queue, i.e. this thread is done running Prim
                match edge {
                    Some(e) => {
                        //println(fmt!("(%i,%i) pop (%i,%i)-%f-(%i,%i)",c,d,e.source.x,e.source.y,e.cost,e.dest.x,e.dest.y));
                        println(fmt!("(%i,%i),(%i,%i):%f\n",e.source.x,e.source.y,e.dest.x,e.dest.y,e.cost));
                        let coord = (e.dest.x,e.dest.y);
                        if !visited.contains_key(&coord){
                            // use visited hashmap to figure out if we're at a new vertex or a previously seen one
                            visited.insert(coord,true); //add to growing spanning forest
                            x = e.dest.x; // update search coordinates for next iteration
                            y = e.dest.y;
                            newvisit = true; // update flag to claim new vertex's neighbors
                        } else {
                            newvisit = false;
                        }
                    },
                    None => { break; } // this should execute at the end when there are no more unvisited or uncolored nodes for a thread
                }
            }

            // write all of the supervertex's shared boundaries out to be compared concurrently for contraction
            do shared_boundaries.write |bounds| {
                loop {
                    match boundaries.maybe_pop() {
                        Some(e) =>
                            {
                            bounds.push(e);
                        }
                        None => { break; }
                    }
                }
            }
            child_chan.send(0); // tell master that we're done
        }
    }

    // wait for all the child threads to write their boundary-crossing edges
    for x in range(0,numnodes) {
        port.recv();
    }

    // then find the cut-crossing edges
    do boundary_arc.write |boundaries| {
        let mut bridges:uint = 0;
        loop {
            match boundaries.maybe_pop() {
                Some(e) => {
                     do arcs[e.dest.y][e.dest.x].read |dest| {
                        do arcs[e.source.y][e.source.x].read |src| {
//                            println(fmt!("boundary (%i,%i:%i)-%f-(%i,%i:%i)",src.x,src.y,src.color,e.cost,dest.x,dest.y,dest.color));
                            let dest_parent = findParent(&colormap,dest.color);
                            let src_parent =  findParent(&colormap,src.color);
                            if src_parent != dest_parent {
                                setParent(&mut colormap,src.color,dest_parent);
                //                println(fmt!("bridge: (%i,%i:%i->%i)-(%i,%i:%i->%i) : %f",src.x,src.y,src.color,src_parent,dest.x,dest.y,dest.color,dest_parent, e.cost));
                                println(fmt!("(%i,%i),(%i,%i):%f",src.x,src.y,dest.x,dest.y,e.cost));
                                bridges +=1;
                            }
                        }
                    }

                    // break when all of the supervertices have been connected
                    if bridges >= numnodes -1 {
                        break;
                    }
                },
                None => { break } // should not execute. break two lines above should do it
            }
        }
    }

}
<commit_msg>cleaned up a little bi.<commit_after>/**
Katy Williamson kcw4sn
Ben Terner bt3ze
@virginia.edu

Final Project for CS4414 - Operating Systems
A parallel MST implementation on images in Rust

*/

/*
some documentation:
Pixel object is composed of r,g,b values, a color, and an x,y index that takes the place of its adjacency list
Point is just an (x,y) value to denote a pixel's location
Edge contains two points: source and dest, along with the edge cost between them

*/

extern mod extra;
use std::{os, num, hashmap} ;
use extra::{arc,priority_queue};
use std::comm::*;

struct Pixel{
    r: int,
    b: int,
    g: int,
    color: int,
    x: int,
    y: int
}

impl Pixel {
    fn new(red: int, blue: int, green: int, x: int, y: int) -> Pixel {
        Pixel{
            r: red,
            b: blue,
            g: green,
            color: -1,
            x: x,
            y: y
        }
    }
}

impl Clone for Pixel{
    fn clone(&self) -> Pixel {
        Pixel{
            r: self.r,
            b: self.b,
            g: self.g,
            color: self.color,
            x: self.x,
            y: self.y
        }
    }
}

struct Point {
    x: int,
    y: int
}

impl Point{
    fn new(x: int, y: int)-> Point {
        Point {
            x: x,
            y: y
        }
    }
}

struct Edge {
    source: Point,
    dest: Point,
    cost: float
}

impl Edge {
    fn new(s: Point, d: Point, cost: float) -> Edge {
        Edge {
            source: s,
            dest: d,
            cost: cost
        }
    }
}

impl Ord for Edge {
    fn lt(&self, other: &Edge) -> bool {
        self.cost > other.cost
    }
}

fn edgeCost(a: &Pixel, b: &Pixel) -> float {
    num::sqrt( (
            (a.r-b.r)*(a.r-b.r) + (a.g-b.g)*(a.g-b.g) + (a.b-b.b)*(a.b-b.b) ) as float)
}

fn findParent(map: &~[int], a: int) -> int {
    if map[a] < 0 {
            a
    } else {
        findParent(map, map[a])
    }
}

fn setParent(colors: &mut ~[int], ind: int, val: int) {
    let tmp = colors[ind];
    colors[ind] = val;
    if tmp >= 0 {
        setParent(colors, tmp, val);
    }
}

fn readImage( filename: &~str) -> ~ [ ~[Pixel]] {
    let mut retval: ~[~[Pixel]] = ~[];

    let file: &str = filename.to_owned();
//    let file2: ~str = file.to_owned();
    let split_filename: ~[&str] = file.split_iter('.').collect();
    let file_data: &str = split_filename[0] + ".txt";

    println(fmt!("The image name is [%?]", file));
//    println(fmt!("The image data will be stored at [%?]", file_data));

    //read in the .txt associated with the file title
    let path = &PosixPath(file_data);

    match std::io::file_reader(path) {
	Ok(reader) => {
	    //run the java program to process the image
/*	    let program: &str = "java ImageReader";
	    let argv: ~[~str] = ~[file2];
	    let mut prog = std::run::Process::new(program, argv,
		std::run::ProcessOptions {
			env: None,
			dir: None,
			in_fd: None,
			out_fd: None,
			err_fd: None
		}
	    );
	    prog.finish();
*/
	    //parse out the array dimensions
    	    let dimensions_str: &str = reader.read_line();
   	    println(fmt!("dimensons: %s",dimensions_str));
	    let mut h: int = 0;
	    let mut w: int = 0;
	    match dimensions_str[0] as char {
		'H' => {
		    let split_dim: ~[&str] = dimensions_str.split_iter('W').collect();
		    h = from_str(split_dim[0].slice(1,split_dim[0].len())).unwrap();
		    w = from_str(split_dim[1]).unwrap();
		//    println(fmt!("Dimensions passed: H %? W %?",h,w));
		    //let retval: ~[ ~[Pixel, ..w], ..h];
		}
		_ => {println("Dimensions corrupted! Abort");}
	    }

	    //fill in the retVal array with pixel data
	    for row in range(0,h){
                retval.push(~[]);
		for col in range(0,w){
	    	    if !reader.eof() {
			let line: &str = reader.read_line();
			//println(line);
			let rpos:uint = match line.find('R') { Some(n)=>n,None=>line.len() };
			let gpos:uint = match line.find('G') { Some(n)=>n,None=>line.len() };
			let bpos:uint = match line.find('B') { Some(n)=>n,None=>line.len() };

			if rpos == line.len() || gpos == line.len() || bpos == line.len() {
			    println("Pixel data corrupted! Abort");
			}

			let R:int = from_str(line.slice(rpos+1,gpos)).unwrap();
			let G:int = from_str(line.slice(gpos+1,bpos)).unwrap();
			let B:int = from_str(line.slice(bpos+1,line.len())).unwrap();

			//println(fmt!("R %? G %? B %?",R,G,B));

			//fn new(red: int, blue: int, green: int, x: int, y: int) -> Pixel {
			retval[row].push(Pixel::new(R,G,B,col,row));

		    }
		    else {
			println("Data file corrupted! Abort");
		    }
		}
	    }
	},
	Err(err)   => { fail!(err) }
    }

    retval
}

fn main(){
    let argv =  os::args();

    let pixels: ~[ ~[Pixel] ] = readImage(&argv[1]);
    let height = pixels.len() as int;
    let width = pixels[0].len() as int;

    println(fmt!("Dimensions received: H %? W %?",height,width));

    let mut find_arcs: ~[ ~[arc::RWArc<Pixel>] ] =  ~[];
    for h in range(0,height){
	find_arcs.push(~[]);
        for w in range(0,width){
 //           println(fmt!("pix %?",pixels[h][w]));
	    find_arcs[h].push(arc::RWArc::new(pixels[h][w]));
	}
    }

    let arcs = find_arcs; // now we have an immutable array that can be shared

    let mut colormap: ~[int] = ~[];
    let nodes = [ (0,0),(width-1,0),(0,height-1),(width-1,height-1) ];
    let numnodes: uint = nodes.len();
    println(fmt!("number of nodes: %u",numnodes));

    let mut color_index = 0;
    for &node in nodes.iter(){
        let (a,b) = node;
        do arcs[b][a].write |pix| {
            pix.color = color_index;
        }
        color_index+=1;
        colormap.push(-1);
    }

    let boundaryqueue: priority_queue::PriorityQueue<Edge> =  priority_queue::PriorityQueue::new();
    let boundary_arc: arc::RWArc<priority_queue::PriorityQueue<Edge>> = arc::RWArc::new(boundaryqueue);

    let (port, chan) = stream();
    let chan = SharedChan::new(chan);

    for &node in nodes.iter() {
        let (a,b) = node;
        let shared_arcs = arcs.clone();
        let shared_boundaries = boundary_arc.clone();
        let child_chan = chan.clone();
        do spawn { // split into threads here
            let mut x=a;
            let mut y=b;
            let mut queue: priority_queue::PriorityQueue<Edge> =  priority_queue::PriorityQueue::new();
            let mut visited: hashmap::HashMap<(int,int),bool> = hashmap::HashMap::new();
            let mut newvisit: bool = true;
            let mut boundaries: priority_queue::PriorityQueue<Edge> =  priority_queue::PriorityQueue::new();
            let mut color: int = -1;
            do shared_arcs[b][a].read |pix| {
                color = pix.color;
            }

//            println(fmt!("start at (%i,%i): color = %i",c,d,color));
            loop {
                //  at most once each:
                //   visit the next vertex (determined by the last edge we chose or the starting vertex) to claim its neighbors and add its edges to our queue
                //   pop the next edge off the queue, which contains all of the edges between vertices claimed by the local thread

                if(newvisit){ // if the next vertex has not previously been visited to claim neighbors and add edges
                    let neighbors = [ (x,y-1),(x+1,y), (x,y+1), (x-1,y)]; // potential neighbors
                    for &coord in neighbors.iter() {
                        let (w,z) = coord;
                        if w >=0 && w < width && z >=0 && z < height { // bounds checking on neighbors to only select valid edges
                            let mut newvertex = false;
                            let mut colored = false;
                            do shared_arcs[z][w].read |dest| {
                                if dest.color >= 0 {
                                    colored = true; //vertex has been previously claimed
                                }
                            }
                            if !colored { // this thread will claim the unclaimed vertex
                                do shared_arcs[z][w].write |dest| {
                                    if dest.color < 0 {
                                        dest.color = color;
                                        newvertex = true;
                                    } else {
                                        // edge has been claimed during a race since we last checked. add to supervertex boundary
                                        colored = true;
                                    }
                                }
                            }
                            if colored {
                                // we have found an edge that crosses a cut!
                                // here, somehow collect these edges for contraction later
                                do shared_arcs[y][x].read |src| {
                                    do shared_arcs[z][w].read |dest| {
                                        if dest.color != color {
                                            boundaries.push( Edge::new(Point::new(x,y),Point::new(w,z),edgeCost(src,dest)));
                                            // println(fmt!("%?\n-->%?",src,dest));
                                        }
                                    }
                                }
                            }
                            if newvertex { // we have an unvisited but previously claimed vertex
                                // add the edge to our local edges queue
                                do shared_arcs[y][x].read |src| {
                                    do shared_arcs[z][w].read |dest| {
                                        queue.push( Edge::new(Point::new(x,y),Point::new(w,z),edgeCost(src,dest)));
                                    }
                                }
                            }
                        }
                    }
                }

                let edge = queue.maybe_pop(); // should fail only when we've exhausted all the edges in our queue, i.e. this thread is done running Prim
                match edge {
                    Some(e) => {
                        //println(fmt!("(%i,%i) pop (%i,%i)-%f-(%i,%i)",c,d,e.source.x,e.source.y,e.cost,e.dest.x,e.dest.y));
                        println(fmt!("(%i,%i),(%i,%i):%f\n",e.source.x,e.source.y,e.dest.x,e.dest.y,e.cost));
                        let coord = (e.dest.x,e.dest.y);
                        if !visited.contains_key(&coord){
                            // use visited hashmap to figure out if we're at a new vertex or a previously seen one
                            visited.insert(coord,true); //add to growing spanning forest
                            x = e.dest.x; // update search coordinates for next iteration
                            y = e.dest.y;
                            newvisit = true; // update flag to claim new vertex's neighbors
                        } else {
                            newvisit = false;
                        }
                    },
                    None => { break; } // this should execute at the end when there are no more unvisited or uncolored nodes for a thread
                }
            }

            // write all of the supervertex's shared boundaries out to be compared concurrently for contraction
            do shared_boundaries.write |bounds| {
                loop {
                    match boundaries.maybe_pop() {
                        Some(e) =>
                            {
                            bounds.push(e);
                        }
                        None => { break; }
                    }
                }
            }
            child_chan.send(0); // tell master that we're done
        }
    }

    // wait for all the child threads to write their boundary-crossing edges
    for x in range(0,numnodes) {
        port.recv();
    }

    // then find the cut-crossing edges
    do boundary_arc.write |boundaries| {
        let mut bridges:uint = 0;
        loop {
            match boundaries.maybe_pop() {
                Some(e) => {
                     do arcs[e.dest.y][e.dest.x].read |dest| {
                        do arcs[e.source.y][e.source.x].read |src| {
//                            println(fmt!("boundary (%i,%i:%i)-%f-(%i,%i:%i)",src.x,src.y,src.color,e.cost,dest.x,dest.y,dest.color));
                            let dest_parent = findParent(&colormap,dest.color);
                            let src_parent =  findParent(&colormap,src.color);
                            if src_parent != dest_parent {
                                setParent(&mut colormap,src.color,dest_parent);
                //                println(fmt!("bridge: (%i,%i:%i->%i)-(%i,%i:%i->%i) : %f",src.x,src.y,src.color,src_parent,dest.x,dest.y,dest.color,dest_parent, e.cost));
                                println(fmt!("(%i,%i),(%i,%i):%f",src.x,src.y,dest.x,dest.y,e.cost));
                                bridges +=1;
                            }
                        }
                    }

                    // break when all of the supervertices have been connected
                    if bridges >= numnodes -1 {
                        break;
                    }
                },
                None => { break } // should not execute. break two lines above should do it
            }
        }
    }

}
<|endoftext|>