<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.

#![allow(dead_code)]

use core::prelude::*;

use cmp;
use ffi::CString;
use io;
use libc::consts::os::posix01::PTHREAD_STACK_MIN;
use libc;
use mem;
use ptr;
use sys::os;
use thunk::Thunk;
use time::Duration;

use sys_common::stack::RED_ZONE;
use sys_common::thread::*;

pub type rust_thread = libc::pthread_t;

#[cfg(all(not(target_os = "linux"),
          not(target_os = "macos"),
          not(target_os = "bitrig"),
          not(target_os = "openbsd")))]
pub mod guard {
    pub unsafe fn current() -> usize { 0 }
    pub unsafe fn main() -> usize { 0 }
    pub unsafe fn init() {}
}

#[cfg(any(target_os = "linux",
          target_os = "macos",
          target_os = "bitrig",
          target_os = "openbsd"))]
#[allow(unused_imports)]
pub mod guard {
    use libc::{self, pthread_t};
    use libc::funcs::posix88::mman::mmap;
    use libc::consts::os::posix88::{PROT_NONE,
                                    MAP_PRIVATE,
                                    MAP_ANON,
                                    MAP_FAILED,
                                    MAP_FIXED};
    use mem;
    use ptr;
    use super::{pthread_self, pthread_attr_destroy};
    use sys::os;

    // These are initialized in init() and only read from after
    static mut GUARD_PAGE: usize = 0;

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

    #[cfg(any(target_os = "linux", target_os = "android"))]
    unsafe fn get_stack_start() -> *mut libc::c_void {
        let mut attr: libc::pthread_attr_t = mem::zeroed();
        assert_eq!(pthread_getattr_np(pthread_self(), &mut attr), 0);
        let mut stackaddr = ptr::null_mut();
        let mut stacksize = 0;
        assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 0);
        assert_eq!(pthread_attr_destroy(&mut attr), 0);
        stackaddr
    }

    pub unsafe fn init() {
        let psize = os::page_size();
        let mut stackaddr = get_stack_start();

        // 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!(target_os = "linux") {2} else {1};

        GUARD_PAGE = stackaddr as usize + offset * psize;
    }

    pub unsafe fn main() -> usize {
        GUARD_PAGE
    }

    #[cfg(target_os = "macos")]
    pub unsafe fn current() -> usize {
        extern {
            fn pthread_get_stackaddr_np(thread: pthread_t) -> *mut libc::c_void;
            fn pthread_get_stacksize_np(thread: pthread_t) -> libc::size_t;
        }
        (pthread_get_stackaddr_np(pthread_self()) as libc::size_t -
         pthread_get_stacksize_np(pthread_self())) as usize
    }

    #[cfg(any(target_os = "openbsd", target_os = "bitrig"))]
    pub unsafe fn current() -> usize {
        #[repr(C)]
        struct stack_t {
            ss_sp: *mut libc::c_void,
            ss_size: libc::size_t,
            ss_flags: libc::c_int,
        }
        extern {
            fn pthread_main_np() -> libc::c_uint;
            fn pthread_stackseg_np(thread: pthread_t,
                                   sinfo: *mut stack_t) -> libc::c_uint;
        }

        let mut current_stack: stack_t = mem::zeroed();
        assert_eq!(pthread_stackseg_np(pthread_self(), &mut current_stack), 0);

        let extra = if cfg!(target_os = "bitrig") {3} else {1} * os::page_size();
        if 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 = "linux", target_os = "android"))]
    pub unsafe fn current() -> usize {
        let mut attr: libc::pthread_attr_t = mem::zeroed();
        assert_eq!(pthread_getattr_np(pthread_self(), &mut attr), 0);
        let mut guardsize = 0;
        assert_eq!(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!(pthread_attr_getstack(&attr, &mut stackaddr, &mut size), 0);
        assert_eq!(pthread_attr_destroy(&mut attr), 0);

        stackaddr as usize + guardsize as usize
    }

    #[cfg(any(target_os = "linux", target_os = "android"))]
    extern {
        fn pthread_getattr_np(native: libc::pthread_t,
                              attr: *mut libc::pthread_attr_t) -> libc::c_int;
        fn pthread_attr_getguardsize(attr: *const libc::pthread_attr_t,
                                     guardsize: *mut libc::size_t) -> libc::c_int;
        fn pthread_attr_getstack(attr: *const libc::pthread_attr_t,
                                 stackaddr: *mut *mut libc::c_void,
                                 stacksize: *mut libc::size_t) -> libc::c_int;
    }
}

pub unsafe fn create(stack: usize, p: Thunk) -> io::Result<rust_thread> {
    let p = box p;
    let mut native: libc::pthread_t = mem::zeroed();
    let mut attr: libc::pthread_attr_t = mem::zeroed();
    assert_eq!(pthread_attr_init(&mut attr), 0);

    // Reserve room for the red zone, the runtime's stack of last resort.
    let stack_size = cmp::max(stack, RED_ZONE + min_stack_size(&attr) as usize);
    match 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);
            assert_eq!(pthread_attr_setstacksize(&mut attr,
                                                 stack_size as libc::size_t), 0);
        }
    };

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

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

    #[no_stack_check]
    extern fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
        start_thread(main);
        0 as *mut _
    }
}

#[cfg(any(target_os = "linux", target_os = "android"))]
pub unsafe fn set_name(name: &str) {
    // pthread_setname_np() since glibc 2.12
    // availability autodetected via weak linkage
    type F = unsafe extern fn(libc::pthread_t, *const libc::c_char)
                              -> libc::c_int;
    extern {
        #[linkage = "extern_weak"]
        static pthread_setname_np: *const ();
    }
    if !pthread_setname_np.is_null() {
        let cname = CString::new(name).unwrap();
        mem::transmute::<*const (), F>(pthread_setname_np)(pthread_self(),
                                                           cname.as_ptr());
    }
}

#[cfg(any(target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "bitrig",
          target_os = "openbsd"))]
