<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

use std::error::{Error};
use std::fmt::{Display, Formatter};

/// An error type for failures that occurred when receiving a message.
#[derive(Debug)]
pub enum ReadError {
    /// An I/O error occurred when reading from the input stream.
    Input(std::io::Error),
    /// An error occurred when decoding bytes of the proto message.
    Decode(prost::DecodeError),
    /// An error occurred because the decoded proto message was malformed.
    Malformed(Box<dyn Error + Send + Sync>),
    /// An invalid magic number has been read from the input stream.
    Magic(u32),
}

/// An error type for failures that occured when sending a message.
#[derive(Debug)]
pub enum WriteError {
    /// An I/O error occurred when writing to the output stream.
    Output(std::io::Error),
    /// An error occurred when encoding the proto message to bytes.
    Encode(prost::EncodeError),
}

impl ReadError {

    pub fn malformed<E>(err: E) -> ReadError
    where
        E: Into<Box<dyn Error + Send + Sync>>,
    {
        ReadError::Malformed(err.into())
    }
}

impl Display for ReadError {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        use ReadError::*;

        match *self {
            Input(ref err) => write!(fmt, "input error: {}", err),
            Decode(ref err) => write!(fmt, "proto decoding error: {}", err),
            Malformed(ref err) => write!(fmt, "malformed proto: {}", err),
            Magic(magic) => write!(fmt, "invalid magic: {}", magic),
        }
    }
}

impl Display for WriteError {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        use WriteError::*;

        match *self {
            Output(ref err) => write!(fmt, "output error: {}", err),
            Encode(ref err) => write!(fmt, "proto encoding error: {}", err),
        }
    }
}

impl Error for ReadError {

    fn source(&self) -> Option<&(dyn Error + 'static)> {
        use ReadError::*;

        match *self {
            Input(ref err) => Some(err),
            Decode(ref err) => Some(err),
            Malformed(ref err) => Some(err.as_ref()),
            Magic(_) => None,
        }
    }
}

impl Error for WriteError {

    fn source(&self) -> Option<&(dyn Error + 'static)> {
        use WriteError::*;

        match *self {
            Output(ref err) => Some(err),
            Encode(ref err) => Some(err),
        }
    }
}

impl From<std::io::Error> for ReadError {

    fn from(err: std::io::Error) -> ReadError {
        ReadError::Input(err)
    }
}

impl From<prost::DecodeError> for ReadError {

    fn from(err: prost::DecodeError) -> ReadError {
        ReadError::Decode(err)
    }
}

impl From<std::io::Error> for WriteError {

    fn from(err: std::io::Error) -> WriteError {
        WriteError::Output(err)
    }
}

impl From<prost::EncodeError> for WriteError {

    fn from(err: prost::EncodeError) -> WriteError {
        WriteError::Encode(err)
    }
}

impl From<ReadError> for std::io::Error {

    fn from(err: ReadError) -> std::io::Error {
        use ReadError::*;

        match err {
            Input(err) => err,
            Decode(err) => err.into(),
            Malformed(err) => {
                let err = format!("malformed proto: {}", err);
                std::io::Error::new(std::io::ErrorKind::InvalidData, err)
            },
            Magic(magic) => {
                let err = format!("invalid magic: {}", magic);
                std::io::Error::new(std::io::ErrorKind::InvalidData, err)
            },
        }
    }
}

impl From<WriteError> for std::io::Error {

    fn from(err: WriteError) -> std::io::Error {
        use WriteError::*;

        match err {
            Output(err) => err,
            Encode(err) => err.into(),
        }
    }
}
<commit_msg>Add a missing doc comment for one of the methods.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

use std::error::{Error};
use std::fmt::{Display, Formatter};

/// An error type for failures that occurred when receiving a message.
#[derive(Debug)]
pub enum ReadError {
    /// An I/O error occurred when reading from the input stream.
    Input(std::io::Error),
    /// An error occurred when decoding bytes of the proto message.
    Decode(prost::DecodeError),
    /// An error occurred because the decoded proto message was malformed.
    Malformed(Box<dyn Error + Send + Sync>),
    /// An invalid magic number has been read from the input stream.
    Magic(u32),
}

/// An error type for failures that occured when sending a message.
#[derive(Debug)]
pub enum WriteError {
    /// An I/O error occurred when writing to the output stream.
    Output(std::io::Error),
    /// An error occurred when encoding the proto message to bytes.
    Encode(prost::EncodeError),
}

impl ReadError {

    /// Converts an error indicating malformed proto message to `ReadError`.
    pub fn malformed<E>(err: E) -> ReadError
    where
        E: Into<Box<dyn Error + Send + Sync>>,
    {
        ReadError::Malformed(err.into())
    }
}

impl Display for ReadError {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        use ReadError::*;

        match *self {
            Input(ref err) => write!(fmt, "input error: {}", err),
            Decode(ref err) => write!(fmt, "proto decoding error: {}", err),
            Malformed(ref err) => write!(fmt, "malformed proto: {}", err),
            Magic(magic) => write!(fmt, "invalid magic: {}", magic),
        }
    }
}

impl Display for WriteError {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        use WriteError::*;

        match *self {
            Output(ref err) => write!(fmt, "output error: {}", err),
            Encode(ref err) => write!(fmt, "proto encoding error: {}", err),
        }
    }
}

impl Error for ReadError {

    fn source(&self) -> Option<&(dyn Error + 'static)> {
        use ReadError::*;

        match *self {
            Input(ref err) => Some(err),
            Decode(ref err) => Some(err),
            Malformed(ref err) => Some(err.as_ref()),
            Magic(_) => None,
        }
    }
}

impl Error for WriteError {

    fn source(&self) -> Option<&(dyn Error + 'static)> {
        use WriteError::*;

        match *self {
            Output(ref err) => Some(err),
            Encode(ref err) => Some(err),
        }
    }
}

impl From<std::io::Error> for ReadError {

    fn from(err: std::io::Error) -> ReadError {
        ReadError::Input(err)
    }
}

impl From<prost::DecodeError> for ReadError {

    fn from(err: prost::DecodeError) -> ReadError {
        ReadError::Decode(err)
    }
}

impl From<std::io::Error> for WriteError {

    fn from(err: std::io::Error) -> WriteError {
        WriteError::Output(err)
    }
}

impl From<prost::EncodeError> for WriteError {

    fn from(err: prost::EncodeError) -> WriteError {
        WriteError::Encode(err)
    }
}

impl From<ReadError> for std::io::Error {

    fn from(err: ReadError) -> std::io::Error {
        use ReadError::*;

        match err {
            Input(err) => err,
            Decode(err) => err.into(),
            Malformed(err) => {
                let err = format!("malformed proto: {}", err);
                std::io::Error::new(std::io::ErrorKind::InvalidData, err)
            },
            Magic(magic) => {
                let err = format!("invalid magic: {}", magic);
                std::io::Error::new(std::io::ErrorKind::InvalidData, err)
            },
        }
    }
}

impl From<WriteError> for std::io::Error {

    fn from(err: WriteError) -> std::io::Error {
        use WriteError::*;

        match err {
            Output(err) => err,
            Encode(err) => err.into(),
        }
    }
}
<|endoftext|>


<commit_before>use super::{Clock, Reference, Relative};
use crate::lib::*;

/// A mock implementation of a clock. All it does is keep track of
/// what "now" is (relative to some point meaningful to the program),
/// and returns that.
#[derive(Debug, PartialEq, Clone)]
pub struct FakeClock {
    now: Duration,
}

impl Default for FakeClock {
    fn default() -> Self {
        FakeClock {
            Duration::from_nanos(0)
        }
    }
}

impl FakeClock {
    /// Advances the fake clock by the given amount.
    pub fn advance(&mut self, by: Duration) {
        self.now += by
    }
}

impl Clock for FakeClock {
    type Instant = Duration;
    type Duration = Duration;

    fn now(&self) -> Self::Instant {
        self.now
    }
}
<commit_msg>Hopefully fix no_std tests too<commit_after>use super::{Clock, Reference, Relative};
use crate::lib::*;

/// A mock implementation of a clock. All it does is keep track of
/// what "now" is (relative to some point meaningful to the program),
/// and returns that.
#[derive(Debug, PartialEq, Clone)]
pub struct FakeClock {
    now: Duration,
}

impl Default for FakeClock {
    fn default() -> Self {
        FakeClock {
            now: Duration::from_nanos(0),
        }
    }
}

impl FakeClock {
    /// Advances the fake clock by the given amount.
    pub fn advance(&mut self, by: Duration) {
        self.now += by
    }
}

impl Clock for FakeClock {
    type Instant = Duration;
    type Duration = Duration;

    fn now(&self) -> Self::Instant {
        self.now
    }
}
<|endoftext|>


<commit_before>//! This module implements the root command of the CLI tool.

use std::io;
use std::io::Write;
use std::env;
use std::process;

use log;
use clap::{Arg, App, AppSettings};

use prelude::*;
use constants::VERSION;
use utils::Logger;
use config::{Config, Auth};

const ABOUT: &'static str = "
Command line utility for Sentry.

This tool helps you managing remote resources on a Sentry server like
sourcemaps, debug symbols, releases or similar.  Use `--help` on the
subcommands to learn more about them.";

