<commit_before>extern crate semver;

use std::collections::HashMap;
use std::io::net::ip::IpAddr;
use std::hash::Hash;
use std::any::Any;
use std::fmt::Show;

#[deriving(PartialEq, Show, Clone)]
pub enum Scheme {
    Http,
    Https
}

#[deriving(PartialEq, Show, Clone)]
pub enum Host<'a> {
    HostName(&'a str),
    HostIp(IpAddr)
}

#[deriving(PartialEq, Hash, Eq, Show, Clone)]
pub enum Method {
    Get,
    Post,
    Put,
    Delete,
    Head,
    Connect,
    Options,
    Trace,

    // RFC-5789
    Patch,
    Purge,

    // WebDAV, Subversion, UPNP
    Other(&'static str)
}

/// A Dictionary for extensions provided by the server or middleware
pub type Extensions = HashMap<&'static str, Box<Any>>;

pub trait Request {
    /// The version of HTTP being used
    fn http_version(&self) -> semver::Version;

    /// The version of the conduit spec being used
    fn conduit_version(&self) -> semver::Version;

    /// The request method, such as GET, POST, PUT, DELETE or PATCH
    fn method(&self) -> Method;

    /// The scheme part of the request URL
    fn scheme(&self) -> Scheme;

    /// The host part of the requested URL
    fn host<'a>(&'a self) -> Host<'a>;

    /// The initial part of the request URL's path that corresponds
    /// to a virtual root. This allows an application to have a
    /// virtual location that consumes part of the path.
    fn virtual_root<'a>(&'a self) -> Option<&'a str>;

    /// The remainder of the path.
    fn path<'a>(&'a self) -> &'a str;

    /// The portion of the request URL that follows the "?"
    fn query_string<'a>(&'a self) -> Option<&'a str>;

    /// The remote IP address of the client or the last proxy that
    /// sent the request.
    fn remote_ip(&self) -> IpAddr;

    /// The byte-size of the body, if any
    fn content_length(&self) -> Option<uint>;

    /// The request's headers, as conduit::Headers.
    fn headers<'a>(&'a self) -> &'a Headers;

    /// A Reader for the body of the request
    fn body<'a>(&'a mut self) -> &'a mut Reader;

    /// A readable map of extensions
    fn extensions<'a>(&'a self) -> &'a Extensions;

    /// A mutable map of extensions
    fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions;
}

pub type HeaderEntries<'a> = Box<Iterator<(&'a str, Vec<&'a str>)>>;

pub trait Headers {
    /// Find the value of a given header. Multi-line headers are represented
    /// as an array.
    fn find<'a>(&'a self, key: &str) -> Option<Vec<&'a str>>;

    /// Returns true if a particular header exists
    fn has(&self, key: &str) -> bool;

    /// Iterate over all of the available headers.
    fn iter<'a>(&'a self) -> HeaderEntries<'a>;
}

pub struct Response {
    /// The status code as a tuple of the return code and status string
    pub status: (uint, &'static str),

    /// A Map of the headers
    pub headers: HashMap<String, Vec<String>>,

    /// A Writer for body of the response
    pub body: Box<Reader + Send>
}

/// A Handler takes a request and returns a response or an error.
/// By default, a bare function implements `Handler`.
pub trait Handler {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Show>>;
}

impl<T: 'static + Show> Handler for fn(&mut Request) -> Result<Response, T> {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Show>> {
        { (*self)(request) }.map_err(|e| box e as Box<Show>)
    }
}
<commit_msg>Require handlers to be Share + Send<commit_after>extern crate semver;

use std::collections::HashMap;
use std::io::net::ip::IpAddr;
use std::hash::Hash;
use std::any::Any;
use std::fmt::Show;

#[deriving(PartialEq, Show, Clone)]
pub enum Scheme {
    Http,
    Https
}

#[deriving(PartialEq, Show, Clone)]
pub enum Host<'a> {
    HostName(&'a str),
    HostIp(IpAddr)
}

#[deriving(PartialEq, Hash, Eq, Show, Clone)]
pub enum Method {
    Get,
    Post,
    Put,
    Delete,
    Head,
    Connect,
    Options,
    Trace,

    // RFC-5789
    Patch,
    Purge,

    // WebDAV, Subversion, UPNP
    Other(&'static str)
}

/// A Dictionary for extensions provided by the server or middleware
pub type Extensions = HashMap<&'static str, Box<Any>>;

pub trait Request {
    /// The version of HTTP being used
    fn http_version(&self) -> semver::Version;

    /// The version of the conduit spec being used
    fn conduit_version(&self) -> semver::Version;

    /// The request method, such as GET, POST, PUT, DELETE or PATCH
    fn method(&self) -> Method;

    /// The scheme part of the request URL
    fn scheme(&self) -> Scheme;

    /// The host part of the requested URL
    fn host<'a>(&'a self) -> Host<'a>;

    /// The initial part of the request URL's path that corresponds
    /// to a virtual root. This allows an application to have a
    /// virtual location that consumes part of the path.
    fn virtual_root<'a>(&'a self) -> Option<&'a str>;

    /// The remainder of the path.
    fn path<'a>(&'a self) -> &'a str;

    /// The portion of the request URL that follows the "?"
    fn query_string<'a>(&'a self) -> Option<&'a str>;

    /// The remote IP address of the client or the last proxy that
    /// sent the request.
    fn remote_ip(&self) -> IpAddr;

    /// The byte-size of the body, if any
    fn content_length(&self) -> Option<uint>;

    /// The request's headers, as conduit::Headers.
    fn headers<'a>(&'a self) -> &'a Headers;

    /// A Reader for the body of the request
    fn body<'a>(&'a mut self) -> &'a mut Reader;

    /// A readable map of extensions
    fn extensions<'a>(&'a self) -> &'a Extensions;

    /// A mutable map of extensions
    fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions;
}

pub type HeaderEntries<'a> = Box<Iterator<(&'a str, Vec<&'a str>)>>;

pub trait Headers {
    /// Find the value of a given header. Multi-line headers are represented
    /// as an array.
    fn find<'a>(&'a self, key: &str) -> Option<Vec<&'a str>>;

    /// Returns true if a particular header exists
    fn has(&self, key: &str) -> bool;

    /// Iterate over all of the available headers.
    fn iter<'a>(&'a self) -> HeaderEntries<'a>;
}

pub struct Response {
    /// The status code as a tuple of the return code and status string
    pub status: (uint, &'static str),

    /// A Map of the headers
    pub headers: HashMap<String, Vec<String>>,

    /// A Writer for body of the response
    pub body: Box<Reader + Send>
}

/// A Handler takes a request and returns a response or an error.
/// By default, a bare function implements `Handler`.
pub trait Handler : Share + Send {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Show>>;
}

impl<T: Send + Share + Show> Handler for fn(&mut Request) -> Result<Response, T> {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Show>> {
        { (*self)(request) }.map_err(|e| box e as Box<Show>)
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use std::sync::atomic::{AtomicU8, Ordering};
use std::time::{Duration, Instant};
use parking_lot::{self, UnparkResult};
use mutex::{MutexGuard, guard_lock};

/// A type indicating whether a timed wait on a condition variable returned
/// due to a time out or not.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct WaitTimeoutResult(bool);

impl WaitTimeoutResult {
    /// Returns whether the wait was known to have timed out.
    pub fn timed_out(&self) -> bool {
        self.0
    }
}

/// A Condition Variable
///
/// Condition variables represent the ability to block a thread such that it
/// consumes no CPU time while waiting for an event to occur. Condition
/// variables are typically associated with a boolean predicate (a condition)
/// and a mutex. The predicate is always verified inside of the mutex before
/// determining that thread must block.
///
/// # Differences from the standard library `Condvar`
///
/// - No spurious wakeups: A wait will only return a non-timeout result if it
///   was woken up by `notify_one` or `notify_all`.
/// - Only requires 1 byte of space, whereas the standard library boxes the
///   `Condvar` due to platform limitations.
/// - Can be statically constructed (requires the `const_fn` nightly feature).
/// - Does not require any drop glue when dropped.
/// - Inline fast path for the uncontended case.
///
/// # Examples
///
/// ```
/// use parking_lot::{Mutex, Condvar};
/// use std::sync::Arc;
/// use std::thread;
///
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
/// let pair2 = pair.clone();
///
/// // Inside of our lock, spawn a new thread, and then wait for it to start
/// thread::spawn(move|| {
///     let &(ref lock, ref cvar) = &*pair2;
///     let mut started = lock.lock();
///     *started = true;
///     cvar.notify_one();
/// });
///
/// // wait for the thread to start up
/// let &(ref lock, ref cvar) = &*pair;
/// let mut started = lock.lock();
/// while !*started {
///     cvar.wait(&mut started);
/// }
/// ```
pub struct Condvar {
    state: AtomicU8,
}

impl Condvar {
    /// Creates a new condition variable which is ready to be waited on and
    /// notified.
    #[inline]
    pub const fn new() -> Condvar {
        Condvar { state: AtomicU8::new(0) }
    }

    /// Wakes up one blocked thread on this condvar.
    ///
    /// If there is a blocked thread on this condition variable, then it will
    /// be woken up from its call to `wait` or `wait_timeout`. Calls to
    /// `notify_one` are not buffered in any way.
    ///
    /// To wake up all threads, see `notify_all()`.
    #[inline]
    pub fn notify_one(&self) {
        // Nothing to do if there are no waiting threads
        if self.state.load(Ordering::Relaxed) == 0 {
            return;
        }

        unsafe {
            // Unpark one thread
            let addr = self as *const _ as usize;
            let callback = &mut |result| {
                // Clear our state if there are no more waiting threads
                if result != UnparkResult::UnparkedNotLast {
                    self.state.store(0, Ordering::Relaxed);
                }
            };
            parking_lot::unpark_one(addr, callback);
        }
    }

    /// Wakes up all blocked threads on this condvar.
    ///
    /// This method will ensure that any current waiters on the condition
    /// variable are awoken. Calls to `notify_all()` are not buffered in any
    /// way.
    ///
    /// To wake up only one thread, see `notify_one()`.
    #[inline]
    pub fn notify_all(&self) {
        // Nothing to do if there are no waiting threads
        if self.state.load(Ordering::Relaxed) == 0 {
            return;
        }

        // Clear our state since we are going to wake all threads up anyways
        self.state.store(0, Ordering::Relaxed);

        unsafe {
            // Unpark all threads
            let addr = self as *const _ as usize;
            parking_lot::unpark_all(addr);
        }
    }

    /// Blocks the current thread until this condition variable receives a
    /// notification.
    ///
    /// This function will atomically unlock the mutex specified (represented by
    /// `mutex_guard`) and block the current thread. This means that any calls
    /// to `notify_*()` which happen logically after the mutex is unlocked are
    /// candidates to wake this thread up. When this function call returns, the
    /// lock specified will have been re-acquired.
    #[inline]
    pub fn wait<T: ?Sized>(&self, guard: &mut MutexGuard<T>) {
        unsafe {
            let addr = self as *const _ as usize;
            let validate = &mut || {
                // This is done while locked to avoid races with notify_one
                self.state.store(1, Ordering::Relaxed);
                true
            };
            let before_sleep = &mut || {
                // Unlock the mutex before sleeping...
                guard_lock(guard).unlock();
            };
            parking_lot::park(addr, validate, before_sleep, None);

            // ... and re-lock it once we are done sleeping
            guard_lock(guard).lock();
        }
    }

