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

#[doc(keyword = "fn")]
//
/// The `fn` keyword.
///
/// The `fn` keyword is used to declare a function.
///
/// Example:
///
/// ```rust
/// fn some_function() {
///     // code goes in here
/// }
/// ```
///
/// For more information about functions, take a look at the [Rust Book][book].
///
/// [book]: https://doc.rust-lang.org/book/second-edition/ch03-03-how-functions-work.html
mod fn_keyword { }

#[doc(keyword = "let")]
//
/// The `let` keyword.
///
/// The `let` keyword is used to declare a variable.
///
/// Example:
///
/// ```rust
/// # #![allow(unused_assignments)]
/// let x = 3; // We create a variable named `x` with the value `3`.
/// ```
///
/// By default, all variables are **not** mutable. If you want a mutable variable,
/// you'll have to use the `mut` keyword.
///
/// Example:
///
/// ```rust
/// # #![allow(unused_assignments)]
/// let mut x = 3; // We create a mutable variable named `x` with the value `3`.
///
/// x += 4; // `x` is now equal to `7`.
/// ```
///
/// For more information about the `let` keyword, take a look at the [Rust Book][book].
///
/// [book]: https://doc.rust-lang.org/book/second-edition/ch03-01-variables-and-mutability.html
mod let_keyword { }
<commit_msg>Add struct keyword doc<commit_after>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[doc(keyword = "fn")]
//
/// The `fn` keyword.
///
/// The `fn` keyword is used to declare a function.
///
/// Example:
///
/// ```rust
/// fn some_function() {
///     // code goes in here
/// }
/// ```
///
/// For more information about functions, take a look at the [Rust Book][book].
///
/// [book]: https://doc.rust-lang.org/book/second-edition/ch03-03-how-functions-work.html
mod fn_keyword { }

#[doc(keyword = "let")]
//
/// The `let` keyword.
///
/// The `let` keyword is used to declare a variable.
///
/// Example:
///
/// ```rust
/// # #![allow(unused_assignments)]
/// let x = 3; // We create a variable named `x` with the value `3`.
/// ```
///
/// By default, all variables are **not** mutable. If you want a mutable variable,
/// you'll have to use the `mut` keyword.
///
/// Example:
///
/// ```rust
/// # #![allow(unused_assignments)]
/// let mut x = 3; // We create a mutable variable named `x` with the value `3`.
///
/// x += 4; // `x` is now equal to `7`.
/// ```
///
/// For more information about the `let` keyword, take a look at the [Rust Book][book].
///
/// [book]: https://doc.rust-lang.org/book/second-edition/ch03-01-variables-and-mutability.html
mod let_keyword { }

#[doc(keyword = "struct")]
//
/// The `struct` keyword.
///
/// The `struct` keyword is used to define a struct type.
///
/// Example:
///
/// ```
/// struct Foo {
///     field1: u32,
///     field2: String,
/// }
/// ```
///
/// There are different kinds of structs. For more information, take a look at the
/// [Rust Book][book].
///
/// [book]: https://doc.rust-lang.org/book/second-edition/ch05-01-defining-structs.html
mod struct_keyword { }
<|endoftext|>


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

use fmt;
use sync::atomic::{AtomicUsize, Ordering};
use sync::{mutex, MutexGuard, PoisonError};
use sys_common::condvar as sys;
use sys_common::mutex as sys_mutex;
use sys_common::poison::{self, LockResult};
use time::Duration;

/// 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)]
#[stable(feature = "wait_timeout", since = "1.5.0")]
pub struct WaitTimeoutResult(bool);

impl WaitTimeoutResult {
    /// Returns whether the wait was known to have timed out.
    #[stable(feature = "wait_timeout", since = "1.5.0")]
    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.
///
/// Functions in this module will block the current **thread** of execution and
/// are bindings to system-provided condition variables where possible. Note
/// that this module places one additional restriction over the system condition
/// variables: each condvar can be used with precisely one mutex at runtime. Any
/// attempt to use multiple mutexes on the same condition variable will result
/// in a runtime panic. If this is not desired, then the unsafe primitives in
/// `sys` do not have this restriction but may result in undefined behavior.
///
/// # Examples
///
/// ```
/// use std::sync::{Arc, Mutex, Condvar};
/// 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().unwrap();
///     *started = true;
///     cvar.notify_one();
/// });
///
/// // wait for the thread to start up
/// let &(ref lock, ref cvar) = &*pair;
/// let mut started = lock.lock().unwrap();
/// while !*started {
///     started = cvar.wait(started).unwrap();
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Condvar {
    inner: Box<sys::Condvar>,
    mutex: AtomicUsize,
}

impl Condvar {
    /// Creates a new condition variable which is ready to be waited on and
    /// notified.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn new() -> Condvar {
        let mut c = Condvar {
            inner: box sys::Condvar::new(),
            mutex: AtomicUsize::new(0),
        };
        unsafe {
            c.inner.init();
        }
        c
    }

    /// 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.
    ///
    /// Note that this function is susceptible to spurious wakeups. Condition
    /// variables normally have a boolean predicate associated with them, and
    /// the predicate must always be checked each time this function returns to
    /// protect against spurious wakeups.
    ///
    /// # Errors
    ///
    /// This function will return an error if the mutex being waited on is
    /// poisoned when this thread re-acquires the lock. For more information,
    /// see information about poisoning on the Mutex type.
    ///
    /// # Panics
    ///
    /// This function will `panic!()` if it is used with more than one mutex
    /// over time. Each condition variable is dynamically bound to exactly one
    /// mutex to ensure defined behavior across platforms. If this functionality
    /// is not desired, then unsafe primitives in `sys` are provided.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>)
                       -> LockResult<MutexGuard<'a, T>> {
        let poisoned = unsafe {
            let lock = mutex::guard_lock(&guard);
            self.verify(lock);
            self.inner.wait(lock);
            mutex::guard_poison(&guard).get()
        };
        if poisoned {
            Err(PoisonError::new(guard))
        } else {
            Ok(guard)
        }
    }

    /// 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 `ms` milliseconds. 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 `ms`.
    ///
    /// Note that the best effort is made to ensure that the time waited is
    /// measured with a monotonic clock, and not affected by the changes made to
    /// the system time.
    ///
    /// The returned boolean is `false` only 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.
    #[stable(feature = "rust1", since = "1.0.0")]
    #[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::sync::Condvar::wait_timeout`")]
    pub fn wait_timeout_ms<'a, T>(&self, guard: MutexGuard<'a, T>, ms: u32)
                                  -> LockResult<(MutexGuard<'a, T>, bool)> {
        let res = self.wait_timeout(guard, Duration::from_millis(ms as u64));
        poison::map_result(res, |(a, b)| {
            (a, !b.timed_out())
        })
    }

    /// 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 `dur`. 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 `dur`.
    ///
    /// Note that the best effort is made to ensure that the time waited is
    /// measured with a monotonic clock, and not affected by the changes made to
    /// the system time.
    ///
    /// 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.
    #[stable(feature = "wait_timeout", since = "1.5.0")]
    pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>,
                               dur: Duration)
                               -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> {
        let (poisoned, result) = unsafe {
            let lock = mutex::guard_lock(&guard);
            self.verify(lock);
            let success = self.inner.wait_timeout(lock, dur);
            (mutex::guard_poison(&guard).get(), WaitTimeoutResult(!success))
        };
        if poisoned {
            Err(PoisonError::new((guard, result)))
        } else {
            Ok((guard, result))
        }
    }

    /// 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()`.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn notify_one(&self) {
        unsafe { self.inner.notify_one() }
    }

    /// 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()`.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn notify_all(&self) {
        unsafe { self.inner.notify_all() }
    }

    fn verify(&self, mutex: &sys_mutex::Mutex) {
        let addr = mutex as *const _ as usize;
        match self.mutex.compare_and_swap(0, addr, Ordering::SeqCst) {
            // If we got out 0, then we have successfully bound the mutex to
            // this cvar.
            0 => {}

            // If we get out a value that's the same as `addr`, then someone
            // already beat us to the punch.
            n if n == addr => {}

            // Anything else and we're using more than one mutex on this cvar,
            // which is currently disallowed.
            _ => panic!("attempted to use a condition variable with two \
                         mutexes"),
        }
    }
}

#[stable(feature = "std_debug", since = "1.15.0")]
impl fmt::Debug for Condvar {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("Condvar { .. }")
    }
}

#[stable(feature = "condvar_default", since = "1.9.0")]
impl Default for Condvar {
    /// Creates a `Condvar` which is ready to be waited on and notified.
    fn default() -> Condvar {
        Condvar::new()
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Drop for Condvar {
    fn drop(&mut self) {
        unsafe { self.inner.destroy() }
    }
}

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

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

    #[test]
    #[cfg_attr(target_os = "emscripten", ignore)]
    fn notify_one() {
        let m = Arc::new(Mutex::new(()));
        let m2 = m.clone();
        let c = Arc::new(Condvar::new());
        let c2 = c.clone();

        let g = m.lock().unwrap();
        let _t = thread::spawn(move|| {
            let _g = m2.lock().unwrap();
            c2.notify_one();
        });
        let g = c.wait(g).unwrap();
        drop(g);
    }

    #[test]
    #[cfg_attr(target_os = "emscripten", ignore)]
    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().unwrap();
                *cnt += 1;
                if *cnt == N {
                    tx.send(()).unwrap();
                }
                while *cnt != 0 {
                    cnt = cond.wait(cnt).unwrap();
                }
                tx.send(()).unwrap();
            });
        }
        drop(tx);

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

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

    #[test]
    #[cfg_attr(target_os = "emscripten", ignore)]
    fn wait_timeout_ms() {
        let m = Arc::new(Mutex::new(()));
        let m2 = m.clone();
        let c = Arc::new(Condvar::new());
        let c2 = c.clone();

        let g = m.lock().unwrap();
        let (g, _no_timeout) = c.wait_timeout(g, Duration::from_millis(1)).unwrap();
        // spurious wakeups mean this isn't necessarily true
        // assert!(!no_timeout);
        let _t = thread::spawn(move || {
            let _g = m2.lock().unwrap();
            c2.notify_one();
        });
        let (g, timeout_res) = c.wait_timeout(g, Duration::from_millis(u32::MAX as u64)).unwrap();
        assert!(!timeout_res.timed_out());
        drop(g);
    }

    #[test]
    #[should_panic]
    #[cfg_attr(target_os = "emscripten", ignore)]
    fn two_mutexes() {
        let m = Arc::new(Mutex::new(()));
        let m2 = m.clone();
        let c = Arc::new(Condvar::new());
        let c2 = c.clone();

        let mut g = m.lock().unwrap();
        let _t = thread::spawn(move|| {
            let _g = m2.lock().unwrap();
            c2.notify_one();
        });
        g = c.wait(g).unwrap();
        drop(g);

        let m = Mutex::new(());
        let _ = c.wait(m.lock().unwrap()).unwrap();
    }
}
<commit_msg>Rollup merge of #39486 - phungleson:tiny-doc-wording-change, r=alexcrichton<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use fmt;
use sync::atomic::{AtomicUsize, Ordering};
use sync::{mutex, MutexGuard, PoisonError};
use sys_common::condvar as sys;
use sys_common::mutex as sys_mutex;
use sys_common::poison::{self, LockResult};
use time::Duration;

