<commit_before>use std::cell::UnsafeCell;
use std::marker::PhantomData;
use std::mem;
use std::ops::Deref;
use std::ptr::{self, NonNull};
use std::sync::{Arc, Weak};
use std::sync::atomic::{AtomicPtr, AtomicBool};
use std::sync::atomic::Ordering::SeqCst;

use futures_core::task::{UnsafeWake, Waker, LocalWaker};

use super::ReadyToRunQueue;
use super::abort::abort;

pub(super) struct Node<Fut> {
    // The future
    pub(super) future: UnsafeCell<Option<Fut>>,

    // Next pointer for linked list tracking all active nodes
    pub(super) next_all: UnsafeCell<*const Node<Fut>>,

    // Previous node in linked list tracking all active nodes
    pub(super) prev_all: UnsafeCell<*const Node<Fut>>,

    // Next pointer in readiness queue
    pub(super) next_ready_to_run: AtomicPtr<Node<Fut>>,

    // Queue that we'll be enqueued to when notified
    pub(super) ready_to_run_queue: Weak<ReadyToRunQueue<Fut>>,

    // Whether or not this node is currently in the ready to run queue.
    pub(super) queued: AtomicBool,
}

pub(super) struct LocalWakerRef<'a> {
    local_waker: LocalWaker,
    _marker: PhantomData<&'a ()>,
}

impl<'a> Deref for LocalWakerRef<'a> {
    type Target = LocalWaker;

    fn deref(&self) -> &LocalWaker {
        &self.local_waker
    }
}

impl<Fut> Node<Fut> {
    pub(super) fn wake(self: &Arc<Node<Fut>>) {
        let inner = match self.ready_to_run_queue.upgrade() {
            Some(inner) => inner,
            None => return,
        };

        // It's our job to notify the node that it's ready to get polled,
        // meaning that we need to enqueue it into the readiness queue. To
        // do this we flag that we're ready to be queued, and if successful
        // we then do the literal queueing operation, ensuring that we're
        // only queued once.
        //
        // Once the node is inserted we be sure to notify the parent task,
        // as it'll want to come along and pick up our node now.
        //
        // Note that we don't change the reference count of the node here,
        // we're just enqueueing the raw pointer. The `FuturesUnordered`
        // implementation guarantees that if we set the `queued` flag true that
        // there's a reference count held by the main `FuturesUnordered` queue
        // still.
        let prev = self.queued.swap(true, SeqCst);
        if !prev {
            inner.enqueue(&**self);
            inner.parent.wake();
        }
    }

    /// Returns a waker.
    pub(super) fn waker(self: &Arc<Node<Fut>>) -> Waker {
        let clone = self.clone();

        // Safety: This is save because an `Arc` is a struct which contains
        // a single field that is a pointer.
        let ptr = unsafe {
            mem::transmute::<Arc<Node<Fut>>,
                             NonNull<ArcNode<Fut>>>(clone)
        };

        let ptr = ptr as NonNull<dyn UnsafeWake>;

        // Hide lifetime of `Fut`
        // Safety: The waker can safely outlive the future because the
        // `UnsafeWake` impl is guaranteed to not touch `Fut`.
        let ptr = unsafe {
            mem::transmute::<NonNull<dyn UnsafeWake>,
                             NonNull<dyn UnsafeWake>>(ptr)
        };

        unsafe { Waker::new(ptr) }
    }

    /// Returns a local waker for this node without cloning the Arc.
    pub(super) fn local_waker(self: &'a Arc<Node<Fut>>) -> LocalWakerRef<'a> {
        // Safety: This is save because an `Arc` is a struct which contains
        // a single field that is a pointer.
        let ptr = unsafe {
            *mem::transmute::<*const Arc<Node<Fut>>,
                              *const NonNull<ArcNodeUnowned<Fut>>>(self)
        };

        let ptr = ptr as NonNull<dyn UnsafeWake>;

        // Hide lifetime of `self`
        // Safety:
        // - Since the `Arc` has not been cloned, the local waker must
        //   not outlive it. This is ensured by the lifetime of `LocalWakerRef`.
        // - The local waker can safely outlive the future because the
        //   `UnsafeWake` impl is guaranteed to not touch `Fut`.
        unsafe {
            let ptr = mem::transmute::<NonNull<dyn UnsafeWake>,
                                       NonNull<dyn UnsafeWake>>(ptr);
            LocalWakerRef {
                local_waker: LocalWaker::new(ptr),
                _marker: PhantomData,
            }
        }
    }
}

impl<Fut> Drop for Node<Fut> {
    fn drop(&mut self) {
        // Currently a `Node<Fut>` is sent across all threads for any lifetime,
        // regardless of `Fut`. This means that for memory safety we can't
        // actually touch `Fut` at any time except when we have a reference to
        // the `FuturesUnordered` itself.
        //
        // Consequently it *should* be the case that we always drop futures from
        // the `FuturesUnordered` instance, but this is a bomb in place to catch
        // any bugs in that logic.
        unsafe {
            if (*self.future.get()).is_some() {
                abort("future still here when dropping");
            }
        }
    }
}

// `ArcNode<Fut>` represents conceptually the struct an `Arc<Node<Fut>>` points
// to. `*const ArcNode<Fut>` is equal to `Arc<Node<Fut>>`
// It may only be used through references because its layout obviously doesn't
// match the real inner struct of an `Arc` which (currently) has the form
// `{ strong, weak, data }`.
struct ArcNode<Fut>(PhantomData<Fut>);

struct ArcNodeUnowned<Fut>(PhantomData<Fut>); // Doesn't drop the `Arc`'s data

// We should never touch the future `Fut` on any thread other than the one
// owning `FuturesUnordered`, so this should be a safe operation.
unsafe impl<Fut> Send for ArcNode<Fut> {}
unsafe impl<Fut> Sync for ArcNode<Fut> {}

unsafe impl<Fut> Send for ArcNodeUnowned<Fut> {}
unsafe impl<Fut> Sync for ArcNodeUnowned<Fut> {}

// We need to implement `UnsafeWake` trait directly and can't implement `Wake`
// for `Node<Fut>` because `Fut`, the future, isn't required to have a static
// lifetime. `UnsafeWake` lets us forget about `Fut` and its lifetime. This is
// safe because neither `drop_raw` nor `wake` touch `Fut`. This is the case even
// though `drop_raw` runs the destructor for `Node<Fut>` because its destructor
// is guaranteed to not touch `Fut`. `Fut` must already have been dropped by the
// time it runs. See `Drop` impl for `Node<Fut>` for more details.
unsafe impl<Fut> UnsafeWake for ArcNode<Fut> {
    #[inline]
    unsafe fn clone_raw(&self) -> Waker {
        let me: *const ArcNode<Fut> = self;
        let node = &*(&me as *const *const ArcNode<Fut>
                          as *const Arc<Node<Fut>>);
        node.waker()
    }

    #[inline]
    unsafe fn drop_raw(&self) {
        let mut me: *const ArcNode<Fut> = self;
        let node_ptr = &mut me as *mut *const ArcNode<Fut>
                               as *mut Arc<Node<Fut>>;
        ptr::drop_in_place(node_ptr);
    }

    #[inline]
    unsafe fn wake(&self) {
        let me: *const ArcNode<Fut> = self;
        let node = &*(&me as *const *const ArcNode<Fut>
                          as *const Arc<Node<Fut>>);
        node.wake();
    }
}

unsafe impl<Fut> UnsafeWake for ArcNodeUnowned<Fut> {
    #[inline]
    unsafe fn clone_raw(&self) -> Waker {
        let me: *const ArcNodeUnowned<Fut> = self;
        let node = &*(&me as *const *const ArcNodeUnowned<Fut>
                          as *const Arc<Node<Fut>>);
        node.waker() // Clones the `Arc` and the returned waker owns the
                     // clone. (`ArcNode<Fut>` not `ArcNodeUnowned<Fut>`)
    }

    #[inline]
    unsafe fn drop_raw(&self) {} // Does nothing

    #[inline]
    unsafe fn wake(&self) {
        let me: *const ArcNodeUnowned<Fut> = self;
        let node = &*(&me as *const *const ArcNodeUnowned<Fut>
                          as *const Arc<Node<Fut>>);
       node.wake();
    }
}
<commit_msg>Fix clippy warning in futures_unordered<commit_after>use std::cell::UnsafeCell;
use std::marker::PhantomData;
use std::mem;
use std::ops::Deref;
use std::ptr::{self, NonNull};
use std::sync::{Arc, Weak};
use std::sync::atomic::{AtomicPtr, AtomicBool};
use std::sync::atomic::Ordering::SeqCst;

use futures_core::task::{UnsafeWake, Waker, LocalWaker};

use super::ReadyToRunQueue;
use super::abort::abort;

pub(super) struct Node<Fut> {
    // The future
    pub(super) future: UnsafeCell<Option<Fut>>,

    // Next pointer for linked list tracking all active nodes
    pub(super) next_all: UnsafeCell<*const Node<Fut>>,

    // Previous node in linked list tracking all active nodes
    pub(super) prev_all: UnsafeCell<*const Node<Fut>>,

    // Next pointer in readiness queue
    pub(super) next_ready_to_run: AtomicPtr<Node<Fut>>,

    // Queue that we'll be enqueued to when notified
    pub(super) ready_to_run_queue: Weak<ReadyToRunQueue<Fut>>,

    // Whether or not this node is currently in the ready to run queue.
    pub(super) queued: AtomicBool,
}

pub(super) struct LocalWakerRef<'a> {
    local_waker: LocalWaker,
    _marker: PhantomData<&'a ()>,
}

impl<'a> Deref for LocalWakerRef<'a> {
    type Target = LocalWaker;

    fn deref(&self) -> &LocalWaker {
        &self.local_waker
    }
}

impl<Fut> Node<Fut> {
    pub(super) fn wake(self: &Arc<Node<Fut>>) {
        let inner = match self.ready_to_run_queue.upgrade() {
            Some(inner) => inner,
            None => return,
        };

        // It's our job to notify the node that it's ready to get polled,
        // meaning that we need to enqueue it into the readiness queue. To
        // do this we flag that we're ready to be queued, and if successful
        // we then do the literal queueing operation, ensuring that we're
        // only queued once.
        //
        // Once the node is inserted we be sure to notify the parent task,
        // as it'll want to come along and pick up our node now.
        //
        // Note that we don't change the reference count of the node here,
        // we're just enqueueing the raw pointer. The `FuturesUnordered`
        // implementation guarantees that if we set the `queued` flag true that
        // there's a reference count held by the main `FuturesUnordered` queue
        // still.
        let prev = self.queued.swap(true, SeqCst);
        if !prev {
            inner.enqueue(&**self);
            inner.parent.wake();
        }
    }

    /// Returns a waker.
    pub(super) fn waker(self: &Arc<Node<Fut>>) -> Waker {
        let clone = self.clone();

        // Safety: This is save because an `Arc` is a struct which contains
        // a single field that is a pointer.
        let ptr = unsafe {
            mem::transmute::<Arc<Node<Fut>>,
                             NonNull<ArcNode<Fut>>>(clone)
        };

        let ptr = ptr as NonNull<dyn UnsafeWake>;

        // Hide lifetime of `Fut`
        // Safety: The waker can safely outlive the future because the
        // `UnsafeWake` impl is guaranteed to not touch `Fut`.
        let ptr = unsafe {
            mem::transmute::<NonNull<dyn UnsafeWake>,
                             NonNull<dyn UnsafeWake>>(ptr)
        };

        unsafe { Waker::new(ptr) }
    }