macro_rules! each_subcommand {
    ($mac:ident) => {
        $mac!(upload_dsym);
        $mac!(releases);
        $mac!(issues);
        $mac!(update);
        $mac!(uninstall);
        $mac!(info);
        $mac!(login);
        $mac!(send_event);
        #[cfg(target_os="macos")]
        $mac!(react_native_xcode);
    }
}

// it would be great if this could be a macro expansion as well
// but rust bug #37663 breaks location information then.
pub mod upload_dsym;
pub mod releases;
pub mod issues;
pub mod update;
pub mod uninstall;
pub mod info;
pub mod login;
pub mod send_event;

#[cfg(target_os="macos")]
pub mod react_native_xcode;

fn preexecute_hooks() -> Result<()> {
    sentry_react_native_xcode_wrap()?;

    return Ok(());

    #[cfg(target_os="macos")]
    fn sentry_react_native_xcode_wrap() -> Result<()> {
        if let Ok(val) = env::var("__SENTRY_RN_WRAP_XCODE_CALL") {
            env::remove_var("__SENTRY_RN_WRAP_XCODE_CALL");
            if &val == "1" {
                return react_native_xcode::wrap_call();
            }
        }
        Ok(())
    }

    #[cfg(not(target_os="macos"))]
    fn sentry_react_native_xcode_wrap() -> Result<()> {
        Ok(())
    }
}

/// Given an argument vector and a `Config` this executes the
/// command line and returns the result.
pub fn execute(args: Vec<String>, config: &mut Config) -> Result<()> {
    // special case for the xcode integration for react native.  For more
    // information see commands/react_native_xcode.rs
    preexecute_hooks()?;

    let mut app = App::new("sentry-cli")
        .version(VERSION)
        .about(ABOUT)
        .max_term_width(100)
        .setting(AppSettings::VersionlessSubcommands)
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .global_setting(AppSettings::UnifiedHelpMessage)
        .arg(Arg::with_name("url")
            .value_name("URL")
            .long("url")
            .help("The sentry API URL{n}defaults to https://sentry.io/"))
        .arg(Arg::with_name("auth_token")
            .value_name("AUTH_TOKEN")
            .long("auth-token")
            .help("The sentry auth token to use"))
        .arg(Arg::with_name("api_key")
            .value_name("API_KEY")
            .long("api-key")
            .help("The sentry API key to use"))
        .arg(Arg::with_name("log_level")
            .value_name("LOG_LEVEL")
            .long("log-level")
            .help("The log level for sentry-cli{n}\
                   (valid levels: TRACE, DEBUG, INFO, WARN, ERROR)"));

    macro_rules! add_subcommand {
        ($name:ident) => {{
            app = app.subcommand($name::make_app(
                App::new(stringify!($name).replace("_", "-").as_str())));
        }}
    }
    each_subcommand!(add_subcommand);

    let matches = app.get_matches_from_safe(args)?;

    if let Some(url) = matches.value_of("url") {
        config.url = url.to_owned();
    }
    if let Some(api_key) = matches.value_of("api_key") {
        config.auth = Some(Auth::Key(api_key.to_owned()));
    }
    if let Some(auth_token) = matches.value_of("auth_token") {
        config.auth = Some(Auth::Token(auth_token.to_owned()));
    }
    if let Some(level_str) = matches.value_of("log_level") {
        match level_str.parse() {
            Ok(level) => {
                config.log_level = level;
            }
            Err(_) => {
                fail!("Unknown log level: {}", level_str);
            }
        }
    }

    log::set_logger(|max_log_level| {
            max_log_level.set(config.log_level);
            Box::new(Logger)
        })
        .ok();

    macro_rules! execute_subcommand {
        ($name:ident) => {{
            let cmd = stringify!($name).replace("_", "-");
            if let Some(sub_matches) = matches.subcommand_matches(cmd) {
                return Ok($name::execute(&sub_matches, &config)?);
            }
        }}
    }
    each_subcommand!(execute_subcommand);
    unreachable!();
}

fn run() -> Result<()> {
    execute(env::args().collect(), &mut Config::from_cli_config()?)
}

/// Executes the command line application and exists the process.
pub fn main() {
    match run() {
        Ok(()) => process::exit(0),
        Err(err) => {
            if let &ErrorKind::Clap(ref clap_err) = err.kind() {
                clap_err.exit();
            }

            writeln!(&mut io::stderr(), "error: {}", err).ok();

            if env::var("RUST_BACKTRACE") == Ok("1".into()) {
                writeln!(&mut io::stderr(), "").ok();
                writeln!(&mut io::stderr(), "{:?}", err.backtrace()).ok();
            }

            process::exit(1);
        }
    }
}
<commit_msg>Make sentry-cli not report unnecessary failures on wrapping node<commit_after>//! This module implements the root command of the CLI tool.

use std::io;
use std::io::Write;
use std::env;
use std::process;

use log;
use clap::{Arg, App, AppSettings};

use prelude::*;
use constants::VERSION;
use utils::Logger;
use config::{Config, Auth};

const ABOUT: &'static str = "
Command line utility for Sentry.

This tool helps you managing remote resources on a Sentry server like
sourcemaps, debug symbols, releases or similar.  Use `--help` on the
subcommands to learn more about them.";

macro_rules! each_subcommand {
    ($mac:ident) => {
        $mac!(upload_dsym);
        $mac!(releases);
        $mac!(issues);
        $mac!(update);
        $mac!(uninstall);
        $mac!(info);
        $mac!(login);
        $mac!(send_event);
        #[cfg(target_os="macos")]
        $mac!(react_native_xcode);
    }
}

// it would be great if this could be a macro expansion as well
// but rust bug #37663 breaks location information then.
pub mod upload_dsym;
pub mod releases;
pub mod issues;
pub mod update;
pub mod uninstall;
pub mod info;
pub mod login;
pub mod send_event;

#[cfg(target_os="macos")]
pub mod react_native_xcode;

fn preexecute_hooks() -> Result<bool> {
    return sentry_react_native_xcode_wrap();

    #[cfg(target_os="macos")]
    fn sentry_react_native_xcode_wrap() -> Result<bool> {
        if let Ok(val) = env::var("__SENTRY_RN_WRAP_XCODE_CALL") {
            env::remove_var("__SENTRY_RN_WRAP_XCODE_CALL");
            if &val == "1" {
                react_native_xcode::wrap_call()?;
                return Ok(true);
            }
        }
        Ok(false)
    }

    #[cfg(not(target_os="macos"))]
    fn sentry_react_native_xcode_wrap() -> Result<bool> {
        Ok(false)
    }
}

/// Given an argument vector and a `Config` this executes the
/// command line and returns the result.
pub fn execute(args: Vec<String>, config: &mut Config) -> Result<()> {
    // special case for the xcode integration for react native.  For more
    // information see commands/react_native_xcode.rs
    if preexecute_hooks()? {
        return Ok(());
    }

    let mut app = App::new("sentry-cli")
        .version(VERSION)
        .about(ABOUT)
        .max_term_width(100)
        .setting(AppSettings::VersionlessSubcommands)
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .global_setting(AppSettings::UnifiedHelpMessage)
        .arg(Arg::with_name("url")
            .value_name("URL")
            .long("url")
            .help("The sentry API URL{n}defaults to https://sentry.io/"))
        .arg(Arg::with_name("auth_token")
            .value_name("AUTH_TOKEN")
            .long("auth-token")
            .help("The sentry auth token to use"))
        .arg(Arg::with_name("api_key")
            .value_name("API_KEY")
            .long("api-key")
            .help("The sentry API key to use"))
        .arg(Arg::with_name("log_level")
            .value_name("LOG_LEVEL")
            .long("log-level")
            .help("The log level for sentry-cli{n}\
                   (valid levels: TRACE, DEBUG, INFO, WARN, ERROR)"));

    macro_rules! add_subcommand {
        ($name:ident) => {{
            app = app.subcommand($name::make_app(
                App::new(stringify!($name).replace("_", "-").as_str())));
        }}
    }
    each_subcommand!(add_subcommand);

    let matches = app.get_matches_from_safe(args)?;

    if let Some(url) = matches.value_of("url") {
        config.url = url.to_owned();
    }
    if let Some(api_key) = matches.value_of("api_key") {
        config.auth = Some(Auth::Key(api_key.to_owned()));
    }
    if let Some(auth_token) = matches.value_of("auth_token") {
        config.auth = Some(Auth::Token(auth_token.to_owned()));
    }
    if let Some(level_str) = matches.value_of("log_level") {
        match level_str.parse() {
            Ok(level) => {
                config.log_level = level;
            }
            Err(_) => {
                fail!("Unknown log level: {}", level_str);
            }
        }
    }

    log::set_logger(|max_log_level| {
            max_log_level.set(config.log_level);
            Box::new(Logger)
        })
        .ok();

    macro_rules! execute_subcommand {
        ($name:ident) => {{
            let cmd = stringify!($name).replace("_", "-");
            if let Some(sub_matches) = matches.subcommand_matches(cmd) {
                return Ok($name::execute(&sub_matches, &config)?);
            }
        }}
    }
    each_subcommand!(execute_subcommand);
    unreachable!();
}

fn run() -> Result<()> {
    execute(env::args().collect(), &mut Config::from_cli_config()?)
}

