<commit_before>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! A library providing high-level abstractions for event loop concurrency,
//! heavily borrowing ideas from [KJ](https://capnproto.org/cxxrpc.html#kj-concurrency-framework).
//! Allows for coordination of asynchronous tasks using [promises](struct.Promise.html) as
//! a basic building block.

extern crate mio;
extern crate nix;

use std::cell::{Cell, RefCell};
use std::rc::Rc;
use std::result::Result;
use private::{promise_node, Event, BoolEvent, PromiseAndFulfillerHub,
              EVENT_LOOP, with_current_event_loop, PromiseNode};

pub mod io;

mod private;
mod handle_table;

pub struct Forced;

/// A computation that might eventually resolve to a value of type `T`.
pub struct Promise<T, E> where T: 'static, E: 'static {
    node: Box<PromiseNode<T, E>>,
}

impl <T, E> Promise <T, E> {
    /// Chains further computation to be executed once the promise resolves.
    /// When the promise is fulfilled successfully, invokes `func` on its result.
    /// When the promise is rejected, invokes `error_handler` on the resulting error.
    ///
    /// If the returned promise is dropped before the chained computation runs, the chained
    /// computation will be cancelled.
    ///
    /// Always returns immediately, even if the promise is already resolved. The earliest that
    /// `func` or `error_handler` might be invoked is during the next `turn()` of the event loop.
    pub fn then_else<F, R, E1>(self, func: F) -> Promise<R, E1>
        where F: 'static,
              F: FnOnce(Result<T, E>) -> Result<Promise<R, E1>, E1>,
              R: 'static
    {
        let intermediate = Box::new(promise_node::Transform::new(self.node, func));
        Promise { node: Box::new(promise_node::Chain::new(intermediate)) }
    }

    /// Calls `then_else()` with a default error handler that simply propagates all errors.
    pub fn then<F, R>(self, func: F) -> Promise<R, E>
        where F: 'static,
              F: FnOnce(T) -> Result<Promise<R, E>, E>,
              R: 'static,
    {
        self.then_else(|r| { match r { Ok(v) => func(v), Err(e) => Err(e) } })
    }

    /// Like then_else() but for a `func` that returns a direct value rather than a promise.
    pub fn map_else<F, R, E1>(self, func: F) -> Promise<R, E1>
        where F: 'static,
              F: FnOnce(Result<T, E>) -> Result<R, E1>,
              R: 'static,
              E1: 'static
    {
        Promise { node: Box::new(promise_node::Transform::new(self.node, func)) }
    }

    /// Calls `map_else()` with a default error handler that simple propagates all errors.
    pub fn map<F, R>(self, func: F) -> Promise<R, E>
        where F: 'static,
              F: FnOnce(T) -> Result<R, E>,
              R: 'static
    {
        self.map_else(|r| { match r { Ok(v) => func(v), Err(e) =>  Err(e) } } )
    }

    pub fn map_err<E1, F>(self, func: F) -> Promise<T, E1>
        where F: 'static,
              F: FnOnce(E) -> E1
    {
        self.map_else(|r| { match r { Ok(v) => Ok(v), Err(e) =>  Err(func(e)) } } )
    }

    pub fn box_err(self) -> Promise<T, Box<::std::error::Error>> where E: Into<Box<::std::error::Error>> {
        self.map_err(|e| e.into())
    }

    /// Cancels the promise, returning its value if it has already been fulfilled. If the promise has not
    /// already been fulfilled, the result must be an Err.
    pub fn force(self) -> Result<T, E> {
        self.node.force()
    }

    /// Returns a new promise that resolves when either `self` or `other` resolves. The promise that
    /// doesn't resolve first is cancelled.
    pub fn exclusive_join(self, other: Promise<T, E>) -> Promise<T, E> {
        Promise { node: Box::new(private::promise_node::ExclusiveJoin::new(self.node, other.node)) }
    }

    /// Creates a new promise that has already been fulfilled.
    pub fn fulfilled(value: T) -> Promise<T, E> {
        Promise { node: Box::new(promise_node::Immediate::new(Ok(value))) }
    }

    /// Creates a new promise that has already been rejected with the given error.
    pub fn rejected(error: E) -> Promise<T, E> {
        Promise { node: Box::new(promise_node::Immediate::new(Err(error))) }
    }

    /// Runs the event loop until the promise is fulfilled.
    ///
    /// The `WaitScope` argument ensures that `wait()` can only be called at the top level of a program.
    /// Waiting within event callbacks is disallowed.
    pub fn wait(mut self, _wait_scope: &WaitScope) -> Result<T, E> {
        with_current_event_loop(move |event_loop| {
            let fired = ::std::rc::Rc::new(::std::cell::Cell::new(false));
            let done_event = BoolEvent::new(fired.clone());
            let (handle, _dropper) = private::EventHandle::new();
            handle.set(Box::new(done_event));
            self.node.on_ready(handle);

            //event_loop.running = true;

            while !fired.get() {
                if !event_loop.turn() {
                    // No events in the queue.
                    event_loop.event_port.borrow_mut().wait();
                }
            }

            self.node.get()
        })
    }
}

/// A scope in which asynchronous programming can occur. Corresponds to the top level scope
/// of some event loop.
pub struct WaitScope(::std::marker::PhantomData<*mut u8>); // impl !Sync for WaitScope {}

/// Interface between an `EventLoop` and events originating from outside of the loop's thread.
trait EventPort {
    /// Waits for an external event to arrive, sleeping if necessary.
    /// Returns true if wake() has been called from another thread.
    fn wait(&mut self) -> bool;

    /// Checks whether any external events have arrived, but does not sleep.
    /// Returns true if wake() has been called from another thread.
    fn poll(&mut self) -> bool;

    /// Called to notify the `EventPort` when the `EventLoop` has work to do; specifically when it
    /// transitions from empty -> runnable or runnable -> empty. This is typically useful when
    /// integrating with an external event loop; if the loop is currently runnable then you should
    /// arrange to call run() on it soon. The default implementation does nothing.
    fn set_runnable(&mut self, _runnable: bool) { }

    fn wake(&mut self) { unimplemented!(); }
}

/// A queue of events being executed in a loop on a single thread.
pub struct EventLoop {
//    daemons: TaskSetImpl,
    event_port: RefCell<io::MioEventPort>,
    _running: bool,
    _last_runnable_state: bool,
    events: RefCell<handle_table::HandleTable<private::EventNode>>,
    head: private::EventHandle,
    tail: Cell<private::EventHandle>,
    depth_first_insertion_point: Cell<private::EventHandle>,
}

impl EventLoop {
    /// Creates an event loop for the current thread, panicking if one already exists. Runs the given
    /// closure and then drops the event loop.
    pub fn top_level<F>(main: F) -> Result<(), Box<::std::error::Error>>
        where F: FnOnce(&WaitScope) -> Result<(), Box<::std::error::Error>>
    {
        let mut events = handle_table::HandleTable::<private::EventNode>::new();
        let dummy = private::EventNode { event: None, next: None, prev: None };
        let head_handle = private::EventHandle(events.push(dummy));

        EVENT_LOOP.with(move |maybe_event_loop| {
            let event_loop = EventLoop {
                event_port: RefCell::new(io::MioEventPort::new().unwrap()),
                _running: false,
                _last_runnable_state: false,
                events: RefCell::new(events),
                head: head_handle,
                tail: Cell::new(head_handle),
                depth_first_insertion_point: Cell::new(head_handle), // insert after this node
            };

            assert!(maybe_event_loop.borrow().is_none());
            *maybe_event_loop.borrow_mut() = Some(event_loop);
        });
        let wait_scope = WaitScope(::std::marker::PhantomData );

        let result = main(&wait_scope);

        EVENT_LOOP.with(move |maybe_event_loop| {
            *maybe_event_loop.borrow_mut() = None;
        });

        return result;
    }

    fn arm_depth_first(&self, event_handle: private::EventHandle) {

        let insertion_node_next = self.events.borrow()[self.depth_first_insertion_point.get().0].next;

        match insertion_node_next {
            Some(next_handle) => {
                self.events.borrow_mut()[next_handle.0].prev = Some(event_handle);
                self.events.borrow_mut()[event_handle.0].next = Some(next_handle);
            }
            None => {
                self.tail.set(event_handle);
            }
        }

        self.events.borrow_mut()[event_handle.0].prev = Some(self.depth_first_insertion_point.get());
        self.events.borrow_mut()[self.depth_first_insertion_point.get().0].next = Some(event_handle);
        self.depth_first_insertion_point.set(event_handle);
    }

    fn arm_breadth_first(&self, event_handle: private::EventHandle) {
        let events = &mut *self.events.borrow_mut();
        events[self.tail.get().0].next = Some(event_handle);
        events[event_handle.0].prev = Some(self.tail.get());
        self.tail.set(event_handle);
    }

    /// Runs the event loop for `max_turn_count` turns or until there is nothing left to be done,
    /// whichever comes first. This never calls the `EventPort`'s `sleep()` or `poll()`. It will
    /// call the `EventPort`'s `set_runnable(false)` if the queue becomes empty.
    fn _run(&mut self, max_turn_count: u32) {
        self._running = true;

        for _ in 0..max_turn_count {
            if !self.turn() {
                break;
            }
        }
    }

    /// Runs the event loop for a single step.
    fn turn(&self) -> bool {

        let event_handle = match self.events.borrow()[self.head.0].next {
            None => return false,
            Some(event_handle) => { event_handle }
        };
        self.depth_first_insertion_point.set(event_handle);

        let mut event = ::std::mem::replace(&mut self.events.borrow_mut()[event_handle.0].event, None)
            .expect("No event to fire?");
        let _dropper = event.fire();

        let maybe_next = self.events.borrow()[event_handle.0].next;
        self.events.borrow_mut()[self.head.0].next = maybe_next;
        match maybe_next {
            Some(e) => {
                self.events.borrow_mut()[e.0].prev = Some(self.head);
            }
            None => {}
        }

        self.events.borrow_mut()[event_handle.0].next = None;
        self.events.borrow_mut()[event_handle.0].prev = None;

        if self.tail.get() == event_handle {
            self.tail.set(self.head);
        }

        self.depth_first_insertion_point.set(self.head);
        return true;
    }
}

