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

#[cfg(feature = "nightly")]
use std::sync::atomic::{AtomicUsize, Ordering};
#[cfg(not(feature = "nightly"))]
use stable::{AtomicUsize, Ordering};
use std::thread;
use parking_lot::{self, UnparkResult};
use elision::{have_elision, AtomicElisionExt};
use SPIN_LIMIT;

const SHARED_PARKED_BIT: usize = 1;
const EXCLUSIVE_PARKED_BIT: usize = 2;
const EXCLUSIVE_LOCKED_BIT: usize = 4;
const SHARED_COUNT_MASK: usize = !7;
const SHARED_COUNT_INC: usize = 8;

pub struct RawRwLock {
    state: AtomicUsize,
}

impl RawRwLock {
    #[cfg(feature = "nightly")]
    #[inline]
    pub const fn new() -> RawRwLock {
        RawRwLock { state: AtomicUsize::new(0) }
    }
    #[cfg(not(feature = "nightly"))]
    #[inline]
    pub fn new() -> RawRwLock {
        RawRwLock { state: AtomicUsize::new(0) }
    }

    #[inline]
    pub fn lock_exclusive(&self) {
        if self.state
            .compare_exchange_weak(0,
                                   EXCLUSIVE_LOCKED_BIT,
                                   Ordering::Acquire,
                                   Ordering::Relaxed)
            .is_ok() {
            return;
        }
        self.lock_exclusive_slow();
    }

    #[inline]
    pub fn try_lock_exclusive(&self) -> bool {
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            if state & (EXCLUSIVE_LOCKED_BIT | SHARED_COUNT_MASK) != 0 {
                return false;
            }
            match self.state.compare_exchange_weak(state,
                                                   state | EXCLUSIVE_LOCKED_BIT,
                                                   Ordering::Acquire,
                                                   Ordering::Relaxed) {
                Ok(_) => return true,
                Err(x) => state = x,
            }
        }
    }

    #[inline]
    pub fn unlock_exclusive(&self) {
        if self.state
            .compare_exchange_weak(EXCLUSIVE_LOCKED_BIT,
                                   0,
                                   Ordering::Release,
                                   Ordering::Relaxed)
            .is_ok() {
            return;
        }
        self.unlock_exclusive_slow();
    }

    #[inline]
    pub fn lock_shared(&self) {
        let state = self.state.load(Ordering::Relaxed);
        // Use hardware lock elision to avoid cache conflicts when multiple
        // readers try to acquire the lock. We only do this if the lock is
        // completely empty since elision handles conflicts poorly.
        if have_elision() && state == 0 {
            if self.state.elision_acquire(0, SHARED_COUNT_INC) {
                return;
            }
        } else if let Some(new_state) = state.checked_add(SHARED_COUNT_INC) {
            if state & (EXCLUSIVE_LOCKED_BIT | EXCLUSIVE_PARKED_BIT) == 0 &&
               self.state
                .compare_exchange_weak(state, new_state, Ordering::Acquire, Ordering::Relaxed)
                .is_ok() {
                return;
            }
        }
        self.lock_shared_slow();
    }

    #[inline]
    pub fn try_lock_shared(&self) -> bool {
        let state = self.state.load(Ordering::Relaxed);
        if state & (EXCLUSIVE_LOCKED_BIT | EXCLUSIVE_PARKED_BIT) != 0 {
            return false;
        }
        // Use hardware lock elision to avoid cache conflicts when multiple
        // readers try to acquire the lock. We only do this if the lock is
        // completely empty since elision handles conflicts poorly.
        if have_elision() && state == 0 {
            if self.state.elision_acquire(0, SHARED_COUNT_INC) {
                return true;
            }
        } else if let Some(new_state) = state.checked_add(SHARED_COUNT_INC) {
            if state & (EXCLUSIVE_LOCKED_BIT | EXCLUSIVE_PARKED_BIT) == 0 &&
               self.state
                .compare_exchange_weak(state, new_state, Ordering::Acquire, Ordering::Relaxed)
                .is_ok() {
                return true;
            }
        }
        self.try_lock_shared_slow()
    }

    #[inline]
    pub fn unlock_shared(&self) {
        let state = self.state.load(Ordering::Relaxed);
        // Release the elided lock here. If we elided the lock then it will look
        // as if we are the only reader on it.
        if have_elision() && state == SHARED_COUNT_INC {
            if self.state.elision_release(SHARED_COUNT_INC, 0) {
                return;
            }
        } else {
            if (state & EXCLUSIVE_PARKED_BIT == 0 ||
                state & SHARED_COUNT_MASK != SHARED_COUNT_INC) &&
               self.state
                .compare_exchange_weak(state,
                                       state - SHARED_COUNT_INC,
                                       Ordering::Release,
                                       Ordering::Relaxed)
                .is_ok() {
                return;

            }
        }
        self.unlock_shared_slow();
    }

    #[cold]
    #[inline(never)]
    fn lock_exclusive_slow(&self) {
        let mut spin_count = 0;
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            // Grab the lock if it isn't locked, even if there are other
            // threads parked.
            if state & (EXCLUSIVE_LOCKED_BIT | SHARED_COUNT_MASK) == 0 {
                match self.state
                    .compare_exchange_weak(state,
                                           state | EXCLUSIVE_LOCKED_BIT,
                                           Ordering::Acquire,
                                           Ordering::Relaxed) {
                    Ok(_) => return,
                    Err(x) => state = x,
                }
                continue;
            }

            // If there are no parked exclusive threads and only one reader or
            // writer, try spinning a few times.
            if state & EXCLUSIVE_PARKED_BIT == 0 &&
               (state & EXCLUSIVE_LOCKED_BIT != 0 ||
                state & SHARED_COUNT_MASK == SHARED_COUNT_INC) &&
               spin_count < SPIN_LIMIT {
                spin_count += 1;
                thread::yield_now();
                state = self.state.load(Ordering::Relaxed);
                continue;
            }

            // Set the parked bit
            if state & EXCLUSIVE_PARKED_BIT == 0 {
                if let Err(x) = self.state.compare_exchange_weak(state,
                                                                 state | EXCLUSIVE_PARKED_BIT,
                                                                 Ordering::Relaxed,
                                                                 Ordering::Relaxed) {
                    state = x;
                    continue;
                }
            }

            // Park our thread until we are woken up by an unlock
            unsafe {
                let addr = self as *const _ as usize;
                let validate = &mut || {
                    let state = self.state.load(Ordering::Relaxed);
                    state & EXCLUSIVE_PARKED_BIT != 0 &&
                    state & (EXCLUSIVE_LOCKED_BIT | SHARED_COUNT_MASK) != 0
                };
                let before_sleep = &mut || {};
                let timed_out = &mut |_, _| unreachable!();
                parking_lot::park(addr, validate, before_sleep, timed_out, None);
            }

            // Loop back and try locking again
            state = self.state.load(Ordering::Relaxed);
        }
    }

    #[cold]
    #[inline(never)]
    fn unlock_exclusive_slow(&self) {
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            // Unlock directly if there are no parked threads
            if state & (EXCLUSIVE_PARKED_BIT | SHARED_PARKED_BIT) == 0 {
                match self.state
                    .compare_exchange_weak(EXCLUSIVE_LOCKED_BIT,
                                           0,
                                           Ordering::Release,
                                           Ordering::Relaxed) {
                    Ok(_) => return,
                    Err(x) => state = x,
                }
                continue;
            }

            // If there are exclusive parked threads, wake one of them up.
            if state & EXCLUSIVE_PARKED_BIT != 0 {
                unsafe {
                    let addr = self as *const _ as usize;
                    let callback = &mut |result| {
                        // Clear the exclusive parked bit if this was the last
                        // exclusive thread. Also clear the locked bit if we
                        // successfully unparked a thread.
                        let mask = match result {
                            UnparkResult::UnparkedNotLast => !EXCLUSIVE_LOCKED_BIT,
                            UnparkResult::UnparkedLast => {
                                !(EXCLUSIVE_PARKED_BIT | EXCLUSIVE_LOCKED_BIT)
                            }
                            UnparkResult::NoParkedThreads => !EXCLUSIVE_PARKED_BIT,
                        };
                        self.state.fetch_and(mask, Ordering::Release);
                    };
                    if parking_lot::unpark_one(addr, callback) != UnparkResult::NoParkedThreads {
                        // If we successfully unparked an exclusive thread,
                        // stop here.
                        return;
                    }
                }
            }

            // Release the exclusive lock and clear the shared parked bit
            if let Err(x) = self.state
                .compare_exchange_weak(EXCLUSIVE_LOCKED_BIT | SHARED_PARKED_BIT,
                                       0,
                                       Ordering::Release,
                                       Ordering::Relaxed) {
                state = x;
                continue;
            }

            // Unpark all waiting shared threads.
            unsafe {
                let addr = self as *const _ as usize;
                parking_lot::unpark_all(addr + 1);
            }
            break;
        }
    }

    #[cold]
    #[inline(never)]
    fn lock_shared_slow(&self) {
        let mut spin_count = 0;
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            // Grab the lock if there are no exclusive threads locked or waiting
            if state & (EXCLUSIVE_LOCKED_BIT | EXCLUSIVE_PARKED_BIT) == 0 {
                match self.state
                    .compare_exchange_weak(state,
                                           state.checked_add(SHARED_COUNT_INC)
                                               .expect("RwLock shared count overflow"),
                                           Ordering::Acquire,
                                           Ordering::Relaxed) {
                    Ok(_) => return,
                    Err(x) => state = x,
                }
                continue;
            }

            // If there are no parked exclusive threads, try spinning a few
            // times
            if state & EXCLUSIVE_PARKED_BIT == 0 && spin_count < SPIN_LIMIT {
                spin_count += 1;
                thread::yield_now();
                state = self.state.load(Ordering::Relaxed);
                continue;
            }

            // Set the shared parked bit
            if state & SHARED_PARKED_BIT == 0 {
                if let Err(x) = self.state.compare_exchange_weak(state,
                                                                 state | SHARED_PARKED_BIT,
                                                                 Ordering::Relaxed,
                                                                 Ordering::Relaxed) {
                    state = x;
                    continue;
                }
            }

            // Park our thread until we are woken up by an unlock
            unsafe {
                let addr = self as *const _ as usize;
                let validate = &mut || {
                    let state = self.state.load(Ordering::Relaxed);
                    state & SHARED_PARKED_BIT != 0 &&
                    state & (EXCLUSIVE_LOCKED_BIT | EXCLUSIVE_PARKED_BIT) != 0
                };
                let before_sleep = &mut || {};
                let timed_out = &mut |_, _| unreachable!();
                parking_lot::park(addr + 1, validate, before_sleep, timed_out, None);
            }

            // Loop back and try locking again
            state = self.state.load(Ordering::Relaxed);
        }
    }

    #[cold]
    #[inline(never)]
    pub fn try_lock_shared_slow(&self) -> bool {
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            if state & (EXCLUSIVE_LOCKED_BIT | EXCLUSIVE_PARKED_BIT) != 0 {
                return false;
            }
            // Use hardware lock elision to avoid cache conflicts when multiple
            // readers try to acquire the lock. We only do this if the lock is
            // completely empty since elision handles conflicts poorly.
            if have_elision() && state == 0 {
                if self.state.elision_acquire(0, SHARED_COUNT_INC) {
                    return true;
                }
            } else {
                match self.state.compare_exchange(state,
                                                  state.checked_add(SHARED_COUNT_INC)
                                                      .expect("RwLock shared count overflow"),
                                                  Ordering::Acquire,
                                                  Ordering::Relaxed) {
                    Ok(_) => return true,
                    Err(x) => state = x,
                }
            }
        }
    }

    #[cold]
    #[inline(never)]
    fn unlock_shared_slow(&self) {
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            // If this is the last shared thread and there are exclusive parked
            // threads then wake one up.
            if state & EXCLUSIVE_PARKED_BIT != 0 && state & SHARED_COUNT_MASK == SHARED_COUNT_INC {
                unsafe {
                    let addr = self as *const _ as usize;
                    let callback = &mut |result| {
                        // Clear the exclusive parked bit if this was the last
                        // exclusive thread.
                        loop {
                            let mut new_state = state;
                            if result != UnparkResult::NoParkedThreads {
                                new_state -= SHARED_COUNT_INC;
                            }
                            if result != UnparkResult::UnparkedNotLast {
                                new_state &= !EXCLUSIVE_PARKED_BIT;
                            }
                            match self.state.compare_exchange_weak(state,
                                                                   new_state,
                                                                   Ordering::Release,
                                                                   Ordering::Relaxed) {
                                Ok(_) => {
                                    state = new_state;
                                    return;
                                }
                                Err(x) => state = x,
                            }
                        }
                    };
                    if parking_lot::unpark_one(addr, callback) != UnparkResult::NoParkedThreads {
                        // If we successfully unparked an exclusive thread,
                        // stop here.
                        return;
                    }
                }
            }

            // Release the shared lock and clear the shared parked bit if there
            // are no pending exclusive threads.
            let mut new_state = state - SHARED_COUNT_INC;
            if state & EXCLUSIVE_PARKED_BIT == 0 {
                new_state &= !SHARED_PARKED_BIT;
            }
            if let Err(x) = self.state
                .compare_exchange_weak(state, new_state, Ordering::Release, Ordering::Relaxed) {
                state = x;
                continue;
            }

            // If there are any shared parked threads and no parked exclusive
            // threads then unpark all shared threads.
            if state & EXCLUSIVE_PARKED_BIT == 0 && state & SHARED_PARKED_BIT != 0 {
                unsafe {
                    let addr = self as *const _ as usize;
                    parking_lot::unpark_all(addr + 1);
                }
            }
            break;
        }
    }
}
<commit_msg>Remove stray newline<commit_after>// Copyright 2016 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