    /// Returns a local waker for this node without cloning the Arc.
    pub(super) fn local_waker(self: &'a Arc<Node<Fut>>) -> LocalWakerRef<'a> {
        // Safety: This is safe because an `Arc` is a struct which contains
        // a single field that is a pointer.
        let ptr = unsafe {
            *(self as *const _ as *const NonNull<ArcNodeUnowned<Fut>>)
        };

        let ptr = ptr as NonNull<dyn UnsafeWake>;

        // Hide lifetime of `self`
        // Safety:
        // - Since the `Arc` has not been cloned, the local waker must
        //   not outlive it. This is ensured by the lifetime of `LocalWakerRef`.
        // - The local waker can safely outlive the future because the
        //   `UnsafeWake` impl is guaranteed to not touch `Fut`.
        unsafe {
            let ptr = mem::transmute::<NonNull<dyn UnsafeWake>,
                                       NonNull<dyn UnsafeWake>>(ptr);
            LocalWakerRef {
                local_waker: LocalWaker::new(ptr),
                _marker: PhantomData,
            }
        }
    }
}

impl<Fut> Drop for Node<Fut> {
    fn drop(&mut self) {
        // Currently a `Node<Fut>` is sent across all threads for any lifetime,
        // regardless of `Fut`. This means that for memory safety we can't
        // actually touch `Fut` at any time except when we have a reference to
        // the `FuturesUnordered` itself.
        //
        // Consequently it *should* be the case that we always drop futures from
        // the `FuturesUnordered` instance, but this is a bomb in place to catch
        // any bugs in that logic.
        unsafe {
            if (*self.future.get()).is_some() {
                abort("future still here when dropping");
            }
        }
    }
}

// `ArcNode<Fut>` represents conceptually the struct an `Arc<Node<Fut>>` points
// to. `*const ArcNode<Fut>` is equal to `Arc<Node<Fut>>`
// It may only be used through references because its layout obviously doesn't
// match the real inner struct of an `Arc` which (currently) has the form
// `{ strong, weak, data }`.
struct ArcNode<Fut>(PhantomData<Fut>);

struct ArcNodeUnowned<Fut>(PhantomData<Fut>); // Doesn't drop the `Arc`'s data

// We should never touch the future `Fut` on any thread other than the one
// owning `FuturesUnordered`, so this should be a safe operation.
unsafe impl<Fut> Send for ArcNode<Fut> {}
unsafe impl<Fut> Sync for ArcNode<Fut> {}

unsafe impl<Fut> Send for ArcNodeUnowned<Fut> {}
unsafe impl<Fut> Sync for ArcNodeUnowned<Fut> {}

// We need to implement `UnsafeWake` trait directly and can't implement `Wake`
// for `Node<Fut>` because `Fut`, the future, isn't required to have a static
// lifetime. `UnsafeWake` lets us forget about `Fut` and its lifetime. This is
// safe because neither `drop_raw` nor `wake` touch `Fut`. This is the case even
// though `drop_raw` runs the destructor for `Node<Fut>` because its destructor
// is guaranteed to not touch `Fut`. `Fut` must already have been dropped by the
// time it runs. See `Drop` impl for `Node<Fut>` for more details.
unsafe impl<Fut> UnsafeWake for ArcNode<Fut> {
    #[inline]
    unsafe fn clone_raw(&self) -> Waker {
        let me: *const ArcNode<Fut> = self;
        let node = &*(&me as *const *const ArcNode<Fut>
                          as *const Arc<Node<Fut>>);
        node.waker()
    }

    #[inline]
    unsafe fn drop_raw(&self) {
        let mut me: *const ArcNode<Fut> = self;
        let node_ptr = &mut me as *mut *const ArcNode<Fut>
                               as *mut Arc<Node<Fut>>;
        ptr::drop_in_place(node_ptr);
    }

    #[inline]
    unsafe fn wake(&self) {
        let me: *const ArcNode<Fut> = self;
        let node = &*(&me as *const *const ArcNode<Fut>
                          as *const Arc<Node<Fut>>);
        node.wake();
    }
}

unsafe impl<Fut> UnsafeWake for ArcNodeUnowned<Fut> {
    #[inline]
    unsafe fn clone_raw(&self) -> Waker {
        let me: *const ArcNodeUnowned<Fut> = self;
        let node = &*(&me as *const *const ArcNodeUnowned<Fut>
                          as *const Arc<Node<Fut>>);
        node.waker() // Clones the `Arc` and the returned waker owns the
                     // clone. (`ArcNode<Fut>` not `ArcNodeUnowned<Fut>`)
    }

    #[inline]
    unsafe fn drop_raw(&self) {} // Does nothing

    #[inline]
    unsafe fn wake(&self) {
        let me: *const ArcNodeUnowned<Fut> = self;
        let node = &*(&me as *const *const ArcNodeUnowned<Fut>
                          as *const Arc<Node<Fut>>);
       node.wake();
    }
}
<|endoftext|>


<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(bad_style)]

use libc;

pub use self::os::{PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_RECURSIVE, pthread_mutex_t,
                   pthread_mutexattr_t};
pub use self::os::{PTHREAD_COND_INITIALIZER, pthread_cond_t};
pub use self::os::{PTHREAD_RWLOCK_INITIALIZER, pthread_rwlock_t};

extern {
    // mutexes
    pub fn pthread_mutex_init(lock: *mut pthread_mutex_t, attr: *const pthread_mutexattr_t)
                            -> libc::c_int;
    pub fn pthread_mutex_destroy(lock: *mut pthread_mutex_t) -> libc::c_int;
    pub fn pthread_mutex_lock(lock: *mut pthread_mutex_t) -> libc::c_int;
    pub fn pthread_mutex_trylock(lock: *mut pthread_mutex_t) -> libc::c_int;
    pub fn pthread_mutex_unlock(lock: *mut pthread_mutex_t) -> libc::c_int;

    pub fn pthread_mutexattr_init(attr: *mut pthread_mutexattr_t) -> libc::c_int;
    pub fn pthread_mutexattr_destroy(attr: *mut pthread_mutexattr_t) -> libc::c_int;
    pub fn pthread_mutexattr_settype(attr: *mut pthread_mutexattr_t, _type: libc::c_int)
                                    -> libc::c_int;

    // cvars
    pub fn pthread_cond_wait(cond: *mut pthread_cond_t,
                             lock: *mut pthread_mutex_t) -> libc::c_int;
    pub fn pthread_cond_timedwait(cond: *mut pthread_cond_t,
                              lock: *mut pthread_mutex_t,
                              abstime: *const libc::timespec) -> libc::c_int;
    pub fn pthread_cond_signal(cond: *mut pthread_cond_t) -> libc::c_int;
    pub fn pthread_cond_broadcast(cond: *mut pthread_cond_t) -> libc::c_int;
    pub fn pthread_cond_destroy(cond: *mut pthread_cond_t) -> libc::c_int;
    #[cfg_attr(target_os = "netbsd", link_name = "__gettimeofday50")]
    pub fn gettimeofday(tp: *mut libc::timeval,
                        tz: *mut libc::c_void) -> libc::c_int;

    // rwlocks
    pub fn pthread_rwlock_destroy(lock: *mut pthread_rwlock_t) -> libc::c_int;
    pub fn pthread_rwlock_rdlock(lock: *mut pthread_rwlock_t) -> libc::c_int;
    pub fn pthread_rwlock_tryrdlock(lock: *mut pthread_rwlock_t) -> libc::c_int;
    pub fn pthread_rwlock_wrlock(lock: *mut pthread_rwlock_t) -> libc::c_int;
    pub fn pthread_rwlock_trywrlock(lock: *mut pthread_rwlock_t) -> libc::c_int;
    pub fn pthread_rwlock_unlock(lock: *mut pthread_rwlock_t) -> libc::c_int;
}

#[cfg(any(target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "bitrig",
          target_os = "openbsd"))]
mod os {
    use libc;
    use ptr;

    pub type pthread_mutex_t = *mut libc::c_void;
    pub type pthread_mutexattr_t = *mut libc::c_void;
    pub type pthread_cond_t = *mut libc::c_void;
    pub type pthread_rwlock_t = *mut libc::c_void;

    pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = ptr::null_mut();
    pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = ptr::null_mut();
    pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = ptr::null_mut();
    pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 2;
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
mod os {
    use libc;

    #[cfg(any(target_arch = "x86_64",
              target_arch = "aarch64"))]
    const __PTHREAD_MUTEX_SIZE__: usize = 56;
    #[cfg(any(target_arch = "x86",
              target_arch = "arm"))]
    const __PTHREAD_MUTEX_SIZE__: usize = 40;

    #[cfg(any(target_arch = "x86_64",
              target_arch = "aarch64"))]
    const __PTHREAD_COND_SIZE__: usize = 40;
    #[cfg(any(target_arch = "x86",
              target_arch = "arm"))]
    const __PTHREAD_COND_SIZE__: usize = 24;

    #[cfg(any(target_arch = "x86_64",
              target_arch = "aarch64"))]
    const __PTHREAD_RWLOCK_SIZE__: usize = 192;
    #[cfg(any(target_arch = "x86",
              target_arch = "arm"))]
    const __PTHREAD_RWLOCK_SIZE__: usize = 124;

    const _PTHREAD_MUTEX_SIG_INIT: libc::c_long = 0x32AAABA7;
    const _PTHREAD_COND_SIG_INIT: libc::c_long = 0x3CB0B1BB;
    const _PTHREAD_RWLOCK_SIG_INIT: libc::c_long = 0x2DA8B3B4;

    #[repr(C)]
    pub struct pthread_mutex_t {
        __sig: libc::c_long,
        __opaque: [u8; __PTHREAD_MUTEX_SIZE__],
    }
    #[repr(C)]
    pub struct pthread_mutexattr_t {
        __sig: libc::c_long,
        // note, that this is 16 bytes just to be safe, the actual struct might be smaller.
        __opaque: [u8; 16],
    }
    #[repr(C)]
    pub struct pthread_cond_t {
        __sig: libc::c_long,
        __opaque: [u8; __PTHREAD_COND_SIZE__],
    }
    #[repr(C)]
    pub struct pthread_rwlock_t {
        __sig: libc::c_long,
        __opaque: [u8; __PTHREAD_RWLOCK_SIZE__],
    }

    pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t {
        __sig: _PTHREAD_MUTEX_SIG_INIT,
        __opaque: [0; __PTHREAD_MUTEX_SIZE__],
    };
    pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t {
        __sig: _PTHREAD_COND_SIG_INIT,
        __opaque: [0; __PTHREAD_COND_SIZE__],
    };
    pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t {
        __sig: _PTHREAD_RWLOCK_SIG_INIT,
        __opaque: [0; __PTHREAD_RWLOCK_SIZE__],
    };

    pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 2;
}

#[cfg(target_os = "linux")]
mod os {
    use libc;

    // minus 8 because we have an 'align' field
    #[cfg(target_arch = "x86_64")]
    const __SIZEOF_PTHREAD_MUTEX_T: usize = 40 - 8;
    #[cfg(any(target_arch = "x86",
              target_arch = "arm",
              target_arch = "mips",
              target_arch = "mipsel",
              target_arch = "powerpc"))]
    const __SIZEOF_PTHREAD_MUTEX_T: usize = 24 - 8;
    #[cfg(target_arch = "aarch64")]
    const __SIZEOF_PTHREAD_MUTEX_T: usize = 48 - 8;

    #[cfg(any(target_arch = "x86_64",
              target_arch = "x86",
              target_arch = "arm",
              target_arch = "aarch64",
              target_arch = "mips",
              target_arch = "mipsel",
              target_arch = "powerpc"))]
    const __SIZEOF_PTHREAD_COND_T: usize = 48 - 8;

    #[cfg(any(target_arch = "x86_64",
              target_arch = "aarch64"))]
    const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56 - 8;

    #[cfg(any(target_arch = "x86",
              target_arch = "arm",
              target_arch = "mips",
              target_arch = "mipsel",
              target_arch = "powerpc"))]
    const __SIZEOF_PTHREAD_RWLOCK_T: usize = 32 - 8;

    #[repr(C)]
    pub struct pthread_mutex_t {
        __align: libc::c_longlong,
        size: [u8; __SIZEOF_PTHREAD_MUTEX_T],
    }
    #[repr(C)]
    pub struct pthread_mutexattr_t {
        __align: libc::c_longlong,
        // note, that this is 16 bytes just to be safe, the actual struct might be smaller.
        size: [u8; 16],
    }
    #[repr(C)]
    pub struct pthread_cond_t {
        __align: libc::c_longlong,
        size: [u8; __SIZEOF_PTHREAD_COND_T],
    }
    #[repr(C)]
    pub struct pthread_rwlock_t {
        __align: libc::c_longlong,
        size: [u8; __SIZEOF_PTHREAD_RWLOCK_T],
    }

    pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t {
        __align: 0,
        size: [0; __SIZEOF_PTHREAD_MUTEX_T],
    };
    pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t {
        __align: 0,
        size: [0; __SIZEOF_PTHREAD_COND_T],
    };
    pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t {
        __align: 0,
        size: [0; __SIZEOF_PTHREAD_RWLOCK_T],
    };
    pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 1;
}
#[cfg(target_os = "android")]
mod os {
    use libc;
    use ptr;