pub unsafe fn set_name(name: &str) {
    extern {
        fn pthread_set_name_np(tid: libc::pthread_t, name: *const libc::c_char);
    }
    let cname = CString::new(name).unwrap();
    pthread_set_name_np(pthread_self(), cname.as_ptr());
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
pub unsafe fn set_name(name: &str) {
    extern {
        fn pthread_setname_np(name: *const libc::c_char) -> libc::c_int;
    }
    let cname = CString::new(name).unwrap();
    pthread_setname_np(cname.as_ptr());
}

pub unsafe fn join(native: rust_thread) {
    assert_eq!(pthread_join(native, ptr::null_mut()), 0);
}

pub unsafe fn detach(native: rust_thread) {
    assert_eq!(pthread_detach(native), 0);
}

pub unsafe fn yield_now() {
    assert_eq!(sched_yield(), 0);
}

pub fn sleep(dur: Duration) {
    unsafe {
        if dur < Duration::zero() {
            return yield_now()
        }
        let seconds = dur.num_seconds();
        let ns = dur - Duration::seconds(seconds);
        let mut ts = libc::timespec {
            tv_sec: seconds as libc::time_t,
            tv_nsec: ns.num_nanoseconds().unwrap() 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.
        while dosleep(&mut ts) == -1 {
            assert_eq!(os::errno(), libc::EINTR);
        }
    }

    #[cfg(target_os = "linux")]
    unsafe fn dosleep(ts: *mut libc::timespec) -> libc::c_int {
        extern {
            fn clock_nanosleep(clock_id: libc::c_int, flags: libc::c_int,
                               request: *const libc::timespec,
                               remain: *mut libc::timespec) -> libc::c_int;
        }
        clock_nanosleep(libc::CLOCK_MONOTONIC, 0, ts, ts)
    }
    #[cfg(not(target_os = "linux"))]
    unsafe fn dosleep(ts: *mut libc::timespec) -> libc::c_int {
        libc::nanosleep(ts, ts)
    }
}

// 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.
//
// Link weakly to the symbol for compatibility with older versions of glibc.
// Assumes that we've been dynamically linked to libpthread but that is
// currently always the case.  Note that you need to check that the symbol
// is non-null before calling it!
#[cfg(target_os = "linux")]
fn min_stack_size(attr: *const libc::pthread_attr_t) -> libc::size_t {
    type F = unsafe extern "C" fn(*const libc::pthread_attr_t) -> libc::size_t;
    extern {
        #[linkage = "extern_weak"]
        static __pthread_get_minstack: *const ();
    }
    if __pthread_get_minstack.is_null() {
        PTHREAD_STACK_MIN
    } else {
        unsafe { mem::transmute::<*const (), F>(__pthread_get_minstack)(attr) }
    }
}

// __pthread_get_minstack() is marked as weak but extern_weak linkage is
// not supported on OS X, hence this kludge...
#[cfg(not(target_os = "linux"))]
fn min_stack_size(_: *const libc::pthread_attr_t) -> libc::size_t {
    PTHREAD_STACK_MIN
}

extern {
    fn pthread_self() -> libc::pthread_t;
    fn pthread_create(native: *mut libc::pthread_t,
                      attr: *const libc::pthread_attr_t,
                      f: extern fn(*mut libc::c_void) -> *mut libc::c_void,
                      value: *mut libc::c_void) -> libc::c_int;
    fn pthread_join(native: libc::pthread_t,
                    value: *mut *mut libc::c_void) -> libc::c_int;
    fn pthread_attr_init(attr: *mut libc::pthread_attr_t) -> libc::c_int;
    fn pthread_attr_destroy(attr: *mut libc::pthread_attr_t) -> libc::c_int;
    fn pthread_attr_setstacksize(attr: *mut libc::pthread_attr_t,
                                 stack_size: libc::size_t) -> libc::c_int;
    fn pthread_attr_setdetachstate(attr: *mut libc::pthread_attr_t,
                                   state: libc::c_int) -> libc::c_int;
    fn pthread_detach(thread: libc::pthread_t) -> libc::c_int;
    fn sched_yield() -> libc::c_int;
}
<commit_msg>Get __pthread_get_minstack at runtime with dlsym<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.

#![allow(dead_code)]

use core::prelude::*;

use cmp;
use dynamic_lib::DynamicLibrary;
use ffi::CString;
use io;
use libc::consts::os::posix01::PTHREAD_STACK_MIN;
use libc;
use mem;
use ptr;
use sync::{Once, ONCE_INIT};
use sys::os;
use thunk::Thunk;
use time::Duration;

use sys_common::stack::RED_ZONE;
use sys_common::thread::*;

pub type rust_thread = libc::pthread_t;

#[cfg(all(not(target_os = "linux"),
          not(target_os = "macos"),
          not(target_os = "bitrig"),
          not(target_os = "openbsd")))]
pub mod guard {
    pub unsafe fn current() -> usize { 0 }
    pub unsafe fn main() -> usize { 0 }
    pub unsafe fn init() {}
}

#[cfg(any(target_os = "linux",
          target_os = "macos",
          target_os = "bitrig",
          target_os = "openbsd"))]
#[allow(unused_imports)]
pub mod guard {
    use libc::{self, pthread_t};
    use libc::funcs::posix88::mman::mmap;
    use libc::consts::os::posix88::{PROT_NONE,
                                    MAP_PRIVATE,
                                    MAP_ANON,
                                    MAP_FAILED,
                                    MAP_FIXED};
    use mem;
    use ptr;
    use super::{pthread_self, pthread_attr_destroy};
    use sys::os;

    // These are initialized in init() and only read from after
    static mut GUARD_PAGE: usize = 0;

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

    #[cfg(any(target_os = "linux", target_os = "android"))]
    unsafe fn get_stack_start() -> *mut libc::c_void {
        let mut attr: libc::pthread_attr_t = mem::zeroed();
        assert_eq!(pthread_getattr_np(pthread_self(), &mut attr), 0);
        let mut stackaddr = ptr::null_mut();
        let mut stacksize = 0;
        assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 0);
        assert_eq!(pthread_attr_destroy(&mut attr), 0);
        stackaddr
    }

    pub unsafe fn init() {
        let psize = os::page_size();
        let mut stackaddr = get_stack_start();

        // 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!(target_os = "linux") {2} else {1};

        GUARD_PAGE = stackaddr as usize + offset * psize;
    }

    pub unsafe fn main() -> usize {
        GUARD_PAGE
    }

    #[cfg(target_os = "macos")]
    pub unsafe fn current() -> usize {
        extern {
            fn pthread_get_stackaddr_np(thread: pthread_t) -> *mut libc::c_void;
            fn pthread_get_stacksize_np(thread: pthread_t) -> libc::size_t;
        }
        (pthread_get_stackaddr_np(pthread_self()) as libc::size_t -
         pthread_get_stacksize_np(pthread_self())) as usize
    }

    #[cfg(any(target_os = "openbsd", target_os = "bitrig"))]
    pub unsafe fn current() -> usize {
        #[repr(C)]
        struct stack_t {
            ss_sp: *mut libc::c_void,
            ss_size: libc::size_t,
            ss_flags: libc::c_int,
        }
        extern {
            fn pthread_main_np() -> libc::c_uint;
            fn pthread_stackseg_np(thread: pthread_t,
                                   sinfo: *mut stack_t) -> libc::c_uint;
        }

        let mut current_stack: stack_t = mem::zeroed();
        assert_eq!(pthread_stackseg_np(pthread_self(), &mut current_stack), 0);

        let extra = if cfg!(target_os = "bitrig") {3} else {1} * os::page_size();
        if 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 = "linux", target_os = "android"))]
    pub unsafe fn current() -> usize {
        let mut attr: libc::pthread_attr_t = mem::zeroed();
        assert_eq!(pthread_getattr_np(pthread_self(), &mut attr), 0);
        let mut guardsize = 0;
        assert_eq!(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!(pthread_attr_getstack(&attr, &mut stackaddr, &mut size), 0);
        assert_eq!(pthread_attr_destroy(&mut attr), 0);

        stackaddr as usize + guardsize as usize
    }

    #[cfg(any(target_os = "linux", target_os = "android"))]
    extern {
        fn pthread_getattr_np(native: libc::pthread_t,
                              attr: *mut libc::pthread_attr_t) -> libc::c_int;
        fn pthread_attr_getguardsize(attr: *const libc::pthread_attr_t,
                                     guardsize: *mut libc::size_t) -> libc::c_int;
        fn pthread_attr_getstack(attr: *const libc::pthread_attr_t,
                                 stackaddr: *mut *mut libc::c_void,
                                 stacksize: *mut libc::size_t) -> libc::c_int;
    }
}

pub unsafe fn create(stack: usize, p: Thunk) -> io::Result<rust_thread> {
    let p = box p;
    let mut native: libc::pthread_t = mem::zeroed();
    let mut attr: libc::pthread_attr_t = mem::zeroed();
    assert_eq!(pthread_attr_init(&mut attr), 0);

    // Reserve room for the red zone, the runtime's stack of last resort.
    let stack_size = cmp::max(stack, RED_ZONE + min_stack_size(&attr) as usize);
    match 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);
            assert_eq!(pthread_attr_setstacksize(&mut attr,
                                                 stack_size as libc::size_t), 0);
        }
    };

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

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

    #[no_stack_check]
    extern fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
        start_thread(main);
        0 as *mut _
    }
}

#[cfg(any(target_os = "linux", target_os = "android"))]
pub unsafe fn set_name(name: &str) {
    // pthread_setname_np() since glibc 2.12
    // availability autodetected via weak linkage
    type F = unsafe extern fn(libc::pthread_t, *const libc::c_char)
                              -> libc::c_int;
    extern {
        #[linkage = "extern_weak"]
        static pthread_setname_np: *const ();
    }
    if !pthread_setname_np.is_null() {
        let cname = CString::new(name).unwrap();
        mem::transmute::<*const (), F>(pthread_setname_np)(pthread_self(),
                                                           cname.as_ptr());
    }
}

#[cfg(any(target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "bitrig",
          target_os = "openbsd"))]