#[cfg(feature = "nightly")]
use std::sync::atomic::{AtomicUsize, Ordering};
#[cfg(not(feature = "nightly"))]
use stable::{AtomicUsize, Ordering};
use std::thread;
use parking_lot::{self, UnparkResult};
use elision::{have_elision, AtomicElisionExt};
use SPIN_LIMIT;

const SHARED_PARKED_BIT: usize = 1;
const EXCLUSIVE_PARKED_BIT: usize = 2;
const EXCLUSIVE_LOCKED_BIT: usize = 4;
const SHARED_COUNT_MASK: usize = !7;
const SHARED_COUNT_INC: usize = 8;

pub struct RawRwLock {
    state: AtomicUsize,
}

impl RawRwLock {
    #[cfg(feature = "nightly")]
    #[inline]
    pub const fn new() -> RawRwLock {
        RawRwLock { state: AtomicUsize::new(0) }
    }
    #[cfg(not(feature = "nightly"))]
    #[inline]
    pub fn new() -> RawRwLock {
        RawRwLock { state: AtomicUsize::new(0) }
    }

    #[inline]
    pub fn lock_exclusive(&self) {
        if self.state
            .compare_exchange_weak(0,
                                   EXCLUSIVE_LOCKED_BIT,
                                   Ordering::Acquire,
                                   Ordering::Relaxed)
            .is_ok() {
            return;
        }
        self.lock_exclusive_slow();
    }

    #[inline]
    pub fn try_lock_exclusive(&self) -> bool {
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            if state & (EXCLUSIVE_LOCKED_BIT | SHARED_COUNT_MASK) != 0 {
                return false;
            }
            match self.state.compare_exchange_weak(state,
                                                   state | EXCLUSIVE_LOCKED_BIT,
                                                   Ordering::Acquire,
                                                   Ordering::Relaxed) {
                Ok(_) => return true,
                Err(x) => state = x,
            }
        }
    }

    #[inline]
    pub fn unlock_exclusive(&self) {
        if self.state
            .compare_exchange_weak(EXCLUSIVE_LOCKED_BIT,
                                   0,
                                   Ordering::Release,
                                   Ordering::Relaxed)
            .is_ok() {
            return;
        }
        self.unlock_exclusive_slow();
    }

    #[inline]
    pub fn lock_shared(&self) {
        let state = self.state.load(Ordering::Relaxed);
        // Use hardware lock elision to avoid cache conflicts when multiple
        // readers try to acquire the lock. We only do this if the lock is
        // completely empty since elision handles conflicts poorly.
        if have_elision() && state == 0 {
            if self.state.elision_acquire(0, SHARED_COUNT_INC) {
                return;
            }
        } else if let Some(new_state) = state.checked_add(SHARED_COUNT_INC) {
            if state & (EXCLUSIVE_LOCKED_BIT | EXCLUSIVE_PARKED_BIT) == 0 &&
               self.state
                .compare_exchange_weak(state, new_state, Ordering::Acquire, Ordering::Relaxed)
                .is_ok() {
                return;
            }
        }
        self.lock_shared_slow();
    }

    #[inline]
    pub fn try_lock_shared(&self) -> bool {
        let state = self.state.load(Ordering::Relaxed);
        if state & (EXCLUSIVE_LOCKED_BIT | EXCLUSIVE_PARKED_BIT) != 0 {
            return false;
        }
        // Use hardware lock elision to avoid cache conflicts when multiple
        // readers try to acquire the lock. We only do this if the lock is
        // completely empty since elision handles conflicts poorly.
        if have_elision() && state == 0 {
            if self.state.elision_acquire(0, SHARED_COUNT_INC) {
                return true;
            }
        } else if let Some(new_state) = state.checked_add(SHARED_COUNT_INC) {
            if state & (EXCLUSIVE_LOCKED_BIT | EXCLUSIVE_PARKED_BIT) == 0 &&
               self.state
                .compare_exchange_weak(state, new_state, Ordering::Acquire, Ordering::Relaxed)
                .is_ok() {
                return true;
            }
        }
        self.try_lock_shared_slow()
    }

    #[inline]
    pub fn unlock_shared(&self) {
        let state = self.state.load(Ordering::Relaxed);
        // Release the elided lock here. If we elided the lock then it will look
        // as if we are the only reader on it.
        if have_elision() && state == SHARED_COUNT_INC {
            if self.state.elision_release(SHARED_COUNT_INC, 0) {
                return;
            }
        } else {
            if (state & EXCLUSIVE_PARKED_BIT == 0 ||
                state & SHARED_COUNT_MASK != SHARED_COUNT_INC) &&
               self.state
                .compare_exchange_weak(state,
                                       state - SHARED_COUNT_INC,
                                       Ordering::Release,
                                       Ordering::Relaxed)
                .is_ok() {
                return;

            }
        }
        self.unlock_shared_slow();
    }

    #[cold]
    #[inline(never)]
    fn lock_exclusive_slow(&self) {
        let mut spin_count = 0;
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            // Grab the lock if it isn't locked, even if there are other
            // threads parked.
            if state & (EXCLUSIVE_LOCKED_BIT | SHARED_COUNT_MASK) == 0 {
                match self.state
                    .compare_exchange_weak(state,
                                           state | EXCLUSIVE_LOCKED_BIT,
                                           Ordering::Acquire,
                                           Ordering::Relaxed) {
                    Ok(_) => return,
                    Err(x) => state = x,
                }
                continue;
            }

            // If there are no parked exclusive threads and only one reader or
            // writer, try spinning a few times.
            if state & EXCLUSIVE_PARKED_BIT == 0 &&
               (state & EXCLUSIVE_LOCKED_BIT != 0 ||
                state & SHARED_COUNT_MASK == SHARED_COUNT_INC) &&
               spin_count < SPIN_LIMIT {
                spin_count += 1;
                thread::yield_now();
                state = self.state.load(Ordering::Relaxed);
                continue;
            }

            // Set the parked bit
            if state & EXCLUSIVE_PARKED_BIT == 0 {
                if let Err(x) = self.state.compare_exchange_weak(state,
                                                                 state | EXCLUSIVE_PARKED_BIT,
                                                                 Ordering::Relaxed,
                                                                 Ordering::Relaxed) {
                    state = x;
                    continue;
                }
            }

            // Park our thread until we are woken up by an unlock
            unsafe {
                let addr = self as *const _ as usize;
                let validate = &mut || {
                    let state = self.state.load(Ordering::Relaxed);
                    state & EXCLUSIVE_PARKED_BIT != 0 &&
                    state & (EXCLUSIVE_LOCKED_BIT | SHARED_COUNT_MASK) != 0
                };
                let before_sleep = &mut || {};
                let timed_out = &mut |_, _| unreachable!();
                parking_lot::park(addr, validate, before_sleep, timed_out, None);
            }

            // Loop back and try locking again
            state = self.state.load(Ordering::Relaxed);
        }
    }

    #[cold]
    #[inline(never)]
    fn unlock_exclusive_slow(&self) {
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            // Unlock directly if there are no parked threads
            if state & (EXCLUSIVE_PARKED_BIT | SHARED_PARKED_BIT) == 0 {
                match self.state
                    .compare_exchange_weak(EXCLUSIVE_LOCKED_BIT,
                                           0,
                                           Ordering::Release,
                                           Ordering::Relaxed) {
                    Ok(_) => return,
                    Err(x) => state = x,
                }
                continue;
            }

            // If there are exclusive parked threads, wake one of them up.
            if state & EXCLUSIVE_PARKED_BIT != 0 {
                unsafe {
                    let addr = self as *const _ as usize;
                    let callback = &mut |result| {
                        // Clear the exclusive parked bit if this was the last
                        // exclusive thread. Also clear the locked bit if we
                        // successfully unparked a thread.
                        let mask = match result {
                            UnparkResult::UnparkedNotLast => !EXCLUSIVE_LOCKED_BIT,
                            UnparkResult::UnparkedLast => {
                                !(EXCLUSIVE_PARKED_BIT | EXCLUSIVE_LOCKED_BIT)
                            }
                            UnparkResult::NoParkedThreads => !EXCLUSIVE_PARKED_BIT,
                        };
                        self.state.fetch_and(mask, Ordering::Release);
                    };
                    if parking_lot::unpark_one(addr, callback) != UnparkResult::NoParkedThreads {
                        // If we successfully unparked an exclusive thread,
                        // stop here.
                        return;
                    }
                }
            }

            // Release the exclusive lock and clear the shared parked bit
            if let Err(x) = self.state
                .compare_exchange_weak(EXCLUSIVE_LOCKED_BIT | SHARED_PARKED_BIT,
                                       0,
                                       Ordering::Release,
                                       Ordering::Relaxed) {
                state = x;
                continue;
            }

            // Unpark all waiting shared threads.
            unsafe {
                let addr = self as *const _ as usize;
                parking_lot::unpark_all(addr + 1);
            }
            break;
        }
    }

    #[cold]
    #[inline(never)]
    fn lock_shared_slow(&self) {
        let mut spin_count = 0;
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            // Grab the lock if there are no exclusive threads locked or waiting
            if state & (EXCLUSIVE_LOCKED_BIT | EXCLUSIVE_PARKED_BIT) == 0 {
                match self.state
                    .compare_exchange_weak(state,
                                           state.checked_add(SHARED_COUNT_INC)
                                               .expect("RwLock shared count overflow"),
                                           Ordering::Acquire,
                                           Ordering::Relaxed) {
                    Ok(_) => return,
                    Err(x) => state = x,
                }
                continue;
            }

            // If there are no parked exclusive threads, try spinning a few
            // times
            if state & EXCLUSIVE_PARKED_BIT == 0 && spin_count < SPIN_LIMIT {
                spin_count += 1;
                thread::yield_now();
                state = self.state.load(Ordering::Relaxed);
                continue;
            }

            // Set the shared parked bit
            if state & SHARED_PARKED_BIT == 0 {
                if let Err(x) = self.state.compare_exchange_weak(state,
                                                                 state | SHARED_PARKED_BIT,
                                                                 Ordering::Relaxed,
                                                                 Ordering::Relaxed) {
                    state = x;
                    continue;
                }
            }

            // Park our thread until we are woken up by an unlock
            unsafe {
                let addr = self as *const _ as usize;
                let validate = &mut || {
                    let state = self.state.load(Ordering::Relaxed);
                    state & SHARED_PARKED_BIT != 0 &&
                    state & (EXCLUSIVE_LOCKED_BIT | EXCLUSIVE_PARKED_BIT) != 0
                };
                let before_sleep = &mut || {};
                let timed_out = &mut |_, _| unreachable!();
                parking_lot::park(addr + 1, validate, before_sleep, timed_out, None);
            }

            // Loop back and try locking again
            state = self.state.load(Ordering::Relaxed);
        }
    }

    #[cold]
    #[inline(never)]
    pub fn try_lock_shared_slow(&self) -> bool {
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            if state & (EXCLUSIVE_LOCKED_BIT | EXCLUSIVE_PARKED_BIT) != 0 {
                return false;
            }
            // Use hardware lock elision to avoid cache conflicts when multiple
            // readers try to acquire the lock. We only do this if the lock is
            // completely empty since elision handles conflicts poorly.
            if have_elision() && state == 0 {
                if self.state.elision_acquire(0, SHARED_COUNT_INC) {
                    return true;
                }
            } else {
                match self.state.compare_exchange(state,
                                                  state.checked_add(SHARED_COUNT_INC)
                                                      .expect("RwLock shared count overflow"),
                                                  Ordering::Acquire,
                                                  Ordering::Relaxed) {
                    Ok(_) => return true,
                    Err(x) => state = x,
                }
            }
        }
    }

    #[cold]
    #[inline(never)]
    fn unlock_shared_slow(&self) {
        let mut state = self.state.load(Ordering::Relaxed);
        loop {
            // If this is the last shared thread and there are exclusive parked
            // threads then wake one up.
            if state & EXCLUSIVE_PARKED_BIT != 0 && state & SHARED_COUNT_MASK == SHARED_COUNT_INC {
                unsafe {
                    let addr = self as *const _ as usize;
                    let callback = &mut |result| {
                        // Clear the exclusive parked bit if this was the last
                        // exclusive thread.
                        loop {
                            let mut new_state = state;
                            if result != UnparkResult::NoParkedThreads {
                                new_state -= SHARED_COUNT_INC;
                            }
                            if result != UnparkResult::UnparkedNotLast {
                                new_state &= !EXCLUSIVE_PARKED_BIT;
                            }
                            match self.state.compare_exchange_weak(state,
                                                                   new_state,
                                                                   Ordering::Release,
                                                                   Ordering::Relaxed) {
                                Ok(_) => {
                                    state = new_state;
                                    return;
                                }
                                Err(x) => state = x,
                            }
                        }
                    };
                    if parking_lot::unpark_one(addr, callback) != UnparkResult::NoParkedThreads {
                        // If we successfully unparked an exclusive thread,
                        // stop here.
                        return;
                    }
                }
            }

            // Release the shared lock and clear the shared parked bit if there
            // are no pending exclusive threads.
            let mut new_state = state - SHARED_COUNT_INC;
            if state & EXCLUSIVE_PARKED_BIT == 0 {
                new_state &= !SHARED_PARKED_BIT;
            }
            if let Err(x) = self.state
                .compare_exchange_weak(state, new_state, Ordering::Release, Ordering::Relaxed) {
                state = x;
                continue;
            }

            // If there are any shared parked threads and no parked exclusive
            // threads then unpark all shared threads.
            if state & EXCLUSIVE_PARKED_BIT == 0 && state & SHARED_PARKED_BIT != 0 {
                unsafe {
                    let addr = self as *const _ as usize;
                    parking_lot::unpark_all(addr + 1);
                }
            }
            break;
        }
    }
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;
use super::{Collection, SearchableByOrder, RetainsOrder, SortOrder, Sortable};