    #[repr(C)]
    pub struct pthread_mutex_t { value: libc::c_int }
    pub type pthread_mutexattr_t = libc::c_long;
    #[repr(C)]
    pub struct pthread_cond_t { value: libc::c_int }
    #[repr(C)]
    pub struct pthread_rwlock_t {
        lock: pthread_mutex_t,
        cond: pthread_cond_t,
        numLocks: libc::c_int,
        writerThreadId: libc::c_int,
        pendingReaders: libc::c_int,
        pendingWriters: libc::c_int,
        reserved: [*mut libc::c_void; 4],
    }

    pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t {
        value: 0,
    };
    pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t {
        value: 0,
    };
    pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t {
        lock: PTHREAD_MUTEX_INITIALIZER,
        cond: PTHREAD_COND_INITIALIZER,
        numLocks: 0,
        writerThreadId: 0,
        pendingReaders: 0,
        pendingWriters: 0,
        reserved: [ptr::null_mut(); 4],
    };
    pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 1;
}

#[cfg(target_os = "netbsd")]
mod os {
    use libc;

    // size of the type minus width of the magic int field
    #[cfg(target_arch = "x86_64")]
    const __PTHREAD_MUTEX_SIZE__: usize = 48 - 4;

    #[cfg(target_arch = "x86_64")]
    const __PTHREAD_COND_SIZE__: usize = 40 - 4;

    #[cfg(target_arch = "x86_64")]
    const __PTHREAD_RWLOCK_SIZE__: usize = 64 - 4;

    const _PTHREAD_MUTEX_MAGIC_INIT: libc::c_uint = 0x33330003;
    const _PTHREAD_COND_MAGIC_INIT: libc::c_uint = 0x55550005;
    const _PTHREAD_RWLOCK_MAGIC_INIT: libc::c_uint = 0x99990009;

    // note the actual structs are smaller

    #[repr(C, packed)]
    pub struct pthread_mutex_t {
        __magic: libc::c_uint,
        __opaque: [u8; __PTHREAD_MUTEX_SIZE__],
    }
    #[repr(C, packed)]
    pub struct pthread_mutexattr_t {
        __opaque: [u8; 16],
    }
    #[repr(C, packed)]
    pub struct pthread_cond_t {
        __magic: libc::c_uint,
        __opaque: [u8; __PTHREAD_COND_SIZE__],
    }
    #[repr(C, packed)]
    pub struct pthread_rwlock_t {
        __magic: libc::c_uint,
        __opaque: [u8; __PTHREAD_RWLOCK_SIZE__],
    }

    pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t {
        __magic: _PTHREAD_MUTEX_MAGIC_INIT,
        __opaque: [0; __PTHREAD_MUTEX_SIZE__],
    };
    pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t {
        __magic: _PTHREAD_COND_MAGIC_INIT,
        __opaque: [0; __PTHREAD_COND_SIZE__],
    };
    pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t {
        __magic: _PTHREAD_RWLOCK_MAGIC_INIT,
        __opaque: [0; __PTHREAD_RWLOCK_SIZE__],
    };

    pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 2;
}
<commit_msg>Fix alignment of pthread types on NetBSD<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(bad_style)]

use libc;

pub use self::os::{PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_RECURSIVE, pthread_mutex_t,
                   pthread_mutexattr_t};
pub use self::os::{PTHREAD_COND_INITIALIZER, pthread_cond_t};
pub use self::os::{PTHREAD_RWLOCK_INITIALIZER, pthread_rwlock_t};

extern {
    // mutexes
    pub fn pthread_mutex_init(lock: *mut pthread_mutex_t, attr: *const pthread_mutexattr_t)
                            -> libc::c_int;
    pub fn pthread_mutex_destroy(lock: *mut pthread_mutex_t) -> libc::c_int;
    pub fn pthread_mutex_lock(lock: *mut pthread_mutex_t) -> libc::c_int;
    pub fn pthread_mutex_trylock(lock: *mut pthread_mutex_t) -> libc::c_int;
    pub fn pthread_mutex_unlock(lock: *mut pthread_mutex_t) -> libc::c_int;

    pub fn pthread_mutexattr_init(attr: *mut pthread_mutexattr_t) -> libc::c_int;
    pub fn pthread_mutexattr_destroy(attr: *mut pthread_mutexattr_t) -> libc::c_int;
    pub fn pthread_mutexattr_settype(attr: *mut pthread_mutexattr_t, _type: libc::c_int)
                                    -> libc::c_int;

    // cvars
    pub fn pthread_cond_wait(cond: *mut pthread_cond_t,
                             lock: *mut pthread_mutex_t) -> libc::c_int;
    pub fn pthread_cond_timedwait(cond: *mut pthread_cond_t,
                              lock: *mut pthread_mutex_t,
                              abstime: *const libc::timespec) -> libc::c_int;
    pub fn pthread_cond_signal(cond: *mut pthread_cond_t) -> libc::c_int;
    pub fn pthread_cond_broadcast(cond: *mut pthread_cond_t) -> libc::c_int;
    pub fn pthread_cond_destroy(cond: *mut pthread_cond_t) -> libc::c_int;
    #[cfg_attr(target_os = "netbsd", link_name = "__gettimeofday50")]
    pub fn gettimeofday(tp: *mut libc::timeval,
                        tz: *mut libc::c_void) -> libc::c_int;

    // rwlocks
    pub fn pthread_rwlock_destroy(lock: *mut pthread_rwlock_t) -> libc::c_int;
    pub fn pthread_rwlock_rdlock(lock: *mut pthread_rwlock_t) -> libc::c_int;
    pub fn pthread_rwlock_tryrdlock(lock: *mut pthread_rwlock_t) -> libc::c_int;
    pub fn pthread_rwlock_wrlock(lock: *mut pthread_rwlock_t) -> libc::c_int;
    pub fn pthread_rwlock_trywrlock(lock: *mut pthread_rwlock_t) -> libc::c_int;
    pub fn pthread_rwlock_unlock(lock: *mut pthread_rwlock_t) -> libc::c_int;
}

#[cfg(any(target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "bitrig",
          target_os = "openbsd"))]
mod os {
    use libc;
    use ptr;

    pub type pthread_mutex_t = *mut libc::c_void;
    pub type pthread_mutexattr_t = *mut libc::c_void;
    pub type pthread_cond_t = *mut libc::c_void;
    pub type pthread_rwlock_t = *mut libc::c_void;

    pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = ptr::null_mut();
    pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = ptr::null_mut();
    pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = ptr::null_mut();
    pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 2;
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
mod os {
    use libc;

    #[cfg(any(target_arch = "x86_64",
              target_arch = "aarch64"))]
    const __PTHREAD_MUTEX_SIZE__: usize = 56;
    #[cfg(any(target_arch = "x86",
              target_arch = "arm"))]
    const __PTHREAD_MUTEX_SIZE__: usize = 40;

    #[cfg(any(target_arch = "x86_64",
              target_arch = "aarch64"))]
    const __PTHREAD_COND_SIZE__: usize = 40;
    #[cfg(any(target_arch = "x86",
              target_arch = "arm"))]
    const __PTHREAD_COND_SIZE__: usize = 24;

    #[cfg(any(target_arch = "x86_64",
              target_arch = "aarch64"))]
    const __PTHREAD_RWLOCK_SIZE__: usize = 192;
    #[cfg(any(target_arch = "x86",
              target_arch = "arm"))]
    const __PTHREAD_RWLOCK_SIZE__: usize = 124;

    const _PTHREAD_MUTEX_SIG_INIT: libc::c_long = 0x32AAABA7;
    const _PTHREAD_COND_SIG_INIT: libc::c_long = 0x3CB0B1BB;
    const _PTHREAD_RWLOCK_SIG_INIT: libc::c_long = 0x2DA8B3B4;

    #[repr(C)]
    pub struct pthread_mutex_t {
        __sig: libc::c_long,
        __opaque: [u8; __PTHREAD_MUTEX_SIZE__],
    }
    #[repr(C)]
    pub struct pthread_mutexattr_t {
        __sig: libc::c_long,
        // note, that this is 16 bytes just to be safe, the actual struct might be smaller.
        __opaque: [u8; 16],
    }
    #[repr(C)]
    pub struct pthread_cond_t {
        __sig: libc::c_long,
        __opaque: [u8; __PTHREAD_COND_SIZE__],
    }
    #[repr(C)]
    pub struct pthread_rwlock_t {
        __sig: libc::c_long,
        __opaque: [u8; __PTHREAD_RWLOCK_SIZE__],
    }

    pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t {
        __sig: _PTHREAD_MUTEX_SIG_INIT,
        __opaque: [0; __PTHREAD_MUTEX_SIZE__],
    };
    pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t {
        __sig: _PTHREAD_COND_SIG_INIT,
        __opaque: [0; __PTHREAD_COND_SIZE__],
    };
    pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t {
        __sig: _PTHREAD_RWLOCK_SIG_INIT,
        __opaque: [0; __PTHREAD_RWLOCK_SIZE__],
    };

    pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 2;
}

#[cfg(target_os = "linux")]
mod os {
    use libc;

    // minus 8 because we have an 'align' field
    #[cfg(target_arch = "x86_64")]
    const __SIZEOF_PTHREAD_MUTEX_T: usize = 40 - 8;
    #[cfg(any(target_arch = "x86",
              target_arch = "arm",
              target_arch = "mips",
              target_arch = "mipsel",
              target_arch = "powerpc"))]
    const __SIZEOF_PTHREAD_MUTEX_T: usize = 24 - 8;
    #[cfg(target_arch = "aarch64")]
    const __SIZEOF_PTHREAD_MUTEX_T: usize = 48 - 8;

    #[cfg(any(target_arch = "x86_64",
              target_arch = "x86",
              target_arch = "arm",
              target_arch = "aarch64",
              target_arch = "mips",
              target_arch = "mipsel",
              target_arch = "powerpc"))]
    const __SIZEOF_PTHREAD_COND_T: usize = 48 - 8;

    #[cfg(any(target_arch = "x86_64",
              target_arch = "aarch64"))]
    const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56 - 8;

    #[cfg(any(target_arch = "x86",
              target_arch = "arm",
              target_arch = "mips",
              target_arch = "mipsel",
              target_arch = "powerpc"))]
    const __SIZEOF_PTHREAD_RWLOCK_T: usize = 32 - 8;

    #[repr(C)]
    pub struct pthread_mutex_t {
        __align: libc::c_longlong,
        size: [u8; __SIZEOF_PTHREAD_MUTEX_T],
    }
    #[repr(C)]
    pub struct pthread_mutexattr_t {
        __align: libc::c_longlong,
        // note, that this is 16 bytes just to be safe, the actual struct might be smaller.
        size: [u8; 16],
    }
    #[repr(C)]
    pub struct pthread_cond_t {
        __align: libc::c_longlong,
        size: [u8; __SIZEOF_PTHREAD_COND_T],
    }
    #[repr(C)]
    pub struct pthread_rwlock_t {
        __align: libc::c_longlong,
        size: [u8; __SIZEOF_PTHREAD_RWLOCK_T],
    }

    pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t {
        __align: 0,
        size: [0; __SIZEOF_PTHREAD_MUTEX_T],
    };
    pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t {
        __align: 0,
        size: [0; __SIZEOF_PTHREAD_COND_T],
    };
    pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t {
        __align: 0,
        size: [0; __SIZEOF_PTHREAD_RWLOCK_T],
    };
    pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 1;
}
#[cfg(target_os = "android")]
mod os {
    use libc;
    use ptr;

    #[repr(C)]
    pub struct pthread_mutex_t { value: libc::c_int }
    pub type pthread_mutexattr_t = libc::c_long;
    #[repr(C)]
    pub struct pthread_cond_t { value: libc::c_int }
    #[repr(C)]
    pub struct pthread_rwlock_t {
        lock: pthread_mutex_t,
        cond: pthread_cond_t,
        numLocks: libc::c_int,
        writerThreadId: libc::c_int,
        pendingReaders: libc::c_int,
        pendingWriters: libc::c_int,
        reserved: [*mut libc::c_void; 4],
    }

    pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t {
        value: 0,
    };
    pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t {
        value: 0,
    };
    pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t {
        lock: PTHREAD_MUTEX_INITIALIZER,
        cond: PTHREAD_COND_INITIALIZER,
        numLocks: 0,
        writerThreadId: 0,
        pendingReaders: 0,
        pendingWriters: 0,
        reserved: [ptr::null_mut(); 4],
    };
    pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 1;
}

#[cfg(target_os = "netbsd")]
mod os {
    use libc;

    // size of the type minus width of the magic and alignment field
    #[cfg(target_arch = "x86_64")]
    const __PTHREAD_MUTEX_SIZE__: usize = 48 - 4 - 8;

    #[cfg(target_arch = "x86_64")]
    const __PTHREAD_MUTEXATTR_SIZE__: usize = 16 - 8; // no magic field

    #[cfg(target_arch = "x86_64")]
    const __PTHREAD_COND_SIZE__: usize = 40 - 4 - 8;

    #[cfg(target_arch = "x86_64")]
    const __PTHREAD_RWLOCK_SIZE__: usize = 64 - 4 - 8;

    const _PTHREAD_MUTEX_MAGIC_INIT: libc::c_uint = 0x33330003;
    const _PTHREAD_COND_MAGIC_INIT: libc::c_uint = 0x55550005;
    const _PTHREAD_RWLOCK_MAGIC_INIT: libc::c_uint = 0x99990009;

    #[repr(C)]
    pub struct pthread_mutex_t {
        __magic: libc::c_uint,
        __opaque: [u8; __PTHREAD_MUTEX_SIZE__],
        __align: libc::c_longlong,
    }
    #[repr(C)]
    pub struct pthread_mutexattr_t {
        __opaque: [u8; __PTHREAD_MUTEXATTR_SIZE__],
        __align: libc::c_longlong,
    }
    #[repr(C)]
    pub struct pthread_cond_t {
        __magic: libc::c_uint,
        __opaque: [u8; __PTHREAD_COND_SIZE__],
        __align: libc::c_longlong,
    }
    #[repr(C)]
    pub struct pthread_rwlock_t {
        __magic: libc::c_uint,
        __opaque: [u8; __PTHREAD_RWLOCK_SIZE__],
        __align: libc::c_longlong,
    }

    pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t {
        __magic: _PTHREAD_MUTEX_MAGIC_INIT,
        __opaque: [0; __PTHREAD_MUTEX_SIZE__],
        __align: 0,
    };
    pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t {
        __magic: _PTHREAD_COND_MAGIC_INIT,
        __opaque: [0; __PTHREAD_COND_SIZE__],
        __align: 0,
    };
    pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t {
        __magic: _PTHREAD_RWLOCK_MAGIC_INIT,
        __opaque: [0; __PTHREAD_RWLOCK_SIZE__],
        __align: 0,
    };

    pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 2;
}
<|endoftext|>


<commit_before>fn is_prime(number: i32) -> bool {
    if number % 2 == 0 && number != 2 {
        return false;
    }

    let limit = (number as f32).sqrt() as i32 + 1;

    // We test if the number is divisible by any odd number up to the limit
    (3..limit).step_by(2).all(|x| number % x != 0)
}

fn main() {
    println!("{}", is_prime(15_485_863)); // The 1 000 000th prime.
    println!("{}", is_prime(62_773_913)); // The product of the 1000th and 1001st primes.
}

#[test]
fn test_one() {
    assert!(is_prime(1));
}

#[test]
fn test_two() {
    assert!(is_prime(2));
}

#[test]
fn test_many() {
    let primes = [3, 5, 7, 11, 13, 17, 19, 23, 29, 31];
    assert!(primes.iter().all(|&x| is_prime(x)));
}
<commit_msg>assert that 1 is not prime<commit_after>fn is_prime(number: i32) -> bool {
    if number % 2 == 0 && number != 2 || number == 1 {
        return false;
    }

    let limit = (number as f32).sqrt() as i32 + 1;

    // We test if the number is divisible by any odd number up to the limit
    (3..limit).step_by(2).all(|x| number % x != 0)
}

fn main() {
    println!("{}", is_prime(15_485_863)); // The 1 000 000th prime.
    println!("{}", is_prime(62_773_913)); // The product of the 1000th and 1001st primes.
}

#[test]
fn test_one() {
    // https://primes.utm.edu/notes/faq/one.html
    assert!(!is_prime(1));
}

#[test]
fn test_two() {
    assert!(is_prime(2));
}

#[test]
fn test_many() {
    let primes = [3, 5, 7, 11, 13, 17, 19, 23, 29, 31];
    assert!(primes.iter().all(|&x| is_prime(x)));
}
<|endoftext|>


<commit_before>#![macro_escape]

macro_rules!  format (
    ($($arg:tt)*) => (
        format_args!(::std::fmt::format, $($arg)*)
    )
);

macro_rules! write(
    ($dst:expr, $($arg:tt)*) => ({
        let dst = &mut *$dst;
        format_args!(|args| { dst.write_fmt(args) }, $($arg)*)
    })
);

macro_rules! println(
    ($($arg:tt)*) => (format_args!(::std::io::stdio::println_args, $($arg)*))
);

macro_rules! cstr(
    ($str:expr) => (
        concat!($str, "\0").as_ptr() as *const ::libc::c_char
    )
);

macro_rules! panic(
    () => ({
        panic!("explicit panic")
    });
    ($msg:expr) => ({
        // static requires less code at runtime, more constant data
        static _FILE_LINE: (&'static str, uint) = (file!(), line!());
        ::log::log(
            concat!(file!(), ":", line!(), ": ", $msg),
            ::android::log::ANDROID_LOG_FATAL);
        ::std::rt::begin_unwind($msg, &_FILE_LINE)
    });
    ($fmt:expr, $($arg:tt)*) => ({
        // a closure can't have return type !, so we need a full
        // function to pass to format_args!, *and* we need the
        // file and line numbers right here; so an inner bare fn
        // is our only choice.
        //
        // LLVM doesn't tend to inline this, presumably because begin_unwind_fmt
        // is #[cold] and #[inline(never)] and because this is flagged as cold
        // as returning !. We really do want this to be inlined, however,
        // because it's just a tiny wrapper. Small wins (156K to 149K in size)
        // were seen when forcing this to be inlined, and that number just goes
        // up with the number of calls to panic!()
        //
        // The leading _'s are to avoid dead code warnings if this is
        // used inside a dead function. Just `#[allow(dead_code)]` is
        // insufficient, since the user may have
        // `#[forbid(dead_code)]` and which cannot be overridden.
        #[inline(always)]
        fn _run_fmt(fmt: &::std::fmt::Arguments) -> ! {
            static _FILE_LINE: (&'static str, uint) = (file!(), line!());
            ::std::rt::begin_unwind_fmt(fmt, &_FILE_LINE)
        }
        ::log::log(
            format!(concat!(file!(), ":", line!(), ": ", $fmt), $($arg)*).as_slice(),
            ::android::log::ANDROID_LOG_FATAL);
        format_args!(_run_fmt, $fmt, $($arg)*)
    });
);

macro_rules! try(
    ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
);

macro_rules! try_opt(
    ($e:expr) => (match $e { Some(e) => e, None => return None })
);

macro_rules! assert(
    ($cond:expr) => (
        if !$cond {
            panic!(concat!(": assertion failed: ", stringify!($cond)))
        }
    );
    ($cond:expr, $($arg:expr),+) => (
        if !$cond {
            panic!($($arg),+)
        }
    );
);

macro_rules! debug_assert(
    ($($arg:tt)*) => (if cfg!(not(ndebug)) { assert!($($arg)*); })
);

macro_rules! assert_eq(
    ($given:expr , $expected:expr) => ({
        match (&($given), &($expected)) {
            (given_val, expected_val) => {
                // check both directions of equality....
                if !((*given_val == *expected_val) &&
                     (*expected_val == *given_val)) {
                    panic!("assertion failed: `(left == right) && (right == left)` \
                           (left: `{}`, right: `{}`)", *given_val, *expected_val)
                }
            }
        }
    })
);
<commit_msg>update macros<commit_after>#![macro_escape]

macro_rules! format {
    ($($arg:tt)*) => ($crate::fmt::format(format_args!($($arg)*)))
}

macro_rules! write {
    ($dst:expr, $($arg:tt)*) => ((&mut *$dst).write_fmt(format_args!($($arg)*)))
}

macro_rules! println {
    ($($arg:tt)*) => ($crate::io::stdio::println_args(format_args!($($arg)*)))
}

macro_rules! cstr {
    ($str:expr) => ({
        concat!($str, "\0").as_ptr() as *const ::libc::c_char
    })
}

macro_rules! panic {
    () => ({
        panic!("explicit panic")
    });
    ($msg:expr) => ({
        $crate::rt::begin_unwind($msg, {
            // static requires less code at runtime, more constant data
            static _FILE_LINE: (&'static str, usize) = (file!(), line!());
            &_FILE_LINE
        })
    });
    ($fmt:expr, $($arg:tt)+) => ({
        $crate::rt::begin_unwind_fmt(format_args!($fmt, $($arg)+), {
            // The leading _'s are to avoid dead code warnings if this is
            // used inside a dead function. Just `#[allow(dead_code)]` is
            // insufficient, since the user may have
            // `#[forbid(dead_code)]` and which cannot be overridden.
            ::log::log(
                format!(concat!(file!(), ":", line!(), ": ", $fmt), $($arg)*).as_slice(),
                ::android::log::ANDROID_LOG_FATAL);
            static _FILE_LINE: (&'static str, usize) = (file!(), line!());
            &_FILE_LINE
        })
    });
}

macro_rules! try {
    ($expr:expr) => (match $expr {
        $crate::result::Result::Ok(val) => val,
        $crate::result::Result::Err(err) => {
            return $crate::result::Result::Err($crate::error::FromError::from_error(err))
        }
    })
}

macro_rules! try_opt(
    ($e:expr) => (match $e { Some(e) => e, None => return None })
);

macro_rules! assert {
    ($cond:expr) => (
        if !$cond {
            panic!(concat!("assertion failed: ", stringify!($cond)))
        }
    );
    ($cond:expr, $($arg:tt)+) => (
        if !$cond {
            panic!($($arg)+)
        }
    );
}

macro_rules! debug_assert {
    ($($arg:tt)*) => (if cfg!(not(ndebug)) { assert!($($arg)*); })
}

macro_rules! assert_eq {
    ($left:expr , $right:expr) => ({
        match (&($left), &($right)) {
            (left_val, right_val) => {
                // check both directions of equality....
                if !((*left_val == *right_val) &&
                     (*right_val == *left_val)) {
                    panic!("assertion failed: `(left == right) && (right == left)` \
                           (left: `{:?}`, right: `{:?}`)", *left_val, *right_val)
                }
            }
        }
    })
}
<|endoftext|>


<commit_before>extern crate twig;

use twig::node::{ Expr, ExprValue, ExprConstant };
use twig::Environment;
use twig::Lexer;
use twig::node::Module;
use twig::parser::{ Context, Parse };

#[test]
fn test_string_expression() {
    for (template, expected) in get_tests_for_string() {
        let env = Environment::default().init_all();
        let lexer = Lexer::default(&env.lexing);
        let mut tokens = lexer.tokens(&template);
        let mut context = Context::new(&env.parsing, &mut tokens);
        let module = match Module::parse(&mut context) {
            Ok(m) => m,
            Err(e) => panic!("parsing error: {:?}", e),
        };
        assert_eq!(module.body.expect_print(), &expected);
    }
}

fn get_tests_for_string<'r>() -> Vec<(&'static str, Expr<'r>)> {
    vec![
        (r#"{{ "foo" }}"#, Expr::new_str_constant("foo", 1)),
        (r#"{{ "foo #{bar}" }}"#, Expr::new_at(ExprValue::Concat {
            left: Box::new(Expr::new_str_constant("foo ", 1)),
            right: Box::new(Expr::new_name("bar", 1)),
        }, 1)),
        (r#"{{ "foo #{bar} baz" }}"#, Expr::new_at(ExprValue::Concat {
            left: Box::new(Expr::new_at(ExprValue::Concat {
                left: Box::new(Expr::new_str_constant("foo ", 1)),
                right: Box::new(Expr::new_name("bar", 1)),
            }, 1)),
            right: Box::new(Expr::new_str_constant(" baz", 1)),
        }, 1)),
    ]
}
<commit_msg>Pass string expression tests.<commit_after>extern crate twig;