/// Executes the command line application and exists the process.
pub fn main() {
    match run() {
        Ok(()) => process::exit(0),
        Err(err) => {
            if let &ErrorKind::Clap(ref clap_err) = err.kind() {
                clap_err.exit();
            }

            writeln!(&mut io::stderr(), "error: {}", err).ok();

            if env::var("RUST_BACKTRACE") == Ok("1".into()) {
                writeln!(&mut io::stderr(), "").ok();
                writeln!(&mut io::stderr(), "{:?}", err.backtrace()).ok();
            }

            process::exit(1);
        }
    }
}
<|endoftext|>


<commit_before>//! # The Redox OS Kernel, version 2
//!
//! The Redox OS Kernel is a hybrid kernel that supports X86 systems and
//! provides Unix-like syscalls for primarily Rust applications
//!
//! ## Syscalls
//! Syscalls in Redox are often handled by userspace `schemes`.
//! The essential syscalls in Redox are as follows:
//!
//! ### Open
//! `open(path: &str, flags: usize) -> Result<file_descriptor: usize>`
//!
//! Open a file, providing a path as a `&str` and flags, defined elsewhere.
//!
//! Returns a number, known as a file descriptor, that is passed to other syscalls
//!
//! ### Close
//! `close(file_descriptor: usize) -> Result<()>`
//!
//! Close a file descriptor, providing the file descriptor from `open`
//!
//! Returns an error, `EBADF`, if the file descriptor was not found.
//!
//! This potential error is often ignored by userspace
//!
//! ### Duplicate
//! `dup(file_descriptor: usize) -> Result<file_descriptor: usize>`
//!
//! Duplicate a file descriptor, providing the file descriptor from `open`
//!
//! Returns a new file descriptor, or an error
//!
//! ### Read
//! `read(file_descriptor: usize, buffer: &mut [u8]) -> Result<count: usize>`
//!
//! Read from a file descriptor, providing the file descriptor from `open` and a mutable buffer
//!
//! Returns the number of bytes actually read, or an error
//!
//! ### Write
//! `write(file_descriptor: usize, buffer: &[u8]) -> Result<count: usize>`
//!
//! Write to a file descriptor, providing the file descriptor from `open` and a const buffer
//!
//! Returns the number of bytes actually written, or an error
//!
//! ### Stat
//! `fstat(file_descriptor: usize, stat: &mut Stat) -> Result<()>`
//!
//! Get information from a file descriptor, providing the file descriptor from `open`
//! and a mutable Stat struct, defined elsewhere.
//!
//! Returns an error if the operation failed
//!
//! ### Path
//! `fpath(file_descriptor: usize, buffer: &mut [u8]) -> Result<count: usize>`
//!
//! Read the path of a file descriptor, providing the file descriptor from `open` and
//! a mutable buffer.
//!
//! Returns the number of bytes actually read, or an error
//!
//! The buffer should be 4096 bytes, to ensure that the entire path will fit.
//! An error will be returned, `ENOBUFS`, if the buffer is not long enough for the name.
//! In this case, it is recommended to add one page, 4096 bytes, to the buffer and retry.

#![feature(alloc)]
#![feature(collections)]
#![feature(const_fn)]
#![feature(question_mark)]
#![no_std]

use arch::interrupt::{enable_interrupts, halt};

/// Architecture specific items (test)
#[cfg(test)]
#[macro_use]
extern crate arch_test as arch;

/// Architecture specific items (x86_64)
#[cfg(all(not(test), target_arch = "x86_64"))]
#[macro_use]
extern crate arch_x86_64 as arch;

extern crate alloc;
#[macro_use]
extern crate collections;

#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate lazy_static;
extern crate spin;

/// Context management
pub mod context;

/// Schemes, filesystem handlers
pub mod scheme;

/// Syscall handlers
pub mod syscall;

/// Tests
#[cfg(test)]
pub mod tests;

#[no_mangle]
pub extern fn kmain() {
    println!("TEST");

    println!("{:?}", syscall::open(b"debug:", 0));
    println!("{:?}", syscall::open(b"debug:", 0));
    println!("{:?}", syscall::open(b"debug:", 0));

    loop {
        unsafe {
            enable_interrupts();
            halt();
        }
        println!("{:?}", syscall::write(1, b"HALT\n"));
    }
}
<commit_msg>Keep track of AP count, allocate bigger AP stack, stack trace function<commit_after>//! # The Redox OS Kernel, version 2
//!
//! The Redox OS Kernel is a hybrid kernel that supports X86 systems and
//! provides Unix-like syscalls for primarily Rust applications
//!
//! ## Syscalls
//! Syscalls in Redox are often handled by userspace `schemes`.
//! The essential syscalls in Redox are as follows:
//!
//! ### Open
//! `open(path: &str, flags: usize) -> Result<file_descriptor: usize>`
//!
//! Open a file, providing a path as a `&str` and flags, defined elsewhere.
//!
//! Returns a number, known as a file descriptor, that is passed to other syscalls
//!
//! ### Close
//! `close(file_descriptor: usize) -> Result<()>`
//!
//! Close a file descriptor, providing the file descriptor from `open`
//!
//! Returns an error, `EBADF`, if the file descriptor was not found.
//!
//! This potential error is often ignored by userspace
//!
//! ### Duplicate
//! `dup(file_descriptor: usize) -> Result<file_descriptor: usize>`
//!
//! Duplicate a file descriptor, providing the file descriptor from `open`
//!
//! Returns a new file descriptor, or an error
//!
//! ### Read
//! `read(file_descriptor: usize, buffer: &mut [u8]) -> Result<count: usize>`
//!
//! Read from a file descriptor, providing the file descriptor from `open` and a mutable buffer
//!
//! Returns the number of bytes actually read, or an error
//!
//! ### Write
//! `write(file_descriptor: usize, buffer: &[u8]) -> Result<count: usize>`
//!
//! Write to a file descriptor, providing the file descriptor from `open` and a const buffer
//!
//! Returns the number of bytes actually written, or an error
//!
//! ### Stat
//! `fstat(file_descriptor: usize, stat: &mut Stat) -> Result<()>`
//!
//! Get information from a file descriptor, providing the file descriptor from `open`
//! and a mutable Stat struct, defined elsewhere.
//!
//! Returns an error if the operation failed
//!
//! ### Path
//! `fpath(file_descriptor: usize, buffer: &mut [u8]) -> Result<count: usize>`
//!
//! Read the path of a file descriptor, providing the file descriptor from `open` and
//! a mutable buffer.
//!
//! Returns the number of bytes actually read, or an error
//!
//! The buffer should be 4096 bytes, to ensure that the entire path will fit.
//! An error will be returned, `ENOBUFS`, if the buffer is not long enough for the name.
//! In this case, it is recommended to add one page, 4096 bytes, to the buffer and retry.

#![feature(alloc)]
#![feature(collections)]
#![feature(const_fn)]
#![feature(question_mark)]
#![no_std]

use arch::interrupt;

/// Architecture specific items (test)
#[cfg(test)]
#[macro_use]
extern crate arch_test as arch;

/// Architecture specific items (x86_64)
#[cfg(all(not(test), target_arch = "x86_64"))]
#[macro_use]
extern crate arch_x86_64 as arch;

extern crate alloc;
#[macro_use]
extern crate collections;

#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate lazy_static;
extern crate spin;

/// Context management
pub mod context;

/// Schemes, filesystem handlers
pub mod scheme;

/// Syscall handlers
pub mod syscall;

/// Tests
#[cfg(test)]
pub mod tests;

#[no_mangle]
pub extern fn kmain() {
    loop {
        unsafe { interrupt::enable_and_halt(); }
        print!("HALT\n");
    }
}
<|endoftext|>


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

use std::cell::RefCell;
use std::sync::Arc;
use std::{fs, path};

use failure::ResultExt;
use uuid::Uuid;

use keychain::{Identifier, Keychain};
use store::{self, option_to_not_found, to_key, u64_to_key};

use libwallet::types::*;
use libwallet::{internal, Error, ErrorKind};
use types::{WalletConfig, WalletSeed};
use util::secp::pedersen;

pub const DB_DIR: &'static str = "wallet_data";

const COMMITMENT_PREFIX: u8 = 'c' as u8;
const OUTPUT_PREFIX: u8 = 'o' as u8;
const DERIV_PREFIX: u8 = 'd' as u8;
const CONFIRMED_HEIGHT_PREFIX: u8 = 'c' as u8;
const TX_LOG_ENTRY_PREFIX: u8 = 't' as u8;
const TX_LOG_ID_PREFIX: u8 = 'i' as u8;

impl From<store::Error> for Error {
	fn from(error: store::Error) -> Error {
		Error::from(ErrorKind::Backend(format!("{:?}", error)))
	}
}

/// test to see if database files exist in the current directory. If so,
/// use a DB backend for all operations
pub fn wallet_db_exists(config: WalletConfig) -> bool {
	let db_path = path::Path::new(&config.data_file_dir).join(DB_DIR);
	db_path.exists()
}

pub struct LMDBBackend<C, K> {
	db: store::Store,
	config: WalletConfig,
	/// passphrase: TODO better ways of dealing with this other than storing
	passphrase: String,
	/// Keychain
	keychain: Option<K>,
	/// client
	client: C,
}

