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

use alloc::boxed::FnBox;
use cmp;
use ffi::CStr;
use io;
use libc;
use mem;
use ptr;
use sys::os;
use time::Duration;

use sys_common::thread::*;

pub struct Thread {
    id: libc::pthread_t,
}

// Some platforms may have pthread_t as a pointer in which case we still want
// a thread to be Send/Sync
unsafe impl Send for Thread {}
unsafe impl Sync for Thread {}

impl Thread {
    pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>)
                          -> io::Result<Thread> {
        let p = box p;
        let mut native: libc::pthread_t = mem::zeroed();
        let mut attr: libc::pthread_attr_t = mem::zeroed();
        assert_eq!(libc::pthread_attr_init(&mut attr), 0);

        let stack_size = cmp::max(stack, min_stack_size(&attr));
        match libc::pthread_attr_setstacksize(&mut attr,
                                              stack_size as libc::size_t) {
            0 => {}
            n => {
                assert_eq!(n, libc::EINVAL);
                // EINVAL means |stack_size| is either too small or not a
                // multiple of the system page size.  Because it's definitely
                // >= PTHREAD_STACK_MIN, it must be an alignment issue.
                // Round up to the nearest page and try again.
                let page_size = os::page_size();
                let stack_size = (stack_size + page_size - 1) &
                                 (-(page_size as isize - 1) as usize - 1);
                let stack_size = stack_size as libc::size_t;
                assert_eq!(libc::pthread_attr_setstacksize(&mut attr,
                                                           stack_size), 0);
            }
        };

        let ret = libc::pthread_create(&mut native, &attr, thread_start,
                                       &*p as *const _ as *mut _);
        assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);

        return if ret != 0 {
            Err(io::Error::from_raw_os_error(ret))
        } else {
            mem::forget(p); // ownership passed to pthread_create
            Ok(Thread { id: native })
        };

        extern fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
            unsafe { start_thread(main); }
            ptr::null_mut()
        }
    }

    pub fn yield_now() {
        let ret = unsafe { libc::sched_yield() };
        debug_assert_eq!(ret, 0);
    }

    #[cfg(any(target_os = "linux",
              target_os = "android"))]
    pub fn set_name(name: &CStr) {
        const PR_SET_NAME: libc::c_int = 15;
        // pthread wrapper only appeared in glibc 2.12, so we use syscall
        // directly.
        unsafe {
            libc::prctl(PR_SET_NAME, name.as_ptr() as libc::c_ulong, 0, 0, 0);
        }
    }

    #[cfg(any(target_os = "freebsd",
              target_os = "dragonfly",
              target_os = "bitrig",
              target_os = "openbsd"))]
    pub fn set_name(name: &CStr) {
        unsafe {
            libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr());
        }
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    pub fn set_name(name: &CStr) {
        unsafe {
            libc::pthread_setname_np(name.as_ptr());
        }
    }

    #[cfg(target_os = "netbsd")]
    pub fn set_name(name: &CStr) {
        use ffi::CString;
        let cname = CString::new(&b"%s"[..]).unwrap();
        unsafe {
            libc::pthread_setname_np(libc::pthread_self(), cname.as_ptr(),
                                     name.as_ptr() as *mut libc::c_void);
        }
    }
    #[cfg(any(target_env = "newlib", target_os = "solaris", target_os = "emscripten"))]
    pub fn set_name(_name: &CStr) {
        // Newlib, Illumos and Emscripten have no way to set a thread name.
    }

    #[cfg(target_os = "haiku")]
    pub fn set_name(_name: &CStr) {
        // Haiku has no way to set a thread name.
    }

    pub fn sleep(dur: Duration) {
        let mut secs = dur.as_secs();
        let mut nsecs = dur.subsec_nanos() as libc::c_long;

        // If we're awoken with a signal then the return value will be -1 and
        // nanosleep will fill in `ts` with the remaining time.
        unsafe {
            while secs > 0 || nsecs > 0 {
                let mut ts = libc::timespec {
                    tv_sec: cmp::min(libc::time_t::max_value() as u64, secs) as libc::time_t,
                    tv_nsec: nsecs,
                };
                secs -= ts.tv_sec as u64;
                if libc::nanosleep(&ts, &mut ts) == -1 {
                    assert_eq!(os::errno(), libc::EINTR);
                    secs += ts.tv_sec as u64;
                    nsecs = ts.tv_nsec;
                } else {
                    nsecs = 0;
                }
            }
        }
    }

    pub fn join(self) {
        unsafe {
            let ret = libc::pthread_join(self.id, ptr::null_mut());
            mem::forget(self);
            debug_assert_eq!(ret, 0);
        }
    }

    pub fn id(&self) -> libc::pthread_t { self.id }

    pub fn into_id(self) -> libc::pthread_t {
        let id = self.id;
        mem::forget(self);
        id
    }
}

impl Drop for Thread {
    fn drop(&mut self) {
        let ret = unsafe { libc::pthread_detach(self.id) };
        debug_assert_eq!(ret, 0);
    }
}

#[cfg(all(not(all(target_os = "linux", not(target_env = "musl"))),
          not(target_os = "freebsd"),
          not(target_os = "macos"),
          not(target_os = "bitrig"),
          not(all(target_os = "netbsd", not(target_vendor = "rumprun"))),
          not(target_os = "openbsd"),
          not(target_os = "solaris")))]
#[cfg_attr(test, allow(dead_code))]
pub mod guard {
    pub unsafe fn current() -> Option<usize> { None }
    pub unsafe fn init() -> Option<usize> { None }
}

#[cfg(any(all(target_os = "linux", not(target_env = "musl")),
          target_os = "freebsd",
          target_os = "macos",
          target_os = "bitrig",
          all(target_os = "netbsd", not(target_vendor = "rumprun")),
          target_os = "openbsd",
          target_os = "solaris"))]
#[cfg_attr(test, allow(dead_code))]
pub mod guard {
    use libc;
    use libc::mmap;
    use libc::{PROT_NONE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED};
    use sys::os;

    #[cfg(any(target_os = "macos",
              target_os = "bitrig",
              target_os = "openbsd",
              target_os = "solaris"))]
    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
        current().map(|s| s as *mut libc::c_void)
    }

    #[cfg(any(target_os = "android", target_os = "freebsd",
              target_os = "linux", target_os = "netbsd"))]
    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
        let mut ret = None;
        let mut attr: libc::pthread_attr_t = ::mem::zeroed();
        assert_eq!(libc::pthread_attr_init(&mut attr), 0);
        #[cfg(target_os = "freebsd")]
            let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr);
        #[cfg(not(target_os = "freebsd"))]
            let e = libc::pthread_getattr_np(libc::pthread_self(), &mut attr);
        if e == 0 {
            let mut stackaddr = ::ptr::null_mut();
            let mut stacksize = 0;
            assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr,
                                                   &mut stacksize), 0);
            ret = Some(stackaddr);
        }
        assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
        ret
    }

    pub unsafe fn init() -> Option<usize> {
        let psize = os::page_size();
        let mut stackaddr = match get_stack_start() {
            Some(addr) => addr,
            None => return None,
        };

        // Ensure stackaddr is page aligned! A parent process might
        // have reset RLIMIT_STACK to be non-page aligned. The
        // pthread_attr_getstack() reports the usable stack area
        // stackaddr < stackaddr + stacksize, so if stackaddr is not
        // page-aligned, calculate the fix such that stackaddr <
        // new_page_aligned_stackaddr < stackaddr + stacksize
        let remainder = (stackaddr as usize) % psize;
        if remainder != 0 {
            stackaddr = ((stackaddr as usize) + psize - remainder)
                as *mut libc::c_void;
        }

        // Rellocate the last page of the stack.
        // This ensures SIGBUS will be raised on
        // stack overflow.
        let result = mmap(stackaddr,
                          psize as libc::size_t,
                          PROT_NONE,
                          MAP_PRIVATE | MAP_ANON | MAP_FIXED,
                          -1,
                          0);

        if result != stackaddr || result == MAP_FAILED {
            panic!("failed to allocate a guard page");
        }

        let offset = if cfg!(any(target_os = "linux", target_os = "freebsd")) {
            2
        } else {
            1
        };

        Some(stackaddr as usize + offset * psize)
    }

    #[cfg(target_os = "solaris")]
    pub unsafe fn current() -> Option<usize> {
        let mut current_stack: libc::stack_t = ::mem::zeroed();
        assert_eq!(libc::stack_getbounds(&mut current_stack), 0);
        Some(current_stack.ss_sp as usize)
    }

    #[cfg(target_os = "macos")]
    pub unsafe fn current() -> Option<usize> {
        Some((libc::pthread_get_stackaddr_np(libc::pthread_self()) as libc::size_t -
              libc::pthread_get_stacksize_np(libc::pthread_self())) as usize)
    }

    #[cfg(any(target_os = "openbsd", target_os = "bitrig"))]
    pub unsafe fn current() -> Option<usize> {
        let mut current_stack: libc::stack_t = ::mem::zeroed();
        assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(),
                                             &mut current_stack), 0);

        let extra = if cfg!(target_os = "bitrig") {3} else {1} * os::page_size();
        Some(if libc::pthread_main_np() == 1 {
            // main thread
            current_stack.ss_sp as usize - current_stack.ss_size as usize + extra
        } else {
            // new thread
            current_stack.ss_sp as usize - current_stack.ss_size as usize
        })
    }

    #[cfg(any(target_os = "android", target_os = "freebsd",
              target_os = "linux", target_os = "netbsd"))]
    pub unsafe fn current() -> Option<usize> {
        let mut ret = None;
        let mut attr: libc::pthread_attr_t = ::mem::zeroed();
        assert_eq!(libc::pthread_attr_init(&mut attr), 0);
        #[cfg(target_os = "freebsd")]
            let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr);
        #[cfg(not(target_os = "freebsd"))]
            let e = libc::pthread_getattr_np(libc::pthread_self(), &mut attr);
        if e == 0 {
            let mut guardsize = 0;
            assert_eq!(libc::pthread_attr_getguardsize(&attr, &mut guardsize), 0);
            if guardsize == 0 {
                panic!("there is no guard page");
            }
            let mut stackaddr = ::ptr::null_mut();
            let mut size = 0;
            assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr,
                                                   &mut size), 0);

            ret = if cfg!(target_os = "freebsd") {
                Some(stackaddr as usize - guardsize as usize)
            } else if cfg!(target_os = "netbsd") {
                Some(stackaddr as usize)
            } else {
                Some(stackaddr as usize + guardsize as usize)
            };
        }
        assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
        ret
    }
}