pub unsafe fn set_name(name: &str) {
    extern {
        fn pthread_set_name_np(tid: libc::pthread_t, name: *const libc::c_char);
    }
    let cname = CString::new(name).unwrap();
    pthread_set_name_np(pthread_self(), cname.as_ptr());
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
pub unsafe fn set_name(name: &str) {
    extern {
        fn pthread_setname_np(name: *const libc::c_char) -> libc::c_int;
    }
    let cname = CString::new(name).unwrap();
    pthread_setname_np(cname.as_ptr());
}

pub unsafe fn join(native: rust_thread) {
    assert_eq!(pthread_join(native, ptr::null_mut()), 0);
}

pub unsafe fn detach(native: rust_thread) {
    assert_eq!(pthread_detach(native), 0);
}

pub unsafe fn yield_now() {
    assert_eq!(sched_yield(), 0);
}

pub fn sleep(dur: Duration) {
    unsafe {
        if dur < Duration::zero() {
            return yield_now()
        }
        let seconds = dur.num_seconds();
        let ns = dur - Duration::seconds(seconds);
        let mut ts = libc::timespec {
            tv_sec: seconds as libc::time_t,
            tv_nsec: ns.num_nanoseconds().unwrap() 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.
        while dosleep(&mut ts) == -1 {
            assert_eq!(os::errno(), libc::EINTR);
        }
    }

    #[cfg(target_os = "linux")]
    unsafe fn dosleep(ts: *mut libc::timespec) -> libc::c_int {
        extern {
            fn clock_nanosleep(clock_id: libc::c_int, flags: libc::c_int,
                               request: *const libc::timespec,
                               remain: *mut libc::timespec) -> libc::c_int;
        }
        clock_nanosleep(libc::CLOCK_MONOTONIC, 0, ts, ts)
    }
    #[cfg(not(target_os = "linux"))]
    unsafe fn dosleep(ts: *mut libc::timespec) -> libc::c_int {
        libc::nanosleep(ts, ts)
    }
}

// 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.
//
// Use dlsym to get the symbol value at runtime, for compatibility
// with older versions of glibc.  Assumes that we've been dynamically
// linked to libpthread but that is currently always the case.  We
// previously used weak linkage (under the same assumption), but that
// caused Debian to detect an unnecessarily strict versioned
// dependency on libc6 (#23628).
#[cfg(target_os = "linux")]
fn min_stack_size(attr: *const libc::pthread_attr_t) -> libc::size_t {
    type F = unsafe extern "C" fn(*const libc::pthread_attr_t) -> libc::size_t;
    static INIT: Once = ONCE_INIT;
    static mut __pthread_get_minstack: Option<F> = None;

    INIT.call_once(|| {
        let lib = DynamicLibrary::open(None).unwrap();
        unsafe {
            if let Ok(f) = lib.symbol("__pthread_get_minstack") {
                __pthread_get_minstack = Some(mem::transmute::<*const (), F>(f));
            }
        }
    });

    match unsafe { __pthread_get_minstack } {
        None => PTHREAD_STACK_MIN,
        Some(f) => unsafe { f(attr) },
    }
}

// __pthread_get_minstack() is marked as weak but extern_weak linkage is
// not supported on OS X, hence this kludge...
#[cfg(not(target_os = "linux"))]
fn min_stack_size(_: *const libc::pthread_attr_t) -> libc::size_t {
    PTHREAD_STACK_MIN
}

extern {
    fn pthread_self() -> libc::pthread_t;
    fn pthread_create(native: *mut libc::pthread_t,
                      attr: *const libc::pthread_attr_t,
                      f: extern fn(*mut libc::c_void) -> *mut libc::c_void,
                      value: *mut libc::c_void) -> libc::c_int;
    fn pthread_join(native: libc::pthread_t,
                    value: *mut *mut libc::c_void) -> libc::c_int;
    fn pthread_attr_init(attr: *mut libc::pthread_attr_t) -> libc::c_int;
    fn pthread_attr_destroy(attr: *mut libc::pthread_attr_t) -> libc::c_int;
    fn pthread_attr_setstacksize(attr: *mut libc::pthread_attr_t,
                                 stack_size: libc::size_t) -> libc::c_int;
    fn pthread_attr_setdetachstate(attr: *mut libc::pthread_attr_t,
                                   state: libc::c_int) -> libc::c_int;
    fn pthread_detach(thread: libc::pthread_t) -> libc::c_int;
    fn sched_yield() -> libc::c_int;
}
<|endoftext|>


<commit_before>// Copyright 2021 Google LLC
//
// 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
//
//     https://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 aarch64_esr_decoder::{decode, Decoded, FieldInfo};
use std::num::ParseIntError;
use std::ops::Deref;
use wasm_bindgen::prelude::*;
use web_sys::{Document, Element};

#[wasm_bindgen]
pub fn init() {
    #[cfg(feature = "console_error_panic_hook")]
    console_error_panic_hook::set_once();
}

#[wasm_bindgen]
pub fn decode_esr(esr: &str) -> String {
    if let Ok(esr) = parse_number(esr) {
        let decoded = decode(esr);
        if let Ok(decoded) = &decoded {
            show_decoded(esr, decoded);
        }
        format!("{:?}", decoded)
    } else {
        "Invalid ESR".to_string()
    }
}

fn make_cell(
    document: &Document,
    contents: Option<&str>,
    colspan: usize,
) -> Result<Element, JsValue> {
    let cell = document.create_element("td")?;
    cell.set_attribute("colspan", &colspan.to_string())?;
    cell.set_text_content(contents);
    Ok(cell)
}

fn show_decoded(esr: u64, decoded: &Decoded) -> Result<(), JsValue> {
    let document = web_sys::window()
        .expect("Couldn't find window")
        .document()
        .expect("Couldn't find document");
    let table = document
        .get_element_by_id("result_table")
        .expect("Couldn't find result table");
    // Remove existing contents.
    table.set_inner_html("");

    // First row has ESR in binary
    let row = document.create_element("tr")?;
    for i in (0..u64::BITS).rev() {
        let bit = esr & (1 << i) != 0;
        let cell = make_cell(&document, Some(if bit { "1" } else { "0" }), 1)?;
        row.append_child(&cell)?;
    }
    table.append_child(&row)?;

    // Top-level description
    let row = document.create_element("tr")?;
    let cell = make_cell(&document, decoded.description.as_deref(), 64)?;
    row.append_child(&cell)?;
    table.append_child(&row)?;

    // Top-level field names and values
    let row = document.create_element("tr")?;
    add_field_cells(&document, &row, &decoded.fields, |field| {
        Some(field.to_string())
    })?;
    table.append_child(&row)?;

    // Top-level field descriptions
    let row = document.create_element("tr")?;
    add_field_cells(&document, &row, &decoded.fields, |field| {
        field
            .decoded
            .as_ref()
            .and_then(|decoded| decoded.description.clone())
    })?;
    table.append_child(&row)?;

    Ok(())
}

fn add_field_cells<F, S>(
    document: &Document,
    row: &Element,
    fields: &[FieldInfo],
    get_contents: F,
) -> Result<(), JsValue>
where
    F: Fn(&FieldInfo) -> Option<S>,
    S: Deref<Target = str>,
{
    let mut last = 64;
    for field in fields {
        if field.start + field.width != last {
            // Add a filler
            let cell = make_cell(document, None, last - field.start - field.width)?;
            row.append_child(&cell)?;
        }
        let cell = make_cell(document, get_contents(field).as_deref(), field.width)?;
        row.append_child(&cell)?;
        last = field.start;
    }
    Ok(())
}

/// Parse a decimal or hexadecimal number.
fn parse_number(s: &str) -> Result<u64, ParseIntError> {
    if s.starts_with("0x") {
        u64::from_str_radix(&s[2..], 16)
    } else {
        s.parse()
    }
}
<commit_msg>Show second-level fields too.<commit_after>// Copyright 2021 Google LLC
//
// 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
//
//     https://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 aarch64_esr_decoder::{decode, Decoded, FieldInfo};
use std::num::ParseIntError;
use std::ops::Deref;
use wasm_bindgen::prelude::*;
use web_sys::{Document, Element};

#[wasm_bindgen]
pub fn init() {
    #[cfg(feature = "console_error_panic_hook")]
    console_error_panic_hook::set_once();
}

#[wasm_bindgen]
pub fn decode_esr(esr: &str) -> String {
    if let Ok(esr) = parse_number(esr) {
        let decoded = decode(esr);
        if let Ok(decoded) = &decoded {
            show_decoded(esr, decoded);
        }
        format!("{:?}", decoded)
    } else {
        "Invalid ESR".to_string()
    }
}

fn make_cell(
    document: &Document,
    contents: Option<&str>,
    colspan: usize,
) -> Result<Element, JsValue> {
    let cell = document.create_element("td")?;
    cell.set_attribute("colspan", &colspan.to_string())?;
    cell.set_text_content(contents);
    Ok(cell)
}

fn show_decoded(esr: u64, decoded: &Decoded) -> Result<(), JsValue> {
    let document = web_sys::window()
        .expect("Couldn't find window")
        .document()
        .expect("Couldn't find document");
    let table = document
        .get_element_by_id("result_table")
        .expect("Couldn't find result table");
    // Remove existing contents.
    table.set_inner_html("");

    // First row has ESR in binary
    let row = document.create_element("tr")?;
    for i in (0..u64::BITS).rev() {
        let bit = esr & (1 << i) != 0;
        let cell = make_cell(&document, Some(if bit { "1" } else { "0" }), 1)?;
        row.append_child(&cell)?;
    }
    table.append_child(&row)?;

    // Top-level description
    let row = document.create_element("tr")?;
    let cell = make_cell(&document, decoded.description.as_deref(), 64)?;
    row.append_child(&cell)?;
    table.append_child(&row)?;

    // Top-level field names and values
    let row = document.create_element("tr")?;
    let mut last = 64;
    add_field_cells(&document, &row, &decoded.fields, &mut last, |field| {
        Some(field.to_string())
    })?;
    table.append_child(&row)?;

    // Top-level field descriptions
    let row = document.create_element("tr")?;
    let mut last = 64;
    add_field_cells(&document, &row, &decoded.fields, &mut last, |field| {
        field
            .decoded
            .as_ref()
            .and_then(|decoded| decoded.description.clone())
    })?;
    table.append_child(&row)?;

    // Second level field names and values
    let row = document.create_element("tr")?;
    let mut last = 64;
    for field in &decoded.fields {
        if let Some(field_decoded) = &field.decoded {
            add_field_cells(&document, &row, &field_decoded.fields, &mut last, |field| {
                Some(field.to_string())
            })?;
        }
    }
    table.append_child(&row)?;

    // Second level field descriptions
    let row = document.create_element("tr")?;
    let mut last = 64;
    for field in &decoded.fields {
        if let Some(field_decoded) = &field.decoded {
            add_field_cells(&document, &row, &field_decoded.fields, &mut last, |field| {
                field
                    .decoded
                    .as_ref()
                    .and_then(|decoded| decoded.description.clone())
            })?;
        }
    }
    table.append_child(&row)?;

    Ok(())
}

fn add_field_cells<F, S>(
    document: &Document,
    row: &Element,
    fields: &[FieldInfo],
    last: &mut usize,
    get_contents: F,
) -> Result<(), JsValue>
where
    F: Fn(&FieldInfo) -> Option<S>,
    S: Deref<Target = str>,
{
    for field in fields {
        if field.start + field.width != *last {
            // Add a filler
            let cell = make_cell(document, None, *last - field.start - field.width)?;
            row.append_child(&cell)?;
        }
        let cell = make_cell(document, get_contents(field).as_deref(), field.width)?;
        row.append_child(&cell)?;
        *last = field.start;
    }
    Ok(())
}

/// Parse a decimal or hexadecimal number.
fn parse_number(s: &str) -> Result<u64, ParseIntError> {
    if s.starts_with("0x") {
        u64::from_str_radix(&s[2..], 16)
    } else {
        s.parse()
    }
}
<|endoftext|>


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

#![feature(plugin, rustc_private, box_syntax)]

extern crate rustc;
extern crate rustc_driver;
extern crate rustc_llvm;
extern crate rustc_trans;
#[macro_use] extern crate syntax;
extern crate getopts;

use rustc_driver::{CompilerCalls, Compilation};
use rustc_driver::driver::CompileController;
use rustc_trans::ModuleSource;
use rustc::session::Session;
use syntax::codemap::FileLoader;
use std::env;
use std::io;
use std::path::{PathBuf, Path};

struct JitLoader;

impl FileLoader for JitLoader {
    fn file_exists(&self, _: &Path) -> bool { true }
    fn abs_path(&self, _: &Path) -> Option<PathBuf> { None }
    fn read_file(&self, _: &Path) -> io::Result<String> {
        Ok(r#"
#[no_mangle]
pub fn test_add(a: i32, b: i32) -> i32 { a + b }
"#.to_string())
    }
}

#[derive(Copy, Clone)]
struct JitCalls;

impl<'a> CompilerCalls<'a> for JitCalls {
    fn build_controller(&mut self,
                        _: &Session,
                        _: &getopts::Matches)
                        -> CompileController<'a> {
        let mut cc = CompileController::basic();
        cc.after_llvm.stop = Compilation::Stop;
        cc.after_llvm.run_callback_on_error = true;
        cc.after_llvm.callback = Box::new(|state| {
            state.session.abort_if_errors();
            let trans = state.trans.unwrap();
            assert_eq!(trans.modules.len(), 1);
            let rs_llmod = match trans.modules[0].source {
                ModuleSource::Preexisting(_) => unimplemented!(),
                ModuleSource::Translated(llvm) => llvm.llmod,
            };
            unsafe { rustc_llvm::LLVMDumpModule(rs_llmod) };
        });
        cc
    }
}

fn main() {
    use rustc_driver;

    let mut path = match std::env::args().nth(2) {
        Some(path) => PathBuf::from(&path),
        None => panic!("missing rustc path")
    };

    // Remove two segments from rustc path to get sysroot.
    path.pop();
    path.pop();

    let mut args: Vec<String> =
        format!("_ _ --sysroot {} --crate-type dylib", path.to_str().unwrap())
        .split(' ').map(|s| s.to_string()).collect();
    args.push("--out-dir".to_string());
    args.push(env::var("TMPDIR").unwrap());

    let (result, _) = rustc_driver::run_compiler(
        &args, &mut JitCalls, Some(box JitLoader), None);
    if let Err(n) = result {
        panic!("Error {:?}", n);
    }
}
<commit_msg>async-llvm(29): Adapt run-make/llvm-phase test case to LLVM module not being available in memory.<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(plugin, rustc_private, box_syntax)]

extern crate rustc;
extern crate rustc_driver;
extern crate rustc_llvm;
extern crate rustc_trans;
#[macro_use] extern crate syntax;
extern crate getopts;

use rustc_driver::{CompilerCalls, Compilation};
use rustc_driver::driver::CompileController;
use rustc_trans::ModuleSource;
use rustc::session::Session;
use syntax::codemap::FileLoader;
use std::env;
use std::io;
use std::path::{PathBuf, Path};

struct JitLoader;

impl FileLoader for JitLoader {
    fn file_exists(&self, _: &Path) -> bool { true }
    fn abs_path(&self, _: &Path) -> Option<PathBuf> { None }
    fn read_file(&self, _: &Path) -> io::Result<String> {
        Ok(r#"
#[no_mangle]
pub fn test_add(a: i32, b: i32) -> i32 { a + b }
"#.to_string())
    }
}

#[derive(Copy, Clone)]
struct JitCalls;

impl<'a> CompilerCalls<'a> for JitCalls {
    fn build_controller(&mut self,
                        _: &Session,
                        _: &getopts::Matches)
                        -> CompileController<'a> {
        let mut cc = CompileController::basic();
        cc.after_llvm.stop = Compilation::Stop;
        cc.after_llvm.run_callback_on_error = true;
        cc.after_llvm.callback = Box::new(|state| {
            state.session.abort_if_errors();
            let trans = state.trans.unwrap();
            assert_eq!(trans.modules.len(), 1);
            println!("name of compiled module = {}", trans.modules[0].name);
        });
        cc
    }
}

fn main() {
    use rustc_driver;

    let mut path = match std::env::args().nth(2) {
        Some(path) => PathBuf::from(&path),
        None => panic!("missing rustc path")
    };

    // Remove two segments from rustc path to get sysroot.
    path.pop();
    path.pop();

    let mut args: Vec<String> =
        format!("_ _ --sysroot {} --crate-type dylib", path.to_str().unwrap())
        .split(' ').map(|s| s.to_string()).collect();
    args.push("--out-dir".to_string());
    args.push(env::var("TMPDIR").unwrap());

    let (result, _) = rustc_driver::run_compiler(
        &args, &mut JitCalls, Some(box JitLoader), None);
    if let Err(n) = result {
        panic!("Error {:?}", n);
    }
}
<|endoftext|>


<commit_before>use crate::{ReadOnly, ReadableKey, WriteableKey};
use elektra_sys;
use std::borrow::Cow;
use std::convert::TryInto;
use std::ffi::{CStr, CString};
use std::ptr::NonNull;

#[derive(Debug)]
pub struct StringKey<'a> {
    ptr: NonNull<elektra_sys::Key>,
    _marker: std::marker::PhantomData<&'a mut elektra_sys::Key>,
}