impl<C, K> LMDBBackend<C, K> {
	pub fn new(config: WalletConfig, passphrase: &str, client: C) -> Result<Self, Error> {
		let db_path = path::Path::new(&config.data_file_dir).join(DB_DIR);
		fs::create_dir_all(&db_path).expect("Couldn't create wallet backend directory!");

		let lmdb_env = Arc::new(store::new_env(db_path.to_str().unwrap().to_string()));
		let db = store::Store::open(lmdb_env, DB_DIR);
		Ok(LMDBBackend {
			db,
			config: config.clone(),
			passphrase: String::from(passphrase),
			keychain: None,
			client: client,
		})
	}

	/// Just test to see if database files exist in the current directory. If
	/// so, use a DB backend for all operations
	pub fn exists(config: WalletConfig) -> bool {
		let db_path = path::Path::new(&config.data_file_dir).join(DB_DIR);
		db_path.exists()
	}
}

impl<C, K> WalletBackend<C, K> for LMDBBackend<C, K>
where
	C: WalletClient,
	K: Keychain,
{
	/// Initialise with whatever stored credentials we have
	fn open_with_credentials(&mut self) -> Result<(), Error> {
		let wallet_seed = WalletSeed::from_file(&self.config)
			.context(ErrorKind::CallbackImpl("Error opening wallet"))?;
		let keychain = wallet_seed.derive_keychain(&self.passphrase);
		self.keychain = Some(keychain.context(ErrorKind::CallbackImpl("Error deriving keychain"))?);
		// Just blow up password for now after it's been used
		self.passphrase = String::from("");
		Ok(())
	}

	/// Close wallet and remove any stored credentials (TBD)
	fn close(&mut self) -> Result<(), Error> {
		self.keychain = None;
		Ok(())
	}

	/// Return the keychain being used
	fn keychain(&mut self) -> &mut K {
		self.keychain.as_mut().unwrap()
	}

	/// Return the client being used
	fn client(&mut self) -> &mut C {
		&mut self.client
	}

	fn get(&self, id: &Identifier) -> Result<OutputData, Error> {
		let key = to_key(OUTPUT_PREFIX, &mut id.to_bytes().to_vec());
		option_to_not_found(self.db.get_ser(&key), &format!("Key Id: {}", id)).map_err(|e| e.into())
	}

	fn get_commitment(&mut self, id: &Identifier) -> Result<pedersen::Commitment, Error> {
		let key = to_key(COMMITMENT_PREFIX, &mut id.to_bytes().to_vec());

		let res: Result<pedersen::Commitment, Error> =
			option_to_not_found(self.db.get_ser(&key), &format!("Key Id: {}", id))
				.map_err(|e| e.into());

		// "cache hit" and return the commitment
		if let Ok(commit) = res {
			Ok(commit)
		} else {
			let out = self.get(id)?;

			// Save the output data back to the db
			// which builds and saves the associated commitment.
			{
				let mut batch = self.batch()?;
				batch.save(out)?;
				batch.commit()?;
			}

			// Now retrieve the saved commitment and return it.
			option_to_not_found(self.db.get_ser(&key), &format!("Key Id: {}", id))
				.map_err(|e| e.into())
		}
	}

	fn iter<'a>(&'a self) -> Box<Iterator<Item = OutputData> + 'a> {
		Box::new(self.db.iter(&[OUTPUT_PREFIX]).unwrap())
	}

	fn get_tx_log_entry(&self, u: &Uuid) -> Result<Option<TxLogEntry>, Error> {
		let key = to_key(TX_LOG_ENTRY_PREFIX, &mut u.as_bytes().to_vec());
		self.db.get_ser(&key).map_err(|e| e.into())
	}

	fn tx_log_iter<'a>(&'a self) -> Box<Iterator<Item = TxLogEntry> + 'a> {
		Box::new(self.db.iter(&[TX_LOG_ENTRY_PREFIX]).unwrap())
	}

	fn batch<'a>(&'a mut self) -> Result<Box<WalletOutputBatch<K> + 'a>, Error> {
		Ok(Box::new(Batch {
			_store: self,
			db: RefCell::new(Some(self.db.batch()?)),
			keychain: self.keychain.clone(),
		}))
	}

	fn next_child<'a>(&mut self, root_key_id: Identifier) -> Result<u32, Error> {
		let mut details = self.details(root_key_id.clone())?;
		let mut batch = self.batch()?;
		details.last_child_index = details.last_child_index + 1;
		batch.save_details(root_key_id, details.clone())?;
		batch.commit()?;
		Ok(details.last_child_index + 1)
	}

	fn details(&mut self, root_key_id: Identifier) -> Result<WalletDetails, Error> {
		let batch = self.db.batch()?;
		let deriv_key = to_key(DERIV_PREFIX, &mut root_key_id.to_bytes().to_vec());
		let deriv_idx = match batch.get_ser(&deriv_key)? {
			Some(idx) => idx,
			None => 0,
		};
		let height_key = to_key(
			CONFIRMED_HEIGHT_PREFIX,
			&mut root_key_id.to_bytes().to_vec(),
		);
		let last_confirmed_height = match batch.get_ser(&height_key)? {
			Some(h) => h,
			None => 0,
		};
		Ok(WalletDetails {
			last_child_index: deriv_idx,
			last_confirmed_height: last_confirmed_height,
		})
	}

	fn restore(&mut self) -> Result<(), Error> {
		internal::restore::restore(self).context(ErrorKind::Restore)?;
		Ok(())
	}
}

/// An atomic batch in which all changes can be committed all at once or
/// discarded on error.
pub struct Batch<'a, C: 'a, K: 'a>
where
	C: WalletClient,
	K: Keychain,
{
	_store: &'a LMDBBackend<C, K>,
	db: RefCell<Option<store::Batch<'a>>>,
	/// Keychain
	keychain: Option<K>,
}