// glibc >= 2.15 has a __pthread_get_minstack() function that returns
// PTHREAD_STACK_MIN plus however many bytes are needed for thread-local
// storage.  We need that information to avoid blowing up when a small stack
// is created in an application with big thread-local storage requirements.
// See #6233 for rationale and details.
#[cfg(target_os = "linux")]
#[allow(deprecated)]
fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize {
    weak!(fn __pthread_get_minstack(*const libc::pthread_attr_t) -> libc::size_t);

    match __pthread_get_minstack.get() {
        None => libc::PTHREAD_STACK_MIN as usize,
        Some(f) => unsafe { f(attr) as usize },
    }
}

// No point in looking up __pthread_get_minstack() on non-glibc
// platforms.
#[cfg(all(not(target_os = "linux"),
          not(target_os = "netbsd")))]
fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
    libc::PTHREAD_STACK_MIN as usize
}

#[cfg(target_os = "netbsd")]
fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
    2048 // just a guess
}
<commit_msg>Haiku: Use common thread set_name stub<commit_after>// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use alloc::boxed::FnBox;
use cmp;
use ffi::CStr;
use io;
use libc;
use mem;
use ptr;
use sys::os;
use time::Duration;

use sys_common::thread::*;

pub struct Thread {
    id: libc::pthread_t,
}

// Some platforms may have pthread_t as a pointer in which case we still want
// a thread to be Send/Sync
unsafe impl Send for Thread {}
unsafe impl Sync for Thread {}

impl Thread {
    pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>)
                          -> io::Result<Thread> {
        let p = box p;
        let mut native: libc::pthread_t = mem::zeroed();
        let mut attr: libc::pthread_attr_t = mem::zeroed();
        assert_eq!(libc::pthread_attr_init(&mut attr), 0);

        let stack_size = cmp::max(stack, min_stack_size(&attr));
        match libc::pthread_attr_setstacksize(&mut attr,
                                              stack_size as libc::size_t) {
            0 => {}
            n => {
                assert_eq!(n, libc::EINVAL);
                // EINVAL means |stack_size| is either too small or not a
                // multiple of the system page size.  Because it's definitely
                // >= PTHREAD_STACK_MIN, it must be an alignment issue.
                // Round up to the nearest page and try again.
                let page_size = os::page_size();
                let stack_size = (stack_size + page_size - 1) &
                                 (-(page_size as isize - 1) as usize - 1);
                let stack_size = stack_size as libc::size_t;
                assert_eq!(libc::pthread_attr_setstacksize(&mut attr,
                                                           stack_size), 0);
            }
        };

        let ret = libc::pthread_create(&mut native, &attr, thread_start,
                                       &*p as *const _ as *mut _);
        assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);

        return if ret != 0 {
            Err(io::Error::from_raw_os_error(ret))
        } else {
            mem::forget(p); // ownership passed to pthread_create
            Ok(Thread { id: native })
        };

        extern fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
            unsafe { start_thread(main); }
            ptr::null_mut()
        }
    }

    pub fn yield_now() {
        let ret = unsafe { libc::sched_yield() };
        debug_assert_eq!(ret, 0);
    }

    #[cfg(any(target_os = "linux",
              target_os = "android"))]
    pub fn set_name(name: &CStr) {
        const PR_SET_NAME: libc::c_int = 15;
        // pthread wrapper only appeared in glibc 2.12, so we use syscall
        // directly.
        unsafe {
            libc::prctl(PR_SET_NAME, name.as_ptr() as libc::c_ulong, 0, 0, 0);
        }
    }

    #[cfg(any(target_os = "freebsd",
              target_os = "dragonfly",
              target_os = "bitrig",
              target_os = "openbsd"))]
    pub fn set_name(name: &CStr) {
        unsafe {
            libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr());
        }
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    pub fn set_name(name: &CStr) {
        unsafe {
            libc::pthread_setname_np(name.as_ptr());
        }
    }

    #[cfg(target_os = "netbsd")]
    pub fn set_name(name: &CStr) {
        use ffi::CString;
        let cname = CString::new(&b"%s"[..]).unwrap();
        unsafe {
            libc::pthread_setname_np(libc::pthread_self(), cname.as_ptr(),
                                     name.as_ptr() as *mut libc::c_void);
        }
    }
    #[cfg(any(target_env = "newlib",
              target_os = "solaris",
              target_os = "haiku",
              target_os = "emscripten"))]
    pub fn set_name(_name: &CStr) {
        // Newlib, Illumos, Haiku, and Emscripten have no way to set a thread name.
    }

    pub fn sleep(dur: Duration) {
        let mut secs = dur.as_secs();
        let mut nsecs = dur.subsec_nanos() as libc::c_long;

        // If we're awoken with a signal then the return value will be -1 and
        // nanosleep will fill in `ts` with the remaining time.
        unsafe {
            while secs > 0 || nsecs > 0 {
                let mut ts = libc::timespec {
                    tv_sec: cmp::min(libc::time_t::max_value() as u64, secs) as libc::time_t,
                    tv_nsec: nsecs,
                };
                secs -= ts.tv_sec as u64;
                if libc::nanosleep(&ts, &mut ts) == -1 {
                    assert_eq!(os::errno(), libc::EINTR);
                    secs += ts.tv_sec as u64;
                    nsecs = ts.tv_nsec;
                } else {
                    nsecs = 0;
                }
            }
        }
    }

    pub fn join(self) {
        unsafe {
            let ret = libc::pthread_join(self.id, ptr::null_mut());
            mem::forget(self);
            debug_assert_eq!(ret, 0);
        }
    }

    pub fn id(&self) -> libc::pthread_t { self.id }

    pub fn into_id(self) -> libc::pthread_t {
        let id = self.id;
        mem::forget(self);
        id
    }
}

impl Drop for Thread {
    fn drop(&mut self) {
        let ret = unsafe { libc::pthread_detach(self.id) };
        debug_assert_eq!(ret, 0);
    }
}

#[cfg(all(not(all(target_os = "linux", not(target_env = "musl"))),
          not(target_os = "freebsd"),
          not(target_os = "macos"),
          not(target_os = "bitrig"),
          not(all(target_os = "netbsd", not(target_vendor = "rumprun"))),
          not(target_os = "openbsd"),
          not(target_os = "solaris")))]
#[cfg_attr(test, allow(dead_code))]
pub mod guard {
    pub unsafe fn current() -> Option<usize> { None }
    pub unsafe fn init() -> Option<usize> { None }
}

#[cfg(any(all(target_os = "linux", not(target_env = "musl")),
          target_os = "freebsd",
          target_os = "macos",
          target_os = "bitrig",
          all(target_os = "netbsd", not(target_vendor = "rumprun")),
          target_os = "openbsd",
          target_os = "solaris"))]
#[cfg_attr(test, allow(dead_code))]
pub mod guard {
    use libc;
    use libc::mmap;
    use libc::{PROT_NONE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED};
    use sys::os;

    #[cfg(any(target_os = "macos",
              target_os = "bitrig",
              target_os = "openbsd",
              target_os = "solaris"))]
    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
        current().map(|s| s as *mut libc::c_void)
    }

    #[cfg(any(target_os = "android", target_os = "freebsd",
              target_os = "linux", target_os = "netbsd"))]
    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
        let mut ret = None;
        let mut attr: libc::pthread_attr_t = ::mem::zeroed();
        assert_eq!(libc::pthread_attr_init(&mut attr), 0);
        #[cfg(target_os = "freebsd")]
            let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr);
        #[cfg(not(target_os = "freebsd"))]
            let e = libc::pthread_getattr_np(libc::pthread_self(), &mut attr);
        if e == 0 {
            let mut stackaddr = ::ptr::null_mut();
            let mut stacksize = 0;
            assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr,
                                                   &mut stacksize), 0);
            ret = Some(stackaddr);
        }
        assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
        ret
    }

    pub unsafe fn init() -> Option<usize> {
        let psize = os::page_size();
        let mut stackaddr = match get_stack_start() {
            Some(addr) => addr,
            None => return None,
        };

        // Ensure stackaddr is page aligned! A parent process might
        // have reset RLIMIT_STACK to be non-page aligned. The
        // pthread_attr_getstack() reports the usable stack area
        // stackaddr < stackaddr + stacksize, so if stackaddr is not
        // page-aligned, calculate the fix such that stackaddr <
        // new_page_aligned_stackaddr < stackaddr + stacksize
        let remainder = (stackaddr as usize) % psize;
        if remainder != 0 {
            stackaddr = ((stackaddr as usize) + psize - remainder)
                as *mut libc::c_void;
        }

        // Rellocate the last page of the stack.
        // This ensures SIGBUS will be raised on
        // stack overflow.
        let result = mmap(stackaddr,
                          psize as libc::size_t,
                          PROT_NONE,
                          MAP_PRIVATE | MAP_ANON | MAP_FIXED,
                          -1,
                          0);

        if result != stackaddr || result == MAP_FAILED {
            panic!("failed to allocate a guard page");
        }

        let offset = if cfg!(any(target_os = "linux", target_os = "freebsd")) {
            2
        } else {
            1
        };

        Some(stackaddr as usize + offset * psize)
    }

    #[cfg(target_os = "solaris")]
    pub unsafe fn current() -> Option<usize> {
        let mut current_stack: libc::stack_t = ::mem::zeroed();
        assert_eq!(libc::stack_getbounds(&mut current_stack), 0);
        Some(current_stack.ss_sp as usize)
    }

    #[cfg(target_os = "macos")]
    pub unsafe fn current() -> Option<usize> {
        Some((libc::pthread_get_stackaddr_np(libc::pthread_self()) as libc::size_t -
              libc::pthread_get_stacksize_np(libc::pthread_self())) as usize)
    }

    #[cfg(any(target_os = "openbsd", target_os = "bitrig"))]
    pub unsafe fn current() -> Option<usize> {
        let mut current_stack: libc::stack_t = ::mem::zeroed();
        assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(),
                                             &mut current_stack), 0);

        let extra = if cfg!(target_os = "bitrig") {3} else {1} * os::page_size();
        Some(if libc::pthread_main_np() == 1 {
            // main thread
            current_stack.ss_sp as usize - current_stack.ss_size as usize + extra
        } else {
            // new thread
            current_stack.ss_sp as usize - current_stack.ss_size as usize
        })
    }

    #[cfg(any(target_os = "android", target_os = "freebsd",
              target_os = "linux", target_os = "netbsd"))]
    pub unsafe fn current() -> Option<usize> {
        let mut ret = None;
        let mut attr: libc::pthread_attr_t = ::mem::zeroed();
        assert_eq!(libc::pthread_attr_init(&mut attr), 0);
        #[cfg(target_os = "freebsd")]
            let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr);
        #[cfg(not(target_os = "freebsd"))]
            let e = libc::pthread_getattr_np(libc::pthread_self(), &mut attr);
        if e == 0 {
            let mut guardsize = 0;
            assert_eq!(libc::pthread_attr_getguardsize(&attr, &mut guardsize), 0);
            if guardsize == 0 {
                panic!("there is no guard page");
            }
            let mut stackaddr = ::ptr::null_mut();
            let mut size = 0;
            assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr,
                                                   &mut size), 0);

            ret = if cfg!(target_os = "freebsd") {
                Some(stackaddr as usize - guardsize as usize)
            } else if cfg!(target_os = "netbsd") {
                Some(stackaddr as usize)
            } else {
                Some(stackaddr as usize + guardsize as usize)
            };
        }
        assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
        ret
    }
}

