<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! A generic, safe mechanism by which DOM objects can be pinned and transferred
//! between threads (or intra-thread for asynchronous events). Akin to Gecko's
//! nsMainThreadPtrHandle, this uses thread-safe reference counting and ensures
//! that the actual SpiderMonkey GC integration occurs on the script thread via
//! weak refcounts. Ownership of a `Trusted<T>` object means the DOM object of
//! type T to which it points remains alive. Any other behaviour is undefined.
//! To guarantee the lifetime of a DOM object when performing asynchronous operations,
//! obtain a `Trusted<T>` from that object and pass it along with each operation.
//! A usable pointer to the original DOM object can be obtained on the script thread
//! from a `Trusted<T>` via the `root` method.
//!
//! The implementation of `Trusted<T>` is as follows:
//! The `Trusted<T>` object contains an atomic reference counted pointer to the Rust DOM object.
//! A hashtable resides in the script thread, keyed on the pointer.
//! The values in this hashtable are weak reference counts. When a `Trusted<T>` object is
//! created or cloned, the reference count is increased. When a `Trusted<T>` is dropped, the count
//! decreases. If the count hits zero, the weak reference is emptied, and is removed from
//! its hash table during the next GC. During GC, the entries of the hash table are counted
//! as JS roots.

use core::nonzero::NonZero;
use dom::bindings::conversions::ToJSValConvertible;
use dom::bindings::error::Error;
use dom::bindings::js::Root;
use dom::bindings::reflector::{DomObject, Reflector};
use dom::bindings::trace::trace_reflector;
use dom::promise::Promise;
use js::jsapi::JSAutoCompartment;
use js::jsapi::JSTracer;
use libc;
use std::cell::RefCell;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::hash_map::HashMap;
use std::hash::Hash;
use std::marker::PhantomData;
use std::os;
use std::rc::Rc;
use std::sync::{Arc, Weak};
use task::Task;

#[allow(missing_docs)]  // FIXME
mod dummy {  // Attributes don’t apply through the macro.
    use std::cell::RefCell;
    use std::rc::Rc;
    use super::LiveDOMReferences;
    thread_local!(pub static LIVE_REFERENCES: Rc<RefCell<Option<LiveDOMReferences>>> =
            Rc::new(RefCell::new(None)));
}
pub use self::dummy::LIVE_REFERENCES;

/// A pointer to a Rust DOM object that needs to be destroyed.
pub struct TrustedReference(*const libc::c_void);
unsafe impl Send for TrustedReference {}

impl TrustedReference {
    fn new<T: DomObject>(ptr: *const T) -> TrustedReference {
        TrustedReference(ptr as *const libc::c_void)
    }
}

/// A safe wrapper around a DOM Promise object that can be shared among threads for use
/// in asynchronous operations. The underlying DOM object is guaranteed to live at least
/// as long as the last outstanding `TrustedPromise` instance. These values cannot be cloned,
/// only created from existing Rc<Promise> values.
pub struct TrustedPromise {
    dom_object: *const Promise,
    owner_thread: *const libc::c_void,
}

unsafe impl Send for TrustedPromise {}

impl TrustedPromise {
    /// Create a new `TrustedPromise` instance from an existing DOM object. The object will
    /// be prevented from being GCed for the duration of the resulting `TrustedPromise` object's
    /// lifetime.
    #[allow(unrooted_must_root)]
    pub fn new(promise: Rc<Promise>) -> TrustedPromise {
        LIVE_REFERENCES.with(|ref r| {
            let r = r.borrow();
            let live_references = r.as_ref().unwrap();
            let ptr = &*promise as *const Promise;
            live_references.addref_promise(promise);
            TrustedPromise {
                dom_object: ptr,
                owner_thread: (&*live_references) as *const _ as *const libc::c_void,
            }
        })
    }

    /// Obtain a usable DOM Promise from a pinned `TrustedPromise` value. Fails if used on
    /// a different thread than the original value from which this `TrustedPromise` was
    /// obtained.
    #[allow(unrooted_must_root)]
    pub fn root(self) -> Rc<Promise> {
        LIVE_REFERENCES.with(|ref r| {
            let r = r.borrow();
            let live_references = r.as_ref().unwrap();
            assert!(self.owner_thread == (&*live_references) as *const _ as *const libc::c_void);
            // Borrow-check error requires the redundant `let promise = ...; promise` here.
            let promise = match live_references.promise_table.borrow_mut().entry(self.dom_object) {
                Occupied(mut entry) => {
                    let promise = {
                        let promises = entry.get_mut();
                        promises.pop().expect("rooted promise list unexpectedly empty")
                    };
                    if entry.get().is_empty() {
                        entry.remove();
                    }
                    promise
                }
                Vacant(_) => unreachable!(),
            };
            promise
        })
    }

    /// A task which will reject the promise.
    #[allow(unrooted_must_root)]
    pub fn reject_task(self, error: Error) -> impl Send + Task {
        struct RejectPromise(TrustedPromise, Error);
        impl Task for RejectPromise {
            fn run(self: Box<Self>) {
                debug!("Rejecting promise.");
                let this = *self;
                let promise = this.0.root();
                let cx = promise.global().get_cx();
                let _ac = JSAutoCompartment::new(cx, promise.reflector().get_jsobject().get());
                promise.reject_error(cx, this.1);
            }
        }
        RejectPromise(self, error)
    }

    /// A task which will resolve the promise.
    #[allow(unrooted_must_root)]
    pub fn resolve_task<T>(self, value: T) -> impl Send + Task
    where
        T: ToJSValConvertible + Send,
    {
        struct ResolvePromise<T>(TrustedPromise, T);
        impl<T: ToJSValConvertible> Task for ResolvePromise<T> {
            fn run(self: Box<Self>) {
                debug!("Resolving promise.");
                let this = *self;
                let promise = this.0.root();
                let cx = promise.global().get_cx();
                let _ac = JSAutoCompartment::new(cx, promise.reflector().get_jsobject().get());
                promise.resolve_native(cx, &this.1);
            }
        }
        ResolvePromise(self, value)
    }
}

/// A safe wrapper around a raw pointer to a DOM object that can be
/// shared among threads for use in asynchronous operations. The underlying
/// DOM object is guaranteed to live at least as long as the last outstanding
/// `Trusted<T>` instance.
#[allow_unrooted_interior]
pub struct Trusted<T: DomObject> {
    /// A pointer to the Rust DOM object of type T, but void to allow
    /// sending `Trusted<T>` between threads, regardless of T's sendability.
    refcount: Arc<TrustedReference>,
    owner_thread: *const libc::c_void,
    phantom: PhantomData<T>,
}

unsafe impl<T: DomObject> Send for Trusted<T> {}

impl<T: DomObject> Trusted<T> {
    /// Create a new `Trusted<T>` instance from an existing DOM pointer. The DOM object will
    /// be prevented from being GCed for the duration of the resulting `Trusted<T>` object's
    /// lifetime.
    pub fn new(ptr: &T) -> Trusted<T> {
        LIVE_REFERENCES.with(|ref r| {
            let r = r.borrow();
            let live_references = r.as_ref().unwrap();
            let refcount = live_references.addref(&*ptr as *const T);
            Trusted {
                refcount: refcount,
                owner_thread: (&*live_references) as *const _ as *const libc::c_void,
                phantom: PhantomData,
            }
        })
    }

    /// Obtain a usable DOM pointer from a pinned `Trusted<T>` value. Fails if used on
    /// a different thread than the original value from which this `Trusted<T>` was
    /// obtained.
    pub fn root(&self) -> Root<T> {
        assert!(LIVE_REFERENCES.with(|ref r| {
            let r = r.borrow();
            let live_references = r.as_ref().unwrap();
            self.owner_thread == (&*live_references) as *const _ as *const libc::c_void
        }));
        unsafe {
            Root::new(NonZero::new_unchecked(self.refcount.0 as *const T))
        }
    }
}

impl<T: DomObject> Clone for Trusted<T> {
    fn clone(&self) -> Trusted<T> {
        Trusted {
            refcount: self.refcount.clone(),
            owner_thread: self.owner_thread,
            phantom: PhantomData,
        }
    }
}

/// The set of live, pinned DOM objects that are currently prevented
/// from being garbage collected due to outstanding references.
#[allow(unrooted_must_root)]
pub struct LiveDOMReferences {
    // keyed on pointer to Rust DOM object
    reflectable_table: RefCell<HashMap<*const libc::c_void, Weak<TrustedReference>>>,
    promise_table: RefCell<HashMap<*const Promise, Vec<Rc<Promise>>>>,
}

impl LiveDOMReferences {
    /// Set up the thread-local data required for storing the outstanding DOM references.
    pub fn initialize() {
        LIVE_REFERENCES.with(|ref r| {
            *r.borrow_mut() = Some(LiveDOMReferences {
                reflectable_table: RefCell::new(HashMap::new()),
                promise_table: RefCell::new(HashMap::new()),
            })
        });
    }

    #[allow(unrooted_must_root)]
    fn addref_promise(&self, promise: Rc<Promise>) {
        let mut table = self.promise_table.borrow_mut();
        table.entry(&*promise).or_insert(vec![]).push(promise)
    }

    fn addref<T: DomObject>(&self, ptr: *const T) -> Arc<TrustedReference> {
        let mut table = self.reflectable_table.borrow_mut();
        let capacity = table.capacity();
        let len = table.len();
        if (0 < capacity) && (capacity <= len) {
            info!("growing refcounted references by {}", len);
            remove_nulls(&mut table);
            table.reserve(len);
        }
        match table.entry(ptr as *const libc::c_void) {
            Occupied(mut entry) => match entry.get().upgrade() {
                Some(refcount) => refcount,
                None => {
                    let refcount = Arc::new(TrustedReference::new(ptr));
                    entry.insert(Arc::downgrade(&refcount));
                    refcount
                },
            },
            Vacant(entry) => {
                let refcount = Arc::new(TrustedReference::new(ptr));
                entry.insert(Arc::downgrade(&refcount));
                refcount
            }
        }
    }
}

/// Remove null entries from the live references table
fn remove_nulls<K: Eq + Hash + Clone, V> (table: &mut HashMap<K, Weak<V>>) {
    let to_remove: Vec<K> =
        table.iter()
        .filter(|&(_, value)| Weak::upgrade(value).is_none())
        .map(|(key, _)| key.clone())
        .collect();
    info!("removing {} refcounted references", to_remove.len());
    for key in to_remove {
        table.remove(&key);
    }
}

