<commit_before>use latch::{CountLatch, Latch, LatchProbe};
#[allow(warnings)]
use log::Event::*;
use futures::{Async, Future, Poll};
use futures::executor;
use futures::future::CatchUnwind;
use futures::task::{self, Spawn, Task, Unpark};
use job::{Job, JobRef};
use registry::{Registry, WorkerThread};
use std::any::Any;
use std::panic::AssertUnwindSafe;
use std::mem;
use std::sync::Arc;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::*;
use std::sync::Mutex;
use unwind;

const STATE_PARKED: usize = 0;
const STATE_UNPARKED: usize = 1;
const STATE_EXECUTING: usize = 2;
const STATE_EXECUTING_UNPARKED: usize = 3;
const STATE_COMPLETE: usize = 4;

// Warning: Public end-user API.
pub struct RayonFuture<T, E> {
    inner: Arc<ScopeFutureTrait<Result<T, E>, Box<Any + Send + 'static>>>,
}

/// Create a `RayonFuture` that will execute `F` and yield its result,
/// propagating any panics.
///
/// Unsafe because caller asserts that all references in `F` will
/// remain valid at least until `counter` is decremented via `set()`.
/// In practice, this is ensured by the `scope()` API, which ensures
/// that `F: 'scope` and that `'scope` does not end until `counter`
/// reaches 0.
///
/// NB. This is a free fn so that we can expose `RayonFuture` as public API.
pub unsafe fn new_rayon_future<F>(future: F,
                                  counter: *const CountLatch)
                                  -> RayonFuture<F::Item, F::Error>
    where F: Future + Send
{
    let inner = ScopeFuture::spawn(future, counter);
    RayonFuture { inner: hide_lifetime(inner) }
}

unsafe fn hide_lifetime<'l, T, E>(x: Arc<ScopeFutureTrait<T, E> + 'l>)
                                  -> Arc<ScopeFutureTrait<T, E>> {
    mem::transmute(x)
}

impl<T, E> RayonFuture<T, E> {
    pub fn rayon_wait(mut self) -> Result<T, E> {
        let worker_thread = WorkerThread::current();
        if worker_thread.is_null() {
            self.wait()
        } else {
            // Assert that uses of `worker_thread` pointer below are
            // valid (because we are on the worker-thread).
            unsafe {
                (*worker_thread).wait_until(&*self.inner);
                debug_assert!(self.inner.probe());
                self.poll().map(|a_v| match a_v {
                    Async::Ready(v) => v,
                    Async::NotReady => panic!("probe() returned true but poll not ready")
                })
            }
        }
    }
}

impl<T, E> Future for RayonFuture<T, E> {
    type Item = T;
    type Error = E;

    fn wait(self) -> Result<T, E> {
        if WorkerThread::current().is_null() {
            executor::spawn(self).wait_future()
        } else {
            panic!("using  `wait()` in a Rayon thread is unwise; try `rayon_wait()`")
        }
    }

    fn poll(&mut self) -> Poll<T, E> {
        match self.inner.poll() {
            Ok(Async::Ready(Ok(v))) => Ok(Async::Ready(v)),
            Ok(Async::Ready(Err(e))) => Err(e),
            Ok(Async::NotReady) => Ok(Async::NotReady),
            Err(e) => unwind::resume_unwinding(e),
        }
    }
}

impl<T, E> Drop for RayonFuture<T, E> {
    fn drop(&mut self) {
        self.inner.cancel();
    }
}

/// ////////////////////////////////////////////////////////////////////////

struct ScopeFuture<F: Future + Send> {
    state: AtomicUsize,
    registry: Arc<Registry>,
    contents: Mutex<ScopeFutureContents<F>>,
}

type CU<F> = CatchUnwind<AssertUnwindSafe<F>>;

struct ScopeFutureContents<F: Future + Send> {
    spawn: Option<Spawn<CU<F>>>,
    unpark: Option<Arc<Unpark>>,

    // Pointer to ourselves. We `None` this out when we are finished
    // executing, but it's convenient to keep around normally.
    this: Option<Arc<ScopeFuture<F>>>,

    // the counter in the scope; since the scope doesn't terminate until
    // counter reaches zero, and we hold a ref in this counter, we are
    // assured that this pointer remains valid
    counter: *const CountLatch,

    waiting_task: Option<Task>,
    result: Poll<<CU<F> as Future>::Item, <CU<F> as Future>::Error>,
}

trait Ping: Send + Sync {
    fn ping(&self);
}

// Assert that the `*const` is safe to transmit between threads:
unsafe impl<F: Future + Send> Send for ScopeFuture<F> {}
unsafe impl<F: Future + Send> Sync for ScopeFuture<F> {}

impl<F: Future + Send> ScopeFuture<F> {
    // Unsafe: Caller asserts that `future` and `counter` will remain
    // valid until we invoke `counter.set()`.
    unsafe fn spawn(future: F, counter: *const CountLatch) -> Arc<Self> {
        let worker_thread = WorkerThread::current();
        debug_assert!(!worker_thread.is_null());

        // Using `AssertUnwindSafe` is valid here because (a) the data
        // is `Send + Sync`, which is our usual boundary and (b)
        // panics will be propagated when the `RayonFuture` is polled.
        let spawn = task::spawn(AssertUnwindSafe(future).catch_unwind());

        let future: Arc<Self> = Arc::new(ScopeFuture::<F> {
            state: AtomicUsize::new(STATE_PARKED),
            registry: (*worker_thread).registry().clone(),
            contents: Mutex::new(ScopeFutureContents {
                spawn: None,
                unpark: None,
                this: None,
                counter: counter,
                waiting_task: None,
                result: Ok(Async::NotReady),
            }),
        });

        // Make the two self-cycles. Note that these imply the future
        // cannot be freed until these fields are set to `None` (which
        // occurs when it is finished executing).
        {
            let mut contents = future.contents.try_lock().unwrap();
            contents.spawn = Some(spawn);
            contents.unpark = Some(Self::make_unpark(&future));
            contents.this = Some(future.clone());
        }

        future.ping();

        future
    }

    /// Creates a `JobRef` from this job -- note that this hides all
    /// lifetimes, so it is up to you to ensure that this JobRef
    /// doesn't outlive any data that it closes over.
    unsafe fn into_job_ref(this: Arc<Self>) -> JobRef {
        let this: *const Self = mem::transmute(this);
        JobRef::new(this)
    }

    fn make_unpark(this: &Arc<Self>) -> Arc<Unpark> {
        // Hide any lifetimes in `self`. This is safe because, until
        // `self` is dropped, the counter is not decremented, and so
        // the `'scope` lifetimes cannot end.
        //
        // Unfortunately, as `Unpark` currently requires `'static`, we
        // have to do an indirection and this ultimately requires a
        // fresh allocation.
        //
        // Here we assert that hiding the lifetimes in this fashion is
        // safe: we claim this is true because the lifetimes we are
        // hiding are part of `F`, and we now that any lifetimes in
        // `F` outlive `counter`. And we can see from `complete()`
        // that we drop all values of type `F` before decrementing
        // `counter`.
        unsafe {
            let ping: PingUnpark = PingUnpark::new(this.clone());
            let ping: PingUnpark<'static> = mem::transmute(ping);
            Arc::new(ping)
        }
    }

    fn unpark_inherent(&self) {
        loop {
            match self.state.load(Relaxed) {
                STATE_PARKED => {
                    if {
                        self.state
                            .compare_exchange_weak(STATE_PARKED, STATE_UNPARKED, Release, Relaxed)
                            .is_ok()
                    } {
                        // Contention here is unlikely but possible: a
                        // previous execution might have moved us to the
                        // PARKED state but not yet released the lock.
                        let contents = self.contents.lock().unwrap();

                        // Assert that `job_ref` remains valid until
                        // it is executed.  That's true because
                        // `job_ref` holds a ref on the `Arc` and
                        // because, until `job_ref` completes, the
                        // references in the future are valid.
                        unsafe {
                            let job_ref = Self::into_job_ref(contents.this.clone().unwrap());
                            self.registry.inject(&[job_ref]);
                        }
                        return;
                    }
                }

                STATE_EXECUTING => {
                    if {
                        self.state
                            .compare_exchange_weak(STATE_EXECUTING,
                                                   STATE_EXECUTING_UNPARKED,
                                                   Release,
                                                   Relaxed)
                            .is_ok()
                    } {
                        return;
                    }
                }

                state => {
                    debug_assert!(state == STATE_UNPARKED || state == STATE_EXECUTING_UNPARKED ||
                                  state == STATE_COMPLETE);
                    return;
                }
            }
        }
    }

    fn begin_execute_state(&self) {
        // When we are put into the unparked state, we are enqueued in
        // a worker thread. We should then be executed exactly once,
        // at which point we transiition to STATE_EXECUTING. Nobody
        // should be contending with us to change the state here.
        let state = self.state.load(Acquire);
        debug_assert_eq!(state, STATE_UNPARKED);
        let result = self.state.compare_exchange(state, STATE_EXECUTING, Release, Relaxed);
        debug_assert_eq!(result, Ok(STATE_UNPARKED));
    }