    /// Waits on this condition variable for a notification, timing out after
    /// the specified time instant.
    ///
    /// The semantics of this function are equivalent to `wait()` except that
    /// the thread will be blocked roughly until `timeout` is reached. This
    /// method should not be used for precise timing due to anomalies such as
    /// preemption or platform differences that may not cause the maximum
    /// amount of time waited to be precisely `timeout`.
    ///
    /// The returned `WaitTimeoutResult` value indicates if the timeout is
    /// known to have elapsed.
    ///
    /// Like `wait`, the lock specified will be re-acquired when this function
    /// returns, regardless of whether the timeout elapsed or not.
    #[inline]
    pub fn wait_until<T: ?Sized>(&self,
                                 guard: &mut MutexGuard<T>,
                                 timeout: Instant)
                                 -> WaitTimeoutResult {
        unsafe {
            let result;
            if timeout <= Instant::now() {
                // If the timeout is in the past, we still need to release and
                // re-acquire the mutex.
                guard_lock(guard).unlock();
                result = false;
            } else {
                let addr = self as *const _ as usize;
                let validate = &mut || {
                    // This is done while locked to avoid races with notify_one
                    self.state.store(1, Ordering::Relaxed);
                    true
                };
                let before_sleep = &mut || {
                    // Unlock the mutex before sleeping...
                    guard_lock(guard).unlock();
                };
                result = parking_lot::park(addr, validate, before_sleep, Some(timeout));
            }

            // ... and re-lock it once we are done sleeping
            guard_lock(guard).lock();

            WaitTimeoutResult(!result)
        }
    }

    /// Waits on this condition variable for a notification, timing out after a
    /// specified duration.
    ///
    /// The semantics of this function are equivalent to `wait()` except that
    /// the thread will be blocked for roughly no longer than `timeout`. This
    /// method should not be used for precise timing due to anomalies such as
    /// preemption or platform differences that may not cause the maximum
    /// amount of time waited to be precisely `timeout`.
    ///
    /// The returned `WaitTimeoutResult` value indicates if the timeout is
    /// known to have elapsed.
    ///
    /// Like `wait`, the lock specified will be re-acquired when this function
    /// returns, regardless of whether the timeout elapsed or not.
    #[inline]
    pub fn wait_for<T: ?Sized>(&self,
                               guard: &mut MutexGuard<T>,
                               timeout: Duration)
                               -> WaitTimeoutResult {
        self.wait_until(guard, Instant::now() + timeout)
    }
}

impl Default for Condvar {
    fn default() -> Condvar {
        Condvar::new()
    }
}

#[cfg(test)]
mod tests {
    use std::sync::mpsc::channel;
    use std::sync::Arc;
    use std::thread;
    use std::time::{Duration, Instant};
    use {Condvar, Mutex};

    #[test]
    fn smoke() {
        let c = Condvar::new();
        c.notify_one();
        c.notify_all();
    }

    #[test]
    fn notify_one() {
        static C: Condvar = Condvar::new();
        static M: Mutex<()> = Mutex::new(());

        let mut g = M.lock();
        let _t = thread::spawn(move || {
            let _g = M.lock();
            C.notify_one();
        });
        C.wait(&mut g);
    }

    #[test]
    fn notify_all() {
        const N: usize = 10;

        let data = Arc::new((Mutex::new(0), Condvar::new()));
        let (tx, rx) = channel();
        for _ in 0..N {
            let data = data.clone();
            let tx = tx.clone();
            thread::spawn(move || {
                let &(ref lock, ref cond) = &*data;
                let mut cnt = lock.lock();
                *cnt += 1;
                if *cnt == N {
                    tx.send(()).unwrap();
                }
                while *cnt != 0 {
                    cond.wait(&mut cnt);
                }
                tx.send(()).unwrap();
            });
        }
        drop(tx);

        let &(ref lock, ref cond) = &*data;
        rx.recv().unwrap();
        let mut cnt = lock.lock();
        *cnt = 0;
        cond.notify_all();
        drop(cnt);

        for _ in 0..N {
            rx.recv().unwrap();
        }
    }

    #[test]
    fn wait_for() {
        static C: Condvar = Condvar::new();
        static M: Mutex<()> = Mutex::new(());

        let mut g = M.lock();
        let no_timeout = C.wait_for(&mut g, Duration::from_millis(1));
        assert!(no_timeout.timed_out());
        let _t = thread::spawn(move || {
            let _g = M.lock();
            C.notify_one();
        });
        let timeout_res = C.wait_for(&mut g, Duration::from_millis(u32::max_value() as u64));
        assert!(!timeout_res.timed_out());
        drop(g);
    }

    #[test]
    fn wait_until() {
        static C: Condvar = Condvar::new();
        static M: Mutex<()> = Mutex::new(());

        let mut g = M.lock();
        let no_timeout = C.wait_until(&mut g, Instant::now() + Duration::from_millis(1));
        assert!(no_timeout.timed_out());
        let _t = thread::spawn(move || {
            let _g = M.lock();
            C.notify_one();
        });
        let timeout_res = C.wait_until(&mut g,
                                       Instant::now() +
                                       Duration::from_millis(u32::max_value() as u64));
        assert!(!timeout_res.timed_out());
        drop(g);
    }
}
<commit_msg>Use AtomicBool for Condvar now that it is 1 byte<commit_after>// Copyright 2016 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use std::sync::atomic::{AtomicBool, Ordering};
use std::time::{Duration, Instant};
use parking_lot::{self, UnparkResult};
use mutex::{MutexGuard, guard_lock};

/// A type indicating whether a timed wait on a condition variable returned
/// due to a time out or not.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct WaitTimeoutResult(bool);

impl WaitTimeoutResult {
    /// Returns whether the wait was known to have timed out.
    pub fn timed_out(&self) -> bool {
        self.0
    }
}

/// A Condition Variable
///
/// Condition variables represent the ability to block a thread such that it
/// consumes no CPU time while waiting for an event to occur. Condition
/// variables are typically associated with a boolean predicate (a condition)
/// and a mutex. The predicate is always verified inside of the mutex before
/// determining that thread must block.
///
/// # Differences from the standard library `Condvar`
///
/// - No spurious wakeups: A wait will only return a non-timeout result if it
///   was woken up by `notify_one` or `notify_all`.
/// - Only requires 1 byte of space, whereas the standard library boxes the
///   `Condvar` due to platform limitations.
/// - Can be statically constructed (requires the `const_fn` nightly feature).
/// - Does not require any drop glue when dropped.
/// - Inline fast path for the uncontended case.
///
/// # Examples
///
/// ```
/// use parking_lot::{Mutex, Condvar};
/// use std::sync::Arc;
/// use std::thread;
///
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
/// let pair2 = pair.clone();
///
/// // Inside of our lock, spawn a new thread, and then wait for it to start
/// thread::spawn(move|| {
///     let &(ref lock, ref cvar) = &*pair2;
///     let mut started = lock.lock();
///     *started = true;
///     cvar.notify_one();
/// });
///
/// // wait for the thread to start up
/// let &(ref lock, ref cvar) = &*pair;
/// let mut started = lock.lock();
/// while !*started {
///     cvar.wait(&mut started);
/// }
/// ```
pub struct Condvar {
    state: AtomicBool,
}

impl Condvar {
    /// Creates a new condition variable which is ready to be waited on and
    /// notified.
    #[inline]
    pub const fn new() -> Condvar {
        Condvar { state: AtomicBool::new(false) }
    }

    /// Wakes up one blocked thread on this condvar.
    ///
    /// If there is a blocked thread on this condition variable, then it will
    /// be woken up from its call to `wait` or `wait_timeout`. Calls to
    /// `notify_one` are not buffered in any way.
    ///
    /// To wake up all threads, see `notify_all()`.
    #[inline]
    pub fn notify_one(&self) {
        // Nothing to do if there are no waiting threads
        if !self.state.load(Ordering::Relaxed) {
            return;
        }

        unsafe {
            // Unpark one thread
            let addr = self as *const _ as usize;
            let callback = &mut |result| {
                // Clear our state if there are no more waiting threads
                if result != UnparkResult::UnparkedNotLast {
                    self.state.store(false, Ordering::Relaxed);
                }
            };
            parking_lot::unpark_one(addr, callback);
        }
    }

    /// Wakes up all blocked threads on this condvar.
    ///
    /// This method will ensure that any current waiters on the condition
    /// variable are awoken. Calls to `notify_all()` are not buffered in any
    /// way.
    ///
    /// To wake up only one thread, see `notify_one()`.
    #[inline]
    pub fn notify_all(&self) {
        // Nothing to do if there are no waiting threads
        if !self.state.load(Ordering::Relaxed) {
            return;
        }

        // Clear our state since we are going to wake all threads up anyways
        self.state.store(false, Ordering::Relaxed);

        unsafe {
            // Unpark all threads
            let addr = self as *const _ as usize;
            parking_lot::unpark_all(addr);
        }
    }

    /// Blocks the current thread until this condition variable receives a
    /// notification.
    ///
    /// This function will atomically unlock the mutex specified (represented by
    /// `mutex_guard`) and block the current thread. This means that any calls
    /// to `notify_*()` which happen logically after the mutex is unlocked are
    /// candidates to wake this thread up. When this function call returns, the
    /// lock specified will have been re-acquired.
    #[inline]
    pub fn wait<T: ?Sized>(&self, guard: &mut MutexGuard<T>) {
        unsafe {
            let addr = self as *const _ as usize;
            let validate = &mut || {
                // This is done while locked to avoid races with notify_one
                self.state.store(true, Ordering::Relaxed);
                true
            };
            let before_sleep = &mut || {
                // Unlock the mutex before sleeping...
                guard_lock(guard).unlock();
            };
            parking_lot::park(addr, validate, before_sleep, None);

            // ... and re-lock it once we are done sleeping
            guard_lock(guard).lock();
        }
    }

    /// Waits on this condition variable for a notification, timing out after
    /// the specified time instant.
    ///
    /// The semantics of this function are equivalent to `wait()` except that
    /// the thread will be blocked roughly until `timeout` is reached. This
    /// method should not be used for precise timing due to anomalies such as
    /// preemption or platform differences that may not cause the maximum
    /// amount of time waited to be precisely `timeout`.
    ///
    /// The returned `WaitTimeoutResult` value indicates if the timeout is
    /// known to have elapsed.
    ///
    /// Like `wait`, the lock specified will be re-acquired when this function
    /// returns, regardless of whether the timeout elapsed or not.
    #[inline]
    pub fn wait_until<T: ?Sized>(&self,
                                 guard: &mut MutexGuard<T>,
                                 timeout: Instant)
                                 -> WaitTimeoutResult {
        unsafe {
            let result;
            if timeout <= Instant::now() {
                // If the timeout is in the past, we still need to release and
                // re-acquire the mutex.
                guard_lock(guard).unlock();
                result = false;
            } else {
                let addr = self as *const _ as usize;
                let validate = &mut || {
                    // This is done while locked to avoid races with notify_one
                    self.state.store(true, Ordering::Relaxed);
                    true
                };
                let before_sleep = &mut || {
                    // Unlock the mutex before sleeping...
                    guard_lock(guard).unlock();
                };
                result = parking_lot::park(addr, validate, before_sleep, Some(timeout));
            }

            // ... and re-lock it once we are done sleeping
            guard_lock(guard).lock();

            WaitTimeoutResult(!result)
        }
    }