/// A JSTraceDataOp for tracing reflectors held in LIVE_REFERENCES
#[allow(unrooted_must_root)]
pub unsafe extern "C" fn trace_refcounted_objects(tracer: *mut JSTracer,
                                                  _data: *mut os::raw::c_void) {
    info!("tracing live refcounted references");
    LIVE_REFERENCES.with(|ref r| {
        let r = r.borrow();
        let live_references = r.as_ref().unwrap();
        {
            let mut table = live_references.reflectable_table.borrow_mut();
            remove_nulls(&mut table);
            for obj in table.keys() {
                let reflectable = &*(*obj as *const Reflector);
                trace_reflector(tracer, "refcounted", reflectable);
            }
        }

        {
            let table = live_references.promise_table.borrow_mut();
            for promise in table.keys() {
                trace_reflector(tracer, "refcounted", (**promise).reflector());
            }
        }
    });
}
<commit_msg>Use task! to reject promises<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! A generic, safe mechanism by which DOM objects can be pinned and transferred
//! between threads (or intra-thread for asynchronous events). Akin to Gecko's
//! nsMainThreadPtrHandle, this uses thread-safe reference counting and ensures
//! that the actual SpiderMonkey GC integration occurs on the script thread via
//! weak refcounts. Ownership of a `Trusted<T>` object means the DOM object of
//! type T to which it points remains alive. Any other behaviour is undefined.
//! To guarantee the lifetime of a DOM object when performing asynchronous operations,
//! obtain a `Trusted<T>` from that object and pass it along with each operation.
//! A usable pointer to the original DOM object can be obtained on the script thread
//! from a `Trusted<T>` via the `root` method.
//!
//! The implementation of `Trusted<T>` is as follows:
//! The `Trusted<T>` object contains an atomic reference counted pointer to the Rust DOM object.
//! A hashtable resides in the script thread, keyed on the pointer.
//! The values in this hashtable are weak reference counts. When a `Trusted<T>` object is
//! created or cloned, the reference count is increased. When a `Trusted<T>` is dropped, the count
//! decreases. If the count hits zero, the weak reference is emptied, and is removed from
//! its hash table during the next GC. During GC, the entries of the hash table are counted
//! as JS roots.

use core::nonzero::NonZero;
use dom::bindings::conversions::ToJSValConvertible;
use dom::bindings::error::Error;
use dom::bindings::js::Root;
use dom::bindings::reflector::{DomObject, Reflector};
use dom::bindings::trace::trace_reflector;
use dom::promise::Promise;
use js::jsapi::JSAutoCompartment;
use js::jsapi::JSTracer;
use libc;
use std::cell::RefCell;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::hash_map::HashMap;
use std::hash::Hash;
use std::marker::PhantomData;
use std::os;
use std::rc::Rc;
use std::sync::{Arc, Weak};
use task::Task;

#[allow(missing_docs)]  // FIXME
mod dummy {  // Attributes don’t apply through the macro.
    use std::cell::RefCell;
    use std::rc::Rc;
    use super::LiveDOMReferences;
    thread_local!(pub static LIVE_REFERENCES: Rc<RefCell<Option<LiveDOMReferences>>> =
            Rc::new(RefCell::new(None)));
}
pub use self::dummy::LIVE_REFERENCES;

/// A pointer to a Rust DOM object that needs to be destroyed.
pub struct TrustedReference(*const libc::c_void);
unsafe impl Send for TrustedReference {}

impl TrustedReference {
    fn new<T: DomObject>(ptr: *const T) -> TrustedReference {
        TrustedReference(ptr as *const libc::c_void)
    }
}

/// A safe wrapper around a DOM Promise object that can be shared among threads for use
/// in asynchronous operations. The underlying DOM object is guaranteed to live at least
/// as long as the last outstanding `TrustedPromise` instance. These values cannot be cloned,
/// only created from existing Rc<Promise> values.
pub struct TrustedPromise {
    dom_object: *const Promise,
    owner_thread: *const libc::c_void,
}

unsafe impl Send for TrustedPromise {}

impl TrustedPromise {
    /// Create a new `TrustedPromise` instance from an existing DOM object. The object will
    /// be prevented from being GCed for the duration of the resulting `TrustedPromise` object's
    /// lifetime.
    #[allow(unrooted_must_root)]
    pub fn new(promise: Rc<Promise>) -> TrustedPromise {
        LIVE_REFERENCES.with(|ref r| {
            let r = r.borrow();
            let live_references = r.as_ref().unwrap();
            let ptr = &*promise as *const Promise;
            live_references.addref_promise(promise);
            TrustedPromise {
                dom_object: ptr,
                owner_thread: (&*live_references) as *const _ as *const libc::c_void,
            }
        })
    }

    /// Obtain a usable DOM Promise from a pinned `TrustedPromise` value. Fails if used on
    /// a different thread than the original value from which this `TrustedPromise` was
    /// obtained.
    #[allow(unrooted_must_root)]
    pub fn root(self) -> Rc<Promise> {
        LIVE_REFERENCES.with(|ref r| {
            let r = r.borrow();
            let live_references = r.as_ref().unwrap();
            assert!(self.owner_thread == (&*live_references) as *const _ as *const libc::c_void);
            // Borrow-check error requires the redundant `let promise = ...; promise` here.
            let promise = match live_references.promise_table.borrow_mut().entry(self.dom_object) {
                Occupied(mut entry) => {
                    let promise = {
                        let promises = entry.get_mut();
                        promises.pop().expect("rooted promise list unexpectedly empty")
                    };
                    if entry.get().is_empty() {
                        entry.remove();
                    }
                    promise
                }
                Vacant(_) => unreachable!(),
            };
            promise
        })
    }

    /// A task which will reject the promise.
    #[allow(unrooted_must_root)]
    pub fn reject_task(self, error: Error) -> impl Send + Task {
        let this = self;
        task!(reject_promise: move || {
            debug!("Rejecting promise.");
            let this = this.root();
            let cx = this.global().get_cx();
            let _ac = JSAutoCompartment::new(cx, this.reflector().get_jsobject().get());
            this.reject_error(cx, error);
        })
    }

    /// A task which will resolve the promise.
    #[allow(unrooted_must_root)]
    pub fn resolve_task<T>(self, value: T) -> impl Send + Task
    where
        T: ToJSValConvertible + Send,
    {
        struct ResolvePromise<T>(TrustedPromise, T);
        impl<T: ToJSValConvertible> Task for ResolvePromise<T> {
            fn run(self: Box<Self>) {
                debug!("Resolving promise.");
                let this = *self;
                let promise = this.0.root();
                let cx = promise.global().get_cx();
                let _ac = JSAutoCompartment::new(cx, promise.reflector().get_jsobject().get());
                promise.resolve_native(cx, &this.1);
            }
        }
        ResolvePromise(self, value)
    }
}

/// A safe wrapper around a raw pointer to a DOM object that can be
/// shared among threads for use in asynchronous operations. The underlying
/// DOM object is guaranteed to live at least as long as the last outstanding
/// `Trusted<T>` instance.
#[allow_unrooted_interior]
pub struct Trusted<T: DomObject> {
    /// A pointer to the Rust DOM object of type T, but void to allow
    /// sending `Trusted<T>` between threads, regardless of T's sendability.
    refcount: Arc<TrustedReference>,
    owner_thread: *const libc::c_void,
    phantom: PhantomData<T>,
}

unsafe impl<T: DomObject> Send for Trusted<T> {}

impl<T: DomObject> Trusted<T> {
    /// Create a new `Trusted<T>` instance from an existing DOM pointer. The DOM object will
    /// be prevented from being GCed for the duration of the resulting `Trusted<T>` object's
    /// lifetime.
    pub fn new(ptr: &T) -> Trusted<T> {
        LIVE_REFERENCES.with(|ref r| {
            let r = r.borrow();
            let live_references = r.as_ref().unwrap();
            let refcount = live_references.addref(&*ptr as *const T);
            Trusted {
                refcount: refcount,
                owner_thread: (&*live_references) as *const _ as *const libc::c_void,
                phantom: PhantomData,
            }
        })
    }

    /// Obtain a usable DOM pointer from a pinned `Trusted<T>` value. Fails if used on
    /// a different thread than the original value from which this `Trusted<T>` was
    /// obtained.
    pub fn root(&self) -> Root<T> {
        assert!(LIVE_REFERENCES.with(|ref r| {
            let r = r.borrow();
            let live_references = r.as_ref().unwrap();
            self.owner_thread == (&*live_references) as *const _ as *const libc::c_void
        }));
        unsafe {
            Root::new(NonZero::new_unchecked(self.refcount.0 as *const T))
        }
    }
}

impl<T: DomObject> Clone for Trusted<T> {
    fn clone(&self) -> Trusted<T> {
        Trusted {
            refcount: self.refcount.clone(),
            owner_thread: self.owner_thread,
            phantom: PhantomData,
        }
    }
}

/// The set of live, pinned DOM objects that are currently prevented
/// from being garbage collected due to outstanding references.
#[allow(unrooted_must_root)]
pub struct LiveDOMReferences {
    // keyed on pointer to Rust DOM object
    reflectable_table: RefCell<HashMap<*const libc::c_void, Weak<TrustedReference>>>,
    promise_table: RefCell<HashMap<*const Promise, Vec<Rc<Promise>>>>,
}

impl LiveDOMReferences {
    /// Set up the thread-local data required for storing the outstanding DOM references.
    pub fn initialize() {
        LIVE_REFERENCES.with(|ref r| {
            *r.borrow_mut() = Some(LiveDOMReferences {
                reflectable_table: RefCell::new(HashMap::new()),
                promise_table: RefCell::new(HashMap::new()),
            })
        });
    }

    #[allow(unrooted_must_root)]
    fn addref_promise(&self, promise: Rc<Promise>) {
        let mut table = self.promise_table.borrow_mut();
        table.entry(&*promise).or_insert(vec![]).push(promise)
    }

    fn addref<T: DomObject>(&self, ptr: *const T) -> Arc<TrustedReference> {
        let mut table = self.reflectable_table.borrow_mut();
        let capacity = table.capacity();
        let len = table.len();
        if (0 < capacity) && (capacity <= len) {
            info!("growing refcounted references by {}", len);
            remove_nulls(&mut table);
            table.reserve(len);
        }
        match table.entry(ptr as *const libc::c_void) {
            Occupied(mut entry) => match entry.get().upgrade() {
                Some(refcount) => refcount,
                None => {
                    let refcount = Arc::new(TrustedReference::new(ptr));
                    entry.insert(Arc::downgrade(&refcount));
                    refcount
                },
            },
            Vacant(entry) => {
                let refcount = Arc::new(TrustedReference::new(ptr));
                entry.insert(Arc::downgrade(&refcount));
                refcount
            }
        }
    }
}

/// Remove null entries from the live references table
fn remove_nulls<K: Eq + Hash + Clone, V> (table: &mut HashMap<K, Weak<V>>) {
    let to_remove: Vec<K> =
        table.iter()
        .filter(|&(_, value)| Weak::upgrade(value).is_none())
        .map(|(key, _)| key.clone())
        .collect();
    info!("removing {} refcounted references", to_remove.len());
    for key in to_remove {
        table.remove(&key);
    }
}

/// A JSTraceDataOp for tracing reflectors held in LIVE_REFERENCES
#[allow(unrooted_must_root)]
pub unsafe extern "C" fn trace_refcounted_objects(tracer: *mut JSTracer,
                                                  _data: *mut os::raw::c_void) {
    info!("tracing live refcounted references");
    LIVE_REFERENCES.with(|ref r| {
        let r = r.borrow();
        let live_references = r.as_ref().unwrap();
        {
            let mut table = live_references.reflectable_table.borrow_mut();
            remove_nulls(&mut table);
            for obj in table.keys() {
                let reflectable = &*(*obj as *const Reflector);
                trace_reflector(tracer, "refcounted", reflectable);
            }
        }

        {
            let table = live_references.promise_table.borrow_mut();
            for promise in table.keys() {
                trace_reflector(tracer, "refcounted", (**promise).reflector());
            }
        }
    });
}
<|endoftext|>