    fn end_execute_state(&self) -> bool {
        loop {
            match self.state.load(Relaxed) {
                STATE_EXECUTING => {
                    if {
                        self.state
                            .compare_exchange_weak(STATE_EXECUTING, STATE_PARKED, Release, Relaxed)
                            .is_ok()
                    } {
                        // We put ourselves into parked state, no need to
                        // re-execute.  We'll just wait for the Unpark.
                        return true;
                    }
                }

                state => {
                    debug_assert_eq!(state, STATE_EXECUTING_UNPARKED);
                    if {
                        self.state
                            .compare_exchange_weak(state, STATE_EXECUTING, Release, Relaxed)
                            .is_ok()
                    } {
                        // We finished executing, but an unpark request
                        // came in the meantime.  We need to execute
                        // again. Return false as we failed to end the
                        // execution phase.
                        return false;
                    }
                }
            }
        }
    }
}

impl<F: Future + Send> Ping for ScopeFuture<F> {
    fn ping(&self) {
        self.unpark_inherent();
    }
}

impl<F: Future + Send> Job for ScopeFuture<F> {
    unsafe fn execute(this: *const Self) {
        let this: Arc<Self> = mem::transmute(this);

        // *generally speaking* there should be no contention for the
        // lock, but it is possible -- we can end execution, get re-enqeueud,
        // and re-executed, before we have time to return from this fn
        let mut contents = this.contents.lock().unwrap();

        log!(FutureExecute { state: this.state.load(Relaxed) });

        this.begin_execute_state();
        loop {
            match contents.poll() {
                Ok(Async::Ready(v)) => {
                    log!(FutureExecuteReady);
                    return contents.complete(Ok(Async::Ready(v)));
                }
                Ok(Async::NotReady) => {
                    log!(FutureExecuteNotReady);
                    if this.end_execute_state() {
                        return;
                    }
                }
                Err(err) => {
                    log!(FutureExecuteErr);
                    return contents.complete(Err(err));
                }
            }
        }
    }
}

impl<F: Future + Send> ScopeFutureContents<F> {
    fn poll(&mut self) -> Poll<<CU<F> as Future>::Item, <CU<F> as Future>::Error> {
        let unpark = self.unpark.clone().unwrap();
        self.spawn.as_mut().unwrap().poll_future(unpark)
    }

    fn complete(&mut self, value: Poll<<CU<F> as Future>::Item, <CU<F> as Future>::Error>) {
        log!(FutureComplete);

        // So, this is subtle. We know that the type `F` may have some
        // data which is only valid until the end of the scope, and we
        // also know that the scope doesn't end until `self.counter`
        // is decremented below. So we want to be sure to drop
        // `self.future` first, lest its dtor try to access some of
        // that state or something!
        self.spawn.take().unwrap();

        self.unpark = None;
        self.result = value;
        let this = self.this.take().unwrap();
        if cfg!(debug_assertions) {
            let state = this.state.load(Relaxed);
            debug_assert!(state == STATE_EXECUTING || state == STATE_EXECUTING_UNPARKED,
                          "cannot complete when not executing (state = {})",
                          state);
        }
        this.state.store(STATE_COMPLETE, Release);

        if let Some(waiting_task) = self.waiting_task.take() {
            log!(FutureUnparkWaitingTask);
            waiting_task.unpark();
        }

        // Allow the enclosing scope to end. Asserts that
        // `self.counter` is still valid, which we know because caller
        // to `new_rayon_future()` ensures it for us.
        unsafe {
            (*self.counter).set();
        }
    }
}

struct PingUnpark<'l> {
    ping: Arc<Ping + 'l>,
}

impl<'l> PingUnpark<'l> {
    fn new(ping: Arc<Ping + 'l>) -> PingUnpark {
        PingUnpark { ping: ping }
    }
}

impl Unpark for PingUnpark<'static> {
    fn unpark(&self) {
        self.ping.ping()
    }
}

impl<F> LatchProbe for ScopeFuture<F>
    where F: Future + Send
{
    fn probe(&self) -> bool {
        self.state.load(Acquire) == STATE_COMPLETE
    }
}

pub trait ScopeFutureTrait<T, E>: Send + Sync + LatchProbe {
    fn poll(&self) -> Poll<T, E>;
    fn cancel(&self);
}

impl<F> ScopeFutureTrait<<CU<F> as Future>::Item, <CU<F> as Future>::Error> for ScopeFuture<F>
    where F: Future + Send
{
    fn poll(&self) -> Poll<<CU<F> as Future>::Item, <CU<F> as Future>::Error> {
        // Important: due to transmute hackery, not all the fields are
        // truly known to be valid at this point. In particular, the
        // type F is erased. But the `state` and `result` fields
        // should be valid.
        let mut contents = self.contents.lock().unwrap();
        let state = self.state.load(Relaxed);
        if state == STATE_COMPLETE {
            let r = mem::replace(&mut contents.result, Ok(Async::NotReady));
            return r;
        } else {
            assert!(contents.waiting_task.is_none());
            log!(FutureInstallWaitingTask { state: state });
            contents.waiting_task = Some(task::park());
            Ok(Async::NotReady)
        }
    }

    fn cancel(&self) {
        // Fast-path: check if this is already complete and return if
        // so. A relaxed load suffices since we are not going to
        // access any data as a result of this action.
        if self.state.load(Relaxed) == STATE_COMPLETE {
            return;
        }

        // Slow-path. Get the lock and everything.
        let mut contents = self.contents.lock().unwrap();
        loop {
            match self.state.load(Relaxed) {
                STATE_COMPLETE => {
                    return;
                }

                state => {
                    log!(FutureCancel { state: state });
                    if {
                        self.state
                            .compare_exchange_weak(state, STATE_COMPLETE, Release, Relaxed)
                            .is_ok()
                    } {
                        contents.complete(Ok(Async::NotReady));
                        return;
                    }
                }
            }
        }
    }
}

#[cfg(test)]
mod test;
<commit_msg>remove the `Ping` trait<commit_after>use latch::{CountLatch, Latch, LatchProbe};
#[allow(warnings)]
use log::Event::*;
use futures::{Async, Future, Poll};
use futures::executor;
use futures::future::CatchUnwind;
use futures::task::{self, Spawn, Task, Unpark};
use job::{Job, JobRef};
use registry::{Registry, WorkerThread};
use std::any::Any;
use std::panic::AssertUnwindSafe;
use std::mem;
use std::sync::Arc;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::*;
use std::sync::Mutex;
use unwind;

const STATE_PARKED: usize = 0;
const STATE_UNPARKED: usize = 1;
const STATE_EXECUTING: usize = 2;
const STATE_EXECUTING_UNPARKED: usize = 3;
const STATE_COMPLETE: usize = 4;

// Warning: Public end-user API.
pub struct RayonFuture<T, E> {
    inner: Arc<ScopeFutureTrait<Result<T, E>, Box<Any + Send + 'static>>>,
}

/// Create a `RayonFuture` that will execute `F` and yield its result,
/// propagating any panics.
///
/// Unsafe because caller asserts that all references in `F` will
/// remain valid at least until `counter` is decremented via `set()`.
/// In practice, this is ensured by the `scope()` API, which ensures
/// that `F: 'scope` and that `'scope` does not end until `counter`
/// reaches 0.
///
/// NB. This is a free fn so that we can expose `RayonFuture` as public API.
pub unsafe fn new_rayon_future<F>(future: F,
                                  counter: *const CountLatch)
                                  -> RayonFuture<F::Item, F::Error>
    where F: Future + Send
{
    let inner = ScopeFuture::spawn(future, counter);
    return RayonFuture { inner: hide_lifetime(inner) };

    unsafe fn hide_lifetime<'l, T, E>(x: Arc<ScopeFutureTrait<T, E> + 'l>)
                                      -> Arc<ScopeFutureTrait<T, E>> {
        mem::transmute(x)
    }
}

impl<T, E> RayonFuture<T, E> {
    pub fn rayon_wait(mut self) -> Result<T, E> {
        let worker_thread = WorkerThread::current();
        if worker_thread.is_null() {
            self.wait()
        } else {
            // Assert that uses of `worker_thread` pointer below are
            // valid (because we are on the worker-thread).
            unsafe {
                (*worker_thread).wait_until(&*self.inner);
                debug_assert!(self.inner.probe());
                self.poll().map(|a_v| match a_v {
                    Async::Ready(v) => v,
                    Async::NotReady => panic!("probe() returned true but poll not ready")
                })
            }
        }
    }
}

impl<T, E> Future for RayonFuture<T, E> {
    type Item = T;
    type Error = E;

    fn wait(self) -> Result<T, E> {
        if WorkerThread::current().is_null() {
            executor::spawn(self).wait_future()
        } else {
            panic!("using  `wait()` in a Rayon thread is unwise; try `rayon_wait()`")
        }
    }

    fn poll(&mut self) -> Poll<T, E> {
        match self.inner.poll() {
            Ok(Async::Ready(Ok(v))) => Ok(Async::Ready(v)),
            Ok(Async::Ready(Err(e))) => Err(e),
            Ok(Async::NotReady) => Ok(Async::NotReady),
            Err(e) => unwind::resume_unwinding(e),
        }
    }
}

impl<T, E> Drop for RayonFuture<T, E> {
    fn drop(&mut self) {
        self.inner.cancel();
    }
}

/// ////////////////////////////////////////////////////////////////////////

struct ScopeFuture<F: Future + Send> {
    state: AtomicUsize,
    registry: Arc<Registry>,
    contents: Mutex<ScopeFutureContents<F>>,
}

type CU<F> = CatchUnwind<AssertUnwindSafe<F>>;

struct ScopeFutureContents<F: Future + Send> {
    spawn: Option<Spawn<CU<F>>>,
    unpark: Option<Arc<Unpark>>,