#[derive(Debug)]
pub struct BinaryKey<'a> {
    ptr: NonNull<elektra_sys::Key>,
    _marker: std::marker::PhantomData<&'a mut elektra_sys::Key>,
}

macro_rules! add_traits {
    ($($t:ty)*) => ($(
        impl PartialEq for $t {

            #[inline]
            fn eq(&self, other: &Self) -> bool {
                unsafe {
                    elektra_sys::keyCmp(
                        self.as_ref(),
                        other.as_ref(),
                    ) == 0
                }
            }
        }

        impl Eq for $t {}

        impl Ord for $t {
            fn cmp(&self, other: &Self) -> std::cmp::Ordering {
                let cmp = unsafe {
                    elektra_sys::keyCmp(
                        self.as_ref(),
                        other.as_ref(),
                    )
                };

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

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

        impl AsRef<elektra_sys::Key> for $t {
            fn as_ref(&self) -> &elektra_sys::Key {
                unsafe { self.ptr.as_ref() }
            }
        }
    )*)
}

add_traits!(StringKey<'_>);
add_traits!(BinaryKey<'_>);

impl<'a> Iterator for StringKey<'a> {
    type Item = ReadOnly<StringKey<'a>>;
    fn next(&mut self) -> Option<Self::Item> {
        let key_ptr = unsafe { elektra_sys::keyNextMeta(self.as_ptr()) };
        if key_ptr.is_null() {
            None
        } else {
            Some(ReadOnly::from_ptr(key_ptr as *mut elektra_sys::Key))
        }
    }
}

impl<'a> Iterator for BinaryKey<'a> {
    type Item = ReadOnly<StringKey<'a>>;
    fn next(&mut self) -> Option<Self::Item> {
        let key_ptr = unsafe { elektra_sys::keyNextMeta(self.as_ptr()) };
        if key_ptr.is_null() {
            None
        } else {
            Some(ReadOnly::from_ptr(key_ptr as *mut elektra_sys::Key))
        }
    }
}

impl<'a> Drop for BinaryKey<'a> {
    fn drop(&mut self) {
        unsafe { elektra_sys::keyDel(self.as_ptr()) };
    }
}

impl<'a> Drop for StringKey<'a> {
    fn drop(&mut self) {
        unsafe { elektra_sys::keyDel(self.as_ptr()) };
    }
}

impl<'a> StringKey<'a> {
    /// Sets the value of the key to the supplied string.
    ///
    /// # Panics
    /// Panics if the provided string contains interior nul bytes.
    fn set_string(&mut self, value: &str) {
        let cstr = CString::new(value).unwrap();
        unsafe { elektra_sys::keySetString(self.as_ptr(), cstr.as_ptr()) };
    }

    /// Returns the string value of the key or a Utf8Error if it cannot be converted.
    fn string(&self) -> Cow<'a, str> {
        let c_str = unsafe { CStr::from_ptr(elektra_sys::keyString(self.as_ref())) };
        c_str.to_string_lossy()
    }

    pub fn duplicate<'b>(&'a self) -> StringKey<'b> {
        let dup_ptr = unsafe { elektra_sys::keyDup(self.as_ref()) };
        StringKey::from_ptr(dup_ptr)
    }
}

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

    /// Returns the keys binary content
    /// Returns a TypeMismatch if the key is of type string
    fn get_binary(&self) -> Vec<u8> {
        let mut vec: Vec<u8> = Vec::with_capacity(self.value_size());

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

        if ret_val > 0 {
            unsafe { vec.set_len(ret_val.try_into().unwrap()) };
        }

        vec
    }

    pub fn duplicate<'b>(&'a self) -> BinaryKey<'b> {
        let dup_ptr = unsafe { elektra_sys::keyDup(self.as_ref()) };
        BinaryKey::from_ptr(dup_ptr)
    }
}