#[allow(missing_docs)]
impl<'a, C, K> WalletOutputBatch<K> for Batch<'a, C, K>
where
	C: WalletClient,
	K: Keychain,
{
	fn keychain(&mut self) -> &mut K {
		self.keychain.as_mut().unwrap()
	}

	fn save(&mut self, out: OutputData) -> Result<(), Error> {
		// Save the output data to the db.
		{
			let key = to_key(OUTPUT_PREFIX, &mut out.key_id.to_bytes().to_vec());
			self.db.borrow().as_ref().unwrap().put_ser(&key, &out)?;
		}

		// Save the associated output commitment.
		{
			let key = to_key(COMMITMENT_PREFIX, &mut out.key_id.to_bytes().to_vec());
			let commit = self.keychain().commit(out.value, &out.key_id)?;
			self.db.borrow().as_ref().unwrap().put_ser(&key, &commit)?;
		}

		Ok(())
	}

	fn get(&self, id: &Identifier) -> Result<OutputData, Error> {
		let key = to_key(OUTPUT_PREFIX, &mut id.to_bytes().to_vec());
		option_to_not_found(
			self.db.borrow().as_ref().unwrap().get_ser(&key),
			&format!("Key ID: {}", id),
		).map_err(|e| e.into())
	}

	fn iter(&self) -> Box<Iterator<Item = OutputData>> {
		Box::new(
			self.db
				.borrow()
				.as_ref()
				.unwrap()
				.iter(&[OUTPUT_PREFIX])
				.unwrap(),
		)
	}

	fn delete(&mut self, id: &Identifier) -> Result<(), Error> {
		// Delete the output data.
		{
			let key = to_key(OUTPUT_PREFIX, &mut id.to_bytes().to_vec());
			let _ = self.db.borrow().as_ref().unwrap().delete(&key);
		}

		// Delete the associated output commitment.
		{
			let key = to_key(COMMITMENT_PREFIX, &mut id.to_bytes().to_vec());
			let _ = self.db.borrow().as_ref().unwrap().delete(&key);
		}

		Ok(())
	}

	fn next_tx_log_id(&mut self, root_key_id: Identifier) -> Result<u32, Error> {
		let tx_id_key = to_key(TX_LOG_ID_PREFIX, &mut root_key_id.to_bytes().to_vec());
		let mut last_tx_log_id = match self.db.borrow().as_ref().unwrap().get_ser(&tx_id_key)? {
			Some(t) => t,
			None => 0,
		};
		last_tx_log_id = last_tx_log_id + 1;
		self.db
			.borrow()
			.as_ref()
			.unwrap()
			.put_ser(&tx_id_key, &last_tx_log_id)?;
		Ok(last_tx_log_id)
	}

	fn tx_log_iter(&self) -> Box<Iterator<Item = TxLogEntry>> {
		Box::new(
			self.db
				.borrow()
				.as_ref()
				.unwrap()
				.iter(&[TX_LOG_ENTRY_PREFIX])
				.unwrap(),
		)
	}

	fn save_details(&mut self, root_key_id: Identifier, d: WalletDetails) -> Result<(), Error> {
		let deriv_key = to_key(DERIV_PREFIX, &mut root_key_id.to_bytes().to_vec());
		let height_key = to_key(
			CONFIRMED_HEIGHT_PREFIX,
			&mut root_key_id.to_bytes().to_vec(),
		);
		self.db
			.borrow()
			.as_ref()
			.unwrap()
			.put_ser(&deriv_key, &d.last_child_index)?;
		self.db
			.borrow()
			.as_ref()
			.unwrap()
			.put_ser(&height_key, &d.last_confirmed_height)?;
		Ok(())
	}

	fn save_tx_log_entry(&self, t: TxLogEntry) -> Result<(), Error> {
		let tx_log_key = u64_to_key(TX_LOG_ENTRY_PREFIX, t.id as u64);
		self.db.borrow().as_ref().unwrap().put_ser(&tx_log_key, &t)?;
		Ok(())
	}

	fn lock_output(&mut self, out: &mut OutputData) -> Result<(), Error> {
		out.lock();
		self.save(out.clone())
	}

	fn commit(&self) -> Result<(), Error> {
		let db = self.db.replace(None);
		db.unwrap().commit()?;
		Ok(())
	}
}
<commit_msg>minor fix: prefix code conflict between 'COMMITMENT_PREFIX' and 'CONFIRMED_HEIGHT_PREFIX' (#1375)<commit_after>// Copyright 2018 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::cell::RefCell;
use std::sync::Arc;
use std::{fs, path};

use failure::ResultExt;
use uuid::Uuid;

use keychain::{Identifier, Keychain};
use store::{self, option_to_not_found, to_key, u64_to_key};

use libwallet::types::*;
use libwallet::{internal, Error, ErrorKind};
use types::{WalletConfig, WalletSeed};
use util::secp::pedersen;

pub const DB_DIR: &'static str = "wallet_data";

const COMMITMENT_PREFIX: u8 = 'C' as u8;
const OUTPUT_PREFIX: u8 = 'o' as u8;
const DERIV_PREFIX: u8 = 'd' as u8;
const CONFIRMED_HEIGHT_PREFIX: u8 = 'c' as u8;
const TX_LOG_ENTRY_PREFIX: u8 = 't' as u8;
const TX_LOG_ID_PREFIX: u8 = 'i' as u8;

impl From<store::Error> for Error {
	fn from(error: store::Error) -> Error {
		Error::from(ErrorKind::Backend(format!("{:?}", error)))
	}
}

/// test to see if database files exist in the current directory. If so,
/// use a DB backend for all operations
pub fn wallet_db_exists(config: WalletConfig) -> bool {
	let db_path = path::Path::new(&config.data_file_dir).join(DB_DIR);
	db_path.exists()
}

pub struct LMDBBackend<C, K> {
	db: store::Store,
	config: WalletConfig,
	/// passphrase: TODO better ways of dealing with this other than storing
	passphrase: String,
	/// Keychain
	keychain: Option<K>,
	/// client
	client: C,
}

impl<C, K> LMDBBackend<C, K> {
	pub fn new(config: WalletConfig, passphrase: &str, client: C) -> Result<Self, Error> {
		let db_path = path::Path::new(&config.data_file_dir).join(DB_DIR);
		fs::create_dir_all(&db_path).expect("Couldn't create wallet backend directory!");

		let lmdb_env = Arc::new(store::new_env(db_path.to_str().unwrap().to_string()));
		let db = store::Store::open(lmdb_env, DB_DIR);
		Ok(LMDBBackend {
			db,
			config: config.clone(),
			passphrase: String::from(passphrase),
			keychain: None,
			client: client,
		})
	}

	/// Just test to see if database files exist in the current directory. If
	/// so, use a DB backend for all operations
	pub fn exists(config: WalletConfig) -> bool {
		let db_path = path::Path::new(&config.data_file_dir).join(DB_DIR);
		db_path.exists()
	}
}

impl<C, K> WalletBackend<C, K> for LMDBBackend<C, K>
where
	C: WalletClient,
	K: Keychain,
{
	/// Initialise with whatever stored credentials we have
	fn open_with_credentials(&mut self) -> Result<(), Error> {
		let wallet_seed = WalletSeed::from_file(&self.config)
			.context(ErrorKind::CallbackImpl("Error opening wallet"))?;
		let keychain = wallet_seed.derive_keychain(&self.passphrase);
		self.keychain = Some(keychain.context(ErrorKind::CallbackImpl("Error deriving keychain"))?);
		// Just blow up password for now after it's been used
		self.passphrase = String::from("");
		Ok(())
	}

	/// Close wallet and remove any stored credentials (TBD)
	fn close(&mut self) -> Result<(), Error> {
		self.keychain = None;
		Ok(())
	}

	/// Return the keychain being used
	fn keychain(&mut self) -> &mut K {
		self.keychain.as_mut().unwrap()
	}

	/// Return the client being used
	fn client(&mut self) -> &mut C {
		&mut self.client
	}

	fn get(&self, id: &Identifier) -> Result<OutputData, Error> {
		let key = to_key(OUTPUT_PREFIX, &mut id.to_bytes().to_vec());
		option_to_not_found(self.db.get_ser(&key), &format!("Key Id: {}", id)).map_err(|e| e.into())
	}

	fn get_commitment(&mut self, id: &Identifier) -> Result<pedersen::Commitment, Error> {
		let key = to_key(COMMITMENT_PREFIX, &mut id.to_bytes().to_vec());

		let res: Result<pedersen::Commitment, Error> =
			option_to_not_found(self.db.get_ser(&key), &format!("Key Id: {}", id))
				.map_err(|e| e.into());

		// "cache hit" and return the commitment
		if let Ok(commit) = res {
			Ok(commit)
		} else {
			let out = self.get(id)?;

			// Save the output data back to the db
			// which builds and saves the associated commitment.
			{
				let mut batch = self.batch()?;
				batch.save(out)?;
				batch.commit()?;
			}

			// Now retrieve the saved commitment and return it.
			option_to_not_found(self.db.get_ser(&key), &format!("Key Id: {}", id))
				.map_err(|e| e.into())
		}
	}

	fn iter<'a>(&'a self) -> Box<Iterator<Item = OutputData> + 'a> {
		Box::new(self.db.iter(&[OUTPUT_PREFIX]).unwrap())
	}

	fn get_tx_log_entry(&self, u: &Uuid) -> Result<Option<TxLogEntry>, Error> {
		let key = to_key(TX_LOG_ENTRY_PREFIX, &mut u.as_bytes().to_vec());
		self.db.get_ser(&key).map_err(|e| e.into())
	}

	fn tx_log_iter<'a>(&'a self) -> Box<Iterator<Item = TxLogEntry> + 'a> {
		Box::new(self.db.iter(&[TX_LOG_ENTRY_PREFIX]).unwrap())
	}

	fn batch<'a>(&'a mut self) -> Result<Box<WalletOutputBatch<K> + 'a>, Error> {
		Ok(Box::new(Batch {
			_store: self,
			db: RefCell::new(Some(self.db.batch()?)),
			keychain: self.keychain.clone(),
		}))
	}

	fn next_child<'a>(&mut self, root_key_id: Identifier) -> Result<u32, Error> {
		let mut details = self.details(root_key_id.clone())?;
		let mut batch = self.batch()?;
		details.last_child_index = details.last_child_index + 1;
		batch.save_details(root_key_id, details.clone())?;
		batch.commit()?;
		Ok(details.last_child_index + 1)
	}

	fn details(&mut self, root_key_id: Identifier) -> Result<WalletDetails, Error> {
		let batch = self.db.batch()?;
		let deriv_key = to_key(DERIV_PREFIX, &mut root_key_id.to_bytes().to_vec());
		let deriv_idx = match batch.get_ser(&deriv_key)? {
			Some(idx) => idx,
			None => 0,
		};
		let height_key = to_key(
			CONFIRMED_HEIGHT_PREFIX,
			&mut root_key_id.to_bytes().to_vec(),
		);
		let last_confirmed_height = match batch.get_ser(&height_key)? {
			Some(h) => h,
			None => 0,
		};
		Ok(WalletDetails {
			last_child_index: deriv_idx,
			last_confirmed_height: last_confirmed_height,
		})
	}

	fn restore(&mut self) -> Result<(), Error> {
		internal::restore::restore(self).context(ErrorKind::Restore)?;
		Ok(())
	}
}

/// An atomic batch in which all changes can be committed all at once or
/// discarded on error.
pub struct Batch<'a, C: 'a, K: 'a>
where
	C: WalletClient,
	K: Keychain,
{
	_store: &'a LMDBBackend<C, K>,
	db: RefCell<Option<store::Batch<'a>>>,
	/// Keychain
	keychain: Option<K>,
}