/// 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)]
#[stable(feature = "wait_timeout", since = "1.5.0")]
pub struct WaitTimeoutResult(bool);

impl WaitTimeoutResult {
    /// Returns whether the wait was known to have timed out.
    #[stable(feature = "wait_timeout", since = "1.5.0")]
    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 a thread must block.
///
/// Functions in this module will block the current **thread** of execution and
/// are bindings to system-provided condition variables where possible. Note
/// that this module places one additional restriction over the system condition
/// variables: each condvar can be used with precisely one mutex at runtime. Any
/// attempt to use multiple mutexes on the same condition variable will result
/// in a runtime panic. If this is not desired, then the unsafe primitives in
/// `sys` do not have this restriction but may result in undefined behavior.
///
/// # Examples
///
/// ```
/// use std::sync::{Arc, Mutex, Condvar};
/// 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().unwrap();
///     *started = true;
///     cvar.notify_one();
/// });
///
/// // wait for the thread to start up
/// let &(ref lock, ref cvar) = &*pair;
/// let mut started = lock.lock().unwrap();
/// while !*started {
///     started = cvar.wait(started).unwrap();
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Condvar {
    inner: Box<sys::Condvar>,
    mutex: AtomicUsize,
}

impl Condvar {
    /// Creates a new condition variable which is ready to be waited on and
    /// notified.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn new() -> Condvar {
        let mut c = Condvar {
            inner: box sys::Condvar::new(),
            mutex: AtomicUsize::new(0),
        };
        unsafe {
            c.inner.init();
        }
        c
    }

    /// 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.
    ///
    /// Note that this function is susceptible to spurious wakeups. Condition
    /// variables normally have a boolean predicate associated with them, and
    /// the predicate must always be checked each time this function returns to
    /// protect against spurious wakeups.
    ///
    /// # Errors
    ///
    /// This function will return an error if the mutex being waited on is
    /// poisoned when this thread re-acquires the lock. For more information,
    /// see information about poisoning on the Mutex type.
    ///
    /// # Panics
    ///
    /// This function will `panic!()` if it is used with more than one mutex
    /// over time. Each condition variable is dynamically bound to exactly one
    /// mutex to ensure defined behavior across platforms. If this functionality
    /// is not desired, then unsafe primitives in `sys` are provided.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>)
                       -> LockResult<MutexGuard<'a, T>> {
        let poisoned = unsafe {
            let lock = mutex::guard_lock(&guard);
            self.verify(lock);
            self.inner.wait(lock);
            mutex::guard_poison(&guard).get()
        };
        if poisoned {
            Err(PoisonError::new(guard))
        } else {
            Ok(guard)
        }
    }

    /// 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 `ms` milliseconds. 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 `ms`.
    ///
    /// Note that the best effort is made to ensure that the time waited is
    /// measured with a monotonic clock, and not affected by the changes made to
    /// the system time.
    ///
    /// The returned boolean is `false` only 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.
    #[stable(feature = "rust1", since = "1.0.0")]
    #[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::sync::Condvar::wait_timeout`")]
    pub fn wait_timeout_ms<'a, T>(&self, guard: MutexGuard<'a, T>, ms: u32)
                                  -> LockResult<(MutexGuard<'a, T>, bool)> {
        let res = self.wait_timeout(guard, Duration::from_millis(ms as u64));
        poison::map_result(res, |(a, b)| {
            (a, !b.timed_out())
        })
    }

    /// 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 `dur`. 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 `dur`.
    ///
    /// Note that the best effort is made to ensure that the time waited is
    /// measured with a monotonic clock, and not affected by the changes made to
    /// the system time.
    ///
    /// 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.
    #[stable(feature = "wait_timeout", since = "1.5.0")]
    pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>,
                               dur: Duration)
                               -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> {
        let (poisoned, result) = unsafe {
            let lock = mutex::guard_lock(&guard);
            self.verify(lock);
            let success = self.inner.wait_timeout(lock, dur);
            (mutex::guard_poison(&guard).get(), WaitTimeoutResult(!success))
        };
        if poisoned {
            Err(PoisonError::new((guard, result)))
        } else {
            Ok((guard, result))
        }
    }

    /// 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()`.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn notify_one(&self) {
        unsafe { self.inner.notify_one() }
    }

    /// 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()`.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn notify_all(&self) {
        unsafe { self.inner.notify_all() }
    }

    fn verify(&self, mutex: &sys_mutex::Mutex) {
        let addr = mutex as *const _ as usize;
        match self.mutex.compare_and_swap(0, addr, Ordering::SeqCst) {
            // If we got out 0, then we have successfully bound the mutex to
            // this cvar.
            0 => {}

            // If we get out a value that's the same as `addr`, then someone
            // already beat us to the punch.
            n if n == addr => {}

            // Anything else and we're using more than one mutex on this cvar,
            // which is currently disallowed.
            _ => panic!("attempted to use a condition variable with two \
                         mutexes"),
        }
    }
}

#[stable(feature = "std_debug", since = "1.15.0")]
impl fmt::Debug for Condvar {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("Condvar { .. }")
    }
}

#[stable(feature = "condvar_default", since = "1.9.0")]
impl Default for Condvar {
    /// Creates a `Condvar` which is ready to be waited on and notified.
    fn default() -> Condvar {
        Condvar::new()
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Drop for Condvar {
    fn drop(&mut self) {
        unsafe { self.inner.destroy() }
    }
}

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

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

    #[test]
    #[cfg_attr(target_os = "emscripten", ignore)]
    fn notify_one() {
        let m = Arc::new(Mutex::new(()));
        let m2 = m.clone();
        let c = Arc::new(Condvar::new());
        let c2 = c.clone();

        let g = m.lock().unwrap();
        let _t = thread::spawn(move|| {
            let _g = m2.lock().unwrap();
            c2.notify_one();
        });
        let g = c.wait(g).unwrap();
        drop(g);
    }

    #[test]
    #[cfg_attr(target_os = "emscripten", ignore)]
    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().unwrap();
                *cnt += 1;
                if *cnt == N {
                    tx.send(()).unwrap();
                }
                while *cnt != 0 {
                    cnt = cond.wait(cnt).unwrap();
                }
                tx.send(()).unwrap();
            });
        }
        drop(tx);

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

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

    #[test]
    #[cfg_attr(target_os = "emscripten", ignore)]
    fn wait_timeout_ms() {
        let m = Arc::new(Mutex::new(()));
        let m2 = m.clone();
        let c = Arc::new(Condvar::new());
        let c2 = c.clone();

        let g = m.lock().unwrap();
        let (g, _no_timeout) = c.wait_timeout(g, Duration::from_millis(1)).unwrap();
        // spurious wakeups mean this isn't necessarily true
        // assert!(!no_timeout);
        let _t = thread::spawn(move || {
            let _g = m2.lock().unwrap();
            c2.notify_one();
        });
        let (g, timeout_res) = c.wait_timeout(g, Duration::from_millis(u32::MAX as u64)).unwrap();
        assert!(!timeout_res.timed_out());
        drop(g);
    }

    #[test]
    #[should_panic]
    #[cfg_attr(target_os = "emscripten", ignore)]
    fn two_mutexes() {
        let m = Arc::new(Mutex::new(()));
        let m2 = m.clone();
        let c = Arc::new(Condvar::new());
        let c2 = c.clone();

        let mut g = m.lock().unwrap();
        let _t = thread::spawn(move|| {
            let _g = m2.lock().unwrap();
            c2.notify_one();
        });
        g = c.wait(g).unwrap();
        drop(g);

        let m = Mutex::new(());
        let _ = c.wait(m.lock().unwrap()).unwrap();
    }
}
<|endoftext|>


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

//! Implementation of `std::os` functionality for unix systems

#![allow(unused_imports)] // lots of cfg code here

use os::unix::prelude::*;

use error::Error as StdError;
use ffi::{OsString, OsStr};
use fmt;
use io::{self, Read, Write};
use iter;
use marker::PhantomData;
use mem;
use memchr;
use path::{self, PathBuf};
use ptr;
use slice;
use str;
use sys_common::mutex::Mutex;
use sys::{cvt, fd, syscall};
use vec;

const TMPBUF_SZ: usize = 128;
static ENV_LOCK: Mutex = Mutex::new();

extern {
    #[link_name = "__errno_location"]
    fn errno_location() -> *mut i32;
}

/// Returns the platform-specific value of errno
pub fn errno() -> i32 {
    unsafe {
        (*errno_location())
    }
}

/// Gets a detailed string description for the given error number.
pub fn error_string(errno: i32) -> String {
    if let Some(string) = syscall::STR_ERROR.get(errno as usize) {
        string.to_string()
    } else {
        "unknown error".to_string()
    }
}

pub fn getcwd() -> io::Result<PathBuf> {
    let mut buf = [0; 4096];
    let count = cvt(syscall::getcwd(&mut buf))?;
    Ok(PathBuf::from(OsString::from_vec(buf[.. count].to_vec())))
}

pub fn chdir(p: &path::Path) -> io::Result<()> {
    cvt(syscall::chdir(p.to_str().unwrap())).and(Ok(()))
}

pub struct SplitPaths<'a> {
    iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>,
                    fn(&'a [u8]) -> PathBuf>,
}

pub fn split_paths(unparsed: &OsStr) -> SplitPaths {
    fn bytes_to_path(b: &[u8]) -> PathBuf {
        PathBuf::from(<OsStr as OsStrExt>::from_bytes(b))
    }
    fn is_semicolon(b: &u8) -> bool { *b == b';' }
    let unparsed = unparsed.as_bytes();
    SplitPaths {
        iter: unparsed.split(is_semicolon as fn(&u8) -> bool)
                      .map(bytes_to_path as fn(&[u8]) -> PathBuf)
    }
}

impl<'a> Iterator for SplitPaths<'a> {
    type Item = PathBuf;
    fn next(&mut self) -> Option<PathBuf> { self.iter.next() }
    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
}