// Impl traits for &mut [T].

impl<'a, T> Collection for &'a mut [T] {
    type Item = T;
}

impl<'a, T> Sortable for &'a mut [T] {
    fn sort<F>(&mut self, f: F)
        where F: FnMut(&Self::Item, &Self::Item) -> Ordering
    {
        self.sort_by(f);
    }
}

impl<'a, T, O> SearchableByOrder<O> for &'a mut [T] where
    O: SortOrder<T>
{
    fn search(&self, a: &T) -> Result<usize, usize>
    {
        self.binary_search_by(|b| O::cmp(a, b))
    }
}

impl<'a, T> RetainsOrder for &'a mut [T] {}

// Impl traits for &[T].

impl<'a, T> Collection for &'a [T] {
    type Item = T;
}

impl<'a, T, O> SearchableByOrder<O> for &'a [T]
    where O: SortOrder<T>
{
    fn search(&self, a: &T) -> Result<usize, usize>
    {
        self.binary_search_by(|b| O::cmp(a, b))
    }
}

impl<'a, T> RetainsOrder for &'a [T] {}

// Impl traits for [T;n]

macro_rules! arr_traits {
    ($($x:expr)*) => {
        $(
            impl<T> Collection for [T;$x] {
                type Item = T;
            }

            impl<T> Sortable for [T;$x]
            {
                fn sort<F>(&mut self, f: F)
                where
                    F: FnMut(&Self::Item, &Self::Item) -> Ordering
                {
                    self.sort_by(f);
                }
            }

            impl<T,O> SearchableByOrder<O> for [T;$x]
                where O: SortOrder<T>
            {
                fn search(&self, a: &T) -> Result<usize, usize>
                {
                    self.binary_search_by(|b| O::cmp(a,b))
                }
            }

            impl<T> RetainsOrder for [T;$x] {}
        )*
    }
}

arr_traits!(
     1  2  3  4  5  6  7  8
     9 10 11 12 13 14 15 16
    17 18 19 20 21 22 23 24
    25 26 27 28 29 30 31 32
);<commit_msg>Add impl Collection, RetainsOrder and SearchableByOrder for [T].<commit_after>use std::cmp::Ordering;
use super::{Collection, SearchableByOrder, RetainsOrder, SortOrder, Sortable};

// Impl traits for &mut [T].

impl<'a, T> Collection for &'a mut [T] {
    type Item = T;
}

impl<'a, T> Sortable for &'a mut [T] {
    fn sort<F>(&mut self, f: F)
        where F: FnMut(&Self::Item, &Self::Item) -> Ordering
    {
        self.sort_by(f);
    }
}

impl<'a, T, O> SearchableByOrder<O> for &'a mut [T] where
    O: SortOrder<T>
{
    fn search(&self, a: &T) -> Result<usize, usize>
    {
        self.binary_search_by(|b| O::cmp(a, b))
    }
}

impl<'a, T> RetainsOrder for &'a mut [T] {}

// Impl traits for &[T].

impl<'a, T> Collection for &'a [T] {
    type Item = T;
}

impl<'a, T, O> SearchableByOrder<O> for &'a [T]
    where O: SortOrder<T>
{
    fn search(&self, a: &T) -> Result<usize, usize>
    {
        self.binary_search_by(|b| O::cmp(a, b))
    }
}

impl<'a, T> RetainsOrder for &'a [T] {}

impl<T> Collection for [T] {
    type Item = T;
}

impl<T> RetainsOrder for [T] {}

impl<T,O> SearchableByOrder<O> for [T]
    where O: SortOrder<T>
{
    fn search(&self, a: &T) -> Result<usize, usize>
    {
        self.binary_search_by(|b| O::cmp(a, b))
    }
}

// Impl traits for [T;n]

macro_rules! arr_traits {
    ($($x:expr)*) => {
        $(
            impl<T> Collection for [T;$x] {
                type Item = T;
            }

            impl<T> Sortable for [T;$x]
            {
                fn sort<F>(&mut self, f: F)
                where
                    F: FnMut(&Self::Item, &Self::Item) -> Ordering
                {
                    self.sort_by(f);
                }
            }

            impl<T,O> SearchableByOrder<O> for [T;$x]
                where O: SortOrder<T>
            {
                fn search(&self, a: &T) -> Result<usize, usize>
                {
                    self.binary_search_by(|b| O::cmp(a,b))
                }
            }

            impl<T> RetainsOrder for [T;$x] {}
        )*
    }
}

arr_traits!(
     1  2  3  4  5  6  7  8
     9 10 11 12 13 14 15 16
    17 18 19 20 21 22 23 24
    25 26 27 28 29 30 31 32
);<|endoftext|>


<commit_before>mod block;
mod camera;
mod cube;
mod error;
mod event;
mod shader;
mod text;
mod texture;
mod wire_cube;

use std::f32::consts::PI;

use image;
use cgmath::{ Point, Point3, Matrix4 };
use glium::{ self, glutin, DisplayBuild, Surface };
use glium::program::Program;
use glium::glutin::Event as GlEvent;
use glium::backend::glutin_backend::WinRef;

use self::camera::Camera;
use self::text::Text;
use self::error::RenderCreationError;
use self::event::Event;
use game::GameState;

const MOUSE_SENSIVITY: f32 = 0.1;

#[derive(Clone, Copy, Debug)]
pub struct Position {
    pub cube_pos: (i32, i32, i32),
}
implement_vertex!(Position, cube_pos);

#[derive(Clone, Copy, Debug)]
pub enum HDirection {
    Forth,
    Back,
    Left,
    Right,
}

#[derive(Clone, Copy, Debug)]
pub enum VDirection {
    Up,
    Down,
}

pub struct Renderer {
    display: glium::Display,
    cube_program: Program,
    wire_program: Program,
    camera: Camera,
    fov: f32, //in radians
    text: Text,
    stats: bool,
    fill: bool,
    game: GameState,
}