    /// Waits on this condition variable for a notification, timing out after a
    /// specified duration.
    ///
    /// The semantics of this function are equivalent to `wait()` except that
    /// the thread will be blocked for roughly no longer than `timeout`. This
    /// method should not be used for precise timing due to anomalies such as
    /// preemption or platform differences that may not cause the maximum
    /// amount of time waited to be precisely `timeout`.
    ///
    /// The returned `WaitTimeoutResult` value indicates if the timeout is
    /// known to have elapsed.
    ///
    /// Like `wait`, the lock specified will be re-acquired when this function
    /// returns, regardless of whether the timeout elapsed or not.
    #[inline]
    pub fn wait_for<T: ?Sized>(&self,
                               guard: &mut MutexGuard<T>,
                               timeout: Duration)
                               -> WaitTimeoutResult {
        self.wait_until(guard, Instant::now() + timeout)
    }
}

impl Default for Condvar {
    fn default() -> Condvar {
        Condvar::new()
    }
}

#[cfg(test)]
mod tests {
    use std::sync::mpsc::channel;
    use std::sync::Arc;
    use std::thread;
    use std::time::{Duration, Instant};
    use {Condvar, Mutex};

    #[test]
    fn smoke() {
        let c = Condvar::new();
        c.notify_one();
        c.notify_all();
    }

    #[test]
    fn notify_one() {
        static C: Condvar = Condvar::new();
        static M: Mutex<()> = Mutex::new(());

        let mut g = M.lock();
        let _t = thread::spawn(move || {
            let _g = M.lock();
            C.notify_one();
        });
        C.wait(&mut g);
    }

    #[test]
    fn notify_all() {
        const N: usize = 10;

        let data = Arc::new((Mutex::new(0), Condvar::new()));
        let (tx, rx) = channel();
        for _ in 0..N {
            let data = data.clone();
            let tx = tx.clone();
            thread::spawn(move || {
                let &(ref lock, ref cond) = &*data;
                let mut cnt = lock.lock();
                *cnt += 1;
                if *cnt == N {
                    tx.send(()).unwrap();
                }
                while *cnt != 0 {
                    cond.wait(&mut cnt);
                }
                tx.send(()).unwrap();
            });
        }
        drop(tx);

        let &(ref lock, ref cond) = &*data;
        rx.recv().unwrap();
        let mut cnt = lock.lock();
        *cnt = 0;
        cond.notify_all();
        drop(cnt);

        for _ in 0..N {
            rx.recv().unwrap();
        }
    }

    #[test]
    fn wait_for() {
        static C: Condvar = Condvar::new();
        static M: Mutex<()> = Mutex::new(());

        let mut g = M.lock();
        let no_timeout = C.wait_for(&mut g, Duration::from_millis(1));
        assert!(no_timeout.timed_out());
        let _t = thread::spawn(move || {
            let _g = M.lock();
            C.notify_one();
        });
        let timeout_res = C.wait_for(&mut g, Duration::from_millis(u32::max_value() as u64));
        assert!(!timeout_res.timed_out());
        drop(g);
    }

    #[test]
    fn wait_until() {
        static C: Condvar = Condvar::new();
        static M: Mutex<()> = Mutex::new(());

        let mut g = M.lock();
        let no_timeout = C.wait_until(&mut g, Instant::now() + Duration::from_millis(1));
        assert!(no_timeout.timed_out());
        let _t = thread::spawn(move || {
            let _g = M.lock();
            C.notify_one();
        });
        let timeout_res = C.wait_until(&mut g,
                                       Instant::now() +
                                       Duration::from_millis(u32::max_value() as u64));
        assert!(!timeout_res.timed_out());
        drop(g);
    }
}
<|endoftext|>


<commit_before>mod addressing;
mod instructions;
mod registers;

use self::addressing::*;
use bus::{Addressable, Bus, IO_IE_ADDR, IO_IF_ADDR};
use byteorder::{ByteOrder, LittleEndian};
use enum_primitive::FromPrimitive;
use self::instructions as inst;
use self::registers::*;
use std::fmt;

pub use self::instructions::{decode, Instruction};

#[derive(Copy, Clone, PartialEq)]
pub enum Condition {
    None,
    Z,
    C,
    Nz,
    Nc
}

impl fmt::Display for Condition {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Condition::None => write!(f, ""),
            Condition::Z    => write!(f, "Z"),
            Condition::C    => write!(f, "C"),
            Condition::Nz   => write!(f, "NZ"),
            Condition::Nc   => write!(f, "NC")
        }
    }
}

struct DecodedInstruction {
    opcode: u8,
    prefixed: bool,
    instruction: Instruction
}

enum_from_primitive! {
    #[derive(Copy, Clone)]
    pub enum Interrupt {
        Joypad = 0b0001_0000,
        Serial = 0b0000_1000,
        Timer  = 0b0000_0100,
        Stat   = 0b0000_0010,
        VBlank = 0b0000_0001
    }
}

fn interrupt_start_address(interrupt: Interrupt) -> u16 {
    match interrupt {
        Interrupt::Joypad => 0x60,
        Interrupt::Serial => 0x58,
        Interrupt::Timer  => 0x50,
        Interrupt::Stat   => 0x48,
        Interrupt::VBlank => 0x40
    }
}

static CYCLES: &'static [(usize, usize)] = &[
    (4, 4), (12, 12), (8, 8), (8, 8), (4, 4), (4, 4), (8, 8), (4, 4), (20, 20), (8, 8), (8, 8), (8, 8), (4, 4), (4, 4), (8, 8), (4, 4),
    (4, 4), (12, 12), (8, 8), (8, 8), (4, 4), (4, 4), (8, 8), (4, 4), (12, 12), (8, 8), (8, 8), (8, 8), (4, 4), (4, 4), (8, 8), (4, 4),
    (12, 8), (12, 12), (8, 8), (8, 8), (4, 4), (4, 4), (8, 8), (4, 4), (12, 8), (8, 8), (8, 8), (8, 8), (4, 4), (4, 4), (8, 8), (4, 4),
    (12, 8), (12, 12), (8, 8), (8, 8), (12, 12), (12, 12), (12, 12), (4, 4), (12, 8), (8, 8), (8, 8), (8, 8), (4, 4), (4, 4), (8, 8), (4, 4),
    (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4),
    (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4),
    (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4),
    (8, 8), (8, 8), (8, 8), (8, 8), (8, 8), (8, 8), (8, 8), (8, 8), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4),
    (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4),
    (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4),
    (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4),
    (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4),
    (20, 8), (12, 12), (16, 12), (16, 16), (24, 12), (16, 16), (8, 8), (16, 16), (20, 8), (16, 16), (16, 12), (4, 4), (24, 24), (24, 24), (8, 8), (16, 16),
    (20, 8), (12, 12), (16, 12), (0, 0), (24, 12), (16, 16), (8, 8), (16, 16), (20, 8), (16, 16), (16, 12), (0, 0), (24, 12), (0, 0), (8, 8), (16, 16),
    (12, 12), (12, 12), (8, 8), (0, 0), (0, 0), (16, 16), (8, 8), (16, 16), (16, 16), (4, 4), (16, 16), (0, 0), (0, 0), (0, 0), (8, 8), (16, 16),
    (12, 12), (12, 12), (8, 8), (4, 4), (0, 0), (16, 16), (8, 8), (16, 16), (12, 12), (8, 8), (16, 16), (4, 4), (0, 0), (0, 0), (8, 8), (16, 16)
];

static PREFIXED_CYCLES: &'static [(usize, usize)] = &[
    (8, 8), (8, 8), (8, 8), (8, 8), (8, 8), (8, 8), (16, 16), (8, 8), (8, 8), (8, 8), (8, 8), (8, 8), (8, 8), (8, 8), (16, 16), (8, 8)
];

const DISPATCH_CYCLES: usize = 20;
const CLEAR_HALT_CYCLES: usize = 4;

pub struct Cpu {
    pub regs: Registers,
    ime: bool,
    halted: bool
}

impl Cpu {
    pub fn new() -> Self {
        Self {
            regs: Registers::default(),
            ime: true,
            halted: false
        }
    }

    pub fn reset(&mut self) {
        self.regs.set_af(0x01B0);
        self.regs.set_bc(0x0013);
        self.regs.set_de(0x00D8);
        self.regs.set_hl(0x014D);
        self.regs.set_sp(0xFFFE);
        self.regs.set_pc(0x100);
        self.ime = true;
    }

    pub fn step(&mut self, bus: &mut Bus) -> usize {
        let mut used_cycles = 0;
        let interrupt = self.pending_interrupt(bus);

        // If an interrupt is pending and interrupts are enabled, jump to interrupt
        if interrupt.is_some() && self.ime {
            self.handle_interrupt(bus, interrupt.unwrap());

            // It takes 20 cycles to dispatch interrupt, 24 if HALTed.
            used_cycles += DISPATCH_CYCLES;

            if self.halted {
                // Clear HALT.
                self.halted = false;
                used_cycles += CLEAR_HALT_CYCLES;
            }
        // An an interrupt is pending, interrupts are disabled, and the CPU is halted, then unhalt the CPU
        } else if interrupt.is_some() & !self.ime && self.halted {
            self.halted = false;
            used_cycles += CLEAR_HALT_CYCLES;
        // CPU is halted and there's no interrupt
        } else if self.halted {
            used_cycles += 1;
        // Else execute the next instruction
        } else {
            let decoded = self.decode_next_instruction(bus);
            let condition_met = inst::execute(self, bus, &decoded.instruction);

            let instruction_cycles =
                if decoded.prefixed {
                    PREFIXED_CYCLES[decoded.opcode as usize & 0x0F]
                } else {
                    CYCLES[decoded.opcode as usize]
                };

            used_cycles =
                if condition_met {
                    instruction_cycles.1
                } else {
                    instruction_cycles.0
                }
        };

        used_cycles
    }

    fn decode_next_instruction(&mut self, bus: &Bus) -> DecodedInstruction {
        let mut opcode = self.step_next_byte(bus);
        let mut prefixed = false;

        if opcode == 0xCB {
            prefixed = true;
            opcode = self.step_next_byte(bus);
        }

        DecodedInstruction {
            opcode: opcode,
            prefixed: prefixed,
            instruction: inst::decode(self, bus, opcode, prefixed)
        }
    }

    pub fn step_next_byte(&mut self, bus: &Bus) -> u8 {
        let pc = self.regs.pc();
        let byte = bus.read(pc);
        self.regs.set_pc(pc.wrapping_add(1));

        byte
    }

    pub fn step_next_word(&mut self, bus: &Bus) -> u16 {
        let lb = self.step_next_byte(bus);
        let hb = self.step_next_byte(bus);

        LittleEndian::read_u16(&[lb, hb])
    }

    pub fn interrupt(&mut self, bus: &mut Bus, interrupt: Interrupt) {
        let flags = bus.read(IO_IF_ADDR);
        let interrupt_flag = interrupt as u8;

        self.halted = false;
        bus.write(IO_IF_ADDR, flags | interrupt_flag);
    }

    fn pop_stack(&mut self, bus: &Bus) -> u16 {
        let addr = self.regs.sp();
        let word = &[bus.read(addr), bus.read(addr.wrapping_add(1))];
        self.regs.set_sp(addr.wrapping_add(2));

        LittleEndian::read_u16(word)
    }

    fn push_stack(&mut self, bus: &mut Bus, val: u16) {
        let addr = self.regs.sp();

        bus.write(addr.wrapping_sub(2), (val & 0x00FF) as u8);
        bus.write(addr.wrapping_sub(1), ((val >> 8) & 0x00FF) as u8);

        self.regs.set_sp(addr.wrapping_sub(2));
    }