impl<'a> ReadableKey for StringKey<'a> {
    type GetValue = Cow<'a, str>;

    fn from_ptr(ptr: *mut elektra_sys::Key) -> StringKey<'a> {
        StringKey {
            ptr: NonNull::new(ptr).unwrap(),
            _marker: std::marker::PhantomData,
        }
    }

    fn value(&self) -> Self::GetValue {
        self.string()
    }
}

impl<'a> ReadableKey for BinaryKey<'a> {
    type GetValue = Vec<u8>;

    fn from_ptr(ptr: *mut elektra_sys::Key) -> BinaryKey<'a> {
        BinaryKey {
            ptr: NonNull::new(ptr).unwrap(),
            _marker: std::marker::PhantomData,
        }
    }

    fn value(&self) -> Self::GetValue {
        self.get_binary()
    }
}

impl<'a> WriteableKey for BinaryKey<'a> {
    type SetValue = &'a [u8];

    fn as_ptr(&mut self) -> *mut elektra_sys::Key {
        self.ptr.as_ptr()
    }

    fn set_value(&mut self, value: Self::SetValue) {
        self.set_binary(value);
    }
}
impl<'a> WriteableKey for StringKey<'a> {
    type SetValue = &'a str;

    fn as_ptr(&mut self) -> *mut elektra_sys::Key {
        self.ptr.as_ptr()
    }
    fn set_value(&mut self, value: Self::SetValue) {
        self.set_string(value);
    }
}

impl From<StringKey<'_>> for BinaryKey<'_> {
    fn from(mut sk: StringKey) -> Self {
        let binary_key = BinaryKey::from_ptr(sk.as_ptr());
        std::mem::forget(sk);
        binary_key
    }
}

impl From<BinaryKey<'_>> for StringKey<'_> {
    fn from(mut bk: BinaryKey) -> Self {
        let str_key = StringKey::from_ptr(bk.as_ptr());
        std::mem::forget(bk);
        str_key
    }
}

#[derive(Debug, PartialEq)]
pub enum KeyError {
    InvalidName,
    TypeMismatch,
    NameReadOnly,
    NotFound,
}

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