use twig::node::{ Expr, ExprValue };
use twig::Environment;
use twig::Lexer;
use twig::node::Module;
use twig::parser::{ Context, Parse };

#[test]
fn test_string_expression() {
    for (template, expected) in get_tests_for_string() {
        let env = Environment::default().init_all();
        let lexer = Lexer::default(&env.lexing);
        let mut tokens = lexer.tokens(&template);
        let mut context = Context::new(&env.parsing, &mut tokens);
        let module = match Module::parse(&mut context) {
            Ok(m) => m,
            Err(e) => panic!("parsing error: {:?}", e),
        };
        assert_eq!(module.body.expect_print(), &expected);
    }
}

fn get_tests_for_string<'r>() -> Vec<(&'static str, Expr<'r>)> {
    vec![
        (r#"{{ "foo" }}"#, Expr::new_str_constant("foo", 1)),
        (r#"{{ "foo #{bar}" }}"#, Expr::new_at(ExprValue::Concat {
            left: Box::new(Expr::new_str_constant("foo ", 1)),
            right: Box::new(Expr::new_name("bar", 1)),
        }, 1)),
        (r#"{{ "foo #{bar} baz" }}"#, Expr::new_at(ExprValue::Concat {
            left: Box::new(Expr::new_at(ExprValue::Concat {
                left: Box::new(Expr::new_str_constant("foo ", 1)),
                right: Box::new(Expr::new_name("bar", 1)),
            }, 1)),
            right: Box::new(Expr::new_str_constant(" baz", 1)),
        }, 1)),
        (r#"{{ "foo #{"foo #{bar} baz"} baz" }}"#, Expr::new_at(ExprValue::Concat {
            left: Box::new(Expr::new_at(ExprValue::Concat {
                left: Box::new(Expr::new_str_constant("foo ", 1)),
                right: Box::new(Expr::new_at(ExprValue::Concat {
                    left: Box::new(Expr::new_at(ExprValue::Concat {
                        left: Box::new(Expr::new_str_constant("foo ", 1)),
                        right: Box::new(Expr::new_name("bar", 1)),
                    }, 1)),
                    right: Box::new(Expr::new_str_constant(" baz", 1)),
                }, 1)),
            }, 1)),
            right: Box::new(Expr::new_str_constant(" baz", 1)),
        }, 1)),
    ]
}
<|endoftext|>


<commit_before>//! Defines database & queries for macro expansion.

use std::sync::Arc;

use mbe::MacroRules;
use ra_db::{salsa, SourceDatabase};
use ra_parser::FragmentKind;
use ra_prof::profile;
use ra_syntax::{AstNode, Parse, SyntaxKind::*, SyntaxNode};

use crate::{
    ast_id_map::AstIdMap, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallLoc, EagerMacroId,
    HirFileId, HirFileIdRepr, LazyMacroId, MacroCallId, MacroCallLoc, MacroDefId, MacroDefKind,
    MacroFile,
};

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum TokenExpander {
    MacroRules(mbe::MacroRules),
    Builtin(BuiltinFnLikeExpander),
    BuiltinDerive(BuiltinDeriveExpander),
}

impl TokenExpander {
    pub fn expand(
        &self,
        db: &dyn AstDatabase,
        id: LazyMacroId,
        tt: &tt::Subtree,
    ) -> Result<tt::Subtree, mbe::ExpandError> {
        match self {
            TokenExpander::MacroRules(it) => it.expand(tt),
            TokenExpander::Builtin(it) => it.expand(db, id, tt),
            TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt),
        }
    }

    pub fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId {
        match self {
            TokenExpander::MacroRules(it) => it.map_id_down(id),
            TokenExpander::Builtin(..) => id,
            TokenExpander::BuiltinDerive(..) => id,
        }
    }

    pub fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) {
        match self {
            TokenExpander::MacroRules(it) => it.map_id_up(id),
            TokenExpander::Builtin(..) => (id, mbe::Origin::Call),
            TokenExpander::BuiltinDerive(..) => (id, mbe::Origin::Call),
        }
    }
}

// FIXME: rename to ExpandDatabase
#[salsa::query_group(AstDatabaseStorage)]
pub trait AstDatabase: SourceDatabase {
    fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>;

    #[salsa::transparent]
    fn parse_or_expand(&self, file_id: HirFileId) -> Option<SyntaxNode>;

    #[salsa::interned]
    fn intern_macro(&self, macro_call: MacroCallLoc) -> LazyMacroId;
    fn macro_arg(&self, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>>;
    fn macro_def(&self, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>>;
    fn parse_macro(&self, macro_file: MacroFile)
        -> Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>;
    fn macro_expand(&self, macro_call: MacroCallId) -> Result<Arc<tt::Subtree>, String>;

    #[salsa::interned]
    fn intern_eager_expansion(&self, eager: EagerCallLoc) -> EagerMacroId;
}

pub(crate) fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> {
    let map =
        db.parse_or_expand(file_id).map_or_else(AstIdMap::default, |it| AstIdMap::from_source(&it));
    Arc::new(map)
}

pub(crate) fn macro_def(
    db: &dyn AstDatabase,
    id: MacroDefId,
) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> {
    match id.kind {
        MacroDefKind::Declarative => {
            let macro_call = id.ast_id?.to_node(db);
            let arg = macro_call.token_tree()?;
            let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| {
                log::warn!("fail on macro_def to token tree: {:#?}", arg);
                None
            })?;
            let rules = match MacroRules::parse(&tt) {
                Ok(it) => it,
                Err(err) => {
                    log::warn!("fail on macro_def parse: error: {:#?} {:#?}", err, tt);
                    return None;
                }
            };
            Some(Arc::new((TokenExpander::MacroRules(rules), tmap)))
        }
        MacroDefKind::BuiltIn(expander) => {
            Some(Arc::new((TokenExpander::Builtin(expander), mbe::TokenMap::default())))
        }
        MacroDefKind::BuiltInDerive(expander) => {
            Some(Arc::new((TokenExpander::BuiltinDerive(expander), mbe::TokenMap::default())))
        }
        MacroDefKind::BuiltInEager(_expander) => None,
    }
}

pub(crate) fn macro_arg(
    db: &dyn AstDatabase,
    id: MacroCallId,
) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> {
    let id = match id {
        MacroCallId::LazyMacro(id) => id,
        MacroCallId::EagerMacro(_id) => {
            // FIXME: support macro_arg for eager macro
            return None;
        }
    };
    let loc = db.lookup_intern_macro(id);
    let arg = loc.kind.arg(db)?;
    let (tt, tmap) = mbe::syntax_node_to_token_tree(&arg)?;
    Some(Arc::new((tt, tmap)))
}

pub(crate) fn macro_expand(
    db: &dyn AstDatabase,
    id: MacroCallId,
) -> Result<Arc<tt::Subtree>, String> {
    macro_expand_with_arg(db, id, None)
}

// TODO hack
pub fn expander(
    db: &dyn AstDatabase,
    id: MacroCallId,
) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> {
    let lazy_id = match id {
        MacroCallId::LazyMacro(id) => id,
        MacroCallId::EagerMacro(_id) => {
            // TODO
            unimplemented!()
        }
    };

    let loc = db.lookup_intern_macro(lazy_id);
    let macro_rules = db.macro_def(loc.def)?;
    Some(macro_rules)
}

pub(crate) fn macro_expand_with_arg(
    db: &dyn AstDatabase,
    id: MacroCallId,
    arg: Option<Arc<(tt::Subtree, mbe::TokenMap)>>,
) -> Result<Arc<tt::Subtree>, String> {
    let lazy_id = match id {
        MacroCallId::LazyMacro(id) => id,
        MacroCallId::EagerMacro(id) => {
            // TODO
            return Ok(db.lookup_intern_eager_expansion(id).subtree);
        }
    };

    let loc = db.lookup_intern_macro(lazy_id);
    let macro_arg = arg.or_else(|| db.macro_arg(id)).ok_or("Fail to args in to tt::TokenTree")?;

    let macro_rules = db.macro_def(loc.def).ok_or("Fail to find macro definition")?;
    let tt = macro_rules.0.expand(db, lazy_id, &macro_arg.0).map_err(|err| format!("{:?}", err))?;
    // Set a hard limit for the expanded tt
    let count = tt.count();
    if count > 65536 {
        return Err(format!("Total tokens count exceed limit : count = {}", count));
    }
    Ok(Arc::new(tt))
}

pub(crate) fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNode> {
    match file_id.0 {
        HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()),
        HirFileIdRepr::MacroFile(macro_file) => {
            db.parse_macro(macro_file).map(|(it, _)| it.syntax_node())
        }
    }
}

pub(crate) fn parse_macro(
    db: &dyn AstDatabase,
    macro_file: MacroFile,
) -> Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)> {
    parse_macro_with_arg(db, macro_file, None)
}

pub fn parse_macro_with_arg(
    db: &dyn AstDatabase,
    macro_file: MacroFile,
    arg: Option<Arc<(tt::Subtree, mbe::TokenMap)>>,
) -> Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)> {
    let _p = profile("parse_macro_query");

    let macro_call_id = macro_file.macro_call_id;
    let expansion = if let Some(arg) = arg {
        macro_expand_with_arg(db, macro_call_id, Some(arg))
    } else {
        db.macro_expand(macro_call_id)
    };
    let tt = expansion
        .map_err(|err| {
            // Note:
            // The final goal we would like to make all parse_macro success,
            // such that the following log will not call anyway.
            match macro_call_id {
                MacroCallId::LazyMacro(id) => {
                    let loc: MacroCallLoc = db.lookup_intern_macro(id);
                    let node = loc.kind.node(db);

                    // collect parent information for warning log
                    let parents = std::iter::successors(loc.kind.file_id().call_node(db), |it| {
                        it.file_id.call_node(db)
                    })
                    .map(|n| format!("{:#}", n.value))
                    .collect::<Vec<_>>()
                    .join("\n");

                    eprintln!(
                        "fail on macro_parse: (reason: {} macro_call: {:#}) parents: {}",
                        err, node.value, parents
                    );
                }
                _ => {
                    eprintln!("fail on macro_parse: (reason: {})", err);
                }
            }
        })
        .ok()?;

    let fragment_kind = to_fragment_kind(db, macro_call_id);

    let (parse, rev_token_map) = mbe::token_tree_to_syntax_node(&tt, fragment_kind).ok()?;
    Some((parse, Arc::new(rev_token_map)))
}

/// Given a `MacroCallId`, return what `FragmentKind` it belongs to.
/// FIXME: Not completed
fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind {
    let lazy_id = match id {
        MacroCallId::LazyMacro(id) => id,
        MacroCallId::EagerMacro(id) => {
            return db.lookup_intern_eager_expansion(id).fragment;
        }
    };
    let syn = db.lookup_intern_macro(lazy_id).kind.node(db).value;

    let parent = match syn.parent() {
        Some(it) => it,
        None => {
            // FIXME:
            // If it is root, which means the parent HirFile
            // MacroKindFile must be non-items
            // return expr now.
            return FragmentKind::Expr;
        }
    };

    match parent.kind() {
        MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items,
        ITEM_LIST => FragmentKind::Items,
        LET_STMT => {
            // FIXME: Handle Pattern
            FragmentKind::Expr
        }
        // FIXME: Expand to statements in appropriate positions; HIR lowering needs to handle that
        EXPR_STMT | BLOCK => FragmentKind::Expr,
        ARG_LIST => FragmentKind::Expr,
        TRY_EXPR => FragmentKind::Expr,
        TUPLE_EXPR => FragmentKind::Expr,
        PAREN_EXPR => FragmentKind::Expr,

        FOR_EXPR => FragmentKind::Expr,
        PATH_EXPR => FragmentKind::Expr,
        LAMBDA_EXPR => FragmentKind::Expr,
        CONDITION => FragmentKind::Expr,
        BREAK_EXPR => FragmentKind::Expr,
        RETURN_EXPR => FragmentKind::Expr,
        BLOCK_EXPR => FragmentKind::Expr,
        MATCH_EXPR => FragmentKind::Expr,
        MATCH_ARM => FragmentKind::Expr,
        MATCH_GUARD => FragmentKind::Expr,
        RECORD_FIELD => FragmentKind::Expr,
        CALL_EXPR => FragmentKind::Expr,
        INDEX_EXPR => FragmentKind::Expr,
        METHOD_CALL_EXPR => FragmentKind::Expr,
        AWAIT_EXPR => FragmentKind::Expr,
        CAST_EXPR => FragmentKind::Expr,
        REF_EXPR => FragmentKind::Expr,
        PREFIX_EXPR => FragmentKind::Expr,
        RANGE_EXPR => FragmentKind::Expr,
        BIN_EXPR => FragmentKind::Expr,
        _ => {
            // Unknown , Just guess it is `Items`
            FragmentKind::Items
        }
    }
}
<commit_msg>Remove TODOs<commit_after>//! Defines database & queries for macro expansion.