#[derive(Debug)]
pub struct JoinPathsError;

pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
    where I: Iterator<Item=T>, T: AsRef<OsStr>
{
    let mut joined = Vec::new();
    let sep = b';';

    for (i, path) in paths.enumerate() {
        let path = path.as_ref().as_bytes();
        if i > 0 { joined.push(sep) }
        if path.contains(&sep) {
            return Err(JoinPathsError)
        }
        joined.extend_from_slice(path);
    }
    Ok(OsStringExt::from_vec(joined))
}

impl fmt::Display for JoinPathsError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        "path segment contains separator `:`".fmt(f)
    }
}

impl StdError for JoinPathsError {
    fn description(&self) -> &str { "failed to join paths" }
}

pub fn current_exe() -> io::Result<PathBuf> {
    use fs::File;

    let mut file = File::open("sys:exe")?;

    let mut path = String::new();
    file.read_to_string(&mut path)?;

    if path.ends_with('\n') {
        path.pop();
    }

    Ok(PathBuf::from(path))
}

pub struct Env {
    iter: vec::IntoIter<(OsString, OsString)>,
    _dont_send_or_sync_me: PhantomData<*mut ()>,
}

impl Iterator for Env {
    type Item = (OsString, OsString);
    fn next(&mut self) -> Option<(OsString, OsString)> { self.iter.next() }
    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
}

/// Returns a vector of (variable, value) byte-vector pairs for all the
/// environment variables of the current process.
pub fn env() -> Env {
    let mut variables: Vec<(OsString, OsString)> = Vec::new();
    if let Ok(mut file) = ::fs::File::open("env:") {
        let mut string = String::new();
        if file.read_to_string(&mut string).is_ok() {
            for line in string.lines() {
                let mut parts = line.splitn(2, '=');
                if let Some(name) = parts.next() {
                    let value = parts.next().unwrap_or("");
                    variables.push((OsString::from(name.to_string()),
                                    OsString::from(value.to_string())));
                }
            }
        }
    }
    Env { iter: variables.into_iter(), _dont_send_or_sync_me: PhantomData }
}

pub fn getenv(key: &OsStr) -> io::Result<Option<OsString>> {
    if ! key.is_empty() {
        if let Ok(mut file) = ::fs::File::open(&("env:".to_owned() + key.to_str().unwrap())) {
            let mut string = String::new();
            file.read_to_string(&mut string)?;
            Ok(Some(OsString::from(string)))
        } else {
            Ok(None)
        }
    } else {
        Ok(None)
    }
}

pub fn setenv(key: &OsStr, value: &OsStr) -> io::Result<()> {
    if ! key.is_empty() {
        let mut file = ::fs::File::create(&("env:".to_owned() + key.to_str().unwrap()))?;
        file.write_all(value.as_bytes())?;
        file.set_len(value.len() as u64)?;
    }
    Ok(())
}

pub fn unsetenv(key: &OsStr) -> io::Result<()> {
    ::fs::remove_file(&("env:".to_owned() + key.to_str().unwrap()))?;
    Ok(())
}

pub fn page_size() -> usize {
    4096
}

pub fn temp_dir() -> PathBuf {
    ::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| {
        PathBuf::from("/tmp")
    })
}

pub fn home_dir() -> Option<PathBuf> {
    return ::env::var_os("HOME").map(PathBuf::from);
}

pub fn exit(code: i32) -> ! {
    let _ = syscall::exit(code as usize);
    unreachable!();
}

pub fn getpid() -> u32 {
    syscall::getpid().unwrap() as u32
}

pub fn getppid() -> u32 {
    syscall::getppid().unwrap() as u32
}
<commit_msg>Auto merge of #51555 - ccesare:remove_unused_variables_redox_os, r=kennytm<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementation of `std::os` functionality for unix systems

#![allow(unused_imports)] // lots of cfg code here

use os::unix::prelude::*;

use error::Error as StdError;
use ffi::{OsString, OsStr};
use fmt;
use io::{self, Read, Write};
use iter;
use marker::PhantomData;
use mem;
use memchr;
use path::{self, PathBuf};
use ptr;
use slice;
use str;
use sys_common::mutex::Mutex;
use sys::{cvt, fd, syscall};
use vec;

extern {
    #[link_name = "__errno_location"]
    fn errno_location() -> *mut i32;
}

/// Returns the platform-specific value of errno
pub fn errno() -> i32 {
    unsafe {
        (*errno_location())
    }
}

/// Gets a detailed string description for the given error number.
pub fn error_string(errno: i32) -> String {
    if let Some(string) = syscall::STR_ERROR.get(errno as usize) {
        string.to_string()
    } else {
        "unknown error".to_string()
    }
}

pub fn getcwd() -> io::Result<PathBuf> {
    let mut buf = [0; 4096];
    let count = cvt(syscall::getcwd(&mut buf))?;
    Ok(PathBuf::from(OsString::from_vec(buf[.. count].to_vec())))
}

pub fn chdir(p: &path::Path) -> io::Result<()> {
    cvt(syscall::chdir(p.to_str().unwrap())).and(Ok(()))
}

pub struct SplitPaths<'a> {
    iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>,
                    fn(&'a [u8]) -> PathBuf>,
}

pub fn split_paths(unparsed: &OsStr) -> SplitPaths {
    fn bytes_to_path(b: &[u8]) -> PathBuf {
        PathBuf::from(<OsStr as OsStrExt>::from_bytes(b))
    }
    fn is_semicolon(b: &u8) -> bool { *b == b';' }
    let unparsed = unparsed.as_bytes();
    SplitPaths {
        iter: unparsed.split(is_semicolon as fn(&u8) -> bool)
                      .map(bytes_to_path as fn(&[u8]) -> PathBuf)
    }
}

impl<'a> Iterator for SplitPaths<'a> {
    type Item = PathBuf;
    fn next(&mut self) -> Option<PathBuf> { self.iter.next() }
    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
}

#[derive(Debug)]
pub struct JoinPathsError;

pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
    where I: Iterator<Item=T>, T: AsRef<OsStr>
{
    let mut joined = Vec::new();
    let sep = b';';

    for (i, path) in paths.enumerate() {
        let path = path.as_ref().as_bytes();
        if i > 0 { joined.push(sep) }
        if path.contains(&sep) {
            return Err(JoinPathsError)
        }
        joined.extend_from_slice(path);
    }
    Ok(OsStringExt::from_vec(joined))
}

impl fmt::Display for JoinPathsError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        "path segment contains separator `:`".fmt(f)
    }
}

impl StdError for JoinPathsError {
    fn description(&self) -> &str { "failed to join paths" }
}

pub fn current_exe() -> io::Result<PathBuf> {
    use fs::File;

    let mut file = File::open("sys:exe")?;

    let mut path = String::new();
    file.read_to_string(&mut path)?;

    if path.ends_with('\n') {
        path.pop();
    }

    Ok(PathBuf::from(path))
}

pub struct Env {
    iter: vec::IntoIter<(OsString, OsString)>,
    _dont_send_or_sync_me: PhantomData<*mut ()>,
}

impl Iterator for Env {
    type Item = (OsString, OsString);
    fn next(&mut self) -> Option<(OsString, OsString)> { self.iter.next() }
    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
}

/// Returns a vector of (variable, value) byte-vector pairs for all the
/// environment variables of the current process.
pub fn env() -> Env {
    let mut variables: Vec<(OsString, OsString)> = Vec::new();
    if let Ok(mut file) = ::fs::File::open("env:") {
        let mut string = String::new();
        if file.read_to_string(&mut string).is_ok() {
            for line in string.lines() {
                let mut parts = line.splitn(2, '=');
                if let Some(name) = parts.next() {
                    let value = parts.next().unwrap_or("");
                    variables.push((OsString::from(name.to_string()),
                                    OsString::from(value.to_string())));
                }
            }
        }
    }
    Env { iter: variables.into_iter(), _dont_send_or_sync_me: PhantomData }
}

pub fn getenv(key: &OsStr) -> io::Result<Option<OsString>> {
    if ! key.is_empty() {
        if let Ok(mut file) = ::fs::File::open(&("env:".to_owned() + key.to_str().unwrap())) {
            let mut string = String::new();
            file.read_to_string(&mut string)?;
            Ok(Some(OsString::from(string)))
        } else {
            Ok(None)
        }
    } else {
        Ok(None)
    }
}

pub fn setenv(key: &OsStr, value: &OsStr) -> io::Result<()> {
    if ! key.is_empty() {
        let mut file = ::fs::File::create(&("env:".to_owned() + key.to_str().unwrap()))?;
        file.write_all(value.as_bytes())?;
        file.set_len(value.len() as u64)?;
    }
    Ok(())
}

pub fn unsetenv(key: &OsStr) -> io::Result<()> {
    ::fs::remove_file(&("env:".to_owned() + key.to_str().unwrap()))?;
    Ok(())
}

pub fn page_size() -> usize {
    4096
}

pub fn temp_dir() -> PathBuf {
    ::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| {
        PathBuf::from("/tmp")
    })
}

pub fn home_dir() -> Option<PathBuf> {
    return ::env::var_os("HOME").map(PathBuf::from);
}

pub fn exit(code: i32) -> ! {
    let _ = syscall::exit(code as usize);
    unreachable!();
}

pub fn getpid() -> u32 {
    syscall::getpid().unwrap() as u32
}

pub fn getppid() -> u32 {
    syscall::getppid().unwrap() as u32
}
<|endoftext|>


<commit_before>use {Field, Matrix2d, Rectangle};

/// An ellipse context.
pub struct EllipseContext<'a> {
    /// Base/origin transform.
    pub base: Field<'a, Matrix2d>,
    /// Current transformation.
    pub transform: Field<'a, Matrix2d>,
    /// Current rectangle enclosing the ellipse.
    pub rect: Field<'a, Rectangle>,
}

<commit_msg>Implemented Transform2d for EllipseContext<commit_after>use {Field, Matrix2d, Rectangle};
use {Transform2d};
use {Borrowed, Value};
use vecmath::{translate, multiply, rotate_radians, scale, shear};

/// An ellipse context.
pub struct EllipseContext<'a> {
    /// Base/origin transform.
    pub base: Field<'a, Matrix2d>,
    /// Current transformation.
    pub transform: Field<'a, Matrix2d>,
    /// Current rectangle enclosing the ellipse.
    pub rect: Field<'a, Rectangle>,
}