<commit_before>use std::ops::Deref;
use std::rc::Rc;
use std::cell::RefCell;
use progress::Timestamp;
use progress::count_map::CountMap;
use std::fmt::{self, Debug};

/// A capability for timestamp `t` represents a permit for an operator that holds the capability
/// to send data and request notifications at timestamp `t`.
pub struct Capability<T: Timestamp> {
    time: T,
    internal: Rc<RefCell<CountMap<T>>>,
}

impl<T: Timestamp> Capability<T> {
    /// The timestamp associated with this capability.
    #[inline]
    pub fn time(&self) -> T {
        self.time
    }

    /// Makes a new capability for a timestamp that's greater then the timestamp associated with
    /// the source capability (`self`).
    #[inline]
    pub fn delayed(&self, new_time: &T) -> Capability<T> {
        assert!(new_time >= &self.time);
        mint(*new_time, self.internal.clone())
    }
}

/// Creates a new capability at `t` while incrementing (and keeping a reference to) the provided
/// `CountMap`.
/// Declared separately so that it can be kept private when `Capability` is re-exported.
pub fn mint<T: Timestamp>(time: T, internal: Rc<RefCell<CountMap<T>>>) -> Capability<T> {
    internal.borrow_mut().update(&time, 1);
    Capability {
        time: time,
        internal: internal
    }
}

// Necessary for correctness. When a capability is dropped, the "internal" `CountMap` needs to be
// updated accordingly to inform the rest of the system that the operator has released its permit
// to send data and request notification at the associated timestamp.
impl<T: Timestamp> Drop for Capability<T> {
    fn drop(&mut self) {
        self.internal.borrow_mut().update(&self.time, -1);
    }
}

impl<T: Timestamp> Clone for Capability<T> {
    fn clone(&self) -> Capability<T> {
        mint(self.time, self.internal.clone())
    }
}

impl<T: Timestamp> Deref for Capability<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.time
    }
}

impl<T: Timestamp> Debug for Capability<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Capability {{ time: {:?}, internal: ... }}", self.time)
    }
}
<commit_msg>added / updated many comments<commit_after>//! Capabilities to send data from operators
//!
//! Timely dataflow operators are only able to send data if they possess a "capability",
//! a system-created object which warns the runtime that the operator may still produce
//! output records.
//!
//! The timely dataflow runtime creates a capability and provides it to an operator whenever
//! the operator receives input data. The capabilities allow the operator to respond to the
//! received data, immediately or in the future, for as long as the capability is held.
//!
//! Timely dataflow's progress tracking infrastructure communicates the number of outstanding
//! capabilities across all workers.
//! Each operator may hold on to its capabilities, and may clone, advance, and drop them.
//! Each of these actions informs the timely dataflow runtime of changes to the number of outstanding
//! capabilities, so that the runtime can notice when the count for some capability reaches zero.
//! While an operator can hold capabilities indefinitely, and create as many new copies of them
//! as it would like, the progress tracking infrastructure will not move forward until the
//! operators eventually release their capabilities.
//!
//! Note that these capabilities currently lack the property of "transferability":
//! An operator should not hand its capabilities to some other operator. In the future, we should
//! probably bind capabilities more strongly to a specific operator and output.

use std::ops::Deref;
use std::rc::Rc;
use std::cell::RefCell;
use progress::Timestamp;
use progress::count_map::CountMap;
use std::fmt::{self, Debug};

/// A capability for timestamp `t` represents a permit for an operator that holds the capability
/// to send data and request notifications at timestamp `t`.
pub struct Capability<T: Timestamp> {
    time: T,
    internal: Rc<RefCell<CountMap<T>>>,
}

impl<T: Timestamp> Capability<T> {
    /// The timestamp associated with this capability.
    #[inline]
    pub fn time(&self) -> T {
        self.time
    }

    /// Makes a new capability for a timestamp `new_time` greater or equal to the timestamp of
    /// the source capability (`self`).
    #[inline]
    pub fn delayed(&self, new_time: &T) -> Capability<T> {
        assert!(new_time >= &self.time);
        mint(*new_time, self.internal.clone())
    }
}

/// Creates a new capability at `t` while incrementing (and keeping a reference to) the provided
/// `CountMap`.
/// Declared separately so that it can be kept private when `Capability` is re-exported.
pub fn mint<T: Timestamp>(time: T, internal: Rc<RefCell<CountMap<T>>>) -> Capability<T> {
    internal.borrow_mut().update(&time, 1);
    Capability {
        time: time,
        internal: internal
    }
}

// Necessary for correctness. When a capability is dropped, the "internal" `CountMap` needs to be
// updated accordingly to inform the rest of the system that the operator has released its permit
// to send data and request notification at the associated timestamp.
impl<T: Timestamp> Drop for Capability<T> {
    fn drop(&mut self) {
        self.internal.borrow_mut().update(&self.time, -1);
    }
}

impl<T: Timestamp> Clone for Capability<T> {
    fn clone(&self) -> Capability<T> {
        mint(self.time, self.internal.clone())
    }
}

impl<T: Timestamp> Deref for Capability<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.time
    }
}

impl<T: Timestamp> Debug for Capability<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Capability {{ time: {:?}, internal: ... }}", self.time)
    }
}
<|endoftext|>


<commit_before>/*!
`ndarray` compability

This adds support for reading data into [`ndarray`][ndarray] array objects. This primarily
enables support for automatically reshaping the resulting arrays to have the dimensionality of
the image that was asked for.

Data is read into the [`ndarray::ArrayD`][arrayd] type. The following methods from
[`FitsHdu`][fits-hdu] are supported:

* [`read_image`][read-image]
* [`read_region`][read-region]
* [`read_row`][read-row]
* [`read_rows`][read-rows]
* [`read_section`][read-section]

## `read_image`

```rust
# extern crate fitsio;
# #[cfg(feature = "array")]
# extern crate ndarray;
use fitsio::FitsFile;
# #[cfg(feature = "array")]
use ndarray::ArrayD;

# #[cfg(feature = "array")]
# fn main() {
let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
let hdu = f.primary_hdu().unwrap();

let data: ArrayD<u32> = hdu.read_image(&mut f).unwrap();
let dim = data.dim();
assert_eq!(data.ndim(), 2);
assert_eq!(dim[0], 100);
assert_eq!(dim[1], 100);
assert_eq!(data[[20, 5]], 152);
# }
#
# #[cfg(not(feature = "array"))]
# fn main() {}
```

## `read_region`

```rust
# extern crate fitsio;
# #[cfg(feature = "array")]
# extern crate ndarray;
use fitsio::FitsFile;
# #[cfg(feature = "array")]
use ndarray::ArrayD;

# #[cfg(feature = "array")]
# fn main() {
let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
let hdu = f.primary_hdu().unwrap();

let data: ArrayD<u32> = hdu.read_region(&mut f, &[&(70..80), &(20..50)]).unwrap();
let dim = data.dim();
assert_eq!(data.ndim(), 2);
assert_eq!(dim[0], 10);
assert_eq!(dim[1], 30);
assert_eq!(data[[5, 10]], 177);
# }
#
# #[cfg(not(feature = "array"))]
# fn main() {}
```

## `read_row`

```rust
# extern crate fitsio;
# #[cfg(feature = "array")]
# extern crate ndarray;
use fitsio::FitsFile;
# #[cfg(feature = "array")]
use ndarray::ArrayD;

# #[cfg(feature = "array")]
# fn main() {
let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
let hdu = f.primary_hdu().unwrap();

let data: ArrayD<u32> = hdu.read_row(&mut f, 49).unwrap();
assert_eq!(data.ndim(), 1);
assert_eq!(data[20], 156);
# }
#
# #[cfg(not(feature = "array"))]
# fn main() {}
```

## `read_rows`

```rust
# extern crate fitsio;
# #[cfg(feature = "array")]
# extern crate ndarray;
use fitsio::FitsFile;
# #[cfg(feature = "array")]
use ndarray::ArrayD;

# #[cfg(feature = "array")]
# fn main() {
let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
let hdu = f.primary_hdu().unwrap();

let data: ArrayD<u32> = hdu.read_rows(&mut f, 0, 2).unwrap();
let dim = data.dim();
assert_eq!(data.ndim(), 2);
assert_eq!(dim[0], 2);
assert_eq!(dim[1], 100);
assert_eq!(data[[1, 52]], 184);
# }
#
# #[cfg(not(feature = "array"))]
# fn main() {}
```

## `read_section`

```rust
# extern crate fitsio;
# #[cfg(feature = "array")]
# extern crate ndarray;
use fitsio::FitsFile;
use fitsio::errors::Error;
# #[cfg(feature = "array")]
use ndarray::ArrayD;

# #[cfg(feature = "array")]
# fn main() {
let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
let hdu = f.primary_hdu().unwrap();

match hdu.read_section::<ArrayD<u32>>(&mut f, 0, 250) {
    Err(Error::Message(msg)) => {
        assert_eq!(
            msg,
            "must request number of pixels exactly divisible by image width".to_string()
        );
    }
    _ => panic!("invalid result"),
}

let data: ArrayD<u32> = hdu.read_section(&mut f, 0, 200).unwrap();
let dim = data.dim();
assert_eq!(data.ndim(), 2);
assert_eq!(dim[0], 2);
assert_eq!(dim[1], 100);
assert_eq!(data[[0, 10]], 160);
# }
#
# #[cfg(not(feature = "array"))]
# fn main() {}
```

[ndarray]: https://crates.io/crates/ndarray
[arrayd]: https://docs.rs/ndarray/0.11.2/ndarray/type.ArrayD.html
[fits-hdu]: hdu/struct.FitsHdu.html
[read-image]: images/struct.FitsHdu.html#method.read_image
[read-region]: images/struct.FitsHdu.html#method.read_region
[read-row]: images/struct.FitsHdu.html#method.read_row
[read-rows]: images/struct.FitsHdu.html#method.read_rows
[read-section]: images/struct.FitsHdu.html#method.read_section
*/

use errors::Result;
use fitsfile::FitsFile;
use hdu::{FitsHdu, HduInfo};
use images::ReadImage;
use ndarray::{Array, ArrayD};
use std::ops::Range;