impl Renderer {
    pub fn new() -> Result<Renderer, RenderCreationError<glutin::CreationError>> {
        let display = try!(glutin::WindowBuilder::new()
            .with_depth_buffer(24)
            .build_glium());
        let cube_prog = try!(Program::from_source(
            &display,
            shader::CUBE_VERTEX,
            shader::CUBE_FRAGMENT,
            None,
        ));
        let wire_prog = try!(Program::from_source(
            &display,
            shader::WIRE_VERTEX,
            shader::WIRE_FRAGMENT,
            None,
        ));
        let text = try!(Text::new(&display, "/usr/share/fonts/TTF/NotoSans-Regular.ttf", 24));
        {
            let window = display.get_window().unwrap();
            window.set_cursor(glium::glutin::MouseCursor::Crosshair);
        }
        Ok(Renderer {
            display: display,
            cube_program: cube_prog,
            wire_program: wire_prog,
            camera: Camera::at(Point3::new(5.0, 5.0, 5.0), Point::origin()),
            fov: PI / 3.0,
            text: text,
            stats: false,
            fill: true,
            game: GameState::new(),
        })
    }

    pub fn game_loop(mut self) {

        let image = image::load(::std::io::Cursor::new(&include_bytes!(
            "../../assets/textures/dirt.png"
        )[..]),image::PNG).unwrap().to_rgba();
        let image_dimensions = image.dimensions();
        let image = glium::texture::RawImage2d::from_raw_rgba_reversed(image.into_raw(), image_dimensions);
        let texture = glium::texture::SrgbTexture2d::new(&self.display, image).unwrap();
        let texture_sampler = glium::uniforms::Sampler::new(&texture)
            .magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest)
            .minify_filter(glium::uniforms::MinifySamplerFilter::Nearest);

        let vb_cube = glium::VertexBuffer::new(&self.display, &cube::VERTICES).unwrap();
        let ib_cube = glium::IndexBuffer::new(&self.display, glium::index::PrimitiveType::TrianglesList, &cube::INDICES).unwrap();

        let vb_wire = glium::VertexBuffer::new(&self.display, &wire_cube::VERTICES).unwrap();
        let ib_wire = glium::IndexBuffer::new(&self.display, glium::index::PrimitiveType::LinesList, &wire_cube::INDICES).unwrap();

        loop {
            let mut target = self.display.draw();
            target.clear_color_and_depth((0.0, 0.0, 1.0, 1.0), 1.0);

            let perspective: [[f32; 4]; 4] = self.get_perspective(&target).into();
            let view: [[f32; 4]; 4] = self.camera.view_matrix().into();
            {
                let params = self.get_params();

                let cubes: Vec<_> = self.game.stones.iter().map(|&(x, y, z)| Position { cube_pos: (x, y, z) }).collect();
                let cubes_buffer = glium::vertex::VertexBuffer::new(&self.display, &cubes).unwrap();

                let wires: Vec<Position> = self.game.stones.iter().min().map(|&(x, y, z)| Position { cube_pos: (x, y, z) }).into_iter().collect();
                let wires_buffer = glium::vertex::VertexBuffer::new(&self.display, &wires).unwrap();

                target.draw(
                    (&vb_cube, cubes_buffer.per_instance().unwrap()),
                    &ib_cube,
                    &self.cube_program,
                    &uniform! {
                        model: block::MODEL,
                        view: view,
                        perspective: perspective,
                        tex: texture_sampler,
                    },
                    &params
                ).unwrap();
                target.draw(
                    (&vb_wire, wires_buffer.per_instance().unwrap()),
                    &ib_wire,
                    &self.wire_program,
                    &uniform! { model: block::MODEL, view: view, perspective: perspective },
                    &params
                ).unwrap();

                if self.stats {
                    self.text.draw(&mut target, &format!("{}", self.camera), (1.0, 1.0, 0.0, 1.0));
                }
            }
            target.finish().unwrap();

            if !self.handle_events() {
                return;
            }
            self.camera.update();
        }
    }

    fn get_perspective<T: Surface>(&self, surface: &T) -> Matrix4<f32> {
        let (width, height) = surface.get_dimensions();
        let aspect_ratio = height as f32 / width as f32;

        let zfar = 1024.0;
        let znear = 0.1;

        let f = 1.0 / (self.fov / 2.0).tan();

        Matrix4::new(
            f * aspect_ratio, 0.0,              0.0              , 0.0,
                   0.0      ,  f ,              0.0              , 0.0,
                   0.0      , 0.0,      (zfar+znear)/(zfar-znear), 1.0,
                   0.0      , 0.0, -(2.0*zfar*znear)/(zfar-znear), 0.0,
        )
    }

    fn get_params(&self) -> glium::DrawParameters {
        use glium::draw_parameters::PolygonMode::{ Fill, Line };
        use glium::draw_parameters::DepthTest;
        glium::DrawParameters {
            depth: glium::Depth {
                test: DepthTest::IfLess,
                write: true,
                .. Default::default()
            },
            //backface_culling: glium::draw_parameters::BackfaceCullingMode::CullClockwise,
            polygon_mode: if self.fill { Fill } else { Line },
            .. Default::default()
        }
    }

    fn convert(ev: GlEvent) -> Option<Event> {
        use self::event::Event::*;
        use self::HDirection::*;
        use self::VDirection::*;
        use glium::glutin::Event as E;
        use glium::glutin::ElementState::Pressed;
        use glium::glutin::VirtualKeyCode as V;
        match ev {
            E::KeyboardInput(state, _, Some(key)) => {
                let t = state == Pressed;
                match (state, key) {
                    (Pressed, V::Numpad1)   => Some(ToogleBlock { block: (-1, 0,  1) }),
                    (Pressed, V::Numpad2)   => Some(ToogleBlock { block: ( 0, 0,  1) }),
                    (Pressed, V::Numpad3)   => Some(ToogleBlock { block: ( 1, 0,  1) }),
                    (Pressed, V::Numpad4)   => Some(ToogleBlock { block: (-1, 0,  0) }),
                    (Pressed, V::Numpad5)   => Some(ToogleBlock { block: ( 0, 0,  0) }),
                    (Pressed, V::Numpad6)   => Some(ToogleBlock { block: ( 1, 0,  0) }),
                    (Pressed, V::Numpad7)   => Some(ToogleBlock { block: (-1, 0, -1) }),
                    (Pressed, V::Numpad8)   => Some(ToogleBlock { block: ( 0, 0, -1) }),
                    (Pressed, V::Numpad9)   => Some(ToogleBlock { block: ( 1, 0, -1) }),
                    (_      , V::W)      => Some(Move { dir: Forth, toogle: t }),
                    (_      , V::A)      => Some(Move { dir: Left , toogle: t }),
                    (_      , V::S)      => Some(Move { dir: Back , toogle: t }),
                    (_      , V::D)      => Some(Move { dir: Right, toogle: t }),
                    (_      , V::Up)     => Some(Turn { dir: Forth, toogle: t }),
                    (_      , V::Left)   => Some(Turn { dir: Left , toogle: t }),
                    (_      , V::Down)   => Some(Turn { dir: Back , toogle: t }),
                    (_      , V::Right)  => Some(Turn { dir: Right, toogle: t }),
                    (_      , V::Space)  => Some(Fly  { dir: Up   , toogle: t }),
                    (_      , V::LShift) => Some(Fly  { dir: Down , toogle: t }),
                    _ => None,
                }

            },
            _ => None,
        }
    }

    fn handle_events(&mut self) -> bool {
        for ev in self.display.poll_events() {
            use glium::glutin::Event as E;
            use glium::glutin::ElementState::Pressed;
            use glium::glutin::VirtualKeyCode::*;
            match ev {
                E::Closed => return false,
                E::MouseMoved((mouse_x, mouse_y)) => {
                    let window = self.display.get_window().unwrap();
                    let (mid_x, mid_y) = Renderer::fix_mouse(window);
                    // screen coordinates increase to the right, just like phi
                    self.camera.add_phi((mouse_x - mid_x as i32) as f32 * MOUSE_SENSIVITY);
                    // screen coordinates decrease to the top, unlike theta
                    self.camera.add_theta((mid_y - mouse_y as i32) as f32 * MOUSE_SENSIVITY);
                },
                E::KeyboardInput(Pressed, _, Some(Escape)) => return false,
                _ => if let Some(ev) = Renderer::convert(ev) {
                    use self::event::Event::*;
                    match ev {
                        ToogleBlock { block: n }   => self.game.flip_stone(n),
                        Move { dir: d, toogle: t } => self.camera.mov (d, t),
                        Turn { dir: d, toogle: t } => self.camera.turn(d, t),
                        Fly  { dir: d, toogle: t } => self.camera.fly (d, t),
                        _ => {}
                    }
                },
            }
        }
        return true;
    }

    //returns mouse delta
    fn fix_mouse(window: WinRef) -> (i32, i32) {
        let (x, y) = window.get_inner_size_points().unwrap();
        let (mid_x, mid_y) = (x as i32 / 2, y as i32 / 2);
        window.set_cursor_position(mid_x, mid_y).unwrap();
        (mid_x, mid_y)
    }
}
<commit_msg>reenabled F1 and F3<commit_after>mod block;
mod camera;
mod cube;
mod error;
mod event;
mod shader;
mod text;
mod texture;
mod wire_cube;

use std::f32::consts::PI;

use image;
use cgmath::{ Point, Point3, Matrix4 };
use glium::{ self, glutin, DisplayBuild, Surface };
use glium::program::Program;
use glium::glutin::Event as GlEvent;
use glium::backend::glutin_backend::WinRef;

use self::camera::Camera;
use self::text::Text;
use self::error::RenderCreationError;
use self::event::Event;
use game::GameState;

const MOUSE_SENSIVITY: f32 = 0.1;

#[derive(Clone, Copy, Debug)]
pub struct Position {
    pub cube_pos: (i32, i32, i32),
}
implement_vertex!(Position, cube_pos);

#[derive(Clone, Copy, Debug)]
pub enum HDirection {
    Forth,
    Back,
    Left,
    Right,
}

#[derive(Clone, Copy, Debug)]
pub enum VDirection {
    Up,
    Down,
}

pub struct Renderer {
    display: glium::Display,
    cube_program: Program,
    wire_program: Program,
    camera: Camera,
    fov: f32, //in radians
    text: Text,
    stats: bool,
    fill: bool,
    game: GameState,
}

impl Renderer {
    pub fn new() -> Result<Renderer, RenderCreationError<glutin::CreationError>> {
        let display = try!(glutin::WindowBuilder::new()
            .with_depth_buffer(24)
            .build_glium());
        let cube_prog = try!(Program::from_source(
            &display,
            shader::CUBE_VERTEX,
            shader::CUBE_FRAGMENT,
            None,
        ));
        let wire_prog = try!(Program::from_source(
            &display,
            shader::WIRE_VERTEX,
            shader::WIRE_FRAGMENT,
            None,
        ));
        let text = try!(Text::new(&display, "/usr/share/fonts/TTF/NotoSans-Regular.ttf", 24));
        {
            let window = display.get_window().unwrap();
            window.set_cursor(glium::glutin::MouseCursor::Crosshair);
        }
        Ok(Renderer {
            display: display,
            cube_program: cube_prog,
            wire_program: wire_prog,
            camera: Camera::at(Point3::new(5.0, 5.0, 5.0), Point::origin()),
            fov: PI / 3.0,
            text: text,
            stats: false,
            fill: true,
            game: GameState::new(),
        })
    }

    pub fn game_loop(mut self) {

        let image = image::load(::std::io::Cursor::new(&include_bytes!(
            "../../assets/textures/dirt.png"
        )[..]),image::PNG).unwrap().to_rgba();
        let image_dimensions = image.dimensions();
        let image = glium::texture::RawImage2d::from_raw_rgba_reversed(image.into_raw(), image_dimensions);
        let texture = glium::texture::SrgbTexture2d::new(&self.display, image).unwrap();
        let texture_sampler = glium::uniforms::Sampler::new(&texture)
            .magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest)
            .minify_filter(glium::uniforms::MinifySamplerFilter::Nearest);