/// A callback that can be used to fulfill or reject a promise.
pub trait PromiseFulfiller<T, E> where T: 'static, E: 'static, E: From<Forced> {
    fn fulfill(self: Box<Self>, value: T);
    fn reject(self: Box<Self>, error: E);
}

/// Creates a new promise/fulfiller pair.
pub fn new_promise_and_fulfiller<T, E>() -> (Promise<T, E>, Box<PromiseFulfiller<T, E>>)
    where T: 'static,
          E: 'static + From<Forced>
{
    let result = ::std::rc::Rc::new(::std::cell::RefCell::new(PromiseAndFulfillerHub::new()));
    let result_promise: Promise<T, E> = Promise { node: Box::new(result.clone())};
    (result_promise, Box::new(result))
}

/// Holds a collection of `Promise<()>`s and ensures that each executes to completion.
/// Destroying a TaskSet automatically cancels all of its unfinished promises.
pub struct TaskSet {
    task_set_impl: Rc<RefCell<private::TaskSetImpl>>,
}

impl TaskSet {
    pub fn new(error_handler: Box<ErrorHandler>) -> TaskSet {
        TaskSet { task_set_impl : Rc::new(RefCell::new(private::TaskSetImpl::new(error_handler))) }
    }

    pub fn add(&mut self, promise: Promise<(), Box<::std::error::Error>>) {
        private::TaskSetImpl::add(self.task_set_impl.clone(), promise.node);
    }
}

/// A callback to be invoked when a task in a `TaskSet` fails.
pub trait ErrorHandler {
    fn task_failed(&mut self, error: Box<::std::error::Error>);
}

/// Transforms a vector of promises into a promise for a vector.
pub fn join_promises<T, E>(promises: Vec<Promise<T, E>>) -> Promise<Vec<T>, E>
{
    let nodes = promises.into_iter().map(|p| { p.node }).collect();
    Promise { node: Box::new(private::promise_node::ArrayJoin::new(nodes)) }
}

impl From<Forced> for ::std::io::Error {
    fn from(_: Forced) -> ::std::io::Error {
        ::std::io::Error::new(::std::io::ErrorKind::Other, "forced unfulfilled promise")
    }
}

impl From<Forced> for Box<::std::error::Error> {
    fn from(_: Forced) -> Box<::std::error::Error> {
        ::std::io::Error::new(::std::io::ErrorKind::Other, "forced unfulfilled promise").into()
    }
}
<commit_msg>Update documentation.<commit_after>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! A library providing high-level abstractions for event loop concurrency,
//! heavily borrowing ideas from [KJ](https://capnproto.org/cxxrpc.html#kj-concurrency-framework).
//! Allows for coordination of asynchronous tasks using [promises](struct.Promise.html) as
//! a basic building block.

extern crate mio;
extern crate nix;

use std::cell::{Cell, RefCell};
use std::rc::Rc;
use std::result::Result;
use private::{promise_node, Event, BoolEvent, PromiseAndFulfillerHub,
              EVENT_LOOP, with_current_event_loop, PromiseNode};

pub mod io;

mod private;
mod handle_table;

pub struct Forced;

/// A computation that might eventually resolve to a value of type `T` or to an error
//  of type `E`.
pub struct Promise<T, E> where T: 'static, E: 'static {
    node: Box<PromiseNode<T, E>>,
}

impl <T, E> Promise <T, E> {
    /// Chains further computation to be executed once the promise resolves.
    /// When the promise is fulfilled or rejected, invokes `func` on its result.
    ///
    /// If the returned promise is dropped before the chained computation runs, the chained
    /// computation will be cancelled.
    ///
    /// Always returns immediately, even if the promise is already resolved. The earliest that
    /// `func` might be invoked is during the next `turn()` of the event loop.
    pub fn then_else<F, R, E1>(self, func: F) -> Promise<R, E1>
        where F: 'static,
              F: FnOnce(Result<T, E>) -> Result<Promise<R, E1>, E1>,
              R: 'static
    {
        let intermediate = Box::new(promise_node::Transform::new(self.node, func));
        Promise { node: Box::new(promise_node::Chain::new(intermediate)) }
    }

    /// Calls `then_else()` with a default error handler that simply propagates all errors.
    pub fn then<F, R>(self, func: F) -> Promise<R, E>
        where F: 'static,
              F: FnOnce(T) -> Result<Promise<R, E>, E>,
              R: 'static,
    {
        self.then_else(|r| { match r { Ok(v) => func(v), Err(e) => Err(e) } })
    }

    /// Like then_else() but for a `func` that returns a direct value rather than a promise.
    pub fn map_else<F, R, E1>(self, func: F) -> Promise<R, E1>
        where F: 'static,
              F: FnOnce(Result<T, E>) -> Result<R, E1>,
              R: 'static,
              E1: 'static
    {
        Promise { node: Box::new(promise_node::Transform::new(self.node, func)) }
    }

    /// Calls `map_else()` with a default error handler that simple propagates all errors.
    pub fn map<F, R>(self, func: F) -> Promise<R, E>
        where F: 'static,
              F: FnOnce(T) -> Result<R, E>,
              R: 'static
    {
        self.map_else(|r| { match r { Ok(v) => func(v), Err(e) =>  Err(e) } } )
    }

    /// Transforms the error branch of the promise.
    pub fn map_err<E1, F>(self, func: F) -> Promise<T, E1>
        where F: 'static,
              F: FnOnce(E) -> E1
    {
        self.map_else(|r| { match r { Ok(v) => Ok(v), Err(e) =>  Err(func(e)) } } )
    }

    /// Transforms the error branch into a common type that all errors should be convertible into.
    pub fn box_err(self) -> Promise<T, Box<::std::error::Error>> where E: Into<Box<::std::error::Error>> {
        self.map_err(|e| e.into())
    }

    /// Cancels the promise, returning its value if it has already been fulfilled. If the promise has not
    /// already been fulfilled, the result must be an Err.
    pub fn force(self) -> Result<T, E> {
        self.node.force()
    }

    /// Returns a new promise that resolves when either `self` or `other` resolves. The promise that
    /// doesn't resolve first is cancelled.
    pub fn exclusive_join(self, other: Promise<T, E>) -> Promise<T, E> {
        Promise { node: Box::new(private::promise_node::ExclusiveJoin::new(self.node, other.node)) }
    }

    /// Creates a new promise that has already been fulfilled.
    pub fn fulfilled(value: T) -> Promise<T, E> {
        Promise { node: Box::new(promise_node::Immediate::new(Ok(value))) }
    }

    /// Creates a new promise that has already been rejected with the given error.
    pub fn rejected(error: E) -> Promise<T, E> {
        Promise { node: Box::new(promise_node::Immediate::new(Err(error))) }
    }

    /// Runs the event loop until the promise is fulfilled.
    ///
    /// The `WaitScope` argument ensures that `wait()` can only be called at the top level of a program.
    /// Waiting within event callbacks is disallowed.
    pub fn wait(mut self, _wait_scope: &WaitScope) -> Result<T, E> {
        with_current_event_loop(move |event_loop| {
            let fired = ::std::rc::Rc::new(::std::cell::Cell::new(false));
            let done_event = BoolEvent::new(fired.clone());
            let (handle, _dropper) = private::EventHandle::new();
            handle.set(Box::new(done_event));
            self.node.on_ready(handle);

            //event_loop.running = true;

            while !fired.get() {
                if !event_loop.turn() {
                    // No events in the queue.
                    event_loop.event_port.borrow_mut().wait();
                }
            }

            self.node.get()
        })
    }
}

/// A scope in which asynchronous programming can occur. Corresponds to the top level scope
/// of some event loop.
pub struct WaitScope(::std::marker::PhantomData<*mut u8>); // impl !Sync for WaitScope {}

/// Interface between an `EventLoop` and events originating from outside of the loop's thread.
trait EventPort {
    /// Waits for an external event to arrive, sleeping if necessary.
    /// Returns true if wake() has been called from another thread.
    fn wait(&mut self) -> bool;

    /// Checks whether any external events have arrived, but does not sleep.
    /// Returns true if wake() has been called from another thread.
    fn poll(&mut self) -> bool;

    /// Called to notify the `EventPort` when the `EventLoop` has work to do; specifically when it
    /// transitions from empty -> runnable or runnable -> empty. This is typically useful when
    /// integrating with an external event loop; if the loop is currently runnable then you should
    /// arrange to call run() on it soon. The default implementation does nothing.
    fn set_runnable(&mut self, _runnable: bool) { }

    fn wake(&mut self) { unimplemented!(); }
}

/// A queue of events being executed in a loop on a single thread.
pub struct EventLoop {
//    daemons: TaskSetImpl,
    event_port: RefCell<io::MioEventPort>,
    _running: bool,
    _last_runnable_state: bool,
    events: RefCell<handle_table::HandleTable<private::EventNode>>,
    head: private::EventHandle,
    tail: Cell<private::EventHandle>,
    depth_first_insertion_point: Cell<private::EventHandle>,
}

impl EventLoop {
    /// Creates an event loop for the current thread, panicking if one already exists. Runs the given
    /// closure and then drops the event loop.
    pub fn top_level<F>(main: F) -> Result<(), Box<::std::error::Error>>
        where F: FnOnce(&WaitScope) -> Result<(), Box<::std::error::Error>>
    {
        let mut events = handle_table::HandleTable::<private::EventNode>::new();
        let dummy = private::EventNode { event: None, next: None, prev: None };
        let head_handle = private::EventHandle(events.push(dummy));

        EVENT_LOOP.with(move |maybe_event_loop| {
            let event_loop = EventLoop {
                event_port: RefCell::new(io::MioEventPort::new().unwrap()),
                _running: false,
                _last_runnable_state: false,
                events: RefCell::new(events),
                head: head_handle,
                tail: Cell::new(head_handle),
                depth_first_insertion_point: Cell::new(head_handle), // insert after this node
            };

            assert!(maybe_event_loop.borrow().is_none());
            *maybe_event_loop.borrow_mut() = Some(event_loop);
        });
        let wait_scope = WaitScope(::std::marker::PhantomData );

        let result = main(&wait_scope);

        EVENT_LOOP.with(move |maybe_event_loop| {
            *maybe_event_loop.borrow_mut() = None;
        });

        return result;
    }