use std::sync::Arc;

use mbe::MacroRules;
use ra_db::{salsa, SourceDatabase};
use ra_parser::FragmentKind;
use ra_prof::profile;
use ra_syntax::{AstNode, Parse, SyntaxKind::*, SyntaxNode};

use crate::{
    ast_id_map::AstIdMap, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallLoc, EagerMacroId,
    HirFileId, HirFileIdRepr, LazyMacroId, MacroCallId, MacroCallLoc, MacroDefId, MacroDefKind,
    MacroFile,
};

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum TokenExpander {
    MacroRules(mbe::MacroRules),
    Builtin(BuiltinFnLikeExpander),
    BuiltinDerive(BuiltinDeriveExpander),
}

impl TokenExpander {
    pub fn expand(
        &self,
        db: &dyn AstDatabase,
        id: LazyMacroId,
        tt: &tt::Subtree,
    ) -> Result<tt::Subtree, mbe::ExpandError> {
        match self {
            TokenExpander::MacroRules(it) => it.expand(tt),
            TokenExpander::Builtin(it) => it.expand(db, id, tt),
            TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt),
        }
    }

    pub fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId {
        match self {
            TokenExpander::MacroRules(it) => it.map_id_down(id),
            TokenExpander::Builtin(..) => id,
            TokenExpander::BuiltinDerive(..) => id,
        }
    }

    pub fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) {
        match self {
            TokenExpander::MacroRules(it) => it.map_id_up(id),
            TokenExpander::Builtin(..) => (id, mbe::Origin::Call),
            TokenExpander::BuiltinDerive(..) => (id, mbe::Origin::Call),
        }
    }
}

// FIXME: rename to ExpandDatabase
#[salsa::query_group(AstDatabaseStorage)]
pub trait AstDatabase: SourceDatabase {
    fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>;

    #[salsa::transparent]
    fn parse_or_expand(&self, file_id: HirFileId) -> Option<SyntaxNode>;

    #[salsa::interned]
    fn intern_macro(&self, macro_call: MacroCallLoc) -> LazyMacroId;
    fn macro_arg(&self, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>>;
    fn macro_def(&self, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>>;
    fn parse_macro(&self, macro_file: MacroFile)
        -> Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>;
    fn macro_expand(&self, macro_call: MacroCallId) -> Result<Arc<tt::Subtree>, String>;

    #[salsa::interned]
    fn intern_eager_expansion(&self, eager: EagerCallLoc) -> EagerMacroId;
}

pub(crate) fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> {
    let map =
        db.parse_or_expand(file_id).map_or_else(AstIdMap::default, |it| AstIdMap::from_source(&it));
    Arc::new(map)
}

pub(crate) fn macro_def(
    db: &dyn AstDatabase,
    id: MacroDefId,
) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> {
    match id.kind {
        MacroDefKind::Declarative => {
            let macro_call = id.ast_id?.to_node(db);
            let arg = macro_call.token_tree()?;
            let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| {
                log::warn!("fail on macro_def to token tree: {:#?}", arg);
                None
            })?;
            let rules = match MacroRules::parse(&tt) {
                Ok(it) => it,
                Err(err) => {
                    log::warn!("fail on macro_def parse: error: {:#?} {:#?}", err, tt);
                    return None;
                }
            };
            Some(Arc::new((TokenExpander::MacroRules(rules), tmap)))
        }
        MacroDefKind::BuiltIn(expander) => {
            Some(Arc::new((TokenExpander::Builtin(expander), mbe::TokenMap::default())))
        }
        MacroDefKind::BuiltInDerive(expander) => {
            Some(Arc::new((TokenExpander::BuiltinDerive(expander), mbe::TokenMap::default())))
        }
        MacroDefKind::BuiltInEager(_expander) => None,
    }
}

pub(crate) fn macro_arg(
    db: &dyn AstDatabase,
    id: MacroCallId,
) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> {
    let id = match id {
        MacroCallId::LazyMacro(id) => id,
        MacroCallId::EagerMacro(_id) => {
            // FIXME: support macro_arg for eager macro
            return None;
        }
    };
    let loc = db.lookup_intern_macro(id);
    let arg = loc.kind.arg(db)?;
    let (tt, tmap) = mbe::syntax_node_to_token_tree(&arg)?;
    Some(Arc::new((tt, tmap)))
}

pub(crate) fn macro_expand(
    db: &dyn AstDatabase,
    id: MacroCallId,
) -> Result<Arc<tt::Subtree>, String> {
    macro_expand_with_arg(db, id, None)
}

pub fn expander(
    db: &dyn AstDatabase,
    id: MacroCallId,
) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> {
    let lazy_id = match id {
        MacroCallId::LazyMacro(id) => id,
        MacroCallId::EagerMacro(_id) => {
            return None;
        }
    };

    let loc = db.lookup_intern_macro(lazy_id);
    let macro_rules = db.macro_def(loc.def)?;
    Some(macro_rules)
}

pub(crate) fn macro_expand_with_arg(
    db: &dyn AstDatabase,
    id: MacroCallId,
    arg: Option<Arc<(tt::Subtree, mbe::TokenMap)>>,
) -> Result<Arc<tt::Subtree>, String> {
    let lazy_id = match id {
        MacroCallId::LazyMacro(id) => id,
        MacroCallId::EagerMacro(id) => {
            if arg.is_some() {
                return Err("hypothetical macro expansion not implemented for eager macro".to_owned());
            } else {
                return Ok(db.lookup_intern_eager_expansion(id).subtree);
            }
        }
    };

    let loc = db.lookup_intern_macro(lazy_id);
    let macro_arg = arg.or_else(|| db.macro_arg(id)).ok_or("Fail to args in to tt::TokenTree")?;

    let macro_rules = db.macro_def(loc.def).ok_or("Fail to find macro definition")?;
    let tt = macro_rules.0.expand(db, lazy_id, &macro_arg.0).map_err(|err| format!("{:?}", err))?;
    // Set a hard limit for the expanded tt
    let count = tt.count();
    if count > 65536 {
        return Err(format!("Total tokens count exceed limit : count = {}", count));
    }
    Ok(Arc::new(tt))
}

pub(crate) fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNode> {
    match file_id.0 {
        HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()),
        HirFileIdRepr::MacroFile(macro_file) => {
            db.parse_macro(macro_file).map(|(it, _)| it.syntax_node())
        }
    }
}

pub(crate) fn parse_macro(
    db: &dyn AstDatabase,
    macro_file: MacroFile,
) -> Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)> {
    parse_macro_with_arg(db, macro_file, None)
}

pub fn parse_macro_with_arg(
    db: &dyn AstDatabase,
    macro_file: MacroFile,
    arg: Option<Arc<(tt::Subtree, mbe::TokenMap)>>,
) -> Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)> {
    let _p = profile("parse_macro_query");

    let macro_call_id = macro_file.macro_call_id;
    let expansion = if let Some(arg) = arg {
        macro_expand_with_arg(db, macro_call_id, Some(arg))
    } else {
        db.macro_expand(macro_call_id)
    };
    let tt = expansion
        .map_err(|err| {
            // Note:
            // The final goal we would like to make all parse_macro success,
            // such that the following log will not call anyway.
            match macro_call_id {
                MacroCallId::LazyMacro(id) => {
                    let loc: MacroCallLoc = db.lookup_intern_macro(id);
                    let node = loc.kind.node(db);

                    // collect parent information for warning log
                    let parents = std::iter::successors(loc.kind.file_id().call_node(db), |it| {
                        it.file_id.call_node(db)
                    })
                    .map(|n| format!("{:#}", n.value))
                    .collect::<Vec<_>>()
                    .join("\n");

                    eprintln!(
                        "fail on macro_parse: (reason: {} macro_call: {:#}) parents: {}",
                        err, node.value, parents
                    );
                }
                _ => {
                    eprintln!("fail on macro_parse: (reason: {})", err);
                }
            }
        })
        .ok()?;

    let fragment_kind = to_fragment_kind(db, macro_call_id);

    let (parse, rev_token_map) = mbe::token_tree_to_syntax_node(&tt, fragment_kind).ok()?;
    Some((parse, Arc::new(rev_token_map)))
}

/// Given a `MacroCallId`, return what `FragmentKind` it belongs to.
/// FIXME: Not completed
fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind {
    let lazy_id = match id {
        MacroCallId::LazyMacro(id) => id,
        MacroCallId::EagerMacro(id) => {
            return db.lookup_intern_eager_expansion(id).fragment;
        }
    };
    let syn = db.lookup_intern_macro(lazy_id).kind.node(db).value;

    let parent = match syn.parent() {
        Some(it) => it,
        None => {
            // FIXME:
            // If it is root, which means the parent HirFile
            // MacroKindFile must be non-items
            // return expr now.
            return FragmentKind::Expr;
        }
    };

    match parent.kind() {
        MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items,
        ITEM_LIST => FragmentKind::Items,
        LET_STMT => {
            // FIXME: Handle Pattern
            FragmentKind::Expr
        }
        // FIXME: Expand to statements in appropriate positions; HIR lowering needs to handle that
        EXPR_STMT | BLOCK => FragmentKind::Expr,
        ARG_LIST => FragmentKind::Expr,
        TRY_EXPR => FragmentKind::Expr,
        TUPLE_EXPR => FragmentKind::Expr,
        PAREN_EXPR => FragmentKind::Expr,

        FOR_EXPR => FragmentKind::Expr,
        PATH_EXPR => FragmentKind::Expr,
        LAMBDA_EXPR => FragmentKind::Expr,
        CONDITION => FragmentKind::Expr,
        BREAK_EXPR => FragmentKind::Expr,
        RETURN_EXPR => FragmentKind::Expr,
        BLOCK_EXPR => FragmentKind::Expr,
        MATCH_EXPR => FragmentKind::Expr,
        MATCH_ARM => FragmentKind::Expr,
        MATCH_GUARD => FragmentKind::Expr,
        RECORD_FIELD => FragmentKind::Expr,
        CALL_EXPR => FragmentKind::Expr,
        INDEX_EXPR => FragmentKind::Expr,
        METHOD_CALL_EXPR => FragmentKind::Expr,
        AWAIT_EXPR => FragmentKind::Expr,
        CAST_EXPR => FragmentKind::Expr,
        REF_EXPR => FragmentKind::Expr,
        PREFIX_EXPR => FragmentKind::Expr,
        RANGE_EXPR => FragmentKind::Expr,
        BIN_EXPR => FragmentKind::Expr,
        _ => {
            // Unknown , Just guess it is `Items`
            FragmentKind::Items
        }
    }
}
<|endoftext|>


<commit_before>extern crate ra_syntax;
#[macro_use]
extern crate test_utils;
extern crate walkdir;

use std::{
    fmt::Write,
    fs,
    path::{Path, PathBuf, Component},
};

use ra_syntax::{
    utils::{check_fuzz_invariants, dump_tree},
    SourceFileNode,
};

#[test]
fn lexer_tests() {
    dir_tests(&["lexer"], |text, _| {
        let tokens = ra_syntax::tokenize(text);
        dump_tokens(&tokens, text)
    })
}

#[test]
fn parser_tests() {
    dir_tests(&["parser/inline/ok", "parser/ok"], |text, path| {
        let file = SourceFileNode::parse(text);
        let errors = file.errors();
        assert_eq!(
            &*errors,
            &[] as &[ra_syntax::SyntaxError],
            "There should be no errors in the file {:?}",
            path.display()
        );
        dump_tree(file.syntax())
    });
    dir_tests(&["parser/err", "parser/inline/err"], |text, path| {
        let file = SourceFileNode::parse(text);
        let errors = file.errors();
        assert_ne!(
            &*errors,
            &[] as &[ra_syntax::SyntaxError],
            "There should be errors in the file {:?}",
            path.display()
        );
        dump_tree(file.syntax())
    });
}