impl<'a> Transform2d<'a> for EllipseContext<'a> {
    #[inline(always)]
    fn trans(&'a self, x: f64, y: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: {
                let trans = translate(x, y);
                Value(multiply(&trans, self.transform.get()))
            },
            rect: Borrowed(self.rect.get()),
        }
    }

    #[inline(always)]
    fn rot_rad(&'a self, angle: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: {
                let rot = rotate_radians(angle);
                Value(multiply(&rot, self.transform.get()))
            },
            rect: Borrowed(self.rect.get()),
        }
    }

    #[inline(always)]
    fn scale(&'a self, sx: f64, sy: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: {
                let scale = scale(sx, sy);
                Value(multiply(&scale, self.transform.get()))
            },
            rect: Borrowed(self.rect.get()),
        }
    }

    #[inline(always)]
    fn shear(&'a self, sx: f64, sy: f64) -> EllipseContext<'a> {
        EllipseContext {
            base: Borrowed(self.base.get()),
            transform: {
                let shear = shear(sx, sy);
                Value(multiply(&shear, self.transform.get()))
            },
            rect: Borrowed(self.rect.get()),
        }
    }
}

<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
use std::iter::ExactSizeIterator;

use either::Either;

use crate::size_hint;

/// Iterator returned for the error case of `IterTools::exactly_one()`
/// This iterator yields exactly the same elements as the input iterator.
///
/// During the execution of exactly_one the iterator must be mutated.  This wrapper
/// effectively "restores" the state of the input iterator when it's handed back.
///
/// This is very similar to PutBackN except this iterator only supports 0-2 elements and does not
/// use a `Vec`.
#[derive(Clone)]
pub struct ExactlyOneError<I>
where
    I: Iterator,
{
    first_two: Option<Either<[I::Item; 2], I::Item>>,
    inner: I,
}

impl<I> ExactlyOneError<I>
where
    I: Iterator,
{
    /// Creates a new `ExactlyOneErr` iterator.
    pub(crate) fn new(first_two: Option<Either<[I::Item; 2], I::Item>>, inner: I) -> Self {
        Self { first_two, inner }
    }

    fn additional_len(&self) -> usize {
        match self.first_two {
            Some(Either::Left(_)) => 2,
            Some(Either::Right(_)) => 1,
            None => 0,
        }
    }
}

impl<I> Iterator for ExactlyOneError<I>
where
    I: Iterator,
{
    type Item = I::Item;

    fn next(&mut self) -> Option<Self::Item> {
        match self.first_two.take() {
            Some(Either::Left([first, second])) => {
                self.first_two = Some(Either::Right(second));
                Some(first)
            },
            Some(Either::Right(second)) => {
                Some(second)
            }
            None => {
                self.inner.next()
            }
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        size_hint::add_scalar(self.inner.size_hint(), self.additional_len())
    }
}

impl<I> ExactSizeIterator for ExactlyOneError<I> where I: ExactSizeIterator {}

impl<I> Display for ExactlyOneError<I>
    where I: Iterator
{
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        let additional = self.additional_len();
        if additional > 0 {
            write!(f, "got at least 2 elements when exactly one was expected")
        } else {
            write!(f, "got zero elements when exactly one was expected")
        }
    }
}

impl<I> Debug for ExactlyOneError<I>
    where I: Iterator,
          I::Item: Debug,
{
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        match &self.first_two {
            Some(Either::Left([first, second])) => {
                write!(f, "ExactlyOneError[{:?}, {:?}, ...]", first, second)
            },
            Some(Either::Right(second)) => {
                write!(f, "ExactlyOneError[{:?}, ...]", second)
            }
            None => {
                write!(f, "ExactlyOneError[...]")
            }
        }
    }
}

impl<I> Error for ExactlyOneError<I>  where I: Iterator, I::Item: Debug, {}

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

    #[test]
    fn question_mark_syntax_works() {
        question_mark_return().unwrap_err()
    }

    fn question_mark_return() -> Result<(), impl Error> {
        let x = Err(ExactlyOneError::new(None, []))?;
        Ok(())
    }
}
<commit_msg>Make availability of Error impl conditional<commit_after>#[cfg(feature = "use_std")]
use std::error::Error;
#[cfg(feature = "use_std")]
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};

use std::iter::ExactSizeIterator;

use either::Either;

use crate::size_hint;

/// Iterator returned for the error case of `IterTools::exactly_one()`
/// This iterator yields exactly the same elements as the input iterator.
///
/// During the execution of exactly_one the iterator must be mutated.  This wrapper
/// effectively "restores" the state of the input iterator when it's handed back.
///
/// This is very similar to PutBackN except this iterator only supports 0-2 elements and does not
/// use a `Vec`.
#[derive(Clone)]
pub struct ExactlyOneError<I>
where
    I: Iterator,
{
    first_two: Option<Either<[I::Item; 2], I::Item>>,
    inner: I,
}

impl<I> ExactlyOneError<I>
where
    I: Iterator,
{
    /// Creates a new `ExactlyOneErr` iterator.
    pub(crate) fn new(first_two: Option<Either<[I::Item; 2], I::Item>>, inner: I) -> Self {
        Self { first_two, inner }
    }

    fn additional_len(&self) -> usize {
        match self.first_two {
            Some(Either::Left(_)) => 2,
            Some(Either::Right(_)) => 1,
            None => 0,
        }
    }
}

impl<I> Iterator for ExactlyOneError<I>
where
    I: Iterator,
{
    type Item = I::Item;

    fn next(&mut self) -> Option<Self::Item> {
        match self.first_two.take() {
            Some(Either::Left([first, second])) => {
                self.first_two = Some(Either::Right(second));
                Some(first)
            },
            Some(Either::Right(second)) => {
                Some(second)
            }
            None => {
                self.inner.next()
            }
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        size_hint::add_scalar(self.inner.size_hint(), self.additional_len())
    }
}

impl<I> ExactSizeIterator for ExactlyOneError<I> where I: ExactSizeIterator {}

#[cfg(feature = "use_std")]
impl<I> Display for ExactlyOneError<I>
    where I: Iterator
{
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        let additional = self.additional_len();
        if additional > 0 {
            write!(f, "got at least 2 elements when exactly one was expected")
        } else {
            write!(f, "got zero elements when exactly one was expected")
        }
    }
}

#[cfg(feature = "use_std")]
impl<I> Debug for ExactlyOneError<I>
    where I: Iterator,
          I::Item: Debug,
{
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        match &self.first_two {
            Some(Either::Left([first, second])) => {
                write!(f, "ExactlyOneError[{:?}, {:?}, ...]", first, second)
            },
            Some(Either::Right(second)) => {
                write!(f, "ExactlyOneError[{:?}, ...]", second)
            }
            None => {
                write!(f, "ExactlyOneError[...]")
            }
        }
    }
}

#[cfg(feature = "use_std")]
impl<I> Error for ExactlyOneError<I>  where I: Iterator, I::Item: Debug, {}

#[cfg(all(test, feature = "use_std"))]
mod tests {
    use super::*;

    #[test]
    fn question_mark_syntax_works() {
        question_mark_return().unwrap_err()
    }