impl<T> ReadImage for ArrayD<T>
where
    T: Clone,
    Vec<T>: ReadImage,
{
    fn read_section(fits_file: &mut FitsFile, hdu: &FitsHdu, range: Range<usize>) -> Result<Self> {
        match hdu.info {
            HduInfo::ImageInfo { ref shape, .. } => {
                if shape.len() != 2 {
                    return Err("Only 2D images supported for now".into());
                }

                let width = shape[1];

                if range.start % width != 0 {
                    return Err("range must start on row boundary".into());
                }
                let start_pixel = range.start / width;

                let n_pixels_requested = range.end - range.start;
                if n_pixels_requested % width != 0 {
                    return Err(
                        "must request number of pixels exactly divisible by image width".into(),
                    );
                }

                let n_rows = n_pixels_requested / width;
                ReadImage::read_rows(fits_file, hdu, start_pixel, n_rows)
            }
            HduInfo::TableInfo { .. } => {
                return Err("Cannot read image data from a FITS table".into());
            }
            _ => unreachable!(),
        }
    }

    fn read_rows(
        fits_file: &mut FitsFile,
        hdu: &FitsHdu,
        start_row: usize,
        num_rows: usize,
    ) -> Result<Self> {
        let data: Vec<T> = ReadImage::read_rows(fits_file, hdu, start_row, num_rows)?;
        let arr = Array::from_vec(data);
        let row_length = arr.len() / num_rows;
        Ok(arr.into_shape(vec![num_rows, row_length]).unwrap())
    }

    fn read_row(fits_file: &mut FitsFile, hdu: &FitsHdu, row: usize) -> Result<Self> {
        let data: Vec<T> = ReadImage::read_row(fits_file, hdu, row)?;
        let shape = vec![data.len()];
        Ok(Array::from_shape_vec(shape, data).unwrap())
    }

    fn read_region(
        fits_file: &mut FitsFile,
        hdu: &FitsHdu,
        ranges: &[&Range<usize>],
    ) -> Result<Self> {
        let data: Vec<T> = ReadImage::read_region(fits_file, hdu, ranges)?;
        let shape: Vec<usize> = (0..ranges.len())
            .map(|i| ranges[i].end - ranges[i].start)
            .collect();
        let arr = Array::from_shape_vec(shape, data).unwrap();
        Ok(arr)
    }

    fn read_image(fits_file: &mut FitsFile, hdu: &FitsHdu) -> Result<Self> {
        match hdu.info {
            HduInfo::ImageInfo { ref shape, .. } => {
                let data: Vec<T> = ReadImage::read_image(fits_file, hdu)?;
                let shape: Vec<usize> = (0..2).map(|i| shape[i]).collect();
                let arr = Array::from_shape_vec(shape, data).unwrap();
                Ok(arr)
            }
            _ => unreachable!(),
        }
    }
}

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

    #[test]
    fn test_read_image() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        let data: ArrayD<u32> = hdu.read_image(&mut f).unwrap();
        let dim = data.dim();
        assert_eq!(data.ndim(), 2);
        assert_eq!(dim[0], 100);
        assert_eq!(dim[1], 100);
        assert_eq!(data[[20, 5]], 152);
    }

    #[test]
    fn test_read_rows() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        let data: ArrayD<u32> = hdu.read_rows(&mut f, 0, 2).unwrap();
        let dim = data.dim();
        assert_eq!(data.ndim(), 2);
        assert_eq!(dim[0], 2);
        assert_eq!(dim[1], 100);
        assert_eq!(data[[1, 52]], 184);
    }

    #[test]
    fn test_read_row() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        let data: ArrayD<u32> = hdu.read_row(&mut f, 49).unwrap();
        assert_eq!(data.ndim(), 1);
        assert_eq!(data[20], 156);
    }

    #[test]
    fn test_read_region() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        let data: ArrayD<u32> = hdu.read_region(&mut f, &[&(70..80), &(20..50)]).unwrap();
        let dim = data.dim();
        assert_eq!(data.ndim(), 2);
        assert_eq!(dim[0], 10);
        assert_eq!(dim[1], 30);
        assert_eq!(data[[5, 10]], 177);
    }

    #[test]
    fn test_read_section() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        match hdu.read_section::<ArrayD<u32>>(&mut f, 0, 250) {
            Err(Error::Message(msg)) => {
                assert_eq!(
                    msg,
                    "must request number of pixels exactly divisible by image width".to_string()
                );
            }
            _ => panic!("invalid result"),
        }

        let data: ArrayD<u32> = hdu.read_section(&mut f, 0, 200).unwrap();
        let dim = data.dim();
        assert_eq!(data.ndim(), 2);
        assert_eq!(dim[0], 2);
        assert_eq!(dim[1], 100);
        assert_eq!(data[[0, 10]], 160);
    }
}
<commit_msg>Fixes module import for 2018<commit_after>/*!
`ndarray` compability

This adds support for reading data into [`ndarray`][ndarray] array objects. This primarily
enables support for automatically reshaping the resulting arrays to have the dimensionality of
the image that was asked for.

Data is read into the [`ndarray::ArrayD`][arrayd] type. The following methods from
[`FitsHdu`][fits-hdu] are supported:

* [`read_image`][read-image]
* [`read_region`][read-region]
* [`read_row`][read-row]
* [`read_rows`][read-rows]
* [`read_section`][read-section]

## `read_image`

```rust
# extern crate fitsio;
# #[cfg(feature = "array")]
# extern crate ndarray;
use fitsio::FitsFile;
# #[cfg(feature = "array")]
use ndarray::ArrayD;

# #[cfg(feature = "array")]
# fn main() {
let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
let hdu = f.primary_hdu().unwrap();

let data: ArrayD<u32> = hdu.read_image(&mut f).unwrap();
let dim = data.dim();
assert_eq!(data.ndim(), 2);
assert_eq!(dim[0], 100);
assert_eq!(dim[1], 100);
assert_eq!(data[[20, 5]], 152);
# }
#
# #[cfg(not(feature = "array"))]
# fn main() {}
```

## `read_region`

```rust
# extern crate fitsio;
# #[cfg(feature = "array")]
# extern crate ndarray;
use fitsio::FitsFile;
# #[cfg(feature = "array")]
use ndarray::ArrayD;

# #[cfg(feature = "array")]
# fn main() {
let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
let hdu = f.primary_hdu().unwrap();

let data: ArrayD<u32> = hdu.read_region(&mut f, &[&(70..80), &(20..50)]).unwrap();
let dim = data.dim();
assert_eq!(data.ndim(), 2);
assert_eq!(dim[0], 10);
assert_eq!(dim[1], 30);
assert_eq!(data[[5, 10]], 177);
# }
#
# #[cfg(not(feature = "array"))]
# fn main() {}
```

## `read_row`

```rust
# extern crate fitsio;
# #[cfg(feature = "array")]
# extern crate ndarray;
use fitsio::FitsFile;
# #[cfg(feature = "array")]
use ndarray::ArrayD;

# #[cfg(feature = "array")]
# fn main() {
let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
let hdu = f.primary_hdu().unwrap();

let data: ArrayD<u32> = hdu.read_row(&mut f, 49).unwrap();
assert_eq!(data.ndim(), 1);
assert_eq!(data[20], 156);
# }
#
# #[cfg(not(feature = "array"))]
# fn main() {}
```

## `read_rows`

```rust
# extern crate fitsio;
# #[cfg(feature = "array")]
# extern crate ndarray;
use fitsio::FitsFile;
# #[cfg(feature = "array")]
use ndarray::ArrayD;

# #[cfg(feature = "array")]
# fn main() {
let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
let hdu = f.primary_hdu().unwrap();

let data: ArrayD<u32> = hdu.read_rows(&mut f, 0, 2).unwrap();
let dim = data.dim();
assert_eq!(data.ndim(), 2);
assert_eq!(dim[0], 2);
assert_eq!(dim[1], 100);
assert_eq!(data[[1, 52]], 184);
# }
#
# #[cfg(not(feature = "array"))]
# fn main() {}
```

## `read_section`

```rust
# extern crate fitsio;
# #[cfg(feature = "array")]
# extern crate ndarray;
use fitsio::FitsFile;
use fitsio::errors::Error;
# #[cfg(feature = "array")]
use ndarray::ArrayD;

# #[cfg(feature = "array")]
# fn main() {
let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
let hdu = f.primary_hdu().unwrap();

match hdu.read_section::<ArrayD<u32>>(&mut f, 0, 250) {
    Err(Error::Message(msg)) => {
        assert_eq!(
            msg,
            "must request number of pixels exactly divisible by image width".to_string()
        );
    }
    _ => panic!("invalid result"),
}

let data: ArrayD<u32> = hdu.read_section(&mut f, 0, 200).unwrap();
let dim = data.dim();
assert_eq!(data.ndim(), 2);
assert_eq!(dim[0], 2);
assert_eq!(dim[1], 100);
assert_eq!(data[[0, 10]], 160);
# }
#
# #[cfg(not(feature = "array"))]
# fn main() {}
```

[ndarray]: https://crates.io/crates/ndarray
[arrayd]: https://docs.rs/ndarray/0.11.2/ndarray/type.ArrayD.html
[fits-hdu]: hdu/struct.FitsHdu.html
[read-image]: images/struct.FitsHdu.html#method.read_image
[read-region]: images/struct.FitsHdu.html#method.read_region
[read-row]: images/struct.FitsHdu.html#method.read_row
[read-rows]: images/struct.FitsHdu.html#method.read_rows
[read-section]: images/struct.FitsHdu.html#method.read_section
*/

use crate::errors::Result;
use crate::fitsfile::FitsFile;
use crate::hdu::{FitsHdu, HduInfo};
use crate::images::ReadImage;
use ndarray::{Array, ArrayD};
use std::ops::Range;