#[allow(missing_docs)]
impl<'a, C, K> WalletOutputBatch<K> for Batch<'a, C, K>
where
	C: WalletClient,
	K: Keychain,
{
	fn keychain(&mut self) -> &mut K {
		self.keychain.as_mut().unwrap()
	}

	fn save(&mut self, out: OutputData) -> Result<(), Error> {
		// Save the output data to the db.
		{
			let key = to_key(OUTPUT_PREFIX, &mut out.key_id.to_bytes().to_vec());
			self.db.borrow().as_ref().unwrap().put_ser(&key, &out)?;
		}

		// Save the associated output commitment.
		{
			let key = to_key(COMMITMENT_PREFIX, &mut out.key_id.to_bytes().to_vec());
			let commit = self.keychain().commit(out.value, &out.key_id)?;
			self.db.borrow().as_ref().unwrap().put_ser(&key, &commit)?;
		}

		Ok(())
	}

	fn get(&self, id: &Identifier) -> Result<OutputData, Error> {
		let key = to_key(OUTPUT_PREFIX, &mut id.to_bytes().to_vec());
		option_to_not_found(
			self.db.borrow().as_ref().unwrap().get_ser(&key),
			&format!("Key ID: {}", id),
		).map_err(|e| e.into())
	}

	fn iter(&self) -> Box<Iterator<Item = OutputData>> {
		Box::new(
			self.db
				.borrow()
				.as_ref()
				.unwrap()
				.iter(&[OUTPUT_PREFIX])
				.unwrap(),
		)
	}

	fn delete(&mut self, id: &Identifier) -> Result<(), Error> {
		// Delete the output data.
		{
			let key = to_key(OUTPUT_PREFIX, &mut id.to_bytes().to_vec());
			let _ = self.db.borrow().as_ref().unwrap().delete(&key);
		}

		// Delete the associated output commitment.
		{
			let key = to_key(COMMITMENT_PREFIX, &mut id.to_bytes().to_vec());
			let _ = self.db.borrow().as_ref().unwrap().delete(&key);
		}

		Ok(())
	}

	fn next_tx_log_id(&mut self, root_key_id: Identifier) -> Result<u32, Error> {
		let tx_id_key = to_key(TX_LOG_ID_PREFIX, &mut root_key_id.to_bytes().to_vec());
		let mut last_tx_log_id = match self.db.borrow().as_ref().unwrap().get_ser(&tx_id_key)? {
			Some(t) => t,
			None => 0,
		};
		last_tx_log_id = last_tx_log_id + 1;
		self.db
			.borrow()
			.as_ref()
			.unwrap()
			.put_ser(&tx_id_key, &last_tx_log_id)?;
		Ok(last_tx_log_id)
	}

	fn tx_log_iter(&self) -> Box<Iterator<Item = TxLogEntry>> {
		Box::new(
			self.db
				.borrow()
				.as_ref()
				.unwrap()
				.iter(&[TX_LOG_ENTRY_PREFIX])
				.unwrap(),
		)
	}

	fn save_details(&mut self, root_key_id: Identifier, d: WalletDetails) -> Result<(), Error> {
		let deriv_key = to_key(DERIV_PREFIX, &mut root_key_id.to_bytes().to_vec());
		let height_key = to_key(
			CONFIRMED_HEIGHT_PREFIX,
			&mut root_key_id.to_bytes().to_vec(),
		);
		self.db
			.borrow()
			.as_ref()
			.unwrap()
			.put_ser(&deriv_key, &d.last_child_index)?;
		self.db
			.borrow()
			.as_ref()
			.unwrap()
			.put_ser(&height_key, &d.last_confirmed_height)?;
		Ok(())
	}

	fn save_tx_log_entry(&self, t: TxLogEntry) -> Result<(), Error> {
		let tx_log_key = u64_to_key(TX_LOG_ENTRY_PREFIX, t.id as u64);
		self.db.borrow().as_ref().unwrap().put_ser(&tx_log_key, &t)?;
		Ok(())
	}

	fn lock_output(&mut self, out: &mut OutputData) -> Result<(), Error> {
		out.lock();
		self.save(out.clone())
	}

	fn commit(&self) -> Result<(), Error> {
		let db = self.db.replace(None);
		db.unwrap().commit()?;
		Ok(())
	}
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use cgmath::vector::Vec2;

pub struct TileIterator {
  cursor: Vec2<i32>,
}

impl TileIterator {
  pub fn new() -> TileIterator {
    TileIterator {
      cursor: Vec2::zero(),
    }
  }
}

impl Iterator<Vec2<i32>> for TileIterator {
  fn next(&mut self) -> Option<Vec2<i32>> {
    let map_size = Vec2::<i32>{x: 3, y: 4};
    let current_pos = if self.cursor.y > map_size.y {
      None
    } else {
      Some(self.cursor)
    };
    self.cursor.x += 1;
    if self.cursor.x > map_size.x {
      self.cursor.x = 0;
      self.cursor.y += 1;
    }
    current_pos
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<commit_msg>Map: next(): Removed '::<i32>'<commit_after>// See LICENSE file for copyright and license details.

use cgmath::vector::Vec2;

pub struct TileIterator {
  cursor: Vec2<i32>,
}

impl TileIterator {
  pub fn new() -> TileIterator {
    TileIterator {
      cursor: Vec2::zero(),
    }
  }
}

impl Iterator<Vec2<i32>> for TileIterator {
  fn next(&mut self) -> Option<Vec2<i32>> {
    let map_size = Vec2{x: 3, y: 4};
    let current_pos = if self.cursor.y > map_size.y {
      None
    } else {
      Some(self.cursor)
    };
    self.cursor.x += 1;
    if self.cursor.x > map_size.x {
      self.cursor.x = 0;
      self.cursor.y += 1;
    }
    current_pos
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<|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};

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: &arc::RWArc<~[int]>, a: int) -> int {
    do map.read() |colors| {
        if colors[a] < 0 {
            a
        } else {
            findParent(map, colors[a])
        }
    }
}

fn setParent(map: &arc::RWArc<~[int]>, ind: int, val: int) {
    let mut tmp: int = -1;
    do map.write() |colors| {
        tmp = colors[ind];
        colors[ind] = val;
    }
    if tmp >= 0 {
        setParent(map, 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 corners = [ (0,0),(width-1,0),(0,height-1),(width-1,height-1) ];

    let mut color_index = 0;
    for &corner in corners.iter(){
        let (a,b) = corner;
        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);

    for &corner in corners.iter() {
        let (a,b) = corner;
        let shared_arcs = arcs.clone();
        let shared_colormap = colormap_arc.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));
                        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
                }
            }

            loop {
                match boundaries.maybe_pop() {
                    Some(e) =>
                        {
                        do shared_arcs[e.dest.y][e.dest.x].read |dest| {
                            do shared_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(&shared_colormap,dest.color);
                                let src_parent =  findParent(&shared_colormap,src.color);
                                if src_parent != dest_parent {
                                    setParent(&shared_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));
                                }
                            }
                        }
                    }
                    None => { break; }
                }
            }

        }
    }

    for h in range(0,height){
        for w in range(0,width){
            do arcs[h][w].read |pix| {
        //        println(fmt!("color(%i,%i) %i",w,h,pix.color));
	    }
        }
    }
}
<commit_msg>i believe the problems with concurrency are solved for finding the minimum crossing edge between all of our cuts.<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: &arc::RWArc<~[int]>, a: int) -> int {
    do map.read() |colors| {
        if colors[a] < 0 {
            a
        } else {
            findParent(map, colors[a])
        }
    }
}

fn setParent(map: &arc::RWArc<~[int]>, ind: int, val: int) {
    let mut tmp: int = -1;
    do map.write() |colors| {
        tmp = colors[ind];
        colors[ind] = val;
    }
    if tmp >= 0 {
        setParent(map, 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 corners = [ (0,0),(width-1,0),(0,height-1),(width-1,height-1) ];
    let numnodes: uint = corners.len();
    println(fmt!("number of nodes: %u",numnodes));

    let mut color_index = 0;
    for &corner in corners.iter(){
        let (a,b) = corner;
        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 &corner in corners.iter() {
        let (a,b) = corner;
        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));
                        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
                }
            }

            do shared_boundaries.write |bounds| {
                loop {
                    match boundaries.maybe_pop() {
                        Some(e) =>
                            {
                            bounds.push(e);
//                            do shared_arcs[e.dest.y][e.dest.x].read |dest| {
  //                              do shared_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));
//                                    bounds.push(e);

       //                             let dest_parent = findParent(&shared_colormap,dest.color);
        //                            let src_parent =  findParent(&shared_colormap,src.color);
         //                           if src_parent != dest_parent {
          //                              setParent(&shared_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));
            //                        }

      //                          }
        //                    }
                        }
                        None => { break; }
                    }
                }
            }
            child_chan.send(0);
        }
    }

    for x in range(0,numnodes) {
        port.recv();
    }
    do boundary_arc.write |boundaries| {
        let mut bridges:uint = 0;
        loop {
            match boundaries.maybe_pop() {
                Some(e) => {
//                    println(fmt!("%?",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_arc,dest.color);
                            let src_parent =  findParent(&colormap_arc,src.color);
                            if src_parent != dest_parent {
                                setParent(&colormap_arc,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));
                                bridges +=1;
                            }
                        }
                    }
                    if bridges >= numnodes -1 {
                        break;
                    }
                },
                None => { break }
            }
        }
    }

/*
    for h in range(0,height){
        for w in range(0,width){
            do arcs[h][w].read |pix| {
                //        println(fmt!("color(%i,%i) %i",w,h,pix.color));
	    }
        }
    }
*/
}
<|endoftext|>


<commit_before><commit_msg>Switch to using Option<> for keys and values<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// 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.

#[macro_use]
extern crate log;
extern crate protobuf;
extern crate time;
extern crate zmq;

mod message;

use message::event::EventEnvelope;
use protobuf::parse_from_bytes;
use std::collections::HashMap;
use std::collections::HashSet;
use zmq::{Context, PULL, XPUB};