    // Pointer to ourselves. We `None` this out when we are finished
    // executing, but it's convenient to keep around normally.
    this: Option<Arc<ScopeFuture<F>>>,

    // the counter in the scope; since the scope doesn't terminate until
    // counter reaches zero, and we hold a ref in this counter, we are
    // assured that this pointer remains valid
    counter: *const CountLatch,

    waiting_task: Option<Task>,
    result: Poll<<CU<F> as Future>::Item, <CU<F> as Future>::Error>,
}

// Assert that the `*const` is safe to transmit between threads:
unsafe impl<F: Future + Send> Send for ScopeFuture<F> {}
unsafe impl<F: Future + Send> Sync for ScopeFuture<F> {}

impl<F: Future + Send> ScopeFuture<F> {
    // Unsafe: Caller asserts that `future` and `counter` will remain
    // valid until we invoke `counter.set()`.
    unsafe fn spawn(future: F, counter: *const CountLatch) -> Arc<Self> {
        let worker_thread = WorkerThread::current();
        debug_assert!(!worker_thread.is_null());

        // Using `AssertUnwindSafe` is valid here because (a) the data
        // is `Send + Sync`, which is our usual boundary and (b)
        // panics will be propagated when the `RayonFuture` is polled.
        let spawn = task::spawn(AssertUnwindSafe(future).catch_unwind());

        let future: Arc<Self> = Arc::new(ScopeFuture::<F> {
            state: AtomicUsize::new(STATE_PARKED),
            registry: (*worker_thread).registry().clone(),
            contents: Mutex::new(ScopeFutureContents {
                spawn: None,
                unpark: None,
                this: None,
                counter: counter,
                waiting_task: None,
                result: Ok(Async::NotReady),
            }),
        });

        // Make the two self-cycles. Note that these imply the future
        // cannot be freed until these fields are set to `None` (which
        // occurs when it is finished executing).
        {
            let mut contents = future.contents.try_lock().unwrap();
            contents.spawn = Some(spawn);
            contents.unpark = Some(Self::make_unpark(&future));
            contents.this = Some(future.clone());
        }

        future.unpark();

        future
    }

    /// Creates a `JobRef` from this job -- note that this hides all
    /// lifetimes, so it is up to you to ensure that this JobRef
    /// doesn't outlive any data that it closes over.
    unsafe fn into_job_ref(this: Arc<Self>) -> JobRef {
        let this: *const Self = mem::transmute(this);
        JobRef::new(this)
    }

    fn make_unpark(this: &Arc<Self>) -> Arc<Unpark> {
        // Hide any lifetimes in `self`. This is safe because, until
        // `self` is dropped, the counter is not decremented, and so
        // the `'scope` lifetimes cannot end.
        //
        // Unfortunately, as `Unpark` currently requires `'static`, we
        // have to do an indirection and this ultimately requires a
        // fresh allocation.
        //
        // Here we assert that hiding the lifetimes in this fashion is
        // safe: we claim this is true because the lifetimes we are
        // hiding are part of `F`, and we now that any lifetimes in
        // `F` outlive `counter`. And we can see from `complete()`
        // that we drop all values of type `F` before decrementing
        // `counter`.
        unsafe {
            return hide_lifetime(this.clone());
        }

        unsafe fn hide_lifetime<'l>(x: Arc<Unpark + 'l>) -> Arc<Unpark> {
            mem::transmute(x)
        }
    }

    fn unpark_inherent(&self) {
        loop {
            match self.state.load(Relaxed) {
                STATE_PARKED => {
                    if {
                        self.state
                            .compare_exchange_weak(STATE_PARKED, STATE_UNPARKED, Release, Relaxed)
                            .is_ok()
                    } {
                        // Contention here is unlikely but possible: a
                        // previous execution might have moved us to the
                        // PARKED state but not yet released the lock.
                        let contents = self.contents.lock().unwrap();

                        // Assert that `job_ref` remains valid until
                        // it is executed.  That's true because
                        // `job_ref` holds a ref on the `Arc` and
                        // because, until `job_ref` completes, the
                        // references in the future are valid.
                        unsafe {
                            let job_ref = Self::into_job_ref(contents.this.clone().unwrap());
                            self.registry.inject(&[job_ref]);
                        }
                        return;
                    }
                }

                STATE_EXECUTING => {
                    if {
                        self.state
                            .compare_exchange_weak(STATE_EXECUTING,
                                                   STATE_EXECUTING_UNPARKED,
                                                   Release,
                                                   Relaxed)
                            .is_ok()
                    } {
                        return;
                    }
                }

                state => {
                    debug_assert!(state == STATE_UNPARKED || state == STATE_EXECUTING_UNPARKED ||
                                  state == STATE_COMPLETE);
                    return;
                }
            }
        }
    }

    fn begin_execute_state(&self) {
        // When we are put into the unparked state, we are enqueued in
        // a worker thread. We should then be executed exactly once,
        // at which point we transiition to STATE_EXECUTING. Nobody
        // should be contending with us to change the state here.
        let state = self.state.load(Acquire);
        debug_assert_eq!(state, STATE_UNPARKED);
        let result = self.state.compare_exchange(state, STATE_EXECUTING, Release, Relaxed);
        debug_assert_eq!(result, Ok(STATE_UNPARKED));
    }

    fn end_execute_state(&self) -> bool {
        loop {
            match self.state.load(Relaxed) {
                STATE_EXECUTING => {
                    if {
                        self.state
                            .compare_exchange_weak(STATE_EXECUTING, STATE_PARKED, Release, Relaxed)
                            .is_ok()
                    } {
                        // We put ourselves into parked state, no need to
                        // re-execute.  We'll just wait for the Unpark.
                        return true;
                    }
                }

                state => {
                    debug_assert_eq!(state, STATE_EXECUTING_UNPARKED);
                    if {
                        self.state
                            .compare_exchange_weak(state, STATE_EXECUTING, Release, Relaxed)
                            .is_ok()
                    } {
                        // We finished executing, but an unpark request
                        // came in the meantime.  We need to execute
                        // again. Return false as we failed to end the
                        // execution phase.
                        return false;
                    }
                }
            }
        }
    }
}

impl<F: Future + Send> Unpark for ScopeFuture<F> {
    fn unpark(&self) {
        self.unpark_inherent();
    }
}

impl<F: Future + Send> Job for ScopeFuture<F> {
    unsafe fn execute(this: *const Self) {
        let this: Arc<Self> = mem::transmute(this);

        // *generally speaking* there should be no contention for the
        // lock, but it is possible -- we can end execution, get re-enqeueud,
        // and re-executed, before we have time to return from this fn
        let mut contents = this.contents.lock().unwrap();

        log!(FutureExecute { state: this.state.load(Relaxed) });

        this.begin_execute_state();
        loop {
            match contents.poll() {
                Ok(Async::Ready(v)) => {
                    log!(FutureExecuteReady);
                    return contents.complete(Ok(Async::Ready(v)));
                }
                Ok(Async::NotReady) => {
                    log!(FutureExecuteNotReady);
                    if this.end_execute_state() {
                        return;
                    }
                }
                Err(err) => {
                    log!(FutureExecuteErr);
                    return contents.complete(Err(err));
                }
            }
        }
    }
}

impl<F: Future + Send> ScopeFutureContents<F> {
    fn poll(&mut self) -> Poll<<CU<F> as Future>::Item, <CU<F> as Future>::Error> {
        let unpark = self.unpark.clone().unwrap();
        self.spawn.as_mut().unwrap().poll_future(unpark)
    }

    fn complete(&mut self, value: Poll<<CU<F> as Future>::Item, <CU<F> as Future>::Error>) {
        log!(FutureComplete);

        // So, this is subtle. We know that the type `F` may have some
        // data which is only valid until the end of the scope, and we
        // also know that the scope doesn't end until `self.counter`
        // is decremented below. So we want to be sure to drop
        // `self.future` first, lest its dtor try to access some of
        // that state or something!
        self.spawn.take().unwrap();

        self.unpark = None;
        self.result = value;
        let this = self.this.take().unwrap();
        if cfg!(debug_assertions) {
            let state = this.state.load(Relaxed);
            debug_assert!(state == STATE_EXECUTING || state == STATE_EXECUTING_UNPARKED,
                          "cannot complete when not executing (state = {})",
                          state);
        }
        this.state.store(STATE_COMPLETE, Release);

        if let Some(waiting_task) = self.waiting_task.take() {
            log!(FutureUnparkWaitingTask);
            waiting_task.unpark();
        }

        // Allow the enclosing scope to end. Asserts that
        // `self.counter` is still valid, which we know because caller
        // to `new_rayon_future()` ensures it for us.
        unsafe {
            (*self.counter).set();
        }
    }
}

impl<F> LatchProbe for ScopeFuture<F>
    where F: Future + Send
{
    fn probe(&self) -> bool {
        self.state.load(Acquire) == STATE_COMPLETE
    }
}

pub trait ScopeFutureTrait<T, E>: Send + Sync + LatchProbe {
    fn poll(&self) -> Poll<T, E>;
    fn cancel(&self);
}