    fn condition_met(&self, cond: Condition) -> bool {
        match cond {
            Condition::None => true,
            Condition::C    => (self.regs.f() & FLAG_C) == FLAG_C,
            Condition::Z    => (self.regs.f() & FLAG_Z) == FLAG_Z,
            Condition::Nc   => (self.regs.f() & FLAG_C) != FLAG_C,
            Condition::Nz   => (self.regs.f() & FLAG_Z) != FLAG_Z
        }
    }

    fn pending_interrupt(&self, bus: &Bus) -> Option<Interrupt> {
        let mut result = None;

        let interrupts = bus.read(IO_IF_ADDR) & bus.read(IO_IE_ADDR);
        if interrupts > 0 {
            let mut flag = Interrupt::Joypad as u8;
            while flag > 0 {
                if interrupts & flag == flag {
                    let interrupt = Interrupt::from_u8(flag).unwrap();
                    result = Some(interrupt);
                    break;
                }

                flag = flag >> 1;
            }
        }

        result
    }

    fn handle_interrupt(&mut self, bus: &mut Bus, interrupt: Interrupt) {
        let addr = interrupt_start_address(interrupt);

        // Push current PC to stack and set PC to interrupt address.
        let pc = self.regs.pc();
        self.push_stack(bus, pc);
        self.regs.set_pc(addr);

        // Disable interrupts
        self.ime = false;

        // Clear IF flag
        let if_register = bus.read(IO_IF_ADDR);
        bus.write(IO_IF_ADDR, if_register ^ (interrupt as u8));
    }
}

impl fmt::Debug for Cpu {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "Interrupts: {}",
            if self.ime { "Enabled" } else { "Disabled" }
        )?;

        writeln!(f, "Registers:")?;
        write!(f, "{:?}", self.regs)
    }
}<commit_msg>Instruction cycles reversed<commit_after>mod addressing;
mod instructions;
mod registers;

use self::addressing::*;
use bus::{Addressable, Bus, IO_IE_ADDR, IO_IF_ADDR};
use byteorder::{ByteOrder, LittleEndian};
use enum_primitive::FromPrimitive;
use self::instructions as inst;
use self::registers::*;
use std::fmt;

pub use self::instructions::{decode, Instruction};

#[derive(Copy, Clone, PartialEq)]
pub enum Condition {
    None,
    Z,
    C,
    Nz,
    Nc
}

impl fmt::Display for Condition {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Condition::None => write!(f, ""),
            Condition::Z    => write!(f, "Z"),
            Condition::C    => write!(f, "C"),
            Condition::Nz   => write!(f, "NZ"),
            Condition::Nc   => write!(f, "NC")
        }
    }
}

struct DecodedInstruction {
    opcode: u8,
    prefixed: bool,
    instruction: Instruction
}

enum_from_primitive! {
    #[derive(Copy, Clone)]
    pub enum Interrupt {
        Joypad = 0b0001_0000,
        Serial = 0b0000_1000,
        Timer  = 0b0000_0100,
        Stat   = 0b0000_0010,
        VBlank = 0b0000_0001
    }
}

fn interrupt_start_address(interrupt: Interrupt) -> u16 {
    match interrupt {
        Interrupt::Joypad => 0x60,
        Interrupt::Serial => 0x58,
        Interrupt::Timer  => 0x50,
        Interrupt::Stat   => 0x48,
        Interrupt::VBlank => 0x40
    }
}

// Number of clock cycles (not machine cycles) used by each instruction.
// First number is cycles used if instruction is conditional and condition is met. Secodn number if cycles used if condition is not met.
static CYCLES: &'static [(usize, usize)] = &[
    (4, 4), (12, 12), (8, 8), (8, 8), (4, 4), (4, 4), (8, 8), (4, 4), (20, 20), (8, 8), (8, 8), (8, 8), (4, 4), (4, 4), (8, 8), (4, 4),
    (4, 4), (12, 12), (8, 8), (8, 8), (4, 4), (4, 4), (8, 8), (4, 4), (12, 12), (8, 8), (8, 8), (8, 8), (4, 4), (4, 4), (8, 8), (4, 4),
    (12, 8), (12, 12), (8, 8), (8, 8), (4, 4), (4, 4), (8, 8), (4, 4), (12, 8), (8, 8), (8, 8), (8, 8), (4, 4), (4, 4), (8, 8), (4, 4),
    (12, 8), (12, 12), (8, 8), (8, 8), (12, 12), (12, 12), (12, 12), (4, 4), (12, 8), (8, 8), (8, 8), (8, 8), (4, 4), (4, 4), (8, 8), (4, 4),
    (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4),
    (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4),
    (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4),
    (8, 8), (8, 8), (8, 8), (8, 8), (8, 8), (8, 8), (8, 8), (8, 8), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4),
    (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4),
    (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4),
    (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4),
    (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (4, 4), (8, 8), (4, 4),
    (20, 8), (12, 12), (16, 12), (16, 16), (24, 12), (16, 16), (8, 8), (16, 16), (20, 8), (16, 16), (16, 12), (4, 4), (24, 24), (24, 24), (8, 8), (16, 16),
    (20, 8), (12, 12), (16, 12), (0, 0), (24, 12), (16, 16), (8, 8), (16, 16), (20, 8), (16, 16), (16, 12), (0, 0), (24, 12), (0, 0), (8, 8), (16, 16),
    (12, 12), (12, 12), (8, 8), (0, 0), (0, 0), (16, 16), (8, 8), (16, 16), (16, 16), (4, 4), (16, 16), (0, 0), (0, 0), (0, 0), (8, 8), (16, 16),
    (12, 12), (12, 12), (8, 8), (4, 4), (0, 0), (16, 16), (8, 8), (16, 16), (12, 12), (8, 8), (16, 16), (4, 4), (0, 0), (0, 0), (8, 8), (16, 16)
];

static PREFIXED_CYCLES: &'static [(usize, usize)] = &[
    (8, 8), (8, 8), (8, 8), (8, 8), (8, 8), (8, 8), (16, 16), (8, 8), (8, 8), (8, 8), (8, 8), (8, 8), (8, 8), (8, 8), (16, 16), (8, 8)
];

const DISPATCH_CYCLES: usize = 20;
const CLEAR_HALT_CYCLES: usize = 4;

pub struct Cpu {
    pub regs: Registers,
    ime: bool,
    halted: bool
}

impl Cpu {
    pub fn new() -> Self {
        Self {
            regs: Registers::default(),
            ime: true,
            halted: false
        }
    }

    pub fn reset(&mut self) {
        self.regs.set_af(0x01B0);
        self.regs.set_bc(0x0013);
        self.regs.set_de(0x00D8);
        self.regs.set_hl(0x014D);
        self.regs.set_sp(0xFFFE);
        self.regs.set_pc(0x100);
        self.ime = true;
    }

    pub fn step(&mut self, bus: &mut Bus) -> usize {
        let mut used_cycles = 0;
        let interrupt = self.pending_interrupt(bus);

        // If an interrupt is pending and interrupts are enabled, jump to interrupt
        if interrupt.is_some() && self.ime {
            self.handle_interrupt(bus, interrupt.unwrap());

            // It takes 20 cycles to dispatch interrupt, 24 if HALTed.
            used_cycles += DISPATCH_CYCLES;

            if self.halted {
                // Clear HALT.
                self.halted = false;
                used_cycles += CLEAR_HALT_CYCLES;
            }
        // An an interrupt is pending, interrupts are disabled, and the CPU is halted, then unhalt the CPU
        } else if interrupt.is_some() & !self.ime && self.halted {
            self.halted = false;
            used_cycles += CLEAR_HALT_CYCLES;
        // CPU is halted and there's no interrupt
        } else if self.halted {
            used_cycles += 1;
        // Else execute the next instruction
        } else {
            let decoded = self.decode_next_instruction(bus);
            let condition_met = inst::execute(self, bus, &decoded.instruction);

            let (cond_met_cycles, cond_not_met_cycles) =
                if decoded.prefixed {
                    PREFIXED_CYCLES[decoded.opcode as usize & 0x0F]
                } else {
                    CYCLES[decoded.opcode as usize]
                };

            used_cycles =
                if condition_met {
                    cond_met_cycles
                } else {
                    cond_not_met_cycles
                }
        };

        used_cycles
    }

    fn decode_next_instruction(&mut self, bus: &Bus) -> DecodedInstruction {
        let mut opcode = self.step_next_byte(bus);
        let mut prefixed = false;

        if opcode == 0xCB {
            prefixed = true;
            opcode = self.step_next_byte(bus);
        }

        DecodedInstruction {
            opcode: opcode,
            prefixed: prefixed,
            instruction: inst::decode(self, bus, opcode, prefixed)
        }
    }

    pub fn step_next_byte(&mut self, bus: &Bus) -> u8 {
        let pc = self.regs.pc();
        let byte = bus.read(pc);
        self.regs.set_pc(pc.wrapping_add(1));

        byte
    }

    pub fn step_next_word(&mut self, bus: &Bus) -> u16 {
        let lb = self.step_next_byte(bus);
        let hb = self.step_next_byte(bus);

        LittleEndian::read_u16(&[lb, hb])
    }

    pub fn interrupt(&mut self, bus: &mut Bus, interrupt: Interrupt) {
        let flags = bus.read(IO_IF_ADDR);
        let interrupt_flag = interrupt as u8;

        self.halted = false;
        bus.write(IO_IF_ADDR, flags | interrupt_flag);
    }

    fn pop_stack(&mut self, bus: &Bus) -> u16 {
        let addr = self.regs.sp();
        let word = &[bus.read(addr), bus.read(addr.wrapping_add(1))];
        self.regs.set_sp(addr.wrapping_add(2));

        LittleEndian::read_u16(word)
    }

    fn push_stack(&mut self, bus: &mut Bus, val: u16) {
        let addr = self.regs.sp();

        bus.write(addr.wrapping_sub(2), (val & 0x00FF) as u8);
        bus.write(addr.wrapping_sub(1), ((val >> 8) & 0x00FF) as u8);

        self.regs.set_sp(addr.wrapping_sub(2));
    }

    fn condition_met(&self, cond: Condition) -> bool {
        match cond {
            Condition::None => true,
            Condition::C    => (self.regs.f() & FLAG_C) == FLAG_C,
            Condition::Z    => (self.regs.f() & FLAG_Z) == FLAG_Z,
            Condition::Nc   => (self.regs.f() & FLAG_C) != FLAG_C,
            Condition::Nz   => (self.regs.f() & FLAG_Z) != FLAG_Z
        }
    }

    fn pending_interrupt(&self, bus: &Bus) -> Option<Interrupt> {
        let mut result = None;

        let interrupts = bus.read(IO_IF_ADDR) & bus.read(IO_IE_ADDR);
        if interrupts > 0 {
            let mut flag = Interrupt::Joypad as u8;
            while flag > 0 {
                if interrupts & flag == flag {
                    let interrupt = Interrupt::from_u8(flag).unwrap();
                    result = Some(interrupt);
                    break;
                }

                flag = flag >> 1;
            }
        }

        result
    }