        let vb_cube = glium::VertexBuffer::new(&self.display, &cube::VERTICES).unwrap();
        let ib_cube = glium::IndexBuffer::new(&self.display, glium::index::PrimitiveType::TrianglesList, &cube::INDICES).unwrap();

        let vb_wire = glium::VertexBuffer::new(&self.display, &wire_cube::VERTICES).unwrap();
        let ib_wire = glium::IndexBuffer::new(&self.display, glium::index::PrimitiveType::LinesList, &wire_cube::INDICES).unwrap();

        loop {
            let mut target = self.display.draw();
            target.clear_color_and_depth((0.0, 0.0, 1.0, 1.0), 1.0);

            let perspective: [[f32; 4]; 4] = self.get_perspective(&target).into();
            let view: [[f32; 4]; 4] = self.camera.view_matrix().into();
            {
                let params = self.get_params();

                let cubes: Vec<_> = self.game.stones.iter().map(|&(x, y, z)| Position { cube_pos: (x, y, z) }).collect();
                let cubes_buffer = glium::vertex::VertexBuffer::new(&self.display, &cubes).unwrap();

                let wires: Vec<Position> = self.game.stones.iter().min().map(|&(x, y, z)| Position { cube_pos: (x, y, z) }).into_iter().collect();
                let wires_buffer = glium::vertex::VertexBuffer::new(&self.display, &wires).unwrap();

                target.draw(
                    (&vb_cube, cubes_buffer.per_instance().unwrap()),
                    &ib_cube,
                    &self.cube_program,
                    &uniform! {
                        model: block::MODEL,
                        view: view,
                        perspective: perspective,
                        tex: texture_sampler,
                    },
                    &params
                ).unwrap();
                target.draw(
                    (&vb_wire, wires_buffer.per_instance().unwrap()),
                    &ib_wire,
                    &self.wire_program,
                    &uniform! { model: block::MODEL, view: view, perspective: perspective },
                    &params
                ).unwrap();

                if self.stats {
                    self.text.draw(&mut target, &format!("{}", self.camera), (1.0, 1.0, 0.0, 1.0));
                }
            }
            target.finish().unwrap();

            if !self.handle_events() {
                return;
            }
            self.camera.update();
        }
    }

    fn get_perspective<T: Surface>(&self, surface: &T) -> Matrix4<f32> {
        let (width, height) = surface.get_dimensions();
        let aspect_ratio = height as f32 / width as f32;

        let zfar = 1024.0;
        let znear = 0.1;

        let f = 1.0 / (self.fov / 2.0).tan();

        Matrix4::new(
            f * aspect_ratio, 0.0,              0.0              , 0.0,
                   0.0      ,  f ,              0.0              , 0.0,
                   0.0      , 0.0,      (zfar+znear)/(zfar-znear), 1.0,
                   0.0      , 0.0, -(2.0*zfar*znear)/(zfar-znear), 0.0,
        )
    }

    fn get_params(&self) -> glium::DrawParameters {
        use glium::draw_parameters::PolygonMode::{ Fill, Line };
        use glium::draw_parameters::DepthTest;
        glium::DrawParameters {
            depth: glium::Depth {
                test: DepthTest::IfLess,
                write: true,
                .. Default::default()
            },
            //backface_culling: glium::draw_parameters::BackfaceCullingMode::CullClockwise,
            polygon_mode: if self.fill { Fill } else { Line },
            .. Default::default()
        }
    }

    fn convert(ev: GlEvent) -> Option<Event> {
        use self::event::Event::*;
        use self::HDirection::*;
        use self::VDirection::*;
        use glium::glutin::Event as E;
        use glium::glutin::ElementState::Pressed;
        use glium::glutin::VirtualKeyCode as V;
        match ev {
            E::KeyboardInput(state, _, Some(key)) => {
                let t = state == Pressed;
                match (state, key) {
                    (Pressed, V::Numpad1)   => Some(ToogleBlock { block: (-1, 0,  1) }),
                    (Pressed, V::Numpad2)   => Some(ToogleBlock { block: ( 0, 0,  1) }),
                    (Pressed, V::Numpad3)   => Some(ToogleBlock { block: ( 1, 0,  1) }),
                    (Pressed, V::Numpad4)   => Some(ToogleBlock { block: (-1, 0,  0) }),
                    (Pressed, V::Numpad5)   => Some(ToogleBlock { block: ( 0, 0,  0) }),
                    (Pressed, V::Numpad6)   => Some(ToogleBlock { block: ( 1, 0,  0) }),
                    (Pressed, V::Numpad7)   => Some(ToogleBlock { block: (-1, 0, -1) }),
                    (Pressed, V::Numpad8)   => Some(ToogleBlock { block: ( 0, 0, -1) }),
                    (Pressed, V::Numpad9)   => Some(ToogleBlock { block: ( 1, 0, -1) }),
                    (_      , V::W)      => Some(Move { dir: Forth, toogle: t }),
                    (_      , V::A)      => Some(Move { dir: Left , toogle: t }),
                    (_      , V::S)      => Some(Move { dir: Back , toogle: t }),
                    (_      , V::D)      => Some(Move { dir: Right, toogle: t }),
                    (_      , V::Up)     => Some(Turn { dir: Forth, toogle: t }),
                    (_      , V::Left)   => Some(Turn { dir: Left , toogle: t }),
                    (_      , V::Down)   => Some(Turn { dir: Back , toogle: t }),
                    (_      , V::Right)  => Some(Turn { dir: Right, toogle: t }),
                    (_      , V::Space)  => Some(Fly  { dir: Up   , toogle: t }),
                    (_      , V::LShift) => Some(Fly  { dir: Down , toogle: t }),
                    _ => None,
                }

            },
            _ => None,
        }
    }

    fn handle_events(&mut self) -> bool {
        for ev in self.display.poll_events() {
            use glium::glutin::Event as E;
            use glium::glutin::ElementState::Pressed;
            use glium::glutin::VirtualKeyCode::*;
            match ev {
                E::Closed => return false,
                E::MouseMoved((mouse_x, mouse_y)) => {
                    let window = self.display.get_window().unwrap();
                    let (mid_x, mid_y) = Renderer::fix_mouse(window);
                    // screen coordinates increase to the right, just like phi
                    self.camera.add_phi((mouse_x - mid_x as i32) as f32 * MOUSE_SENSIVITY);
                    // screen coordinates decrease to the top, unlike theta
                    self.camera.add_theta((mid_y - mouse_y as i32) as f32 * MOUSE_SENSIVITY);
                },
                E::KeyboardInput(Pressed, _, Some(F1)) => self.fill = !self.fill,
                E::KeyboardInput(Pressed, _, Some(F3)) => self.stats = ! self.stats,
                E::KeyboardInput(Pressed, _, Some(Escape)) => return false,
                _ => if let Some(ev) = Renderer::convert(ev) {
                    use self::event::Event::*;
                    match ev {
                        ToogleBlock { block: n }   => self.game.flip_stone(n),
                        Move { dir: d, toogle: t } => self.camera.mov (d, t),
                        Turn { dir: d, toogle: t } => self.camera.turn(d, t),
                        Fly  { dir: d, toogle: t } => self.camera.fly (d, t),
                        _ => {}
                    }
                },
            }
        }
        return true;
    }

    //returns mouse delta
    fn fix_mouse(window: WinRef) -> (i32, i32) {
        let (x, y) = window.get_inner_size_points().unwrap();
        let (mid_x, mid_y) = (x as i32 / 2, y as i32 / 2);
        window.set_cursor_position(mid_x, mid_y).unwrap();
        (mid_x, mid_y)
    }
}
<|endoftext|>


<commit_before>// Copyright Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use once_cell::sync::Lazy;
use std::time::Instant;
use tracing_subscriber::prelude::*;

pub static APPLICATION_START_TIME: Lazy<Instant> = Lazy::new(Instant::now);

#[cfg(feature = "console")]
pub fn setup_logging() {
    Lazy::force(&APPLICATION_START_TIME);
    let console_layer = console_subscriber::spawn();

    let filter_layer = tracing_subscriber::EnvFilter::try_from_default_env()
        .or_else(|_| tracing_subscriber::EnvFilter::try_new("info"))
        .unwrap();
    tracing_subscriber::registry()
        .with(console_layer)
        .with(filter_layer)
        .with(tracing_subscriber::fmt::layer())
        .init();
}

#[cfg(not(feature = "console"))]
pub fn setup_logging() {
    Lazy::force(&APPLICATION_START_TIME);
    let filter_layer = tracing_subscriber::EnvFilter::try_from_default_env()
        .or_else(|_| tracing_subscriber::EnvFilter::try_new("info"))
        .unwrap();
    tracing_subscriber::registry()
        .with(filter_layer)
        .with(tracing_subscriber::fmt::layer())
        .init();
}
<commit_msg>Fix integration with tokio-console. (#202)<commit_after>// Copyright Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use once_cell::sync::Lazy;
use std::time::Instant;
use tracing_subscriber::prelude::*;

pub static APPLICATION_START_TIME: Lazy<Instant> = Lazy::new(Instant::now);

#[cfg(feature = "console")]
pub fn setup_logging() {
    Lazy::force(&APPLICATION_START_TIME);
    let console_layer = console_subscriber::spawn();

    let filter_layer = tracing_subscriber::EnvFilter::try_from_default_env()
        .or_else(|_| tracing_subscriber::EnvFilter::try_new("info"))
        .unwrap();
    tracing_subscriber::registry()
        .with(console_layer)
        .with(tracing_subscriber::fmt::layer().with_filter(filter_layer))
        .init();
}

#[cfg(not(feature = "console"))]
pub fn setup_logging() {
    Lazy::force(&APPLICATION_START_TIME);
    let filter_layer = tracing_subscriber::EnvFilter::try_from_default_env()
        .or_else(|_| tracing_subscriber::EnvFilter::try_new("info"))
        .unwrap();
    tracing_subscriber::registry()
        .with(tracing_subscriber::fmt::layer().with_filter(filter_layer))
        .init();
}
<|endoftext|>


<commit_before>/* The Wizards' Wallet
 * Written in 2014 by
 *   Andrew Poelstra <apoelstra@wpsoftware.net>
 *
 * To the extent possible under law, the author(s) have dedicated all
 * copyright and related and neighboring rights to this software to
 * the public domain worldwide. This software is distributed without
 * any warranty.
 *
 * You should have received a copy of the CC0 Public Domain Dedication
 * along with this software.
 * If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
 */

//! # RPC Server
//!
//! Functions and data to handle RPC calls

use std::io::{IoError, MemReader};
use std::collections::TreeMap;
use std::time::Duration;
use serialize::Decodable;
use serialize::hex::FromHex;
use serialize::json;
use serialize::json::ToJson;

use bitcoin::network::serialize::{RawDecoder, deserialize};
use bitcoin::network::encodable::ConsensusDecodable;
use bitcoin::util::hash::Sha256dHash;
use bitcoin::blockdata::transaction::Transaction;
use jsonrpc;
use jsonrpc::error::{standard_error, Error, InvalidParams, MethodNotFound};
use phf::PhfOrderedMap;

use bitcoind::IdleState;
use coinjoin::server::{Server, Session, SessionId};

pub type JsonResult = jsonrpc::JsonResult<json::Json>;

/// A single RPC command
pub struct RpcCall {
  name: &'static str,
  desc: &'static str,
  usage: &'static str,
  coinjoin: bool,
  call: fn(&RpcCall, &mut IdleState, Vec<json::Json>) -> JsonResult
}

// Forget you saw this macro...just forget it.
macro_rules! rpc_calls(
  ( $( #[doc=$doc:tt]
       #[usage=$usage:tt]
       #[coinjoin=$coinjoin:tt]
       pub fn $name:ident($($param:tt: $paramty:ty),+) $code:expr),+ ) => (
    $(
      // `tt` token trees can only be passed to a macro. On the other hand,
      // there is no other type which will accept a doccomment as a token.
      // So we accept a tt and hand it to the macro_rules! macro ;)
      //
      // Notice that we are using the same name as the outer macro...this
      // means that the macro can only be called once, since we effectively
      // overwrite it here.
      macro_rules! rpc_calls( () => (
        // I don't really want these to be public, but they don't show up
        // in the output of `cargo doc` otherwise.
        #[doc=$doc]
        pub fn $name($($param: $paramty),+) -> JsonResult { $code }
      ))
      rpc_calls!()
    )+
    // Let's do it again!
    macro_rules! rpc_calls( () => (
      static RPC_CALLS: PhfOrderedMap<&'static str, RpcCall> = phf_ordered_map! {
        $(stringify!($name) => RpcCall {
            name: stringify!($name),
            desc: $doc,
            usage: $usage,
            coinjoin: $coinjoin,
            call: $name
          }
        ),+
      };
    ))
    rpc_calls!()
    // Erase the dummy macro, to avoid confusing errors in case somebody
    // tries to use it outside of this macro.
    macro_rules! rpc_calls(
      () => (Sorry, you can only call rpc_calls! once.)
    )
  )
)