impl<F> ScopeFutureTrait<<CU<F> as Future>::Item, <CU<F> as Future>::Error> for ScopeFuture<F>
    where F: Future + Send
{
    fn poll(&self) -> Poll<<CU<F> as Future>::Item, <CU<F> as Future>::Error> {
        // Important: due to transmute hackery, not all the fields are
        // truly known to be valid at this point. In particular, the
        // type F is erased. But the `state` and `result` fields
        // should be valid.
        let mut contents = self.contents.lock().unwrap();
        let state = self.state.load(Relaxed);
        if state == STATE_COMPLETE {
            let r = mem::replace(&mut contents.result, Ok(Async::NotReady));
            return r;
        } else {
            assert!(contents.waiting_task.is_none());
            log!(FutureInstallWaitingTask { state: state });
            contents.waiting_task = Some(task::park());
            Ok(Async::NotReady)
        }
    }

    fn cancel(&self) {
        // Fast-path: check if this is already complete and return if
        // so. A relaxed load suffices since we are not going to
        // access any data as a result of this action.
        if self.state.load(Relaxed) == STATE_COMPLETE {
            return;
        }

        // Slow-path. Get the lock and everything.
        let mut contents = self.contents.lock().unwrap();
        loop {
            match self.state.load(Relaxed) {
                STATE_COMPLETE => {
                    return;
                }

                state => {
                    log!(FutureCancel { state: state });
                    if {
                        self.state
                            .compare_exchange_weak(state, STATE_COMPLETE, Release, Relaxed)
                            .is_ok()
                    } {
                        contents.complete(Ok(Async::NotReady));
                        return;
                    }
                }
            }
        }
    }
}

#[cfg(test)]
mod test;
<|endoftext|>


<commit_before>// Helianto -- static website generator
// Copyright © 2015-2016 Mickaël RAYBAUD-ROIG
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use std::path::Path;
use std::fs::File;
use regex::Regex;
use std::io::Read;
use std::ascii::AsciiExt;
use pulldown_cmark::{Parser, Event, Tag};
use pulldown_cmark::{OPTION_ENABLE_TABLES, OPTION_ENABLE_FOOTNOTES};
use pulldown_cmark::html;
use super::{Metadata, Reader};
use super::super::{Error, Result, Settings};

#[derive(Debug, Clone)]
pub struct MarkdownReader;

static EXTENSIONS: &'static [&'static str] = &["markdown", "md", "mkd", "mdown"];

impl Reader for MarkdownReader {
    fn new(_settings: &Settings) -> MarkdownReader {
        MarkdownReader
    }

    fn extensions() -> &'static [&'static str] {
        EXTENSIONS
    }

    fn load(&self, path: &Path) -> Result<(String, Metadata)> {
        let mut input = String::new();
        try! {
            File::open(path)
                .and_then(|mut fd| fd.read_to_string(&mut input))
                .map_err(|err| Error::Reader {
                    path: path.into(),
                    cause: Box::new(err),
                }
            )
        };

        Ok(process_markdown(&input))
    }
}

#[derive(PartialEq, Eq, Debug)]
enum State {
    BeforeTitle,
    InsideTitle,
    BeforeMetadata,
    InsideMetadata,
    InsideBody,
}

struct MetadataExtractor<'a> {
    inner: Parser<'a>,
    regex: Regex,
    state: State,
    pub metadata: Metadata,
    buffer: Vec<Event<'a>>,
}

impl<'a> From<Parser<'a>> for MetadataExtractor<'a> {
    fn from(parser: Parser) -> MetadataExtractor {
        MetadataExtractor {
            inner: parser,
            regex: Regex::new(r"^[\w][\w\d_\x2D ]*\s*:").unwrap(),
            state: State::BeforeTitle,
            metadata: Metadata::new(),
            buffer: Vec::new(),
        }
    }
}

impl<'a> Iterator for MetadataExtractor<'a> {
    type Item = Event<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        use self::State::*;

        if self.state == State::InsideBody {
            if self.buffer.len() > 0 {
                return Some(self.buffer.remove(0));
            } else {
                return self.inner.next();
            }
        }

        let event = match self.inner.next() {
            Some(ev) => ev,
            None => return None,
        };

        println!("{:?} {:?}", self.state, event);
        match self.state {
            BeforeTitle => {
                match event {
                    Event::Start(Tag::Header(_)) => {
                        self.state = State::InsideTitle;
                        self.next()
                    },
                    Event::Start(Tag::Paragraph) => {
                        self.state = State::InsideMetadata;
                        self.buffer.push(event);
                        self.next()
                    },
                    _ => {
                        self.state = State::InsideBody;
                        Some(event)
                    }
                }
            },
            InsideTitle => {
                match event {
                    Event::Text(_) => {
                        self.metadata.insert("title".into(), get_event_text(&event));
                        self.next()
                    },
                    Event::End(Tag::Header(_)) => {
                        self.state = State::BeforeMetadata;
                        self.next()
                    },
                    _ => self.next(),
                }
            },
            BeforeMetadata => {
                match event {
                    Event::Start(Tag::Paragraph) => {
                        self.state = State::InsideMetadata;
                        self.buffer.push(event);
                        self.next()
                    },
                    _ => {
                        self.state = State::InsideBody;
                        Some(event)
                    }
                }
            },
            InsideMetadata => {
                match event {
                    Event::Text(_) => {
                        if ! self.regex.is_match(&get_event_text(&event)) {
                            self.state = State::InsideBody;
                            println!("metadata end: {}", get_event_text(&event));
                        }
                        self.buffer.push(event);
                        self.next()
                    },
                    Event::End(Tag::Paragraph) => {
                        self.metadata.extend(
                            self.buffer.drain(..).filter_map(|event| {
                                if let Event::Text(text) = event {
                                    let (key, value) = split_pair(&text);
                                    Some((key.to_ascii_lowercase(), value))
                                } else {
                                    None
                                }
                            })
                        );
                        self.state = State::InsideBody;
                        self.next()
                    },
                    Event::SoftBreak | Event::HardBreak => {
                        self.buffer.push(event);
                        self.next()
                    },
                    _ => {
                        self.buffer.push(event);
                        self.state = State::InsideBody;
                        self.next()
                    }
                }
            },
            InsideBody => unreachable!(),
        }
    }
}

fn split_pair<S: AsRef<str>>(input: &S) -> (String, String) {
    let mut split = input.as_ref().splitn(2, ':');
    let key: &str = split.next().unwrap_or("");
    let value: &str = split.next().unwrap_or("");
    (key.trim().into(), value.trim().into())
}

fn get_event_text<'a>(event: &Event<'a>) -> String {
    if let Event::Text(ref text) = *event {
        text.clone().into_owned()
    } else {
        panic!()
    }
}

fn process_markdown<S: AsRef<str>>(input: &S) -> (String, Metadata) {
    let mut parser = MetadataExtractor::from(
        Parser::new_ext(input.as_ref(), OPTION_ENABLE_TABLES | OPTION_ENABLE_FOOTNOTES)
    );
    let mut output = String::with_capacity(input.as_ref().len() * (3/2));
    html::push_html(&mut output, &mut parser);
    (output, parser.metadata.clone())
}