    fn handle_interrupt(&mut self, bus: &mut Bus, interrupt: Interrupt) {
        let addr = interrupt_start_address(interrupt);

        // Push current PC to stack and set PC to interrupt address.
        let pc = self.regs.pc();
        self.push_stack(bus, pc);
        self.regs.set_pc(addr);

        // Disable interrupts
        self.ime = false;

        // Clear IF flag
        let if_register = bus.read(IO_IF_ADDR);
        bus.write(IO_IF_ADDR, if_register ^ (interrupt as u8));
    }
}

impl fmt::Debug for Cpu {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "Interrupts: {}",
            if self.ime { "Enabled" } else { "Disabled" }
        )?;

        writeln!(f, "Registers:")?;
        write!(f, "{:?}", self.regs)
    }
}<|endoftext|>


<commit_before>use std::io::{File,fs};
use std::path::posix::Path;
use std::os::{homedir};
use std::rand::random;

pub fn new<'r>(name: &str) {
    let home_unwrap = homedir().unwrap();
    let path = format!("{}/.muxed/{}", home_unwrap.display(), name);
    File::create(&Path::new(path));
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = format!("test_project_{}", random::<f64>());
    let home_unwrap = homedir().unwrap();
    let path = &Path::new(format!("{}/.muxed/{}", home_unwrap.display(), name));
    new(name);
    new(name.as_slice());
    assert!(path.exists());
    fs::unlink(path);
}
<commit_msg>Create the mixed dir if it does not exist.<commit_after>use std::io::{File,fs};
use std::path::posix::Path;
use std::os::{homedir};
use std::rand::random;

pub fn new<'r>(name: &str) {
    let home_unwrap = homedir().unwrap();
    let path = format!("{}/.muxed/{}", home_unwrap.display(), name);
    File::create(&Path::new(path));
}

fn create_muxed_dir(name: &String) -> Path {
    let home_unwrap = homedir().unwrap();
    let path = &Path::new(format!("{}/.{}", home_unwrap.display(), name));
    fs::mkdir(path, ::std::io::UserRWX);
    path.clone()
}
#[test]
fn creates_muxed_dir() {
    let name        = format!("test_project_{}", random::<f64>());
    let dir         = format!("test_dir_{}", random::<f64>());
    let home_unwrap = homedir().unwrap();
    let muxed_path  = &Path::new(format!("{}/.{}/", home_unwrap.display(), dir.as_slice()));
    create_muxed_dir(&dir);
    assert!(muxed_path.exists());
    fs::rmdir_recursive(muxed_path);
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = format!("test_project_{}", random::<f64>());
    let home_unwrap = homedir().unwrap();
    let path = &Path::new(format!("{}/.muxed/{}", home_unwrap.display(), name));
    new(name);
    new(name.as_slice());
    assert!(path.exists());
    fs::unlink(path);
}
<|endoftext|>


<commit_before>//! The initializer module parses arguments and verfies commands are valid
//! The creator module handles creating the muxed directory and project files.
#![allow(experimental)]

use std::io::File;
use std::path::posix::Path;
use editor;
use root;

#[cfg(test)] use std::io::fs;
#[cfg(test)] use std::finally::Finally;
#[cfg(test)] use test_helper::random_name;

static TEMPLATE: &'static str = include_str!("creator/template.toml");
static DEFAULT_MUXED_DIR: &'static str = "muxed";

pub fn new(name: &str) {
    let muxed_dir = match root::muxed_dir_exists(&DEFAULT_MUXED_DIR.to_string()) {
        true  => Path::new(format!("{}/.{}/", root::homedir_string(), &DEFAULT_MUXED_DIR.to_string())),
        false => root::create_muxed_dir(&DEFAULT_MUXED_DIR.to_string())
    };

    let path = &Path::new(format!("{}/{}.toml", muxed_dir.display(), name));
    if !path.exists() {
        create_project_file(path);

        match editor::default_editor_set() {
            true  => editor::open_project_file(path),
            false => println!("Default editor is not set. Please define $EDITOR in your ~/.bashrc or similar file.")
        }
    } else {
        println!("Project already exists.");
    }
}

/// Copy and create the new project file from a template. Attempt to open the
/// users default editor to make changes.
fn create_project_file(path: &Path) {
    match File::create(path).write(TEMPLATE.as_bytes()) {
        Ok(()) => (),
        Err(_e) => println!("Failed to create project {}", path.filename()),
    }
}

#[test]
fn creates_project_file() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), name));
    create_project_file(path);
    assert!(path.exists());
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), name));
    new(name.as_slice());
    assert!(path.exists());
    match fs::unlink(path) {
        Ok(()) => (), // succeeded
        Err(e) => println!("Failed to unlink the path {} with error {}", path.display(), e),
    }
}

#[test]
// TODO: Fix this test so it verifies something better.
fn new_doesnt_overwrite_existing_file() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}", root::homedir_string(), name));
    new(name.as_slice());
    (|| {
        new(name.as_slice());
    }).finally(|| {
        match fs::unlink(path) {
            Ok(()) => (), // succeeded
            Err(e) => println!("Failed to unlink the path {} with error {}", path.display(), e),
        }
    })
}
<commit_msg>Use the cleanup method.<commit_after>//! The initializer module parses arguments and verfies commands are valid
//! The creator module handles creating the muxed directory and project files.
#![allow(experimental)]

use std::io::File;
use std::path::posix::Path;
use editor;
use root;

#[cfg(test)] use std::finally::Finally;
#[cfg(test)] use test_helper::{random_name,cleanup_file};

static TEMPLATE: &'static str = include_str!("creator/template.toml");
static DEFAULT_MUXED_DIR: &'static str = "muxed";

pub fn new(name: &str) {
    let muxed_dir = match root::muxed_dir_exists(&DEFAULT_MUXED_DIR.to_string()) {
        true  => Path::new(format!("{}/.{}/", root::homedir_string(), &DEFAULT_MUXED_DIR.to_string())),
        false => root::create_muxed_dir(&DEFAULT_MUXED_DIR.to_string())
    };

    let path = &Path::new(format!("{}/{}.toml", muxed_dir.display(), name));
    if !path.exists() {
        create_project_file(path);

        match editor::default_editor_set() {
            true  => editor::open_project_file(path),
            false => println!("Default editor is not set. Please define $EDITOR in your ~/.bashrc or similar file.")
        }
    } else {
        println!("Project already exists.");
    }
}

/// Copy and create the new project file from a template. Attempt to open the
/// users default editor to make changes.
fn create_project_file(path: &Path) {
    match File::create(path).write(TEMPLATE.as_bytes()) {
        Ok(()) => (),
        Err(_e) => println!("Failed to create project {}", path.filename()),
    }
}

#[test]
fn creates_project_file() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), name));
    create_project_file(path);
    assert!(path.exists());

    cleanup_file(path);
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), name));
    new(name.as_slice());
    assert!(path.exists());
    match fs::unlink(path) {
        Ok(()) => (), // succeeded
        Err(e) => println!("Failed to unlink the path {} with error {}", path.display(), e),
    }

    cleanup_file(path);
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), name));
    new(name.as_slice());
    assert!(path.exists());

    cleanup_file(path);
}
<|endoftext|>


<commit_before>use elektra_sys::{keyDel, keyDup, keyName, keyNew, keySetName, keySetString};
use std::error::Error;
use std::ffi::{CStr, CString};
use std::fmt;
use std::ptr::NonNull;

#[derive(Debug, PartialEq)]
pub enum KeyError {
    InvalidName,
    TypeMismatch,
    // TypeConversion,
    // NotFoundException
}

impl fmt::Display for KeyError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        match self {
            KeyError::InvalidName => write!(f, "Key has an invalid name"),
            KeyError::TypeMismatch => write!(f, "Binary/String key mismatch, use the appropriate method for your key type, get_string or get_binary"),
            // _ => unimplemented!(),
        }
    }
}

impl Error for KeyError {}

#[derive(Debug)]
pub struct Key {
    ptr: NonNull<elektra_sys::Key>,
}

impl Drop for Key {
    fn drop(&mut self) {
        println!("Drop {:?}", self);
        unsafe { keyDel(self.ptr.as_ptr()) };
    }
}

impl PartialEq for Key {
    fn eq(&self, other: &Self) -> bool {
        unsafe {
            elektra_sys::keyCmp(
                self.ptr.as_ptr() as *const elektra_sys::Key,
                other.ptr.as_ptr() as *const elektra_sys::Key,
            ) == 0
        }
    }
}

impl Eq for Key {}

impl Ord for Key {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        let cmp = unsafe {
            elektra_sys::keyCmp(
                self.ptr.as_ptr() as *const elektra_sys::Key,
                other.ptr.as_ptr() as *const elektra_sys::Key,
            )
        };

        if cmp < 0 {
            std::cmp::Ordering::Less
        } else if cmp == 0 {
            std::cmp::Ordering::Equal
        } else {
            std::cmp::Ordering::Greater
        }
    }
}

impl PartialOrd for Key {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl Key {

    /// Construct a new key with a name
    pub fn new(name: &str) -> Result<Key, KeyError> {
        let mut key = Key::new_empty();
        key.set_name(name)?;
        Ok(key)
    }

    /// Construct a new empty key
    pub fn new_empty() -> Key {
        let key_ptr = unsafe { keyNew(0 as *const i8) };
        Key::from(key_ptr)
    }

    /// Construct a new key from a raw key pointer
    pub fn from(ptr: *mut elektra_sys::Key) -> Key {
        Key {
            ptr: NonNull::new(ptr).unwrap(),
        }
    }

    /// Set the name of a key. Must adhere to the rules for keynames otherwise an error is returned.
    /// Returns the size in bytes of this new key name including the ending NUL.
    /// # Examples
    /// ```
    /// use elektra::Key;
    /// let mut key = Key::new_empty();
    /// key.set_name("user/test/rust").unwrap();
    /// assert_eq!(key.get_name(), "user/test/rust");
    /// ```
    /// # Panics
    /// Panics if the provided string contains internal nul bytes.
    pub fn set_name(&mut self, name: &str) -> Result<u32, KeyError> {
        let cptr = CString::new(name).unwrap();
        let ret_val = unsafe { keySetName(self.ptr.as_ptr(), cptr.as_ptr()) };

        if ret_val > 0 {
            Ok(ret_val as u32)
        } else {
            Err(KeyError::InvalidName)
        }
    }

    /// Return the name of the key as a borrowed slice.
    pub fn get_name(&self) -> &str {
        let c_str = unsafe { CStr::from_ptr(keyName(self.ptr.as_ref())) };
        c_str.to_str().unwrap()
    }

    // keyvalue methds

    // Omitted keyValue() due to return value of void pointer, which cannot be used safely in Rust

    /// Returns the number of bytes needed to store the key value, including the
    /// NULL terminator.
    pub fn get_value_size(&self) -> usize {
        let ret_val = unsafe { elektra_sys::keyGetValueSize(self.ptr.as_ptr()) };
        // keyGetValueSize returns -1 on null pointers, but we can be sure self.ptr is valid
        // so this conversion is safe
        ret_val as usize
    }

    /// Sets the value of the key to the supplied string.
    /// # Panics
    /// Panics if the provided string contains internal nul bytes.
    pub fn set_string(&mut self, value: &str) {
        let cptr = CString::new(value).unwrap();
        unsafe { keySetString(self.ptr.as_ptr(), cptr.as_ptr()) };
    }

    /// Returns the string value of the key if the type of the key is string, an error if it's binary.
    /// # Panics
    /// Panics if the underlying string cannot be converted to UTF-8.
    pub fn get_string(&self) -> Result<&str, KeyError> {
        if self.is_binary() {
            return Err(KeyError::TypeMismatch);
        }
        let c_str = unsafe { CStr::from_ptr(elektra_sys::keyString(self.ptr.as_ref())) };
        Ok(c_str.to_str().unwrap())
    }