    fn arm_depth_first(&self, event_handle: private::EventHandle) {

        let insertion_node_next = self.events.borrow()[self.depth_first_insertion_point.get().0].next;

        match insertion_node_next {
            Some(next_handle) => {
                self.events.borrow_mut()[next_handle.0].prev = Some(event_handle);
                self.events.borrow_mut()[event_handle.0].next = Some(next_handle);
            }
            None => {
                self.tail.set(event_handle);
            }
        }

        self.events.borrow_mut()[event_handle.0].prev = Some(self.depth_first_insertion_point.get());
        self.events.borrow_mut()[self.depth_first_insertion_point.get().0].next = Some(event_handle);
        self.depth_first_insertion_point.set(event_handle);
    }

    fn arm_breadth_first(&self, event_handle: private::EventHandle) {
        let events = &mut *self.events.borrow_mut();
        events[self.tail.get().0].next = Some(event_handle);
        events[event_handle.0].prev = Some(self.tail.get());
        self.tail.set(event_handle);
    }

    /// Runs the event loop for `max_turn_count` turns or until there is nothing left to be done,
    /// whichever comes first. This never calls the `EventPort`'s `sleep()` or `poll()`. It will
    /// call the `EventPort`'s `set_runnable(false)` if the queue becomes empty.
    fn _run(&mut self, max_turn_count: u32) {
        self._running = true;

        for _ in 0..max_turn_count {
            if !self.turn() {
                break;
            }
        }
    }

    /// Runs the event loop for a single step.
    fn turn(&self) -> bool {

        let event_handle = match self.events.borrow()[self.head.0].next {
            None => return false,
            Some(event_handle) => { event_handle }
        };
        self.depth_first_insertion_point.set(event_handle);

        let mut event = ::std::mem::replace(&mut self.events.borrow_mut()[event_handle.0].event, None)
            .expect("No event to fire?");
        let _dropper = event.fire();

        let maybe_next = self.events.borrow()[event_handle.0].next;
        self.events.borrow_mut()[self.head.0].next = maybe_next;
        match maybe_next {
            Some(e) => {
                self.events.borrow_mut()[e.0].prev = Some(self.head);
            }
            None => {}
        }

        self.events.borrow_mut()[event_handle.0].next = None;
        self.events.borrow_mut()[event_handle.0].prev = None;

        if self.tail.get() == event_handle {
            self.tail.set(self.head);
        }

        self.depth_first_insertion_point.set(self.head);
        return true;
    }
}

/// A callback that can be used to fulfill or reject a promise.
pub trait PromiseFulfiller<T, E> where T: 'static, E: 'static, E: From<Forced> {
    fn fulfill(self: Box<Self>, value: T);
    fn reject(self: Box<Self>, error: E);
}

/// Creates a new promise/fulfiller pair.
pub fn new_promise_and_fulfiller<T, E>() -> (Promise<T, E>, Box<PromiseFulfiller<T, E>>)
    where T: 'static,
          E: 'static + From<Forced>
{
    let result = ::std::rc::Rc::new(::std::cell::RefCell::new(PromiseAndFulfillerHub::new()));
    let result_promise: Promise<T, E> = Promise { node: Box::new(result.clone())};
    (result_promise, Box::new(result))
}

/// Holds a collection of `Promise<()>`s and ensures that each executes to completion.
/// Destroying a TaskSet automatically cancels all of its unfinished promises.
pub struct TaskSet {
    task_set_impl: Rc<RefCell<private::TaskSetImpl>>,
}

impl TaskSet {
    pub fn new(error_handler: Box<ErrorHandler>) -> TaskSet {
        TaskSet { task_set_impl : Rc::new(RefCell::new(private::TaskSetImpl::new(error_handler))) }
    }

    pub fn add(&mut self, promise: Promise<(), Box<::std::error::Error>>) {
        private::TaskSetImpl::add(self.task_set_impl.clone(), promise.node);
    }
}

/// A callback to be invoked when a task in a `TaskSet` fails.
pub trait ErrorHandler {
    fn task_failed(&mut self, error: Box<::std::error::Error>);
}

/// Transforms a vector of promises into a promise for a vector.
pub fn join_promises<T, E>(promises: Vec<Promise<T, E>>) -> Promise<Vec<T>, E>
{
    let nodes = promises.into_iter().map(|p| { p.node }).collect();
    Promise { node: Box::new(private::promise_node::ArrayJoin::new(nodes)) }
}

impl From<Forced> for ::std::io::Error {
    fn from(_: Forced) -> ::std::io::Error {
        ::std::io::Error::new(::std::io::ErrorKind::Other, "forced unfulfilled promise")
    }
}

impl From<Forced> for Box<::std::error::Error> {
    fn from(_: Forced) -> Box<::std::error::Error> {
        ::std::io::Error::new(::std::io::ErrorKind::Other, "forced unfulfilled promise").into()
    }
}
<|endoftext|>


<commit_before>#![feature(collections)]

extern crate rust_base58;
extern crate openssl;
#[cfg(test)] extern crate rustc_serialize;

use rust_base58::ToBase58;
use self::HashType::*;

use openssl::crypto::hash as openssl_hash;

// https://github.com/jbenet/multihash
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum HashType {
    SHA1 = 0x11,
    SHA2_256 = 0x12,
    SHA2_512 = 0x13,
    SHA3 = 0x14,
    BLAKE2B = 0x40,
    BLAKE2S = 0x41,
}

impl HashType {
    pub fn from_u8(x: u8) -> Option<HashType> {
        match x {
            0x11 => Some(SHA1),
            0x12 => Some(SHA2_256),
            0x13 => Some(SHA2_512),
            0x14 => Some(SHA3),
            0x40 => Some(BLAKE2B),
            0x41 => Some(BLAKE2S),
            _ => None,
        }
    }

    pub fn to_u8(&self) -> u8 {
        *self as u8
    }
}

// Takes bytes and a HashType, returns multihash of the bytes
pub fn multihash<'a>(data: &'a[u8], hash_type: HashType) -> Multihash {
    let mut openssl_type: openssl_hash::Type = match hash_type {
        SHA1 => openssl_hash::Type::SHA1,
        SHA2_256 => openssl_hash::Type::SHA256,
        SHA2_512 => openssl_hash::Type::SHA512,
        _ => panic!("That hash function is not yet implemented. Sorry"),
    };

    let mut hashed = openssl_hash::hash(openssl_type, data);

    Multihash::encode(&hashed[..], hash_type as u8).unwrap()
}

struct HashFnTypeData {
    name: &'static str,
    default_len: u8,
}

fn hashfn_data(hft: &HashType) -> HashFnTypeData {
    match *hft {
        SHA1 =>
            HashFnTypeData { name: "sha1", default_len: 20 },
        SHA2_256 =>
            HashFnTypeData { name: "sha2-256", default_len: 32 },
        SHA2_512 =>
            HashFnTypeData { name: "sha2-512", default_len: 64 },
        SHA3 =>
            HashFnTypeData { name: "sha3", default_len: 64 },
        BLAKE2B =>
            HashFnTypeData { name: "blake2b", default_len: 64 },
        BLAKE2S =>
            HashFnTypeData { name: "blake2s", default_len: 32 },
    }
}

pub struct Multihash(Vec<u8>);

impl Multihash {
    pub fn new() -> Multihash {
        Multihash(Vec::new())
    }

    pub fn to_vec(self) -> Vec<u8> {
        self.0
    }

    // Constructs a Multihash out of the bytes of a hash and the
    // HashFnCode corresponding to the type of hash function used
    pub fn encode<'a>(data: &'a [u8], code: u8) -> Result<Multihash, EncodeError> {
        match HashType::from_u8(code) {
            None => return Err(EncodeError::UnknownCode(code)),
            Some(_) => {},
        }

        let size = data.len();
        if size > 127 {
            return Err(EncodeError::NotSupported(size));
        }

        let mut v = Vec::with_capacity(size + 2);
        v.push(code);
        v.push(size as u8);
        v.extend(data);
        Ok(Multihash(v))
    }

    pub fn decode<'a>(&'a self) -> Result<DecodedMultiHash<'a>, DecodeError> {
        let mhlen = self.0.len();
        if mhlen < 3 {
            return Err(DecodeError::TooShort);
        } else if mhlen > 129 {
            return Err(DecodeError::TooLong);
        } else {
            let digest_len = (mhlen - 2) as u8;
            if digest_len != self.0[1] {
                return Err(DecodeError::InvalidDigestLength(self.0[1], digest_len));
            }
        }

        let fn_code = match HashType::from_u8(self.0[0]) {
            None => return Err(DecodeError::UnknownCode(self.0[0])),
            Some(code) => code,
        };

        let hash_fn = hashfn_data(&fn_code);

        let decoded = DecodedMultiHash {
            code: fn_code,
            name: hash_fn.name,
            length: self.0[1],
            digest: &self.0[2..],
        };
        Ok(decoded)

    }

    pub fn to_base58_string(&self) -> String {
        self.0.to_base58()
    }
}

pub struct DecodedMultiHash<'a> {
    code: HashType,
    name: &'static str,
    length: u8,
    digest: &'a [u8],
}

#[derive(Debug)]
pub enum DecodeError {
    UnknownCode(u8),
    TooShort,
    TooLong,
    InvalidDigestLength(u8, u8), // (stated, actual)
}

#[derive(Debug)]
pub enum EncodeError {
    UnknownCode(u8),
    NotSupported(usize),
}

#[cfg(test)]
mod tests {
    use super::{Multihash, HashType, DecodedMultiHash, multihash, hashfn_data};
    use rustc_serialize::hex::FromHex;

    struct TestCase {
        hexstr: &'static str,
        hash_fn_type: HashType,
    }