#[test]
fn extract_title() {
    let (output, metadata) = process_markdown(&"# Foo\nbar\nbaz");
    assert_eq!(metadata.get("title"), Some(&"Foo".into()));
    assert_eq!(output, "
bar\nbaz
\n");
}

#[test]
fn extract_metadata() {
    let (output, metadata) = process_markdown(&"# Foo\n\nBar: baz:quux\nFoo bar: qux baz\n\nfoo: bar");
    assert_eq!(metadata.get("title"), Some(&"Foo".into()));
    assert_eq!(metadata.get("bar"), Some(&"baz:quux".into()));
    assert_eq!(metadata.get("foo bar"), Some(&"qux baz".into()));
    assert_eq!(output, "
foo: bar
\n");
}

#[test]
fn can_skip_to_metadata() {
    let (output, metadata) = process_markdown(&"\n\n\nBar: baz:quux\nFoo bar: qux baz\n\nfoo: bar");
    assert_eq!(metadata.get("title"), None);
    assert_eq!(metadata.get("bar"), Some(&"baz:quux".into()));
    assert_eq!(metadata.get("foo bar"), Some(&"qux baz".into()));
    assert_eq!(output, "
foo: bar
\n");
}

#[test]
fn can_skip_to_body() {
    let (output, metadata) = process_markdown(&"\n\n\nBar: baz:quux\nFoo bar: qux baz  \nlol\n\nfoo: bar");
    assert_eq!(metadata.get("title"), None);
    assert_eq!(metadata.get("bar"), None);
    assert_eq!(metadata.get("foo bar"), None);
    assert_eq!(output, "
Bar: baz:quux\nFoo bar: qux baz
\nlol
\n
foo: bar
\n");
}

#[test]
fn can_skip_metadata() {
    let (output, metadata) = process_markdown(&"# Title\n\n\nBar: baz:quux\nFoo bar: qux baz  \nlol\n\nfoo: bar");
    assert_eq!(metadata.get("title"), Some(&String::from("Title")));
    assert_eq!(metadata.get("bar"), None);
    assert_eq!(metadata.get("foo bar"), None);
    assert_eq!(output, "
Bar: baz:quux\nFoo bar: qux baz
\nlol
\n
foo: bar
\n");
}<commit_msg>Builds on Rust 1.5<commit_after>// Helianto -- static website generator
// Copyright © 2015-2016 Mickaël RAYBAUD-ROIG
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use std::path::Path;
use std::fs::File;
use regex::Regex;
use std::io::Read;
use std::ascii::AsciiExt;
use std::mem::replace;
use pulldown_cmark::{Parser, Event, Tag};
use pulldown_cmark::{OPTION_ENABLE_TABLES, OPTION_ENABLE_FOOTNOTES};
use pulldown_cmark::html;
use super::{Metadata, Reader};
use super::super::{Error, Result, Settings};

#[derive(Debug, Clone)]
pub struct MarkdownReader;

static EXTENSIONS: &'static [&'static str] = &["markdown", "md", "mkd", "mdown"];

impl Reader for MarkdownReader {
    fn new(_settings: &Settings) -> MarkdownReader {
        MarkdownReader
    }

    fn extensions() -> &'static [&'static str] {
        EXTENSIONS
    }

    fn load(&self, path: &Path) -> Result<(String, Metadata)> {
        let mut input = String::new();
        try! {
            File::open(path)
                .and_then(|mut fd| fd.read_to_string(&mut input))
                .map_err(|err| Error::Reader {
                    path: path.into(),
                    cause: Box::new(err),
                }
            )
        };

        Ok(process_markdown(&input))
    }
}

#[derive(PartialEq, Eq, Debug)]
enum State {
    BeforeTitle,
    InsideTitle,
    BeforeMetadata,
    InsideMetadata,
    InsideBody,
}

struct MetadataExtractor<'a> {
    inner: Parser<'a>,
    regex: Regex,
    state: State,
    pub metadata: Metadata,
    buffer: Vec<Event<'a>>,
}

impl<'a> From<Parser<'a>> for MetadataExtractor<'a> {
    fn from(parser: Parser) -> MetadataExtractor {
        MetadataExtractor {
            inner: parser,
            regex: Regex::new(r"^[\w][\w\d_\x2D ]*\s*:").unwrap(),
            state: State::BeforeTitle,
            metadata: Metadata::new(),
            buffer: Vec::new(),
        }
    }
}

impl<'a> Iterator for MetadataExtractor<'a> {
    type Item = Event<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        use self::State::*;

        if self.state == State::InsideBody {
            if self.buffer.len() > 0 {
                return Some(self.buffer.remove(0));
            } else {
                return self.inner.next();
            }
        }

        let event = match self.inner.next() {
            Some(ev) => ev,
            None => return None,
        };

        println!("{:?} {:?}", self.state, event);
        match self.state {
            BeforeTitle => {
                match event {
                    Event::Start(Tag::Header(_)) => {
                        self.state = State::InsideTitle;
                        self.next()
                    },
                    Event::Start(Tag::Paragraph) => {
                        self.state = State::InsideMetadata;
                        self.buffer.push(event);
                        self.next()
                    },
                    _ => {
                        self.state = State::InsideBody;
                        Some(event)
                    }
                }
            },
            InsideTitle => {
                match event {
                    Event::Text(_) => {
                        self.metadata.insert("title".into(), get_event_text(&event));
                        self.next()
                    },
                    Event::End(Tag::Header(_)) => {
                        self.state = State::BeforeMetadata;
                        self.next()
                    },
                    _ => self.next(),
                }
            },
            BeforeMetadata => {
                match event {
                    Event::Start(Tag::Paragraph) => {
                        self.state = State::InsideMetadata;
                        self.buffer.push(event);
                        self.next()
                    },
                    _ => {
                        self.state = State::InsideBody;
                        Some(event)
                    }
                }
            },
            InsideMetadata => {
                match event {
                    Event::Text(_) => {
                        if ! self.regex.is_match(&get_event_text(&event)) {
                            self.state = State::InsideBody;
                            println!("metadata end: {}", get_event_text(&event));
                        }
                        self.buffer.push(event);
                        self.next()
                    },
                    Event::End(Tag::Paragraph) => {
                        self.metadata.extend(
                            replace(&mut self.buffer, Vec::new()).into_iter().filter_map(|event| {
                                if let Event::Text(text) = event {
                                    let (key, value) = split_pair(&text);
                                    Some((key.to_ascii_lowercase(), value))
                                } else {
                                    None
                                }
                            })
                        );
                        self.state = State::InsideBody;
                        self.next()
                    },
                    Event::SoftBreak | Event::HardBreak => {
                        self.buffer.push(event);
                        self.next()
                    },
                    _ => {
                        self.buffer.push(event);
                        self.state = State::InsideBody;
                        self.next()
                    }
                }
            },
            InsideBody => unreachable!(),
        }
    }
}

fn split_pair<S: AsRef<str>>(input: &S) -> (String, String) {
    let mut split = input.as_ref().splitn(2, ':');
    let key: &str = split.next().unwrap_or("");
    let value: &str = split.next().unwrap_or("");
    (key.trim().into(), value.trim().into())
}

fn get_event_text<'a>(event: &Event<'a>) -> String {
    if let Event::Text(ref text) = *event {
        text.clone().into_owned()
    } else {
        panic!()
    }
}

fn process_markdown<S: AsRef<str>>(input: &S) -> (String, Metadata) {
    let mut parser = MetadataExtractor::from(
        Parser::new_ext(input.as_ref(), OPTION_ENABLE_TABLES | OPTION_ENABLE_FOOTNOTES)
    );
    let mut output = String::with_capacity(input.as_ref().len() * (3/2));
    html::push_html(&mut output, &mut parser);
    (output, parser.metadata.clone())
}