    /// Sets the key's binary content to the supplied data.
    pub fn set_binary(&mut self, data: &[u8]) {
        unsafe {
            elektra_sys::keySetBinary(
                self.ptr.as_ptr(),
                data.as_ptr() as *const std::os::raw::c_void,
                data.len(),
            );
        }
    }

    /// Returns the keys binary content
    /// Returns a TypeMismatch if the key is of type string
    pub fn get_binary(&self) -> Result<Vec<u8>, KeyError> {
        if self.is_string() {
            return Err(KeyError::TypeMismatch);
        }
        let mut vec: Vec<u8> = Vec::with_capacity(self.get_value_size());

        let ret_val = unsafe {
            elektra_sys::keyGetBinary(
                self.ptr.as_ptr(),
                vec.as_mut_ptr() as *mut std::os::raw::c_void,
                vec.capacity(),
            )
        };

        if ret_val >= 0 {
            unsafe { vec.set_len(ret_val as usize) };
            Ok(vec)
        } else {
            // Since the function checks for is_string, a type mismatch is caught earlier
            // So this error can only occur as a result of a logic error in the program
            panic!("maxSize is 0, too small or too large.");
        }
    }

    // keytest methods

    /// Returns true if the key has a binary value.
    pub fn is_binary(&self) -> bool {
        unsafe { elektra_sys::keyIsBinary(self.ptr.as_ptr()) == 1 }
    }

    /// Returns true if the key has a string value.
    pub fn is_string(&self) -> bool {
        unsafe { elektra_sys::keyIsString(self.ptr.as_ptr()) == 1 }
    }

    /// Returns true if other is below self
    /// # Examples
    /// ```
    /// use elektra::Key;
    /// let key = Key::new("user/sw/app").unwrap();
    /// let key2 = Key::new("user/sw/app/key").unwrap();
    /// assert!(key2.is_below(&key));
    /// ```
    pub fn is_below(&self, other: &Self) -> bool {
        unsafe {
            elektra_sys::keyIsBelow(
                other.ptr.as_ptr() as *const elektra_sys::Key,
                self.ptr.as_ptr() as *const elektra_sys::Key,
            ) == 1
        }
    }

    /// Return a duplicate of the key.
    pub fn duplicate(&self) -> Key {
        let dup_ptr = unsafe { keyDup(self.ptr.as_ptr()) };
        Key::from(dup_ptr)
    }
}

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

    #[test]
    fn can_write_read_key() {
        let key_name = "user/test/key";
        let key = Key::new(key_name).unwrap();
        assert_eq!(key.get_name(), key_name);
    }

    #[test]
    fn can_write_read_key_value() {
        let key_name = "user/test/key";
        let utf8_value = "😃";
        let mut key = Key::new(key_name).unwrap();
        key.set_string(utf8_value);
        assert_eq!(key.get_name(), key_name);
        assert_eq!(key.get_string().unwrap(), utf8_value);
    }

    #[test]
    fn can_duplicate_key() {
        let key_name = "user/test/key";
        let mut key_dup;
        {
            let key = Key::new(key_name).unwrap();
            key_dup = Some(key.duplicate());
            // key is dropped here
        }
        assert_eq!(key_dup.unwrap().get_name(), key_name);
    }

    #[test]
    fn can_write_read_binary() {
        let mut key = Key::new("user/test/rust").unwrap();
        let binary_content: [u8; 7] = [25, 34, 0, 254, 1, 0, 7];
        key.set_binary(&binary_content);
        let read_content = key.get_binary().unwrap();
        assert_eq!(read_content, binary_content);
    }
    #[test]
    fn can_write_read_empty_binary() {
        let mut key = Key::new("user/test/binary").unwrap();
        let binary_content: [u8; 0] = [];
        key.set_binary(&binary_content);
        // set_binary does not set binary flag, size is 0
        // so get_binary returns error
        let err = key.get_binary().unwrap_err();
        assert_eq!(err, KeyError::TypeMismatch);
    }

    #[test]
    fn equality_is_exclusive() {
        let key = Key::new("user/test/exclusive").unwrap();
        let key2 = Key::new("dir/test/exclusive").unwrap();

        assert!(!(key != key));
        assert!(key == key);

        assert!(!(key == key2));
        assert!(key != key2);
    }

    #[test]
    fn equality_is_reflexive() {
        let key = Key::new("user/test/reflexive").unwrap();
        assert!(key == key);
    }

    #[test]
    fn equality_is_symmetric() {
        let key = Key::new("user/test/symmetric").unwrap();
        let key_dup = Key::new("user/test/symmetric").unwrap();

        assert!(key_dup == key);
        assert!(key == key_dup);
    }

    #[test]
    fn equality_is_transitive() {
        let key = Key::new("user/test/transitive").unwrap();
        let key2 = Key::new("user/test/transitive").unwrap();
        let key3 = Key::new("user/test/transitive").unwrap();

        assert!(key == key2);
        assert!(key2 == key3);
        assert!(key == key3);
    }

    #[test]
    fn keys_are_ordered() {
        let key = Key::new("user/test/a").unwrap();
        let key2 = Key::new("user/test/b").unwrap();
        let key3 = Key::new("user/test/c").unwrap();

        assert!(key != key2);
        assert!(key < key2);
        assert!(key2 > key);
        // Check for antisymmetry
        assert!(!(key > key2));
        assert!(!(key2 < key));

        // Check for transitivity
        assert!(key2 < key3);
        assert!(key < key3);
    }

    #[test]
    fn keys_are_ordered_with_metadata() {
        // TODO Add once it's possible to add metadata
        //Key * k1 = keyNew("user/a", KEY_OWNER, "markus", KEY_END);
        //Key * k2 = keyNew("user/a", KEY_OWNER, "max", KEY_END);
        // keyCmp(k1,k2) < 0
        // keyCmp(k2,k1) > 0
        assert!(5 + 2 == 7);
    }
}
<commit_msg>Rust: Implement all keytest methods<commit_after>use elektra_sys::{keyDel, keyDup, keyName, keyNew, keySetName, keySetString};
use std::error::Error;
use std::ffi::{CStr, CString};
use std::fmt;
use std::ptr::NonNull;

#[derive(Debug, PartialEq)]
pub enum KeyError {
    InvalidName,
    TypeMismatch,
    // TypeConversion,
    // NotFoundException
}

impl fmt::Display for KeyError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        match self {
            KeyError::InvalidName => write!(f, "Key has an invalid name"),
            KeyError::TypeMismatch => write!(f, "Binary/String key mismatch, use the appropriate method for your key type, get_string or get_binary"),
            // _ => unimplemented!(),
        }
    }
}

impl Error for KeyError {}

#[derive(Debug)]
pub struct Key {
    ptr: NonNull<elektra_sys::Key>,
}

impl Drop for Key {
    fn drop(&mut self) {
        println!("Drop {:?}", self);
        unsafe { keyDel(self.ptr.as_ptr()) };
    }
}

impl PartialEq for Key {
    fn eq(&self, other: &Self) -> bool {
        unsafe {
            elektra_sys::keyCmp(
                self.ptr.as_ptr() as *const elektra_sys::Key,
                other.ptr.as_ptr() as *const elektra_sys::Key,
            ) == 0
        }
    }
}

impl Eq for Key {}

impl Ord for Key {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        let cmp = unsafe {
            elektra_sys::keyCmp(
                self.ptr.as_ptr() as *const elektra_sys::Key,
                other.ptr.as_ptr() as *const elektra_sys::Key,
            )
        };

        if cmp < 0 {
            std::cmp::Ordering::Less
        } else if cmp == 0 {
            std::cmp::Ordering::Equal
        } else {
            std::cmp::Ordering::Greater
        }
    }
}

impl PartialOrd for Key {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl Key {
    /// Construct a new key with a name
    pub fn new(name: &str) -> Result<Key, KeyError> {
        let mut key = Key::new_empty();
        key.set_name(name)?;
        Ok(key)
    }

    /// Construct a new empty key
    pub fn new_empty() -> Key {
        let key_ptr = unsafe { keyNew(0 as *const i8) };
        Key::from(key_ptr)
    }

    /// Construct a new key from a raw key pointer
    pub fn from(ptr: *mut elektra_sys::Key) -> Key {
        Key {
            ptr: NonNull::new(ptr).unwrap(),
        }
    }

    /// Set the name of a key. Must adhere to the rules for keynames otherwise an error is returned.
    /// Returns the size in bytes of this new key name including the ending NUL.
    /// # Examples
    /// ```
    /// use elektra::Key;
    /// let mut key = Key::new_empty();
    /// key.set_name("user/test/rust").unwrap();
    /// assert_eq!(key.get_name(), "user/test/rust");
    /// ```
    /// # Panics
    /// Panics if the provided string contains internal nul bytes.
    pub fn set_name(&mut self, name: &str) -> Result<u32, KeyError> {
        let cptr = CString::new(name).unwrap();
        let ret_val = unsafe { keySetName(self.ptr.as_ptr(), cptr.as_ptr()) };

        if ret_val > 0 {
            Ok(ret_val as u32)
        } else {
            Err(KeyError::InvalidName)
        }
    }

    /// Return the name of the key as a borrowed slice.
    pub fn get_name(&self) -> &str {
        let c_str = unsafe { CStr::from_ptr(keyName(self.ptr.as_ref())) };
        c_str.to_str().unwrap()
    }

    // keyvalue methds

    // Omitted keyValue() due to return value of void pointer, which cannot be used safely in Rust

    /// Returns the number of bytes needed to store the key value, including the
    /// NULL terminator.
    pub fn get_value_size(&self) -> usize {
        let ret_val = unsafe { elektra_sys::keyGetValueSize(self.ptr.as_ptr()) };
        // keyGetValueSize returns -1 on null pointers, but we can be sure self.ptr is valid
        // so this conversion is safe
        ret_val as usize
    }

    /// Sets the value of the key to the supplied string.
    /// # Panics
    /// Panics if the provided string contains internal nul bytes.
    pub fn set_string(&mut self, value: &str) {
        let cptr = CString::new(value).unwrap();
        unsafe { keySetString(self.ptr.as_ptr(), cptr.as_ptr()) };
    }

    /// Returns the string value of the key if the type of the key is string, an error if it's binary.
    /// # Panics
    /// Panics if the underlying string cannot be converted to UTF-8.
    pub fn get_string(&self) -> Result<&str, KeyError> {
        if self.is_binary() {
            return Err(KeyError::TypeMismatch);
        }
        let c_str = unsafe { CStr::from_ptr(elektra_sys::keyString(self.ptr.as_ref())) };
        Ok(c_str.to_str().unwrap())
    }

    /// Sets the key's binary content to the supplied data.
    pub fn set_binary(&mut self, data: &[u8]) {
        unsafe {
            elektra_sys::keySetBinary(
                self.ptr.as_ptr(),
                data.as_ptr() as *const std::os::raw::c_void,
                data.len(),
            );
        }
    }