    fn question_mark_return() -> Result<(), impl Error> {
        let x = Err(ExactlyOneError::new(None, []))?;
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::sync::atomic::{AtomicUsize, Ordering};
use std::ptr;

use ctxt::SemContext;
use gc::Address;
use gc::root::IndirectObj;
use gc::swiper::{PROMOTION_AGE, Region};
use object::Obj;
use timer::{in_ms, Timer};

pub struct YoungGen {
    total: Region,
    from: SemiSpace,
    to: SemiSpace,
}

impl YoungGen {
    pub fn new(young_start: Address, young_end: Address) -> YoungGen {
        let half_size = (young_end.to_usize() - young_start.to_usize()) / 2;
        let half_address = young_start.offset(half_size);

        YoungGen {
            total: Region::new(young_start, young_end),
            from: SemiSpace::new(young_start, half_address),
            to: SemiSpace::new(half_address, young_end),
        }
    }

    pub fn alloc(&self, size: usize) -> *const u8 {
        let mut old = self.from.free.load(Ordering::Relaxed);
        let mut new;

        loop {
            new = old + size;

            if new >= self.from.end.to_usize() {
                return ptr::null();
            }

            let res =
                self.from.free
                    .compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed);

            match res {
                Ok(_) => break,
                Err(x) => old = x,
            }
        }

        old as *const u8
    }

    pub fn collect(
        &mut self,
        ctxt: &SemContext,
        rootset: Vec<IndirectObj>,
    ) {
        let mut timer = Timer::new(ctxt.args.flag_gc_events);

        let mut scan = self.from.start;
        let end: Address = self.from.free.load(Ordering::SeqCst).into();
        let mut free = self.to.start;

        for &root in &rootset {
            let root_ptr = root.get();

            if self.from.includes(root_ptr as usize) {
                root.set(copy(root_ptr, &mut free));
            }
        }

        while scan < end {
            let object = unsafe { &mut *scan.to_mut_ptr::<Obj>() };

            object.visit_reference_fields(|child| {
                let child_ptr = child.get();

                if self.from.includes(child_ptr as usize) {
                    child.set(copy(child_ptr, &mut free));
                }
            });

            scan = scan.offset(object.size());
        }

        // memset from-space to garbage data for debug builds
        // makes sure that no pointer into from-space is left
        if cfg!(debug_assertions) {
            unsafe {
                ptr::write_bytes(self.from.start.to_usize() as *mut u8, 0xcc, self.from.size());
            }
        }

        self.swap_spaces();

        timer.stop_with(|dur| {
            if ctxt.args.flag_gc_events {
                println!("GC minor: collect garbage ({} ms)", in_ms(dur));
            }
        });
    }

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

struct SemiSpace {
    start: Address,
    free: AtomicUsize,
    uncommitted: Address,
    end: Address,
}

impl SemiSpace {
    fn new(start: Address, end: Address) -> SemiSpace {
        SemiSpace {
            start: start,
            free: AtomicUsize::new(start.to_usize()),
            uncommitted: start,
            end: end,
        }
    }

    fn empty() -> SemiSpace {
        SemiSpace {
            start: Address::null(),
            free: AtomicUsize::new(0),
            uncommitted: Address::null(),
            end: Address::null(),
        }
    }

    fn size(&self) -> usize {
        self.end.to_usize() - self.start.to_usize()
    }

    fn committed_size(&self) -> usize {
        self.uncommitted.to_usize() - self.start.to_usize()
    }

    fn uncommitted_size(&self) -> usize {
        self.end.to_usize() - self.uncommitted.to_usize()
    }

    fn includes(&self, ptr: usize) -> bool {
        self.start.to_usize() <= ptr && ptr < self.end.to_usize()
    }
}

pub fn copy(obj: *mut Obj, free: &mut Address) -> *mut Obj {
    let obj = unsafe { &mut *obj };
    let addr = get_forwarding_address(obj);

    if is_forwarding_address(addr) {
        unmark_forwarding_address(addr).to_mut_ptr::<Obj>()
    } else {
        let obj_size = obj.size();
        let age = obj.header_mut().increase_age();

        let addr: Address;

        // if object is old enough we copy it into the old generation
        if age >= PROMOTION_AGE {
            unimplemented!();

        // otherwise the object remains in the young generation for nows
        } else {
            addr = *free;

            unsafe {
                ptr::copy_nonoverlapping(obj as *const Obj as *const u8, addr.to_mut_ptr::<u8>(), obj_size);
                *free = addr.offset(obj_size);
            }
        }

        set_forwarding_address(obj, addr);

        addr.to_mut_ptr::<Obj>()
    }
}

pub fn is_forwarding_address(obj: Address) -> bool {
    (obj.to_usize() & 1) == 1
}

pub fn mark_forwarding_address(obj: Address) -> Address {
    (obj.to_usize() | 1).into()
}

pub fn unmark_forwarding_address(obj: Address) -> Address {
    (obj.to_usize() & !1).into()
}

pub fn get_forwarding_address(obj: &Obj) -> Address {
    unsafe { *(obj as *const Obj as *const Address) }
}

pub fn set_forwarding_address(obj: &mut Obj, addr: Address) {
    unsafe {
        *(obj as *mut Obj as *mut Address) = mark_forwarding_address(addr);
    }
}<commit_msg>swiper: promote objects into old space<commit_after>use std::sync::atomic::{AtomicUsize, Ordering};
use std::ptr;

use ctxt::SemContext;
use gc::Address;
use gc::root::IndirectObj;
use gc::swiper::{PROMOTION_AGE, Region};
use gc::swiper::old::OldGen;
use object::Obj;
use timer::{in_ms, Timer};

pub struct YoungGen {
    total: Region,
    from: SemiSpace,
    to: SemiSpace,
}

impl YoungGen {
    pub fn new(young_start: Address, young_end: Address) -> YoungGen {
        let half_size = (young_end.to_usize() - young_start.to_usize()) / 2;
        let half_address = young_start.offset(half_size);

        YoungGen {
            total: Region::new(young_start, young_end),
            from: SemiSpace::new(young_start, half_address),
            to: SemiSpace::new(half_address, young_end),
        }
    }

    pub fn alloc(&self, size: usize) -> *const u8 {
        let mut old = self.from.free.load(Ordering::Relaxed);
        let mut new;

        loop {
            new = old + size;

            if new >= self.from.end.to_usize() {
                return ptr::null();
            }

            let res =
                self.from.free
                    .compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed);

            match res {
                Ok(_) => break,
                Err(x) => old = x,
            }
        }

        old as *const u8
    }

    pub fn collect(
        &mut self,
        ctxt: &SemContext,
        rootset: Vec<IndirectObj>,
        old: &OldGen,
    ) {
        let mut timer = Timer::new(ctxt.args.flag_gc_events);

        let mut scan = self.from.start;
        let end: Address = self.from.free.load(Ordering::SeqCst).into();
        let mut free = self.to.start;

        for &root in &rootset {
            let root_ptr = root.get();

            if self.from.includes(root_ptr as usize) {
                root.set(copy(root_ptr, &mut free, old));
            }
        }

        while scan < end {
            let object = unsafe { &mut *scan.to_mut_ptr::<Obj>() };

            object.visit_reference_fields(|child| {
                let child_ptr = child.get();

                if self.from.includes(child_ptr as usize) {
                    child.set(copy(child_ptr, &mut free, old));
                }
            });

            scan = scan.offset(object.size());
        }

        // memset from-space to garbage data for debug builds
        // makes sure that no pointer into from-space is left
        if cfg!(debug_assertions) {
            unsafe {
                ptr::write_bytes(self.from.start.to_usize() as *mut u8, 0xcc, self.from.size());
            }
        }

        self.swap_spaces();

        timer.stop_with(|dur| {
            if ctxt.args.flag_gc_events {
                println!("GC minor: collect garbage ({} ms)", in_ms(dur));
            }
        });
    }

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

struct SemiSpace {
    start: Address,
    free: AtomicUsize,
    uncommitted: Address,
    end: Address,
}

impl SemiSpace {
    fn new(start: Address, end: Address) -> SemiSpace {
        SemiSpace {
            start: start,
            free: AtomicUsize::new(start.to_usize()),
            uncommitted: start,
            end: end,
        }
    }

    fn empty() -> SemiSpace {
        SemiSpace {
            start: Address::null(),
            free: AtomicUsize::new(0),
            uncommitted: Address::null(),
            end: Address::null(),
        }
    }

    fn size(&self) -> usize {
        self.end.to_usize() - self.start.to_usize()
    }

    fn committed_size(&self) -> usize {
        self.uncommitted.to_usize() - self.start.to_usize()
    }

    fn uncommitted_size(&self) -> usize {
        self.end.to_usize() - self.uncommitted.to_usize()
    }

    fn includes(&self, ptr: usize) -> bool {
        self.start.to_usize() <= ptr && ptr < self.end.to_usize()
    }
}

pub fn copy(obj: *mut Obj, free: &mut Address, old: &OldGen) -> *mut Obj {
    let obj = unsafe { &mut *obj };
    let addr = get_forwarding_address(obj);

    if is_forwarding_address(addr) {
        unmark_forwarding_address(addr).to_mut_ptr::<Obj>()
    } else {
        let obj_size = obj.size();
        let age = obj.header_mut().increase_age();

        let addr: Address;

        // if object is old enough we copy it into the old generation
        if age >= PROMOTION_AGE {
            addr = Address::from_ptr(old.alloc(obj_size));
            copy_object(obj, addr, obj_size);

        // otherwise the object remains in the young generation for nows
        } else {
            addr = *free;
            copy_object(obj, addr, obj_size);
            *free = addr.offset(obj_size);
        }

        set_forwarding_address(obj, addr);

        addr.to_mut_ptr::<Obj>()
    }
}

fn copy_object(obj: &Obj, addr: Address, size: usize) {
    unsafe {
        ptr::copy_nonoverlapping(obj as *const Obj as *const u8, addr.to_mut_ptr::<u8>(), size);
    }
}

pub fn is_forwarding_address(obj: Address) -> bool {
    (obj.to_usize() & 1) == 1
}

pub fn mark_forwarding_address(obj: Address) -> Address {
    (obj.to_usize() | 1).into()
}

pub fn unmark_forwarding_address(obj: Address) -> Address {
    (obj.to_usize() & !1).into()
}

pub fn get_forwarding_address(obj: &Obj) -> Address {
    unsafe { *(obj as *const Obj as *const Address) }
}

pub fn set_forwarding_address(obj: &mut Obj, addr: Address) {
    unsafe {
        *(obj as *mut Obj as *mut Address) = mark_forwarding_address(addr);
    }
}<|endoftext|>


<commit_before>use crate::Msg;
use seed::prelude::*;

pub fn render() -> Node<Msg> {
    div![
        h1!["Primality Test, Calculate Primes"],
        br![],
        br![],
        br![],
        //TODO: Convert the j.js file into rust!
        Script!(attrs!{At::Src => "https://static.bigprimes.net/j.js"}),
        table![
            attrs!{At::Class => "text", At::Width => "300", At::Style => "border:1px solid #444; background-color:#e0faed"},
            tr![
                td![
                    attrs!{At::Style => "padding: 10px"},
                    form![
                        attrs!{At::Name => "primetest", At::OnSubmit => "return false"},
                        "Tool is limited to checking numbers upto 16 digits.",
                        br![],
                        br![],
                        "Is ",
                        input![attrs!{At::Type => "text", At::Size => "16", At::Name => "input", At::Value => "", At::MaxLength => "16"}],
                        " prime? ",
                        button![attrs!{At::OnClick => "check(false,0)"},"Check!"],
                        br![],
                        br![],
                        textarea![attrs!{At::Name => "javascriptoutput", At::Cols => 60, At::Rows => 2, At::Disabled => "disabled"}]
                    ]
                ]
            ]
        ],
        br![],
        br![],
        table![
            attrs!{At::Class => "text", At::Width => "300", At::Style => "border:1px solid #444; background-color:#e0faed"},
            tr![
                td![
                    attrs!{At::Style => "padding: 10px"},
                    form![
                        attrs!{At::Name => "primelist", At::OnSubmit => "return false"},
                        "This tool is limited to checking numbers upto 15 digits.",
                        br![],
                        br![],
                        "This will show ",
                        input![attrs!{At::Type => "text", At::Size => "4", At::Name => "primes", At::Value => "1", At::MaxLength => "2"}],
                        " prime numbers after ",
                        input![attrs!{At::Type => "text", At::Size => "16", At::Name => "start", At::Value => "0", At::MaxLength => "15"}],
                        " ",
                        button![attrs!{At::OnClick => "primelist.javascriptlistoutput.value='';listy();"},"Go!"],
                        br![],
                        br![],
                        textarea![attrs!{At::Name => "javascriptlistoutput", At::Cols => 60, At::Rows => 10, At::Disabled => "disabled"}]
                    ]
                ]
            ]
        ]
    ]
}
<commit_msg>Now correctly formatted rust using rustfmt!<commit_after>use crate::Msg;
use seed::prelude::*;

pub fn render() -> Node<Msg> {
    div![
        h1!["Primality Test, Calculate Primes"],
        br![],
        br![],
        br![],
        //TODO: Convert the j.js file into rust!
        Script!(attrs! {At::Src => "https://static.bigprimes.net/j.js"}),
        table![
            attrs! {At::Class => "text", At::Width => "300", At::Style => "border:1px solid #444; background-color:#e0faed"},
            tr![td![
                attrs! {At::Style => "padding: 10px"},
                form![
                    attrs! {At::Name => "primetest", At::OnSubmit => "return false"},
                    "Tool is limited to checking numbers upto 16 digits.",
                    br![],
                    br![],
                    "Is ",
                    input![
                        attrs! {At::Type => "text", At::Size => "16", At::Name => "input", At::Value => "", At::MaxLength => "16"}
                    ],
                    " prime? ",
                    button![attrs! {At::OnClick => "check(false,0)"}, "Check!"],
                    br![],
                    br![],
                    textarea![
                        attrs! {At::Name => "javascriptoutput", At::Cols => 60, At::Rows => 2, At::Disabled => "disabled"}
                    ]
                ]
            ]]
        ],
        br![],
        br![],
        table![
            attrs! {At::Class => "text", At::Width => "300", At::Style => "border:1px solid #444; background-color:#e0faed"},
            tr![td![
                attrs! {At::Style => "padding: 10px"},
                form![
                    attrs! {At::Name => "primelist", At::OnSubmit => "return false"},
                    "This tool is limited to checking numbers upto 15 digits.",
                    br![],
                    br![],
                    "This will show ",
                    input![
                        attrs! {At::Type => "text", At::Size => "4", At::Name => "primes", At::Value => "1", At::MaxLength => "2"}
                    ],
                    " prime numbers after ",
                    input![
                        attrs! {At::Type => "text", At::Size => "16", At::Name => "start", At::Value => "0", At::MaxLength => "15"}
                    ],
                    " ",
                    button![
                        attrs! {At::OnClick => "primelist.javascriptlistoutput.value='';listy();"},
                        "Go!"
                    ],
                    br![],
                    br![],
                    textarea![
                        attrs! {At::Name => "javascriptlistoutput", At::Cols => 60, At::Rows => 10, At::Disabled => "disabled"}
                    ]
                ]
            ]]
        ]
    ]
}
<|endoftext|>


<commit_before>//
// zhtta.rs
//
// Starting code for PS3
// Running on Rust 0.9
//
// Note that this code has serious security risks!  You should not run it
// on any system with access to sensitive files.
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu and David Evans
// Version 0.5

// To see debug! outputs set the RUST_LOG environment variable, e.g.: export RUST_LOG="zhtta=debug"

#[feature(globs)];
extern mod extra;

use std::io::*;
use std::io::net::ip::{SocketAddr};
use std::{os, str, libc, from_str};
use std::path::Path;
use std::hashmap::HashMap;

use extra::getopts;
use extra::arc::MutexArc;

static SERVER_NAME : &'static str = "Zhtta Version 0.5";

static IP : &'static str = "127.0.0.1";
static PORT : uint = 4414;
static WWW_DIR : &'static str = "./www";

static HTTP_OK : &'static str = "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n";
static HTTP_BAD : &'static str = "HTTP/1.1 404 Not Found\r\n\r\n";

static COUNTER_STYLE : &'static str = "<doctype !html><title>Hello, Rust!</title>

             ";

static mut visitor_count : uint = 0;

struct HTTP_Request {
    // Use peer_name as the key to access TcpStream in hashmap.

    // (Due to a bug in extra::arc in Rust 0.9, it is very inconvenient to use TcpStream without the "Freeze" bound.
    //  See issue: https://github.com/mozilla/rust/issues/12139)
    peer_name: ~str,
    path: ~Path,
}

struct WebServer {
    ip: ~str,
    port: uint,
    www_dir_path: ~Path,

    request_queue_arc: MutexArc<~[HTTP_Request]>,
    stream_map_arc: MutexArc<HashMap<~str, Option<std::io::net::tcp::TcpStream>>>,

    notify_port: Port<()>,
    shared_notify_chan: SharedChan<()>,
}

impl WebServer {
    fn new(ip: &str, port: uint, www_dir: &str) -> WebServer {
        let (notify_port, shared_notify_chan) = SharedChan::new();
        let www_dir_path = ~Path::new(www_dir);
        os::change_dir(www_dir_path.clone());

        WebServer {
            ip: ip.to_owned(),
            port: port,
            www_dir_path: www_dir_path,

            request_queue_arc: MutexArc::new(~[]),
            stream_map_arc: MutexArc::new(HashMap::new()),

            notify_port: notify_port,
            shared_notify_chan: shared_notify_chan,
        }
    }

    fn run(&mut self) {
        self.listen();
        self.dequeue_static_file_request();
    }

    fn listen(&mut self) {
        let addr = from_str::<SocketAddr>(format!("{:s}:{:u}", self.ip, self.port)).expect("Address error.");
        let www_dir_path_str = self.www_dir_path.as_str().expect("invalid www path?").to_owned();

        let request_queue_arc = self.request_queue_arc.clone();
        let shared_notify_chan = self.shared_notify_chan.clone();
        let stream_map_arc = self.stream_map_arc.clone();

        spawn(proc() {
            let mut acceptor = net::tcp::TcpListener::bind(addr).listen();
            println!("{:s} listening on {:s} (serving from: {:s}).",
                     SERVER_NAME, addr.to_str(), www_dir_path_str);

            for stream in acceptor.incoming() {
                let (queue_port, queue_chan) = Chan::new();
                queue_chan.send(request_queue_arc.clone());

                let notify_chan = shared_notify_chan.clone();
                let stream_map_arc = stream_map_arc.clone();

                // Spawn a task to handle the connection.
                spawn(proc() {
                    unsafe { visitor_count += 1; } // TODO: Fix unsafe counter
                    let request_queue_arc = queue_port.recv();

                    let mut stream = stream;

                    let peer_name = WebServer::get_peer_name(&mut stream);

                    let mut buf = [0, ..500];
                    stream.read(buf);
                    let request_str = str::from_utf8(buf);
                    debug!("Request:\n{:s}", request_str);

                    let req_group : ~[&str]= request_str.splitn(' ', 3).collect();
                    if req_group.len() > 2 {
                        let path_str = "." + req_group[1].to_owned();

                        let mut path_obj = ~os::getcwd();
                        path_obj.push(path_str.clone());

                        let ext_str = match path_obj.extension_str() {
                            Some(e) => e,
                            None => "",
                        };

                        debug!("Requested path: [{:s}]", path_obj.as_str().expect("error"));
                        debug!("Requested path: [{:s}]", path_str);

                        if path_str == ~"./" {
                            debug!("===== Counter Page request =====");
                            WebServer::respond_with_counter_page(stream);
                            debug!("=====Terminated connection from [{:s}].=====", peer_name);
                        } else if !path_obj.exists() || path_obj.is_dir() {
                            debug!("===== Error page request =====");
                            WebServer::respond_with_error_page(stream, path_obj);
                            debug!("=====Terminated connection from [{:s}].=====", peer_name);
                        } else if ext_str == "shtml" { // Dynamic web pages.
                            debug!("===== Dynamic Page request =====");
                            WebServer::respond_with_dynamic_page(stream, path_obj);
                            debug!("=====Terminated connection from [{:s}].=====", peer_name);
                        } else {
                            debug!("===== Static Page request =====");
                            WebServer::enqueue_static_file_request(stream, path_obj, stream_map_arc, request_queue_arc, notify_chan);
                        }
                    }
                });
            }
        });
    }

    fn respond_with_error_page(stream: Option<std::io::net::tcp::TcpStream>, path: &Path) {
        let mut stream = stream;
        let msg: ~str = format!("Cannot open: {:s}", path.as_str().expect("invalid path").to_owned());

        stream.write(HTTP_BAD.as_bytes());
        stream.write(msg.as_bytes());
    }

    // TODO: Safe visitor counter.
    fn respond_with_counter_page(stream: Option<std::io::net::tcp::TcpStream>) {
        let mut stream = stream;
        let response: ~str =
            format!("{:s}{:s}
Greetings, Krusty!

Visitor count: {:u}
\r\n",
                    HTTP_OK, COUNTER_STYLE,
                    unsafe { visitor_count } );
        debug!("Responding to counter request");
        stream.write(response.as_bytes());
    }

    // TODO: Streaming file.
    // TODO: Application-layer file caching.
    fn respond_with_static_file(stream: Option<std::io::net::tcp::TcpStream>, path: &Path) {
        let mut stream = stream;
        let mut file_reader = File::open(path).expect("Invalid file!");
        stream.write(HTTP_OK.as_bytes());
        stream.write(file_reader.read_to_end());
    }

    // TODO: Server-side gashing.
    fn respond_with_dynamic_page(stream: Option<std::io::net::tcp::TcpStream>, path: &Path) {
        // for now, just serve as static file
        WebServer::respond_with_static_file(stream, path);
    }

    // TODO: Smarter Scheduling.
    fn enqueue_static_file_request(stream: Option<std::io::net::tcp::TcpStream>, path_obj: &Path, stream_map_arc: MutexArc<HashMap<~str, Option<std::io::net::tcp::TcpStream>>>, req_queue_arc: MutexArc<~[HTTP_Request]>, notify_chan: SharedChan<()>) {
        // Save stream in hashmap for later response.
        let mut stream = stream;
        let peer_name = WebServer::get_peer_name(&mut stream);
        let (stream_port, stream_chan) = Chan::new();
        stream_chan.send(stream);
        unsafe {
            // Use an unsafe method, because TcpStream in Rust 0.9 doesn't have "Freeze" bound.
            stream_map_arc.unsafe_access(|local_stream_map| {
                let stream = stream_port.recv();
                local_stream_map.swap(peer_name.clone(), stream);
            });
        }

        // Enqueue the HTTP request.
        let req = HTTP_Request { peer_name: peer_name.clone(), path: ~path_obj.clone() };
        let (req_port, req_chan) = Chan::new();
        req_chan.send(req);

        debug!("Waiting for queue mutex lock.");
        req_queue_arc.access(|local_req_queue| {
            debug!("Got queue mutex lock.");
            let req: HTTP_Request = req_port.recv();
            local_req_queue.push(req);
            debug!("A new request enqueued, now the length of queue is {:u}.", local_req_queue.len());
        });

        notify_chan.send(()); // Send incoming notification to responder task.

    }

    // TODO: Smarter Scheduling.
    fn dequeue_static_file_request(&mut self) {
        let req_queue_get = self.request_queue_arc.clone();
        let stream_map_get = self.stream_map_arc.clone();

        // Port<> cannot be sent to another task. So we have to make this task as the main task that can access self.notify_port.

        let (request_port, request_chan) = Chan::new();
        loop {
            self.notify_port.recv();    // waiting for new request enqueued.

            req_queue_get.access( |req_queue| {
                match req_queue.shift_opt() { // FIFO queue.
                    None => { /* do nothing */ }
                    Some(req) => {
                        request_chan.send(req);
                        debug!("A new request dequeued, now the length of queue is {:u}.", req_queue.len());
                    }
                }
            });

            let request = request_port.recv();

            // Get stream from hashmap.
            // Use unsafe method, because TcpStream in Rust 0.9 doesn't have "Freeze" bound.
            let (stream_port, stream_chan) = Chan::new();
            unsafe {
                stream_map_get.unsafe_access(|local_stream_map| {
                    let stream = local_stream_map.pop(&request.peer_name).expect("no option tcpstream");
                    stream_chan.send(stream);
                });
            }

            // TODO: Spawning more tasks to respond the dequeued requests concurrently. You may need a semophore to control the concurrency.
            let stream = stream_port.recv();
            WebServer::respond_with_static_file(stream, request.path);
            // Close stream automatically.
            debug!("=====Terminated connection from [{:s}].=====", request.peer_name);
        }
    }

    fn get_peer_name(stream: &mut Option<std::io::net::tcp::TcpStream>) -> ~str {
        match *stream {
            Some(ref mut s) => {
                         match s.peer_name() {
                            Some(pn) => {pn.to_str()},
                            None => (~"")
                         }
                       },
            None => (~"")
        }
    }
}

fn get_args() -> (~str, uint, ~str) {
    fn print_usage(program: &str) {
        println!("Usage: {:s} [options]", program);
        println!("--ip     \tIP address, \"{:s}\" by default.", IP);
        println!("--port   \tport number, \"{:u}\" by default.", PORT);
        println!("--www    \tworking directory, \"{:s}\" by default", WWW_DIR);
        println("-h --help \tUsage");
    }

    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();
    let program = args[0].clone();

    let opts = ~[
        getopts::optopt("ip"),
        getopts::optopt("port"),
        getopts::optopt("www"),
        getopts::optflag("h"),
        getopts::optflag("help")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("h") || matches.opt_present("help") {
        print_usage(program);
        unsafe { libc::exit(1); }
    }

    let ip_str = if matches.opt_present("ip") {
                    matches.opt_str("ip").expect("invalid ip address?").to_owned()
                 } else {
                    IP.to_owned()
                 };

    let port:uint = if matches.opt_present("port") {
                        from_str::from_str(matches.opt_str("port").expect("invalid port number?")).expect("not uint?")
                    } else {
                        PORT
                    };

    let www_dir_str = if matches.opt_present("www") {
                        matches.opt_str("www").expect("invalid www argument?")
                      } else { WWW_DIR.to_owned() };

    (ip_str, port, www_dir_str)
}

fn main() {
    let (ip_str, port, www_dir_str) = get_args();
    let mut zhtta = WebServer::new(ip_str, port, www_dir_str);
    zhtta.run();
}
<commit_msg>mutex arc of priority queue of http requests (?)<commit_after>//
// zhtta.rs
//
// Starting code for PS3
// Running on Rust 0.9
//
// Note that this code has serious security risks!  You should not run it
// on any system with access to sensitive files.
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu and David Evans
// Version 0.5

// To see debug! outputs set the RUST_LOG environment variable, e.g.: export RUST_LOG="zhtta=debug"

#[feature(globs)];
extern mod extra;

use std::io::*;
use std::io::net::ip::{SocketAddr};
use std::{os, str, libc, from_str};
use std::path::Path;
use std::hashmap::HashMap;

use extra::getopts;
use extra::arc::MutexArc;
use extra::priority_queue::PriorityQueue;

static SERVER_NAME : &'static str = "Zhtta Version 0.5";

static IP : &'static str = "127.0.0.1";
static PORT : uint = 4414;
static WWW_DIR : &'static str = "./www";

static HTTP_OK : &'static str = "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n";
static HTTP_BAD : &'static str = "HTTP/1.1 404 Not Found\r\n\r\n";

static COUNTER_STYLE : &'static str = "<doctype !html><title>Hello, Rust!</title>

             ";

static mut visitor_count : uint = 0;

struct HTTP_Request {
    // Use peer_name as the key to access TcpStream in hashmap.

    // (Due to a bug in extra::arc in Rust 0.9, it is very inconvenient to use TcpStream without the "Freeze" bound.
    //  See issue: https://github.com/mozilla/rust/issues/12139)
    peer_name: ~str,
    path: ~Path,
}

impl std::cmp::Eq for HTTP_Request {
    fn eq(&self, other: &HTTP_Request) -> bool {
        (other.peer_name.slice_to(7) == "128.143." || other.peer_name.slice_to(6) == "137.54." || other.peer_name.slice_to(9) == "127.0.0.1") &&
        (self.peer_name.slice_to(7) == "128.143." || self.peer_name.slice_to(6) == "137.54." || self.peer_name.slice_to(9) == "127.0.0.1")
    }
}

impl std::cmp::Ord for HTTP_Request {
    fn lt(&self, other: &HTTP_Request) -> bool {
        (other.peer_name.slice_to(7) != "128.143." || other.peer_name.slice_to(6) != "137.54." || other.peer_name.slice_to(9) != "127.0.0.1") &&
        (self.peer_name.slice_to(7) == "128.143." || self.peer_name.slice_to(6) == "137.54." || other.peer_name.slice_to(9) == "127.0.0.1")
    }

    fn gt(&self, other: &HTTP_Request) -> bool {
        (other.peer_name.slice_to(7) == "128.143." || other.peer_name.slice_to(6) == "137.54." || other.peer_name.slice_to(9) == "127.0.0.1") &&
        (self.peer_name.slice_to(7) != "128.143." || self.peer_name.slice_to(6) != "137.54." || other.peer_name.slice_to(9) != "127.0.0.1")
    }
}

struct WebServer {
    ip: ~str,
    port: uint,
    www_dir_path: ~Path,

    request_queue_arc: MutexArc<PriorityQueue<HTTP_Request>>,
    stream_map_arc: MutexArc<HashMap<~str, Option<std::io::net::tcp::TcpStream>>>,

    notify_port: Port<()>,
    shared_notify_chan: SharedChan<()>,
}

impl WebServer {
    fn new(ip: &str, port: uint, www_dir: &str) -> WebServer {
        let (notify_port, shared_notify_chan) = SharedChan::new();
        let www_dir_path = ~Path::new(www_dir);
        os::change_dir(www_dir_path.clone());

        WebServer {
            ip: ip.to_owned(),
            port: port,
            www_dir_path: www_dir_path,

            request_queue_arc: MutexArc::new(PriorityQueue::new()),
            stream_map_arc: MutexArc::new(HashMap::new()),

            notify_port: notify_port,
            shared_notify_chan: shared_notify_chan,
        }
    }

    fn run(&mut self) {
        self.listen();
        self.dequeue_static_file_request();
    }

    fn listen(&mut self) {
        let addr = from_str::<SocketAddr>(format!("{:s}:{:u}", self.ip, self.port)).expect("Address error.");
        let www_dir_path_str = self.www_dir_path.as_str().expect("invalid www path?").to_owned();

        let request_queue_arc = self.request_queue_arc.clone();
        let shared_notify_chan = self.shared_notify_chan.clone();
        let stream_map_arc = self.stream_map_arc.clone();

        spawn(proc() {
            let mut acceptor = net::tcp::TcpListener::bind(addr).listen();
            println!("{:s} listening on {:s} (serving from: {:s}).",
                     SERVER_NAME, addr.to_str(), www_dir_path_str);

            for stream in acceptor.incoming() {
                let (queue_port, queue_chan) = Chan::new();
                queue_chan.send(request_queue_arc.clone());

                let notify_chan = shared_notify_chan.clone();
                let stream_map_arc = stream_map_arc.clone();

                // Spawn a task to handle the connection.
                spawn(proc() {
                    unsafe { visitor_count += 1; } // TODO: Fix unsafe counter
                    let request_queue_arc = queue_port.recv();

                    let mut stream = stream;

                    let peer_name = WebServer::get_peer_name(&mut stream);

                    let mut buf = [0, ..500];
                    stream.read(buf);
                    let request_str = str::from_utf8(buf);
                    debug!("Request:\n{:s}", request_str);

                    let req_group : ~[&str]= request_str.splitn(' ', 3).collect();
                    if req_group.len() > 2 {
                        let path_str = "." + req_group[1].to_owned();

                        let mut path_obj = ~os::getcwd();
                        path_obj.push(path_str.clone());

                        let ext_str = match path_obj.extension_str() {
                            Some(e) => e,
                            None => "",
                        };

                        debug!("Requested path: [{:s}]", path_obj.as_str().expect("error"));
                        debug!("Requested path: [{:s}]", path_str);

                        if path_str == ~"./" {
                            debug!("===== Counter Page request =====");
                            WebServer::respond_with_counter_page(stream);
                            debug!("=====Terminated connection from [{:s}].=====", peer_name);
                        } else if !path_obj.exists() || path_obj.is_dir() {
                            debug!("===== Error page request =====");
                            WebServer::respond_with_error_page(stream, path_obj);
                            debug!("=====Terminated connection from [{:s}].=====", peer_name);
                        } else if ext_str == "shtml" { // Dynamic web pages.
                            debug!("===== Dynamic Page request =====");
                            WebServer::respond_with_dynamic_page(stream, path_obj);
                            debug!("=====Terminated connection from [{:s}].=====", peer_name);
                        } else {
                            debug!("===== Static Page request =====");
                            WebServer::enqueue_static_file_request(stream, path_obj, stream_map_arc, request_queue_arc, notify_chan);
                        }
                    }
                });
            }
        });
    }

    fn respond_with_error_page(stream: Option<std::io::net::tcp::TcpStream>, path: &Path) {
        let mut stream = stream;
        let msg: ~str = format!("Cannot open: {:s}", path.as_str().expect("invalid path").to_owned());

        stream.write(HTTP_BAD.as_bytes());
        stream.write(msg.as_bytes());
    }

    // TODO: Safe visitor counter.
    fn respond_with_counter_page(stream: Option<std::io::net::tcp::TcpStream>) {
        let mut stream = stream;
        let response: ~str =
            format!("{:s}{:s}
Greetings, Krusty!

Visitor count: {:u}
\r\n",
                    HTTP_OK, COUNTER_STYLE,
                    unsafe { visitor_count } );
        debug!("Responding to counter request");
        stream.write(response.as_bytes());
    }

    // TODO: Streaming file.
    // TODO: Application-layer file caching.
    fn respond_with_static_file(stream: Option<std::io::net::tcp::TcpStream>, path: &Path) {
        let mut stream = stream;
        let mut file_reader = File::open(path).expect("Invalid file!");
        stream.write(HTTP_OK.as_bytes());
        stream.write(file_reader.read_to_end());
    }

    // TODO: Server-side gashing.
    fn respond_with_dynamic_page(stream: Option<std::io::net::tcp::TcpStream>, path: &Path) {
        // for now, just serve as static file
        WebServer::respond_with_static_file(stream, path);
    }

    // TODO: Smarter Scheduling.
    fn enqueue_static_file_request(stream: Option<std::io::net::tcp::TcpStream>, path_obj: &Path, stream_map_arc: MutexArc<HashMap<~str, Option<std::io::net::tcp::TcpStream>>>, req_queue_arc: MutexArc<PriorityQueue<HTTP_Request>>, notify_chan: SharedChan<()>) {
        // Save stream in hashmap for later response.
        let mut stream = stream;
        let peer_name = WebServer::get_peer_name(&mut stream);
        let (stream_port, stream_chan) = Chan::new();
        stream_chan.send(stream);
        unsafe {
            // Use an unsafe method, because TcpStream in Rust 0.9 doesn't have "Freeze" bound.
            stream_map_arc.unsafe_access(|local_stream_map| {
                let stream = stream_port.recv();
                local_stream_map.swap(peer_name.clone(), stream);
            });
        }

        // Enqueue the HTTP request.
        let req = HTTP_Request { peer_name: peer_name.clone(), path: ~path_obj.clone() };
        let (req_port, req_chan) = Chan::new();
        req_chan.send(req);

        debug!("Waiting for queue mutex lock.");
        req_queue_arc.access(|local_req_queue| {
            debug!("Got queue mutex lock.");
            let req: HTTP_Request = req_port.recv();
            local_req_queue.push(req);
            debug!("A new request enqueued, now the length of queue is {:u}.", local_req_queue.len());
        });

        notify_chan.send(()); // Send incoming notification to responder task.

    }

    // TODO: Smarter Scheduling.
    fn dequeue_static_file_request(&mut self) {
        let req_queue_get = self.request_queue_arc.clone();
        let stream_map_get = self.stream_map_arc.clone();

        // Port<> cannot be sent to another task. So we have to make this task as the main task that can access self.notify_port.

        let (request_port, request_chan) = Chan::new();
        loop {
            self.notify_port.recv();    // waiting for new request enqueued.

            req_queue_get.access( |req_queue| {
                match req_queue.maybe_pop() { // Priority queue.
                    None => { /* do nothing */ }
                    Some(req) => {
                        request_chan.send(req);
                        debug!("A new request dequeued, now the length of queue is {:u}.", req_queue.len());
                    }
                }
            });

            let request = request_port.recv();

            // Get stream from hashmap.
            // Use unsafe method, because TcpStream in Rust 0.9 doesn't have "Freeze" bound.
            let (stream_port, stream_chan) = Chan::new();
            unsafe {
                stream_map_get.unsafe_access(|local_stream_map| {
                    let stream = local_stream_map.pop(&request.peer_name).expect("no option tcpstream");
                    stream_chan.send(stream);
                });
            }

            // TODO: Spawning more tasks to respond the dequeued requests concurrently. You may need a semophore to control the concurrency.
            let stream = stream_port.recv();
            WebServer::respond_with_static_file(stream, request.path);
            // Close stream automatically.
            debug!("=====Terminated connection from [{:s}].=====", request.peer_name);
        }
    }

    fn get_peer_name(stream: &mut Option<std::io::net::tcp::TcpStream>) -> ~str {
        match *stream {
            Some(ref mut s) => {
                         match s.peer_name() {
                            Some(pn) => {pn.to_str()},
                            None => (~"")
                         }
                       },
            None => (~"")
        }
    }
}

fn get_args() -> (~str, uint, ~str) {
    fn print_usage(program: &str) {
        println!("Usage: {:s} [options]", program);
        println!("--ip     \tIP address, \"{:s}\" by default.", IP);
        println!("--port   \tport number, \"{:u}\" by default.", PORT);
        println!("--www    \tworking directory, \"{:s}\" by default", WWW_DIR);
        println("-h --help \tUsage");
    }

    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();
    let program = args[0].clone();

    let opts = ~[
        getopts::optopt("ip"),
        getopts::optopt("port"),
        getopts::optopt("www"),
        getopts::optflag("h"),
        getopts::optflag("help")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("h") || matches.opt_present("help") {
        print_usage(program);
        unsafe { libc::exit(1); }
    }

    let ip_str = if matches.opt_present("ip") {
                    matches.opt_str("ip").expect("invalid ip address?").to_owned()
                 } else {
                    IP.to_owned()
                 };

    let port:uint = if matches.opt_present("port") {
                        from_str::from_str(matches.opt_str("port").expect("invalid port number?")).expect("not uint?")
                    } else {
                        PORT
                    };

    let www_dir_str = if matches.opt_present("www") {
                        matches.opt_str("www").expect("invalid www argument?")
                      } else { WWW_DIR.to_owned() };

    (ip_str, port, www_dir_str)
}

fn main() {
    let (ip_str, port, www_dir_str) = get_args();
    let mut zhtta = WebServer::new(ip_str, port, www_dir_str);
    zhtta.run();
}<|endoftext|>


<commit_before>use builtins::man_pages::{check_help, MAN_IS};
use shell::Shell;

pub(crate) fn is(args: &[String], shell: &mut Shell) -> Result<(), String> {
    match args.len() {
        4 => if args[1] != "not" {
            return Err(format!("Expected 'not' instead found '{}'\n", args[1]).to_string());
        } else if eval_arg(&*args[2], shell) == eval_arg(&*args[3], shell) {
            return Err("".to_string());
        },
        3 => if eval_arg(&*args[1], shell) != eval_arg(&*args[2], shell) {
            return Err("".to_string());
        },
        _ => return Err("is needs 3 or 4 arguments\n".to_string()),
    }

    Ok(())
}

fn eval_arg(arg: &str, shell: &mut Shell) -> String {
    let value = get_var_string(arg, shell);
    if value != "" {
        return value;
    }
    arg.to_string()
}

// On error returns an empty String.
fn get_var_string(name: &str, shell: &mut Shell) -> String {
    if name.chars().nth(0).unwrap() != '$' {
        return "".to_string();
    }

    let var = shell.variables.get_var(&name[1..]);
    let sh_var: &str = match var.as_ref() {
        Some(s) => s,
        None => "",
    };

    sh_var.to_string()
}

#[test]
fn test_is() {
    fn vec_string(args: &[&str]) -> Vec<String> {
        args.iter().map(|s| (*s).to_owned()).collect::<Vec<String>>()
    }
    use shell::ShellBuilder;
    let mut shell = ShellBuilder::new().as_library();
    shell.set_var("x", "value");
    shell.set_var("y", "0");

    // Four arguments
    assert_eq!(
        is(&vec_string(&["is", " ", " ", " "]), &mut shell),
        Err("Expected 'not' instead found ' '\n".to_string())
    );
    assert_eq!(
        is(&vec_string(&["is", "not", " ", " "]), &mut shell),
        Err("".to_string())
    );
    assert_eq!(
        is(&vec_string(&["is", "not", "$x", "$x"]), &mut shell),
        Err("".to_string())
    );
    assert_eq!(is(&vec_string(&["is", "not", "2", "1"]), &mut shell), Ok(()));
    assert_eq!(is(&vec_string(&["is", "not", "$x", "$y"]), &mut shell), Ok(()));

    // Three arguments
    assert_eq!(is(&vec_string(&["is", "1", "2"]), &mut shell), Err("".to_string()));
    assert_eq!(is(&vec_string(&["is", "$x", "$y"]), &mut shell), Err("".to_string()));
    assert_eq!(is(&vec_string(&["is", " ", " "]), &mut shell), Ok(()));
    assert_eq!(is(&vec_string(&["is", "$x", "$x"]), &mut shell), Ok(()));

    // Two arguments
    assert_eq!(
        is(&vec_string(&["is", " "]), &mut shell),
        Err("is needs 3 or 4 arguments\n".to_string())
    );

    // One argument
    assert_eq!(
        is(&vec_string(&["is"]), &mut shell),
        Err("is needs 3 or 4 arguments\n".to_string())
    );
}
<commit_msg>Removed unused imports<commit_after>use shell::Shell;

pub(crate) fn is(args: &[String], shell: &mut Shell) -> Result<(), String> {
    match args.len() {
        4 => if args[1] != "not" {
            return Err(format!("Expected 'not' instead found '{}'\n", args[1]).to_string());
        } else if eval_arg(&*args[2], shell) == eval_arg(&*args[3], shell) {
            return Err("".to_string());
        },
        3 => if eval_arg(&*args[1], shell) != eval_arg(&*args[2], shell) {
            return Err("".to_string());
        },
        _ => return Err("is needs 3 or 4 arguments\n".to_string()),
    }

    Ok(())
}

fn eval_arg(arg: &str, shell: &mut Shell) -> String {
    let value = get_var_string(arg, shell);
    if value != "" {
        return value;
    }
    arg.to_string()
}

// On error returns an empty String.
fn get_var_string(name: &str, shell: &mut Shell) -> String {
    if name.chars().nth(0).unwrap() != '$' {
        return "".to_string();
    }

    let var = shell.variables.get_var(&name[1..]);
    let sh_var: &str = match var.as_ref() {
        Some(s) => s,
        None => "",
    };

    sh_var.to_string()
}

#[test]
fn test_is() {
    fn vec_string(args: &[&str]) -> Vec<String> {
        args.iter().map(|s| (*s).to_owned()).collect::<Vec<String>>()
    }
    use shell::ShellBuilder;
    let mut shell = ShellBuilder::new().as_library();
    shell.set_var("x", "value");
    shell.set_var("y", "0");

    // Four arguments
    assert_eq!(
        is(&vec_string(&["is", " ", " ", " "]), &mut shell),
        Err("Expected 'not' instead found ' '\n".to_string())
    );
    assert_eq!(
        is(&vec_string(&["is", "not", " ", " "]), &mut shell),
        Err("".to_string())
    );
    assert_eq!(
        is(&vec_string(&["is", "not", "$x", "$x"]), &mut shell),
        Err("".to_string())
    );
    assert_eq!(is(&vec_string(&["is", "not", "2", "1"]), &mut shell), Ok(()));
    assert_eq!(is(&vec_string(&["is", "not", "$x", "$y"]), &mut shell), Ok(()));

    // Three arguments
    assert_eq!(is(&vec_string(&["is", "1", "2"]), &mut shell), Err("".to_string()));
    assert_eq!(is(&vec_string(&["is", "$x", "$y"]), &mut shell), Err("".to_string()));
    assert_eq!(is(&vec_string(&["is", " ", " "]), &mut shell), Ok(()));
    assert_eq!(is(&vec_string(&["is", "$x", "$x"]), &mut shell), Ok(()));

    // Two arguments
    assert_eq!(
        is(&vec_string(&["is", " "]), &mut shell),
        Err("is needs 3 or 4 arguments\n".to_string())
    );

    // One argument
    assert_eq!(
        is(&vec_string(&["is"]), &mut shell),
        Err("is needs 3 or 4 arguments\n".to_string())
    );
}
<|endoftext|>