    impl TestCase {
        fn new(s: &'static str, ty: HashType) -> TestCase {
            TestCase { hexstr: s, hash_fn_type: ty }
        }
    }

    static SHA1_STR: &'static str = "a228821137dacdbcd3ba5fa264f918fd
                                     a6223f7b";

    static SHA256_STR: &'static str = "95071c8e1ad3c7a016b30fd25853c1d9\
                                       e346ee7ee4afc977f554b139f71f4f30";

    static SHA512_STR: &'static str = "3912d4c1777934091ed95a15278b351e\
                                       00efa51f524af9af3320f0f6a227d551\
                                       76b1399684d15a05f03d1e519a9a9aa5\
                                       2a812a6d9bc63e5b485d6fd7ebf72114";

    #[test]
    fn test_multihash() {
        multihash(b"ABC", HashType::SHA1);
        multihash(b"ABC", HashType::SHA2_256);
        multihash(b"ABC", HashType::SHA2_512);
    }

    fn hexstr_to_vec(hexstr: &'static str) -> Vec<u8> {
        match hexstr.from_hex() {
            Err(e) => panic!("from_hex() failed with error: {:?}", e),
            Ok(vec) => vec,
        }
    }

    #[test]
    fn test_encode() {
        let mut cases = Vec::new();

        cases.push(TestCase::new(SHA1_STR, HashType::SHA1));
        cases.push(TestCase::new(SHA256_STR, HashType::SHA2_256));
        cases.push(TestCase::new(SHA512_STR, HashType::SHA2_512));

        for case in cases {
            let v = hexstr_to_vec(case.hexstr);

            let mut manual = Vec::new();
            manual.push(case.hash_fn_type as u8);
            manual.push(v.len() as u8);
            manual.extend(&v[..]);

            let mh = Multihash::encode(&v[..], case.hash_fn_type as u8).unwrap();
            assert_eq!(manual, mh.to_vec());
        }
    }

    #[test]
    fn test_decode() {
        let mut cases = Vec::new();

        cases.push(TestCase::new(SHA1_STR, HashType::SHA1));
        cases.push(TestCase::new(SHA256_STR, HashType::SHA2_256));
        cases.push(TestCase::new(SHA512_STR, HashType::SHA2_512));

        for case in cases {
            let v = hexstr_to_vec(case.hexstr);
            let digest_length = v.len() as u8;
            let mh = Multihash::encode(&v[..], case.hash_fn_type as u8).unwrap();
            let hash_name = hashfn_data(&case.hash_fn_type).name;

            match mh.decode() {
                Err(e) => panic!("Error decoding: {:?}", e),
                Ok(decoded) => {
                    assert_eq!(decoded.code, case.hash_fn_type);
                    assert_eq!(decoded.name, hash_name);
                    assert_eq!(decoded.length, digest_length);
                    assert_eq!(decoded.digest, &v[..]);
                },
            }
        }
    }

}
<commit_msg>Finish cleaning up encoding stuff from my rewrite. Decoding is left untouched for now<commit_after>extern crate rust_base58;
extern crate openssl;
#[cfg(test)] extern crate rustc_serialize;

use self::HashType::*;

use openssl::crypto::hash as openssl_hash;
use rust_base58::ToBase58;
use std::hash::Hash;

// https://github.com/jbenet/multihash
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum HashType {
    SHA1 = 0x11,
    SHA2_256 = 0x12,
    SHA2_512 = 0x13,
    SHA3 = 0x14,
    BLAKE2B = 0x40,
    BLAKE2S = 0x41,
}

impl HashType {
    pub fn from_u8(x: u8) -> Option<HashType> {
        match x {
            0x11 => Some(SHA1),
            0x12 => Some(SHA2_256),
            0x13 => Some(SHA2_512),
            0x14 => Some(SHA3),
            0x40 => Some(BLAKE2B),
            0x41 => Some(BLAKE2S),
            _ => None,
        }
    }

    pub fn to_u8(&self) -> u8 {
        *self as u8
    }
}

// Takes bytes and a HashType, returns multihash of the bytes
pub fn multihash<'a>(data: &'a[u8], hash_type: HashType) -> Multihash {
    let openssl_type: openssl_hash::Type = match hash_type {
        SHA1 => openssl_hash::Type::SHA1,
        SHA2_256 => openssl_hash::Type::SHA256,
        SHA2_512 => openssl_hash::Type::SHA512,
        _ => panic!("That hash function is not yet implemented. Sorry"),
    };

    let hashed = openssl_hash::hash(openssl_type, data);

    Multihash::encode(&hashed[..], hash_type).unwrap()
}

struct HashFnTypeData {
    name: &'static str,
    default_len: u8,
}

fn hashfn_data(hft: &HashType) -> HashFnTypeData {
    match *hft {
        SHA1 =>
            HashFnTypeData { name: "sha1", default_len: 20 },
        SHA2_256 =>
            HashFnTypeData { name: "sha2-256", default_len: 32 },
        SHA2_512 =>
            HashFnTypeData { name: "sha2-512", default_len: 64 },
        SHA3 =>
            HashFnTypeData { name: "sha3", default_len: 64 },
        BLAKE2B =>
            HashFnTypeData { name: "blake2b", default_len: 64 },
        BLAKE2S =>
            HashFnTypeData { name: "blake2s", default_len: 32 },
    }
}

#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Multihash(Vec<u8>);

impl Multihash {
    pub fn new() -> Multihash {
        Multihash(Vec::new())
    }

    pub fn as_bytes(&self) -> &[u8] {
        &self.0[..]
    }

    // Constructs a Multihash out of the bytes of a hash and the
    // HashFnCode corresponding to the type of hash function used
    pub fn encode<'a>(digest: &'a [u8], hash_type: HashType) -> Result<Multihash, String> {
        let size = digest.len();
        if size > 127 {
            return Err("Digest length > 127 is currently not supported.".to_string())
        }

        let mut v = Vec::with_capacity(size + 2);
        v.push(hash_type.to_u8());
        v.push(size as u8);
        v.extend(digest);
        Ok(Multihash(v))
    }

    pub fn decode<'a>(&'a self) -> Result<DecodedMultiHash<'a>, DecodeError> {
        let mhlen = self.0.len();
        if mhlen < 3 {
            return Err(DecodeError::TooShort);
        } else if mhlen > 129 {
            return Err(DecodeError::TooLong);
        } else {
            let digest_len = (mhlen - 2) as u8;
            if digest_len != self.0[1] {
                return Err(DecodeError::InvalidDigestLength(self.0[1], digest_len));
            }
        }

        let fn_code = match HashType::from_u8(self.0[0]) {
            None => return Err(DecodeError::UnknownCode(self.0[0])),
            Some(code) => code,
        };

        let hash_fn = hashfn_data(&fn_code);

        let decoded = DecodedMultiHash {
            code: fn_code,
            name: hash_fn.name,
            length: self.0[1],
            digest: &self.0[2..],
        };
        Ok(decoded)

    }

    pub fn to_base58_string(&self) -> String {
        self.0.to_base58()
    }
}

pub struct DecodedMultiHash<'a> {
    code: HashType,
    name: &'static str,
    length: u8,
    digest: &'a [u8],
}

#[derive(Debug)]
pub enum DecodeError {
    UnknownCode(u8),
    TooShort,
    TooLong,
    InvalidDigestLength(u8, u8), // (stated, actual)
}

#[cfg(test)]
mod tests {
    use super::{multihash, Multihash, HashType, DecodedMultiHash, hashfn_data};
    use rustc_serialize::hex::FromHex;

    struct TestCase {
        hexstr: &'static str,
        hash_type: HashType,
    }

    impl TestCase {
        fn new(s: &'static str, ty: HashType) -> TestCase {
            TestCase { hexstr: s, hash_type: ty }
        }
    }

    static SHA1_STR: &'static str = "a228821137dacdbcd3ba5fa264f918fd
                                     a6223f7b";

    static SHA256_STR: &'static str = "95071c8e1ad3c7a016b30fd25853c1d9\
                                       e346ee7ee4afc977f554b139f71f4f30";

    static SHA512_STR: &'static str = "3912d4c1777934091ed95a15278b351e\
                                       00efa51f524af9af3320f0f6a227d551\
                                       76b1399684d15a05f03d1e519a9a9aa5\
                                       2a812a6d9bc63e5b485d6fd7ebf72114";

    #[test]
    fn test_multihash() {
        let abc = b"ABC";
        let sha1_hex = "3c01bdbb26f358bab27f267924aa2c9a03fcfdb8";
        let sha256_hex = "b5d4045c3f466fa91fe2cc6abe79232a1a57cdf104f7a26e716e0a1e2789df78";
        let sha512_hex = "397118fdac8d83ad98813c50759c85b8c47565d8268bf10da483153b747a7474\
                          3a58a90e85aa9f705ce6984ffc128db567489817e4092d050d8a1cc596ddc119";

        let sha1 = multihash(abc, HashType::SHA1);
        let mut sha1_bytes = hexstr_to_vec(sha1_hex);
        let mut expected_bytes = vec![0x11, 20];
        expected_bytes.append(&mut sha1_bytes);
        assert_eq!(sha1.as_bytes(), &expected_bytes[..]);

        let sha256 = multihash(abc, HashType::SHA2_256);
        let mut sha256_bytes = hexstr_to_vec(sha256_hex);
        let mut expected_bytes = vec![0x12, 32];
        expected_bytes.append(&mut sha256_bytes);
        assert_eq!(sha256.as_bytes(), &expected_bytes[..]);

        let sha512 = multihash(abc, HashType::SHA2_512);
        let mut sha512_bytes = hexstr_to_vec(sha512_hex);
        let mut expected_bytes = vec![0x13, 64];
        expected_bytes.append(&mut sha512_bytes);
        assert_eq!(sha512.as_bytes(), &expected_bytes[..]);
    }

    fn hexstr_to_vec(hexstr: &'static str) -> Vec<u8> {
        match hexstr.from_hex() {
            Err(e) => panic!("from_hex() failed with error: {:?}", e),
            Ok(vec) => vec,
        }
    }