    /// Returns the keys binary content
    /// Returns a TypeMismatch if the key is of type string
    pub fn get_binary(&self) -> Result<Vec<u8>, KeyError> {
        if self.is_string() {
            return Err(KeyError::TypeMismatch);
        }
        let mut vec: Vec<u8> = Vec::with_capacity(self.get_value_size());

        let ret_val = unsafe {
            elektra_sys::keyGetBinary(
                self.ptr.as_ptr(),
                vec.as_mut_ptr() as *mut std::os::raw::c_void,
                vec.capacity(),
            )
        };

        if ret_val >= 0 {
            unsafe { vec.set_len(ret_val as usize) };
            Ok(vec)
        } else {
            // Since the function checks for is_string, a type mismatch is caught earlier
            // So this error can only occur as a result of a logic error in the program
            panic!("maxSize is 0, too small or too large.");
        }
    }

    // keytest methods

    /// Returns true if the key has a binary value.
    pub fn is_binary(&self) -> bool {
        unsafe { elektra_sys::keyIsBinary(self.ptr.as_ptr()) == 1 }
    }

    /// Returns true if the key has a string value.
    pub fn is_string(&self) -> bool {
        unsafe { elektra_sys::keyIsString(self.ptr.as_ptr()) == 1 }
    }

    /// Returns true if other is below self
    /// # Examples
    /// ```
    /// use elektra::Key;
    /// let key = Key::new("user/sw/app").unwrap();
    /// let key2 = Key::new("user/sw/app/folder/key").unwrap();
    /// assert!(key2.is_below(&key));
    /// ```
    pub fn is_below(&self, other: &Self) -> bool {
        unsafe {
            elektra_sys::keyIsBelow(
                other.ptr.as_ptr() as *const elektra_sys::Key,
                self.ptr.as_ptr() as *const elektra_sys::Key,
            ) == 1
        }
    }

    /// Returns true if other is *directly* below self
    /// # Examples
    /// ```
    /// use elektra::Key;
    /// let key = Key::new("user/sw/app").unwrap();
    /// let key2 = Key::new("user/sw/app/key").unwrap();
    /// assert!(key2.is_direct_below(&key));
    /// ```
    pub fn is_direct_below(&self, other: &Self) -> bool {
        unsafe {
            elektra_sys::keyIsDirectBelow(
                other.ptr.as_ptr() as *const elektra_sys::Key,
                self.ptr.as_ptr() as *const elektra_sys::Key,
            ) == 1
        }
    }

    /// Returns true if the key is inactive.
    /// In Elektra terminology a hierarchy of keys is inactive if the
    /// rootkey's basename starts with '.'. So a key is also inactive
    /// if it is below an inactive key. For example, `user/key/.hidden`
    /// is inactive and so is `user/.hidden/below`.
    pub fn is_inactive(&self) -> bool {
        unsafe { elektra_sys::keyIsInactive(self.ptr.as_ptr() as *const elektra_sys::Key) == 1 }
    }

    // TODO: CPP Bindings do not implement this.
    // Since is_below flips the order, this should be the case here too.
    // But does this break any usage?
    /// Information about the relation in the hierarchy between two keys.
    // pub fn rel(&self, other: &Self) -> i32 {
    //     unsafe {
    //         elektra_sys::keyRel(
    //             self.ptr.as_ptr() as *const elektra_sys::Key,
    //             other.ptr.as_ptr() as *const elektra_sys::Key,
    //         )
    //     }
    // }

    /// Return a duplicate of the key.
    pub fn duplicate(&self) -> Key {
        let dup_ptr = unsafe { keyDup(self.ptr.as_ptr()) };
        Key::from(dup_ptr)
    }
}

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

    #[test]
    fn can_write_read_key() {
        let key_name = "user/test/key";
        let key = Key::new(key_name).unwrap();
        assert_eq!(key.get_name(), key_name);
    }

    #[test]
    fn can_write_read_key_value() {
        let key_name = "user/test/key";
        let utf8_value = "😃";
        let mut key = Key::new(key_name).unwrap();
        key.set_string(utf8_value);
        assert_eq!(key.get_name(), key_name);
        assert_eq!(key.get_string().unwrap(), utf8_value);
    }

    #[test]
    fn can_duplicate_key() {
        let key_name = "user/test/key";
        let mut key_dup;
        {
            let key = Key::new(key_name).unwrap();
            key_dup = Some(key.duplicate());
            // key is dropped here
        }
        assert_eq!(key_dup.unwrap().get_name(), key_name);
    }

    #[test]
    fn can_write_read_binary() {
        let mut key = Key::new("user/test/rust").unwrap();
        let binary_content: [u8; 7] = [25, 34, 0, 254, 1, 0, 7];
        key.set_binary(&binary_content);
        let read_content = key.get_binary().unwrap();
        assert_eq!(read_content, binary_content);
    }
    #[test]
    fn can_write_read_empty_binary() {
        let mut key = Key::new("user/test/binary").unwrap();
        let binary_content: [u8; 0] = [];
        key.set_binary(&binary_content);
        // set_binary does not set binary flag, size is 0
        // so get_binary returns error
        let err = key.get_binary().unwrap_err();
        assert_eq!(err, KeyError::TypeMismatch);
    }

    #[test]
    fn equality_is_exclusive() {
        let key = Key::new("user/test/exclusive").unwrap();
        let key2 = Key::new("dir/test/exclusive").unwrap();

        assert!(!(key != key));
        assert!(key == key);

        assert!(!(key == key2));
        assert!(key != key2);
    }

    #[test]
    fn equality_is_reflexive() {
        let key = Key::new("user/test/reflexive").unwrap();
        assert!(key == key);
    }

    #[test]
    fn equality_is_symmetric() {
        let key = Key::new("user/test/symmetric").unwrap();
        let key_dup = Key::new("user/test/symmetric").unwrap();

        assert!(key_dup == key);
        assert!(key == key_dup);
    }

    #[test]
    fn equality_is_transitive() {
        let key = Key::new("user/test/transitive").unwrap();
        let key2 = Key::new("user/test/transitive").unwrap();
        let key3 = Key::new("user/test/transitive").unwrap();

        assert!(key == key2);
        assert!(key2 == key3);
        assert!(key == key3);
    }

    #[test]
    fn keys_are_ordered() {
        let key = Key::new("user/test/a").unwrap();
        let key2 = Key::new("user/test/b").unwrap();
        let key3 = Key::new("user/test/c").unwrap();

        assert!(key != key2);
        assert!(key < key2);
        assert!(key2 > key);
        // Check for antisymmetry
        assert!(!(key > key2));
        assert!(!(key2 < key));

        // Check for transitivity
        assert!(key2 < key3);
        assert!(key < key3);
    }

    #[test]
    fn keys_are_ordered_with_metadata() {
        // TODO Add once it's possible to add metadata
        //Key * k1 = keyNew("user/a", KEY_OWNER, "markus", KEY_END);
        //Key * k2 = keyNew("user/a", KEY_OWNER, "max", KEY_END);
        // keyCmp(k1,k2) < 0
        // keyCmp(k2,k1) > 0
        assert!(5 + 2 == 7);
    }
}
<|endoftext|>


<commit_before>use error::Result;
use serde;
use std::{io, slice};

/// An optional Read trait for advanced Bincode usage.
///
/// It is highly recommended to use bincode with `io::Read` or `&[u8]` before
/// implementing a custom `BincodeRead`.
pub trait BincodeRead<'storage>: io::Read {
    /// Forwards reading `length` bytes of a string on to the serde reader.
    fn forward_read_str<V>(&mut self, length: usize, visitor: V) -> Result<V::Value>
    where
        V: serde::de::Visitor<'storage>;

    /// Return the first `length` bytes of the internal byte buffer.
    fn get_byte_buffer(&mut self, length: usize) -> Result<Vec<u8>>;

    /// Forwards reading `length` bytes on to the serde reader.
    fn forward_read_bytes<V>(&mut self, length: usize, visitor: V) -> Result<V::Value>
    where
        V: serde::de::Visitor<'storage>;
}

/// A BincodeRead implementation for byte slices
/// NOT A PART OF THE STABLE PUBLIC API
#[doc(hidden)]
pub struct SliceReader<'storage> {
    slice: &'storage [u8],
}

/// A BincodeRead implementation for io::Readers
/// NOT A PART OF THE STABLE PUBLIC API
#[doc(hidden)]
pub struct IoReader<R> {
    reader: R,
    temp_buffer: Vec<u8>,
}

impl<'storage> SliceReader<'storage> {
    /// Constructs a slice reader
    pub fn new(bytes: &'storage [u8]) -> SliceReader<'storage> {
        SliceReader { slice: bytes }
    }
}

impl<R> IoReader<R> {
    /// Constructs an IoReadReader
    pub fn new(r: R) -> IoReader<R> {
        IoReader {
            reader: r,
            temp_buffer: vec![],
        }
    }
}

impl<'storage> io::Read for SliceReader<'storage> {
    #[inline(always)]
    fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
        (&mut self.slice).read(out)
    }
    #[inline(always)]
    fn read_exact(&mut self, out: &mut [u8]) -> io::Result<()> {
        (&mut self.slice).read_exact(out)
    }
}

impl<R: io::Read> io::Read for IoReader<R> {
    #[inline(always)]
    fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
        self.reader.read(out)
    }
    #[inline(always)]
    fn read_exact(&mut self, out: &mut [u8]) -> io::Result<()> {
        self.reader.read_exact(out)
    }
}

impl<'storage> SliceReader<'storage> {
    #[inline(always)]
    fn unexpected_eof() -> Box<::ErrorKind> {
        return Box::new(::ErrorKind::Io(io::Error::new(
            io::ErrorKind::UnexpectedEof,
            "",
        )));
    }
}

impl<'storage> BincodeRead<'storage> for SliceReader<'storage> {
    #[inline(always)]
    fn forward_read_str<V>(&mut self, length: usize, visitor: V) -> Result<V::Value>
    where
        V: serde::de::Visitor<'storage>,
    {
        use ErrorKind;
        if length > self.slice.len() {
            return Err(SliceReader::unexpected_eof());
        }

        let string = match ::std::str::from_utf8(&self.slice[..length]) {
            Ok(s) => s,
            Err(e) => return Err(ErrorKind::InvalidUtf8Encoding(e).into()),
        };
        let r = visitor.visit_borrowed_str(string);
        self.slice = &self.slice[length..];
        r
    }

    #[inline(always)]
    fn get_byte_buffer(&mut self, length: usize) -> Result<Vec<u8>> {
        if length > self.slice.len() {
            return Err(SliceReader::unexpected_eof());
        }

        let r = &self.slice[..length];
        self.slice = &self.slice[length..];
        Ok(r.to_vec())
    }

    #[inline(always)]
    fn forward_read_bytes<V>(&mut self, length: usize, visitor: V) -> Result<V::Value>
    where
        V: serde::de::Visitor<'storage>,
    {
        if length > self.slice.len() {
            return Err(SliceReader::unexpected_eof());
        }

        let r = visitor.visit_borrowed_bytes(&self.slice[..length]);
        self.slice = &self.slice[length..];
        r
    }
}

impl<R> IoReader<R>
where
    R: io::Read,
{
    fn fill_buffer(&mut self, length: usize) -> Result<()> {
        // We first reserve the space needed in our buffer.
        let current_length = self.temp_buffer.len();
        if length > current_length {
            self.temp_buffer.reserve_exact(length - current_length);
        }

        // Then create a slice with the length as our desired length. This is
        // safe as long as we only write (no reads) to this buffer, because
        // `reserve_exact` above has allocated this space.
        let buf = unsafe {
            slice::from_raw_parts_mut(self.temp_buffer.as_mut_ptr(), length)
        };

        // This method is assumed to properly handle slices which include
        // uninitialized bytes (as ours does). See discussion at the link below.
        // https://github.com/servo/bincode/issues/260
        self.reader.read_exact(buf)?;

        // Only after `read_exact` successfully returns do we set the buffer
        // length. By doing this after the call to `read_exact`, we can avoid
        // exposing uninitialized memory in the case of `read_exact` returning
        // an error.
        unsafe {
            self.temp_buffer.set_len(length);
        }

        Ok(())
    }
}