/// Proxies messages coming into `frontend_port` out through
/// `backend_port`, caching recent messages for new subscribers.
///
/// Event publishers should connect a ZMQ `PUSH` socket to
/// `frontend_port` and send `EventEnvelope` protobuf messages to
/// it. Publishers can connect to multiple such proxy processes;
/// messages will be fairly-dealt to all connected proxies.
///
/// Event subscribers should connect a ZMQ `SUB` socket to
/// `backend_port` to receive `EventEnvelope` protobuf
/// messages. Subscribers should connect to all available proxy
/// processes to ensure they receive all event messages.
///
/// Upon connection, subscribers will receive, from each connected
/// proxy, the most recent messages from each service and from each
/// ring member. Subscribers are responsible for sorting the messages
/// received by timestamp.
pub fn proxy(frontend_port: i32, backend_port: i32) {
    let ctx = Context::new();

    let pull_sock = ctx.socket(PULL).unwrap();
    let pull_bind = format!("tcp://*:{}", frontend_port);
    assert!(pull_sock.bind(&pull_bind).is_ok());

    let xpub_sock = ctx.socket(XPUB).unwrap();
    let xpub_bind = format!("tcp://*:{}", backend_port);
    assert!(xpub_sock.bind(&xpub_bind).is_ok());

    // We'll cache the most recent messages from each service and each
    // ring member. When new subscribers connect, we can send them
    // this "snapshot" of current activity.
    let mut service_cache = HashMap::new();
    let mut member_cache = HashMap::new();

    let mut poll_items = [pull_sock.as_poll_item(zmq::POLLIN),
                          xpub_sock.as_poll_item(zmq::POLLIN)];

    loop {
        // A timeout of -1 says to wait indefinitely until a message comes
        if zmq::poll(&mut poll_items, -1).is_err() {
            break; // This will stop the event service
        }

        if poll_items[0].is_readable() {
            // An event was published!

            let bytes = pull_sock.recv_bytes(0).unwrap();
            let event = parse_from_bytes::<EventEnvelope>(&bytes).unwrap();
            let member_id = event.get_member_id();
            let service = event.get_service().to_string();
            if service.is_empty() {
                warn!("missing service: {:?}", event);
                continue;
            }

            // Store the bytes of the message in the cache. For the
            // service cache, we also record the member ID, and vice
            // versa for the member cache; these data will be used for
            // deduplication of messages being sent to new subscribers.
            service_cache.insert(service.clone(), (member_id, bytes.clone()));
            member_cache.insert(member_id, (service, bytes.clone()));

            xpub_sock.send(&bytes, 0).unwrap();
        }

        if poll_items[1].is_readable() {
            // A subscriber connected; let's ensure they've got a
            // snapshot of what's currently happening.

            // Event is one byte 0=unsub or 1=sub, followed by topic
            let event = xpub_sock.recv_bytes(0).unwrap();
            if event[0] == 1 {
                // The subscriber has subscribed. Send all unique
                // cached messages to it.
                //
                // First we'll send all the latest messages from the
                // services, keeping track of which ring members those
                // were from. Then, we'll send the latest messages
                // from the members, but only if we didn't just send a
                // service message from them. This prevents us from
                // sending the same message twice.

                let mut members_encountered = HashSet::new();

                for (_, &(member_id, ref message)) in &service_cache {
                    members_encountered.insert(member_id);
                    xpub_sock.send(&message, 0).unwrap();
                }
                for (member_id, &(_, ref message)) in &member_cache {
                    if !(members_encountered.contains(member_id)) {
                        xpub_sock.send(&message, 0).unwrap();
                    }
                }
            }
        }
    }
}
<commit_msg>Say why binding failed<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// 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.

#[macro_use]
extern crate log;
extern crate protobuf;
extern crate time;
extern crate zmq;

mod message;

use message::event::EventEnvelope;
use protobuf::parse_from_bytes;
use std::collections::HashMap;
use std::collections::HashSet;
use zmq::{Context, PULL, XPUB};

/// Proxies messages coming into `frontend_port` out through
/// `backend_port`, caching recent messages for new subscribers.
///
/// Event publishers should connect a ZMQ `PUSH` socket to
/// `frontend_port` and send `EventEnvelope` protobuf messages to
/// it. Publishers can connect to multiple such proxy processes;
/// messages will be fairly-dealt to all connected proxies.
///
/// Event subscribers should connect a ZMQ `SUB` socket to
/// `backend_port` to receive `EventEnvelope` protobuf
/// messages. Subscribers should connect to all available proxy
/// processes to ensure they receive all event messages.
///
/// Upon connection, subscribers will receive, from each connected
/// proxy, the most recent messages from each service and from each
/// ring member. Subscribers are responsible for sorting the messages
/// received by timestamp.
pub fn proxy(frontend_port: i32, backend_port: i32) {
    let ctx = Context::new();

    let pull_sock = ctx.socket(PULL).unwrap();
    let pull_bind = format!("tcp://*:{}", frontend_port);
    match pull_sock.bind(&pull_bind) {
        Ok(()) => {},
        Err(e) => panic!(format!("Could not bind socket to port {}: {:?}", frontend_port, e))
    }

    let xpub_sock = ctx.socket(XPUB).unwrap();
    let xpub_bind = format!("tcp://*:{}", backend_port);
    match xpub_sock.bind(&xpub_bind) {
        Ok(()) => {},
        Err(e) => panic!(format!("Could not bind socket to port {}: {:?}", backend_port, e))
    }

    // We'll cache the most recent messages from each service and each
    // ring member. When new subscribers connect, we can send them
    // this "snapshot" of current activity.
    let mut service_cache = HashMap::new();
    let mut member_cache = HashMap::new();

    let mut poll_items = [pull_sock.as_poll_item(zmq::POLLIN),
                          xpub_sock.as_poll_item(zmq::POLLIN)];

    loop {
        // A timeout of -1 says to wait indefinitely until a message comes
        if zmq::poll(&mut poll_items, -1).is_err() {
            break; // This will stop the event service
        }

        if poll_items[0].is_readable() {
            // An event was published!

            let bytes = pull_sock.recv_bytes(0).unwrap();
            let event = parse_from_bytes::<EventEnvelope>(&bytes).unwrap();
            let member_id = event.get_member_id();
            let service = event.get_service().to_string();
            if service.is_empty() {
                warn!("missing service: {:?}", event);
                continue;
            }

            // Store the bytes of the message in the cache. For the
            // service cache, we also record the member ID, and vice
            // versa for the member cache; these data will be used for
            // deduplication of messages being sent to new subscribers.
            service_cache.insert(service.clone(), (member_id, bytes.clone()));
            member_cache.insert(member_id, (service, bytes.clone()));

            xpub_sock.send(&bytes, 0).unwrap();
        }

        if poll_items[1].is_readable() {
            // A subscriber connected; let's ensure they've got a
            // snapshot of what's currently happening.

            // Event is one byte 0=unsub or 1=sub, followed by topic
            let event = xpub_sock.recv_bytes(0).unwrap();
            if event[0] == 1 {
                // The subscriber has subscribed. Send all unique
                // cached messages to it.
                //
                // First we'll send all the latest messages from the
                // services, keeping track of which ring members those
                // were from. Then, we'll send the latest messages
                // from the members, but only if we didn't just send a
                // service message from them. This prevents us from
                // sending the same message twice.

                let mut members_encountered = HashSet::new();

                for (_, &(member_id, ref message)) in &service_cache {
                    members_encountered.insert(member_id);
                    xpub_sock.send(&message, 0).unwrap();
                }
                for (member_id, &(_, ref message)) in &member_cache {
                    if !(members_encountered.contains(member_id)) {
                        xpub_sock.send(&message, 0).unwrap();
                    }
                }
            }
        }
    }
}
<|endoftext|>


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

use db::migration::Migrator;

use error::Result;