impl std::error::Error for KeyError {}

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

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

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

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

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

    #[allow(clippy::eq_op)]
    #[test]
    fn equality_is_exclusive() {
        let key = BinaryKey::new("user/test/exclusive").unwrap();
        let key2 = BinaryKey::new("dir/test/exclusive").unwrap();
        assert!(!(key != key));
        assert!(key == key);

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

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

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

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

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

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

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

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

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

    #[test]
    fn keys_are_ordered_with_metadata()  -> Result<(), KeyError> {
        let k1: StringKey = KeyBuilder::new("user/a")?.meta("owner", "abc")?.build();
        let k2: StringKey = KeyBuilder::new("user/a")?.meta("owner", "abz")?.build();
        assert!(k1 < k2);
        assert!(k2 > k1);
        Ok(())
    }

    #[test]
    fn can_reference_count() {
        let mut key = BinaryKey::new("user/test/a").unwrap();
        assert_eq!(key.get_ref(), 0);
        key.inc_ref();
        assert_eq!(key.get_ref(), 1);
        key.dec_ref();
        assert_eq!(key.get_ref(), 0);
    }

    #[test]
    fn error_on_missing_metaname() {
        let key = StringKey::new("user/test/metatest").unwrap();
        assert!(key.meta("nonexistent metaname").is_err());
    }
    #[test]
    fn can_set_get_metavalue() {
        let mut key = StringKey::new_empty();
        key.set_meta("metakey", "metaval").unwrap();
        let meta_key = key.meta("metakey").unwrap();
        assert_eq!(meta_key.value(), "metaval");
    }

    #[test]
    fn can_iterate_key() {
        let mut key = StringKey::new_empty();
        let meta = [("meta1", "val1"), ("meta2", "val2")];
        key.set_meta(meta[0].0, meta[0].1).unwrap();
        key.set_meta(meta[1].0, meta[1].1).unwrap();
        key.rewind_meta();

        let mut did_iterate = false;
        for (i, metakey) in key.enumerate() {
            did_iterate = true;
            assert_eq!(metakey.name(), meta[i].0);
            assert_eq!(metakey.value(), meta[i].1);
        }
        assert!(did_iterate);
    }

    #[test]
    fn can_delete_metadata() {
        let mut key = StringKey::new_empty();
        key.set_meta("metakey", "metaval").unwrap();
        assert_eq!(key.delete_meta("metakey").unwrap(), 0);
        assert_eq!(key.meta("metakey").unwrap_err(), KeyError::NotFound);
    }

    #[test]
    fn can_cast_key_types() {
        let key = StringKey::new("user/test/cast").unwrap();
        let mut bin_key = BinaryKey::from(key);
        let val = b"data";
        bin_key.set_value(val);
        assert_eq!(bin_key.value(), val);
    }

    #[test]
    fn can_get_fullname() -> Result<(), KeyError>  {
        let name = "user/test/fulltest";
        let key: StringKey = KeyBuilder::new(name)?
            .meta("metaname", "metavalue")?
            .meta("owner", "me")?
            .build();
        assert_eq!(key.fullname(), "user:me/test/fulltest");
        Ok(())
    }

}
<commit_msg>Rust: Implement iterator over metakeys<commit_after>use crate::{ReadOnly, ReadableKey, WriteableKey};
use elektra_sys;
use std::borrow::Cow;
use std::convert::TryInto;
use std::ffi::{CStr, CString};
use std::ptr::NonNull;

#[derive(Debug)]
pub struct StringKey<'a> {
    ptr: NonNull<elektra_sys::Key>,
    _marker: std::marker::PhantomData<&'a mut elektra_sys::Key>,
}

#[derive(Debug)]
pub struct BinaryKey<'a> {
    ptr: NonNull<elektra_sys::Key>,
    _marker: std::marker::PhantomData<&'a mut elektra_sys::Key>,
}

macro_rules! add_traits {
    ($($t:ty)*) => ($(
        impl PartialEq for $t {

            #[inline]
            fn eq(&self, other: &Self) -> bool {
                unsafe {
                    elektra_sys::keyCmp(
                        self.as_ref(),
                        other.as_ref(),
                    ) == 0
                }
            }
        }

        impl Eq for $t {}

        impl Ord for $t {
            fn cmp(&self, other: &Self) -> std::cmp::Ordering {
                let cmp = unsafe {
                    elektra_sys::keyCmp(
                        self.as_ref(),
                        other.as_ref(),
                    )
                };

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

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

        impl AsRef<elektra_sys::Key> for $t {
            fn as_ref(&self) -> &elektra_sys::Key {
                unsafe { self.ptr.as_ref() }
            }
        }

        impl Drop for $t {
            fn drop(&mut self) {
                unsafe { elektra_sys::keyDel(self.as_ptr()) };
            }
        }
    )*)
}

add_traits!(StringKey<'_>);
add_traits!(BinaryKey<'_>);

pub struct KeyMetaIter<'a, T: WriteableKey> {
    key: &'a mut T,
}

impl<'a, T: WriteableKey> Iterator for KeyMetaIter<'a, T> {
    type Item = ReadOnly<StringKey<'a>>;
    fn next(&mut self) -> Option<Self::Item> {
        let key_ptr = unsafe { elektra_sys::keyNextMeta(self.key.as_ptr()) };
        if key_ptr.is_null() {
            None
        } else {
            Some(ReadOnly::from_ptr(key_ptr as *mut elektra_sys::Key))
        }
    }
}

impl<'a> StringKey<'a> {
    /// Sets the value of the key to the supplied string.
    ///
    /// # Panics
    /// Panics if the provided string contains interior nul bytes.
    fn set_string(&mut self, value: &str) {
        let cstr = CString::new(value).unwrap();
        unsafe { elektra_sys::keySetString(self.as_ptr(), cstr.as_ptr()) };
    }

    /// Returns the string value of the key or a Utf8Error if it cannot be converted.
    fn string(&self) -> Cow<'a, str> {
        let c_str = unsafe { CStr::from_ptr(elektra_sys::keyString(self.as_ref())) };
        c_str.to_string_lossy()
    }

    /// Returns a deep copy of the key.
    pub fn duplicate<'b>(&'a self) -> StringKey<'b> {
        let dup_ptr = unsafe { elektra_sys::keyDup(self.as_ref()) };
        StringKey::from_ptr(dup_ptr)
    }

    /// Returns an iterator over the key's metakeys.
    pub fn iter<'b>(&'b mut self) -> KeyMetaIter<'b, StringKey<'a>> {
        KeyMetaIter { key: self }
    }
}

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

    /// Returns the keys binary content
    /// Returns a TypeMismatch if the key is of type string
    fn get_binary(&self) -> Vec<u8> {
        let mut vec: Vec<u8> = Vec::with_capacity(self.value_size());

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

        if ret_val > 0 {
            unsafe { vec.set_len(ret_val.try_into().unwrap()) };
        }

        vec
    }

    /// Returns a deep copy of the key.
    pub fn duplicate<'b>(&'a self) -> BinaryKey<'b> {
        let dup_ptr = unsafe { elektra_sys::keyDup(self.as_ref()) };
        BinaryKey::from_ptr(dup_ptr)
    }

    /// Returns an iterator over the key's metakeys.
    pub fn iter<'b>(&'b mut self) -> KeyMetaIter<'b, BinaryKey<'a>> {
        KeyMetaIter { key: self }
    }
}

impl<'a> ReadableKey for StringKey<'a> {
    type GetValue = Cow<'a, str>;

    fn from_ptr(ptr: *mut elektra_sys::Key) -> StringKey<'a> {
        StringKey {
            ptr: NonNull::new(ptr).unwrap(),
            _marker: std::marker::PhantomData,
        }
    }

    fn value(&self) -> Self::GetValue {
        self.string()
    }
}

impl<'a> ReadableKey for BinaryKey<'a> {
    type GetValue = Vec<u8>;

    fn from_ptr(ptr: *mut elektra_sys::Key) -> BinaryKey<'a> {
        BinaryKey {
            ptr: NonNull::new(ptr).unwrap(),
            _marker: std::marker::PhantomData,
        }
    }

    fn value(&self) -> Self::GetValue {
        self.get_binary()
    }
}

impl<'a> WriteableKey for BinaryKey<'a> {
    type SetValue = &'a [u8];

    fn as_ptr(&mut self) -> *mut elektra_sys::Key {
        self.ptr.as_ptr()
    }

    fn set_value(&mut self, value: Self::SetValue) {
        self.set_binary(value);
    }
}
impl<'a> WriteableKey for StringKey<'a> {
    type SetValue = &'a str;

    fn as_ptr(&mut self) -> *mut elektra_sys::Key {
        self.ptr.as_ptr()
    }
    fn set_value(&mut self, value: Self::SetValue) {
        self.set_string(value);
    }
}

impl From<StringKey<'_>> for BinaryKey<'_> {
    fn from(mut sk: StringKey) -> Self {
        let binary_key = BinaryKey::from_ptr(sk.as_ptr());
        std::mem::forget(sk);
        binary_key
    }
}

impl From<BinaryKey<'_>> for StringKey<'_> {
    fn from(mut bk: BinaryKey) -> Self {
        let str_key = StringKey::from_ptr(bk.as_ptr());
        std::mem::forget(bk);
        str_key
    }
}

#[derive(Debug, PartialEq)]
pub enum KeyError {
    InvalidName,
    TypeMismatch,
    NameReadOnly,
    NotFound,
}

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