// Main RPC call list
rpc_calls!{
  #[doc="Fetches a list of commands"]
  #[usage=""]
  #[coinjoin=false]
  pub fn help(_: &RpcCall, idle_state: &mut IdleState, _: Vec<json::Json>) {
    let mut ret = TreeMap::new();
    for call in RPC_CALLS.values() {
      if !call.coinjoin || idle_state.config.coinjoin_on {
        let mut obj = TreeMap::new();
        obj.insert("description".to_string(), json::String(call.desc.to_string()));
        obj.insert("usage".to_string(), json::String(call.usage.to_string()));
        ret.insert(call.name.to_string(), json::Object(obj));
      }
    }
    Ok(json::Object(ret))
  },

  #[doc="Gets a specific block from the blockchain"]
  #[usage="<hash>"]
  #[coinjoin=false]
  pub fn getblock(rpc: &RpcCall, idle_state: &mut IdleState, params: Vec<json::Json>) {
    match params.len() {
      1 => {
        let blockchain = idle_state.blockchain.read();
        let hash: Sha256dHash = try!(decode_param(params[0].clone()));

        match blockchain.get_block(hash) {
          Some(node) => {
            let mut ret = TreeMap::new();
            ret.insert("header".to_string(), node.block.header.to_json());
            ret.insert("has_txdata".to_string(), json::Boolean(node.has_txdata));
            if node.has_txdata {
              ret.insert("transactions".to_string(), node.block.txdata.to_json());
            }
            Ok(json::Object(ret))
          }
          None => Err(bitcoin_json_error(BlockNotFound, Some(hash.to_json()))),
        }
      }
      _ => Err(usage_error(rpc))
    }
  },

  #[doc="Gets the current number of unspent outputs on the blockchain."]
  #[usage=""]
  #[coinjoin=false]
  pub fn getutxocount(rpc: &RpcCall, idle_state: &mut IdleState, params: Vec<json::Json>) {
    match params.len() {
      0 => Ok(json::Number(idle_state.utxo_set.read().n_utxos() as f64)),
      _ => Err(usage_error(rpc))
    }
  },

  #[doc="Gets the length of the longest chain, starting from the given hash or genesis."]
  #[usage="[start hash]"]
  #[coinjoin=false]
  pub fn getblockcount(rpc: &RpcCall, idle_state: &mut IdleState, params: Vec<json::Json>) {
    match params.len() {
      0 => {
        let blockchain = idle_state.blockchain.read();
        // Subtract 1 from the hash since the genesis counts as block 0
        Ok(json::Number(blockchain.iter(blockchain.genesis_hash()).count() as f64 - 1.0))
      }
      1 => {
        let blockchain = idle_state.blockchain.read();
        let hash: Sha256dHash = try!(decode_param(params[0].clone()));

        // Subtract 1 from the hash since the genesis counts as block 0
        match blockchain.iter(hash).count() {
          0 => Err(bitcoin_json_error(BlockNotFound, Some(hash.to_json()))),
          n => Ok(json::Number(n as f64 - 1.0)),
        }
      }
      _ => Err(usage_error(rpc))
    }
  },

  #[doc="Decodes a raw transaction"]
  #[usage="<hex-encoded tx data>"]
  #[coinjoin=false]
  pub fn raw_decode(rpc: &RpcCall, _: &mut IdleState, params: Vec<json::Json>) {
    match params.len() {
      1 => {
        let tx: Transaction = try!(decode_hex_param(params[0].clone()));
        Ok(tx.to_json())
      }
      _ => Err(usage_error(rpc))
    }
  },

  #[doc="Validates a raw transaction"]
  #[usage="<hex-encoded tx data>"]
  #[coinjoin=false]
  pub fn raw_validate(rpc: &RpcCall, idle_state: &mut IdleState, params: Vec<json::Json>) {
    match params.len() {
      1 => {
        let tx: Transaction = try!(decode_hex_param(params[0].clone()));
        let utxo_set = idle_state.utxo_set.read();
        match tx.validate(&*utxo_set) {
          Ok(_) => Ok(json::Boolean(true)),
          Err(e) => Err(bitcoin_json_error(InvalidTx, Some(json::String(e.to_string()))))
        }
      }
      _ => Err(usage_error(rpc))
    }
  },

  #[doc="Traces execution of a raw transaction's scripts"]
  #[usage="<hex-encoded tx data>"]
  #[coinjoin=false]
  pub fn raw_trace(rpc: &RpcCall, idle_state: &mut IdleState, params: Vec<json::Json>) {
    match params.len() {
      1 => {
        let tx: Transaction = try!(decode_hex_param(params[0].clone()));
        let utxo_set = idle_state.utxo_set.read();
        Ok(tx.trace(&*utxo_set).to_json())
      }
      _ => Err(usage_error(rpc))
    }
  },

  #[doc="Starts a new coinjoin session"]
  #[usage="<target amount (satoshi)> <join duration (seconds)> <merge duration (seconds)>"]
  #[coinjoin=true]
  pub fn coinjoin_start(rpc: &RpcCall, idle_state: &mut IdleState, params: Vec<json::Json>) {
    match params.len() {
      3 => {
        let target: u64 = try!(decode_param(params[0].clone()));
        let join_duration = Duration::milliseconds(try!(decode_param(params[1].clone())));
        let expiry_duration = Duration::milliseconds(try!(decode_param(params[2].clone())));

        // Start session manager if we haven't
        if idle_state.coinjoin.is_none() {
          idle_state.coinjoin = Some(Server::new());
        }
        // Update the server state
        let server = idle_state.coinjoin.get_mut_ref();
        server.update_all();
        // Add the new sesion
        let session = try!(Session::new(target, join_duration, expiry_duration)
                             .map_err(|e| bitcoin_json_error(BadRng,
                                                             Some(json::String(e.to_string())))));
        let id = session.id();
        server.set_current_session(session);
        Ok(id.to_json())
      }
      _ => Err(usage_error(rpc))
    }
  },

  #[doc="Gets the status of the current coinjoin session"]
  #[usage="[session id]"]
  #[coinjoin=true]
  pub fn coinjoin_status(rpc: &RpcCall, idle_state: &mut IdleState, params: Vec<json::Json>) {
    if idle_state.coinjoin.is_none() {
      return Err(bitcoin_json_error(SessionNotFound, None));
    }
    // Update the server state
    let server = idle_state.coinjoin.get_mut_ref();
    server.update_all();

    match params.len() {
      0 => server.current_session().map_or(Err(bitcoin_json_error(SessionNotFound, None)), |s| Ok(s.to_json())),
      1 => {
        let id: SessionId = try!(decode_param(params[0].clone()));
        server.session(&id).map_or(Err(bitcoin_json_error(SessionNotFound, None)), |s| Ok(s.to_json()))
      }
      _ => Err(usage_error(rpc))
    }
  }
}

enum BitcoinJsonError {
  BadRng,
  BlockNotFound,
  InvalidTx,
  SessionNotFound
}

/// Decode a Json parameter
fn decode_param<T:Decodable<json::Decoder, json::DecoderError>>(param: json::Json) -> jsonrpc::JsonResult<T> {
  let mut decoder = json::Decoder::new(param);
  Decodable::decode(&mut decoder)
    .map_err(|e| standard_error(InvalidParams,
                                Some(json::String(e.to_string()))))
}

/// Decode a hex-encoded parameter
fn decode_hex_param<T:ConsensusDecodable<RawDecoder<MemReader>, IoError>>(param: json::Json)
                                                                          -> jsonrpc::JsonResult<T> {
  let hex: String = try!(decode_param(param));
  let raw = match hex.as_slice().from_hex() {
    Ok(raw) => raw,
    Err(e) => { return Err(standard_error(InvalidParams,
                                          Some(json::String(e.to_string())))); }
  };

  deserialize(raw)
    .map_err(|e| standard_error(InvalidParams,
                                Some(json::String(e.to_string()))))
}

/// Create a standard error responses
fn bitcoin_json_error(code: BitcoinJsonError, data: Option<json::Json>) -> Error {
  match code {
    BadRng => Error {
      code: -1,
      message: "Bad RNG".to_string(),
      data: data
    },
    BlockNotFound => Error {
      code: -2,
      message: "Block not found".to_string(),
      data: data
    },
    InvalidTx => Error {
      code: -3,
      message: "Transaction invalid".to_string(),
      data: data
    },
    SessionNotFound => Error {
      code: -4,
      message: "Coinjoin session not found".to_string(),
      data: data
    }
  }
}

/// Generates a `usage` error message
fn usage_error(rpc: &RpcCall) -> Error {
  standard_error(InvalidParams,
                 Some(json::String(format!("Usage: {} {}", rpc.name, rpc.usage))))
}

/// Handles a JSON-RPC request, returning a result to be given back to the peer
pub fn handle_rpc(request: jsonrpc::Request, idle_state: &mut IdleState) -> JsonResult {
  let method = request.method.as_slice();
  match RPC_CALLS.find_equiv(&method) {
    Some(rpc) if !rpc.coinjoin || idle_state.config.coinjoin_on =>
      (rpc.call)(rpc, idle_state, request.params),
    _ => Err(standard_error(MethodNotFound,
                            Some(json::String(request.method.clone()))))
  }
}