#[test]
fn parser_fuzz_tests() {
    for (_, text) in collect_tests(&["parser/fuzz-failures"]) {
        check_fuzz_invariants(&text)
    }
}

/// Test that Rust-analyzer can parse and validate the rust-analyser
/// TODO: Use this as a benchmark
#[test]
fn self_hosting_parsing() {
    use std::ffi::OsStr;
    let dir = project_dir().join("crates");
    let mut count = 0;
    for entry in walkdir::WalkDir::new(dir)
        .into_iter()
        .filter_entry(|entry| {
            !entry
                .path()
                .components()
                // TODO: this more neatly
                .any(|component| {
                    // Get all files which are not in the crates/ra_syntax/tests/data folder
                    component == Component::Normal(OsStr::new("data"))
                })
        })
        .map(|e| e.unwrap())
        .filter(|entry| {
            // Get all `.rs ` files
            !entry.path().is_dir() && (entry.path().extension() == Some(OsStr::new("rs")))
        })
    {
        count += 1;
        let text = read_text(entry.path());
        let node = SourceFileNode::parse(&text);
        let errors = node.errors();
        assert_eq!(
            &*errors,
            &[],
            "There should be no errors in the file {:?}",
            entry
        );
    }
    assert!(
        count > 30,
        "self_hosting_parsing found too few files - is it running in the right directory?"
    )
}
/// Read file and normalize newlines.
///
/// `rustc` seems to always normalize `\r\n` newlines to `\n`:
///
/// ```
/// let s = "
/// ";
/// assert_eq!(s.as_bytes(), &[10]);
/// ```
///
/// so this should always be correct.
fn read_text(path: &Path) -> String {
    fs::read_to_string(path)
        .expect(&format!("File at {:?} should be valid", path))
        .replace("\r\n", "\n")
}

fn dir_tests<F>(paths: &[&str], f: F)
where
    F: Fn(&str, &Path) -> String,
{
    for (path, input_code) in collect_tests(paths) {
        let parse_tree = f(&input_code, &path);
        let path = path.with_extension("txt");
        if !path.exists() {
            println!("\nfile: {}", path.display());
            println!("No .txt file with expected result, creating...\n");
            println!("{}\n{}", input_code, parse_tree);
            fs::write(&path, &parse_tree).unwrap();
            panic!("No expected result")
        }
        let expected = read_text(&path);
        let expected = expected.as_str();
        let parse_tree = parse_tree.as_str();
        assert_equal_text(expected, parse_tree, &path);
    }
}

const REWRITE: bool = false;

fn assert_equal_text(expected: &str, actual: &str, path: &Path) {
    if expected == actual {
        return;
    }
    let dir = project_dir();
    let pretty_path = path.strip_prefix(&dir).unwrap_or_else(|_| path);
    if expected.trim() == actual.trim() {
        println!("whitespace difference, rewriting");
        println!("file: {}\n", pretty_path.display());
        fs::write(path, actual).unwrap();
        return;
    }
    if REWRITE {
        println!("rewriting {}", pretty_path.display());
        fs::write(path, actual).unwrap();
        return;
    }
    assert_eq_text!(expected, actual, "file: {}", pretty_path.display());
}

fn collect_tests(paths: &[&str]) -> Vec<(PathBuf, String)> {
    paths
        .iter()
        .flat_map(|path| {
            let path = test_data_dir().join(path);
            test_from_dir(&path).into_iter()
        })
        .map(|path| {
            let text = read_text(&path);
            (path, text)
        })
        .collect()
}

fn test_from_dir(dir: &Path) -> Vec<PathBuf> {
    let mut acc = Vec::new();
    for file in fs::read_dir(&dir).unwrap() {
        let file = file.unwrap();
        let path = file.path();
        if path.extension().unwrap_or_default() == "rs" {
            acc.push(path);
        }
    }
    acc.sort();
    acc
}

fn project_dir() -> PathBuf {
    let dir = env!("CARGO_MANIFEST_DIR");
    PathBuf::from(dir)
        .parent()
        .unwrap()
        .parent()
        .unwrap()
        .to_owned()
}

fn test_data_dir() -> PathBuf {
    project_dir().join("crates/ra_syntax/tests/data")
}

fn dump_tokens(tokens: &[ra_syntax::Token], text: &str) -> String {
    let mut acc = String::new();
    let mut offset = 0;
    for token in tokens {
        let len: u32 = token.len.into();
        let len = len as usize;
        let token_text = &text[offset..offset + len];
        offset += len;
        write!(acc, "{:?} {} {:?}\n", token.kind, token.len, token_text).unwrap()
    }
    acc
}
<commit_msg>Remove TODO on self_hosting_parsing<commit_after>extern crate ra_syntax;
#[macro_use]
extern crate test_utils;
extern crate walkdir;

use std::{
    fmt::Write,
    fs,
    path::{Path, PathBuf, Component},
};

use ra_syntax::{
    utils::{check_fuzz_invariants, dump_tree},
    SourceFileNode,
};

#[test]
fn lexer_tests() {
    dir_tests(&["lexer"], |text, _| {
        let tokens = ra_syntax::tokenize(text);
        dump_tokens(&tokens, text)
    })
}

#[test]
fn parser_tests() {
    dir_tests(&["parser/inline/ok", "parser/ok"], |text, path| {
        let file = SourceFileNode::parse(text);
        let errors = file.errors();
        assert_eq!(
            &*errors,
            &[] as &[ra_syntax::SyntaxError],
            "There should be no errors in the file {:?}",
            path.display()
        );
        dump_tree(file.syntax())
    });
    dir_tests(&["parser/err", "parser/inline/err"], |text, path| {
        let file = SourceFileNode::parse(text);
        let errors = file.errors();
        assert_ne!(
            &*errors,
            &[] as &[ra_syntax::SyntaxError],
            "There should be errors in the file {:?}",
            path.display()
        );
        dump_tree(file.syntax())
    });
}

#[test]
fn parser_fuzz_tests() {
    for (_, text) in collect_tests(&["parser/fuzz-failures"]) {
        check_fuzz_invariants(&text)
    }
}

/// Test that Rust-analyzer can parse and validate the rust-analyser
/// TODO: Use this as a benchmark
#[test]
fn self_hosting_parsing() {
    use std::ffi::OsStr;
    let dir = project_dir().join("crates");
    let mut count = 0;
    for entry in walkdir::WalkDir::new(dir)
        .into_iter()
        .filter_entry(|entry| {
            !entry.path().components().any(|component| {
                // Get all files which are not in the crates/ra_syntax/tests/data folder
                component == Component::Normal(OsStr::new("data"))
            })
        })
        .map(|e| e.unwrap())
        .filter(|entry| {
            // Get all `.rs ` files
            !entry.path().is_dir() && (entry.path().extension() == Some(OsStr::new("rs")))
        })
    {
        count += 1;
        let text = read_text(entry.path());
        let node = SourceFileNode::parse(&text);
        let errors = node.errors();
        assert_eq!(
            &*errors,
            &[],
            "There should be no errors in the file {:?}",
            entry
        );
    }
    assert!(
        count > 30,
        "self_hosting_parsing found too few files - is it running in the right directory?"
    )
}
/// Read file and normalize newlines.
///
/// `rustc` seems to always normalize `\r\n` newlines to `\n`:
///
/// ```
/// let s = "
/// ";
/// assert_eq!(s.as_bytes(), &[10]);
/// ```
///
/// so this should always be correct.
fn read_text(path: &Path) -> String {
    fs::read_to_string(path)
        .expect(&format!("File at {:?} should be valid", path))
        .replace("\r\n", "\n")
}

fn dir_tests<F>(paths: &[&str], f: F)
where
    F: Fn(&str, &Path) -> String,
{
    for (path, input_code) in collect_tests(paths) {
        let parse_tree = f(&input_code, &path);
        let path = path.with_extension("txt");
        if !path.exists() {
            println!("\nfile: {}", path.display());
            println!("No .txt file with expected result, creating...\n");
            println!("{}\n{}", input_code, parse_tree);
            fs::write(&path, &parse_tree).unwrap();
            panic!("No expected result")
        }
        let expected = read_text(&path);
        let expected = expected.as_str();
        let parse_tree = parse_tree.as_str();
        assert_equal_text(expected, parse_tree, &path);
    }
}

const REWRITE: bool = false;

fn assert_equal_text(expected: &str, actual: &str, path: &Path) {
    if expected == actual {
        return;
    }
    let dir = project_dir();
    let pretty_path = path.strip_prefix(&dir).unwrap_or_else(|_| path);
    if expected.trim() == actual.trim() {
        println!("whitespace difference, rewriting");
        println!("file: {}\n", pretty_path.display());
        fs::write(path, actual).unwrap();
        return;
    }
    if REWRITE {
        println!("rewriting {}", pretty_path.display());
        fs::write(path, actual).unwrap();
        return;
    }
    assert_eq_text!(expected, actual, "file: {}", pretty_path.display());
}

fn collect_tests(paths: &[&str]) -> Vec<(PathBuf, String)> {
    paths
        .iter()
        .flat_map(|path| {
            let path = test_data_dir().join(path);
            test_from_dir(&path).into_iter()
        })
        .map(|path| {
            let text = read_text(&path);
            (path, text)
        })
        .collect()
}

fn test_from_dir(dir: &Path) -> Vec<PathBuf> {
    let mut acc = Vec::new();
    for file in fs::read_dir(&dir).unwrap() {
        let file = file.unwrap();
        let path = file.path();
        if path.extension().unwrap_or_default() == "rs" {
            acc.push(path);
        }
    }
    acc.sort();
    acc
}

fn project_dir() -> PathBuf {
    let dir = env!("CARGO_MANIFEST_DIR");
    PathBuf::from(dir)
        .parent()
        .unwrap()
        .parent()
        .unwrap()
        .to_owned()
}

fn test_data_dir() -> PathBuf {
    project_dir().join("crates/ra_syntax/tests/data")
}

fn dump_tokens(tokens: &[ra_syntax::Token], text: &str) -> String {
    let mut acc = String::new();
    let mut offset = 0;
    for token in tokens {
        let len: u32 = token.len.into();
        let len = len as usize;
        let token_text = &text[offset..offset + len];
        offset += len;
        write!(acc, "{:?} {} {:?}\n", token.kind, token.len, token_text).unwrap()
    }
    acc
}
<|endoftext|>


<commit_before>use ::Executable;
use ::job_handle::JobHandle;
use ::job_spec::Redirect;
use ::libc::c_int;
use ::libc;
use ::result::ShellError;
use ::result::ShellResult;
use ::result::ShellResultExt;
use ::result::check_errno;
use ::std::collections::HashMap;
use ::std::mem;
use ::std::panic;
use ::std::process;
use ::std::sync::Arc;
use ::std::sync::RwLock;
use ::std::sync::Mutex;
use ::pipe_capture::PipeCapture;

#[derive(Debug)]
struct ChildProcessData {
    pid: c_int,
    has_group: bool
}

#[derive(Debug)]
struct ChildProcess(Option<ChildProcessData>);

impl ChildProcess {
    fn new(pid: c_int) -> ChildProcess {
        ChildProcess(Some(ChildProcessData {
            pid: pid,
            has_group: false
        }))
    }

    fn set_has_group(&mut self, value: bool) {
        self.0.as_mut().unwrap().has_group = value;
    }

    fn signal(&self, sig: c_int) -> ShellResult {
        let data = self.0.as_ref().unwrap();
        let kill_pid = if data.has_group {
            -data.pid
        } else {
            data.pid
        };
        unsafe {
            check_errno("kill", libc::kill(kill_pid, sig))?;
        }
        Ok(())
    }

    fn wait_null(&self) -> ShellResult {
        unsafe {
            let mut info = mem::uninitialized::<libc::siginfo_t>();
            check_errno("waitid",
                        libc::waitid(
                            libc::P_PID,
                            self.0.as_ref().unwrap().pid as u32,
                            &mut info as *mut libc::siginfo_t,
                            libc::WEXITED | libc::WNOWAIT))?;
        }
        Ok(())
    }