    #[test]
    fn test_encode() {
        let mut cases = Vec::new();

        cases.push(TestCase::new(SHA1_STR, HashType::SHA1));
        cases.push(TestCase::new(SHA256_STR, HashType::SHA2_256));
        cases.push(TestCase::new(SHA512_STR, HashType::SHA2_512));

        for case in cases {
            let v = hexstr_to_vec(case.hexstr);

            let mut expected = Vec::new();
            expected.push(case.hash_type.to_u8());
            expected.push(v.len() as u8);
            expected.extend(&v[..]);

            let mh = Multihash::encode(&v[..], case.hash_type).unwrap();
            assert_eq!(&expected[..], mh.as_bytes());
        }
    }

    #[test]
    fn test_decode() {
        let mut cases = Vec::new();

        cases.push(TestCase::new(SHA1_STR, HashType::SHA1));
        cases.push(TestCase::new(SHA256_STR, HashType::SHA2_256));
        cases.push(TestCase::new(SHA512_STR, HashType::SHA2_512));

        for case in cases {
            let v = hexstr_to_vec(case.hexstr);
            let digest_length = v.len() as u8;
            let mh = Multihash::encode(&v[..], case.hash_type).unwrap();
            let hash_name = hashfn_data(&case.hash_type).name;

            match mh.decode() {
                Err(e) => panic!("Error decoding: {:?}", e),
                Ok(decoded) => {
                    assert_eq!(decoded.code, case.hash_type);
                    assert_eq!(decoded.name, hash_name);
                    assert_eq!(decoded.length, digest_length);
                    assert_eq!(decoded.digest, &v[..]);
                },
            }
        }
    }

}
<|endoftext|>


<commit_before>// Copyright (c) <2015> <lummax>
// Licensed under MIT (http://opensource.org/licenses/MIT)

#![feature(link_llvm_intrinsics)]

extern crate libc;
use std::{mem, ptr};

pub use self::gc_object::{GCHeader, GCRTTI, GCObject, GCObjectRef};
use immix_collector::ImmixCollector;

mod macros;
mod constants;
mod gc_object;
mod block_info;
mod block_allocator;
mod line_allocator;
mod rc_collector;
mod immix_collector;
mod stack;
mod posix;

pub struct RCImmixCons {
    line_allocator: line_allocator::LineAllocator,
    rc_collector: rc_collector::RCCollector,
}

impl RCImmixCons {
    pub fn new() -> RCImmixCons {
        let block_allocator = block_allocator::BlockAllocator::new();
        return RCImmixCons {
            line_allocator: line_allocator::LineAllocator::new(block_allocator),
            rc_collector: rc_collector::RCCollector::new(),
        };
    }

    pub fn allocate(&mut self, rtti: *const GCRTTI) -> Option<GCObjectRef>{
        // XXX use LOS if size > BLOCK_SIZE - LINE_SIZE
        assert!(unsafe{ (*rtti).object_size() }
                <= constants::BLOCK_SIZE - constants::LINE_SIZE);
        return self.line_allocator.allocate(rtti);
    }

    pub fn collect(&mut self) {
        let perform_cc = self.line_allocator.prepare_collection();
        let roots = stack::enumerate_roots(&self.line_allocator);
        self.rc_collector.collect(&mut self.line_allocator, roots.as_slice());
        if perform_cc {
            ImmixCollector::collect(&mut self.line_allocator, roots.as_slice());
        }
        self.line_allocator.complete_collection();
        valgrind_assert_no_leaks!();
    }

    pub fn write_barrier(&mut self, object: GCObjectRef) {
        if self.line_allocator.is_gc_object(object) {
            self.rc_collector.write_barrier(object);
        }
    }
}

#[no_mangle]
pub extern fn rcx_create() -> *mut RCImmixCons {
    return unsafe { mem::transmute(box RCImmixCons::new()) };
}

#[no_mangle]
pub extern fn rcx_allocate(this: *mut RCImmixCons, rtti: *const GCRTTI)
    -> GCObjectRef {
    unsafe { return (*this).allocate(rtti).unwrap_or(ptr::null_mut()); }
}

#[no_mangle]
pub extern fn rcx_collect(this: *mut RCImmixCons) {
    unsafe { (*this).collect() };
}

#[no_mangle]
pub extern fn rcx_write_barrier(this: *mut RCImmixCons, object: GCObjectRef) {
    unsafe { (*this).write_barrier(object) };
}

#[no_mangle]
pub extern fn rcx_destroy(this: *mut RCImmixCons) {
    let _to_be_dropped: Box<RCImmixCons> = unsafe{ mem::transmute(this) };
}
<commit_msg>Enable automatic collection on allocation failure<commit_after>// Copyright (c) <2015> <lummax>
// Licensed under MIT (http://opensource.org/licenses/MIT)

#![feature(link_llvm_intrinsics)]

extern crate libc;
use std::{mem, ptr};

pub use self::gc_object::{GCHeader, GCRTTI, GCObject, GCObjectRef};
use immix_collector::ImmixCollector;

mod macros;
mod constants;
mod gc_object;
mod block_info;
mod block_allocator;
mod line_allocator;
mod rc_collector;
mod immix_collector;
mod stack;
mod posix;

pub struct RCImmixCons {
    line_allocator: line_allocator::LineAllocator,
    rc_collector: rc_collector::RCCollector,
}

impl RCImmixCons {
    pub fn new() -> RCImmixCons {
        let block_allocator = block_allocator::BlockAllocator::new();
        return RCImmixCons {
            line_allocator: line_allocator::LineAllocator::new(block_allocator),
            rc_collector: rc_collector::RCCollector::new(),
        };
    }

    pub fn allocate(&mut self, rtti: *const GCRTTI) -> Option<GCObjectRef>{
        // XXX use LOS if size > BLOCK_SIZE - LINE_SIZE
        assert!(unsafe{ (*rtti).object_size() }
                <= constants::BLOCK_SIZE - constants::LINE_SIZE);
        return self.line_allocator.allocate(rtti)
                                  .or_else(|| { self.collect(); self.allocate(rtti) });
    }

    pub fn collect(&mut self) {
        let perform_cc = self.line_allocator.prepare_collection();
        let roots = stack::enumerate_roots(&self.line_allocator);
        self.rc_collector.collect(&mut self.line_allocator, roots.as_slice());
        if perform_cc {
            ImmixCollector::collect(&mut self.line_allocator, roots.as_slice());
        }
        self.line_allocator.complete_collection();
        valgrind_assert_no_leaks!();
    }

    pub fn write_barrier(&mut self, object: GCObjectRef) {
        if self.line_allocator.is_gc_object(object) {
            self.rc_collector.write_barrier(object);
        }
    }
}

#[no_mangle]
pub extern fn rcx_create() -> *mut RCImmixCons {
    return unsafe { mem::transmute(box RCImmixCons::new()) };
}

#[no_mangle]
pub extern fn rcx_allocate(this: *mut RCImmixCons, rtti: *const GCRTTI)
    -> GCObjectRef {
    unsafe { return (*this).allocate(rtti).unwrap_or(ptr::null_mut()); }
}

#[no_mangle]
pub extern fn rcx_collect(this: *mut RCImmixCons) {
    unsafe { (*this).collect() };
}

#[no_mangle]
pub extern fn rcx_write_barrier(this: *mut RCImmixCons, object: GCObjectRef) {
    unsafe { (*this).write_barrier(object) };
}