#[test]
fn extract_title() {
    let (output, metadata) = process_markdown(&"# Foo\nbar\nbaz");
    assert_eq!(metadata.get("title"), Some(&"Foo".into()));
    assert_eq!(output, "
bar\nbaz
\n");
}

#[test]
fn extract_metadata() {
    let (output, metadata) = process_markdown(&"# Foo\n\nBar: baz:quux\nFoo bar: qux baz\n\nfoo: bar");
    assert_eq!(metadata.get("title"), Some(&"Foo".into()));
    assert_eq!(metadata.get("bar"), Some(&"baz:quux".into()));
    assert_eq!(metadata.get("foo bar"), Some(&"qux baz".into()));
    assert_eq!(output, "
foo: bar
\n");
}

#[test]
fn can_skip_to_metadata() {
    let (output, metadata) = process_markdown(&"\n\n\nBar: baz:quux\nFoo bar: qux baz\n\nfoo: bar");
    assert_eq!(metadata.get("title"), None);
    assert_eq!(metadata.get("bar"), Some(&"baz:quux".into()));
    assert_eq!(metadata.get("foo bar"), Some(&"qux baz".into()));
    assert_eq!(output, "
foo: bar
\n");
}

#[test]
fn can_skip_to_body() {
    let (output, metadata) = process_markdown(&"\n\n\nBar: baz:quux\nFoo bar: qux baz  \nlol\n\nfoo: bar");
    assert_eq!(metadata.get("title"), None);
    assert_eq!(metadata.get("bar"), None);
    assert_eq!(metadata.get("foo bar"), None);
    assert_eq!(output, "
Bar: baz:quux\nFoo bar: qux baz
\nlol
\n
foo: bar
\n");
}

#[test]
fn can_skip_metadata() {
    let (output, metadata) = process_markdown(&"# Title\n\n\nBar: baz:quux\nFoo bar: qux baz  \nlol\n\nfoo: bar");
    assert_eq!(metadata.get("title"), Some(&String::from("Title")));
    assert_eq!(metadata.get("bar"), None);
    assert_eq!(metadata.get("foo bar"), None);
    assert_eq!(output, "
Bar: baz:quux\nFoo bar: qux baz
\nlol
\n
foo: bar
\n");
}
<|endoftext|>


<commit_before>use crate::config::Config;
use crate::errors::RunError;
use crate::traces::{CoverageStat, TraceMap};
use coveralls_api::*;
use log::{info, warn, trace};
use std::collections::HashMap;
use std::path::Path;
use std::fs;

fn get_git_info(manifest_path: &Path) -> Result<GitInfo, String> {
    let dir_path = manifest_path
        .parent()
        .ok_or_else(|| format!("failed to get parent for path: {}", manifest_path.display()))?;
    let repo = git2::Repository::discover(dir_path).map_err(|err| {
        format!(
            "failed to open git repository: {}: {}",
            dir_path.display(),
            err
        )
    })?;

    let head = repo
        .head()
        .map_err(|err| format!("failed to get repository head: {}", err))?;
    let branch = git2::Branch::wrap(head);
    let branch_name = branch
        .name()
        .map_err(|err| format!("failed to get branch name: {}", err))?;
    let get_string = |data: Option<&str>| match data {
        Some(str) => Ok(str.to_string()),
        None => Err("string is not valid utf-8".to_string()),
    };
    let branch_name = get_string(branch_name)?;
    let commit = repo
        .head()
        .unwrap()
        .peel_to_commit()
        .map_err(|err| format!("failed to get commit: {}", err))?;

    let author = commit.author();
    let committer = commit.committer();
    Ok(GitInfo {
        head: Head {
            id: commit.id().to_string(),
            author_name: get_string(author.name())?,
            author_email: get_string(author.email())?,
            committer_name: get_string(committer.name())?,
            committer_email: get_string(committer.email())?,
            message: get_string(commit.message())?,
        },
        branch: branch_name,
        remotes: Vec::new(),
    })
}

fn get_identity(ci_tool: &Option<CiService>, key: &str) -> Identity {
    match ci_tool {
        Some(CiService::Travis) => {
            let service = Service {
                name: CiService::Travis,
                job_id: Some(key.to_string()),
                number: None,
                build_url: None,
                branch: None,
                pull_request: None,
            };
            Identity::ServiceToken(String::new(), service)
        },
        Some(ref service) => {
            let service = match Service::from_ci(service.clone()) {
                Some(s) => s,
                None => Service {
                    name: service.clone(),
                    job_id: Some(key.to_string()),
                    number: None,
                    build_url: None,
                    branch: None,
                    pull_request: None,
                }
            };
            Identity::ServiceToken(key.to_string(), service)
        },
        _ => Identity::best_match_with_token(key.to_string()),
    }
}

pub fn export(coverage_data: &TraceMap, config: &Config) -> Result<(), RunError> {
    if let Some(ref key) = config.coveralls {
        let id = get_identity(&config.ci_tool, key);

        let mut report = CoverallsReport::new(id);
        for file in &coverage_data.files() {
            let rel_path = config.strip_project_path(file);
            let mut lines: HashMap<usize, usize> = HashMap::new();
            let fcov = coverage_data.get_child_traces(file);

            for c in &fcov {
                match c.stats {
                    CoverageStat::Line(hits) => {
                        lines.insert(c.line as usize, hits as usize);
                    }
                    _ => {
                        info!("Support for coverage statistic not implemented or supported for coveralls.io");
                    }
                }
            }
            if let Ok(source) = Source::new(&rel_path, file, &lines, &None, false) {
                report.add_source(source);
            }
        }

        match get_git_info(&config.manifest) {
            Ok(git_info) => {
                report.set_detailed_git_info(git_info);
                info!("Git info collected");
            }
            Err(err) => warn!("Failed to collect git info: {}", err),
        }

        let res = match config.report_uri {
            Some(ref uri) => {
                info!("Sending report to endpoint: {}", uri);
                report.send_to_endpoint(uri)
            }
            None => {
                info!("Sending coverage data to coveralls.io");
                report.send_to_coveralls()
            }
        };
        if config.debug {
            if let Ok(text) = serde_json::to_string(&report) {
                info!("Attempting to write coveralls report to coveralls.json");
                let _ = fs::write("coveralls.json", text);
            } else {
                warn!("Failed to serialise coverage report");
            }
        }
        match res {
            Ok(s) => {
                trace!("Coveralls response {:?}", s);
                Ok(())
            },
            Err(e) => Err(RunError::CovReport(format!("Coveralls send failed. {}", e))),
        }
    } else {
        Err(RunError::CovReport(
            "No coveralls key specified.".to_string(),
        ))
    }
}
<commit_msg>Shitty printout<commit_after>use crate::config::Config;
use crate::errors::RunError;
use crate::traces::{CoverageStat, TraceMap};
use coveralls_api::*;
use log::{info, warn, trace};
use std::collections::HashMap;
use std::path::Path;
use std::fs;

fn get_git_info(manifest_path: &Path) -> Result<GitInfo, String> {
    let dir_path = manifest_path
        .parent()
        .ok_or_else(|| format!("failed to get parent for path: {}", manifest_path.display()))?;
    let repo = git2::Repository::discover(dir_path).map_err(|err| {
        format!(
            "failed to open git repository: {}: {}",
            dir_path.display(),
            err
        )
    })?;

    let head = repo
        .head()
        .map_err(|err| format!("failed to get repository head: {}", err))?;
    let branch = git2::Branch::wrap(head);
    let branch_name = branch
        .name()
        .map_err(|err| format!("failed to get branch name: {}", err))?;
    let get_string = |data: Option<&str>| match data {
        Some(str) => Ok(str.to_string()),
        None => Err("string is not valid utf-8".to_string()),
    };
    let branch_name = get_string(branch_name)?;
    let commit = repo
        .head()
        .unwrap()
        .peel_to_commit()
        .map_err(|err| format!("failed to get commit: {}", err))?;

    let author = commit.author();
    let committer = commit.committer();
    Ok(GitInfo {
        head: Head {
            id: commit.id().to_string(),
            author_name: get_string(author.name())?,
            author_email: get_string(author.email())?,
            committer_name: get_string(committer.name())?,
            committer_email: get_string(committer.email())?,
            message: get_string(commit.message())?,
        },
        branch: branch_name,
        remotes: Vec::new(),
    })
}

fn get_identity(ci_tool: &Option<CiService>, key: &str) -> Identity {
    match ci_tool {
        Some(CiService::Travis) => {
            let service = Service {
                name: CiService::Travis,
                job_id: Some(key.to_string()),
                number: None,
                build_url: None,
                branch: None,
                pull_request: None,
            };
            Identity::ServiceToken(String::new(), service)
        },
        Some(ref service) => {
            let service = match Service::from_ci(service.clone()) {
                Some(s) => s,
                None => Service {
                    name: service.clone(),
                    job_id: Some(key.to_string()),
                    number: None,
                    build_url: None,
                    branch: None,
                    pull_request: None,
                }
            };
            Identity::ServiceToken(key.to_string(), service)
        },
        _ => Identity::best_match_with_token(key.to_string()),
    }
}

pub fn export(coverage_data: &TraceMap, config: &Config) -> Result<(), RunError> {
    if let Some(ref key) = config.coveralls {
        let id = get_identity(&config.ci_tool, key);

        let mut report = CoverallsReport::new(id);
        for file in &coverage_data.files() {
            let rel_path = config.strip_project_path(file);
            let mut lines: HashMap<usize, usize> = HashMap::new();
            let fcov = coverage_data.get_child_traces(file);

            for c in &fcov {
                match c.stats {
                    CoverageStat::Line(hits) => {
                        lines.insert(c.line as usize, hits as usize);
                    }
                    _ => {
                        info!("Support for coverage statistic not implemented or supported for coveralls.io");
                    }
                }
            }
            if let Ok(source) = Source::new(&rel_path, file, &lines, &None, false) {
                report.add_source(source);
            }
        }

        match get_git_info(&config.manifest) {
            Ok(git_info) => {
                report.set_detailed_git_info(git_info);
                info!("Git info collected");
            }
            Err(err) => warn!("Failed to collect git info: {}", err),
        }

        let res = match config.report_uri {
            Some(ref uri) => {
                info!("Sending report to endpoint: {}", uri);
                report.send_to_endpoint(uri)
            }
            None => {
                info!("Sending coverage data to coveralls.io");
                report.send_to_coveralls()
            }
        };
        if config.debug {
            if let Ok(text) = serde_json::to_string(&report) {
                info!("Attempting to write coveralls report to coveralls.json");
                println!("{}", text);
                let _ = fs::write("coveralls.json", text);
            } else {
                warn!("Failed to serialise coverage report");
            }
        }
        match res {
            Ok(s) => {
                trace!("Coveralls response {:?}", s);
                Ok(())
            },
            Err(e) => Err(RunError::CovReport(format!("Coveralls send failed. {}", e))),
        }
    } else {
        Err(RunError::CovReport(
            "No coveralls key specified.".to_string(),
        ))
    }
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate xml;

use std::io::Read;

pub struct Client<'t> {
    http_client: hyper::Client,
    server_uri: &'t str,
}

impl<'t> Client<'t> {
    pub fn new(server_uri: &'t str) -> Client<'t> {
        Client {
            http_client: hyper::Client::new(),
            server_uri: server_uri,
        }
    }

    pub fn request(&self, function_name: &str, parameters: &Vec<&str>) -> Member {
        let mut body = Vec::<u8>::new();
        {
            let mut writer = xml::EventWriter::new(&mut body);
            writer.write(xml::writer::XmlEvent::start_element("methodCall")).unwrap();
            writer.write(xml::writer::XmlEvent::start_element("methodName")).unwrap();
            writer.write(xml::writer::XmlEvent::characters(function_name)).unwrap();
            writer.write(xml::writer::XmlEvent::end_element()).unwrap();
            writer.write(xml::writer::XmlEvent::start_element("params")).unwrap();
            for param in parameters {
                writer.write(xml::writer::XmlEvent::start_element("value")).unwrap();
                writer.write(xml::writer::XmlEvent::start_element("string")).unwrap();
                writer.write(xml::writer::XmlEvent::characters(param)).unwrap();
                writer.write(xml::writer::XmlEvent::end_element()).unwrap();
                writer.write(xml::writer::XmlEvent::end_element()).unwrap();
            }
            writer.write(xml::writer::XmlEvent::end_element()).unwrap();
            writer.write(xml::writer::XmlEvent::end_element()).unwrap();
        }

        let res = self.http_client
            .post(self.server_uri)
            .body(String::from_utf8(body).unwrap().as_str())
            .send()
            .unwrap();

        let xml_tree = read_xml_tree(&mut xml::EventReader::new(res)).unwrap();
        parse_xml_tree(&xml_tree).unwrap()
    }
}

fn read_xml_tree<T: Read>(mut parser: &mut xml::EventReader<T>) -> Option<XmlTreeNode> {
    match parser.next() {
        Ok(xml::reader::XmlEvent::StartElement { name, .. }) => {
            let mut children = Vec::<XmlTreeNode>::new();
            while let Some(tree) = read_xml_tree(&mut parser) {
                children.push(tree);
            }
            Some(XmlTreeNode::Node(name.local_name, children))
        }
        Ok(xml::reader::XmlEvent::Characters(value)) => Some(XmlTreeNode::Leaf(value)),
        Ok(xml::reader::XmlEvent::EndElement { .. }) => None,
        Err(..) => None,
        _ => read_xml_tree(&mut parser),
    }
}

fn parse_xml_tree(tree: &XmlTreeNode) -> Option<Member> {
    if let Some(tree) = unwrap_xml_layer(&tree, "methodResponse".to_string()) {
        if let Some(tree) = unwrap_xml_layer(&tree, "params".to_string()) {
            if let Some(tree) = unwrap_xml_layer(&tree, "param".to_string()) {
                return parse_xml_tree_helper(&tree);
            }
        }
    }
    None
}

fn parse_xml_tree_helper(tree: &XmlTreeNode) -> Option<Member> {
    if let Some(tree) = unwrap_xml_layer(&tree, "value".to_string()) {
        if let XmlTreeNode::Node(ref name, ref children) = *tree {
            if children.len() == 1 {
                let child = &children[0];
                return match name.as_str() {
                    "array" => parse_xml_array(child),
                    "string" => parse_xml_string(child),
                    "int" | "i4" => parse_xml_int(child),
                    _ => None,
                };
            }
        }
    }
    None
}

fn parse_xml_array(tree: &XmlTreeNode) -> Option<Member> {
    if let XmlTreeNode::Node(ref name, ref children) = *tree {
        if name.eq(&"data".to_string()) {
            return Some(Member::Array(children.iter().filter_map(parse_xml_tree_helper).collect()));
        }
    }
    None
}

fn parse_xml_int(tree: &XmlTreeNode) -> Option<Member> {
    if let Some(Member::String(text)) = parse_xml_string(&tree) {
        if let Ok(value) = text.parse::<i32>() {
            return Some(Member::Int(value));
        }
    }
    None
}

fn parse_xml_string(tree: &XmlTreeNode) -> Option<Member> {
    if let XmlTreeNode::Leaf(ref value) = *tree {
        return Some(Member::String(value.clone()));
    }
    None
}

fn unwrap_xml_layer(tree: &XmlTreeNode, node_name: String) -> Option<&XmlTreeNode> {
    if let XmlTreeNode::Node(ref name, ref children) = *tree {
        if name.eq(&node_name) && children.len() == 1 {
            return Some(&children[0]);
        }
    }
    None
}

enum XmlTreeNode {
    Leaf(String),
    Node(String, Vec<XmlTreeNode>),
}

pub enum Member {
    Array(Vec<Member>),
    String(String),
    Int(i32),
}
<commit_msg>Make data passing more idiomatic<commit_after>extern crate hyper;
extern crate xml;

use std::io::Read;

pub struct Client {
    http_client: hyper::Client,
    server_uri: String,
}

impl Client {
    pub fn new(server_uri: &str) -> Client {
        Client {
            http_client: hyper::Client::new(),
            server_uri: server_uri.to_string(),
        }
    }

    pub fn request(&self, function_name: &str, parameters: &[&str]) -> Member {
        let mut body = Vec::<u8>::new();
        {
            let mut writer = xml::EventWriter::new(&mut body);
            writer.write(xml::writer::XmlEvent::start_element("methodCall")).unwrap();
            writer.write(xml::writer::XmlEvent::start_element("methodName")).unwrap();
            writer.write(xml::writer::XmlEvent::characters(function_name)).unwrap();
            writer.write(xml::writer::XmlEvent::end_element()).unwrap();
            writer.write(xml::writer::XmlEvent::start_element("params")).unwrap();
            for param in parameters {
                writer.write(xml::writer::XmlEvent::start_element("value")).unwrap();
                writer.write(xml::writer::XmlEvent::start_element("string")).unwrap();
                writer.write(xml::writer::XmlEvent::characters(param)).unwrap();
                writer.write(xml::writer::XmlEvent::end_element()).unwrap();
                writer.write(xml::writer::XmlEvent::end_element()).unwrap();
            }
            writer.write(xml::writer::XmlEvent::end_element()).unwrap();
            writer.write(xml::writer::XmlEvent::end_element()).unwrap();
        }

        let res = self.http_client
            .post(&self.server_uri)
            .body(&String::from_utf8(body).unwrap())
            .send()
            .unwrap();

        let xml_tree = read_xml_tree(&mut xml::EventReader::new(res)).unwrap();
        parse_xml_tree(&xml_tree).unwrap()
    }
}

fn read_xml_tree<T: Read>(mut parser: &mut xml::EventReader<T>) -> Option<XmlTreeNode> {
    match parser.next() {
        Ok(xml::reader::XmlEvent::StartElement { name, .. }) => {
            let mut children = Vec::<XmlTreeNode>::new();
            while let Some(tree) = read_xml_tree(&mut parser) {
                children.push(tree);
            }
            Some(XmlTreeNode::Node(name.local_name, children))
        }
        Ok(xml::reader::XmlEvent::Characters(value)) => Some(XmlTreeNode::Leaf(value)),
        Ok(xml::reader::XmlEvent::EndElement { .. }) => None,
        Err(..) => None,
        _ => read_xml_tree(&mut parser),
    }
}

fn parse_xml_tree(tree: &XmlTreeNode) -> Option<Member> {
    if let Some(tree) = peel_xml_layer(&tree, "methodResponse") {
        if let Some(tree) = peel_xml_layer(&tree, "params") {
            if let Some(tree) = peel_xml_layer(&tree, "param") {
                return parse_xml_tree_helper(&tree);
            }
        }
    }
    None
}

fn parse_xml_tree_helper(tree: &XmlTreeNode) -> Option<Member> {
    if let Some(tree) = peel_xml_layer(&tree, "value") {
        if let XmlTreeNode::Node(ref name, ref children) = *tree {
            if children.len() == 1 {
                let child = &children[0];
                return match name.as_str() {
                    "array" => parse_xml_array(child),
                    "string" => parse_xml_string(child),
                    "int" | "i4" => parse_xml_int(child),
                    _ => None,
                };
            }
        }
    }
    None
}

fn parse_xml_array(tree: &XmlTreeNode) -> Option<Member> {
    if let XmlTreeNode::Node(ref name, ref children) = *tree {
        if name.as_str() == "data" {
            return Some(Member::Array(children.iter().filter_map(parse_xml_tree_helper).collect()));
        }
    }
    None
}

fn parse_xml_int(tree: &XmlTreeNode) -> Option<Member> {
    if let Some(Member::String(text)) = parse_xml_string(&tree) {
        if let Ok(value) = text.parse::<i32>() {
            return Some(Member::Int(value));
        }
    }
    None
}

fn parse_xml_string(tree: &XmlTreeNode) -> Option<Member> {
    if let XmlTreeNode::Leaf(ref value) = *tree {
        return Some(Member::String(value.clone()));
    }
    None
}

fn peel_xml_layer<'a>(tree: &'a XmlTreeNode, node_name: &str) -> Option<&'a XmlTreeNode> {
    if let XmlTreeNode::Node(ref name, ref children) = *tree {
        if name.as_str() == node_name && children.len() == 1 {
            return Some(&children[0]);
        }
    }
    None
}

enum XmlTreeNode {
    Leaf(String),
    Node(String, Vec<XmlTreeNode>),
}

pub enum Member {
    Array(Vec<Member>),
    String(String),
    Int(i32),
}
<|endoftext|>


<commit_before>//! Logistic Regression module
//!
//! Contains implemention of logistic regression using
//! gradient descent optimization.
//!
//! The regressor will automatically add the intercept term
//! so you do not need to format the input matrices yourself.
//!
//! # Usage
//!
//! ```
//! use rusty_machine::learning::logistic_reg::LogisticRegressor;
//! use rusty_machine::learning::SupModel;
//! use rusty_machine::linalg::matrix::Matrix;
//! use rusty_machine::linalg::vector::Vector;
//!
//! let inputs = Matrix::new(4,1,vec![1.0,3.0,5.0,7.0]);
//! let targets = Vector::new(vec![0.,0.,1.,1.]);
//!
//! let mut log_mod = LogisticRegressor::default();
//!
//! // Train the model
//! log_mod.train(&inputs, &targets);
//!
//! // Now we'll predict a new point
//! let new_point = Matrix::new(1,1,vec![10.]);
//! let output = log_mod.predict(&new_point);
//!
//! // Hopefully we classified our new point correctly!
//! assert!(output[0] > 0.5, "Our classifier isn't very good!");
//! ```
//!
//! We could have been more specific about the learning of the model
//! by using the `new` constructor instead. This allows us to provide
//! a `GradientDesc` object with custom parameters.

use learning::SupModel;
use linalg::matrix::Matrix;
use linalg::vector::Vector;
use learning::toolkit::activ_fn::ActivationFunc;
use learning::toolkit::activ_fn::Sigmoid;
use learning::toolkit::cost_fn::CostFunc;
use learning::toolkit::cost_fn::CrossEntropyError;
use learning::optim::grad_desc::GradientDesc;
use learning::optim::OptimAlgorithm;
use learning::optim::Optimizable;

/// Logistic Regression Model.
///
/// Contains option for optimized parameter.
pub struct LogisticRegressor
    where A : OptimAlgorithm<BaseLogisticRegressor> {
    base: BaseLogisticRegressor,
    alg: A,
}

impl Default for LogisticRegressor<GradientDesc> {
    fn default() -> LogisticRegressor<GradientDesc> {
        LogisticRegressor {
            base: BaseLogisticRegressor::default(),
            alg: GradientDesc::default(),
        }
    }
}

impl<A : OptimAlgorithm<BaseLogisticRegressor>> LogisticRegressor {
    /// Constructs untrained logistic regression model.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::learning::logistic_reg::LogisticRegressor;
    /// use rusty_machine::learning::optim::grad_desc::GradientDesc;
    ///
    /// let gd = GradientDesc::default();
    /// let mut logistic_mod = LogisticRegressor::new(gd);
    /// ```
    pub fn new(alg: A) -> LogisticRegressor {
        LogisticRegressor {
            base: BaseLogisticRegressor::default(),
            alg: alg,
        }
    }

    /// Get the parameters from the model.
    ///
    /// Returns an option that is None if the model has not been trained.
    pub fn parameters(&self) -> Option<Vector<f64>> {
        match self.base.parameters() {
            &Some(ref p) => Some(p.clone()),
            &None => None,
        }
    }
}

impl<A : OptimAlgorithm<BaseLogisticRegressor>> SupModel<Matrix<f64>, Vector<f64>> for LogisticRegressor {
    /// Train the logistic regression model.
    ///
    /// Takes training data and output values as input.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::learning::logistic_reg::LogisticRegressor;
    /// use rusty_machine::linalg::matrix::Matrix;
    /// use rusty_machine::linalg::vector::Vector;
    /// use rusty_machine::learning::SupModel;
    ///
    /// let mut logistic_mod = LogisticRegressor::default();
    /// let inputs = Matrix::new(3,2, vec![1.0, 2.0, 1.0, 3.0, 1.0, 4.0]);
    /// let targets = Vector::new(vec![5.0, 6.0, 7.0]);
    ///
    /// logistic_mod.train(&inputs, &targets);
    /// ```
    fn train(&mut self, inputs: &Matrix<f64>, targets: &Vector<f64>) {
        let ones = Matrix::<f64>::ones(inputs.rows(), 1);
        let full_inputs = ones.hcat(inputs);

        let initial_params = vec![0.5; full_inputs.cols()];

        let optimal_w = self.alg.optimize(&self.base, &initial_params[..], &full_inputs, targets);
        self.base.set_parameters(Vector::new(optimal_w));
    }

    /// Predict output value from input data.
    ///
    /// Model must be trained before prediction can be made.
    fn predict(&self, inputs: &Matrix<f64>) -> Vector<f64> {
        if let &Some(ref v) = self.base.parameters() {
            let ones = Matrix::<f64>::ones(inputs.rows(), 1);
            let full_inputs = ones.hcat(inputs);
            (full_inputs * v).apply(&Sigmoid::func)
        } else {
            panic!("Model has not been trained.");
        }
    }
}

pub struct BaseLogisticRegressor {
    parameters: Option<Vector<f64>>,
}

impl Default for BaseLogisticRegressor {
    fn default() -> BaseLogisticRegressor {
        BaseLogisticRegressor {
            parameters : None,
        }
    }
}

impl BaseLogisticRegressor {
    pub fn parameters(&self) -> &Option<Vector<f64>> {
        &self.parameters
    }

    pub fn set_parameters(&mut self, params: Vector<f64>) {
        self.parameters = Some(params);
    }
}

impl Optimizable for BaseLogisticRegressor {
    type Inputs = Matrix<f64>;
    type Targets = Vector<f64>;

    fn compute_grad(&self,
                    params: &[f64],
                    inputs: &Matrix<f64>,
                    targets: &Vector<f64>)
                    -> (f64, Vec<f64>) {

        let beta_vec = Vector::new(params.to_vec());
        let outputs = (inputs * beta_vec).apply(&Sigmoid::func);

        let cost = CrossEntropyError::cost(&outputs, targets);
        let grad = (inputs.transpose() * (outputs - targets)) / (inputs.rows() as f64);

        (cost, grad.into_vec())
    }
}
<commit_msg>Making BaseLogisticRegressor non-instantiable.<commit_after>//! Logistic Regression module
//!
//! Contains implemention of logistic regression using
//! gradient descent optimization.
//!
//! The regressor will automatically add the intercept term
//! so you do not need to format the input matrices yourself.
//!
//! # Usage
//!
//! ```
//! use rusty_machine::learning::logistic_reg::LogisticRegressor;
//! use rusty_machine::learning::SupModel;
//! use rusty_machine::linalg::matrix::Matrix;
//! use rusty_machine::linalg::vector::Vector;
//!
//! let inputs = Matrix::new(4,1,vec![1.0,3.0,5.0,7.0]);
//! let targets = Vector::new(vec![0.,0.,1.,1.]);
//!
//! let mut log_mod = LogisticRegressor::default();
//!
//! // Train the model
//! log_mod.train(&inputs, &targets);
//!
//! // Now we'll predict a new point
//! let new_point = Matrix::new(1,1,vec![10.]);
//! let output = log_mod.predict(&new_point);
//!
//! // Hopefully we classified our new point correctly!
//! assert!(output[0] > 0.5, "Our classifier isn't very good!");
//! ```
//!
//! We could have been more specific about the learning of the model
//! by using the `new` constructor instead. This allows us to provide
//! a `GradientDesc` object with custom parameters.

use learning::SupModel;
use linalg::matrix::Matrix;
use linalg::vector::Vector;
use learning::toolkit::activ_fn::{ActivationFunc, Sigmoid};
use learning::toolkit::cost_fn::{CostFunc, CrossEntropyError};
use learning::optim::grad_desc::GradientDesc;
use learning::optim::{OptimAlgorithm, Optimizable};

/// Logistic Regression Model.
///
/// Contains option for optimized parameter.
pub struct LogisticRegressor
    where A: OptimAlgorithm<BaseLogisticRegressor>
{
    base: BaseLogisticRegressor,
    alg: A,
}

/// Constructs a default Logistic Regression model
/// using standard gradient descent.
impl Default for LogisticRegressor<GradientDesc> {
    fn default() -> LogisticRegressor<GradientDesc> {
        LogisticRegressor {
            base: BaseLogisticRegressor::new(),
            alg: GradientDesc::default(),
        }
    }
}

impl<A: OptimAlgorithm<BaseLogisticRegressor>> LogisticRegressor {
    /// Constructs untrained logistic regression model.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::learning::logistic_reg::LogisticRegressor;
    /// use rusty_machine::learning::optim::grad_desc::GradientDesc;
    ///
    /// let gd = GradientDesc::default();
    /// let mut logistic_mod = LogisticRegressor::new(gd);
    /// ```
    pub fn new(alg: A) -> LogisticRegressor {
        LogisticRegressor {
            base: BaseLogisticRegressor::new(),
            alg: alg,
        }
    }

    /// Get the parameters from the model.
    ///
    /// Returns an option that is None if the model has not been trained.
    pub fn parameters(&self) -> Option<Vector<f64>> {
        match self.base.parameters() {
            &Some(ref p) => Some(p.clone()),
            &None => None,
        }
    }
}

impl<A : OptimAlgorithm<BaseLogisticRegressor>> SupModel<Matrix<f64>, Vector<f64>> for LogisticRegressor {
    /// Train the logistic regression model.
    ///
    /// Takes training data and output values as input.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::learning::logistic_reg::LogisticRegressor;
    /// use rusty_machine::linalg::matrix::Matrix;
    /// use rusty_machine::linalg::vector::Vector;
    /// use rusty_machine::learning::SupModel;
    ///
    /// let mut logistic_mod = LogisticRegressor::default();
    /// let inputs = Matrix::new(3,2, vec![1.0, 2.0, 1.0, 3.0, 1.0, 4.0]);
    /// let targets = Vector::new(vec![5.0, 6.0, 7.0]);
    ///
    /// logistic_mod.train(&inputs, &targets);
    /// ```
    fn train(&mut self, inputs: &Matrix<f64>, targets: &Vector<f64>) {
        let ones = Matrix::<f64>::ones(inputs.rows(), 1);
        let full_inputs = ones.hcat(inputs);

        let initial_params = vec![0.5; full_inputs.cols()];

        let optimal_w = self.alg.optimize(&self.base, &initial_params[..], &full_inputs, targets);
        self.base.set_parameters(Vector::new(optimal_w));
    }

    /// Predict output value from input data.
    ///
    /// Model must be trained before prediction can be made.
    fn predict(&self, inputs: &Matrix<f64>) -> Vector<f64> {
        if let &Some(ref v) = self.base.parameters() {
            let ones = Matrix::<f64>::ones(inputs.rows(), 1);
            let full_inputs = ones.hcat(inputs);
            (full_inputs * v).apply(&Sigmoid::func)
        } else {
            panic!("Model has not been trained.");
        }
    }
}

/// The Base Logistic Regression model.
///
/// This model cannot be instantianated and is used internally only.
pub struct BaseLogisticRegressor {
    parameters: Option<Vector<f64>>,
}

impl BaseLogisticRegressor {

    /// Construct a new BaseLogisticRegressor
    /// with parameters set to None.
    fn new() -> BaseLogisticRegressor {
        BaseLogisticRegressor { parameters: None }
    }
}

impl BaseLogisticRegressor {

    /// Returns a reference to the parameters.
    fn parameters(&self) -> &Option<Vector<f64>> {
        &self.parameters
    }

    /// Set the parameters to `Some` vector.
    fn set_parameters(&mut self, params: Vector<f64>) {
        self.parameters = Some(params);
    }
}

/// Computing the gradient of the underlying Logistic
/// Regression model.
///
/// The gradient is given by
///
/// XT(h(Xb) - y) / m
///
/// where `h` is the sigmoid function and `b` the underlying model parameters.
impl Optimizable for BaseLogisticRegressor {
    type Inputs = Matrix<f64>;
    type Targets = Vector<f64>;

    fn compute_grad(&self,
                    params: &[f64],
                    inputs: &Matrix<f64>,
                    targets: &Vector<f64>)
                    -> (f64, Vec<f64>) {

        let beta_vec = Vector::new(params.to_vec());
        let outputs = (inputs * beta_vec).apply(&Sigmoid::func);

        let cost = CrossEntropyError::cost(&outputs, targets);
        let grad = (inputs.transpose() * (outputs - targets)) / (inputs.rows() as f64);

        (cost, grad.into_vec())
    }
}<|endoftext|>