// glibc >= 2.15 has a __pthread_get_minstack() function that returns
// PTHREAD_STACK_MIN plus however many bytes are needed for thread-local
// storage.  We need that information to avoid blowing up when a small stack
// is created in an application with big thread-local storage requirements.
// See #6233 for rationale and details.
#[cfg(target_os = "linux")]
#[allow(deprecated)]
fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize {
    weak!(fn __pthread_get_minstack(*const libc::pthread_attr_t) -> libc::size_t);

    match __pthread_get_minstack.get() {
        None => libc::PTHREAD_STACK_MIN as usize,
        Some(f) => unsafe { f(attr) as usize },
    }
}

// No point in looking up __pthread_get_minstack() on non-glibc
// platforms.
#[cfg(all(not(target_os = "linux"),
          not(target_os = "netbsd")))]
fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
    libc::PTHREAD_STACK_MIN as usize
}

#[cfg(target_os = "netbsd")]
fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
    2048 // just a guess
}
<|endoftext|>


<commit_before><commit_msg>server: Print full URL on serve()<commit_after><|endoftext|>


<commit_before>use slice::item::Slice;
use slice::section::Kind;

pub fn code_for_slice(slice: &Slice) -> String {
    let mut string = String::new();
    for item in slice.section(Kind::From) {
        string.push_str("FROM ");
        string.push_str(item);
        string.push('\n');
    }
    string.push_str("RUN ");
    let mut is_first = true;
    for item in slice.run_section() {
        if is_first {
            is_first = false;
        } else {
            string.push_str(" && \\\n");
        }
        string.push_str(item);
    }
    string
}<commit_msg>Added test for docker formatter<commit_after>use slice::item::Slice;
use slice::section::Kind;

pub fn code_for_slice(slice: &Slice) -> String {
    let mut string = String::new();
    for item in slice.section(Kind::From) {
        string.push_str("FROM ");
        string.push_str(item);
        string.push('\n');
    }
    let run_section = slice.run_section();
    if !run_section.is_empty() {
        string.push_str("RUN ");
        let mut is_first = true;
        for item in run_section {
            if is_first {
                is_first = false;
            } else {
                string.push_str(" && \\\n");
            }
            string.push_str(item);
        }
        string.push('\n');
    }
    string
}

#[cfg(test)]
mod tests {
    use std::path::PathBuf;
    use helper;
    use slice::item::Slice;
    use slice::section::{Kind, Section};

    fn create_slice(from_section_items: Vec<&str>, run_section_items: Vec<&str>) -> Slice {
        let items = from_section_items.into_iter().map(|i| i.to_string()).collect::<Vec<_>>();
        let from_section = Section { kind: Kind::From, items: items };
        let items = run_section_items.into_iter().map(|i| i.to_string()).collect::<Vec<_>>();
        let run_section = Section { kind: Kind::Run, items: items };
        Slice { name: "Hello".to_string(), path: PathBuf::new(),
                version: helper::zero_version(), sections: vec![from_section, run_section] }
    }

    #[test]
    fn code_for_slice() {
        let slice = create_slice(Vec::new(), vec!["apt-get install -q -y wget"]);
        assert_eq!(super::code_for_slice(&slice), "RUN apt-get install -q -y wget\n");

        let slice = create_slice(vec!["base"], vec!["apt-get install -q -y wget"]);
        assert_eq!(super::code_for_slice(&slice), "FROM base
RUN apt-get install -q -y wget\n");

        let run_section_items = vec!["apt-get install -q -y wget",
                                     "apt-get install -q -y wget_gui"];
        let slice = create_slice(vec!["base", "another_base"], run_section_items);
        assert_eq!(super::code_for_slice(&slice), "FROM base
FROM another_base
RUN apt-get install -q -y wget && \\
apt-get install -q -y wget_gui
");
    }
}
<|endoftext|>


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

use std::borrow::Cow;
use std::io;

use bit_vec::BitVec;
use byteorder::{WriteBytesExt, BigEndian};

pub trait Encodable {
    fn encoded_size(&self) -> usize;
    fn write_encoded_to<W>(&self, &mut W) -> io::Result<()>
        where W: io::Write;
}

impl<'a, T: Encodable> Encodable for &'a T {
    fn encoded_size(&self) -> usize {
        (*self).encoded_size()
    }
    fn write_encoded_to<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        (*self).write_encoded_to(writer)
    }
}

impl Encodable for u8 {
    fn encoded_size(&self) -> usize {
        1
    }

    fn write_encoded_to<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        writer.write_u8(*self)
    }
}

impl Encodable for u16 {
    fn encoded_size(&self) -> usize {
        2
    }

    fn write_encoded_to<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        writer.write_u16::<BigEndian>(*self)
    }
}

impl Encodable for u32 {
    fn encoded_size(&self) -> usize {
        4
    }

    fn write_encoded_to<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        writer.write_u32::<BigEndian>(*self)
    }
}

impl Encodable for u64 {
    fn encoded_size(&self) -> usize {
        4
    }

    fn write_encoded_to<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        writer.write_u64::<BigEndian>(*self)
    }
}

impl<'a> Encodable for Cow<'a, [u8]> {
    fn encoded_size(&self) -> usize {
        1 + self.len()
    }

    fn write_encoded_to<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        if self.len() > (::std::u32::MAX as usize) {
            return Err(io::Error::new(io::ErrorKind::InvalidData, "AMQP long string too large"));
        }

        try!(writer.write_u32::<BigEndian>(self.len() as u32));
        try!(writer.write_all(&self[..]));

        Ok(())
    }
}

impl<'a> Encodable for Cow<'a, str> {
    fn encoded_size(&self) -> usize {
        4 + self.len()
    }

    fn write_encoded_to<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        if self.len() > (::std::u8::MAX as usize) {
            return Err(io::Error::new(io::ErrorKind::InvalidData, "AMQP short string too large"));
        }

        try!(writer.write_u8(self.len() as u8));
        try!(writer.write_all(self.as_bytes()));

        Ok(())
    }
}

impl<T: Encodable> Encodable for Option<T> {
    fn encoded_size(&self) -> usize {
        self.as_ref().map(|val| val.encoded_size()).unwrap_or(0)
    }

    fn write_encoded_to<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        match self.as_ref() {
            Some(val) => val.write_encoded_to(writer),
            _ => Ok(()),
        }
    }
}

impl Encodable for BitVec {
    fn encoded_size(&self) -> usize {
        self.len() / 8
    }

    fn write_encoded_to<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        writer.write_all(&self.to_bytes()[..])
    }
}

<commit_msg>[primitives] Correct encoded_size for Cow<'a, str> and Cow<'a, [u8]><commit_after>// Copyright 2016-17 Alexander Reece
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::borrow::Cow;
use std::io;

use bit_vec::BitVec;
use byteorder::{WriteBytesExt, BigEndian};

pub trait Encodable {
    fn encoded_size(&self) -> usize;
    fn write_encoded_to<W>(&self, &mut W) -> io::Result<()>
        where W: io::Write;
}

impl<'a, T: Encodable> Encodable for &'a T {
    fn encoded_size(&self) -> usize {
        (*self).encoded_size()
    }
    fn write_encoded_to<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        (*self).write_encoded_to(writer)
    }
}

impl Encodable for u8 {
    fn encoded_size(&self) -> usize {
        1
    }

    fn write_encoded_to<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        writer.write_u8(*self)
    }
}

impl Encodable for u16 {
    fn encoded_size(&self) -> usize {
        2
    }

    fn write_encoded_to<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        writer.write_u16::<BigEndian>(*self)
    }
}

impl Encodable for u32 {
    fn encoded_size(&self) -> usize {
        4
    }

    fn write_encoded_to<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        writer.write_u32::<BigEndian>(*self)
    }
}

impl Encodable for u64 {
    fn encoded_size(&self) -> usize {
        4
    }