impl std::error::Error for KeyError {}

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

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

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

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

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

    #[allow(clippy::eq_op)]
    #[test]
    fn equality_is_exclusive() {
        let key = BinaryKey::new("user/test/exclusive").unwrap();
        let key2 = BinaryKey::new("dir/test/exclusive").unwrap();
        assert!(!(key != key));
        assert!(key == key);

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

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

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

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

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

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

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

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

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

    #[test]
    fn keys_are_ordered_with_metadata() -> Result<(), KeyError> {
        let k1: StringKey = KeyBuilder::new("user/a")?.meta("owner", "abc")?.build();
        let k2: StringKey = KeyBuilder::new("user/a")?.meta("owner", "abz")?.build();
        assert!(k1 < k2);
        assert!(k2 > k1);
        Ok(())
    }

    #[test]
    fn can_reference_count() {
        let mut key = BinaryKey::new("user/test/a").unwrap();
        assert_eq!(key.get_ref(), 0);
        key.inc_ref();
        assert_eq!(key.get_ref(), 1);
        key.dec_ref();
        assert_eq!(key.get_ref(), 0);
    }

    #[test]
    fn error_on_missing_metaname() {
        let key = StringKey::new("user/test/metatest").unwrap();
        assert!(key.meta("nonexistent metaname").is_err());
    }
    #[test]
    fn can_set_get_metavalue() {
        let mut key = StringKey::new_empty();
        key.set_meta("metakey", "metaval").unwrap();
        let meta_key = key.meta("metakey").unwrap();
        assert_eq!(meta_key.value(), "metaval");
    }

    #[test]
    fn can_iterate_key() {
        let mut key = StringKey::new_empty();
        let meta = [("meta1", "val1"), ("meta2", "val2")];
        key.set_meta(meta[0].0, meta[0].1).unwrap();
        key.set_meta(meta[1].0, meta[1].1).unwrap();
        key.rewind_meta();

        let mut did_iterate = false;
        for (i, metakey) in key.iter().enumerate() {
            did_iterate = true;
            assert_eq!(metakey.name(), meta[i].0);
            assert_eq!(metakey.value(), meta[i].1);
        }
        assert!(did_iterate);
    }

    #[test]
    fn can_delete_metadata() {
        let mut key = StringKey::new_empty();
        key.set_meta("metakey", "metaval").unwrap();
        assert_eq!(key.delete_meta("metakey").unwrap(), 0);
        assert_eq!(key.meta("metakey").unwrap_err(), KeyError::NotFound);
    }

    #[test]
    fn can_cast_key_types() {
        let key = StringKey::new("user/test/cast").unwrap();
        let mut bin_key = BinaryKey::from(key);
        let val = b"data";
        bin_key.set_value(val);
        assert_eq!(bin_key.value(), val);
    }

    #[test]
    fn can_get_fullname() -> Result<(), KeyError> {
        let name = "user/test/fulltest";
        let key: StringKey = KeyBuilder::new(name)?
            .meta("metaname", "metavalue")?
            .meta("owner", "me")?
            .build();
        assert_eq!(key.fullname(), "user:me/test/fulltest");
        Ok(())
    }

}
<|endoftext|>


<commit_before>/*
!poll #announcements Poll text goes here!
:one: Option one
:two: Option two

From @Bot in #announcements
Poll from @jkcclemens:
Poll text goes here!
:one: – Option one
:two: – Option two

@Bot reacts to the message with all the options

!poll #general Some other poll
Auto-generate options
No custom emoji

!poll #channel Another custom poll
:thumbsup: Yes
:thumbsdown: No
*/

use LalafellBot;
use commands::*;

use discord::model::{ChannelId, MessageId, ReactionEmoji};
use discord::builders::EmbedBuilder;

use std::sync::Arc;

const USAGE: &'static str = "!pollresults <channel> <message id>";
const VALID_EMOJI: &'static [&'static str] = &[
  "1⃣",
  "2⃣",
  "3⃣",
  "4⃣",
  "5⃣",
  "6⃣",
  "7⃣",
  "8⃣",
  "9⃣"
];

pub struct PollResultsCommand {
  bot: Arc<LalafellBot>
}

impl PollResultsCommand {
  pub fn new(bot: Arc<LalafellBot>) -> PollResultsCommand {
    PollResultsCommand {
      bot: bot
    }
  }
}

impl<'a> Command<'a> for PollResultsCommand {
  fn run(&self, _: &Message, params: &[&str]) -> CommandResult<'a> {
    if params.len() < 2 {
      return Err(ExternalCommandFailure::default()
        .message(|e: EmbedBuilder| e
          .title("Not enough parameters.")
          .description(USAGE))
        .wrap());
    }
    let channel = params[0];
    let channel = if channel.starts_with("<#") && channel.ends_with('>') {
      &channel[2..channel.len() - 1]
    } else {
      channel
    };
    let channel_id = match channel.parse::<u64>() {
      Ok(u) => ChannelId(u),
      Err(_) => return Err(ExternalCommandFailure::default()
                  .message(|e: EmbedBuilder| e
                    .description("Invalid channel."))
                  .wrap())
    };
    let message_id = match params[1].parse::<u64>() {
      Ok(u) => MessageId(u),
      Err(_) => return Err(ExternalCommandFailure::default()
                  .message(|e: EmbedBuilder| e
                    .description("Invalid message ID."))
                  .wrap())
    };
    let message = match self.bot.discord.get_message(channel_id, message_id) {
      Ok(m) => m,
      Err(e) => { println!("{:#?}", e); return Err(ExternalCommandFailure::default()
                  .message(|e: EmbedBuilder| e
                    .description("Could not get that message."))
                  .wrap());}
    };
    let mut reactions: Vec<(&String, u64)> = message.reactions.iter()
      .map(|r| match r.emoji {
        ReactionEmoji::Unicode(ref s) if VALID_EMOJI.contains(&s.as_str()) && r.me => Some((s, r.count - 1)),
        _ => None
      })
      .filter(|x| x.is_some())
      .map(|x| x.unwrap())
      .collect();
    reactions.sort_by_key(|x| !x.1);
    let votes = reactions.iter()
      .map(|&(emoji, count)| format!("{} with {} vote{}", emoji, count, if count == 1 { "" } else { "s" }))
      .collect::<Vec<_>>()
      .join("\n");
    Ok(CommandSuccess::default()
      .message(move |e: EmbedBuilder| e.description(&votes)))
  }
}
<commit_msg>fix: remove old debug line<commit_after>/*
!poll #announcements Poll text goes here!
:one: Option one
:two: Option two

From @Bot in #announcements
Poll from @jkcclemens:
Poll text goes here!
:one: – Option one
:two: – Option two

@Bot reacts to the message with all the options

!poll #general Some other poll
Auto-generate options
No custom emoji

!poll #channel Another custom poll
:thumbsup: Yes
:thumbsdown: No
*/

use LalafellBot;
use commands::*;

use discord::model::{ChannelId, MessageId, ReactionEmoji};
use discord::builders::EmbedBuilder;

use std::sync::Arc;

const USAGE: &'static str = "!pollresults <channel> <message id>";
const VALID_EMOJI: &'static [&'static str] = &[
  "1⃣",
  "2⃣",
  "3⃣",
  "4⃣",
  "5⃣",
  "6⃣",
  "7⃣",
  "8⃣",
  "9⃣"
];

pub struct PollResultsCommand {
  bot: Arc<LalafellBot>
}

impl PollResultsCommand {
  pub fn new(bot: Arc<LalafellBot>) -> PollResultsCommand {
    PollResultsCommand {
      bot: bot
    }
  }
}