#[no_mangle]
pub extern fn rcx_destroy(this: *mut RCImmixCons) {
    let _to_be_dropped: Box<RCImmixCons> = unsafe{ mem::transmute(this) };
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate heatmap;
extern crate hsl;
extern crate png;
extern crate rusttype;

use heatmap::Heatmap;
use hsl::HSL;
use png::HasParameters;
use rusttype::{FontCollection, PixelsXY, PositionedGlyph, point};
use std::fs::File;
use std::io::BufWriter;
use std::path::Path;

#[allow(dead_code)]
pub struct Waterfall {
    config: Config,
}

pub struct Config {}

impl Default for Config {
    fn default() -> Config {
        Config {}
    }
}

impl Config {
    pub fn new() -> Config {
        Default::default()
    }

    pub fn build(self) -> Waterfall {
        Waterfall::configured(self)
    }
}

struct Label {
    value: u64,
    text: String,
}

impl Default for Waterfall {
    fn default() -> Waterfall {
        Waterfall::configured(Config::default())
    }
}

impl Waterfall {
    pub fn new() -> Waterfall {
        Default::default()
    }

    pub fn configure() -> Config {
        Config::default()
    }

    fn configured(config: Config) -> Waterfall {
        Waterfall { config: config }
    }

    pub fn render_png(&mut self, heatmap: &Heatmap, file: String) {
        let height = heatmap.num_slices() as usize;
        let width = heatmap.histogram_buckets() as usize;

        // build buffer from data
        let mut buffer = ImageBuffer::<ColorRgb>::new(width, height);
        let max = find_max(heatmap);
        let mut x;
        let mut y = 0;

        // loop to color the pixels
        for slice in heatmap {
            x = 0;
            for bucket in &slice.histogram() {
                let value = (bucket.count() as f64) / (bucket.width() as f64);
                let pixel = color_from_value(value, max);
                buffer.set_pixel(x, y, pixel);
                x += 1;
            }
            y += 1;
        }

        // latency annotations
        let labels: Vec<Label> = vec![Label {
                                          value: 200,
                                          text: "200nS".to_string(),
                                      },
                                      Label {
                                          value: 500,
                                          text: "500nS".to_string(),
                                      },
                                      Label {
                                          value: 1000,
                                          text: "1uS".to_string(),
                                      },
                                      Label {
                                          value: 2000,
                                          text: "2uS".to_string(),
                                      },
                                      Label {
                                          value: 5000,
                                          text: "5uS".to_string(),
                                      },
                                      Label {
                                          value: 10000,
                                          text: "10uS".to_string(),
                                      },
                                      Label {
                                          value: 20000,
                                          text: "20uS".to_string(),
                                      },
                                      Label {
                                          value: 50000,
                                          text: "50uS".to_string(),
                                      },
                                      Label {
                                          value: 100000,
                                          text: "100uS".to_string(),
                                      },
                                      Label {
                                          value: 200000,
                                          text: "200uS".to_string(),
                                      },
                                      Label {
                                          value: 500000,
                                          text: "500uS".to_string(),
                                      },
                                      Label {
                                          value: 1000000,
                                          text: "1mS".to_string(),
                                      },
                                      Label {
                                          value: 2000000,
                                          text: "2mS".to_string(),
                                      },
                                      Label {
                                          value: 5000000,
                                          text: "5mS".to_string(),
                                      },
                                      Label {
                                          value: 10000000,
                                          text: "10mS".to_string(),
                                      },
                                      Label {
                                          value: 20000000,
                                          text: "20mS".to_string(),
                                      },
                                      Label {
                                          value: 50000000,
                                          text: "50mS".to_string(),
                                      },
                                      Label {
                                          value: 100000000,
                                          text: "100mS".to_string(),
                                      },
                                      Label {
                                          value: 200000000,
                                          text: "200mS".to_string(),
                                      },
                                      Label {
                                          value: 500000000,
                                          text: "500mS".to_string(),
                                      }];

        let mut l = 0;
        y = 0;

        for slice in heatmap {
            x = 0;
            for bucket in &slice.histogram() {
                if (y % 60) == 0 {
                    if x == 0 {
                        let hour = y / 3600;
                        let minute = y / 60;
                        let time = format!("{:02}:{:02}", hour, minute);
                        let overlay = string_buffer(&time, 25.0);
                        buffer.overlay(&overlay, x, y);
                        buffer.horizontal_line(y, ColorRgb { r: 0, g: 0, b: 0 });
                    }
                    let v = bucket.value();
                    if (l < labels.len()) && (v >= labels[l].value) {
                        let overlay = string_buffer(&labels[l].text, 25.0);
                        buffer.overlay(&overlay, x, y);
                        buffer.vertical_line(x, ColorRgb { r: 0, g: 0, b: 0 });
                        l += 1;
                    }
                }
                x += 1;
            }
            y += 1;
        }

        let _ = buffer.write_png(file.clone());
    }
}

fn find_max(heatmap: &Heatmap) -> f64 {
    let mut max = 0.0;

    for slice in heatmap {
        for bucket in &slice.histogram() {
            let value = (bucket.count() as f64) / (bucket.width() as f64);
            if value > max {
                max = value;
            }
        }
    }
    max
}

fn string_buffer(string: &str, size: f32) -> ImageBuffer<ColorRgb> {
    // load font
    let font_data = include_bytes!("../assets/ubuntumono/UbuntuMono-Regular.ttf");
    let collection = FontCollection::from_bytes(font_data as &[u8]);
    let font = collection.into_font().unwrap();

    // size and scaling
    let height: f32 = size;
    let pixel_height = height.ceil() as usize;
    let scale = PixelsXY(height * 1.0, height);

    let v_metrics = font.v_metrics(scale);
    let offset = point(0.0, v_metrics.ascent);

    let glyphs: Vec<PositionedGlyph> = font.layout(string, scale, offset).collect();

    let width = glyphs
        .iter()
        .map(|g| g.h_metrics().advance_width)
        .fold(0.0, |x, y| x + y)
        .ceil() as usize;

    let mut overlay = ImageBuffer::<ColorRgb>::new(width, pixel_height);

    for g in glyphs {
        if let Some(bb) = g.pixel_bounding_box() {
            g.draw(|x, y, v| {
                let x = (x as i32 + bb.min.x) as usize;
                let y = (y as i32 + bb.min.y) as usize;
                if v > 0.25 {
                    overlay.set_pixel(x,
                                      y,
                                      ColorRgb {
                                          r: 255,
                                          g: 255,
                                          b: 255,
                                      });
                }
            })
        }
    }

    overlay
}

fn color_from_value(value: f64, max: f64) -> ColorRgb {
    let value = value / max;

    let knee = 0.10_f64;

    let hsl = if value < knee {
        let l = 0.25_f64 + 0.25_f64 * value / knee;
        HSL {
            h: 236_f64,
            s: 1_f64,
            l: l,
        }
    } else {
        let h_per_deg: f64 = 236_f64 / (1.0_f64 - knee);
        let deg = (value - knee) * h_per_deg;

        HSL {
            h: (236_f64 - deg),
            s: 1_f64,
            l: 0.50_f64,
        }
    };

    let (r, g, b) = hsl.to_rgb();

    ColorRgb { r: r, g: g, b: b }
}

#[derive(Clone, Copy, Debug, PartialEq)]
struct ColorRgb {
    r: u8,
    g: u8,
    b: u8,
}

struct ImageBuffer<T> {
    buffer: Vec<Vec<T>>,
    height: usize,
    width: usize,
}

impl ImageBuffer<ColorRgb> {
    pub fn new(width: usize, height: usize) -> ImageBuffer<ColorRgb> {
        let background = ColorRgb { r: 0, g: 0, b: 0 };
        let mut row = Vec::<ColorRgb>::with_capacity(width);
        for _ in 0..width {
            row.push(background);
        }
        let mut buffer = Vec::<Vec<ColorRgb>>::with_capacity(height);
        for _ in 0..height {
            buffer.push(row.clone());
        }
        ImageBuffer {
            buffer: buffer,
            height: height,
            width: width,
        }
    }

    pub fn write_png(self, file: String) -> Result<(), &'static str> {
        let mut buffer = Vec::<u8>::with_capacity(self.height * self.width);
        for row in 0..self.height {
            for col in 0..self.width {
                let pixel = self.buffer[row][col];
                buffer.push(pixel.r);
                buffer.push(pixel.g);
                buffer.push(pixel.b);
            }
        }
        let path = &Path::new(&file);
        if let Ok(file) = File::create(path) {
            let w = BufWriter::new(file);
            let mut encoder = png::Encoder::new(w, self.width as u32, self.height as u32);
            encoder.set(png::ColorType::RGB).set(png::BitDepth::Eight);
            if let Ok(mut writer) = encoder.write_header() {
                if writer.write_image_data(&buffer).is_ok() {
                    Ok(())
                } else {
                    Err("Error writing PNG data")
                }
            } else {
                Err("Error writing PNG header")
            }
        } else {
            Err("Error creating file")
        }
    }

    pub fn set_pixel(&mut self, x: usize, y: usize, value: ColorRgb) {
        if x < self.width && y < self.height {
            self.buffer[y][x] = value;
        }
    }

    pub fn overlay(&mut self, other: &ImageBuffer<ColorRgb>, x: usize, y: usize) {
        let ignore = ColorRgb { r: 0, g: 0, b: 0 };
        for sx in 0..other.width {
            for sy in 0..other.height {
                if (other.buffer[sy][sx] != ignore) &&
                   (((sy + y) < self.height) && ((sx + x) < self.width)) {
                    self.buffer[(sy + y)][(sx + x)] = other.buffer[sy][sx];
                }
            }
        }
    }

    pub fn horizontal_line(&mut self, y: usize, color: ColorRgb) {
        for x in 0..self.width {
            self.buffer[y][x] = color;
        }
    }

    pub fn vertical_line(&mut self, x: usize, color: ColorRgb) {
        for y in 0..self.height {
            self.buffer[y][x] = color;
        }
    }
}
<commit_msg>style: rustfmt 0.9.0 (#18)<commit_after>#![deny(warnings)]

extern crate heatmap;
extern crate hsl;
extern crate png;
extern crate rusttype;

use heatmap::Heatmap;
use hsl::HSL;
use png::HasParameters;
use rusttype::{FontCollection, PixelsXY, PositionedGlyph, point};
use std::fs::File;
use std::io::BufWriter;
use std::path::Path;

#[allow(dead_code)]
pub struct Waterfall {
    config: Config,
}

pub struct Config {}

impl Default for Config {
    fn default() -> Config {
        Config {}
    }
}

impl Config {
    pub fn new() -> Config {
        Default::default()
    }

    pub fn build(self) -> Waterfall {
        Waterfall::configured(self)
    }
}

struct Label {
    value: u64,
    text: String,
}

impl Default for Waterfall {
    fn default() -> Waterfall {
        Waterfall::configured(Config::default())
    }
}

impl Waterfall {
    pub fn new() -> Waterfall {
        Default::default()
    }

    pub fn configure() -> Config {
        Config::default()
    }

    fn configured(config: Config) -> Waterfall {
        Waterfall { config: config }
    }

    pub fn render_png(&mut self, heatmap: &Heatmap, file: String) {
        let height = heatmap.num_slices() as usize;
        let width = heatmap.histogram_buckets() as usize;

        // build buffer from data
        let mut buffer = ImageBuffer::<ColorRgb>::new(width, height);
        let max = find_max(heatmap);
        let mut x;
        let mut y = 0;

        // loop to color the pixels
        for slice in heatmap {
            x = 0;
            for bucket in &slice.histogram() {
                let value = (bucket.count() as f64) / (bucket.width() as f64);
                let pixel = color_from_value(value, max);
                buffer.set_pixel(x, y, pixel);
                x += 1;
            }
            y += 1;
        }

        // latency annotations
        let labels: Vec<Label> = vec![
            Label {
                value: 200,
                text: "200nS".to_string(),
            },
            Label {
                value: 500,
                text: "500nS".to_string(),
            },
            Label {
                value: 1000,
                text: "1uS".to_string(),
            },
            Label {
                value: 2000,
                text: "2uS".to_string(),
            },
            Label {
                value: 5000,
                text: "5uS".to_string(),
            },
            Label {
                value: 10000,
                text: "10uS".to_string(),
            },
            Label {
                value: 20000,
                text: "20uS".to_string(),
            },
            Label {
                value: 50000,
                text: "50uS".to_string(),
            },
            Label {
                value: 100000,
                text: "100uS".to_string(),
            },
            Label {
                value: 200000,
                text: "200uS".to_string(),
            },
            Label {
                value: 500000,
                text: "500uS".to_string(),
            },
            Label {
                value: 1000000,
                text: "1mS".to_string(),
            },
            Label {
                value: 2000000,
                text: "2mS".to_string(),
            },
            Label {
                value: 5000000,
                text: "5mS".to_string(),
            },
            Label {
                value: 10000000,
                text: "10mS".to_string(),
            },
            Label {
                value: 20000000,
                text: "20mS".to_string(),
            },
            Label {
                value: 50000000,
                text: "50mS".to_string(),
            },
            Label {
                value: 100000000,
                text: "100mS".to_string(),
            },
            Label {
                value: 200000000,
                text: "200mS".to_string(),
            },
            Label {
                value: 500000000,
                text: "500mS".to_string(),
            },
        ];

        let mut l = 0;
        y = 0;

        for slice in heatmap {
            x = 0;
            for bucket in &slice.histogram() {
                if (y % 60) == 0 {
                    if x == 0 {
                        let hour = y / 3600;
                        let minute = y / 60;
                        let time = format!("{:02}:{:02}", hour, minute);
                        let overlay = string_buffer(&time, 25.0);
                        buffer.overlay(&overlay, x, y);
                        buffer.horizontal_line(y, ColorRgb { r: 0, g: 0, b: 0 });
                    }
                    let v = bucket.value();
                    if (l < labels.len()) && (v >= labels[l].value) {
                        let overlay = string_buffer(&labels[l].text, 25.0);
                        buffer.overlay(&overlay, x, y);
                        buffer.vertical_line(x, ColorRgb { r: 0, g: 0, b: 0 });
                        l += 1;
                    }
                }
                x += 1;
            }
            y += 1;
        }

        let _ = buffer.write_png(file.clone());
    }
}

fn find_max(heatmap: &Heatmap) -> f64 {
    let mut max = 0.0;

    for slice in heatmap {
        for bucket in &slice.histogram() {
            let value = (bucket.count() as f64) / (bucket.width() as f64);
            if value > max {
                max = value;
            }
        }
    }
    max
}

fn string_buffer(string: &str, size: f32) -> ImageBuffer<ColorRgb> {
    // load font
    let font_data = include_bytes!("../assets/ubuntumono/UbuntuMono-Regular.ttf");
    let collection = FontCollection::from_bytes(font_data as &[u8]);
    let font = collection.into_font().unwrap();

    // size and scaling
    let height: f32 = size;
    let pixel_height = height.ceil() as usize;
    let scale = PixelsXY(height * 1.0, height);

    let v_metrics = font.v_metrics(scale);
    let offset = point(0.0, v_metrics.ascent);

    let glyphs: Vec<PositionedGlyph> = font.layout(string, scale, offset).collect();

    let width = glyphs
        .iter()
        .map(|g| g.h_metrics().advance_width)
        .fold(0.0, |x, y| x + y)
        .ceil() as usize;

    let mut overlay = ImageBuffer::<ColorRgb>::new(width, pixel_height);

    for g in glyphs {
        if let Some(bb) = g.pixel_bounding_box() {
            g.draw(|x, y, v| {
                let x = (x as i32 + bb.min.x) as usize;
                let y = (y as i32 + bb.min.y) as usize;
                if v > 0.25 {
                    overlay.set_pixel(
                        x,
                        y,
                        ColorRgb {
                            r: 255,
                            g: 255,
                            b: 255,
                        },
                    );
                }
            })
        }
    }

    overlay
}

fn color_from_value(value: f64, max: f64) -> ColorRgb {
    let value = value / max;

    let knee = 0.10_f64;

    let hsl = if value < knee {
        let l = 0.25_f64 + 0.25_f64 * value / knee;
        HSL {
            h: 236_f64,
            s: 1_f64,
            l: l,
        }
    } else {
        let h_per_deg: f64 = 236_f64 / (1.0_f64 - knee);
        let deg = (value - knee) * h_per_deg;

        HSL {
            h: (236_f64 - deg),
            s: 1_f64,
            l: 0.50_f64,
        }
    };

    let (r, g, b) = hsl.to_rgb();

    ColorRgb { r: r, g: g, b: b }
}

#[derive(Clone, Copy, Debug, PartialEq)]
struct ColorRgb {
    r: u8,
    g: u8,
    b: u8,
}

struct ImageBuffer<T> {
    buffer: Vec<Vec<T>>,
    height: usize,
    width: usize,
}

impl ImageBuffer<ColorRgb> {
    pub fn new(width: usize, height: usize) -> ImageBuffer<ColorRgb> {
        let background = ColorRgb { r: 0, g: 0, b: 0 };
        let mut row = Vec::<ColorRgb>::with_capacity(width);
        for _ in 0..width {
            row.push(background);
        }
        let mut buffer = Vec::<Vec<ColorRgb>>::with_capacity(height);
        for _ in 0..height {
            buffer.push(row.clone());
        }
        ImageBuffer {
            buffer: buffer,
            height: height,
            width: width,
        }
    }

    pub fn write_png(self, file: String) -> Result<(), &'static str> {
        let mut buffer = Vec::<u8>::with_capacity(self.height * self.width);
        for row in 0..self.height {
            for col in 0..self.width {
                let pixel = self.buffer[row][col];
                buffer.push(pixel.r);
                buffer.push(pixel.g);
                buffer.push(pixel.b);
            }
        }
        let path = &Path::new(&file);
        if let Ok(file) = File::create(path) {
            let w = BufWriter::new(file);
            let mut encoder = png::Encoder::new(w, self.width as u32, self.height as u32);
            encoder.set(png::ColorType::RGB).set(png::BitDepth::Eight);
            if let Ok(mut writer) = encoder.write_header() {
                if writer.write_image_data(&buffer).is_ok() {
                    Ok(())
                } else {
                    Err("Error writing PNG data")
                }
            } else {
                Err("Error writing PNG header")
            }
        } else {
            Err("Error creating file")
        }
    }

    pub fn set_pixel(&mut self, x: usize, y: usize, value: ColorRgb) {
        if x < self.width && y < self.height {
            self.buffer[y][x] = value;
        }
    }

    pub fn overlay(&mut self, other: &ImageBuffer<ColorRgb>, x: usize, y: usize) {
        let ignore = ColorRgb { r: 0, g: 0, b: 0 };
        for sx in 0..other.width {
            for sy in 0..other.height {
                if (other.buffer[sy][sx] != ignore) &&
                    (((sy + y) < self.height) && ((sx + x) < self.width))
                {
                    self.buffer[(sy + y)][(sx + x)] = other.buffer[sy][sx];
                }
            }
        }
    }

    pub fn horizontal_line(&mut self, y: usize, color: ColorRgb) {
        for x in 0..self.width {
            self.buffer[y][x] = color;
        }
    }

    pub fn vertical_line(&mut self, x: usize, color: ColorRgb) {
        for y in 0..self.height {
            self.buffer[y][x] = color;
        }
    }
}
<|endoftext|>