    fn write_encoded_to<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        writer.write_u64::<BigEndian>(*self)
    }
}

impl<'a> Encodable for Cow<'a, [u8]> {
    fn encoded_size(&self) -> usize {
        4 + self.len()
    }

    fn write_encoded_to<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        if self.len() > (::std::u32::MAX as usize) {
            return Err(io::Error::new(io::ErrorKind::InvalidData, "AMQP long string too large"));
        }

        try!(writer.write_u32::<BigEndian>(self.len() as u32));
        try!(writer.write_all(&self[..]));

        Ok(())
    }
}

impl<'a> Encodable for Cow<'a, str> {
    fn encoded_size(&self) -> usize {
        1 + self.len()
    }

    fn write_encoded_to<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        if self.len() > (::std::u8::MAX as usize) {
            return Err(io::Error::new(io::ErrorKind::InvalidData, "AMQP short string too large"));
        }

        try!(writer.write_u8(self.len() as u8));
        try!(writer.write_all(self.as_bytes()));

        Ok(())
    }
}

impl<T: Encodable> Encodable for Option<T> {
    fn encoded_size(&self) -> usize {
        self.as_ref().map(|val| val.encoded_size()).unwrap_or(0)
    }

    fn write_encoded_to<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        match self.as_ref() {
            Some(val) => val.write_encoded_to(writer),
            _ => Ok(()),
        }
    }
}

impl Encodable for BitVec {
    fn encoded_size(&self) -> usize {
        self.len() / 8
    }

    fn write_encoded_to<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        writer.write_all(&self.to_bytes()[..])
    }
}

<|endoftext|>


<commit_before>//!

use super::{
    context::GraphicsContext,
    draw::{DrawParam, DrawUniforms, Std140DrawUniforms},
    gpu::arc::ArcBuffer,
    Image, WgpuContext,
};
use crevice::std140::AsStd140;
use std::collections::BTreeMap;

/// Array of instances for fast rendering of many meshes.
///
/// Traditionally known as a "batch".
#[derive(Debug)]
pub struct InstanceArray {
    pub(crate) buffer: ArcBuffer,
    pub(crate) indices: ArcBuffer,
    pub(crate) image: Image,
    pub(crate) ordered: bool,
    dirty: bool,
    capacity: u32,
    uniforms: Vec<Std140DrawUniforms>,
    params: Vec<DrawParam>,
}

impl InstanceArray {
    /// Creates a new [InstanceArray] capable of storing up to n-`capacity` instances (this can be changed and is resized automatically when needed).
    ///
    /// If `image` is `None`, a 1x1 white image will be used which can be used to draw solid rectangles.
    pub fn new(
        gfx: &GraphicsContext,
        image: impl Into<Option<Image>>,
        capacity: u32,
        ordered: bool,
    ) -> Self {
        InstanceArray::new_wgpu(
            &gfx.wgpu,
            image.into().unwrap_or_else(|| gfx.white_image.clone()),
            capacity,
            ordered,
        )
    }

    fn new_wgpu(wgpu: &WgpuContext, image: Image, capacity: u32, ordered: bool) -> Self {
        assert!(capacity > 0);

        let buffer = ArcBuffer::new(wgpu.device.create_buffer(&wgpu::BufferDescriptor {
            label: None,
            size: DrawUniforms::std140_size_static() as u64 * capacity as u64,
            usage: wgpu::BufferUsages::STORAGE
                | wgpu::BufferUsages::COPY_DST
                | wgpu::BufferUsages::COPY_SRC,
            mapped_at_creation: false,
        }));

        let indices = ArcBuffer::new(wgpu.device.create_buffer(&wgpu::BufferDescriptor {
            label: None,
            size: if ordered {
                std::mem::size_of::<u32>() as u64 * capacity as u64
            } else {
                4 // min for layout
            },
            usage: wgpu::BufferUsages::STORAGE
                | wgpu::BufferUsages::COPY_SRC
                | wgpu::BufferUsages::COPY_DST,
            mapped_at_creation: false,
        }));

        let uniforms = Vec::with_capacity(capacity as usize);
        let params = Vec::with_capacity(capacity as usize);

        InstanceArray {
            buffer,
            indices,
            image,
            ordered,
            dirty: false,
            capacity,
            uniforms,
            params,
        }
    }

    /// Resets all the instance data to a set of `DrawParam`.
    pub fn set(&mut self, instances: impl IntoIterator<Item = DrawParam>) {
        self.dirty = true;
        self.params.clear();
        self.params.extend(instances);
        self.uniforms.clear();
        self.uniforms.extend(self.params.iter().map(|x| {
            DrawUniforms::from_param(
                &x,
                [self.image.width() as f32, self.image.height() as f32].into(),
            )
            .as_std140()
        }));
    }

    /// Pushes a new instance onto the end.
    pub fn push(&mut self, instance: DrawParam) {
        self.dirty = true;
        self.uniforms.push(
            DrawUniforms::from_param(
                &instance,
                [self.image.width() as f32, self.image.height() as f32].into(),
            )
            .as_std140(),
        );
        self.params.push(instance);
    }

    /// Updates an existing instance at a given index, if it is valid.
    pub fn update(&mut self, index: u32, instance: DrawParam) {
        if let Some((uniform, param)) = self
            .uniforms
            .get_mut(index as usize)
            .and_then(|x| Some((x, self.params.get_mut(index as usize)?)))
        {
            self.dirty = true;
            *uniform = DrawUniforms::from_param(
                &instance,
                [self.image.width() as f32, self.image.height() as f32].into(),
            )
            .as_std140();
            *param = instance;
        }
    }

    /// Clears all instance data.
    pub fn clear(&mut self) {
        // don't need to set dirty here
        self.uniforms.clear();
        self.params.clear();
    }

    /// Returns whether the instance data has been changed without [`InstanceArray::flush()`] being called.
    #[inline]
    pub fn is_dirty(&self) -> bool {
        self.dirty
    }

    /// Returns an immutable slice of all the instance data in this [`InstanceArray`].
    #[inline]
    pub fn instances(&self) -> &[DrawParam] {
        &self.params
    }

    /// Uploads the instance data to the GPU.
    ///
    /// You do not usually need to call this yourself as it is done automatically during drawing.
    pub fn flush(&mut self, gfx: &GraphicsContext) {
        self.flush_wgpu(&gfx.wgpu)
    }

    #[allow(unsafe_code)]
    pub(crate) fn flush_wgpu(&mut self, wgpu: &WgpuContext) {
        if !self.dirty {
            return;
        } else {
            self.dirty = false;
        }

        let len = self.uniforms.len() as u32;
        if len > self.capacity {
            let resized = InstanceArray::new_wgpu(wgpu, self.image.clone(), len, self.ordered);
            self.buffer = resized.buffer;
            self.indices = resized.indices;
            self.capacity = len;
        }

        wgpu.queue.write_buffer(&self.buffer, 0, unsafe {
            std::slice::from_raw_parts(
                self.uniforms.as_ptr() as *const u8,
                self.uniforms.len() * DrawUniforms::std140_size_static(),
            )
        });

        if self.ordered {
            let mut layers = BTreeMap::<_, Vec<_>>::new();
            for (i, param) in self.params.iter().enumerate() {
                layers.entry(param.z).or_default().push(i);
            }
            let indices = layers.into_values().flatten().collect::<Vec<_>>();
            wgpu.queue.write_buffer(&self.indices, 0, unsafe {
                std::slice::from_raw_parts(
                    indices.as_ptr() as *const u8,
                    indices.len() * std::mem::size_of::<u32>(),
                )
            });
        }
    }

    /// Changes the capacity of this `InstanceArray` while preserving instances.
    ///
    /// If `new_capacity` is less than the `len`, the instances will be truncated.
    pub fn resize(&mut self, gfx: &GraphicsContext, new_capacity: u32) {
        let resized = InstanceArray::new(gfx, self.image.clone(), new_capacity, self.ordered);
        self.buffer = resized.buffer;
        self.indices = resized.indices;
        self.capacity = new_capacity;
        self.dirty = true;
        self.uniforms.truncate(new_capacity as usize);
        self.params.truncate(new_capacity as usize);
        self.uniforms
            .reserve((new_capacity as usize).min(self.uniforms.len()) - self.uniforms.len());
        self.params
            .reserve((new_capacity as usize).min(self.params.len()) - self.params.len());
    }

    /// Returns this `InstanceArray`'s associated `image`.
    #[inline]
    pub fn image(&self) -> Image {
        self.image.clone()
    }

    /// Returns the number of instances this [InstanceArray] is capable of holding.
    /// This number was specified when creating the [InstanceArray], or if the [InstanceArray]
    /// was automatically resized, the greatest length of instances.
    #[inline]
    pub fn capacity(&self) -> usize {
        self.capacity as usize
    }
}
<commit_msg>Fix clippy warning<commit_after>//!

use super::{
    context::GraphicsContext,
    draw::{DrawParam, DrawUniforms, Std140DrawUniforms},
    gpu::arc::ArcBuffer,
    Image, WgpuContext,
};
use crevice::std140::AsStd140;
use std::collections::BTreeMap;

/// Array of instances for fast rendering of many meshes.
///
/// Traditionally known as a "batch".
#[derive(Debug)]
pub struct InstanceArray {
    pub(crate) buffer: ArcBuffer,
    pub(crate) indices: ArcBuffer,
    pub(crate) image: Image,
    pub(crate) ordered: bool,
    dirty: bool,
    capacity: u32,
    uniforms: Vec<Std140DrawUniforms>,
    params: Vec<DrawParam>,
}

impl InstanceArray {
    /// Creates a new [InstanceArray] capable of storing up to n-`capacity` instances (this can be changed and is resized automatically when needed).
    ///
    /// If `image` is `None`, a 1x1 white image will be used which can be used to draw solid rectangles.
    pub fn new(
        gfx: &GraphicsContext,
        image: impl Into<Option<Image>>,
        capacity: u32,
        ordered: bool,
    ) -> Self {
        InstanceArray::new_wgpu(
            &gfx.wgpu,
            image.into().unwrap_or_else(|| gfx.white_image.clone()),
            capacity,
            ordered,
        )
    }