<commit_msg>Add script_trace RPC to execute standalone scripts<commit_after>/* The Wizards' Wallet
 * Written in 2014 by
 *   Andrew Poelstra <apoelstra@wpsoftware.net>
 *
 * To the extent possible under law, the author(s) have dedicated all
 * copyright and related and neighboring rights to this software to
 * the public domain worldwide. This software is distributed without
 * any warranty.
 *
 * You should have received a copy of the CC0 Public Domain Dedication
 * along with this software.
 * If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
 */

//! # RPC Server
//!
//! Functions and data to handle RPC calls

use std::io::{IoError, MemReader};
use std::collections::TreeMap;
use std::time::Duration;
use serialize::Decodable;
use serialize::hex::FromHex;
use serialize::json;
use serialize::json::ToJson;

use bitcoin::network::serialize::{RawDecoder, deserialize, serialize};
use bitcoin::network::encodable::{ConsensusDecodable, VarInt};
use bitcoin::util::hash::Sha256dHash;
use bitcoin::blockdata::script::Script;
use bitcoin::blockdata::transaction::Transaction;
use jsonrpc;
use jsonrpc::error::{standard_error, Error, InvalidParams, MethodNotFound};
use phf::PhfOrderedMap;

use bitcoind::IdleState;
use coinjoin::server::{Server, Session, SessionId};

pub type JsonResult = jsonrpc::JsonResult<json::Json>;

enum RawDecodeMode {
    DecodeAsIs,
    PrependLength
}

/// A single RPC command
pub struct RpcCall {
  name: &'static str,
  desc: &'static str,
  usage: &'static str,
  coinjoin: bool,
  call: fn(&RpcCall, &mut IdleState, Vec<json::Json>) -> JsonResult
}

// Forget you saw this macro...just forget it.
macro_rules! rpc_calls(
  ( $( #[doc=$doc:tt]
       #[usage=$usage:tt]
       #[coinjoin=$coinjoin:tt]
       pub fn $name:ident($($param:tt: $paramty:ty),+) $code:expr),+ ) => (
    $(
      // `tt` token trees can only be passed to a macro. On the other hand,
      // there is no other type which will accept a doccomment as a token.
      // So we accept a tt and hand it to the macro_rules! macro ;)
      //
      // Notice that we are using the same name as the outer macro...this
      // means that the macro can only be called once, since we effectively
      // overwrite it here.
      macro_rules! rpc_calls( () => (
        // I don't really want these to be public, but they don't show up
        // in the output of `cargo doc` otherwise.
        #[doc=$doc]
        pub fn $name($($param: $paramty),+) -> JsonResult { $code }
      ))
      rpc_calls!()
    )+
    // Let's do it again!
    macro_rules! rpc_calls( () => (
      static RPC_CALLS: PhfOrderedMap<&'static str, RpcCall> = phf_ordered_map! {
        $(stringify!($name) => RpcCall {
            name: stringify!($name),
            desc: $doc,
            usage: $usage,
            coinjoin: $coinjoin,
            call: $name
          }
        ),+
      };
    ))
    rpc_calls!()
    // Erase the dummy macro, to avoid confusing errors in case somebody
    // tries to use it outside of this macro.
    macro_rules! rpc_calls(
      () => (Sorry, you can only call rpc_calls! once.)
    )
  )
)

// Main RPC call list
rpc_calls!{
  #[doc="Fetches a list of commands"]
  #[usage=""]
  #[coinjoin=false]
  pub fn help(_: &RpcCall, idle_state: &mut IdleState, _: Vec<json::Json>) {
    let mut ret = TreeMap::new();
    for call in RPC_CALLS.values() {
      if !call.coinjoin || idle_state.config.coinjoin_on {
        let mut obj = TreeMap::new();
        obj.insert("description".to_string(), json::String(call.desc.to_string()));
        obj.insert("usage".to_string(), json::String(call.usage.to_string()));
        ret.insert(call.name.to_string(), json::Object(obj));
      }
    }
    Ok(json::Object(ret))
  },

  #[doc="Gets a specific block from the blockchain"]
  #[usage="<hash>"]
  #[coinjoin=false]
  pub fn getblock(rpc: &RpcCall, idle_state: &mut IdleState, params: Vec<json::Json>) {
    match params.len() {
      1 => {
        let blockchain = idle_state.blockchain.read();
        let hash: Sha256dHash = try!(decode_param(params[0].clone()));

        match blockchain.get_block(hash) {
          Some(node) => {
            let mut ret = TreeMap::new();
            ret.insert("header".to_string(), node.block.header.to_json());
            ret.insert("has_txdata".to_string(), json::Boolean(node.has_txdata));
            if node.has_txdata {
              ret.insert("transactions".to_string(), node.block.txdata.to_json());
            }
            Ok(json::Object(ret))
          }
          None => Err(bitcoin_json_error(BlockNotFound, Some(hash.to_json()))),
        }
      }
      _ => Err(usage_error(rpc))
    }
  },

  #[doc="Gets the current number of unspent outputs on the blockchain."]
  #[usage=""]
  #[coinjoin=false]
  pub fn getutxocount(rpc: &RpcCall, idle_state: &mut IdleState, params: Vec<json::Json>) {
    match params.len() {
      0 => Ok(json::U64(idle_state.utxo_set.read().n_utxos() as u64)),
      _ => Err(usage_error(rpc))
    }
  },

  #[doc="Gets the length of the longest chain, starting from the given hash or genesis."]
  #[usage="[start hash]"]
  #[coinjoin=false]
  pub fn getblockcount(rpc: &RpcCall, idle_state: &mut IdleState, params: Vec<json::Json>) {
    match params.len() {
      0 => {
        let blockchain = idle_state.blockchain.read();
        // Subtract 1 from the hash since the genesis counts as block 0
        Ok(json::U64(blockchain.iter(blockchain.genesis_hash()).count() as u64 - 1))
      }
      1 => {
        let blockchain = idle_state.blockchain.read();
        let hash: Sha256dHash = try!(decode_param(params[0].clone()));

        // Subtract 1 from the hash since the genesis counts as block 0
        match blockchain.iter(hash).count() {
          0 => Err(bitcoin_json_error(BlockNotFound, Some(hash.to_json()))),
          n => Ok(json::U64(n as u64 - 1)),
        }
      }
      _ => Err(usage_error(rpc))
    }
  },

  #[doc="Decodes a raw transaction"]
  #[usage="<hex-encoded tx data>"]
  #[coinjoin=false]
  pub fn raw_decode(rpc: &RpcCall, _: &mut IdleState, params: Vec<json::Json>) {
    match params.len() {
      1 => {
        let tx: Transaction = try!(decode_hex_param(params[0].clone(), DecodeAsIs));
        Ok(tx.to_json())
      }
      _ => Err(usage_error(rpc))
    }
  },

  #[doc="Validates a raw transaction"]
  #[usage="<hex-encoded tx data>"]
  #[coinjoin=false]
  pub fn raw_validate(rpc: &RpcCall, idle_state: &mut IdleState, params: Vec<json::Json>) {
    match params.len() {
      1 => {
        let tx: Transaction = try!(decode_hex_param(params[0].clone(), DecodeAsIs));
        let utxo_set = idle_state.utxo_set.read();
        match tx.validate(&*utxo_set) {
          Ok(_) => Ok(json::Boolean(true)),
          Err(e) => Err(bitcoin_json_error(InvalidTx, Some(json::String(e.to_string()))))
        }
      }
      _ => Err(usage_error(rpc))
    }
  },

  #[doc="Traces execution of a raw transaction's scripts"]
  #[usage="<hex-encoded tx data>"]
  #[coinjoin=false]
  pub fn raw_trace(rpc: &RpcCall, idle_state: &mut IdleState, params: Vec<json::Json>) {
    match params.len() {
      1 => {
        let tx: Transaction = try!(decode_hex_param(params[0].clone(), DecodeAsIs));
        let utxo_set = idle_state.utxo_set.read();
        Ok(tx.trace(&*utxo_set).to_json())
      }
      _ => Err(usage_error(rpc))
    }
  },

  #[doc="Traces execution of an individual script"]
  #[usage="<hex-encoded script>"]
  #[coinjoin=false]
  pub fn script_trace(rpc: &RpcCall, _: &mut IdleState, params: Vec<json::Json>) {
    match params.len() {
      1 => {
        let script: Script = try!(decode_hex_param(params[0].clone(), PrependLength));
        Ok(script.trace(&mut vec![], None).to_json())
      }
      _ => Err(usage_error(rpc))
    }
  },

  #[doc="Starts a new coinjoin session"]
  #[usage="<target amount (satoshi)> <join duration (seconds)> <merge duration (seconds)>"]
  #[coinjoin=true]
  pub fn coinjoin_start(rpc: &RpcCall, idle_state: &mut IdleState, params: Vec<json::Json>) {
    match params.len() {
      3 => {
        let target: u64 = try!(decode_param(params[0].clone()));
        let join_duration = Duration::milliseconds(try!(decode_param(params[1].clone())));
        let expiry_duration = Duration::milliseconds(try!(decode_param(params[2].clone())));

        // Start session manager if we haven't
        if idle_state.coinjoin.is_none() {
          idle_state.coinjoin = Some(Server::new());
        }
        // Update the server state
        let server = idle_state.coinjoin.get_mut_ref();
        server.update_all();
        // Add the new sesion
        let session = try!(Session::new(target, join_duration, expiry_duration)
                             .map_err(|e| bitcoin_json_error(BadRng,
                                                             Some(json::String(e.to_string())))));
        let id = session.id();
        server.set_current_session(session);
        Ok(id.to_json())
      }
      _ => Err(usage_error(rpc))
    }
  },

  #[doc="Gets the status of the current coinjoin session"]
  #[usage="[session id]"]
  #[coinjoin=true]
  pub fn coinjoin_status(rpc: &RpcCall, idle_state: &mut IdleState, params: Vec<json::Json>) {
    if idle_state.coinjoin.is_none() {
      return Err(bitcoin_json_error(SessionNotFound, None));
    }
    // Update the server state
    let server = idle_state.coinjoin.get_mut_ref();
    server.update_all();

    match params.len() {
      0 => server.current_session().map_or(Err(bitcoin_json_error(SessionNotFound, None)), |s| Ok(s.to_json())),
      1 => {
        let id: SessionId = try!(decode_param(params[0].clone()));
        server.session(&id).map_or(Err(bitcoin_json_error(SessionNotFound, None)), |s| Ok(s.to_json()))
      }
      _ => Err(usage_error(rpc))
    }
  }
}

enum BitcoinJsonError {
  BadRng,
  BlockNotFound,
  InvalidTx,
  SessionNotFound
}

/// Decode a Json parameter
fn decode_param<T:Decodable<json::Decoder, json::DecoderError>>(param: json::Json) -> jsonrpc::JsonResult<T> {
  let mut decoder = json::Decoder::new(param);
  Decodable::decode(&mut decoder)
    .map_err(|e| standard_error(InvalidParams,
                                Some(json::String(e.to_string()))))
}

/// Decode a hex-encoded parameter
fn decode_hex_param<T:ConsensusDecodable<RawDecoder<MemReader>, IoError>>(param: json::Json, mode: RawDecodeMode)
                                                                          -> jsonrpc::JsonResult<T> {
  let hex: String = try!(decode_param(param));
  let mut raw = match hex.as_slice().from_hex() {
    Ok(raw) => raw,
    Err(e) => { return Err(standard_error(InvalidParams,
                                          Some(json::String(e.to_string())))); }
  };

  match mode {
    DecodeAsIs => {},
    PrependLength => {
      let len = serialize(&VarInt(raw.len() as u64)).unwrap();
      raw = len.append(raw.as_slice());
    }
  }

  deserialize(raw)
    .map_err(|e| standard_error(InvalidParams,
                                Some(json::String(e.to_string()))))
}