impl<T> ReadImage for ArrayD<T>
where
    T: Clone,
    Vec<T>: ReadImage,
{
    fn read_section(fits_file: &mut FitsFile, hdu: &FitsHdu, range: Range<usize>) -> Result<Self> {
        match hdu.info {
            HduInfo::ImageInfo { ref shape, .. } => {
                if shape.len() != 2 {
                    return Err("Only 2D images supported for now".into());
                }

                let width = shape[1];

                if range.start % width != 0 {
                    return Err("range must start on row boundary".into());
                }
                let start_pixel = range.start / width;

                let n_pixels_requested = range.end - range.start;
                if n_pixels_requested % width != 0 {
                    return Err(
                        "must request number of pixels exactly divisible by image width".into(),
                    );
                }

                let n_rows = n_pixels_requested / width;
                ReadImage::read_rows(fits_file, hdu, start_pixel, n_rows)
            }
            HduInfo::TableInfo { .. } => {
                return Err("Cannot read image data from a FITS table".into());
            }
            _ => unreachable!(),
        }
    }

    fn read_rows(
        fits_file: &mut FitsFile,
        hdu: &FitsHdu,
        start_row: usize,
        num_rows: usize,
    ) -> Result<Self> {
        let data: Vec<T> = ReadImage::read_rows(fits_file, hdu, start_row, num_rows)?;
        let arr = Array::from_vec(data);
        let row_length = arr.len() / num_rows;
        Ok(arr.into_shape(vec![num_rows, row_length]).unwrap())
    }

    fn read_row(fits_file: &mut FitsFile, hdu: &FitsHdu, row: usize) -> Result<Self> {
        let data: Vec<T> = ReadImage::read_row(fits_file, hdu, row)?;
        let shape = vec![data.len()];
        Ok(Array::from_shape_vec(shape, data).unwrap())
    }

    fn read_region(
        fits_file: &mut FitsFile,
        hdu: &FitsHdu,
        ranges: &[&Range<usize>],
    ) -> Result<Self> {
        let data: Vec<T> = ReadImage::read_region(fits_file, hdu, ranges)?;
        let shape: Vec<usize> = (0..ranges.len())
            .map(|i| ranges[i].end - ranges[i].start)
            .collect();
        let arr = Array::from_shape_vec(shape, data).unwrap();
        Ok(arr)
    }

    fn read_image(fits_file: &mut FitsFile, hdu: &FitsHdu) -> Result<Self> {
        match hdu.info {
            HduInfo::ImageInfo { ref shape, .. } => {
                let data: Vec<T> = ReadImage::read_image(fits_file, hdu)?;
                let shape: Vec<usize> = (0..2).map(|i| shape[i]).collect();
                let arr = Array::from_shape_vec(shape, data).unwrap();
                Ok(arr)
            }
            _ => unreachable!(),
        }
    }
}

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

    #[test]
    fn test_read_image() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        let data: ArrayD<u32> = hdu.read_image(&mut f).unwrap();
        let dim = data.dim();
        assert_eq!(data.ndim(), 2);
        assert_eq!(dim[0], 100);
        assert_eq!(dim[1], 100);
        assert_eq!(data[[20, 5]], 152);
    }

    #[test]
    fn test_read_rows() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        let data: ArrayD<u32> = hdu.read_rows(&mut f, 0, 2).unwrap();
        let dim = data.dim();
        assert_eq!(data.ndim(), 2);
        assert_eq!(dim[0], 2);
        assert_eq!(dim[1], 100);
        assert_eq!(data[[1, 52]], 184);
    }

    #[test]
    fn test_read_row() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        let data: ArrayD<u32> = hdu.read_row(&mut f, 49).unwrap();
        assert_eq!(data.ndim(), 1);
        assert_eq!(data[20], 156);
    }

    #[test]
    fn test_read_region() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        let data: ArrayD<u32> = hdu.read_region(&mut f, &[&(70..80), &(20..50)]).unwrap();
        let dim = data.dim();
        assert_eq!(data.ndim(), 2);
        assert_eq!(dim[0], 10);
        assert_eq!(dim[1], 30);
        assert_eq!(data[[5, 10]], 177);
    }

    #[test]
    fn test_read_section() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.primary_hdu().unwrap();

        match hdu.read_section::<ArrayD<u32>>(&mut f, 0, 250) {
            Err(Error::Message(msg)) => {
                assert_eq!(
                    msg,
                    "must request number of pixels exactly divisible by image width".to_string()
                );
            }
            _ => panic!("invalid result"),
        }

        let data: ArrayD<u32> = hdu.read_section(&mut f, 0, 200).unwrap();
        let dim = data.dim();
        assert_eq!(data.ndim(), 2);
        assert_eq!(dim[0], 2);
        assert_eq!(dim[1], 100);
        assert_eq!(data[[0, 10]], 160);
    }
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use engine::Engine;
use engine::EngineError;
use engine::EngineResult;
use engine::ErrorEnum;

use engine::Pool;
use engine::RenameAction;
use engine::Redundancy;

use std::cell::RefCell;
use std::collections::BTreeMap;
use std::collections::btree_map::Entry;
use std::collections::BTreeSet;
use std::iter::FromIterator;
use std::path::Path;
use std::path::PathBuf;
use std::rc::Rc;

use super::pool::SimPool;
use super::randomization::Randomizer;

#[derive(Debug)]
pub struct SimEngine {
    pools: BTreeMap<String, SimPool>,
    rdm: Rc<RefCell<Randomizer>>,
}

impl SimEngine {
    pub fn new() -> SimEngine {
        SimEngine {
            pools: BTreeMap::new(),
            rdm: Rc::new(RefCell::new(Randomizer::new())),
        }
    }
}

impl Engine for SimEngine {
    fn create_pool(&mut self,
                   name: &str,
                   blockdev_paths: &[&Path],
                   redundancy: u16,
                   _force: bool)
                   -> EngineResult<Vec<PathBuf>> {

        let redundancy = redundancy as usize;
        let redundancy = calculate_redundancy!(redundancy);

        if self.pools.contains_key(name) {
            return Err(EngineError::Stratis(ErrorEnum::AlreadyExists(name.into())));
        }

        let devices =
            BTreeSet::from_iter(blockdev_paths).into_iter().map(|x| *x).collect::<Vec<&Path>>();

        let pool = SimPool::new(self.rdm.clone(), &devices, redundancy);

        if self.rdm.borrow_mut().throw_die() {
            return Err(EngineError::Stratis(ErrorEnum::Error("X".into())));
        }

        let bdev_paths = pool.block_devs.values().map(|p| p.devnode.clone()).collect();
        self.pools.insert(name.to_owned(), pool);

        Ok(bdev_paths)
    }

    fn destroy_pool(&mut self, name: &str) -> EngineResult<bool> {
        destroy_pool!{self; name}
    }

    fn rename_pool(&mut self, old_name: &str, new_name: &str) -> EngineResult<RenameAction> {
        rename_pool!{self; old_name; new_name}
    }

    /// Looks up the pool by its unique name
    fn get_pool(&mut self, name: &str) -> EngineResult<&mut Pool> {
        get_pool!(self; name)
    }

    /// Returns a collection of the Pool objects that belong to this engine
    fn pools(&mut self) -> BTreeMap<&str, &mut Pool> {
        pools!(self)
    }

    /// Set properties of the simulator
    fn configure_simulator(&mut self, denominator: u32) -> EngineResult<()> {
        self.rdm.borrow_mut().set_probability(denominator);
        Ok(())
    }
}

#[cfg(test)]
mod tests {

    use std::path::Path;

    use quickcheck::QuickCheck;

    use super::SimEngine;

    use engine::Engine;
    use engine::EngineError;
    use engine::ErrorEnum;
    use engine::RenameAction;

    #[test]
    fn prop_configure_simulator_runs() {

        /// Configure simulator should always return Ok.
        fn configure_simulator_runs(denominator: u32) -> bool {
            SimEngine::new().configure_simulator(denominator).is_ok()
        }

        QuickCheck::new().tests(10).quickcheck(configure_simulator_runs as fn(u32) -> bool);
    }

    #[test]
    /// When an engine has no pools, any name lookup should fail
    fn get_pool_err() {
        assert!(match SimEngine::new().get_pool("name") {
            Err(EngineError::Stratis(ErrorEnum::NotFound(_))) => true,
            _ => false,
        });
    }

    #[test]
    /// When an engine has no pools, the thing returned by pools() is empty
    fn pools_empty() {
        assert!(SimEngine::new().pools().is_empty());
    }

    #[test]
    /// When an engine has no pools, destroying any pool must succeed
    fn destroy_pool_empty() {
        assert!(SimEngine::new().destroy_pool("name").is_ok());
    }