    fn new_wgpu(wgpu: &WgpuContext, image: Image, capacity: u32, ordered: bool) -> Self {
        assert!(capacity > 0);

        let buffer = ArcBuffer::new(wgpu.device.create_buffer(&wgpu::BufferDescriptor {
            label: None,
            size: DrawUniforms::std140_size_static() as u64 * capacity as u64,
            usage: wgpu::BufferUsages::STORAGE
                | wgpu::BufferUsages::COPY_DST
                | wgpu::BufferUsages::COPY_SRC,
            mapped_at_creation: false,
        }));

        let indices = ArcBuffer::new(wgpu.device.create_buffer(&wgpu::BufferDescriptor {
            label: None,
            size: if ordered {
                std::mem::size_of::<u32>() as u64 * capacity as u64
            } else {
                4 // min for layout
            },
            usage: wgpu::BufferUsages::STORAGE
                | wgpu::BufferUsages::COPY_SRC
                | wgpu::BufferUsages::COPY_DST,
            mapped_at_creation: false,
        }));

        let uniforms = Vec::with_capacity(capacity as usize);
        let params = Vec::with_capacity(capacity as usize);

        InstanceArray {
            buffer,
            indices,
            image,
            ordered,
            dirty: false,
            capacity,
            uniforms,
            params,
        }
    }

    /// Resets all the instance data to a set of `DrawParam`.
    pub fn set(&mut self, instances: impl IntoIterator<Item = DrawParam>) {
        self.dirty = true;
        self.params.clear();
        self.params.extend(instances);
        self.uniforms.clear();
        self.uniforms.extend(self.params.iter().map(|x| {
            DrawUniforms::from_param(
                x,
                [self.image.width() as f32, self.image.height() as f32].into(),
            )
            .as_std140()
        }));
    }

    /// Pushes a new instance onto the end.
    pub fn push(&mut self, instance: DrawParam) {
        self.dirty = true;
        self.uniforms.push(
            DrawUniforms::from_param(
                &instance,
                [self.image.width() as f32, self.image.height() as f32].into(),
            )
            .as_std140(),
        );
        self.params.push(instance);
    }

    /// Updates an existing instance at a given index, if it is valid.
    pub fn update(&mut self, index: u32, instance: DrawParam) {
        if let Some((uniform, param)) = self
            .uniforms
            .get_mut(index as usize)
            .and_then(|x| Some((x, self.params.get_mut(index as usize)?)))
        {
            self.dirty = true;
            *uniform = DrawUniforms::from_param(
                &instance,
                [self.image.width() as f32, self.image.height() as f32].into(),
            )
            .as_std140();
            *param = instance;
        }
    }

    /// Clears all instance data.
    pub fn clear(&mut self) {
        // don't need to set dirty here
        self.uniforms.clear();
        self.params.clear();
    }

    /// Returns whether the instance data has been changed without [`InstanceArray::flush()`] being called.
    #[inline]
    pub fn is_dirty(&self) -> bool {
        self.dirty
    }

    /// Returns an immutable slice of all the instance data in this [`InstanceArray`].
    #[inline]
    pub fn instances(&self) -> &[DrawParam] {
        &self.params
    }

    /// Uploads the instance data to the GPU.
    ///
    /// You do not usually need to call this yourself as it is done automatically during drawing.
    pub fn flush(&mut self, gfx: &GraphicsContext) {
        self.flush_wgpu(&gfx.wgpu)
    }

    #[allow(unsafe_code)]
    pub(crate) fn flush_wgpu(&mut self, wgpu: &WgpuContext) {
        if !self.dirty {
            return;
        } else {
            self.dirty = false;
        }

        let len = self.uniforms.len() as u32;
        if len > self.capacity {
            let resized = InstanceArray::new_wgpu(wgpu, self.image.clone(), len, self.ordered);
            self.buffer = resized.buffer;
            self.indices = resized.indices;
            self.capacity = len;
        }

        wgpu.queue.write_buffer(&self.buffer, 0, unsafe {
            std::slice::from_raw_parts(
                self.uniforms.as_ptr() as *const u8,
                self.uniforms.len() * DrawUniforms::std140_size_static(),
            )
        });

        if self.ordered {
            let mut layers = BTreeMap::<_, Vec<_>>::new();
            for (i, param) in self.params.iter().enumerate() {
                layers.entry(param.z).or_default().push(i);
            }
            let indices = layers.into_values().flatten().collect::<Vec<_>>();
            wgpu.queue.write_buffer(&self.indices, 0, unsafe {
                std::slice::from_raw_parts(
                    indices.as_ptr() as *const u8,
                    indices.len() * std::mem::size_of::<u32>(),
                )
            });
        }
    }

    /// Changes the capacity of this `InstanceArray` while preserving instances.
    ///
    /// If `new_capacity` is less than the `len`, the instances will be truncated.
    pub fn resize(&mut self, gfx: &GraphicsContext, new_capacity: u32) {
        let resized = InstanceArray::new(gfx, self.image.clone(), new_capacity, self.ordered);
        self.buffer = resized.buffer;
        self.indices = resized.indices;
        self.capacity = new_capacity;
        self.dirty = true;
        self.uniforms.truncate(new_capacity as usize);
        self.params.truncate(new_capacity as usize);
        self.uniforms
            .reserve((new_capacity as usize).min(self.uniforms.len()) - self.uniforms.len());
        self.params
            .reserve((new_capacity as usize).min(self.params.len()) - self.params.len());
    }

    /// Returns this `InstanceArray`'s associated `image`.
    #[inline]
    pub fn image(&self) -> Image {
        self.image.clone()
    }

    /// Returns the number of instances this [InstanceArray] is capable of holding.
    /// This number was specified when creating the [InstanceArray], or if the [InstanceArray]
    /// was automatically resized, the greatest length of instances.
    #[inline]
    pub fn capacity(&self) -> usize {
        self.capacity as usize
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "nightly", feature(test))]

#[cfg(feature = "nightly")]
extern crate test;

#[macro_use]
extern crate stdweb;

#[macro_use]
extern crate lazy_static;

use std::time::Duration;

use stdweb::web::document;
use stdweb::web::event::ClickEvent;
use stdweb::unstable::TryInto;
use stdweb::traits::*;

lazy_static! {
    static ref IS_NODEJS: bool = {
        let is_nodejs: bool = js!(
            return typeof window === "undefined" && typeof process === "object";
        ).try_into().unwrap();

        return is_nodejs;
    };
}

macro_rules! println {
    ($($token:tt)*) => {
        let string = format!( $($token)+ );
        if !*IS_NODEJS {
            let console = document().query_selector( "#console" ).unwrap().unwrap();
            console.append_child( &document().create_text_node( &string ) );
            console.append_child( &document().create_text_node( "\n" ) );
        }
        js! {
            console.log( @{string} );
        }
    };
}

mod utils;
use utils::Stopwatch;

struct Timer {
    timestamp: f64
}

impl Stopwatch for Timer {
    fn now() -> Self {
        if !*IS_NODEJS {
            let timestamp: f64 = js!( return performance.now(); ).try_into().unwrap();
            Timer {
                timestamp: timestamp / 1000_f64
            }
        } else {
            let timestamp: f64 = js!(
                var t = process.hrtime();
                return t[ 0 ] + t[ 1 ] / 1000000000;
            ).try_into().unwrap();

            Timer { timestamp }
        }
    }

    fn elapsed( &self ) -> Duration {
        let now = Timer::now();
        let difference = now.timestamp - self.timestamp;
        let secs = difference.trunc();
        Duration::new( secs as u64, ((difference - secs) * 1_000_000_000.0) as u32 )
    }
}

struct Bench {
    name: String,
    callback: Box< Fn( &Bench ) + 'static >
}

struct Bencher {
    benches: Vec< Bench >
}

impl Bencher {
    fn new() -> Self {
        Bencher { benches: Vec::new() }
    }

    fn add< R, F: 'static + Fn() -> R >( &mut self, name: &str, callback: F ) {
        self.benches.push( Bench {
            name: name.to_owned(),
            callback: Box::new( move |bench| {
                println!( "Benchmarking '{}'...", bench.name );
                let result = utils::benchmark::< Timer, R, F >( &callback );
                println!( "    {}", result );
            })
        });
    }

    fn run( &self ) {
        for bench in &self.benches {
            (bench.callback)( bench );
        }
    }
}

fn run_benchmarks< F: FnOnce( &mut Bencher ) >( callback: F ) {
    if !*IS_NODEJS {
        let body = document().query_selector( "body" ).unwrap().unwrap();
        let start = document().create_element( "button" ).unwrap();
        start.set_text_content( "Start" );
        body.append_child( &start );
        let pre = document().create_element( "pre" ).unwrap();
        pre.set_attribute( "id", "console" ).unwrap();
        body.append_child( &pre );
    }

    if cfg!( nightly ) {
        js! {
            console.log( "Compiled with the `nightly` feature!" );
        }
    }

    let mut bencher = Bencher::new();
    callback( &mut bencher );

    if !*IS_NODEJS {
        let body = document().query_selector( "body" ).unwrap().unwrap();
        body.add_event_listener( move |_: ClickEvent| {
            bencher.run();
        });
    } else {
        bencher.run();
    }
}

fn main() {
    run_benchmarks( |bencher| {
        bencher.add( "call-into-js", || js!( @(no_return) ) );
        bencher.add( "call-into-js-returning-undefined", || js!() );
        bencher.add( "call-into-js-with-string", || js!( @(no_return) var test = @{"Hello world!"}; ) );
    });
}
<commit_msg>Allow setup before running benchmarks<commit_after>#![cfg_attr(feature = "nightly", feature(test))]

#[cfg(feature = "nightly")]
extern crate test;

#[macro_use]
extern crate stdweb;