impl<'a, R> BincodeRead<'a> for IoReader<R>
where
    R: io::Read,
{
    fn forward_read_str<V>(&mut self, length: usize, visitor: V) -> Result<V::Value>
    where
        V: serde::de::Visitor<'a>,
    {
        self.fill_buffer(length)?;

        let string = match ::std::str::from_utf8(&self.temp_buffer[..]) {
            Ok(s) => s,
            Err(e) => return Err(::ErrorKind::InvalidUtf8Encoding(e).into()),
        };

        let r = visitor.visit_str(string);
        r
    }

    fn get_byte_buffer(&mut self, length: usize) -> Result<Vec<u8>> {
        self.fill_buffer(length)?;
        Ok(::std::mem::replace(&mut self.temp_buffer, Vec::new()))
    }

    fn forward_read_bytes<V>(&mut self, length: usize, visitor: V) -> Result<V::Value>
    where
        V: serde::de::Visitor<'a>,
    {
        self.fill_buffer(length)?;
        let r = visitor.visit_bytes(&self.temp_buffer[..]);
        r
    }
}
<commit_msg>improve documentation of BincodeRead<commit_after>use error::Result;
use serde;
use std::{io, slice};

/// An optional Read trait for advanced Bincode usage.
///
/// It is highly recommended to use bincode with `io::Read` or `&[u8]` before
/// implementing a custom `BincodeRead`.
///
/// The forward_read_* methods are necessary because some byte sources want
/// to pass a long-lived borrow to the visitor and others want to pass a
/// transient slice.
pub trait BincodeRead<'storage>: io::Read {
    /// Check that the next `length` bytes are a valid string and pass
    /// it on to the serde reader.
    fn forward_read_str<V>(&mut self, length: usize, visitor: V) -> Result<V::Value>
    where
        V: serde::de::Visitor<'storage>;

    /// Transfer ownership of the next `length` bytes to the caller.
    fn get_byte_buffer(&mut self, length: usize) -> Result<Vec<u8>>;

    /// Pass a slice of the next `length` bytes on to the serde reader.
    fn forward_read_bytes<V>(&mut self, length: usize, visitor: V) -> Result<V::Value>
    where
        V: serde::de::Visitor<'storage>;
}

/// A BincodeRead implementation for byte slices
/// NOT A PART OF THE STABLE PUBLIC API
#[doc(hidden)]
pub struct SliceReader<'storage> {
    slice: &'storage [u8],
}

/// A BincodeRead implementation for io::Readers
/// NOT A PART OF THE STABLE PUBLIC API
#[doc(hidden)]
pub struct IoReader<R> {
    reader: R,
    temp_buffer: Vec<u8>,
}

impl<'storage> SliceReader<'storage> {
    /// Constructs a slice reader
    pub fn new(bytes: &'storage [u8]) -> SliceReader<'storage> {
        SliceReader { slice: bytes }
    }
}

impl<R> IoReader<R> {
    /// Constructs an IoReadReader
    pub fn new(r: R) -> IoReader<R> {
        IoReader {
            reader: r,
            temp_buffer: vec![],
        }
    }
}

impl<'storage> io::Read for SliceReader<'storage> {
    #[inline(always)]
    fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
        (&mut self.slice).read(out)
    }
    #[inline(always)]
    fn read_exact(&mut self, out: &mut [u8]) -> io::Result<()> {
        (&mut self.slice).read_exact(out)
    }
}

impl<R: io::Read> io::Read for IoReader<R> {
    #[inline(always)]
    fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
        self.reader.read(out)
    }
    #[inline(always)]
    fn read_exact(&mut self, out: &mut [u8]) -> io::Result<()> {
        self.reader.read_exact(out)
    }
}

impl<'storage> SliceReader<'storage> {
    #[inline(always)]
    fn unexpected_eof() -> Box<::ErrorKind> {
        return Box::new(::ErrorKind::Io(io::Error::new(
            io::ErrorKind::UnexpectedEof,
            "",
        )));
    }
}

impl<'storage> BincodeRead<'storage> for SliceReader<'storage> {
    #[inline(always)]
    fn forward_read_str<V>(&mut self, length: usize, visitor: V) -> Result<V::Value>
    where
        V: serde::de::Visitor<'storage>,
    {
        use ErrorKind;
        if length > self.slice.len() {
            return Err(SliceReader::unexpected_eof());
        }

        let string = match ::std::str::from_utf8(&self.slice[..length]) {
            Ok(s) => s,
            Err(e) => return Err(ErrorKind::InvalidUtf8Encoding(e).into()),
        };
        let r = visitor.visit_borrowed_str(string);
        self.slice = &self.slice[length..];
        r
    }

    #[inline(always)]
    fn get_byte_buffer(&mut self, length: usize) -> Result<Vec<u8>> {
        if length > self.slice.len() {
            return Err(SliceReader::unexpected_eof());
        }

        let r = &self.slice[..length];
        self.slice = &self.slice[length..];
        Ok(r.to_vec())
    }

    #[inline(always)]
    fn forward_read_bytes<V>(&mut self, length: usize, visitor: V) -> Result<V::Value>
    where
        V: serde::de::Visitor<'storage>,
    {
        if length > self.slice.len() {
            return Err(SliceReader::unexpected_eof());
        }

        let r = visitor.visit_borrowed_bytes(&self.slice[..length]);
        self.slice = &self.slice[length..];
        r
    }
}

impl<R> IoReader<R>
where
    R: io::Read,
{
    fn fill_buffer(&mut self, length: usize) -> Result<()> {
        // We first reserve the space needed in our buffer.
        let current_length = self.temp_buffer.len();
        if length > current_length {
            self.temp_buffer.reserve_exact(length - current_length);
        }

        // Then create a slice with the length as our desired length. This is
        // safe as long as we only write (no reads) to this buffer, because
        // `reserve_exact` above has allocated this space.
        let buf = unsafe {
            slice::from_raw_parts_mut(self.temp_buffer.as_mut_ptr(), length)
        };

        // This method is assumed to properly handle slices which include
        // uninitialized bytes (as ours does). See discussion at the link below.
        // https://github.com/servo/bincode/issues/260
        self.reader.read_exact(buf)?;

        // Only after `read_exact` successfully returns do we set the buffer
        // length. By doing this after the call to `read_exact`, we can avoid
        // exposing uninitialized memory in the case of `read_exact` returning
        // an error.
        unsafe {
            self.temp_buffer.set_len(length);
        }

        Ok(())
    }
}

impl<'a, R> BincodeRead<'a> for IoReader<R>
where
    R: io::Read,
{
    fn forward_read_str<V>(&mut self, length: usize, visitor: V) -> Result<V::Value>
    where
        V: serde::de::Visitor<'a>,
    {
        self.fill_buffer(length)?;

        let string = match ::std::str::from_utf8(&self.temp_buffer[..]) {
            Ok(s) => s,
            Err(e) => return Err(::ErrorKind::InvalidUtf8Encoding(e).into()),
        };

        let r = visitor.visit_str(string);
        r
    }

    fn get_byte_buffer(&mut self, length: usize) -> Result<Vec<u8>> {
        self.fill_buffer(length)?;
        Ok(::std::mem::replace(&mut self.temp_buffer, Vec::new()))
    }

    fn forward_read_bytes<V>(&mut self, length: usize, visitor: V) -> Result<V::Value>
    where
        V: serde::de::Visitor<'a>,
    {
        self.fill_buffer(length)?;
        let r = visitor.visit_bytes(&self.temp_buffer[..]);
        r
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::f64::EPSILON;

lazy_static! {
    static ref QGRAMS: HashMap<&'static str, f64> = {
        let mut map = HashMap::new();
        let f = include_str!("data/quadgrams.txt");

        let mut total: usize = 0;
        let mut qgrams = Vec::new();

        for line in f.lines() {
            let mut iter = line.split(' ');
            let qgram = iter.next().unwrap();
            let count = iter.next().unwrap().parse().unwrap();

            qgrams.push((qgram, count));
            total += count;
        }

        for (qgram, n) in qgrams {
            let frequency = (n as f64) / (total as f64);
            map.insert(qgram, frequency.ln());
        }

        map
    };
}

/// Strips all non-alphabetic characters from the given message string and
/// returns the sum of the log-probabilities of each quadgram substring.
pub fn qgram_score(msg: &str) -> f64 {
    let msg: String = msg.chars().filter(|&c| c.is_alphabetic()).collect();

    if msg.len() < 4 {
        panic!("Input string must be longer than 4 characters.");
    }

    (0..(msg.len() - 3))
        .map(|i| *QGRAMS.get(&msg[i..i+4]).unwrap_or(&EPSILON.ln()))
        .sum()
}

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

    #[test]
    fn sensible_qgram_scores() {
        assert!(qgram_score("AN ENGLISH PHRASE") > qgram_score("ESARHP HSILGNE NA"));
    }

    #[test]
    #[should_panic]
    fn invalid_qgram_check() {
        qgram_score("ABC");
    }
}
<commit_msg>Improve quadgram scoring performance<commit_after>use std::f64::EPSILON;
use super::CharIndex;

lazy_static! {
    static ref QGRAMS: Vec<f64> = {
        let f = include_str!("data/quadgrams.txt");

        let mut total: usize = 0;
        let mut qgrams = Vec::new();

        for line in f.lines() {
            let mut iter = line.split(' ');
            let qgram = iter.next().unwrap();
            let count = iter.next().unwrap().parse().unwrap();

            qgrams.push((qgram, count));
            total += count;
        }

        let mut v = vec![EPSILON.ln(); 456_976];

        for (qgram, n) in qgrams {
            let frequency = (n as f64) / (total as f64);
            let index = qgram.chars().fold(0, |acc, c| 26 * acc + c.index());
            v[index] = frequency.ln();
        }

        v
    };
}

/// Strips all non-alphabetic characters from the given message string and
/// returns the sum of the log-probabilities of each quadgram substring.
pub fn qgram_score(msg: &str) -> f64 {
    let msg: Vec<usize> = msg
        .chars()
        .filter(|&c| c.is_alphabetic())
        .map(|c| c.index())
        .collect();

    if msg.len() < 4 {
        panic!("Input string must be longer than 4 characters.");
    }

    let mut sum = 0.0;

    for i in 0..(msg.len() - 3) {
        let a = msg[i];
        let b = msg[i+1];
        let c = msg[i+2];
        let d = msg[i+3];

        let index = (((a * 26) + b) * 26 + c) * 26 + d;
        sum += QGRAMS[index];
    }

    sum
}

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

    #[test]
    fn qgram_estimate() {
        // Score should be approximately -138.3319940227875
        assert!((qgram_score("THE QUICK BROWN FOX") + 138.3).abs() < 0.1);
    }

    #[test]
    fn sensible_qgram_scores() {
        assert!(qgram_score("AN ENGLISH PHRASE") > qgram_score("ESARHP HSILGNE NA"));
    }

    #[test]
    #[should_panic]
    fn invalid_qgram_check() {
        qgram_score("ABC");
    }
}
<|endoftext|>