/// Create a standard error responses
fn bitcoin_json_error(code: BitcoinJsonError, data: Option<json::Json>) -> Error {
  match code {
    BadRng => Error {
      code: -1,
      message: "Bad RNG".to_string(),
      data: data
    },
    BlockNotFound => Error {
      code: -2,
      message: "Block not found".to_string(),
      data: data
    },
    InvalidTx => Error {
      code: -3,
      message: "Transaction invalid".to_string(),
      data: data
    },
    SessionNotFound => Error {
      code: -4,
      message: "Coinjoin session not found".to_string(),
      data: data
    }
  }
}

/// Generates a `usage` error message
fn usage_error(rpc: &RpcCall) -> Error {
  standard_error(InvalidParams,
                 Some(json::String(format!("Usage: {} {}", rpc.name, rpc.usage))))
}

/// Handles a JSON-RPC request, returning a result to be given back to the peer
pub fn handle_rpc(request: jsonrpc::Request, idle_state: &mut IdleState) -> JsonResult {
  let method = request.method.as_slice();
  match RPC_CALLS.find_equiv(&method) {
    Some(rpc) if !rpc.coinjoin || idle_state.config.coinjoin_on =>
      (rpc.call)(rpc, idle_state, request.params),
    _ => Err(standard_error(MethodNotFound,
                            Some(json::String(request.method.clone()))))
  }
}

<|endoftext|>


<commit_before>use Request;

use std::io::Read;
use std::error::Error;

/// Request and response transport abstraction.
///
/// The `Transport` trait provides a way to send a `Request` to a server and to receive the
/// corresponding response. A `Transport` implementor is passed to `Request::call` in order to use
/// it to perform that request.
///
/// The most commonly used transport is simple HTTP: If the `reqwest` feature is enabled (it is by
/// default), the reqwest `RequestBuilder` will implement this trait and send the XML-RPC `Request`
/// via HTTP.
///
/// You can implement this trait for your own types if you want to customize how requests are sent.
/// You can modify HTTP headers or wrap requests in a completely different protocol.
pub trait Transport {
    // FIXME replace with `impl Trait` when stable
    /// The response stream returned by `transmit`.
    type Stream: Read;

    /// Transmits an XML-RPC request and returns the server's response.
    ///
    /// The response is returned as a `Self::Stream` - some type implementing the `Read` trait. The
    /// library will read all of the data and parse it as a response. It must be UTF-8 encoded XML,
    /// otherwise the call will fail.
    ///
    /// If a transport error occurs, this should return it as a boxed error - the library will
    /// interpret it as a transport error and return an appropriate `RequestError`.
    fn transmit(self, request: &Request) -> Result<Self::Stream, Box<Error>>;
}

// FIXME: Link to `Transport` and `RequestBuilder` using intra-rustdoc links. Relative links break
// everything and abs. links don't work locally.
/// Provides helpers for implementing custom `Transport`s using reqwest.
///
/// This module will be disabled if the `reqwest` feature is not enabled.
///
/// The default [`Transport`][transport] implementation for `RequestBuilder` looks roughly like
/// this:
///
/// ```notrust
/// // serialize request into `body` (a `Vec<u8>`)
///
/// build_headers(builder, body.len());
///
/// // send `body` using `builder` and get response
///
/// check_response(&response)?;
/// ```
///
/// From this, you can build your own custom transports.
///
/// [transport]: trait.Transport.html
#[cfg(feature = "reqwest")]
pub mod http {
    extern crate reqwest;

    use {Request, Transport};
    use self::reqwest::{RequestBuilder, mime};
    use self::reqwest::header::{ContentType, ContentLength, UserAgent};

    use std::error::Error;

    /// Appends all HTTP headers required by the XML-RPC specification to the `RequestBuilder`.
    ///
    /// More specifically, the following headers are set:
    ///
    /// ```notrust
    /// User-Agent: Rust xmlrpc
    /// Content-Type: text/xml; charset=utf-8
    /// Content-Length: $body_len
    /// ```
    pub fn build_headers(builder: &mut RequestBuilder, body_len: u64) {
        // Set all required request headers
        // NB: The `Host` header is also required, but reqwest adds it automatically, since
        // HTTP/1.1 requires it.
        builder
            .header(UserAgent::new("Rust xmlrpc"))
            .header(ContentType("text/xml; charset=utf-8".parse().unwrap()))
            .header(ContentLength(body_len));
    }

    /// Checks that a reqwest `Response` has a status code indicating success and contains all
    /// headers mandated by the spec.
    ///
    /// This is done by default to ensure compliance.
    pub fn check_response(response: &reqwest::Response) -> Result<(), Box<Error>> {
        // This is essentially an open-coded version of `Response::error_for_status` that does not
        // consume the response.
        if response.status().is_client_error() || response.status().is_server_error() {
            return Err(format!("server response indicates error: {}", response.status()).into());
        }

        // Check response headers
        // "The Content-Type is text/xml. Content-Length must be present and correct."
        if let Some(content) = response.headers().get::<ContentType>() {
            // (we ignore this if the header is missing completely)
            match (content.type_(), content.subtype()) {
                (mime::TEXT, mime::XML) => {},
                (ty, sub) => return Err(
                    format!("expected Content-Type 'text/xml', got '{}/{}'", ty, sub).into()
                ),
            }
        }

        response.headers().get::<ContentLength>()
            .ok_or_else(|| format!("expected Content-Length header, but none was found"))?;

        Ok(())
    }

    /// Use a `RequestBuilder` as the transport.
    ///
    /// The request will be sent as specified in the XML-RPC specification: A default `User-Agent`
    /// will be set, along with the correct `Content-Type` and `Content-Length`.
    impl Transport for RequestBuilder {
        type Stream = reqwest::Response;

        fn transmit(mut self, request: &Request) -> Result<Self::Stream, Box<Error>> {
            // First, build the body XML
            let mut body = Vec::new();
            // This unwrap never panics as we are using `Vec<u8>` as a `Write` implementor,
            // and not doing anything else that could return an `Err` in `write_as_xml()`.
            request.write_as_xml(&mut body).unwrap();

            build_headers(&mut self, body.len() as u64);

            let response = self
                .body(body)
                .send()?;

            check_response(&response)?;

            Ok(response)
        }
    }
}
<commit_msg>Fix link<commit_after>use Request;

use std::io::Read;
use std::error::Error;

/// Request and response transport abstraction.
///
/// The `Transport` trait provides a way to send a `Request` to a server and to receive the
/// corresponding response. A `Transport` implementor is passed to `Request::call` in order to use
/// it to perform that request.
///
/// The most commonly used transport is simple HTTP: If the `reqwest` feature is enabled (it is by
/// default), the reqwest `RequestBuilder` will implement this trait and send the XML-RPC `Request`
/// via HTTP.
///
/// You can implement this trait for your own types if you want to customize how requests are sent.
/// You can modify HTTP headers or wrap requests in a completely different protocol.
pub trait Transport {
    // FIXME replace with `impl Trait` when stable
    /// The response stream returned by `transmit`.
    type Stream: Read;

    /// Transmits an XML-RPC request and returns the server's response.
    ///
    /// The response is returned as a `Self::Stream` - some type implementing the `Read` trait. The
    /// library will read all of the data and parse it as a response. It must be UTF-8 encoded XML,
    /// otherwise the call will fail.
    ///
    /// If a transport error occurs, this should return it as a boxed error - the library will
    /// interpret it as a transport error and return an appropriate `RequestError`.
    fn transmit(self, request: &Request) -> Result<Self::Stream, Box<Error>>;
}

// FIXME: Link to `Transport` and `RequestBuilder` using intra-rustdoc links. Relative links break
// everything and abs. links don't work locally.
/// Provides helpers for implementing custom `Transport`s using reqwest.
///
/// This module will be disabled if the `reqwest` feature is not enabled.
///
/// The default [`Transport`][transport] implementation for `RequestBuilder` looks roughly like
/// this:
///
/// ```notrust
/// // serialize request into `body` (a `Vec<u8>`)
///
/// build_headers(builder, body.len());
///
/// // send `body` using `builder` and get response
///
/// check_response(&response)?;
/// ```
///
/// From this, you can build your own custom transports.
///
/// [transport]: ../trait.Transport.html
#[cfg(feature = "reqwest")]
pub mod http {
    extern crate reqwest;

    use {Request, Transport};
    use self::reqwest::{RequestBuilder, mime};
    use self::reqwest::header::{ContentType, ContentLength, UserAgent};

    use std::error::Error;

    /// Appends all HTTP headers required by the XML-RPC specification to the `RequestBuilder`.
    ///
    /// More specifically, the following headers are set:
    ///
    /// ```notrust
    /// User-Agent: Rust xmlrpc
    /// Content-Type: text/xml; charset=utf-8
    /// Content-Length: $body_len
    /// ```
    pub fn build_headers(builder: &mut RequestBuilder, body_len: u64) {
        // Set all required request headers
        // NB: The `Host` header is also required, but reqwest adds it automatically, since
        // HTTP/1.1 requires it.
        builder
            .header(UserAgent::new("Rust xmlrpc"))
            .header(ContentType("text/xml; charset=utf-8".parse().unwrap()))
            .header(ContentLength(body_len));
    }

    /// Checks that a reqwest `Response` has a status code indicating success and contains all
    /// headers mandated by the spec.
    ///
    /// This is done by default to ensure compliance.
    pub fn check_response(response: &reqwest::Response) -> Result<(), Box<Error>> {
        // This is essentially an open-coded version of `Response::error_for_status` that does not
        // consume the response.
        if response.status().is_client_error() || response.status().is_server_error() {
            return Err(format!("server response indicates error: {}", response.status()).into());
        }

        // Check response headers
        // "The Content-Type is text/xml. Content-Length must be present and correct."
        if let Some(content) = response.headers().get::<ContentType>() {
            // (we ignore this if the header is missing completely)
            match (content.type_(), content.subtype()) {
                (mime::TEXT, mime::XML) => {},
                (ty, sub) => return Err(
                    format!("expected Content-Type 'text/xml', got '{}/{}'", ty, sub).into()
                ),
            }
        }

        response.headers().get::<ContentLength>()
            .ok_or_else(|| format!("expected Content-Length header, but none was found"))?;

        Ok(())
    }

    /// Use a `RequestBuilder` as the transport.
    ///
    /// The request will be sent as specified in the XML-RPC specification: A default `User-Agent`
    /// will be set, along with the correct `Content-Type` and `Content-Length`.
    impl Transport for RequestBuilder {
        type Stream = reqwest::Response;

        fn transmit(mut self, request: &Request) -> Result<Self::Stream, Box<Error>> {
            // First, build the body XML
            let mut body = Vec::new();
            // This unwrap never panics as we are using `Vec<u8>` as a `Write` implementor,
            // and not doing anything else that could return an `Err` in `write_as_xml()`.
            request.write_as_xml(&mut body).unwrap();

            build_headers(&mut self, body.len() as u64);

            let response = self
                .body(body)
                .send()?;

            check_response(&response)?;

            Ok(response)
        }
    }
}
<|endoftext|>