#[macro_use]
extern crate lazy_static;

use std::time::Duration;

use stdweb::web::document;
use stdweb::web::event::ClickEvent;
use stdweb::unstable::TryInto;
use stdweb::traits::*;

lazy_static! {
    static ref IS_NODEJS: bool = {
        let is_nodejs: bool = js!(
            return typeof window === "undefined" && typeof process === "object";
        ).try_into().unwrap();

        return is_nodejs;
    };
}

macro_rules! println {
    ($($token:tt)*) => {
        let string = format!( $($token)+ );
        if !*IS_NODEJS {
            let console = document().query_selector( "#console" ).unwrap().unwrap();
            console.append_child( &document().create_text_node( &string ) );
            console.append_child( &document().create_text_node( "\n" ) );
        }
        js! {
            console.log( @{string} );
        }
    };
}

mod utils;
use utils::Stopwatch;

struct Timer {
    timestamp: f64
}

impl Stopwatch for Timer {
    fn now() -> Self {
        if !*IS_NODEJS {
            let timestamp: f64 = js!( return performance.now(); ).try_into().unwrap();
            Timer {
                timestamp: timestamp / 1000_f64
            }
        } else {
            let timestamp: f64 = js!(
                var t = process.hrtime();
                return t[ 0 ] + t[ 1 ] / 1000000000;
            ).try_into().unwrap();

            Timer { timestamp }
        }
    }

    fn elapsed( &self ) -> Duration {
        let now = Timer::now();
        let difference = now.timestamp - self.timestamp;
        let secs = difference.trunc();
        Duration::new( secs as u64, ((difference - secs) * 1_000_000_000.0) as u32 )
    }
}

struct Bench {
    name: String,
    callback: Box< Fn( &Bench ) + 'static >
}

struct Bencher {
    benches: Vec< Bench >
}

impl Bencher {
    fn new() -> Self {
        Bencher { benches: Vec::new() }
    }

    fn add< R, F: 'static + Fn() -> R, G: 'static + Fn() -> F >( &mut self, name: &str, callback: G ) {
        self.benches.push( Bench {
            name: name.to_owned(),
            callback: Box::new( move |bench| {
                println!( "Benchmarking '{}'...", bench.name );
                let callback = callback();
                let result = utils::benchmark::< Timer, R, F >( &callback );
                println!( "    {}", result );
            })
        });
    }

    fn run( &self ) {
        for bench in &self.benches {
            (bench.callback)( bench );
        }
    }
}

fn run_benchmarks< F: FnOnce( &mut Bencher ) >( callback: F ) {
    if !*IS_NODEJS {
        let body = document().query_selector( "body" ).unwrap().unwrap();
        let start = document().create_element( "button" ).unwrap();
        start.set_text_content( "Start" );
        body.append_child( &start );
        let pre = document().create_element( "pre" ).unwrap();
        pre.set_attribute( "id", "console" ).unwrap();
        body.append_child( &pre );
    }

    if cfg!( nightly ) {
        js! {
            console.log( "Compiled with the `nightly` feature!" );
        }
    }

    let mut bencher = Bencher::new();
    callback( &mut bencher );

    if !*IS_NODEJS {
        let body = document().query_selector( "body" ).unwrap().unwrap();
        body.add_event_listener( move |_: ClickEvent| {
            bencher.run();
        });
    } else {
        bencher.run();
    }
}

fn main() {
    run_benchmarks( |bencher| {
        bencher.add( "call-into-js", || || js!( @(no_return) ) );
        bencher.add( "call-into-js-returning-undefined", || || js!() );
        bencher.add( "call-into-js-with-string", || || js!( @(no_return) var test = @{"Hello world!"}; ) );
    });
}
<|endoftext|>


<commit_before>#[cfg(feature="bigdecimal")]
mod bigdecimal {
    extern crate num_traits;
    extern crate num_bigint;
    extern crate num_integer;
    extern crate bigdecimal;

    use std::error::Error;
    use std::io::prelude::*;

    use pg::Pg;

    use self::num_traits::{Signed, Zero, ToPrimitive};
    use self::num_bigint::{Sign, BigInt, BigUint, ToBigInt};
    use self::num_integer::Integer;
    use self::bigdecimal::BigDecimal;

    use pg::data_types::PgNumeric;
    use types::{self, FromSql, ToSql, IsNull};

    impl ToSql<types::Numeric, Pg> for BigDecimal {
        fn to_sql<W: Write>(&self, out: &mut W) -> Result<IsNull, Box<Error + Send + Sync>> {
            use std::str::FromStr;

            let absolute = self.abs();

            let mut digits = vec![];
            let ten_k = BigInt::from(10000);
            let mut integer_part = absolute.to_bigint().expect("Can always take integer part of BigDecimal");
            let decimal_part = &absolute;
            let mut decimal_part = decimal_part - absolute.with_scale(0);
            // scale is the amount of digits to print. to_string() includes a "0.",
            // that's why the -2 is there.
            let scale = if decimal_part == Zero::zero() {
                0
            } else {
                decimal_part.to_string().len() as u16 - 2
            };
            let mut weight = 0;

            // Encode the integer part
            while ten_k < integer_part {
                weight += 1;
                // digit is integer_part REM 10_000
                let (div, digit) = integer_part.div_rem(&ten_k);
                digits.push(digit.to_u16().expect("digit < 10000, but cannot fit in i16") as i16);
                integer_part = div;
            }
            digits.push(integer_part.to_string().parse::<i16>().expect("digit < 10000, but cannot fit in i16"));

            digits.reverse();

            // Encode the decimal part
            let ten_k = BigDecimal::from_str("10000").expect("Could not parse into BigDecimal");
            while decimal_part != BigDecimal::zero() {
                decimal_part *= &ten_k;
                let digit = decimal_part.to_bigint().expect("Can always take integer part of BigDecimal");
                // This can be simplified when github.com/akubera/bigdecimal-rs/issues/13 gets
                // solved; decimal_part -= &digit; should suffice by then.
                decimal_part -= BigDecimal::new(digit.clone(), 0);
                digits.push(digit.to_u16().expect("digit < 10000, but cannot fit in i16") as i16);
            }

            let numeric = match self.sign() {
                Sign::Plus => PgNumeric::Positive {
                    digits, scale, weight
                },
                Sign::Minus => PgNumeric::Negative {
                    digits, scale, weight
                },
                Sign::NoSign => PgNumeric::Positive {
                    digits: vec![0],
                    scale: 0,
                    weight: 0,
                },
            };
            ToSql::<types::Numeric, Pg>::to_sql(&numeric, out)
        }
    }

    impl FromSql<types::Numeric, Pg> for BigDecimal {
        fn from_sql(numeric: Option<&[u8]>) -> Result<Self, Box<Error+Send+Sync>> {
            let (sign, weight, _, digits) = match PgNumeric::from_sql(numeric)? {
                PgNumeric::Positive { weight, scale, digits } => (Sign::Plus, weight, scale, digits),
                PgNumeric::Negative { weight, scale, digits } => (Sign::Minus, weight, scale, digits),
                PgNumeric::NaN => return Err(Box::from("NaN is not (yet) supported in BigDecimal")),
            };
            let mut result = BigUint::default();
            let count = digits.len() as i64;
            for digit in digits {
                result = result * BigUint::from(10_000u64);
                result = result + BigUint::from(digit as u64);
            }
            // First digit got factor 10_000^(digits.len() - 1), but should get 10_000^weight
            let correction_exp = 4 * ( (weight as i64) - count + 1);
            // FIXME: `scale` allows to drop some insignificant figures, which is currently unimplemented.
            // This means that e.g. PostgreSQL 0.01 will be interpreted as 0.0100
            let result = BigDecimal::new(BigInt::from_biguint(sign, result), -correction_exp);
            Ok(result)
        }
    }
}
<commit_msg>Add comment to decimal coding.<commit_after>#[cfg(feature="bigdecimal")]
mod bigdecimal {
    extern crate num_traits;
    extern crate num_bigint;
    extern crate num_integer;
    extern crate bigdecimal;

    use std::error::Error;
    use std::io::prelude::*;

    use pg::Pg;

    use self::num_traits::{Signed, Zero, ToPrimitive};
    use self::num_bigint::{Sign, BigInt, BigUint, ToBigInt};
    use self::num_integer::Integer;
    use self::bigdecimal::BigDecimal;

    use pg::data_types::PgNumeric;
    use types::{self, FromSql, ToSql, IsNull};

    impl ToSql<types::Numeric, Pg> for BigDecimal {
        fn to_sql<W: Write>(&self, out: &mut W) -> Result<IsNull, Box<Error + Send + Sync>> {
            use std::str::FromStr;

            // The encoding of the BigDecimal type for PostgreSQL is a bit complicated:
            // PostgreSQL expects the data in base-10000 (so two bytes per 10k),
            // and the decimal point should lie on a boundary (as per definition of "base-10000").

            // BigDecimal, internally, holds an int vector (base-256, one byte per byte),
            // and a base (u64, base-10) shift.

            // Therefore, we split up the encoding in three parts:
            // the sign, the (integer) part before the decimal, and the part after the decimal.

            let absolute = self.abs();

            let mut digits = vec![];
            let ten_k = BigInt::from(10000);
            let mut integer_part = absolute.to_bigint().expect("Can always take integer part of BigDecimal");
            let decimal_part = &absolute;
            let mut decimal_part = decimal_part - absolute.with_scale(0);
            // scale is the amount of digits to print. to_string() includes a "0.",
            // that's why the -2 is there.
            let scale = if decimal_part == Zero::zero() {
                0
            } else {
                decimal_part.to_string().len() as u16 - 2
            };
            let mut weight = 0;

            // Encode the integer part
            while ten_k < integer_part {
                weight += 1;
                // digit is integer_part REM 10_000
                let (div, digit) = integer_part.div_rem(&ten_k);
                digits.push(digit.to_u16().expect("digit < 10000, but cannot fit in i16") as i16);
                integer_part = div;
            }
            digits.push(integer_part.to_string().parse::<i16>().expect("digit < 10000, but cannot fit in i16"));

            digits.reverse();

            // Encode the decimal part
            let ten_k = BigDecimal::from_str("10000").expect("Could not parse into BigDecimal");
            while decimal_part != BigDecimal::zero() {
                decimal_part *= &ten_k;
                let digit = decimal_part.to_bigint().expect("Can always take integer part of BigDecimal");
                // This can be simplified when github.com/akubera/bigdecimal-rs/issues/13 gets
                // solved; decimal_part -= &digit; should suffice by then.
                decimal_part -= BigDecimal::new(digit.clone(), 0);
                digits.push(digit.to_u16().expect("digit < 10000, but cannot fit in i16") as i16);
            }

            let numeric = match self.sign() {
                Sign::Plus => PgNumeric::Positive {
                    digits, scale, weight
                },
                Sign::Minus => PgNumeric::Negative {
                    digits, scale, weight
                },
                Sign::NoSign => PgNumeric::Positive {
                    digits: vec![0],
                    scale: 0,
                    weight: 0,
                },
            };
            ToSql::<types::Numeric, Pg>::to_sql(&numeric, out)
        }
    }