    fn wait_mut(&mut self) -> ShellResult {
        let data = mem::replace(&mut self.0, None).unwrap();
        let pid = data.pid;
        loop {
            unsafe {
                let mut status: c_int = 0;
                check_errno("waitpid", libc::waitpid(
                        pid, &mut status as *mut i32, 0))?;
                if libc::WIFEXITED(status) {
                    let code = libc::WEXITSTATUS(status);
                    if code == 0 {
                        return Ok(());
                    } else {
                        return Err(ShellError::Code(code as u8));
                    }
                } else if libc::WIFSIGNALED(status) {
                    let signal = libc::WTERMSIG(status);
                    return Err(ShellError::Signaled(signal));
                }
            }
        }
    }
}

impl Drop for ChildProcess {
    fn drop(&mut self) {
        if self.0.is_none() {
            return;
        }
        self.wait_mut().print_error();
    }
}

/// Managing global child process state.
pub struct ProcessManager {
    children: HashMap<c_int, Arc<RwLock<ChildProcess>>>
}

impl ProcessManager {
    extern fn handle_signal(signal: c_int) {
        ::std::thread::spawn(move || {
            let mut lock = SIGNAL_HANDLER.lock();
            if let Ok(ref mut process_manager) = lock {
                for child in process_manager.children.values() {
                    child.read().unwrap().signal(signal).print_error();
                }
            }
            ::std::process::exit(128 + signal);
        });
    }

    fn new() -> ProcessManager {
        let result = unsafe {
            libc::signal(libc::SIGINT, ProcessManager::handle_signal as usize)
        };
        if result == ::libc::SIG_ERR {
            panic!("signal failed");
        }
        let result = unsafe {
            libc::signal(libc::SIGTERM, ProcessManager::handle_signal as usize)
        };
        if result == ::libc::SIG_ERR {
            panic!("signal failed");
        }
        ProcessManager {
            children: HashMap::new()
        }
    }

    /// Fork new process
    pub fn fork(executor: Box<Executable>, process_group: bool,
                stdin: Redirect, stdout: Redirect, stderr: Redirect)
            -> Result<JobHandle, ShellError> {
        unsafe {
            let mut stdout = match stdout {
                Redirect::Capture => Some(PipeCapture::new()?),
                _ => None
            };
            let pid = {
                let mut lock = SIGNAL_HANDLER.lock().unwrap();
                let pid = check_errno("fork", libc::fork())?;
                if pid != 0 {
                    let mut child = ChildProcess::new(pid);
                    if process_group {
                        check_errno("setpgid", libc::setpgid(pid, 0)).unwrap();
                        child.set_has_group(true);
                    }
                    lock.children.insert(pid, Arc::new(RwLock::new(child)));
                    if let Some(capture) = stdout.as_mut() {
                        capture.start_reading();
                    }
                    return Ok(JobHandle::new(pid, stdout));
                } else {
                    for child in lock.children.drain() {
                        // After fork ChildProcess should not track parent
                        // processes' ChildProcess. Thus we intentionally let
                        // them leaked.
                        mem::forget(child.1);
                    }
                    match stdout {
                        Some(stdout) => stdout.start_writing()?,
                        None => ()
                    }
                }
                pid
            };
            let mutex = Mutex::new(executor);
            let result = panic::catch_unwind(move || { if process_group {
                    check_errno("setpgid", libc::setpgid(pid, 0)).unwrap();
                }
                mutex.lock().unwrap().exec();
            });
            match result {
                Ok(_) => {
                    eprintln!("exec() does not exit the child process");
                    process::exit(1);
                }
                Err(error) => {
                    eprintln!("Child process paniced {:?}", error);
                    process::exit(101);
                }
            }
        }
    }

    pub fn signal(pid: c_int, signal: c_int) -> ShellResult {
        let process_manager = SIGNAL_HANDLER.lock().unwrap();
        let child = process_manager.children.get(&pid).unwrap();
        let child = child.read().unwrap();
        child.signal(signal)
    }

    pub fn wait(pid: c_int) -> ShellResult {
        let child = {
            let process_manager = SIGNAL_HANDLER.lock().unwrap();
            process_manager.children.get(&pid).unwrap().clone()
        };
        child.read().unwrap().wait_null()?;
        // Here child is zonbi state.
        let child = {
            let mut process_manager = SIGNAL_HANDLER.lock().unwrap();
            process_manager.children.remove(&pid).unwrap()
        };
        let mut child = child.write().unwrap();
        child.wait_mut()
    }
}

lazy_static! {
    static ref SIGNAL_HANDLER: Arc<Mutex<ProcessManager>> =
        Arc::new(Mutex::new(ProcessManager::new()));
}
<commit_msg>Remove unnecessary Arc from SIGNAL_HANDLER<commit_after>use ::Executable;
use ::job_handle::JobHandle;
use ::job_spec::Redirect;
use ::libc::c_int;
use ::libc;
use ::result::ShellError;
use ::result::ShellResult;
use ::result::ShellResultExt;
use ::result::check_errno;
use ::std::collections::HashMap;
use ::std::mem;
use ::std::panic;
use ::std::process;
use ::std::sync::Arc;
use ::std::sync::RwLock;
use ::std::sync::Mutex;
use ::pipe_capture::PipeCapture;

#[derive(Debug)]
struct ChildProcessData {
    pid: c_int,
    has_group: bool
}

#[derive(Debug)]
struct ChildProcess(Option<ChildProcessData>);

impl ChildProcess {
    fn new(pid: c_int) -> ChildProcess {
        ChildProcess(Some(ChildProcessData {
            pid: pid,
            has_group: false
        }))
    }

    fn set_has_group(&mut self, value: bool) {
        self.0.as_mut().unwrap().has_group = value;
    }

    fn signal(&self, sig: c_int) -> ShellResult {
        let data = self.0.as_ref().unwrap();
        let kill_pid = if data.has_group {
            -data.pid
        } else {
            data.pid
        };
        unsafe {
            check_errno("kill", libc::kill(kill_pid, sig))?;
        }
        Ok(())
    }

    fn wait_null(&self) -> ShellResult {
        unsafe {
            let mut info = mem::uninitialized::<libc::siginfo_t>();
            check_errno("waitid",
                        libc::waitid(
                            libc::P_PID,
                            self.0.as_ref().unwrap().pid as u32,
                            &mut info as *mut libc::siginfo_t,
                            libc::WEXITED | libc::WNOWAIT))?;
        }
        Ok(())
    }

    fn wait_mut(&mut self) -> ShellResult {
        let data = mem::replace(&mut self.0, None).unwrap();
        let pid = data.pid;
        loop {
            unsafe {
                let mut status: c_int = 0;
                check_errno("waitpid", libc::waitpid(
                        pid, &mut status as *mut i32, 0))?;
                if libc::WIFEXITED(status) {
                    let code = libc::WEXITSTATUS(status);
                    if code == 0 {
                        return Ok(());
                    } else {
                        return Err(ShellError::Code(code as u8));
                    }
                } else if libc::WIFSIGNALED(status) {
                    let signal = libc::WTERMSIG(status);
                    return Err(ShellError::Signaled(signal));
                }
            }
        }
    }
}

impl Drop for ChildProcess {
    fn drop(&mut self) {
        if self.0.is_none() {
            return;
        }
        self.wait_mut().print_error();
    }
}

/// Managing global child process state.
pub struct ProcessManager {
    children: HashMap<c_int, Arc<RwLock<ChildProcess>>>
}

impl ProcessManager {
    extern fn handle_signal(signal: c_int) {
        ::std::thread::spawn(move || {
            let mut lock = SIGNAL_HANDLER.lock();
            if let Ok(ref mut process_manager) = lock {
                for child in process_manager.children.values() {
                    child.read().unwrap().signal(signal).print_error();
                }
            }
            ::std::process::exit(128 + signal);
        });
    }

    fn new() -> ProcessManager {
        let result = unsafe {
            libc::signal(libc::SIGINT, ProcessManager::handle_signal as usize)
        };
        if result == ::libc::SIG_ERR {
            panic!("signal failed");
        }
        let result = unsafe {
            libc::signal(libc::SIGTERM, ProcessManager::handle_signal as usize)
        };
        if result == ::libc::SIG_ERR {
            panic!("signal failed");
        }
        ProcessManager {
            children: HashMap::new()
        }
    }

    /// Fork new process
    pub fn fork(executor: Box<Executable>, process_group: bool,
                stdin: Redirect, stdout: Redirect, stderr: Redirect)
            -> Result<JobHandle, ShellError> {
        unsafe {
            let mut stdout = match stdout {
                Redirect::Capture => Some(PipeCapture::new()?),
                _ => None
            };
            let pid = {
                let mut lock = SIGNAL_HANDLER.lock().unwrap();
                let pid = check_errno("fork", libc::fork())?;
                if pid != 0 {
                    let mut child = ChildProcess::new(pid);
                    if process_group {
                        check_errno("setpgid", libc::setpgid(pid, 0)).unwrap();
                        child.set_has_group(true);
                    }
                    lock.children.insert(pid, Arc::new(RwLock::new(child)));
                    if let Some(capture) = stdout.as_mut() {
                        capture.start_reading();
                    }
                    return Ok(JobHandle::new(pid, stdout));
                } else {
                    for child in lock.children.drain() {
                        // After fork ChildProcess should not track parent
                        // processes' ChildProcess. Thus we intentionally let
                        // them leaked.
                        mem::forget(child.1);
                    }
                    match stdout {
                        Some(stdout) => stdout.start_writing()?,
                        None => ()
                    }
                }
                pid
            };
            let mutex = Mutex::new(executor);
            let result = panic::catch_unwind(move || { if process_group {
                    check_errno("setpgid", libc::setpgid(pid, 0)).unwrap();
                }
                mutex.lock().unwrap().exec();
            });
            match result {
                Ok(_) => {
                    eprintln!("exec() does not exit the child process");
                    process::exit(1);
                }
                Err(error) => {
                    eprintln!("Child process paniced {:?}", error);
                    process::exit(101);
                }
            }
        }
    }

    pub fn signal(pid: c_int, signal: c_int) -> ShellResult {
        let process_manager = SIGNAL_HANDLER.lock().unwrap();
        let child = process_manager.children.get(&pid).unwrap();
        let child = child.read().unwrap();
        child.signal(signal)
    }

    pub fn wait(pid: c_int) -> ShellResult {
        let child = {
            let process_manager = SIGNAL_HANDLER.lock().unwrap();
            process_manager.children.get(&pid).unwrap().clone()
        };
        child.read().unwrap().wait_null()?;
        // Here child is zonbi state.
        let child = {
            let mut process_manager = SIGNAL_HANDLER.lock().unwrap();
            process_manager.children.remove(&pid).unwrap()
        };
        let mut child = child.write().unwrap();
        child.wait_mut()
    }
}

lazy_static! {
    static ref SIGNAL_HANDLER: Mutex<ProcessManager> =
        Mutex::new(ProcessManager::new());
}
<|endoftext|>


<commit_before>pub mod cli {
    use clap::ArgMatches;
    use regex::Regex;

    use runtime::Runtime;

    pub fn get_tags<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> Vec<String> {

        fn reject_if_with_spaces(e: &String) -> bool {
            if e.contains(" ") {
                warn!("Tag contains spaces: '{}'", e);
                false
            } else {
                true
            }
        }

        debug!("Fetching tags from commandline");
        sub.value_of("tags").and_then(|tags| {
            Some(tags.split(",")
                     .into_iter()
                     .map(|s| s.to_string())
                     .filter(|e| reject_if_with_spaces(e))
                     .collect()
              )
        }).or(Some(vec![])).unwrap()
    }

}
<commit_msg>Add documentation on module helper utils<commit_after>/**
 * Utility helpers for CLI
 */
pub mod cli {
    use clap::ArgMatches;
    use regex::Regex;

    use runtime::Runtime;

    /**
     * Get a commandline option "tags" and split the argument by "," to be able to provide a
     * Vec<String> with the argument as array.
     */
    pub fn get_tags<'a>(rt: &Runtime, sub: &ArgMatches<'a, 'a>) -> Vec<String> {

        fn reject_if_with_spaces(e: &String) -> bool {
            if e.contains(" ") {
                warn!("Tag contains spaces: '{}'", e);
                false
            } else {
                true
            }
        }

        debug!("Fetching tags from commandline");
        sub.value_of("tags").and_then(|tags| {
            Some(tags.split(",")
                     .into_iter()
                     .map(|s| s.to_string())
                     .filter(|e| reject_if_with_spaces(e))
                     .collect()
              )
        }).or(Some(vec![])).unwrap()
    }

}
<|endoftext|>