impl<'a> Command<'a> for PollResultsCommand {
  fn run(&self, _: &Message, params: &[&str]) -> CommandResult<'a> {
    if params.len() < 2 {
      return Err(ExternalCommandFailure::default()
        .message(|e: EmbedBuilder| e
          .title("Not enough parameters.")
          .description(USAGE))
        .wrap());
    }
    let channel = params[0];
    let channel = if channel.starts_with("<#") && channel.ends_with('>') {
      &channel[2..channel.len() - 1]
    } else {
      channel
    };
    let channel_id = match channel.parse::<u64>() {
      Ok(u) => ChannelId(u),
      Err(_) => return Err(ExternalCommandFailure::default()
        .message(|e: EmbedBuilder| e
          .description("Invalid channel."))
        .wrap())
    };
    let message_id = match params[1].parse::<u64>() {
      Ok(u) => MessageId(u),
      Err(_) => return Err(ExternalCommandFailure::default()
        .message(|e: EmbedBuilder| e
          .description("Invalid message ID."))
        .wrap())
    };
    let message = match self.bot.discord.get_message(channel_id, message_id) {
      Ok(m) => m,
      Err(e) => return Err(ExternalCommandFailure::default()
        .message(|e: EmbedBuilder| e
          .description("Could not get that message."))
        .wrap())
    };
    let mut reactions: Vec<(&String, u64)> = message.reactions.iter()
      .map(|r| match r.emoji {
        ReactionEmoji::Unicode(ref s) if VALID_EMOJI.contains(&s.as_str()) && r.me => Some((s, r.count - 1)),
        _ => None
      })
      .filter(|x| x.is_some())
      .map(|x| x.unwrap())
      .collect();
    reactions.sort_by_key(|x| !x.1);
    let votes = reactions.iter()
      .map(|&(emoji, count)| format!("{} with {} vote{}", emoji, count, if count == 1 { "" } else { "s" }))
      .collect::<Vec<_>>()
      .join("\n");
    Ok(CommandSuccess::default()
      .message(move |e: EmbedBuilder| e.description(&votes)))
  }
}
<|endoftext|>


<commit_before>#[cfg(feature = "acpi")]
use acpi;
use syscall::io::{Io, Pio};

#[no_mangle]
pub unsafe extern fn kreset() -> ! {
    println!("kreset");

    // 8042 reset
    {
        println!("Reset with 8042");
        let mut port = Pio::<u8>::new(0x64);
        while port.readf(2) {}
        port.write(0xFE);
    }

    // Use triple fault to guarantee reset
    asm!("cli" : : : : "intel", "volatile");
    asm!("lidt cs:0" : : : : "intel", "volatile");
    asm!("int $$3" : : : : "intel", "volatile");

    unreachable!();
}

#[no_mangle]
pub unsafe extern fn kstop() -> ! {
    println!("kstop");

    #[cfg(feature = "acpi")]
    acpi::set_global_s_state(5);

    // Magic shutdown code for bochs and qemu (older versions).
    for c in "Shutdown".bytes() {
        let port = 0x8900;
        println!("Shutdown with outb(0x{:X}, '{}')", port, c as char);
        Pio::<u8>::new(port).write(c);
    }

    // Magic code for VMWare. Also a hard lock.
    println!("Shutdown with cli hlt");
    asm!("cli; hlt" : : : : "intel", "volatile");

    unreachable!();
}
<commit_msg>Add code to shut down QEMU with it's default ACPI settings, run cli hlt in loop<commit_after>#[cfg(feature = "acpi")]
use acpi;
use syscall::io::{Io, Pio};

#[no_mangle]
pub unsafe extern fn kreset() -> ! {
    println!("kreset");

    // 8042 reset
    {
        println!("Reset with 8042");
        let mut port = Pio::<u8>::new(0x64);
        while port.readf(2) {}
        port.write(0xFE);
    }

    // Use triple fault to guarantee reset
    asm!("cli" : : : : "intel", "volatile");
    asm!("lidt cs:0" : : : : "intel", "volatile");
    asm!("int $$3" : : : : "intel", "volatile");

    unreachable!();
}

#[no_mangle]
pub unsafe extern fn kstop() -> ! {
    println!("kstop");

    #[cfg(feature = "acpi")]
    acpi::set_global_s_state(5);

    // Magic shutdown code for bochs and qemu (older versions).
    for c in "Shutdown".bytes() {
        let port = 0x8900;
        println!("Shutdown with outb(0x{:X}, '{}')", port, c as char);
        Pio::<u8>::new(port).write(c);
    }

    // Magic shutdown using qemu default ACPI method
    {
        let port = 0x604;
        let data = 0x2000;
        println!("Shutdown with outb(0x{:X}, 0x{:X})", port, data);
        Pio::<u16>::new(port).write(data);
    }

    // Magic code for VMWare. Also a hard lock.
    println!("Shutdown with cli hlt");
    loop {
        asm!("cli; hlt" : : : : "intel", "volatile");
    }
}
<|endoftext|>


<commit_before>//! Log all requests in a format similar to Heroku's router, but with additional
//! information that we care about like User-Agent and Referer

use super::prelude::*;
use crate::util::request_header;
use conduit::Request;
use std::fmt;
use std::time::Instant;

#[allow(missing_debug_implementations)] // We can't
#[derive(Default)]
pub struct LogRequests {
    handler: Option<Box<dyn Handler>>,
}

impl AroundMiddleware for LogRequests {
    fn with_handler(&mut self, handler: Box<dyn Handler>) {
        self.handler = Some(handler);
    }
}

impl Handler for LogRequests {
    fn call(&self, req: &mut dyn Request) -> Result<Response, Box<dyn Error + Send>> {
        let request_start = Instant::now();
        let res = self.handler.as_ref().unwrap().call(req);
        let (level, response_code) = match res {
            Ok(ref r) => ("info", r.status.0),
            Err(_) => ("error", 500),
        };
        let response_time = request_start.elapsed();
        let response_time =
            response_time.as_secs() * 1000 + u64::from(response_time.subsec_nanos()) / 1_000_000;

        print!(
            "at={level} method={method} path=\"{path}\" \
             request_id={request_id} fwd=\"{ip}\" service={time_ms}ms \
             status={status} user_agent=\"{user_agent}\" referer=\"{referer}\"",
            level = level,
            method = req.method(),
            path = FullPath(req),
            ip = request_header(req, "X-Real-Ip"),
            time_ms = response_time,
            user_agent = request_header(req, "User-Agent"),
            referer = request_header(req, "Referer"), // sic
            request_id = request_header(req, "X-Request-Id"),
            status = response_code,
        );

        if let Err(ref e) = res {
            print!(" error=\"{}\"", e.description());
        }

        if response_time > 1000 {
            print!(" SLOW REQUEST");
        }

        println!();

        res
    }
}

struct FullPath<'a>(&'a dyn Request);

impl<'a> fmt::Display for FullPath<'a> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0.path())?;
        if let Some(q_string) = self.0.query_string() {
            write!(f, "?{}", q_string)?;
        }
        Ok(())
    }
}
<commit_msg>Auto merge of #1636 - sgrif:sg-stop-logging-referer, r=jtgeibel<commit_after>//! Log all requests in a format similar to Heroku's router, but with additional
//! information that we care about like User-Agent

use super::prelude::*;
use crate::util::request_header;
use conduit::Request;
use std::fmt;
use std::time::Instant;

#[allow(missing_debug_implementations)] // We can't
#[derive(Default)]
pub struct LogRequests {
    handler: Option<Box<dyn Handler>>,
}

impl AroundMiddleware for LogRequests {
    fn with_handler(&mut self, handler: Box<dyn Handler>) {
        self.handler = Some(handler);
    }
}

impl Handler for LogRequests {
    fn call(&self, req: &mut dyn Request) -> Result<Response, Box<dyn Error + Send>> {
        let request_start = Instant::now();
        let res = self.handler.as_ref().unwrap().call(req);
        let (level, response_code) = match res {
            Ok(ref r) => ("info", r.status.0),
            Err(_) => ("error", 500),
        };
        let response_time = request_start.elapsed();
        let response_time =
            response_time.as_secs() * 1000 + u64::from(response_time.subsec_nanos()) / 1_000_000;

        print!(
            "at={level} method={method} path=\"{path}\" \
             request_id={request_id} fwd=\"{ip}\" service={time_ms}ms \
             status={status} user_agent=\"{user_agent}\"",
            level = level,
            method = req.method(),
            path = FullPath(req),
            ip = request_header(req, "X-Real-Ip"),
            time_ms = response_time,
            user_agent = request_header(req, "User-Agent"),
            request_id = request_header(req, "X-Request-Id"),
            status = response_code,
        );

        if let Err(ref e) = res {
            print!(" error=\"{}\"", e.description());
        }

        if response_time > 1000 {
            print!(" SLOW REQUEST");
        }

        println!();

        res
    }
}

struct FullPath<'a>(&'a dyn Request);

impl<'a> fmt::Display for FullPath<'a> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0.path())?;
        if let Some(q_string) = self.0.query_string() {
            write!(f, "?{}", q_string)?;
        }
        Ok(())
    }
}
<|endoftext|>