    impl FromSql<types::Numeric, Pg> for BigDecimal {
        fn from_sql(numeric: Option<&[u8]>) -> Result<Self, Box<Error+Send+Sync>> {
            let (sign, weight, _, digits) = match PgNumeric::from_sql(numeric)? {
                PgNumeric::Positive { weight, scale, digits } => (Sign::Plus, weight, scale, digits),
                PgNumeric::Negative { weight, scale, digits } => (Sign::Minus, weight, scale, digits),
                PgNumeric::NaN => return Err(Box::from("NaN is not (yet) supported in BigDecimal")),
            };
            let mut result = BigUint::default();
            let count = digits.len() as i64;
            for digit in digits {
                result = result * BigUint::from(10_000u64);
                result = result + BigUint::from(digit as u64);
            }
            // First digit got factor 10_000^(digits.len() - 1), but should get 10_000^weight
            let correction_exp = 4 * ( (weight as i64) - count + 1);
            // FIXME: `scale` allows to drop some insignificant figures, which is currently unimplemented.
            // This means that e.g. PostgreSQL 0.01 will be interpreted as 0.0100
            let result = BigDecimal::new(BigInt::from_biguint(sign, result), -correction_exp);
            Ok(result)
        }
    }
}
<|endoftext|>


<commit_before>use sass::output_style::SassOutputStyle;
use token::{Lexeme, Token};
use ast::number_value::NumberValue;
use context::Context;
use error::{Result, SassError, ErrorKind};

#[derive(Debug, Clone, PartialEq)]
pub enum Expression {
    List(Vec<Expression>),
    Number(NumberValue),
    Operator(Lexeme),
    String(Lexeme),
}

impl Expression {
    #[allow(unused_variables)]
    pub fn to_string(&self, style: SassOutputStyle) -> String {
        match *self {
            Expression::List(ref elements) => {
                elements.iter().map(|e|
                    e.to_string(style)
                ).collect::<Vec<_>>().join(" ")
            },
            Expression::Number(ref nv) => nv.to_string(),
            Expression::Operator(ref lex) => lex.token.to_string(),
            Expression::String(ref lex) => lex.token.to_string(),
        }
    }

    pub fn parse<T: Iterator<Item = Result<Lexeme>>>(tokenizer: &mut T) -> Result<Expression> {
        let mut list = vec![];
        while let Some(Ok(lexeme)) = tokenizer.next() {
            match lexeme.token {
                Token::Semicolon => {
                    if list.len() == 1 {
                        return Ok(list.pop().unwrap())
                    } else {
                        return Ok(Expression::List(list))
                    }
                },
                Token::Number(_, _) => {
                    list.push(Expression::Number(NumberValue::from_scalar(lexeme)));
                },
                Token::Plus | Token::Minus | Token::Star | Token::Slash | Token::Percent => {
                    list.push(Expression::Operator(lexeme));
                },
                _ => {
                    list.push(Expression::String(lexeme));
                }
            }
        }

        let error_offset = match list.pop() {
            Some(Expression::String(lexeme)) => lexeme.offset.unwrap_or(0),
            Some(Expression::Operator(lexeme)) => lexeme.offset.unwrap_or(0),
            Some(Expression::Number(nv)) => nv.offset().unwrap_or(0),
            Some(Expression::List(_)) => unreachable!(), // for now until nested lists
            None => 0,
        };
        Err(SassError {
            offset: error_offset,
            kind: ErrorKind::UnexpectedEof,
            message: String::from(
                "Expected semicolon while parsing a value expression; reached EOF instead."
            ),
        })
    }

    pub fn evaluate(self, context: &Context) -> Expression {
        match self {
            Expression::Number(nv) => Expression::Number(nv),
            Expression::Operator(op) => Expression::Operator(op),
            Expression::String(lex) => {
                context.get_variable(&lex).unwrap_or(Expression::String(lex))
            },
            Expression::List(exprs) => {
                let mut last_was_an_operator = true;
                // TODO: I'd love to have more types here, to ensure only values are
                // on the value stack and only operators are on the operator stack...
                let mut value_stack: Vec<Expression> = Vec::new();
                let mut op_stack: Vec<Expression> = Vec::new();

                // Split into value stacks and operator stacks

                let mut exprs = exprs.into_iter();
                while let Some(part) = exprs.next() {
                    match part {
                        Expression::Number(nv) => {
                            if last_was_an_operator {
                                value_stack.push(Expression::Number(nv));
                            } else {
                                let list = create_list(
                                    value_stack.pop(),
                                    Expression::Number(nv),
                                );
                                value_stack.push(list);
                            }
                            last_was_an_operator = false;
                        },
                        Expression::Operator(op) => {
                            op_stack.push(Expression::Operator(op));
                            last_was_an_operator = true;
                        },
                        Expression::String(lex) => {
                            let var_eval = context.get_variable(&lex)
                                            .unwrap_or(Expression::String(lex));

                            if last_was_an_operator {
                                value_stack.push(var_eval);
                            } else {
                                let list = create_list(
                                    value_stack.pop(),
                                    var_eval,
                                );
                                value_stack.push(list);
                            }
                            last_was_an_operator = false;
                        },
                        Expression::List(list) => {
                            value_stack.push(Expression::List(list));
                            last_was_an_operator = false;
                        },
                    }
                }

                // Process the stacks
                while !op_stack.is_empty() {
                    let op = op_stack.pop();
                    let second = value_stack.pop();
                    let first = value_stack.pop();
                    value_stack.push(apply_math(first, op, second));
                }

                value_stack.pop().unwrap()
            },
        }
    }
}

fn apply_math(first: Option<Expression>, operator: Option<Expression>, second: Option<Expression>) -> Expression {
    let first = first.unwrap();
    let operator = operator.unwrap();
    let second = second.unwrap();

    match (first.clone(), second) {
        (Expression::Number(f), Expression::Number(s)) => {
            match operator {
                Expression::Operator(o) => {
                    let result = f.apply_math(&o, &s);
                    Expression::Number(result)
                },
                _ => unreachable!(),
            }
        },
        _ => first,
    }
}

fn create_list(head: Option<Expression>, tail: Expression) -> Expression {
    let mut list = match head {
        Some(Expression::List(v)) => v,
        Some(e) => vec![e],
        None => vec![],
    };
    list.push(tail);
    Expression::List(list)
}

#[cfg(test)]
mod tests {
    use super::*;
    use token::{Lexeme, Token};
    use ast::number_value::NumberValue;
    use context::Context;

    fn semicolon() -> Lexeme {
        Lexeme { token: Token::Semicolon, offset: None }
    }

    fn blue() -> Lexeme {
        Lexeme { token: Token::String("blue".into()), offset: None }
    }

    fn plus() -> Lexeme {
        Lexeme { token: Token::Plus, offset: None }
    }

    fn slash() -> Lexeme {
        Lexeme { token: Token::Slash, offset: None }
    }

    fn one() -> Lexeme {
        Lexeme { token: Token::Number(1.0, None), offset: None }
    }

    fn two() -> Lexeme {
        Lexeme { token: Token::Number(2.0, None), offset: None }
    }

    fn one_px() -> Lexeme {
        Lexeme { token: Token::Number(1.0, Some("px".into())), offset: None }
    }

    #[test]
    fn it_parses_a_single_string() {
        let mut fake_tokenizer = vec![Ok(blue()), Ok(semicolon())].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::String(blue()))
        );
    }

    #[test]
    fn it_parses_a_list() {
        let mut fake_tokenizer = vec![
            Ok(one()),
            Ok(plus()),
            Ok(one()),
            Ok(semicolon())
        ].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::List(vec![
                Expression::Number(NumberValue::from_scalar(one())),
                Expression::Operator(plus()),
                Expression::Number(NumberValue::from_scalar(one())),
            ]))
        );
    }

    #[test]
    fn it_parses_a_number_without_units() {
        let mut fake_tokenizer = vec![Ok(one()), Ok(semicolon())].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::Number(NumberValue::from_scalar(one())))
        );
    }

    #[test]
    fn it_parses_a_number_with_units() {
        let mut fake_tokenizer = vec![Ok(one_px()), Ok(semicolon())].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::Number(NumberValue::from_scalar(one_px())))
        );
    }

    #[test]
    fn it_evaluates_a_list() {
        let ex = Expression::List(vec![
            Expression::Number(NumberValue::from_scalar(one())),
            Expression::Operator(slash()),
            Expression::Number(NumberValue::from_scalar(two())),
            Expression::Operator(plus()),
            Expression::Number(NumberValue::from_scalar(one())),
            Expression::Operator(slash()),
            Expression::Number(NumberValue::from_scalar(two())),
        ]);
        let fake_context = Context::new();
        assert_eq!(
            ex.evaluate(&fake_context),
            Expression::Number(NumberValue { scalar: one(), computed: true })
        );
    }
}
<commit_msg>Extract a private evaluate list function<commit_after>use sass::output_style::SassOutputStyle;
use token::{Lexeme, Token};
use ast::number_value::NumberValue;
use context::Context;
use error::{Result, SassError, ErrorKind};