    #[test]
    /// Destroying an empty pool should succeed.
    fn destroy_empty_pool() {
        let name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[], 0, false).unwrap();
        assert!(engine.destroy_pool(name).is_ok());
    }

    #[test]
    /// Destroying a pool with devices should fail
    fn destroy_pool_w_devices() {
        let name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[Path::new("/s/d")], 0, false).unwrap();
        assert!(match engine.destroy_pool(name) {
            Err(EngineError::Stratis(ErrorEnum::Busy(_))) => true,
            _ => false,
        });
    }

    #[test]
    #[ignore]
    /// Creating a new pool identical to the previous should succeed
    fn create_new_pool_twice() {
        let name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[], 0, false).unwrap();
        assert!(match engine.create_pool(name, &[], 0, false) {
            Ok(devs) => devs.is_empty(),
            Err(_) => false,
        });
    }

    #[test]
    /// Creating a new pool with the same name should fail
    fn create_pool_name_collision() {
        let name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[Path::new("/s/d")], 0, false).unwrap();
        assert!(match engine.create_pool(name, &[], 0, false) {
            Err(EngineError::Stratis(ErrorEnum::AlreadyExists(_))) => true,
            _ => false,
        });
    }

    #[test]
    /// Creating a pool with duplicate devices should succeed
    fn create_pool_duplicate_devices() {
        let path = "/s/d";
        let mut engine = SimEngine::new();
        let devices = vec![Path::new(path), Path::new(path)];
        assert!(match engine.create_pool("name", &devices, 0, false) {
            Ok(devs) => devs.len() == 1,
            _ => false,
        });
    }

    #[test]
    #[ignore]
    /// Creating a pool with an impossible raid level should fail
    fn create_pool_max_u16_raid() {
        let mut engine = SimEngine::new();
        assert!(engine.create_pool("name", &[], u16::max_value(), false).is_err());
    }

    #[test]
    /// Renaming a pool on an empty engine always works
    fn rename_empty() {
        let mut engine = SimEngine::new();
        assert!(match engine.rename_pool("old_name", "new_name") {
            Ok(RenameAction::NoSource) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming a pool to itself in an empty engine always works
    fn rename_empty_identity() {
        let mut engine = SimEngine::new();
        assert!(match engine.rename_pool("old_name", "old_name") {
            Ok(RenameAction::Identity) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming a pool to itself always works
    fn rename_identity() {
        let name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[], 0, false).unwrap();
        assert!(match engine.rename_pool(name, name) {
            Ok(RenameAction::Identity) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming a pool to another pool should work if new name not taken
    fn rename_happens() {
        let name = "old_name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[], 0, false).unwrap();
        assert!(match engine.rename_pool(name, "new_name") {
            Ok(RenameAction::Renamed) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming a pool to another pool should fail if new name taken
    fn rename_fails() {
        let old_name = "old_name";
        let new_name = "new_name";
        let mut engine = SimEngine::new();
        engine.create_pool(old_name, &[], 0, false).unwrap();
        engine.create_pool(new_name, &[], 0, false).unwrap();
        assert!(match engine.rename_pool(old_name, new_name) {
            Err(EngineError::Stratis(ErrorEnum::AlreadyExists(_))) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming should succeed if old_name absent, new present
    fn rename_no_op() {
        let old_name = "old_name";
        let new_name = "new_name";
        let mut engine = SimEngine::new();
        engine.create_pool(new_name, &[], 0, false).unwrap();
        assert!(match engine.rename_pool(old_name, new_name) {
            Ok(RenameAction::NoSource) => true,
            _ => false,
        });
    }

}
<commit_msg>Creating a pool with an unavailable redundancy now fails.<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use engine::Engine;
use engine::EngineError;
use engine::EngineResult;
use engine::ErrorEnum;

use engine::Pool;
use engine::RenameAction;
use engine::Redundancy;

use std::cell::RefCell;
use std::collections::BTreeMap;
use std::collections::btree_map::Entry;
use std::collections::BTreeSet;
use std::iter::FromIterator;
use std::path::Path;
use std::path::PathBuf;
use std::rc::Rc;

use super::pool::SimPool;
use super::randomization::Randomizer;

#[derive(Debug)]
pub struct SimEngine {
    pools: BTreeMap<String, SimPool>,
    rdm: Rc<RefCell<Randomizer>>,
}

impl SimEngine {
    pub fn new() -> SimEngine {
        SimEngine {
            pools: BTreeMap::new(),
            rdm: Rc::new(RefCell::new(Randomizer::new())),
        }
    }
}

impl Engine for SimEngine {
    fn create_pool(&mut self,
                   name: &str,
                   blockdev_paths: &[&Path],
                   redundancy: u16,
                   _force: bool)
                   -> EngineResult<Vec<PathBuf>> {

        let redundancy = redundancy as usize;
        let redundancy = calculate_redundancy!(redundancy);

        if self.pools.contains_key(name) {
            return Err(EngineError::Stratis(ErrorEnum::AlreadyExists(name.into())));
        }

        let devices =
            BTreeSet::from_iter(blockdev_paths).into_iter().map(|x| *x).collect::<Vec<&Path>>();

        let pool = SimPool::new(self.rdm.clone(), &devices, redundancy);

        if self.rdm.borrow_mut().throw_die() {
            return Err(EngineError::Stratis(ErrorEnum::Error("X".into())));
        }

        let bdev_paths = pool.block_devs.values().map(|p| p.devnode.clone()).collect();
        self.pools.insert(name.to_owned(), pool);

        Ok(bdev_paths)
    }

    fn destroy_pool(&mut self, name: &str) -> EngineResult<bool> {
        destroy_pool!{self; name}
    }

    fn rename_pool(&mut self, old_name: &str, new_name: &str) -> EngineResult<RenameAction> {
        rename_pool!{self; old_name; new_name}
    }

    /// Looks up the pool by its unique name
    fn get_pool(&mut self, name: &str) -> EngineResult<&mut Pool> {
        get_pool!(self; name)
    }

    /// Returns a collection of the Pool objects that belong to this engine
    fn pools(&mut self) -> BTreeMap<&str, &mut Pool> {
        pools!(self)
    }

    /// Set properties of the simulator
    fn configure_simulator(&mut self, denominator: u32) -> EngineResult<()> {
        self.rdm.borrow_mut().set_probability(denominator);
        Ok(())
    }
}

#[cfg(test)]
mod tests {

    use std::path::Path;

    use quickcheck::QuickCheck;

    use super::SimEngine;

    use engine::Engine;
    use engine::EngineError;
    use engine::ErrorEnum;
    use engine::RenameAction;

    #[test]
    fn prop_configure_simulator_runs() {

        /// Configure simulator should always return Ok.
        fn configure_simulator_runs(denominator: u32) -> bool {
            SimEngine::new().configure_simulator(denominator).is_ok()
        }

        QuickCheck::new().tests(10).quickcheck(configure_simulator_runs as fn(u32) -> bool);
    }

    #[test]
    /// When an engine has no pools, any name lookup should fail
    fn get_pool_err() {
        assert!(match SimEngine::new().get_pool("name") {
            Err(EngineError::Stratis(ErrorEnum::NotFound(_))) => true,
            _ => false,
        });
    }

    #[test]
    /// When an engine has no pools, the thing returned by pools() is empty
    fn pools_empty() {
        assert!(SimEngine::new().pools().is_empty());
    }

    #[test]
    /// When an engine has no pools, destroying any pool must succeed
    fn destroy_pool_empty() {
        assert!(SimEngine::new().destroy_pool("name").is_ok());
    }

    #[test]
    /// Destroying an empty pool should succeed.
    fn destroy_empty_pool() {
        let name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[], 0, false).unwrap();
        assert!(engine.destroy_pool(name).is_ok());
    }

    #[test]
    /// Destroying a pool with devices should fail
    fn destroy_pool_w_devices() {
        let name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[Path::new("/s/d")], 0, false).unwrap();
        assert!(match engine.destroy_pool(name) {
            Err(EngineError::Stratis(ErrorEnum::Busy(_))) => true,
            _ => false,
        });
    }

    #[test]
    #[ignore]
    /// Creating a new pool identical to the previous should succeed
    fn create_new_pool_twice() {
        let name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[], 0, false).unwrap();
        assert!(match engine.create_pool(name, &[], 0, false) {
            Ok(devs) => devs.is_empty(),
            Err(_) => false,
        });
    }

    #[test]
    /// Creating a new pool with the same name should fail
    fn create_pool_name_collision() {
        let name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[Path::new("/s/d")], 0, false).unwrap();
        assert!(match engine.create_pool(name, &[], 0, false) {
            Err(EngineError::Stratis(ErrorEnum::AlreadyExists(_))) => true,
            _ => false,
        });
    }

    #[test]
    /// Creating a pool with duplicate devices should succeed
    fn create_pool_duplicate_devices() {
        let path = "/s/d";
        let mut engine = SimEngine::new();
        let devices = vec![Path::new(path), Path::new(path)];
        assert!(match engine.create_pool("name", &devices, 0, false) {
            Ok(devs) => devs.len() == 1,
            _ => false,
        });
    }

    #[test]
    /// Creating a pool with an impossible raid level should fail
    fn create_pool_max_u16_raid() {
        let mut engine = SimEngine::new();
        assert!(engine.create_pool("name", &[], u16::max_value(), false).is_err());
    }

    #[test]
    /// Renaming a pool on an empty engine always works
    fn rename_empty() {
        let mut engine = SimEngine::new();
        assert!(match engine.rename_pool("old_name", "new_name") {
            Ok(RenameAction::NoSource) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming a pool to itself in an empty engine always works
    fn rename_empty_identity() {
        let mut engine = SimEngine::new();
        assert!(match engine.rename_pool("old_name", "old_name") {
            Ok(RenameAction::Identity) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming a pool to itself always works
    fn rename_identity() {
        let name = "name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[], 0, false).unwrap();
        assert!(match engine.rename_pool(name, name) {
            Ok(RenameAction::Identity) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming a pool to another pool should work if new name not taken
    fn rename_happens() {
        let name = "old_name";
        let mut engine = SimEngine::new();
        engine.create_pool(name, &[], 0, false).unwrap();
        assert!(match engine.rename_pool(name, "new_name") {
            Ok(RenameAction::Renamed) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming a pool to another pool should fail if new name taken
    fn rename_fails() {
        let old_name = "old_name";
        let new_name = "new_name";
        let mut engine = SimEngine::new();
        engine.create_pool(old_name, &[], 0, false).unwrap();
        engine.create_pool(new_name, &[], 0, false).unwrap();
        assert!(match engine.rename_pool(old_name, new_name) {
            Err(EngineError::Stratis(ErrorEnum::AlreadyExists(_))) => true,
            _ => false,
        });
    }

    #[test]
    /// Renaming should succeed if old_name absent, new present
    fn rename_no_op() {
        let old_name = "old_name";
        let new_name = "new_name";
        let mut engine = SimEngine::new();
        engine.create_pool(new_name, &[], 0, false).unwrap();
        assert!(match engine.rename_pool(old_name, new_name) {
            Ok(RenameAction::NoSource) => true,
            _ => false,
        });
    }

}
<|endoftext|>


<commit_before>extern crate specs;
extern crate futures;
extern crate serde_json;

use self::specs::{Join, ReadStorage, WriteStorage, System, Entities};
use self::futures::{Future, Sink};
use std::collections::HashMap;

use model::comp::{Pos, Vel, Acc, Bounciness, Ping, Player as PlayerComp};
use model::client::{ClientState, Ball, Player};
use model::game::Id;
use engine::OwnedMessage;
use util::timestamp;

pub struct Sending;
impl<'a> System<'a> for Sending {
    #[allow(type_complexity)]
    type SystemData = (
        ReadStorage<'a, Pos>,
        ReadStorage<'a, Vel>,
        ReadStorage<'a, Acc>,
        ReadStorage<'a, Bounciness>,
        WriteStorage<'a, PlayerComp>,
        WriteStorage<'a, Ping>,
        Entities<'a>,
    );

    fn run(
        &mut self,
        (pos, vel, acc, bounciness, mut player, mut ping, entities): Self::SystemData,
    ) {
        let (ball_pos, ball_vel, _) = (&pos, &vel, &bounciness).join().take(1).next().unwrap();
        let ball = Ball {
            pos: ball_pos.clone(),
            vel: ball_vel.clone(),
        };

        let mut players = HashMap::new();
        for (pos, vel, acc, player) in (&pos, &vel, &acc, &player).join() {
            players.insert(
                player.id,
                Player {
                    pos: pos.clone(),
                    vel: vel.clone(),
                    acc: acc.clone(),
                },
            );
        }
        let state = ClientState {
            ball,
            players,
            timestamp: timestamp(),
        };
        for player in &mut player.join() {
            send(player, &state);
        }

        let mut pinged_players = Vec::new();
        for (mut player, entity, _) in (&mut player, &*entities, &mut ping).join() {

            send_ping(&mut player);
            pinged_players.push(entity);
        }

        for pinged_player in pinged_players {
            ping.remove(pinged_player);
        }
    }
}

fn send(player: &PlayerComp, state: &ClientState) {
    let msg = serde_json::to_string(&state).unwrap();
    let send_channel = player.send_channel.clone();
    send_channel
        .send(OwnedMessage::Text(msg))
        .wait()
        .expect("Failed to send message");
}

fn send_ping(player: &mut PlayerComp) {
    let send_channel = player.send_channel.clone();
    let timestamp = timestamp();
    let id = Id::new_v4();
    player.pingpongs.insert(id, (timestamp, None));
    send_channel
        .send(OwnedMessage::Ping(id.as_bytes().to_vec()))
        .wait()
        .unwrap();
}
<commit_msg>Core: Run rustfmt<commit_after>extern crate specs;
extern crate futures;
extern crate serde_json;

use self::specs::{Join, ReadStorage, WriteStorage, System, Entities};
use self::futures::{Future, Sink};
use std::collections::HashMap;

use model::comp::{Pos, Vel, Acc, Bounciness, Ping, Player as PlayerComp};
use model::client::{ClientState, Ball, Player};
use model::game::Id;
use engine::OwnedMessage;
use util::timestamp;

pub struct Sending;
impl<'a> System<'a> for Sending {
    #[allow(type_complexity)]
    type SystemData = (ReadStorage<'a, Pos>,
     ReadStorage<'a, Vel>,
     ReadStorage<'a, Acc>,
     ReadStorage<'a, Bounciness>,
     WriteStorage<'a, PlayerComp>,
     WriteStorage<'a, Ping>,
     Entities<'a>);

    fn run(
        &mut self,
        (pos, vel, acc, bounciness, mut player, mut ping, entities): Self::SystemData,
    ) {
        let (ball_pos, ball_vel, _) = (&pos, &vel, &bounciness).join().take(1).next().unwrap();
        let ball = Ball {
            pos: ball_pos.clone(),
            vel: ball_vel.clone(),
        };

        let mut players = HashMap::new();
        for (pos, vel, acc, player) in (&pos, &vel, &acc, &player).join() {
            players.insert(
                player.id,
                Player {
                    pos: pos.clone(),
                    vel: vel.clone(),
                    acc: acc.clone(),
                },
            );
        }
        let state = ClientState {
            ball,
            players,
            timestamp: timestamp(),
        };
        for player in &mut player.join() {
            send(player, &state);
        }

        let mut pinged_players = Vec::new();
        for (mut player, entity, _) in (&mut player, &*entities, &mut ping).join() {

            send_ping(&mut player);
            pinged_players.push(entity);
        }

        for pinged_player in pinged_players {
            ping.remove(pinged_player);
        }
    }
}

fn send(player: &PlayerComp, state: &ClientState) {
    let msg = serde_json::to_string(&state).unwrap();
    let send_channel = player.send_channel.clone();
    send_channel.send(OwnedMessage::Text(msg)).wait().expect(
        "Failed to send message",
    );
}

fn send_ping(player: &mut PlayerComp) {
    let send_channel = player.send_channel.clone();
    let timestamp = timestamp();
    let id = Id::new_v4();
    player.pingpongs.insert(id, (timestamp, None));
    send_channel
        .send(OwnedMessage::Ping(id.as_bytes().to_vec()))
        .wait()
        .unwrap();
}
<|endoftext|>


<commit_before>extern crate gitlab_api as gitlab;

use std::env;
#[macro_use]
extern crate log;
extern crate env_logger;

use gitlab::GitLab;

fn main() {
    env_logger::init().unwrap();
    info!("starting up");

    let hostname = match env::var("GITLAB_HOSTNAME") {
        Ok(val) => val,
        Err(_) => {
            let default = String::from("gitlab.com");
            println!("Please set environment variable 'GITLAB_HOSTNAME'. Using default '{}'.",
                     default);
            default
        }
    };

    let token = match env::var("GITLAB_TOKEN") {
        Ok(val) => val,
        Err(_) => {
            panic!("Please set environment variable 'GITLAB_TOKEN'. Take it from \
                    http://{}/profile/account",
                   hostname);
        }
    };

    let gl = GitLab::new_insecure(&hostname, &token);

    let project_id = 142;
    let merge_requests_ids = vec![423, 409];

    let merge_requests = gl.merge_requests(project_id).list();
    println!("merge_requests: {:?}", merge_requests);

    let merge_request = gl.merge_requests(project_id).single(merge_requests_ids[0]).list();
    println!("merge_request: {:?}", merge_request);

    let merge_requests = gl.merge_requests(project_id).iid(vec![merge_requests_ids[0]]).list();
    println!("merge_requests: {:?}", merge_requests);

    let merge_requests = gl.merge_requests(project_id).iid(merge_requests_ids).list();
    println!("merge_requests: {:?}", merge_requests);
}
<commit_msg>Change default MR ids<commit_after>extern crate gitlab_api as gitlab;

use std::env;
#[macro_use]
extern crate log;
extern crate env_logger;

use gitlab::GitLab;

fn main() {
    env_logger::init().unwrap();
    info!("starting up");

    let hostname = match env::var("GITLAB_HOSTNAME") {
        Ok(val) => val,
        Err(_) => {
            let default = String::from("gitlab.com");
            println!("Please set environment variable 'GITLAB_HOSTNAME'. Using default '{}'.",
                     default);
            default
        }
    };

    let token = match env::var("GITLAB_TOKEN") {
        Ok(val) => val,
        Err(_) => {
            panic!("Please set environment variable 'GITLAB_TOKEN'. Take it from \
                    http://{}/profile/account",
                   hostname);
        }
    };

    let gl = GitLab::new_insecure(&hostname, &token);

    let project_id = 142;
    let merge_requests_ids = vec![409, 410];

    let merge_requests = gl.merge_requests(project_id).list();
    println!("merge_requests: {:?}", merge_requests);

    let merge_request = gl.merge_requests(project_id).single(merge_requests_ids[0]).list();
    println!("merge_request: {:?}", merge_request);

    let merge_requests = gl.merge_requests(project_id).iid(vec![merge_requests_ids[0]]).list();
    println!("merge_requests: {:?}", merge_requests);

    let merge_requests = gl.merge_requests(project_id).iid(merge_requests_ids).list();
    println!("merge_requests: {:?}", merge_requests);
}
<|endoftext|>


<commit_before>extern crate libc;

#[macro_use]
extern crate apache2;

use apache2::{Request, Status, server_banner, server_description, server_built, show_mpm,
   apr_version_string, apu_version_string};

apache2_module!(info_rs_module, info_rs_handler, c_info_rs_handler, b"mod_info_rs\0");

fn info_rs_handler(r: &Request) -> Status {
   if r.handler().unwrap() != "server-info-rs" {
      return Status::DECLINED
   }

   let conn = r.connection().unwrap();

   r.set_content_type("text/html");

   r.write("<!doctype html><meta charset=\"utf-8\"><title>Apache Info</title>");

   r.write("
Apache Server Information
");

   let server_name = r.escape_html(r.server_name().unwrap()).unwrap();
   let server_port = r.server_port();
   let local_ip = conn.local_ip().unwrap();
   r.write(format!("
Server: {}:{} (via {})
", server_name, server_port, local_ip));

   let description = server_description().unwrap();
   let banner = server_banner().unwrap();
   r.write(format!("
Server Description/Banner: {} / {}
", description, banner));

   let mmp = show_mpm().unwrap();
   r.write(format!("
Server MPM: {}
", mmp));

   let built = server_built().unwrap();
   r.write(format!("
Server Built: {}
", built));

   let apr_version = apr_version_string().unwrap();
   r.write(format!("
Server loaded APR Version: {}
", apr_version));

   let apu_version = apu_version_string().unwrap();
   r.write(format!("
Server loaded APU Version: {}
", apu_version));

   let document_root = r.document_root().unwrap();
   r.write(format!("
Document Root: {}
", document_root));

   r.write("
");

   let client_ip = conn.client_ip().unwrap();
   r.write(format!("
Client IP: {}
", client_ip));

   let args = match r.args() {
      Some(args) => args,
      None => "None"
   };
   r.write(format!("
Request Args: {}
", args));

   r.write("");

   Status::OK
}
<commit_msg>Helper function for unwrapping option string values in the info module.<commit_after>extern crate libc;

#[macro_use]
extern crate apache2;

use apache2::{Request, Status, server_banner, server_description, server_built, show_mpm,
   apr_version_string, apu_version_string};

apache2_module!(info_rs_module, info_rs_handler, c_info_rs_handler, b"mod_info_rs\0");

fn unwrap_str<'a>(option: Option<&'a str>) -> &'a str {
   match option {
      Some(val) => val,
      None => "--"
   }
}

fn info_rs_handler(r: &Request) -> Status {
   if r.handler().unwrap() != "server-info-rs" {
      return Status::DECLINED
   }

   let conn = r.connection().unwrap();

   r.set_content_type("text/html");

   r.write("<!doctype html><meta charset=\"utf-8\"><title>Apache Info</title>");

   r.write("
Apache Server Information
");

   let server_name = unwrap_str(
      r.escape_html(
         unwrap_str(r.server_name())
      )
   );
   let server_port = r.server_port();
   let local_ip = unwrap_str(conn.local_ip());
   r.write(format!("
Server: {}:{} (via {})
", server_name, server_port, local_ip));

   let description = unwrap_str(server_description());
   let banner = unwrap_str(server_banner());
   r.write(format!("
Server Description/Banner: {} / {}
", description, banner));

   let mmp = unwrap_str(show_mpm());
   r.write(format!("
Server MPM: {}
", mmp));

   let built = unwrap_str(server_built());
   r.write(format!("
Server Built: {}
", built));

   let apr_version = unwrap_str(apr_version_string());
   r.write(format!("
Server loaded APR Version: {}
", apr_version));

   let apu_version = unwrap_str(apu_version_string());
   r.write(format!("
Server loaded APU Version: {}
", apu_version));

   let document_root = unwrap_str(r.document_root());
   r.write(format!("
Document Root: {}
", document_root));

   r.write("
");

   let client_ip = unwrap_str(conn.client_ip());
   r.write(format!("
Client IP: {}
", client_ip));

   let args = unwrap_str(r.args());
   r.write(format!("
Request Args: {}
", args));

   r.write("");

   Status::OK
}
<|endoftext|>


<commit_before>//! This crate contains a compiler plugin to generate NBT binary format
//! serialization code for custom structs. It can be used as follows:
//!
//! ```ignore
//! #![feature(plugin, custom_derive)]
//! #![plugin(nbt_macros)]
//!
//! extern crate nbt;
//!
//! use nbt::NbtError;
//! use nbt::serialize::{NbtFmt, to_writer};
//!
//! #[derive(NbtFmt)]
//! struct MyMob {
//! 	name: String,
//! 	health: i8
//! }
//!
//! fn main() {
//!     let mut bytes = Vec::new();
//!     let mob = MyMob { name: "Dr. Evil".to_string(), health: 240 };
//!
//!     to_writer(&mut bytes, mob).unwrap();
//! }
//! ```
//!
//! The custom `derive(NbtFmt)` will generate code equivalent to the following:
//!
//! ```ignore
//! impl NbtFmt for MyMob {
//! 	fn to_bare_nbt<W>(&self, dst: &mut W) -> Result<(), NbtError>
//! 	   where W: std::io::Write
//! 	{
//! 		try!(self.name.to_nbt(dst, "name"));
//!         try!(self.health.to_nbt(dst, "health"));
//!
//!         close_nbt(dst)
//! 	}
//! }
//! ```
//!
//! Which will work so long as the fields of the struct have `NbtFmt`
//! implementations of their own.

#![feature(plugin_registrar, quote, rustc_private)]

extern crate rustc;
extern crate syntax;

use syntax::ast::{Expr, MetaItem, Mutability};
use syntax::codemap::Span;
use syntax::ext::base::{Annotatable, ExtCtxt, MultiDecorator};
use syntax::ext::build::AstBuilder;
use syntax::ext::deriving::generic::*;
use syntax::ext::deriving::generic::ty::*;
use syntax::parse::token::{get_ident, InternedString};
use syntax::ptr::P;

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(reg: &mut rustc::plugin::Registry) {
    reg.register_syntax_extension(
        syntax::parse::token::intern("derive_NbtFmt"),
        MultiDecorator(Box::new(expand_derive_nbtfmt)));
}

macro_rules! pathvec {
    ($($x:ident)::+) => (
        vec![ $( stringify!($x) ),+ ]
    )
}

macro_rules! path {
    ($($x:tt)*) => (
        Path::new( pathvec!( $($x)* ) )
    )
}

macro_rules! pathexpr {
	($cx:ident, $span:ident, $($x:ident)::+) => (
		$cx.expr_path($cx.path_global($span,
			vec![ $( $cx.ident_of( stringify!($x) ) ),+ ]))
	)
}

pub fn expand_derive_nbtfmt(cx: &mut ExtCtxt, span: Span, meta_item: &MetaItem,
                            item: &Annotatable,
                            push: &mut FnMut(Annotatable))
{
	let w_arg = Path::new_local("__W");
    let trait_def = TraitDef {
        span: span,
        attributes: Vec::new(),
        path: path!(nbt::serialize::NbtFmt),
        additional_bounds: Vec::new(),
        generics: LifetimeBounds::empty(),
        methods: vec!(
            MethodDef {
                name: "to_bare_nbt",
                generics: LifetimeBounds {
                    lifetimes: Vec::new(),
                    // This adds a <__W: std::io::Writer> generic to the method.
                    bounds: vec![("__W", vec![path!(std::io::Write)])],
                },
                // Pass the immutable borrowed self argument, `&self`.
                explicit_self: borrowed_explicit_self(),
                // Pass a single argument of type `&mut __W`.
                args: vec!(Ptr(Box::new(Literal(w_arg)),
                               Borrowed(None, Mutability::MutMutable))),
                // Return a `Result<(), nbt::NbtError>`.
                ret_ty: Literal(Path::new_(
                    pathvec!(std::result::Result),
                    None,
                    vec!(Box::new(Tuple(Vec::new())), // Unit.
                         Box::new(Literal(Path::new_( // nbt::NbtError
                             pathvec!(nbt::NbtError),
                             None, Vec::new(), true)))),
                    true)),
                attributes: Vec::new(),
                is_unsafe: false,
                combine_substructure: combine_substructure(Box::new(|c, s, sub| {
                    cs_nbtfmt(c, s, sub)
                })),
            }
        ),
        associated_types: Vec::new(),
    };

    trait_def.expand(cx, meta_item, item, push)
}

fn cs_nbtfmt(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
    // Retrieve the argument passed to the to_bare_nbt function, i.e. the
    // `dst: &mut __W` bit. Since the method is already defined, there's no
    // reason for this to fail, so we call `cx.span_bug` indicating a compiler
    // error.
    let dst_expr = match (substr.nonself_args.len(),
                          substr.nonself_args.get(0)) {
        (1, Some(dst)) => dst,
        _ => cx.span_bug(trait_span,
                         "incorrect number of arguments in `derive(NbtFmt)`")
    };

    let call_nbt_fmt = |span, thing_expr, name| {
        let nbt_fmt_path = pathexpr!(cx, span, nbt::serialize::NbtFmt::to_nbt);
        let ref_thing = cx.expr_addr_of(span, thing_expr);

        // Create a string literal expression for the field's identifier.
        let name_lit = get_ident(name);
        let name_expr = cx.expr_str(span, name_lit);

        // Create a call expression, using the function path (nbt_fmt_path)
        // and `&self, dst, "<field>"` as arguments.
        let fmt_call = cx.expr_call(span, nbt_fmt_path,
                                    vec!(ref_thing, dst_expr.clone(), name_expr));

        // Wrap the call in a try! macro.
        let try_fmt_call = cx.expr_try(span, fmt_call);

        // Add a semicolon.
        cx.stmt_expr(try_fmt_call)
    };

    match *substr.fields {
        Struct(ref fields) => {
        	// Unit structs are kind of irrelevant for NBT, so throw an error
        	// if someone tries to derive(NbtFmt) over one.
            if fields.is_empty() {
                cx.span_err(trait_span,
                            "`NbtFmt` has no meaning for unit structs.");
                cx.expr_fail(trait_span, InternedString::new(""))
            } else if fields[0].name.is_none() {
            	// FIXME: Handle tuple structs using to_nbt
            	// with name = "".
                cx.span_err(trait_span,
                            "`NbtFmt` cannot yet be derived for tuple structs.");
                cx.expr_fail(trait_span, InternedString::new(""))
            } else {
                let mut stmts = Vec::new();

                for &FieldInfo { ref self_, span, name, .. } in fields {
                	// FIXME: Use cx.bug for properly handling unnamed fields.
                    stmts.push(call_nbt_fmt(span, self_.clone(), name.unwrap().clone()));
                }

                let close_nbt_path = pathexpr!(cx, trait_span, nbt::serialize::close_nbt);

                let close = cx.expr_call(trait_span, close_nbt_path, vec![dst_expr.clone()]);

                cx.expr_block(cx.block(trait_span, stmts, Some(close)))
            }
        },
        EnumMatching(..) => {
            cx.span_err(trait_span,
                        "`NbtFmt` cannot yet be derived for enums.");
            cx.expr_fail(trait_span, InternedString::new(""))
        },
        EnumNonMatchingCollapsed(..) => {
            cx.span_bug(trait_span,
                        "non-matching enum variants in `#[derive(NbtFmt)]`")
        },
        StaticEnum(..) | StaticStruct(..) => {
            cx.span_bug(trait_span, "static method in `#[derive(NbtFmt)]`")
        },
    }
}
<commit_msg>Includes some whitespace fixes.<commit_after>//! This crate contains a compiler plugin to generate Named Binary Tag format
//! serialization code for custom structs. It can be used as follows:
//!
//! ```ignore
//! #![feature(plugin, custom_derive)]
//! #![plugin(nbt_macros)]
//!
//! extern crate nbt;
//!
//! use nbt::NbtError;
//! use nbt::serialize::{NbtFmt, to_writer};
//!
//! #[derive(NbtFmt)]
//! struct MyMob {
//!     name: String,
//!     health: i8
//! }
//!
//! fn main() {
//!     let mut bytes = Vec::new();
//!     let mob = MyMob { name: "Dr. Evil".to_string(), health: 240 };
//!
//!     to_writer(&mut bytes, mob).unwrap();
//! }
//! ```
//!
//! The custom `derive(NbtFmt)` will generate code equivalent to the following:
//!
//! ```ignore
//! impl NbtFmt for MyMob {
//!     fn to_bare_nbt<W>(&self, dst: &mut W) -> Result<(), NbtError>
//!        where W: std::io::Write
//!     {
//!         try!(self.name.to_nbt(dst, "name"));
//!         try!(self.health.to_nbt(dst, "health"));
//!
//!         close_nbt(dst)
//!     }
//! }
//! ```
//!
//! Which will work so long as the fields of the struct have `NbtFmt`
//! implementations of their own.

#![feature(plugin_registrar, quote, rustc_private)]

extern crate rustc;
extern crate syntax;

use syntax::ast::{Expr, MetaItem, Mutability};
use syntax::codemap::Span;
use syntax::ext::base::{Annotatable, ExtCtxt, MultiDecorator};
use syntax::ext::build::AstBuilder;
use syntax::ext::deriving::generic::*;
use syntax::ext::deriving::generic::ty::*;
use syntax::parse::token::{get_ident, InternedString};
use syntax::ptr::P;

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(reg: &mut rustc::plugin::Registry) {
    reg.register_syntax_extension(
        syntax::parse::token::intern("derive_NbtFmt"),
        MultiDecorator(Box::new(expand_derive_nbtfmt)));
}

macro_rules! pathvec {
    ($($x:ident)::+) => (
        vec![ $( stringify!($x) ),+ ]
    )
}

macro_rules! path {
    ($($x:tt)*) => (
        Path::new( pathvec!( $($x)* ) )
    )
}

macro_rules! pathexpr {
    ($cx:ident, $span:ident, $($x:ident)::+) => (
        $cx.expr_path($cx.path_global($span,
            vec![ $( $cx.ident_of( stringify!($x) ) ),+ ]))
    )
}

pub fn expand_derive_nbtfmt(cx: &mut ExtCtxt, span: Span, meta_item: &MetaItem,
                            item: &Annotatable,
                            push: &mut FnMut(Annotatable))
{
    let w_arg = Path::new_local("__W");
    let trait_def = TraitDef {
        span: span,
        attributes: Vec::new(),
        path: path!(nbt::serialize::NbtFmt),
        additional_bounds: Vec::new(),
        generics: LifetimeBounds::empty(),
        methods: vec!(
            MethodDef {
                name: "to_bare_nbt",
                generics: LifetimeBounds {
                    lifetimes: Vec::new(),
                    // This adds a <__W: std::io::Writer> generic to the method.
                    bounds: vec![("__W", vec![path!(std::io::Write)])],
                },
                // Pass the immutable borrowed self argument, `&self`.
                explicit_self: borrowed_explicit_self(),
                // Pass a single argument of type `&mut __W`.
                args: vec!(Ptr(Box::new(Literal(w_arg)),
                               Borrowed(None, Mutability::MutMutable))),
                // Return a `Result<(), nbt::NbtError>`.
                ret_ty: Literal(Path::new_(
                    pathvec!(std::result::Result),
                    None,
                    vec!(Box::new(Tuple(Vec::new())), // Unit.
                         Box::new(Literal(Path::new_( // nbt::NbtError
                             pathvec!(nbt::NbtError),
                             None, Vec::new(), true)))),
                    true)),
                attributes: Vec::new(),
                is_unsafe: false,
                combine_substructure: combine_substructure(Box::new(|c, s, sub| {
                    cs_nbtfmt(c, s, sub)
                })),
            }
        ),
        associated_types: Vec::new(),
    };

    trait_def.expand(cx, meta_item, item, push)
}

fn cs_nbtfmt(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
    // Retrieve the argument passed to the to_bare_nbt function, i.e. the
    // `dst: &mut __W` bit. Since the method is already defined, there's no
    // reason for this to fail, so we call `cx.span_bug` indicating a compiler
    // error.
    let dst_expr = match (substr.nonself_args.len(),
                          substr.nonself_args.get(0)) {
        (1, Some(dst)) => dst,
        _ => cx.span_bug(trait_span,
                         "incorrect number of arguments in `derive(NbtFmt)`")
    };

    let call_nbt_fmt = |span, thing_expr, name| {
        let nbt_fmt_path = pathexpr!(cx, span, nbt::serialize::NbtFmt::to_nbt);
        let ref_thing = cx.expr_addr_of(span, thing_expr);

        // Create a string literal expression for the field's identifier.
        let name_lit = get_ident(name);
        let name_expr = cx.expr_str(span, name_lit);

        // Create a call expression, using the function path (nbt_fmt_path)
        // and `&self, dst, "<field>"` as arguments.
        let fmt_call = cx.expr_call(span, nbt_fmt_path,
                                    vec!(ref_thing, dst_expr.clone(), name_expr));

        // Wrap the call in a try! macro.
        let try_fmt_call = cx.expr_try(span, fmt_call);

        // Add a semicolon.
        cx.stmt_expr(try_fmt_call)
    };

    match *substr.fields {
        Struct(ref fields) => {
            // Unit structs are kind of irrelevant for NBT, so throw an error
            // if someone tries to derive(NbtFmt) over one.
            if fields.is_empty() {
                cx.span_err(trait_span,
                            "`NbtFmt` has no meaning for unit structs.");
                cx.expr_fail(trait_span, InternedString::new(""))
            } else if fields[0].name.is_none() {
                // FIXME: Handle tuple structs using to_nbt with each name as
                //  "field0", etc.
                cx.span_err(trait_span,
                            "`NbtFmt` cannot yet be derived for tuple structs.");
                cx.expr_fail(trait_span, InternedString::new(""))
            } else {
                let mut stmts = Vec::new();

                for &FieldInfo { ref self_, span, name, .. } in fields {
                    // FIXME: Use cx.bug for properly handling unnamed fields.
                    stmts.push(call_nbt_fmt(span, self_.clone(), name.unwrap().clone()));
                }

                let close_nbt_path = pathexpr!(cx, trait_span, nbt::serialize::close_nbt);

                let close = cx.expr_call(trait_span, close_nbt_path, vec![dst_expr.clone()]);

                cx.expr_block(cx.block(trait_span, stmts, Some(close)))
            }
        },
        EnumMatching(..) => {
            cx.span_err(trait_span,
                        "`NbtFmt` cannot yet be derived for enums.");
            cx.expr_fail(trait_span, InternedString::new(""))
        },
        EnumNonMatchingCollapsed(..) => {
            cx.span_bug(trait_span,
                        "non-matching enum variants in `#[derive(NbtFmt)]`")
        },
        StaticEnum(..) | StaticStruct(..) => {
            cx.span_bug(trait_span, "static method in `#[derive(NbtFmt)]`")
        },
    }
}
<|endoftext|>