pub fn migrate(migrator: &mut Migrator) -> Result<()> {
    migrator
        .migrate("accountsrv",
                 r#"CREATE SEQUENCE IF NOT EXISTS accounts_id_seq;"#)?;
    migrator
        .migrate("accountsrv",
                 r#"CREATE TABLE accounts (
                        id bigint PRIMARY KEY DEFAULT next_id_v1('accounts_id_seq'),
                        name text UNIQUE,
                        email text UNIQUE,
                        created_at timestamptz DEFAULT now(),
                        updated_at timestamptz
                        )"#)?;
    migrator.migrate("accountsrv",
                 r#"CREATE OR REPLACE FUNCTION select_or_insert_account_v1 (
                    account_name text,
                    account_email text
                 ) RETURNS SETOF accounts AS $$
                     DECLARE
                        existing_account accounts%rowtype;
                     BEGIN
                        SELECT * INTO existing_account FROM accounts WHERE name = account_name LIMIT 1;
                        IF FOUND THEN
                            RETURN NEXT existing_account;
                        ELSE
                            RETURN QUERY INSERT INTO accounts (name, email) VALUES (account_name, account_email) ON CONFLICT DO NOTHING RETURNING *;
                        END IF;
                        RETURN;
                     END
                 $$ LANGUAGE plpgsql VOLATILE"#)?;

    migrator
        .migrate("accountsrv",
                 r#"CREATE OR REPLACE FUNCTION get_account_by_name_v1 (
                    account_name text
                 ) RETURNS SETOF accounts AS $$
                     BEGIN
                        RETURN QUERY SELECT * FROM accounts WHERE name = name;
                        RETURN;
                     END
                 $$ LANGUAGE plpgsql STABLE"#)?;

    migrator
        .migrate("accountsrv",
                 r#"CREATE OR REPLACE FUNCTION get_account_by_id_v1 (
                    account_id bigint
                 ) RETURNS SETOF accounts AS $$
                     BEGIN
                        RETURN QUERY SELECT * FROM accounts WHERE id = account_id;
                        RETURN;
                     END
                 $$ LANGUAGE plpgsql STABLE"#)?;
    migrator
        .migrate("accountsrv",
                 r#"CREATE TABLE account_origins (
                        account_id bigint,
                        account_name text,
                        origin_id bigint,
                        origin_name text,
                        created_at timestamptz DEFAULT now(),
                        updated_at timestamptz,
                        UNIQUE(account_id, origin_id)
                        )"#)?;
    migrator.migrate("accountsrv",
                 r#"CREATE OR REPLACE FUNCTION insert_account_origin_v1 (
                    o_account_id bigint,
                    o_account_name text,
                    o_origin_id bigint,
                    o_origin_name text
                 ) RETURNS void AS $$
                     BEGIN
                        INSERT INTO account_origins (account_id, account_name, origin_id, origin_name) VALUES (o_account_id, o_account_name, o_origin_id, o_origin_name);
                     END
                 $$ LANGUAGE plpgsql VOLATILE"#)?;
    migrator
        .migrate("accountsrv",
                 r#"CREATE OR REPLACE FUNCTION get_account_origins_v1 (
                    in_account_id bigint
                 ) RETURNS SETOF account_origins AS $$
                     BEGIN
                        RETURN QUERY SELECT * FROM account_origins WHERE account_id = in_account_id;
                        RETURN;
                     END
                 $$ LANGUAGE plpgsql STABLE"#)?;

    Ok(())
}
<commit_msg>fixes stored procedure for looking up account by name<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use db::migration::Migrator;

use error::Result;

pub fn migrate(migrator: &mut Migrator) -> Result<()> {
    migrator
        .migrate("accountsrv",
                 r#"CREATE SEQUENCE IF NOT EXISTS accounts_id_seq;"#)?;
    migrator
        .migrate("accountsrv",
                 r#"CREATE TABLE accounts (
                        id bigint PRIMARY KEY DEFAULT next_id_v1('accounts_id_seq'),
                        name text UNIQUE,
                        email text UNIQUE,
                        created_at timestamptz DEFAULT now(),
                        updated_at timestamptz
                        )"#)?;
    migrator.migrate("accountsrv",
                 r#"CREATE OR REPLACE FUNCTION select_or_insert_account_v1 (
                    account_name text,
                    account_email text
                 ) RETURNS SETOF accounts AS $$
                     DECLARE
                        existing_account accounts%rowtype;
                     BEGIN
                        SELECT * INTO existing_account FROM accounts WHERE name = account_name LIMIT 1;
                        IF FOUND THEN
                            RETURN NEXT existing_account;
                        ELSE
                            RETURN QUERY INSERT INTO accounts (name, email) VALUES (account_name, account_email) ON CONFLICT DO NOTHING RETURNING *;
                        END IF;
                        RETURN;
                     END
                 $$ LANGUAGE plpgsql VOLATILE"#)?;

    migrator
        .migrate("accountsrv",
                 r#"CREATE OR REPLACE FUNCTION get_account_by_name_v1 (
                    account_name text
                 ) RETURNS SETOF accounts AS $$
                     BEGIN
                        RETURN QUERY SELECT * FROM accounts WHERE name = account_name;
                        RETURN;
                     END
                 $$ LANGUAGE plpgsql STABLE"#)?;

    migrator
        .migrate("accountsrv",
                 r#"CREATE OR REPLACE FUNCTION get_account_by_id_v1 (
                    account_id bigint
                 ) RETURNS SETOF accounts AS $$
                     BEGIN
                        RETURN QUERY SELECT * FROM accounts WHERE id = account_id;
                        RETURN;
                     END
                 $$ LANGUAGE plpgsql STABLE"#)?;
    migrator
        .migrate("accountsrv",
                 r#"CREATE TABLE account_origins (
                        account_id bigint,
                        account_name text,
                        origin_id bigint,
                        origin_name text,
                        created_at timestamptz DEFAULT now(),
                        updated_at timestamptz,
                        UNIQUE(account_id, origin_id)
                        )"#)?;
    migrator.migrate("accountsrv",
                 r#"CREATE OR REPLACE FUNCTION insert_account_origin_v1 (
                    o_account_id bigint,
                    o_account_name text,
                    o_origin_id bigint,
                    o_origin_name text
                 ) RETURNS void AS $$
                     BEGIN
                        INSERT INTO account_origins (account_id, account_name, origin_id, origin_name) VALUES (o_account_id, o_account_name, o_origin_id, o_origin_name);
                     END
                 $$ LANGUAGE plpgsql VOLATILE"#)?;
    migrator
        .migrate("accountsrv",
                 r#"CREATE OR REPLACE FUNCTION get_account_origins_v1 (
                    in_account_id bigint
                 ) RETURNS SETOF account_origins AS $$
                     BEGIN
                        RETURN QUERY SELECT * FROM account_origins WHERE account_id = in_account_id;
                        RETURN;
                     END
                 $$ LANGUAGE plpgsql STABLE"#)?;

    Ok(())
}
<|endoftext|>


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

// The rust-book JavaScript in string form.

pub static JAVASCRIPT: &'static str = r#"
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
  document.getElementById("toggle-nav").onclick = toggleNav;
  function toggleNav() {
    var toc = document.getElementById("toc");
    var pagewrapper = document.getElementById("page-wrapper");
    toggleClass(toc, "mobile-hidden");
    toggleClass(pagewrapper, "mobile-hidden");
  };

  function toggleClass(el, className) {
     // from http://youmightnotneedjquery.com/
     if (el.classList) {
       el.classList.toggle(className);
     } else {
       var classes = el.className.split(' ');
       var existingIndex = classes.indexOf(className);

       if (existingIndex >= 0) {
         classes.splice(existingIndex, 1);
       } else {
         classes.push(className);
       }

       el.className = classes.join(' ');
     }
  }

  // The below code is used to add prev and next navigation links to the bottom
  // of each of the sections.
  // It works by extracting the current page based on the url and iterates over
  // the menu links until it finds the menu item for the current page. We then
  // create a copy of the preceding and following menu links and add the
  // correct css class and insert them into the bottom of the page.
  var toc = document.getElementById('toc').getElementsByTagName('a');
  var href = document.location.pathname.split('/').pop();
  if (href === 'index.html' || href === '') {
    href = 'README.html';
  }

  for (var i = 0; i < toc.length; i++) {
    if (toc[i].attributes['href'].value.split('/').pop() === href) {
      var nav = document.createElement('p');
      if (i > 0) {
        var prevNode = toc[i-1].cloneNode(true);
        prevNode.className = 'left';
        nav.appendChild(prevNode);
      }
      if (i < toc.length - 1) {
        var nextNode = toc[i+1].cloneNode(true);
        nextNode.className = 'right';
        nav.appendChild(nextNode);
      }
      document.getElementById('page').appendChild(nav);
      break;
    }
  }

});
</script>
<script type="text/javascript" src="playpen.js"></script>
"#;
<commit_msg>doc: add rel=prev/next for links to adjacent sections<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// The rust-book JavaScript in string form.

pub static JAVASCRIPT: &'static str = r#"
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
  document.getElementById("toggle-nav").onclick = toggleNav;
  function toggleNav() {
    var toc = document.getElementById("toc");
    var pagewrapper = document.getElementById("page-wrapper");
    toggleClass(toc, "mobile-hidden");
    toggleClass(pagewrapper, "mobile-hidden");
  };

  function toggleClass(el, className) {
     // from http://youmightnotneedjquery.com/
     if (el.classList) {
       el.classList.toggle(className);
     } else {
       var classes = el.className.split(' ');
       var existingIndex = classes.indexOf(className);

       if (existingIndex >= 0) {
         classes.splice(existingIndex, 1);
       } else {
         classes.push(className);
       }

       el.className = classes.join(' ');
     }
  }

  // The below code is used to add prev and next navigation links to the bottom
  // of each of the sections.
  // It works by extracting the current page based on the url and iterates over
  // the menu links until it finds the menu item for the current page. We then
  // create a copy of the preceding and following menu links and add the
  // correct css class and insert them into the bottom of the page.
  var toc = document.getElementById('toc').getElementsByTagName('a');
  var href = document.location.pathname.split('/').pop();
  if (href === 'index.html' || href === '') {
    href = 'README.html';
  }

  for (var i = 0; i < toc.length; i++) {
    if (toc[i].attributes['href'].value.split('/').pop() === href) {
      var nav = document.createElement('p');
      if (i > 0) {
        var prevNode = toc[i-1].cloneNode(true);
        prevNode.className = 'left';
        prevNode.setAttribute('rel', 'prev');
        nav.appendChild(prevNode);
      }
      if (i < toc.length - 1) {
        var nextNode = toc[i+1].cloneNode(true);
        nextNode.className = 'right';
        nextNode.setAttribute('rel', 'next');
        nav.appendChild(nextNode);
      }
      document.getElementById('page').appendChild(nav);
      break;
    }
  }

});
</script>
<script type="text/javascript" src="playpen.js"></script>
"#;
<|endoftext|>