#[derive(Debug, Clone, PartialEq)]
pub enum Expression {
    List(Vec<Expression>),
    Number(NumberValue),
    Operator(Lexeme),
    String(Lexeme),
}

impl Expression {
    #[allow(unused_variables)]
    pub fn to_string(&self, style: SassOutputStyle) -> String {
        match *self {
            Expression::List(ref elements) => {
                elements.iter().map(|e|
                    e.to_string(style)
                ).collect::<Vec<_>>().join(" ")
            },
            Expression::Number(ref nv) => nv.to_string(),
            Expression::Operator(ref lex) => lex.token.to_string(),
            Expression::String(ref lex) => lex.token.to_string(),
        }
    }

    pub fn parse<T: Iterator<Item = Result<Lexeme>>>(tokenizer: &mut T) -> Result<Expression> {
        let mut list = vec![];
        while let Some(Ok(lexeme)) = tokenizer.next() {
            match lexeme.token {
                Token::Semicolon => {
                    if list.len() == 1 {
                        return Ok(list.pop().unwrap())
                    } else {
                        return Ok(Expression::List(list))
                    }
                },
                Token::Number(_, _) => {
                    list.push(Expression::Number(NumberValue::from_scalar(lexeme)));
                },
                Token::Plus | Token::Minus | Token::Star | Token::Slash | Token::Percent => {
                    list.push(Expression::Operator(lexeme));
                },
                _ => {
                    list.push(Expression::String(lexeme));
                }
            }
        }

        let error_offset = match list.pop() {
            Some(Expression::String(lexeme)) => lexeme.offset.unwrap_or(0),
            Some(Expression::Operator(lexeme)) => lexeme.offset.unwrap_or(0),
            Some(Expression::Number(nv)) => nv.offset().unwrap_or(0),
            Some(Expression::List(_)) => unreachable!(), // for now until nested lists
            None => 0,
        };
        Err(SassError {
            offset: error_offset,
            kind: ErrorKind::UnexpectedEof,
            message: String::from(
                "Expected semicolon while parsing a value expression; reached EOF instead."
            ),
        })
    }

    fn evaluate_list(self, context: &Context, _: bool) -> Expression {
        if let Expression::List(exprs) = self {
            let mut last_was_an_operator = true;
            // TODO: I'd love to have more types here, to ensure only values are
            // on the value stack and only operators are on the operator stack...
            let mut value_stack: Vec<Expression> = Vec::new();
            let mut op_stack: Vec<Expression> = Vec::new();

            // Split into value stacks and operator stacks

            let mut exprs = exprs.into_iter();
            while let Some(part) = exprs.next() {
                match part {
                    Expression::Number(nv) => {
                        if last_was_an_operator {
                            value_stack.push(Expression::Number(nv));
                        } else {
                            let list = create_list(
                                value_stack.pop(),
                                Expression::Number(nv),
                            );
                            value_stack.push(list);
                        }
                        last_was_an_operator = false;
                    },
                    Expression::Operator(op) => {
                        op_stack.push(Expression::Operator(op));
                        last_was_an_operator = true;
                    },
                    Expression::String(lex) => {
                        let var_eval = context.get_variable(&lex)
                                        .unwrap_or(Expression::String(lex));

                        if last_was_an_operator {
                            value_stack.push(var_eval);
                        } else {
                            let list = create_list(
                                value_stack.pop(),
                                var_eval,
                            );
                            value_stack.push(list);
                        }
                        last_was_an_operator = false;
                    },
                    Expression::List(list) => {
                        value_stack.push(Expression::List(list));
                        last_was_an_operator = false;
                    },
                }
            }

            // Process the stacks
            while !op_stack.is_empty() {
                let op = op_stack.pop();
                let second = value_stack.pop();
                let first = value_stack.pop();

                debug!("Processing: \nfirst = {:#?}\nop = {:#?}\nsecond = {:#?}", first, op, second);

                value_stack.push(apply_math(first, op, second));
            }

            value_stack.pop().unwrap()
        } else {
            self
        }
    }

    pub fn evaluate(self, context: &Context) -> Expression {
        match self {
            Expression::Number(nv) => Expression::Number(nv),
            Expression::Operator(op) => Expression::Operator(op),
            Expression::String(lex) => {
                context.get_variable(&lex).unwrap_or(Expression::String(lex))
            },
            Expression::List(exprs) => {
                Expression::List(exprs).evaluate_list(context, false)
            },
        }
    }
}

fn apply_math(first: Option<Expression>, operator: Option<Expression>, second: Option<Expression>) -> Expression {
    let first = first.unwrap();
    let operator = operator.unwrap();
    let second = second.unwrap();

    match (first.clone(), second) {
        (Expression::Number(f), Expression::Number(s)) => {
            match operator {
                Expression::Operator(o) => {
                    let result = f.apply_math(&o, &s);
                    Expression::Number(result)
                },
                _ => unreachable!(),
            }
        },
        _ => first,
    }
}

fn create_list(head: Option<Expression>, tail: Expression) -> Expression {
    let mut list = match head {
        Some(Expression::List(v)) => v,
        Some(e) => vec![e],
        None => vec![],
    };
    list.push(tail);
    Expression::List(list)
}

#[cfg(test)]
mod tests {
    use super::*;
    use token::{Lexeme, Token};
    use ast::number_value::NumberValue;
    use context::Context;

    fn semicolon() -> Lexeme {
        Lexeme { token: Token::Semicolon, offset: None }
    }

    fn blue() -> Lexeme {
        Lexeme { token: Token::String("blue".into()), offset: None }
    }

    fn plus() -> Lexeme {
        Lexeme { token: Token::Plus, offset: None }
    }

    fn slash() -> Lexeme {
        Lexeme { token: Token::Slash, offset: None }
    }

    fn one() -> Lexeme {
        Lexeme { token: Token::Number(1.0, None), offset: None }
    }

    fn two() -> Lexeme {
        Lexeme { token: Token::Number(2.0, None), offset: None }
    }

    fn one_px() -> Lexeme {
        Lexeme { token: Token::Number(1.0, Some("px".into())), offset: None }
    }

    #[test]
    fn it_parses_a_single_string() {
        let mut fake_tokenizer = vec![Ok(blue()), Ok(semicolon())].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::String(blue()))
        );
    }

    #[test]
    fn it_parses_a_list() {
        let mut fake_tokenizer = vec![
            Ok(one()),
            Ok(plus()),
            Ok(one()),
            Ok(semicolon())
        ].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::List(vec![
                Expression::Number(NumberValue::from_scalar(one())),
                Expression::Operator(plus()),
                Expression::Number(NumberValue::from_scalar(one())),
            ]))
        );
    }

    #[test]
    fn it_parses_a_number_without_units() {
        let mut fake_tokenizer = vec![Ok(one()), Ok(semicolon())].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::Number(NumberValue::from_scalar(one())))
        );
    }

    #[test]
    fn it_parses_a_number_with_units() {
        let mut fake_tokenizer = vec![Ok(one_px()), Ok(semicolon())].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::Number(NumberValue::from_scalar(one_px())))
        );
    }

    #[test]
    fn it_evaluates_a_list() {
        let ex = Expression::List(vec![
            Expression::Number(NumberValue::from_scalar(one())),
            Expression::Operator(slash()),
            Expression::Number(NumberValue::from_scalar(two())),
            Expression::Operator(plus()),
            Expression::Number(NumberValue::from_scalar(one())),
            Expression::Operator(slash()),
            Expression::Number(NumberValue::from_scalar(two())),
        ]);
        let fake_context = Context::new();
        assert_eq!(
            ex.evaluate(&fake_context),
            Expression::Number(NumberValue { scalar: one(), computed: true })
        );
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::BufReader;
use std::io::prelude::*;

fn main() {
  let split_char = ',';
  let stdin = io::stdin();
  let mut reader = BufReader::new(stdin);

  let mut line = String::new();
  let _unused_size = reader.read_line(&mut line);

  let headers : Vec<&str> = line.trim().split(split_char).collect();

  let mut first = true;

  for line in reader.lines() {
    if first {
      print!("[");
      first = false;
    } else {
      println!(",");
    }

    // Opening brace (escaped).
    print!("{{");

    let line_str = line.unwrap();

    let mut first = true;
    let components : Vec<&str> = line_str.split(split_char).collect();
    for (header, component) in headers.iter().zip(components.iter()) {
      if !first {
        print!(",");
      } else {
        first = false;
      }
      print!("\"{}\": \"{}\"", header, component);
    }

    // Closing brace (escaped).
    print!("}}");
  }
  println!("]");
}
<commit_msg>Add a usage message<commit_after>use std::io;
use std::io::BufReader;
use std::io::prelude::*;
use std::env;
use std::process::exit;

fn usage() {
  println!("Usage: cat input.csv | csv_to_json");
}

fn main() {
  let args : Vec<String> = env::args().collect();

  if args.len() > 1 {
    usage();
    exit(1);
  }

  let mut reader = BufReader::new(io::stdin());
  let split_char = ',';

  let mut line = String::new();
  let _unused_size = reader.read_line(&mut line);

  let headers : Vec<&str> = line.trim().split(split_char).collect();

  let mut first = true;

  for line in reader.lines() {
    if first {
      print!("[");
      first = false;
    } else {
      println!(",");
    }

    // Opening brace (escaped).
    print!("{{");

    let line_str = line.unwrap();

    let mut first = true;
    let components : Vec<&str> = line_str.split(split_char).collect();
    for (header, component) in headers.iter().zip(components.iter()) {
      if !first {
        print!(",");
      } else {
        first = false;
      }
      print!("\"{}\": \"{}\"", header, component);
    }

    // Closing brace (escaped).
    print!("}}");
  }
  println!("]");
}
<|endoftext|>