<commit_before>extern crate cards;
extern crate holdem;

mod types;
mod lookups;
mod original;
//mod perfect;
pub mod utils;

use cards::card::{Card};
use holdem::{HandCards, CommunityCards};

use holdem::{HandRank};

pub fn eval_5cards(cards: [&Card; 5]) -> HandRank {
    original::eval_5cards(cards)
}

pub fn eval_6cards(cards: [&Card; 6]) -> HandRank {
    original::eval_6cards(cards)
}

pub fn eval_7cards(cards: [&Card; 7]) -> HandRank {
    original::eval_7cards(cards)
}

//TODO: is panic an acceptable behaviour here? Be more verbose about this function expecting all cards to be present?
pub fn eval_for_player(player_cards: &HandCards, community_cards: &CommunityCards) -> HandRank {
    let cards : [&Card; 7] = [
        &player_cards.0.expect_borrow(),
        &player_cards.1.expect_borrow(),
        &community_cards.0.expect_borrow(),
        &community_cards.1.expect_borrow(),
        &community_cards.2.expect_borrow(),
        &community_cards.3.expect_borrow(),
        &community_cards.4.expect_borrow()
    ];

    eval_7cards(cards)
}

//use cards::deck::{Deck};
//use pokereval::{original, perfect}; // two evaluation methods

/*
//TODO: as soon as both methods are expected to agree
// this guy does not always pass
#[test]
fn both_evaluation_methods_agree() {
    let mut deck = Deck::new();

    // try on 10 hands
    for _ in 0..10 {
        let c1 = deck.draw();
        let c2 = deck.draw();
        let c3 = deck.draw();
        let c4 = deck.draw();
        let c5 = deck.draw();

        let rank_original = original::eval_5cards([&c1, &c2, &c3, &c4, &c5]);
        let rank_perfect = perfect::eval_5cards([&c1, &c2, &c3, &c4, &c5]);
        assert_eq!(rank_original, rank_perfect);
    }
}
*/
<commit_msg>Pub all the things.<commit_after>extern crate cards;
extern crate holdem;

pub mod types;
mod lookups;
pub mod original;
//mod perfect;
pub mod utils;

use cards::card::{Card};
use holdem::{HandCards, CommunityCards};

use holdem::{HandRank};

pub fn eval_5cards(cards: [&Card; 5]) -> HandRank {
    original::eval_5cards(cards)
}

pub fn eval_6cards(cards: [&Card; 6]) -> HandRank {
    original::eval_6cards(cards)
}

pub fn eval_7cards(cards: [&Card; 7]) -> HandRank {
    original::eval_7cards(cards)
}

//TODO: is panic an acceptable behaviour here? Be more verbose about this function expecting all cards to be present?
pub fn eval_for_player(player_cards: &HandCards, community_cards: &CommunityCards) -> HandRank {
    let cards : [&Card; 7] = [
        &player_cards.0.expect_borrow(),
        &player_cards.1.expect_borrow(),
        &community_cards.0.expect_borrow(),
        &community_cards.1.expect_borrow(),
        &community_cards.2.expect_borrow(),
        &community_cards.3.expect_borrow(),
        &community_cards.4.expect_borrow()
    ];

    eval_7cards(cards)
}

//use cards::deck::{Deck};
//use pokereval::{original, perfect}; // two evaluation methods

/*
//TODO: as soon as both methods are expected to agree
// this guy does not always pass
#[test]
fn both_evaluation_methods_agree() {
    let mut deck = Deck::new();

    // try on 10 hands
    for _ in 0..10 {
        let c1 = deck.draw();
        let c2 = deck.draw();
        let c3 = deck.draw();
        let c4 = deck.draw();
        let c5 = deck.draw();

        let rank_original = original::eval_5cards([&c1, &c2, &c3, &c4, &c5]);
        let rank_perfect = perfect::eval_5cards([&c1, &c2, &c3, &c4, &c5]);
        assert_eq!(rank_original, rank_perfect);
    }
}
*/
<|endoftext|>


<commit_before>// #![feature(plugin, custom_attribute)]
// #![plugin(c_import)]

//! Message Passing Interface bindings for Rust
//!
//! The [Message Passing Interface][MPI] (MPI) is a specification for a
//! message-passing style concurrency library. Implementations of MPI are often used to structure
//! parallel computation on High Performance Computing systems. The MPI specification describes
//! bindings for the C programming language (and through it C++) as well as for the Fortran
//! programming language. This library tries to bridge the gap into a more rustic world.
//!
//! [MPI]: http://www.mpi-forum.org
//!
//! # Usage
//!
//! Add the `mpi` crate as a dependency in your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! mpi = "0.1.9"
//! ```
//!
//! Then use it in your program like this:
//!
//! ```no_run
//! extern crate mpi;
//!
//! use mpi::traits::*;
//!
//! fn main() {
//!     let universe = mpi::initialize().unwrap();
//!     let world = universe.world();
//!     let size = world.size();
//!     let rank = world.rank();
//!
//!     if size != 2 {
//!         panic!("Size of MPI_COMM_WORLD must be 2, but is {}!", size);
//!      }
//!
//!     match rank {
//!         0 => {
//!             let msg = vec![4.0f64, 8.0, 15.0];
//!             world.process_at_rank(rank + 1).send(&msg[..]);
//!         }
//!         1 => {
//!             let (msg, status) = world.receive_vec::<f64>();
//!             println!("Process {} got message {:?}.\nStatus is: {:?}", rank, msg, status);
//!         }
//!         _ => unreachable!()
//!     }
//! }
//! ```
//!
//! # Features
//!
//! The bindings follow the MPI 3.1 specification.
//!
//! Currently supported:
//!
//! - **Groups, Contexts, Communicators**:
//!   - Group and (Intra-)Communicator management from section 6 is mostly complete.
//!   - no Inter-Communicators
//!   - noprocess topologies
//! - **Point to point communication**:
//!   - standard, buffered, synchronous and ready mode send in blocking and non-blocking variants
//!   - receive in blocking and non-blocking variants
//!   - send-receive
//!   - probe
//!   - matched probe/receive
//! - **Collective communication**:
//!   - barrier in blocking and non-blocking variants
//!   - broadcast
//!   - (all) gather
//!   - scatter
//!   - all to all
//!   - no varying counts operations
//!   - no reductions/scans
//! - **Datatypes**: Bridging between Rust types and MPI basic types as well as custom MPI datatypes
//! which can act as views into buffers.
//!
//! Not supported (yet):
//!
//! - Process management
//! - One-sided communication (RMA)
//! - MPI parallel I/O
//! - A million small things
//!
//! The sub-modules contain a more detailed description of which features are and are not
//! supported.

use std::mem;
use std::string::{FromUtf8Error};

extern crate libc;

use libc::{c_char, c_int};

/// The raw C language MPI API
///
/// Documented in the [Message Passing Interface specification][spec]
///
/// [spec]: http://www.mpi-forum.org/docs/docs.html
#[allow(dead_code, non_snake_case, non_camel_case_types)]
pub mod ffi;

pub mod collective;
pub mod datatype;
pub mod point_to_point;
pub mod topology;
pub mod traits;

#[doc(inline)]
pub use topology::{initialize, initialize_with_threading, Threading};

use ffi::MPI_Aint;

/// Encodes error values returned by MPI functions.
pub type Error = c_int;
/// Encodes number of values in multi-value messages.
pub type Count = c_int;
/// Can be used to tag messages on the sender side and match on the receiver side.
pub type Tag = c_int;
/// An address in memory
pub type Address = MPI_Aint;

/// Identifies the version of the MPI standard implemented by the library.
///
/// Returns a tuple of `(version, subversion)`, e.g. `(3, 0)`.
///
/// Can be called without initializing MPI.
pub fn get_version() -> (c_int, c_int) {
    let mut version: c_int = unsafe { mem::uninitialized() };
    let mut subversion: c_int = unsafe { mem::uninitialized() };
    unsafe { ffi::MPI_Get_version(&mut version as *mut c_int, &mut subversion as *mut c_int); }
    (version, subversion)
}

/// Describes the version of the MPI library itself.
///
/// Can return an `Err` if the description of the MPI library is not a UTF-8 string.
///
/// Can be called without initializing MPI.
pub fn get_library_version() -> Result<String, FromUtf8Error> {
    let mut buf = vec![0u8; ffi::RSMPI_MAX_LIBRARY_VERSION_STRING as usize];
    let mut len: c_int = 0;

    unsafe { ffi::MPI_Get_library_version(buf.as_mut_ptr() as *mut c_char, &mut len as *mut c_int); }
    buf.truncate(len as usize);
    String::from_utf8(buf)
}
<commit_msg>Deny compiling when documentation is missing.<commit_after>// #![feature(plugin, custom_attribute)]
// #![plugin(c_import)]
#![deny(missing_docs)]

//! Message Passing Interface bindings for Rust
//!
//! The [Message Passing Interface][MPI] (MPI) is a specification for a
//! message-passing style concurrency library. Implementations of MPI are often used to structure
//! parallel computation on High Performance Computing systems. The MPI specification describes
//! bindings for the C programming language (and through it C++) as well as for the Fortran
//! programming language. This library tries to bridge the gap into a more rustic world.
//!
//! [MPI]: http://www.mpi-forum.org
//!
//! # Usage
//!
//! Add the `mpi` crate as a dependency in your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! mpi = "0.1.9"
//! ```
//!
//! Then use it in your program like this:
//!
//! ```no_run
//! extern crate mpi;
//!
//! use mpi::traits::*;
//!
//! fn main() {
//!     let universe = mpi::initialize().unwrap();
//!     let world = universe.world();
//!     let size = world.size();
//!     let rank = world.rank();
//!
//!     if size != 2 {
//!         panic!("Size of MPI_COMM_WORLD must be 2, but is {}!", size);
//!      }
//!
//!     match rank {
//!         0 => {
//!             let msg = vec![4.0f64, 8.0, 15.0];
//!             world.process_at_rank(rank + 1).send(&msg[..]);
//!         }
//!         1 => {
//!             let (msg, status) = world.receive_vec::<f64>();
//!             println!("Process {} got message {:?}.\nStatus is: {:?}", rank, msg, status);
//!         }
//!         _ => unreachable!()
//!     }
//! }
//! ```
//!
//! # Features
//!
//! The bindings follow the MPI 3.1 specification.
//!
//! Currently supported:
//!
//! - **Groups, Contexts, Communicators**:
//!   - Group and (Intra-)Communicator management from section 6 is mostly complete.
//!   - no Inter-Communicators
//!   - noprocess topologies
//! - **Point to point communication**:
//!   - standard, buffered, synchronous and ready mode send in blocking and non-blocking variants
//!   - receive in blocking and non-blocking variants
//!   - send-receive
//!   - probe
//!   - matched probe/receive
//! - **Collective communication**:
//!   - barrier in blocking and non-blocking variants
//!   - broadcast
//!   - (all) gather
//!   - scatter
//!   - all to all
//!   - no varying counts operations
//!   - no reductions/scans
//! - **Datatypes**: Bridging between Rust types and MPI basic types as well as custom MPI datatypes
//! which can act as views into buffers.
//!
//! Not supported (yet):
//!
//! - Process management
//! - One-sided communication (RMA)
//! - MPI parallel I/O
//! - A million small things
//!
//! The sub-modules contain a more detailed description of which features are and are not
//! supported.

use std::mem;
use std::string::{FromUtf8Error};

extern crate libc;

use libc::{c_char, c_int};

/// The raw C language MPI API
///
/// Documented in the [Message Passing Interface specification][spec]
///
/// [spec]: http://www.mpi-forum.org/docs/docs.html
#[allow(missing_docs, dead_code, non_snake_case, non_camel_case_types)]
pub mod ffi;

pub mod collective;
pub mod datatype;
pub mod point_to_point;
pub mod topology;
pub mod traits;

#[doc(inline)]
pub use topology::{initialize, initialize_with_threading, Threading};

use ffi::MPI_Aint;

/// Encodes error values returned by MPI functions.
pub type Error = c_int;
/// Encodes number of values in multi-value messages.
pub type Count = c_int;
/// Can be used to tag messages on the sender side and match on the receiver side.
pub type Tag = c_int;
/// An address in memory
pub type Address = MPI_Aint;

/// Identifies the version of the MPI standard implemented by the library.
///
/// Returns a tuple of `(version, subversion)`, e.g. `(3, 0)`.
///
/// Can be called without initializing MPI.
pub fn get_version() -> (c_int, c_int) {
    let mut version: c_int = unsafe { mem::uninitialized() };
    let mut subversion: c_int = unsafe { mem::uninitialized() };
    unsafe { ffi::MPI_Get_version(&mut version as *mut c_int, &mut subversion as *mut c_int); }
    (version, subversion)
}

/// Describes the version of the MPI library itself.
///
/// Can return an `Err` if the description of the MPI library is not a UTF-8 string.
///
/// Can be called without initializing MPI.
pub fn get_library_version() -> Result<String, FromUtf8Error> {
    let mut buf = vec![0u8; ffi::RSMPI_MAX_LIBRARY_VERSION_STRING as usize];
    let mut len: c_int = 0;

    unsafe { ffi::MPI_Get_library_version(buf.as_mut_ptr() as *mut c_char, &mut len as *mut c_int); }
    buf.truncate(len as usize);
    String::from_utf8(buf)
}
<|endoftext|>