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

#[macro_use]
#[cfg(test)]
extern crate lazy_static;

use std::thread::{self, JoinHandle};
use std::sync::mpsc::{channel, Sender, Receiver, SyncSender, sync_channel};
use std::sync::{Arc, Mutex};
use std::marker::PhantomData;

enum Message {
    NewJob(Thunk<'static>),
    Join,
}

trait FnBox {
    fn call_box(self: Box<Self>);
}

impl<F: FnOnce()> FnBox for F {
    fn call_box(self: Box<F>) {
        (*self)()
    }
}

type Thunk<'a> = Box<FnBox + Send + 'a>;

impl Drop for PoolCache {
    fn drop(&mut self) {
        ::std::mem::replace(&mut self.job_sender, None);
    }
}

pub struct PoolCache {
    threads: Vec<ThreadData>,
    job_sender: Option<Sender<Message>>
}

struct ThreadData {
    _thread_join_handle: JoinHandle<()>,
    pool_sync_rx: Receiver<()>,
    thread_sync_tx: SyncSender<()>,
}

impl PoolCache {
    pub fn new(n: u32) -> PoolCache {
        assert!(n >= 1);

        let (job_sender, job_receiver) = channel();
        let job_receiver = Arc::new(Mutex::new(job_receiver));

        let mut threads = Vec::with_capacity(n as usize);

        // spawn n threads, put them in waiting mode
        for _ in 0..n {
            let job_receiver = job_receiver.clone();

            let (pool_sync_tx, pool_sync_rx) =
                sync_channel::<()>(0);
            let (thread_sync_tx, thread_sync_rx) =
                sync_channel::<()>(0);

            let thread = thread::spawn(move || {
                loop {
                    let message = {
                        // Only lock jobs for the time it takes
                        // to get a job, not run it.
                        let lock = job_receiver.lock().unwrap();
                        lock.recv()
                    };

                    match message {
                        Ok(Message::NewJob(job)) => {
                            job.call_box();
                        }
                        Ok(Message::Join) => {
                            // syncronize with pool
                            if pool_sync_tx.send(()).is_err() {
                                // The pool was dropped.
                                break;
                            }
                            if thread_sync_rx.recv().is_err() {
                                // The pool was dropped.
                                break;
                            }
                        }
                        Err(..) => {
                            // The pool was dropped.
                            break
                        }
                    }
                }
            });

            threads.push(ThreadData {
                _thread_join_handle: thread,
                pool_sync_rx: pool_sync_rx,
                thread_sync_tx: thread_sync_tx,
            });
        }

        PoolCache {
            threads: threads,
            job_sender: Some(job_sender),
        }
    }

    pub fn scope<'pool, 'scope, F, R>(&'pool mut self, f: F) -> R
        where F: FnOnce(&Scope<'pool, 'scope>) -> R
    {
        let scope = Scope {
            pool: self,
            _marker: PhantomData,
        };
        f(&scope)
    }

    pub fn thread_count(&self) -> u32 {
        self.threads.len() as u32
    }
}

/////////////////////////////////////////////////////////////////////////////

pub struct Scope<'pool, 'scope> {
    pool: &'pool mut PoolCache,
    _marker: PhantomData<&'scope mut ()>,
}

impl<'pool, 'scope> Scope<'pool, 'scope> {
    pub fn execute<F>(&self, f: F)
        where F: FnOnce() + Send + 'scope
    {
        let b = unsafe {
            ::std::mem::transmute::<Thunk<'scope>, Thunk<'static>>(Box::new(f))
        };
        self.pool.job_sender.as_ref().unwrap().send(Message::NewJob(b)).unwrap();
    }
}

impl<'pool, 'scope> Drop for Scope<'pool, 'scope> {
    fn drop(&mut self) {
        for _ in 0..self.pool.threads.len() {
            self.pool.job_sender.as_ref().unwrap().send(Message::Join).unwrap();
        }

        // syncronize with threads
        for thread_data in &self.pool.threads {
            thread_data.pool_sync_rx.recv().unwrap();
        }
        for thread_data in &self.pool.threads {
            thread_data.thread_sync_tx.send(()).unwrap();
        }
    }
}

/////////////////////////////////////////////////////////////////////////////

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

    #[test]
    fn example() {
        // Create a threadpool holding 4 threads
        let mut pool = PoolCache::new(4);

        let mut vec = vec![0, 1, 2, 3, 4, 5, 6, 7];

        // Use the threads as scoped threads that can
        // reference anything outside this closure
        pool.scope(|scoped| {

            // Create references to each element in the vector ...
            for e in &mut vec {
                // ... and add 1 to it in a seperate thread
                scoped.execute(move || {
                    *e += 1;
                });
            }
        });

        assert_eq!(vec, vec![1, 2, 3, 4, 5, 6, 7, 8]);
    }

    #[test]
    fn smoketest() {
        let mut pool = PoolCache::new(4);

        for i in 1..7 {
            let mut vec = vec![0, 1, 2, 3, 4];
            pool.scope(|s| {
                for e in vec.iter_mut() {
                    s.execute(move || {
                        *e += i;
                    });
                }
            });

            let mut vec2 = vec![0, 1, 2, 3, 4];
            for e in vec2.iter_mut() {
                *e += i;
            }

            assert_eq!(vec, vec2);
        }
    }

    #[test]
    #[should_panic]
    fn thread_panic() {
        let mut pool = PoolCache::new(4);
        pool.scope(|scoped| {
            scoped.execute(move || {
                panic!()
            });
        });
    }

    #[test]
    #[should_panic]
    fn pool_panic() {
        let _pool = PoolCache::new(4);
        panic!()
    }
}

#[cfg(all(test, feature="nightly"))]
mod benches {
    extern crate test;

    use self::test::{Bencher, black_box};
    use super::PoolCache;
    use std::sync::Mutex;

    // const MS_SLEEP_PER_OP: u32 = 1;

    lazy_static! {
        static ref POOL_1: Mutex<PoolCache> = Mutex::new(PoolCache::new(1));
        static ref POOL_2: Mutex<PoolCache> = Mutex::new(PoolCache::new(2));
        static ref POOL_3: Mutex<PoolCache> = Mutex::new(PoolCache::new(3));
        static ref POOL_4: Mutex<PoolCache> = Mutex::new(PoolCache::new(4));
        static ref POOL_5: Mutex<PoolCache> = Mutex::new(PoolCache::new(5));
        static ref POOL_8: Mutex<PoolCache> = Mutex::new(PoolCache::new(8));
    }

    fn fib(n: u64) -> u64 {
        let mut prev_prev: u64 = 1;
        let mut prev = 1;
        let mut current = 1;
        for _ in 2..(n+1) {
            current = prev_prev.wrapping_add(prev);
            prev_prev = prev;
            prev = current;
        }
        current
    }

    fn threads_interleaved_n(pool: &mut PoolCache)  {
        let size = 1024; // 1kiB

        let mut data = vec![1u8; size];
        pool.scope(|s| {
            for e in data.iter_mut() {
                s.execute(move || {
                    *e += fib(black_box(1000 * (*e as u64))) as u8;
                    //thread::sleep_ms(MS_SLEEP_PER_OP);
                });
            }
        });
    }

    #[bench]
    fn threads_interleaved_1(b: &mut Bencher) {
        b.iter(|| threads_interleaved_n(&mut POOL_1.lock().unwrap()))
    }

    #[bench]
    fn threads_interleaved_2(b: &mut Bencher) {
        b.iter(|| threads_interleaved_n(&mut POOL_2.lock().unwrap()))
    }

    #[bench]
    fn threads_interleaved_4(b: &mut Bencher) {
        b.iter(|| threads_interleaved_n(&mut POOL_4.lock().unwrap()))
    }

    #[bench]
    fn threads_interleaved_8(b: &mut Bencher) {
        b.iter(|| threads_interleaved_n(&mut POOL_8.lock().unwrap()))
    }

    fn threads_chunked_n(pool: &mut PoolCache) {
        let size = 1024 * 1024 * 100 / 4; // 100MiB

        let n = pool.thread_count();
        let mut data = vec![0u32; size];
        pool.scope(|s| {
            let l = (data.len() - 1) / n as usize + 1;
            for es in data.chunks_mut(l) {
                s.execute(move || {
                    if es.len() > 1 {
                        es[0] = 1;
                        es[1] = 1;
                        for i in 2..es.len() {
                            // Fibonnaci gets big fast,
                            // so just wrap around all the time
                            es[i] = es[i-1].wrapping_add(es[i-2]);
                        }
                    }
                    //thread::sleep_ms(MS_SLEEP_PER_OP);
                });
            }
        });
    }

    #[bench]
    fn threads_chunked_1(b: &mut Bencher) {
        b.iter(|| threads_chunked_n(&mut POOL_1.lock().unwrap()))
    }

    #[bench]
    fn threads_chunked_2(b: &mut Bencher) {
        b.iter(|| threads_chunked_n(&mut POOL_2.lock().unwrap()))
    }

    #[bench]
    fn threads_chunked_3(b: &mut Bencher) {
        b.iter(|| threads_chunked_n(&mut POOL_3.lock().unwrap()))
    }

    #[bench]
    fn threads_chunked_4(b: &mut Bencher) {
        b.iter(|| threads_chunked_n(&mut POOL_4.lock().unwrap()))
    }

    #[bench]
    fn threads_chunked_5(b: &mut Bencher) {
        b.iter(|| threads_chunked_n(&mut POOL_5.lock().unwrap()))
    }

    #[bench]
    fn threads_chunked_8(b: &mut Bencher) {
        b.iter(|| threads_chunked_n(&mut POOL_8.lock().unwrap()))
    }
}
<commit_msg>Messing around with benchmarks<commit_after>#![cfg_attr(all(feature="nightly", test), feature(test))]
#![cfg_attr(feature="nightly", feature(const_fn))]

#[macro_use]
#[cfg(test)]
extern crate lazy_static;

use std::thread::{self, JoinHandle};
use std::sync::mpsc::{channel, Sender, Receiver, SyncSender, sync_channel};
use std::sync::{Arc, Mutex};
use std::marker::PhantomData;

enum Message {
    NewJob(Thunk<'static>),
    Join,
}

trait FnBox {
    fn call_box(self: Box<Self>);
}

impl<F: FnOnce()> FnBox for F {
    fn call_box(self: Box<F>) {
        (*self)()
    }
}

type Thunk<'a> = Box<FnBox + Send + 'a>;

impl Drop for PoolCache {
    fn drop(&mut self) {
        ::std::mem::replace(&mut self.job_sender, None);
    }
}

pub struct PoolCache {
    threads: Vec<ThreadData>,
    job_sender: Option<Sender<Message>>
}

struct ThreadData {
    _thread_join_handle: JoinHandle<()>,
    pool_sync_rx: Receiver<()>,
    thread_sync_tx: SyncSender<()>,
}

impl PoolCache {
    pub fn new(n: u32) -> PoolCache {
        assert!(n >= 1);

        let (job_sender, job_receiver) = channel();
        let job_receiver = Arc::new(Mutex::new(job_receiver));

        let mut threads = Vec::with_capacity(n as usize);

        // spawn n threads, put them in waiting mode
        for _ in 0..n {
            let job_receiver = job_receiver.clone();

            let (pool_sync_tx, pool_sync_rx) =
                sync_channel::<()>(0);
            let (thread_sync_tx, thread_sync_rx) =
                sync_channel::<()>(0);

            let thread = thread::spawn(move || {
                loop {
                    let message = {
                        // Only lock jobs for the time it takes
                        // to get a job, not run it.
                        let lock = job_receiver.lock().unwrap();
                        lock.recv()
                    };

                    match message {
                        Ok(Message::NewJob(job)) => {
                            job.call_box();
                        }
                        Ok(Message::Join) => {
                            // syncronize with pool
                            if pool_sync_tx.send(()).is_err() {
                                // The pool was dropped.
                                break;
                            }
                            if thread_sync_rx.recv().is_err() {
                                // The pool was dropped.
                                break;
                            }
                        }
                        Err(..) => {
                            // The pool was dropped.
                            break
                        }
                    }
                }
            });

            threads.push(ThreadData {
                _thread_join_handle: thread,
                pool_sync_rx: pool_sync_rx,
                thread_sync_tx: thread_sync_tx,
            });
        }

        PoolCache {
            threads: threads,
            job_sender: Some(job_sender),
        }
    }

    pub fn scope<'pool, 'scope, F, R>(&'pool mut self, f: F) -> R
        where F: FnOnce(&Scope<'pool, 'scope>) -> R
    {
        let scope = Scope {
            pool: self,
            _marker: PhantomData,
        };
        f(&scope)
    }

    pub fn thread_count(&self) -> u32 {
        self.threads.len() as u32
    }
}

/////////////////////////////////////////////////////////////////////////////

pub struct Scope<'pool, 'scope> {
    pool: &'pool mut PoolCache,
    _marker: PhantomData<&'scope mut ()>,
}

impl<'pool, 'scope> Scope<'pool, 'scope> {
    pub fn execute<F>(&self, f: F)
        where F: FnOnce() + Send + 'scope
    {
        let b = unsafe {
            ::std::mem::transmute::<Thunk<'scope>, Thunk<'static>>(Box::new(f))
        };
        self.pool.job_sender.as_ref().unwrap().send(Message::NewJob(b)).unwrap();
    }
}

impl<'pool, 'scope> Drop for Scope<'pool, 'scope> {
    fn drop(&mut self) {
        for _ in 0..self.pool.threads.len() {
            self.pool.job_sender.as_ref().unwrap().send(Message::Join).unwrap();
        }

        // syncronize with threads
        for thread_data in &self.pool.threads {
            thread_data.pool_sync_rx.recv().unwrap();
        }
        for thread_data in &self.pool.threads {
            thread_data.thread_sync_tx.send(()).unwrap();
        }
    }
}

/////////////////////////////////////////////////////////////////////////////

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

    #[test]
    fn example() {
        // Create a threadpool holding 4 threads
        let mut pool = PoolCache::new(4);

        let mut vec = vec![0, 1, 2, 3, 4, 5, 6, 7];

        // Use the threads as scoped threads that can
        // reference anything outside this closure
        pool.scope(|scoped| {

            // Create references to each element in the vector ...
            for e in &mut vec {
                // ... and add 1 to it in a seperate thread
                scoped.execute(move || {
                    *e += 1;
                });
            }
        });

        assert_eq!(vec, vec![1, 2, 3, 4, 5, 6, 7, 8]);
    }

    #[test]
    fn smoketest() {
        let mut pool = PoolCache::new(4);

        for i in 1..7 {
            let mut vec = vec![0, 1, 2, 3, 4];
            pool.scope(|s| {
                for e in vec.iter_mut() {
                    s.execute(move || {
                        *e += i;
                    });
                }
            });

            let mut vec2 = vec![0, 1, 2, 3, 4];
            for e in vec2.iter_mut() {
                *e += i;
            }

            assert_eq!(vec, vec2);
        }
    }

    #[test]
    #[should_panic]
    fn thread_panic() {
        let mut pool = PoolCache::new(4);
        pool.scope(|scoped| {
            scoped.execute(move || {
                panic!()
            });
        });
    }

    #[test]
    #[should_panic]
    fn pool_panic() {
        let _pool = PoolCache::new(4);
        panic!()
    }
}

#[cfg(all(test, feature="nightly"))]
mod benches {
    extern crate test;

    use self::test::{Bencher, black_box};
    use super::PoolCache;
    use std::sync::Mutex;

    // const MS_SLEEP_PER_OP: u32 = 1;

    lazy_static! {
        static ref POOL_1: Mutex<PoolCache> = Mutex::new(PoolCache::new(1));
        static ref POOL_2: Mutex<PoolCache> = Mutex::new(PoolCache::new(2));
        static ref POOL_3: Mutex<PoolCache> = Mutex::new(PoolCache::new(3));
        static ref POOL_4: Mutex<PoolCache> = Mutex::new(PoolCache::new(4));
        static ref POOL_5: Mutex<PoolCache> = Mutex::new(PoolCache::new(5));
        static ref POOL_8: Mutex<PoolCache> = Mutex::new(PoolCache::new(8));
    }

    fn fib(n: u64) -> u64 {
        let mut prev_prev: u64 = 1;
        let mut prev = 1;
        let mut current = 1;
        for _ in 2..(n+1) {
            current = prev_prev.wrapping_add(prev);
            prev_prev = prev;
            prev = current;
        }
        current
    }

    fn threads_interleaved_n(pool: &mut PoolCache)  {
        let size = 1024; // 1kiB

        let mut data = vec![1u8; size];
        pool.scope(|s| {
            for e in data.iter_mut() {
                s.execute(move || {
                    *e += fib(black_box(1000 * (*e as u64))) as u8;
                    for i in 0..10000 { black_box(i); }
                    //thread::sleep_ms(MS_SLEEP_PER_OP);
                });
            }
        });
    }

    #[bench]
    fn threads_interleaved_1(b: &mut Bencher) {
        b.iter(|| threads_interleaved_n(&mut POOL_1.lock().unwrap()))
    }

    #[bench]
    fn threads_interleaved_2(b: &mut Bencher) {
        b.iter(|| threads_interleaved_n(&mut POOL_2.lock().unwrap()))
    }

    #[bench]
    fn threads_interleaved_4(b: &mut Bencher) {
        b.iter(|| threads_interleaved_n(&mut POOL_4.lock().unwrap()))
    }

    #[bench]
    fn threads_interleaved_8(b: &mut Bencher) {
        b.iter(|| threads_interleaved_n(&mut POOL_8.lock().unwrap()))
    }

    fn threads_chunked_n(pool: &mut PoolCache) {
        // Set this to 1GB and 40 to get good but slooow results
        let size = 1024 * 1024 * 10 / 4; // 10MiB
        let bb_repeat = 50;

        let n = pool.thread_count();
        let mut data = vec![0u32; size];
        pool.scope(|s| {
            let l = (data.len() - 1) / n as usize + 1;
            for es in data.chunks_mut(l) {
                s.execute(move || {
                    if es.len() > 1 {
                        es[0] = 1;
                        es[1] = 1;
                        for i in 2..es.len() {
                            // Fibonnaci gets big fast,
                            // so just wrap around all the time
                            es[i] = black_box(es[i-1].wrapping_add(es[i-2]));
                            for i in 0..bb_repeat { black_box(i); }
                        }
                    }
                    //thread::sleep_ms(MS_SLEEP_PER_OP);
                });
            }
        });
    }

    #[bench]
    fn threads_chunked_1(b: &mut Bencher) {
        b.iter(|| threads_chunked_n(&mut POOL_1.lock().unwrap()))
    }

    #[bench]
    fn threads_chunked_2(b: &mut Bencher) {
        b.iter(|| threads_chunked_n(&mut POOL_2.lock().unwrap()))
    }

    #[bench]
    fn threads_chunked_3(b: &mut Bencher) {
        b.iter(|| threads_chunked_n(&mut POOL_3.lock().unwrap()))
    }

    #[bench]
    fn threads_chunked_4(b: &mut Bencher) {
        b.iter(|| threads_chunked_n(&mut POOL_4.lock().unwrap()))
    }

    #[bench]
    fn threads_chunked_5(b: &mut Bencher) {
        b.iter(|| threads_chunked_n(&mut POOL_5.lock().unwrap()))
    }

    #[bench]
    fn threads_chunked_8(b: &mut Bencher) {
        b.iter(|| threads_chunked_n(&mut POOL_8.lock().unwrap()))
    }
}
<|endoftext|>


<commit_before>//! A reference-counted pointer that accepts DST: `Rc<str>`, `Rc<[T]>`, `Rc<Fn>`, etc

#![cfg_attr(test, plugin(quickcheck_macros))]
#![deny(missing_docs)]
#![deny(warnings)]
#![feature(alloc)]
#![feature(collections)]
#![feature(convert)]
#![feature(core)]
#![feature(custom_attribute)]
#![feature(filling_drop)]
#![feature(optin_builtin_traits)]
#![feature(plugin)]
#![feature(unsafe_no_drop_flag)]

#[cfg(test)] extern crate quickcheck;
#[cfg(test)] extern crate rand;

extern crate alloc;
extern crate core;

use core::nonzero::NonZero;
use std::borrow::Borrow;
use std::boxed;
use std::cell::Cell;
use std::hash::{Hash, Hasher};
use std::mem;
use std::ops::Deref;

/// A reference-counted pointer type over an immutable value.
///
/// # Examples
///
/// ```
/// # #![feature(convert)]
/// # extern crate rc;
/// # use rc::Rc;
/// # fn main() {
/// let boxed_fn: Box<Fn() -> i32> = Box::new(|| { 0 });
/// //boxed_fn.clone();  //~ error: does not implement `clone`
/// let original: Rc<Fn() -> i32> = Rc::from(boxed_fn);  // moves `boxed_fn`
/// let rc_fn = original.clone();  // increases refcount to 2
///
/// drop(original);  // decreases refcount to 1
///
/// // overloaded calls work with `Rc<Fn(..) -> ..>`s
/// assert_eq!(rc_fn(), 0);
///
/// // `rc_fn` dropped here, refcount reaches zero, `boxed_fn` is deallocated
/// # }
/// ```
///
/// # Layout
///
/// A single layer of indirection.
///
/// ``` text
///    Stack       |   Heap
///                |
///    Rc<str>     |
/// +------------+ |
/// | *mut str   |-|-> "Hello, world!"
/// | *mut usize |-|-> 3
/// +------------+ |
/// ```
///
/// ^ NOTE: `Cell`/`NonZero` wrappers omitted for brevity. String and reference count are not
/// (necessarily) stored in contiguous memory.
///
/// # Size
///
/// For sized types: 2 words, for DST: 3 words.
///
/// ```
/// # extern crate rc;
/// # use std::mem;
/// # use rc::Rc;
/// # fn main() {
/// assert_eq!(mem::size_of::<Rc<()>>(),    2 * mem::size_of::<usize>());
/// assert_eq!(mem::size_of::<Rc<[i32]>>(), 3 * mem::size_of::<usize>());
/// assert_eq!(mem::size_of::<Rc<str>>(),   3 * mem::size_of::<usize>());
/// # }
/// ```
#[unsafe_no_drop_flag]
pub struct Rc<T: ?Sized> {
    /// The number of references
    count: NonZero<*mut Cell<usize>>,
    /// A pointer to the heap allocated data
    data: NonZero<*mut T>,
}

impl<T> Rc<T> {
    /// Creates a new `Rc` pointer.
    ///
    /// NOTE: `value` will be allocated in the heap. If you have a heap allocated value like `Box`,
    /// `String` or `Vec`, use the `Rc::from()` method instead.
    pub fn new(value: T) -> Rc<T> {
        Rc::from(Box::new(value))
    }
}

impl<T: ?Sized> Rc<T> {
    /// Returns the number of references to this value.
    pub fn count(&self) -> usize {
        unsafe {
            (**self.count).get()
        }
    }

    fn dec_count(&self) {
        unsafe {
            (**self.count).set(self.count() - 1)
        }
    }

    fn inc_count(&self) {
        unsafe {
            (**self.count).set(self.count() + 1)
        }
    }
}

impl<T: ?Sized> Borrow<T> for Rc<T> {
    fn borrow(&self) -> &T {
        self
    }
}

impl<T: ?Sized> Clone for Rc<T> {
    fn clone(&self) -> Rc<T> {
        self.inc_count();

        Rc {
            count: self.count,
            data: self.data,
        }
    }
}

impl<T: ?Sized> Eq for Rc<T> where T: Eq {}

impl<'a, T> From<&'a [T]> for Rc<[T]> where T: Clone {
    /// NOTE: This requires allocating the `slice` first (`Vec::to_vec`).
    fn from(slice: &[T]) -> Rc<[T]> {
        Rc::from(slice.to_vec())
    }
}

impl<'a> From<&'a str> for Rc<str> {
    /// NOTE: This requires allocating the `string` first (`String::from_str`).
    fn from(string: &str) -> Rc<str> {
        Rc::from(String::from_str(string))
    }
}

impl<T: ?Sized> From<Box<T>> for Rc<T> {
    /// NOTE: this involves a single, small heap allocation for the reference count. `boxed_value`
    /// will *not* be reallocated.
    fn from(boxed_value: Box<T>) -> Rc<T> {
        unsafe {
            Rc {
                count: NonZero::new(boxed::into_raw(Box::new(Cell::new(1)))),
                data: NonZero::new(boxed::into_raw(boxed_value)),
            }
        }
    }
}

// TODO(rust-lang/rust#18283) use `Rc::from(string.into_boxed_str())` instead of `transmute`
impl From<String> for Rc<str> {
    /// NOTE: This calls `shrink_to_fit` on `string` (on the underlying `Vec<u8>`), which may incur
    /// in a reallocation.
    fn from(string: String) -> Rc<str> {
        // Create a `Rc<[u8]>` first, and then transmute that into a `Rc<str>`
        unsafe {
            mem::transmute(Rc::from(string.into_bytes()))
        }
    }
}

impl<T> From<Vec<T>> for Rc<[T]> {
    /// NOTE: This calls `shrink_to_fit` on `vec`, which may incur in a reallocation.
    fn from(vec: Vec<T>) -> Rc<[T]> {
        Rc::from(vec.into_boxed_slice())
    }
}

impl<T: ?Sized> Deref for Rc<T> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe {
            mem::transmute(*self.data)
        }
    }
}

impl<T: ?Sized> Drop for Rc<T> {
    fn drop(&mut self) {
        let ptr = *self.count;

        if !ptr.is_null() && ptr as usize != mem::POST_DROP_USIZE {
            unsafe {
                self.dec_count();

                if self.count() == 0 {
                    drop(Box::from_raw(*self.count));
                    drop(Box::from_raw(*self.data));
                }
            }
        }
    }
}

impl<T: ?Sized> Hash for Rc<T> where T: Hash {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        Hash::hash(&**self, state)
    }
}

impl<T: ?Sized> PartialEq for Rc<T> where T: PartialEq {
    fn eq(&self, rhs: &Rc<T>) -> bool {
        PartialEq::eq(&**self, &**rhs)
    }
}

impl<T> !Send for Rc<T> {}
impl<T> !Sync for Rc<T> {}

#[cfg(test)]
mod test {
    use rand::{Rng, XorShiftRng, self};
    use quickcheck::TestResult;

    use Rc;

    #[test]
    fn closure_borrow() {
        let i = 0;
        let rc_fn = {
            let boxed_fn: Box<Fn() -> i32> = Box::new(|| { i });
            Rc::from(boxed_fn)
        };

        assert_eq!(rc_fn(), 0);
    }

    #[test]
    fn closure_move() {
        use std::collections::HashMap;

        let mut map = HashMap::new();
        map.insert("A".to_string(), Box::new(0));

        let boxed_fn: Box<Fn(&str) -> i32> = Box::new(move |k| **map.get(k).unwrap());
        let rc_fn = Rc::from(boxed_fn);

        assert_eq!(rc_fn("A"), 0);
    }

    /// `&str` -> `Rc<str>`, where `&str` is not necessarily aligned
    #[quickcheck]
    fn from_str(len: usize, offset: usize, copies: usize) -> TestResult {
        if offset > len {
            return TestResult::discard()
        }

        // create a random string
        let string = rand::thread_rng()
            .gen::<XorShiftRng>()
            .gen_ascii_chars()
            .take(len)
            .collect::<String>();

        // slice the random string
        let str: &str = &string[offset..];
        // create a ref counted string from the slice (this allocates)
        let rcstr = Rc::from(str);

        // create multiple references
        let references = (0..copies).map(|_| rcstr.clone()).collect::<Vec<_>>();

        // drop the original reference
        drop(rcstr);

        // check data integrity
        TestResult::from_bool(references.iter().all(|rcstr| &**rcstr == str))
    }

    /// `String` -> `Rc<str>`, where `String` may have `capacity >= length`
    #[quickcheck]
    fn from_string(cap: usize, len: usize, copies: usize) -> bool {
        // initialize empty string with some reserved capacity
        let mut string = String::with_capacity(cap);

        // push random ascii chars into the string
        for c in rand::thread_rng().gen::<XorShiftRng>().gen_ascii_chars().take(len) {
            string.push(c);
        }

        // create a ref counted string (consumes `string`)
        let original = string.clone();
        let rcstr = Rc::from(string);

        // create multiple owners
        let copies = (0..copies).map(|_| rcstr.clone()).collect::<Vec<_>>();

        // drop original owner
        drop(rcstr);

        // check data integrity
        copies.iter().all(|rcstr| &**rcstr == original)
    }

    /// `Box<Fn(..) -> ..>` -> `Rc<Fn(..) -> ..>`
    #[test]
    fn rc_fn() {
        let trait_object: Box<Fn() -> i32> = Box::new(|| { 0 });
        let rc_fn = Rc::from(trait_object);

        assert_eq!(rc_fn(), 0);
    }

    #[should_panic]
    #[test]
    fn unwind() {
        let str = "Hello, world!";
        let _rc_str_0 = Rc::from(str);
        let _rc_str_1 = Rc::from(str.to_string());
        let slice: &[_] = &[0, 1, 2];
        let _rc_slice_0 = Rc::from(slice);
        let _rc_slice_1 = Rc::from(slice.to_vec());
        let boxed_fn: Box<Fn()> = Box::new(|| {});
        let _rc_fn = Rc::from(boxed_fn);

        panic!();
    }
}
<commit_msg>fix: remove unused feature<commit_after>//! A reference-counted pointer that accepts DST: `Rc<str>`, `Rc<[T]>`, `Rc<Fn>`, etc

#![cfg_attr(test, plugin(quickcheck_macros))]
#![deny(missing_docs)]
#![deny(warnings)]
#![feature(alloc)]
#![feature(collections)]
#![feature(core)]
#![feature(custom_attribute)]
#![feature(filling_drop)]
#![feature(optin_builtin_traits)]
#![feature(plugin)]
#![feature(unsafe_no_drop_flag)]

#[cfg(test)] extern crate quickcheck;
#[cfg(test)] extern crate rand;

extern crate alloc;
extern crate core;

use core::nonzero::NonZero;
use std::borrow::Borrow;
use std::boxed;
use std::cell::Cell;
use std::hash::{Hash, Hasher};
use std::mem;
use std::ops::Deref;

/// A reference-counted pointer type over an immutable value.
///
/// # Examples
///
/// ```
/// # #![feature(convert)]
/// # extern crate rc;
/// # use rc::Rc;
/// # fn main() {
/// let boxed_fn: Box<Fn() -> i32> = Box::new(|| { 0 });
/// //boxed_fn.clone();  //~ error: does not implement `clone`
/// let original: Rc<Fn() -> i32> = Rc::from(boxed_fn);  // moves `boxed_fn`
/// let rc_fn = original.clone();  // increases refcount to 2
///
/// drop(original);  // decreases refcount to 1
///
/// // overloaded calls work with `Rc<Fn(..) -> ..>`s
/// assert_eq!(rc_fn(), 0);
///
/// // `rc_fn` dropped here, refcount reaches zero, `boxed_fn` is deallocated
/// # }
/// ```
///
/// # Layout
///
/// A single layer of indirection.
///
/// ``` text
///    Stack       |   Heap
///                |
///    Rc<str>     |
/// +------------+ |
/// | *mut str   |-|-> "Hello, world!"
/// | *mut usize |-|-> 3
/// +------------+ |
/// ```
///
/// ^ NOTE: `Cell`/`NonZero` wrappers omitted for brevity. String and reference count are not
/// (necessarily) stored in contiguous memory.
///
/// # Size
///
/// For sized types: 2 words, for DST: 3 words.
///
/// ```
/// # extern crate rc;
/// # use std::mem;
/// # use rc::Rc;
/// # fn main() {
/// assert_eq!(mem::size_of::<Rc<()>>(),    2 * mem::size_of::<usize>());
/// assert_eq!(mem::size_of::<Rc<[i32]>>(), 3 * mem::size_of::<usize>());
/// assert_eq!(mem::size_of::<Rc<str>>(),   3 * mem::size_of::<usize>());
/// # }
/// ```
#[unsafe_no_drop_flag]
pub struct Rc<T: ?Sized> {
    /// The number of references
    count: NonZero<*mut Cell<usize>>,
    /// A pointer to the heap allocated data
    data: NonZero<*mut T>,
}

impl<T> Rc<T> {
    /// Creates a new `Rc` pointer.
    ///
    /// NOTE: `value` will be allocated in the heap. If you have a heap allocated value like `Box`,
    /// `String` or `Vec`, use the `Rc::from()` method instead.
    pub fn new(value: T) -> Rc<T> {
        Rc::from(Box::new(value))
    }
}

impl<T: ?Sized> Rc<T> {
    /// Returns the number of references to this value.
    pub fn count(&self) -> usize {
        unsafe {
            (**self.count).get()
        }
    }

    fn dec_count(&self) {
        unsafe {
            (**self.count).set(self.count() - 1)
        }
    }

    fn inc_count(&self) {
        unsafe {
            (**self.count).set(self.count() + 1)
        }
    }
}

impl<T: ?Sized> Borrow<T> for Rc<T> {
    fn borrow(&self) -> &T {
        self
    }
}

impl<T: ?Sized> Clone for Rc<T> {
    fn clone(&self) -> Rc<T> {
        self.inc_count();

        Rc {
            count: self.count,
            data: self.data,
        }
    }
}

impl<T: ?Sized> Eq for Rc<T> where T: Eq {}

impl<'a, T> From<&'a [T]> for Rc<[T]> where T: Clone {
    /// NOTE: This requires allocating the `slice` first (`Vec::to_vec`).
    fn from(slice: &[T]) -> Rc<[T]> {
        Rc::from(slice.to_vec())
    }
}

impl<'a> From<&'a str> for Rc<str> {
    /// NOTE: This requires allocating the `string` first (`String::from_str`).
    fn from(string: &str) -> Rc<str> {
        Rc::from(String::from_str(string))
    }
}

impl<T: ?Sized> From<Box<T>> for Rc<T> {
    /// NOTE: this involves a single, small heap allocation for the reference count. `boxed_value`
    /// will *not* be reallocated.
    fn from(boxed_value: Box<T>) -> Rc<T> {
        unsafe {
            Rc {
                count: NonZero::new(boxed::into_raw(Box::new(Cell::new(1)))),
                data: NonZero::new(boxed::into_raw(boxed_value)),
            }
        }
    }
}

// TODO(rust-lang/rust#18283) use `Rc::from(string.into_boxed_str())` instead of `transmute`
impl From<String> for Rc<str> {
    /// NOTE: This calls `shrink_to_fit` on `string` (on the underlying `Vec<u8>`), which may incur
    /// in a reallocation.
    fn from(string: String) -> Rc<str> {
        // Create a `Rc<[u8]>` first, and then transmute that into a `Rc<str>`
        unsafe {
            mem::transmute(Rc::from(string.into_bytes()))
        }
    }
}

impl<T> From<Vec<T>> for Rc<[T]> {
    /// NOTE: This calls `shrink_to_fit` on `vec`, which may incur in a reallocation.
    fn from(vec: Vec<T>) -> Rc<[T]> {
        Rc::from(vec.into_boxed_slice())
    }
}

impl<T: ?Sized> Deref for Rc<T> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe {
            mem::transmute(*self.data)
        }
    }
}

impl<T: ?Sized> Drop for Rc<T> {
    fn drop(&mut self) {
        let ptr = *self.count;

        if !ptr.is_null() && ptr as usize != mem::POST_DROP_USIZE {
            unsafe {
                self.dec_count();

                if self.count() == 0 {
                    drop(Box::from_raw(*self.count));
                    drop(Box::from_raw(*self.data));
                }
            }
        }
    }
}

impl<T: ?Sized> Hash for Rc<T> where T: Hash {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        Hash::hash(&**self, state)
    }
}

impl<T: ?Sized> PartialEq for Rc<T> where T: PartialEq {
    fn eq(&self, rhs: &Rc<T>) -> bool {
        PartialEq::eq(&**self, &**rhs)
    }
}

impl<T> !Send for Rc<T> {}
impl<T> !Sync for Rc<T> {}

#[cfg(test)]
mod test {
    use rand::{Rng, XorShiftRng, self};
    use quickcheck::TestResult;

    use Rc;

    #[test]
    fn closure_borrow() {
        let i = 0;
        let rc_fn = {
            let boxed_fn: Box<Fn() -> i32> = Box::new(|| { i });
            Rc::from(boxed_fn)
        };

        assert_eq!(rc_fn(), 0);
    }

    #[test]
    fn closure_move() {
        use std::collections::HashMap;

        let mut map = HashMap::new();
        map.insert("A".to_string(), Box::new(0));

        let boxed_fn: Box<Fn(&str) -> i32> = Box::new(move |k| **map.get(k).unwrap());
        let rc_fn = Rc::from(boxed_fn);

        assert_eq!(rc_fn("A"), 0);
    }

    /// `&str` -> `Rc<str>`, where `&str` is not necessarily aligned
    #[quickcheck]
    fn from_str(len: usize, offset: usize, copies: usize) -> TestResult {
        if offset > len {
            return TestResult::discard()
        }

        // create a random string
        let string = rand::thread_rng()
            .gen::<XorShiftRng>()
            .gen_ascii_chars()
            .take(len)
            .collect::<String>();

        // slice the random string
        let str: &str = &string[offset..];
        // create a ref counted string from the slice (this allocates)
        let rcstr = Rc::from(str);

        // create multiple references
        let references = (0..copies).map(|_| rcstr.clone()).collect::<Vec<_>>();

        // drop the original reference
        drop(rcstr);

        // check data integrity
        TestResult::from_bool(references.iter().all(|rcstr| &**rcstr == str))
    }

    /// `String` -> `Rc<str>`, where `String` may have `capacity >= length`
    #[quickcheck]
    fn from_string(cap: usize, len: usize, copies: usize) -> bool {
        // initialize empty string with some reserved capacity
        let mut string = String::with_capacity(cap);

        // push random ascii chars into the string
        for c in rand::thread_rng().gen::<XorShiftRng>().gen_ascii_chars().take(len) {
            string.push(c);
        }

        // create a ref counted string (consumes `string`)
        let original = string.clone();
        let rcstr = Rc::from(string);

        // create multiple owners
        let copies = (0..copies).map(|_| rcstr.clone()).collect::<Vec<_>>();

        // drop original owner
        drop(rcstr);

        // check data integrity
        copies.iter().all(|rcstr| &**rcstr == original)
    }

    /// `Box<Fn(..) -> ..>` -> `Rc<Fn(..) -> ..>`
    #[test]
    fn rc_fn() {
        let trait_object: Box<Fn() -> i32> = Box::new(|| { 0 });
        let rc_fn = Rc::from(trait_object);

        assert_eq!(rc_fn(), 0);
    }

    #[should_panic]
    #[test]
    fn unwind() {
        let str = "Hello, world!";
        let _rc_str_0 = Rc::from(str);
        let _rc_str_1 = Rc::from(str.to_string());
        let slice: &[_] = &[0, 1, 2];
        let _rc_slice_0 = Rc::from(slice);
        let _rc_slice_1 = Rc::from(slice.to_vec());
        let boxed_fn: Box<Fn()> = Box::new(|| {});
        let _rc_fn = Rc::from(boxed_fn);

        panic!();
    }
}
<|endoftext|>


<commit_before>// Copyright 2019 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interface to the operating system's random number generator.
//!
//! # Supported targets
//!
//! | Target           | Implementation
//! |------------------|---------------------------------------------------------
//! | Linux, Android   | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after successfully polling `/dev/random`
//! | Windows          | [`RtlGenRandom`][3]
//! | [Windows UWP][22]| [`BCryptGenRandom`][23]
//! | macOS            | [`getentropy()`][19] if available, otherwise [`/dev/random`][20] (identical to `/dev/urandom`)
//! | iOS              | [`SecRandomCopyBytes`][4]
//! | FreeBSD          | [`getrandom()`][21] if available, otherwise [`kern.arandom`][5]
//! | OpenBSD          | [`getentropy`][6]
//! | NetBSD           | [`kern.arandom`][7]
//! | Dragonfly BSD    | [`/dev/random`][8]
//! | Solaris, illumos | [`getrandom`][9] system call if available, otherwise [`/dev/random`][10]
//! | Fuchsia OS       | [`cprng_draw`][11]
//! | Redox            | [`rand:`][12]
//! | CloudABI         | [`cloudabi_sys_random_get`][13]
//! | Haiku            | `/dev/random` (identical to `/dev/urandom`)
//! | SGX              | [RDRAND][18]
//! | VxWorks          | `randABytes` after checking entropy pool initialization with `randSecure`
//! | Emscripten       | `/dev/random` (identical to `/dev/urandom`)
//! | WASI             | [`__wasi_random_get`][17]
//! | Web Browser      | [`Crypto.getRandomValues()`][14], see [support for WebAssembly][16]
//! | Node.js          | [`crypto.randomBytes`][15], see [support for WebAssembly][16]
//!
//! There is no blanket implementation on `unix` targets that reads from
//! `/dev/urandom`. This ensures all supported targets are using the recommended
//! interface and respect maximum buffer sizes.
//!
//! Pull Requests that add support for new targets to `getrandom` are always welcome.
//!
//! ## Unsupported targets
//!
//! By default, `getrandom` will not compile on unsupported targets, but certain
//! features allow a user to select a "fallback" implementation if no supported
//! implementation exists.
//!
//! All of the below mechanisms only affect unsupported
//! targets. Supported targets will _always_ use their supported implementations.
//! This prevents a crate from overriding a secure source of randomness
//! (either accidentally or intentionally).
//!
//! ### RDRAND on x86
//!
//! *If the `"rdrand"` Cargo feature is enabled*, `getrandom` will fallback to using
//! the [`RDRAND`][18] instruction to get randomness on `no_std` `x86`/`x86_64`
//! targets. This feature has no effect on other CPU architectures.
//!
//! ### Support for WebAssembly
//!
//! This crate fully supports the `wasm32-wasi` and `wasm32-unknown-emscripten`
//! targets. However, the `wasm32-unknown-unknown` target is not supported since,
//! from the target name alone, we cannot deduce which JavaScript interface is
//! in use (or if JavaScript is available at all).
//!
//! Instead, *if the `"js"` Cargo feature is enabled*, this crate will assume
//! that you are building for an environment containing JavaScript, and will
//! call the appropriate methods. Both Browser and Node.js environments are
//! supported (see above), and both [wasm-bindgen] and [stdweb] toolchains are
//! supported.
//!
//! [wasm-bindgen]: https://github.com/rust-lang/rust-bindgen
//! [stdweb]: https://github.com/koute/stdweb
//!
//! ### Use a custom implementation
//!
//! Some external crates define `getrandom` implementations for specific
//! unsupported targets. If you depend on one of these external crates and you
//! are building for an unsupported target, `getrandom` will use this external
//! implementation instead of failing to compile.
//!
//! See [`register_custom_getrandom!`] for information about writing your own
//! custom `getrandom` implementation for an unsupported target.
//!
//! ### Indirect Dependencies
//!
//! If `getrandom` is not a direct dependency of your crate, you can still
//! enable any of above fallback behaviors by simply enabling the relevant
//! feature in your root crate's `[dependencies]` section:
//! ```toml
//! getrandom = { version = "0.2", features = ["rdrand"] }
//! ```
//!
//! ## Early boot
//!
//! Sometimes, early in the boot process, the OS has not collected enough
//! entropy to securely seed its RNG. This is especially common on virtual
//! machines, where standard "random" events are hard to come by.
//!
//! Some operating system interfaces always block until the RNG is securely
//! seeded. This can take anywhere from a few seconds to more than a minute.
//! A few (Linux, NetBSD and Solaris) offer a choice between blocking and
//! getting an error; in these cases, we always choose to block.
//!
//! On Linux (when the `getrandom` system call is not available), reading from
//! `/dev/urandom` never blocks, even when the OS hasn't collected enough
//! entropy yet. To avoid returning low-entropy bytes, we first poll
//! `/dev/random` and only switch to `/dev/urandom` once this has succeeded.
//!
//! ## Error handling
//!
//! We always choose failure over returning insecure "random" bytes. In general,
//! on supported platforms, failure is highly unlikely, though not impossible.
//! If an error does occur, then it is likely that it will occur on every call to
//! `getrandom`, hence after the first successful call one can be reasonably
//! confident that no errors will occur.
//!
//! [1]: http://man7.org/linux/man-pages/man2/getrandom.2.html
//! [2]: http://man7.org/linux/man-pages/man4/urandom.4.html
//! [3]: https://docs.microsoft.com/en-us/windows/desktop/api/ntsecapi/nf-ntsecapi-rtlgenrandom
//! [4]: https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc
//! [5]: https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4
//! [6]: https://man.openbsd.org/getentropy.2
//! [7]: https://netbsd.gw.com/cgi-bin/man-cgi?sysctl+7+NetBSD-8.0
//! [8]: https://leaf.dragonflybsd.org/cgi/web-man?command=random&section=4
//! [9]: https://docs.oracle.com/cd/E88353_01/html/E37841/getrandom-2.html
//! [10]: https://docs.oracle.com/cd/E86824_01/html/E54777/random-7d.html
//! [11]: https://fuchsia.dev/fuchsia-src/zircon/syscalls/cprng_draw
//! [12]: https://github.com/redox-os/randd/blob/master/src/main.rs
//! [13]: https://github.com/nuxinl/cloudabi#random_get
//! [14]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues
//! [15]: https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback
//! [16]: #support-for-webassembly
//! [17]: https://github.com/WebAssembly/WASI/blob/master/design/WASI-core.md#__wasi_random_get
//! [18]: https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide
//! [19]: https://www.unix.com/man-page/mojave/2/getentropy/
//! [20]: https://www.unix.com/man-page/mojave/4/random/
//! [21]: https://www.freebsd.org/cgi/man.cgi?query=getrandom&manpath=FreeBSD+12.0-stable
//! [22]: https://docs.microsoft.com/en-us/windows/uwp/
//! [23]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom

#![doc(
    html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
    html_favicon_url = "https://www.rust-lang.org/favicon.ico",
    html_root_url = "https://rust-random.github.io/rand/"
)]
#![no_std]
#![warn(rust_2018_idioms, unused_lifetimes, missing_docs)]

#[macro_use]
extern crate cfg_if;

mod error;
mod util;
// To prevent a breaking change when targets are added, we always export the
// register_custom_getrandom macro, so old Custom RNG crates continue to build.
#[cfg(feature = "custom")]
mod custom;
#[cfg(feature = "std")]
mod error_impls;

pub use crate::error::Error;

// System-specific implementations.
//
// These should all provide getrandom_inner with the same signature as getrandom.
cfg_if! {
    if #[cfg(any(target_os = "dragonfly", target_os = "emscripten",
                 target_os = "haiku",     target_os = "redox"))] {
        mod util_libc;
        #[path = "use_file.rs"] mod imp;
    } else if #[cfg(any(target_os = "android", target_os = "linux"))] {
        mod util_libc;
        mod use_file;
        #[path = "linux_android.rs"] mod imp;
    } else if #[cfg(any(target_os = "illumos", target_os = "solaris"))] {
        mod util_libc;
        mod use_file;
        #[path = "solaris_illumos.rs"] mod imp;
    } else if #[cfg(any(target_os = "freebsd", target_os = "netbsd"))] {
        mod util_libc;
        #[path = "bsd_arandom.rs"] mod imp;
    } else if #[cfg(target_os = "cloudabi")] {
        #[path = "cloudabi.rs"] mod imp;
    } else if #[cfg(target_os = "fuchsia")] {
        #[path = "fuchsia.rs"] mod imp;
    } else if #[cfg(target_os = "ios")] {
        #[path = "ios.rs"] mod imp;
    } else if #[cfg(target_os = "macos")] {
        mod util_libc;
        mod use_file;
        #[path = "macos.rs"] mod imp;
    } else if #[cfg(target_os = "openbsd")] {
        mod util_libc;
        #[path = "openbsd.rs"] mod imp;
    } else if #[cfg(target_os = "wasi")] {
        #[path = "wasi.rs"] mod imp;
    } else if #[cfg(target_os = "vxworks")] {
        mod util_libc;
        #[path = "vxworks.rs"] mod imp;
    } else if #[cfg(all(windows, target_vendor = "uwp"))] {
        #[path = "windows_uwp.rs"] mod imp;
    } else if #[cfg(windows)] {
        #[path = "windows.rs"] mod imp;
    } else if #[cfg(all(target_arch = "x86_64", target_env = "sgx"))] {
        #[path = "rdrand.rs"] mod imp;
    } else if #[cfg(all(feature = "rdrand",
                        any(target_arch = "x86_64", target_arch = "x86")))] {
        #[path = "rdrand.rs"] mod imp;
    } else if #[cfg(all(feature = "js",
                        target_arch = "wasm32", target_os = "unknown"))] {
        #[cfg_attr(cargo_web, path = "stdweb.rs")]
        #[cfg_attr(not(cargo_web), path = "wasm-bindgen.rs")]
        mod imp;
    } else if #[cfg(feature = "custom")] {
        use custom as imp;
    } else {
        compile_error!("\
            target is not supported, for more information see: \
            https://docs.rs/getrandom/#unsupported-targets\
        ");
    }
}

/// Fill `dest` with random bytes from the system's preferred random number
/// source.
///
/// This function returns an error on any failure, including partial reads. We
/// make no guarantees regarding the contents of `dest` on error. If `dest` is
/// empty, `getrandom` immediately returns success, making no calls to the
/// underlying operating system.
///
/// Blocking is possible, at least during early boot; see module documentation.
///
/// In general, `getrandom` will be fast enough for interactive usage, though
/// significantly slower than a user-space CSPRNG; for the latter consider
/// [`rand::thread_rng`](https://docs.rs/rand/*/rand/fn.thread_rng.html).
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
    if dest.is_empty() {
        return Ok(());
    }
    imp::getrandom_inner(dest)
}

#[cfg(test)]
mod test_common;
#[cfg(test)]
mod test_rdrand;
<commit_msg>Format compile_error!<commit_after>// Copyright 2019 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interface to the operating system's random number generator.
//!
//! # Supported targets
//!
//! | Target           | Implementation
//! |------------------|---------------------------------------------------------
//! | Linux, Android   | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after successfully polling `/dev/random`
//! | Windows          | [`RtlGenRandom`][3]
//! | [Windows UWP][22]| [`BCryptGenRandom`][23]
//! | macOS            | [`getentropy()`][19] if available, otherwise [`/dev/random`][20] (identical to `/dev/urandom`)
//! | iOS              | [`SecRandomCopyBytes`][4]
//! | FreeBSD          | [`getrandom()`][21] if available, otherwise [`kern.arandom`][5]
//! | OpenBSD          | [`getentropy`][6]
//! | NetBSD           | [`kern.arandom`][7]
//! | Dragonfly BSD    | [`/dev/random`][8]
//! | Solaris, illumos | [`getrandom`][9] system call if available, otherwise [`/dev/random`][10]
//! | Fuchsia OS       | [`cprng_draw`][11]
//! | Redox            | [`rand:`][12]
//! | CloudABI         | [`cloudabi_sys_random_get`][13]
//! | Haiku            | `/dev/random` (identical to `/dev/urandom`)
//! | SGX              | [RDRAND][18]
//! | VxWorks          | `randABytes` after checking entropy pool initialization with `randSecure`
//! | Emscripten       | `/dev/random` (identical to `/dev/urandom`)
//! | WASI             | [`__wasi_random_get`][17]
//! | Web Browser      | [`Crypto.getRandomValues()`][14], see [support for WebAssembly][16]
//! | Node.js          | [`crypto.randomBytes`][15], see [support for WebAssembly][16]
//!
//! There is no blanket implementation on `unix` targets that reads from
//! `/dev/urandom`. This ensures all supported targets are using the recommended
//! interface and respect maximum buffer sizes.
//!
//! Pull Requests that add support for new targets to `getrandom` are always welcome.
//!
//! ## Unsupported targets
//!
//! By default, `getrandom` will not compile on unsupported targets, but certain
//! features allow a user to select a "fallback" implementation if no supported
//! implementation exists.
//!
//! All of the below mechanisms only affect unsupported
//! targets. Supported targets will _always_ use their supported implementations.
//! This prevents a crate from overriding a secure source of randomness
//! (either accidentally or intentionally).
//!
//! ### RDRAND on x86
//!
//! *If the `"rdrand"` Cargo feature is enabled*, `getrandom` will fallback to using
//! the [`RDRAND`][18] instruction to get randomness on `no_std` `x86`/`x86_64`
//! targets. This feature has no effect on other CPU architectures.
//!
//! ### Support for WebAssembly
//!
//! This crate fully supports the `wasm32-wasi` and `wasm32-unknown-emscripten`
//! targets. However, the `wasm32-unknown-unknown` target is not supported since,
//! from the target name alone, we cannot deduce which JavaScript interface is
//! in use (or if JavaScript is available at all).
//!
//! Instead, *if the `"js"` Cargo feature is enabled*, this crate will assume
//! that you are building for an environment containing JavaScript, and will
//! call the appropriate methods. Both Browser and Node.js environments are
//! supported (see above), and both [wasm-bindgen] and [stdweb] toolchains are
//! supported.
//!
//! [wasm-bindgen]: https://github.com/rust-lang/rust-bindgen
//! [stdweb]: https://github.com/koute/stdweb
//!
//! ### Use a custom implementation
//!
//! Some external crates define `getrandom` implementations for specific
//! unsupported targets. If you depend on one of these external crates and you
//! are building for an unsupported target, `getrandom` will use this external
//! implementation instead of failing to compile.
//!
//! See [`register_custom_getrandom!`] for information about writing your own
//! custom `getrandom` implementation for an unsupported target.
//!
//! ### Indirect Dependencies
//!
//! If `getrandom` is not a direct dependency of your crate, you can still
//! enable any of above fallback behaviors by simply enabling the relevant
//! feature in your root crate's `[dependencies]` section:
//! ```toml
//! getrandom = { version = "0.2", features = ["rdrand"] }
//! ```
//!
//! ## Early boot
//!
//! Sometimes, early in the boot process, the OS has not collected enough
//! entropy to securely seed its RNG. This is especially common on virtual
//! machines, where standard "random" events are hard to come by.
//!
//! Some operating system interfaces always block until the RNG is securely
//! seeded. This can take anywhere from a few seconds to more than a minute.
//! A few (Linux, NetBSD and Solaris) offer a choice between blocking and
//! getting an error; in these cases, we always choose to block.
//!
//! On Linux (when the `getrandom` system call is not available), reading from
//! `/dev/urandom` never blocks, even when the OS hasn't collected enough
//! entropy yet. To avoid returning low-entropy bytes, we first poll
//! `/dev/random` and only switch to `/dev/urandom` once this has succeeded.
//!
//! ## Error handling
//!
//! We always choose failure over returning insecure "random" bytes. In general,
//! on supported platforms, failure is highly unlikely, though not impossible.
//! If an error does occur, then it is likely that it will occur on every call to
//! `getrandom`, hence after the first successful call one can be reasonably
//! confident that no errors will occur.
//!
//! [1]: http://man7.org/linux/man-pages/man2/getrandom.2.html
//! [2]: http://man7.org/linux/man-pages/man4/urandom.4.html
//! [3]: https://docs.microsoft.com/en-us/windows/desktop/api/ntsecapi/nf-ntsecapi-rtlgenrandom
//! [4]: https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc
//! [5]: https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4
//! [6]: https://man.openbsd.org/getentropy.2
//! [7]: https://netbsd.gw.com/cgi-bin/man-cgi?sysctl+7+NetBSD-8.0
//! [8]: https://leaf.dragonflybsd.org/cgi/web-man?command=random&section=4
//! [9]: https://docs.oracle.com/cd/E88353_01/html/E37841/getrandom-2.html
//! [10]: https://docs.oracle.com/cd/E86824_01/html/E54777/random-7d.html
//! [11]: https://fuchsia.dev/fuchsia-src/zircon/syscalls/cprng_draw
//! [12]: https://github.com/redox-os/randd/blob/master/src/main.rs
//! [13]: https://github.com/nuxinl/cloudabi#random_get
//! [14]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues
//! [15]: https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback
//! [16]: #support-for-webassembly
//! [17]: https://github.com/WebAssembly/WASI/blob/master/design/WASI-core.md#__wasi_random_get
//! [18]: https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide
//! [19]: https://www.unix.com/man-page/mojave/2/getentropy/
//! [20]: https://www.unix.com/man-page/mojave/4/random/
//! [21]: https://www.freebsd.org/cgi/man.cgi?query=getrandom&manpath=FreeBSD+12.0-stable
//! [22]: https://docs.microsoft.com/en-us/windows/uwp/
//! [23]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom

#![doc(
    html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
    html_favicon_url = "https://www.rust-lang.org/favicon.ico",
    html_root_url = "https://rust-random.github.io/rand/"
)]
#![no_std]
#![warn(rust_2018_idioms, unused_lifetimes, missing_docs)]

#[macro_use]
extern crate cfg_if;

mod error;
mod util;
// To prevent a breaking change when targets are added, we always export the
// register_custom_getrandom macro, so old Custom RNG crates continue to build.
#[cfg(feature = "custom")]
mod custom;
#[cfg(feature = "std")]
mod error_impls;

pub use crate::error::Error;

// System-specific implementations.
//
// These should all provide getrandom_inner with the same signature as getrandom.
cfg_if! {
    if #[cfg(any(target_os = "dragonfly", target_os = "emscripten",
                 target_os = "haiku",     target_os = "redox"))] {
        mod util_libc;
        #[path = "use_file.rs"] mod imp;
    } else if #[cfg(any(target_os = "android", target_os = "linux"))] {
        mod util_libc;
        mod use_file;
        #[path = "linux_android.rs"] mod imp;
    } else if #[cfg(any(target_os = "illumos", target_os = "solaris"))] {
        mod util_libc;
        mod use_file;
        #[path = "solaris_illumos.rs"] mod imp;
    } else if #[cfg(any(target_os = "freebsd", target_os = "netbsd"))] {
        mod util_libc;
        #[path = "bsd_arandom.rs"] mod imp;
    } else if #[cfg(target_os = "cloudabi")] {
        #[path = "cloudabi.rs"] mod imp;
    } else if #[cfg(target_os = "fuchsia")] {
        #[path = "fuchsia.rs"] mod imp;
    } else if #[cfg(target_os = "ios")] {
        #[path = "ios.rs"] mod imp;
    } else if #[cfg(target_os = "macos")] {
        mod util_libc;
        mod use_file;
        #[path = "macos.rs"] mod imp;
    } else if #[cfg(target_os = "openbsd")] {
        mod util_libc;
        #[path = "openbsd.rs"] mod imp;
    } else if #[cfg(target_os = "wasi")] {
        #[path = "wasi.rs"] mod imp;
    } else if #[cfg(target_os = "vxworks")] {
        mod util_libc;
        #[path = "vxworks.rs"] mod imp;
    } else if #[cfg(all(windows, target_vendor = "uwp"))] {
        #[path = "windows_uwp.rs"] mod imp;
    } else if #[cfg(windows)] {
        #[path = "windows.rs"] mod imp;
    } else if #[cfg(all(target_arch = "x86_64", target_env = "sgx"))] {
        #[path = "rdrand.rs"] mod imp;
    } else if #[cfg(all(feature = "rdrand",
                        any(target_arch = "x86_64", target_arch = "x86")))] {
        #[path = "rdrand.rs"] mod imp;
    } else if #[cfg(all(feature = "js",
                        target_arch = "wasm32", target_os = "unknown"))] {
        #[cfg_attr(cargo_web, path = "stdweb.rs")]
        #[cfg_attr(not(cargo_web), path = "wasm-bindgen.rs")]
        mod imp;
    } else if #[cfg(feature = "custom")] {
        use custom as imp;
    } else {
        compile_error!("target is not supported, for more information see: \
                        https://docs.rs/getrandom/#unsupported-targets");
    }
}

/// Fill `dest` with random bytes from the system's preferred random number
/// source.
///
/// This function returns an error on any failure, including partial reads. We
/// make no guarantees regarding the contents of `dest` on error. If `dest` is
/// empty, `getrandom` immediately returns success, making no calls to the
/// underlying operating system.
///
/// Blocking is possible, at least during early boot; see module documentation.
///
/// In general, `getrandom` will be fast enough for interactive usage, though
/// significantly slower than a user-space CSPRNG; for the latter consider
/// [`rand::thread_rng`](https://docs.rs/rand/*/rand/fn.thread_rng.html).
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
    if dest.is_empty() {
        return Ok(());
    }
    imp::getrandom_inner(dest)
}

#[cfg(test)]
mod test_common;
#[cfg(test)]
mod test_rdrand;
<|endoftext|>


<commit_before>// Copyright 2012-2013 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.

//! Semantic version parsing and comparison.
//!
//! Semantic versioning (see http://semver.org/) is a set of rules for
//! assigning version numbers.
//!
//! ## SemVer overview
//!
//! Given a version number MAJOR.MINOR.PATCH, increment the:
//!
//! 1. MAJOR version when you make incompatible API changes,
//! 2. MINOR version when you add functionality in a backwards-compatible manner, and
//! 3. PATCH version when you make backwards-compatible bug fixes.
//!
//! Additional labels for pre-release and build metadata are available as extensions to the
//! MAJOR.MINOR.PATCH format.
//!
//! Any references to 'the spec' in this documentation refer to [version 2.0 of the SemVer
//! spec](http://semver.org/spec/v2.0.0.html).
//!
//! ## SemVer and the Rust ecosystem
//!
//! Rust itself follows the SemVer specification, as does its standard libraries. The two are
//! not tied together.
//!
//! [Cargo](http://crates.io), Rust's package manager, uses SemVer to determine which versions of
//! packages you need installed.
//!
//! ## Versions
//!
//! At its simplest, the `semver` crate allows you to construct `Version` objects using the `parse`
//! method:
//!
//! ```{rust}
//! use semver::Version;
//!
//! assert!(Version::parse("1.2.3") == Ok(Version {
//!    major: 1u32,
//!    minor: 2u32,
//!    patch: 3u32,
//!    pre: vec!(),
//!    build: vec!(),
//! }));
//! ```
//!
//! If you have multiple `Version`s, you can use the usual comparison operators to compare them:
//!
//! ```{rust}
//! use semver::Version;
//!
//! assert!(Version::parse("1.2.3-alpha")  != Version::parse("1.2.3-beta"));
//! assert!(Version::parse("1.2.3-alpha2") >  Version::parse("1.2.0"));
//! ```
//!
//! ## Ranges
//!
//! The `semver` crate also provides a `range` module, which allows you to do more
//! complex comparisons.
//!
//! For example, creating a requirement that only matches versions greater than or
//! equal to 1.0.0:
//!
//! ```{rust}
//! use semver::Version;
//! use semver::VersionReq;
//!
//! let r = VersionReq::parse(">= 1.0.0").unwrap();
//! let v = Version::parse("1.0.0").unwrap();
//!
//! assert!(r.to_string() == ">= 1.0.0".to_string());
//! assert!(r.matches(&v))
//! ```

#![crate_name = "semver"]
#![unstable]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico")]
#![feature(default_type_params)]
#![feature(macro_rules)]

// We take the common approach of keeping our own module system private, and
// just re-exporting the interface that we want.

pub use version::{
    Version,
    Identifier,
    ParseError,
};

pub use range::{VersionReq, ReqParseError};

// SemVer-compliant versions.
mod version;

// advanced version comparisons
mod range;

<commit_msg>rename as requirements<commit_after>// Copyright 2012-2013 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.

//! Semantic version parsing and comparison.
//!
//! Semantic versioning (see http://semver.org/) is a set of rules for
//! assigning version numbers.
//!
//! ## SemVer overview
//!
//! Given a version number MAJOR.MINOR.PATCH, increment the:
//!
//! 1. MAJOR version when you make incompatible API changes,
//! 2. MINOR version when you add functionality in a backwards-compatible manner, and
//! 3. PATCH version when you make backwards-compatible bug fixes.
//!
//! Additional labels for pre-release and build metadata are available as extensions to the
//! MAJOR.MINOR.PATCH format.
//!
//! Any references to 'the spec' in this documentation refer to [version 2.0 of the SemVer
//! spec](http://semver.org/spec/v2.0.0.html).
//!
//! ## SemVer and the Rust ecosystem
//!
//! Rust itself follows the SemVer specification, as does its standard libraries. The two are
//! not tied together.
//!
//! [Cargo](http://crates.io), Rust's package manager, uses SemVer to determine which versions of
//! packages you need installed.
//!
//! ## Versions
//!
//! At its simplest, the `semver` crate allows you to construct `Version` objects using the `parse`
//! method:
//!
//! ```{rust}
//! use semver::Version;
//!
//! assert!(Version::parse("1.2.3") == Ok(Version {
//!    major: 1u32,
//!    minor: 2u32,
//!    patch: 3u32,
//!    pre: vec!(),
//!    build: vec!(),
//! }));
//! ```
//!
//! If you have multiple `Version`s, you can use the usual comparison operators to compare them:
//!
//! ```{rust}
//! use semver::Version;
//!
//! assert!(Version::parse("1.2.3-alpha")  != Version::parse("1.2.3-beta"));
//! assert!(Version::parse("1.2.3-alpha2") >  Version::parse("1.2.0"));
//! ```
//!
//! ## Requirements
//!
//! The `semver` crate also provides the ability to compare requirements, which are more complex
//! comparisons.
//!
//! For example, creating a requirement that only matches versions greater than or
//! equal to 1.0.0:
//!
//! ```{rust}
//! use semver::Version;
//! use semver::VersionReq;
//!
//! let r = VersionReq::parse(">= 1.0.0").unwrap();
//! let v = Version::parse("1.0.0").unwrap();
//!
//! assert!(r.to_string() == ">= 1.0.0".to_string());
//! assert!(r.matches(&v))
//! ```

#![crate_name = "semver"]
#![unstable]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico")]
#![feature(default_type_params)]
#![feature(macro_rules)]

// We take the common approach of keeping our own module system private, and
// just re-exporting the interface that we want.

pub use version::{
    Version,
    Identifier,
    ParseError,
};

pub use range::{VersionReq, ReqParseError};

// SemVer-compliant versions.
mod version;

// advanced version comparisons
mod range;

<|endoftext|>


<commit_before>#![feature(proc_macro)]
#![recursion_limit = "1024"]

#[macro_use] extern crate log;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate error_chain;
#[macro_use] extern crate clap;
extern crate cargo;
extern crate git2;
extern crate serde_json;
extern crate toml;

mod errors;

use std::env;
use std::path::{Path, PathBuf};
use std::fs::{DirBuilder, File, OpenOptions, self};
use std::collections::HashMap;
use std::io::{Read, Write};

use cargo::util;
use git2::Repository;
use git2::Config as GitConfig;
use clap::{App, Arg, ArgSettings};

use errors::*;

const DEFAULT_INDEX: &'static str = "https://github.com/rusttemplates/templates";

fn ensure_exists<P: AsRef<Path>>(p: P) -> Result<()> {
        let p = p.as_ref();
        let _ = DirBuilder::new().recursive(true).create(p)?;
        Ok(())
}

pub struct Config {
    pub index: String,
    pub index_path: PathBuf,
    pub templates_path: PathBuf,
    pub resolved_index_path: Option<PathBuf>,
}

impl Config {
    fn new() -> Result<Config> {
        let cargo_config = util::Config::default()?;
        let index = cargo_config.get_string("template.registry.index")?;
        let index = match index {
            None => DEFAULT_INDEX.to_string(),
            Some(val) => {
                val.val.to_string()
            },
        };

        let config_dir = Path::new(&env::var("CARGO_HOME")?).join("cargo-template");
        ensure_exists(&config_dir)?;

        let index_path = config_dir.join("index");
        ensure_exists(&index_path)?;

        let templates_path = config_dir.join("templates");
        ensure_exists(&templates_path)?;

        Ok(Config {
            index: index,
            index_path: index_path,
            templates_path: templates_path,
            resolved_index_path: None,
        })
    }
}

#[derive(Deserialize, Debug)]
struct IndexMember {
    name: String,
    loc: String,
}

#[derive(Deserialize, Debug)]
struct IndexTopLevel {
    index: Vec<IndexMember>,
}

impl IntoIterator for IndexTopLevel {
    type Item = (String, String);
    type IntoIter = IndexIter;

    fn into_iter(self) -> IndexIter {
        IndexIter {
            next: 0,
            inner: self,
        }
    }
}

struct IndexIter {
    next: usize,
    inner: IndexTopLevel,
}

impl Iterator for IndexIter {
    type Item = (String, String);

    fn next(&mut self) -> Option<Self::Item> {
        let el = self.inner.index.get(self.next).map(|el| (el.name.clone(), el.loc.clone()));
        self.next += 1;
        el
    }
}

struct IndexLoader<'a> {
    index: &'a Path,
}

impl<'a> IndexLoader<'a> {
    fn new(index: &'a Path) -> IndexLoader<'a> {
        IndexLoader {
            index: index,
        }
    }

    fn update_or_clone(&self, source: &str, frozen: bool) -> Result<PathBuf> {
        let repo = self.index.join(self.url_to_repo_dir(source));
        if repo.exists()  && repo.is_dir() {
            if !frozen {
                self.update_index(&repo)
            } else {
                Ok(repo)
            }
        } else {
            self.clone_index(source)
        }
    }

    fn update_index<P: AsRef<Path>>(&self, source: P) -> Result<PathBuf> {
        let source = source.as_ref();
        Ok(source.to_path_buf())
    }

    fn clone_index(&self, source: &str) -> Result<PathBuf> {
        // hacky and not-sufficient way to turn a url into a valid (single) directory name
        let p = self.index.join(self.url_to_repo_dir(source));
        let _ = Repository::clone(source, &p)?;
        debug!("cloned index at {:?}", &p);
        Ok(p)
    }

    fn url_to_repo_dir(&self, url: &str) -> String {
        url.replace(':', "_").replace('/', "_").replace(' ', "-")
    }
}

fn get_index(config: &mut Config, frozen: bool) -> Result<HashMap<String, String>> {
    let i = IndexLoader::new(&config.index_path);
    if let Ok(p) = i.update_or_clone(&config.index, frozen) {
        config.resolved_index_path = Some(p);
    }
    let index_file = match config.resolved_index_path {
        Some(ref p) => p.join("index.json"),
        None => {
            error!("Could not find an index");
            return Err(ErrorKind::GenericError.into());
        }
    };
    debug!("looking for index file {:?}", index_file);
    let index_file = File::open(index_file)?;
    let index_members = serde_json::from_reader::<File, IndexTopLevel>(index_file)?;
    let index_members: HashMap<String, String> = index_members.into_iter().collect();
    Ok(index_members)
}

fn get_template<P: AsRef<Path>>(name: &str, url: &str, templates_dir: P, frozen: bool) -> Result<PathBuf> {
    let templates_dir = templates_dir.as_ref();
    let location = templates_dir.join(name);
    if !location.exists() {
        if frozen {
            return Err(ErrorKind::TemplateNotFound(name.into()).into())
        }
        let _ = Repository::clone(url, &location);
    }

    Ok(location)
}

fn copy_dir<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<()> {
    let from = from.as_ref();
    let to = to.as_ref();

    debug!("copy_dir({}, {})", from.to_str().unwrap(), to.to_str().unwrap());

    if !from.exists() || !from.is_dir() {
        return Err(ErrorKind::SourceDoesNotExist(from.to_string_lossy().into_owned()).into());
    }
    ensure_exists(to)?;

    for entry in fs::read_dir(from)? {
        let entry = entry?;
        let file_name = entry.file_name();
        let lossy = file_name.to_string_lossy();
        if lossy == ".git" {
            continue;
        }
        let path = entry.path();

        if path.is_dir() {
            let new_to = to.join(&file_name);
            ensure_exists(&new_to)?;
            debug!("from {} to {}", path.to_str().unwrap(), new_to.to_str().unwrap());
            copy_dir(path, new_to)?;
        } else if path.is_file() {
            let new_to = to.join(&file_name);
            debug!("copy {} to {}", path.to_str().unwrap(), new_to.to_str().unwrap());
            fs::copy(&path, &new_to)?;
        } else {
            error!("Oops, this isn't a directory or a file, I don't know how to handle this so I'm just gonna ignore it");
            error!("problem entry: {:?}", path.to_str());
        }
    }
    Ok(())
}

// Basically just a port of "get_environment_variable" from cargo/src/cargo/ops/cargo_new.rs
fn get_environment_variable(variables: &[&str]) -> Option<String> {
    variables.iter()
             .filter_map(|var| env::var(var).ok())
             .next()
}

// Basically just a port of "discover_author" from cargo/src/cargo/ops/cargo_new.rs
fn get_name_and_email() -> Result<(String, Option<String>)> {
    let git_config = GitConfig::open_default().ok();
    let git_config = git_config.as_ref();
    let name_variables = ["CARGO_NAME", "GIT_AUTHOR_NAME", "GIT_COMMITTER_NAME",
                          "USER", "USERNAME", "NAME"];
    let name = get_environment_variable(&name_variables[0..3])
                    .or_else(|| git_config.and_then(|g| g.get_string("user.name").ok()))
                    .or_else(|| get_environment_variable(&name_variables[3..]));
    let name = match name {
        Some(name) => name,
        None => {
            let username_var = if cfg!(windows) { "USERNAME" } else { "USER" };
            return Err(ErrorKind::UserError(username_var.into()).into());
        }
    };
    let email_variables = ["CARGO_EMAIL", "GIT_AUTHOR_EMAIL", "GIT_COMMITTER_EMAIL",
                           "EMAIL"];
    let email = get_environment_variable(&email_variables[0..3])
                    .or_else(|| git_config.and_then(|g| g.get_string("user.email").ok()))
                    .or_else(|| get_environment_variable(&email_variables[3..]));
    let name = name.trim().to_string();
    let email = email.map(|s| s.trim().to_string());

    Ok((name, email))
}

fn format_author(author_name: &str, author_email: &Option<String>) -> String {
    match *author_email {
        Some(ref email) => format!("{} <{}>", author_name, email),
        None => format!("{}", author_name),
    }
}

fn write_toml<P: AsRef<Path>>(file: P, val: toml::Value) -> Result<()> {
    let file = file.as_ref();
    let mut file = OpenOptions::new().read(true).write(true).open(file)?;
    let contents = format!("{}", val);
    write!(file, "{}", contents)?;
    Ok(())
}
fn edit_cargo_toml<P: AsRef<Path>>(file: P, project_name: &str, author_name: &str,
                                   author_email: &Option<String>) -> Result<()> {
    let file = file.as_ref();
    let mut contents = String::new();
    File::open(file)?.read_to_string(&mut contents)?;
    let contents = contents;
    let mut parser = toml::Parser::new(&contents);
    let mut value = match parser.parse() {
        Some(val) => val,
        None => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
    };
    match value.get_mut("package") {
        Some(&mut toml::Value::Table(ref mut t)) => {
            t.insert("name".into(), toml::Value::String(project_name.to_string()));
        },
        Some(_) => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
        None => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
    };

    match value.get_mut("package") {
        Some(&mut toml::Value::Table(ref mut t)) => {
            t.insert("authors".into(),
                     toml::Value::Array(
                         vec![toml::Value::String(format_author(author_name, author_email))]));
        },
        Some(_) => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
        None => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
    }

    write_toml(&file, toml::Value::Table(value))?;

    Ok(())
}
fn find_cargo_toml<P: AsRef<Path>>(project_dir: P, project_name: &str,
                                      author_name: &str, author_email: &Option<String>) -> Result<()> {
    let project_dir = project_dir.as_ref();
    for entry in fs::read_dir(project_dir)? {
        let entry = entry?;
        let path = entry.path();
        if path.is_file() && entry.file_name().to_string_lossy() == "Cargo.toml" {
            edit_cargo_toml(&path, project_name, author_name, author_email)?;
        }
    }
    Ok(())
}

fn cli() -> App<'static, 'static> {
    App::new("cargo-template")
        .author(crate_authors!())
        .version(crate_version!())
        .usage("cargo template [FLAGS] <TEMPLATE> <NAME>")
        .about("initialize new cargo projects from a predefined template")
        .arg(Arg::with_name("frozen")
                .long("frozen")
                .help("Asserts that we shouldn't touch the network"))
        .arg(Arg::with_name("CARGO_ADDS_THIS")
                .set(ArgSettings::Hidden)
                .required(true)
                .index(1))
        .arg(Arg::with_name("TEMPLATE")
                .help("The template to use")
                .required(true)
                .index(2))
        .arg(Arg::with_name("NAME")
                .help("the project name")
                .required(true)
                .index(3))
}

pub fn main() -> Result<()> {
    let matches = cli().get_matches();
    let frozen = matches.is_present("frozen");
    let template = matches.value_of("TEMPLATE").unwrap(); // If we've gotten here, clap has verified that we have this
    let project_name = matches.value_of("NAME").unwrap();
    let cwd = env::current_dir()?;
    let project_dir = cwd.join(project_name);
    if project_dir.exists() {
        return Err(ErrorKind::ExistsError(project_dir.to_string_lossy().into_owned()).into());
    }
    debug!("template: {:?}", template);
    debug!("project name: {:?}", project_name);
    let mut config = Config::new()?;
    let metadata = fs::metadata(template);
    let from = if metadata.is_ok() && metadata.unwrap().is_dir() {
        debug!("found template on filesystem");
        Path::new(template).to_path_buf()
    } else {
        let index = get_index(&mut config, frozen)?;
        let location = match index.get(template) {
            Some(loc) => loc,
            None => return Err(ErrorKind::TemplateDoesNotExist(template.into()).into())
        };
        debug!("template url is {:?}", location);
        let from = match get_template(template, location, &config.templates_path, frozen) {
            Ok(loc) => loc,
            Err(e) => {
                error!("Error getting template: {}", e);
                return Err(e);
            }
        };
        from
    };
    debug!("creating project at {:?}", project_dir);
    copy_dir(&from, &project_dir)?;
    debug!("substituting name & author values");
    // open new Cargo.toml && change the name & author lines
    let (author_name, author_email) = get_name_and_email()?;
    debug!("using author info `({:?}, {:?})`", author_name, author_email);
    find_cargo_toml(&project_dir, &project_name, &author_name, &author_email)?;
    debug!("adding project & author info to the Cargo.toml");
    Ok(())
}<commit_msg>Don't copy `target` dir from local templates<commit_after>#![feature(proc_macro)]
#![recursion_limit = "1024"]

#[macro_use] extern crate log;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate error_chain;
#[macro_use] extern crate clap;
extern crate cargo;
extern crate git2;
extern crate serde_json;
extern crate toml;

mod errors;

use std::env;
use std::path::{Path, PathBuf};
use std::fs::{DirBuilder, File, OpenOptions, self};
use std::collections::HashMap;
use std::io::{Read, Write};

use cargo::util;
use git2::Repository;
use git2::Config as GitConfig;
use clap::{App, Arg, ArgSettings};

use errors::*;

const DEFAULT_INDEX: &'static str = "https://github.com/rusttemplates/templates";

fn ensure_exists<P: AsRef<Path>>(p: P) -> Result<()> {
        let p = p.as_ref();
        let _ = DirBuilder::new().recursive(true).create(p)?;
        Ok(())
}

pub struct Config {
    pub index: String,
    pub index_path: PathBuf,
    pub templates_path: PathBuf,
    pub resolved_index_path: Option<PathBuf>,
}

impl Config {
    fn new() -> Result<Config> {
        let cargo_config = util::Config::default()?;
        let index = cargo_config.get_string("template.registry.index")?;
        let index = match index {
            None => DEFAULT_INDEX.to_string(),
            Some(val) => {
                val.val.to_string()
            },
        };

        let config_dir = Path::new(&env::var("CARGO_HOME")?).join("cargo-template");
        ensure_exists(&config_dir)?;

        let index_path = config_dir.join("index");
        ensure_exists(&index_path)?;

        let templates_path = config_dir.join("templates");
        ensure_exists(&templates_path)?;

        Ok(Config {
            index: index,
            index_path: index_path,
            templates_path: templates_path,
            resolved_index_path: None,
        })
    }
}

#[derive(Deserialize, Debug)]
struct IndexMember {
    name: String,
    loc: String,
}

#[derive(Deserialize, Debug)]
struct IndexTopLevel {
    index: Vec<IndexMember>,
}

impl IntoIterator for IndexTopLevel {
    type Item = (String, String);
    type IntoIter = IndexIter;

    fn into_iter(self) -> IndexIter {
        IndexIter {
            next: 0,
            inner: self,
        }
    }
}

struct IndexIter {
    next: usize,
    inner: IndexTopLevel,
}

impl Iterator for IndexIter {
    type Item = (String, String);

    fn next(&mut self) -> Option<Self::Item> {
        let el = self.inner.index.get(self.next).map(|el| (el.name.clone(), el.loc.clone()));
        self.next += 1;
        el
    }
}

struct IndexLoader<'a> {
    index: &'a Path,
}

impl<'a> IndexLoader<'a> {
    fn new(index: &'a Path) -> IndexLoader<'a> {
        IndexLoader {
            index: index,
        }
    }

    fn update_or_clone(&self, source: &str, frozen: bool) -> Result<PathBuf> {
        let repo = self.index.join(self.url_to_repo_dir(source));
        if repo.exists()  && repo.is_dir() {
            if !frozen {
                self.update_index(&repo)
            } else {
                Ok(repo)
            }
        } else {
            self.clone_index(source)
        }
    }

    fn update_index<P: AsRef<Path>>(&self, source: P) -> Result<PathBuf> {
        let source = source.as_ref();
        Ok(source.to_path_buf())
    }

    fn clone_index(&self, source: &str) -> Result<PathBuf> {
        // hacky and not-sufficient way to turn a url into a valid (single) directory name
        let p = self.index.join(self.url_to_repo_dir(source));
        let _ = Repository::clone(source, &p)?;
        debug!("cloned index at {:?}", &p);
        Ok(p)
    }

    fn url_to_repo_dir(&self, url: &str) -> String {
        url.replace(':', "_").replace('/', "_").replace(' ', "-")
    }
}

fn get_index(config: &mut Config, frozen: bool) -> Result<HashMap<String, String>> {
    let i = IndexLoader::new(&config.index_path);
    if let Ok(p) = i.update_or_clone(&config.index, frozen) {
        config.resolved_index_path = Some(p);
    }
    let index_file = match config.resolved_index_path {
        Some(ref p) => p.join("index.json"),
        None => {
            error!("Could not find an index");
            return Err(ErrorKind::GenericError.into());
        }
    };
    debug!("looking for index file {:?}", index_file);
    let index_file = File::open(index_file)?;
    let index_members = serde_json::from_reader::<File, IndexTopLevel>(index_file)?;
    let index_members: HashMap<String, String> = index_members.into_iter().collect();
    Ok(index_members)
}

fn get_template<P: AsRef<Path>>(name: &str, url: &str, templates_dir: P, frozen: bool) -> Result<PathBuf> {
    let templates_dir = templates_dir.as_ref();
    let location = templates_dir.join(name);
    if !location.exists() {
        if frozen {
            return Err(ErrorKind::TemplateNotFound(name.into()).into())
        }
        let _ = Repository::clone(url, &location);
    }

    Ok(location)
}

fn copy_dir<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<()> {
    let from = from.as_ref();
    let to = to.as_ref();

    debug!("copy_dir({}, {})", from.to_str().unwrap(), to.to_str().unwrap());

    if !from.exists() || !from.is_dir() {
        return Err(ErrorKind::SourceDoesNotExist(from.to_string_lossy().into_owned()).into());
    }
    ensure_exists(to)?;

    for entry in fs::read_dir(from)? {
        let entry = entry?;
        let file_name = entry.file_name();
        let lossy = file_name.to_string_lossy();
        if lossy == ".git" || lossy == "target" {
            continue;
        }
        let path = entry.path();

        if path.is_dir() {
            let new_to = to.join(&file_name);
            ensure_exists(&new_to)?;
            debug!("from {} to {}", path.to_str().unwrap(), new_to.to_str().unwrap());
            copy_dir(path, new_to)?;
        } else if path.is_file() {
            let new_to = to.join(&file_name);
            debug!("copy {} to {}", path.to_str().unwrap(), new_to.to_str().unwrap());
            fs::copy(&path, &new_to)?;
        } else {
            error!("Oops, this isn't a directory or a file, I don't know how to handle this so I'm just gonna ignore it");
            error!("problem entry: {:?}", path.to_str());
        }
    }
    Ok(())
}

// Basically just a port of "get_environment_variable" from cargo/src/cargo/ops/cargo_new.rs
fn get_environment_variable(variables: &[&str]) -> Option<String> {
    variables.iter()
             .filter_map(|var| env::var(var).ok())
             .next()
}

// Basically just a port of "discover_author" from cargo/src/cargo/ops/cargo_new.rs
fn get_name_and_email() -> Result<(String, Option<String>)> {
    let git_config = GitConfig::open_default().ok();
    let git_config = git_config.as_ref();
    let name_variables = ["CARGO_NAME", "GIT_AUTHOR_NAME", "GIT_COMMITTER_NAME",
                          "USER", "USERNAME", "NAME"];
    let name = get_environment_variable(&name_variables[0..3])
                    .or_else(|| git_config.and_then(|g| g.get_string("user.name").ok()))
                    .or_else(|| get_environment_variable(&name_variables[3..]));
    let name = match name {
        Some(name) => name,
        None => {
            let username_var = if cfg!(windows) { "USERNAME" } else { "USER" };
            return Err(ErrorKind::UserError(username_var.into()).into());
        }
    };
    let email_variables = ["CARGO_EMAIL", "GIT_AUTHOR_EMAIL", "GIT_COMMITTER_EMAIL",
                           "EMAIL"];
    let email = get_environment_variable(&email_variables[0..3])
                    .or_else(|| git_config.and_then(|g| g.get_string("user.email").ok()))
                    .or_else(|| get_environment_variable(&email_variables[3..]));
    let name = name.trim().to_string();
    let email = email.map(|s| s.trim().to_string());

    Ok((name, email))
}

fn format_author(author_name: &str, author_email: &Option<String>) -> String {
    match *author_email {
        Some(ref email) => format!("{} <{}>", author_name, email),
        None => format!("{}", author_name),
    }
}

fn write_toml<P: AsRef<Path>>(file: P, val: toml::Value) -> Result<()> {
    let file = file.as_ref();
    let mut file = OpenOptions::new().read(true).write(true).open(file)?;
    let contents = format!("{}", val);
    write!(file, "{}", contents)?;
    Ok(())
}
fn edit_cargo_toml<P: AsRef<Path>>(file: P, project_name: &str, author_name: &str,
                                   author_email: &Option<String>) -> Result<()> {
    let file = file.as_ref();
    let mut contents = String::new();
    File::open(file)?.read_to_string(&mut contents)?;
    let contents = contents;
    let mut parser = toml::Parser::new(&contents);
    let mut value = match parser.parse() {
        Some(val) => val,
        None => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
    };
    match value.get_mut("package") {
        Some(&mut toml::Value::Table(ref mut t)) => {
            t.insert("name".into(), toml::Value::String(project_name.to_string()));
        },
        Some(_) => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
        None => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
    };

    match value.get_mut("package") {
        Some(&mut toml::Value::Table(ref mut t)) => {
            t.insert("authors".into(),
                     toml::Value::Array(
                         vec![toml::Value::String(format_author(author_name, author_email))]));
        },
        Some(_) => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
        None => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
    }

    write_toml(&file, toml::Value::Table(value))?;

    Ok(())
}
fn find_cargo_toml<P: AsRef<Path>>(project_dir: P, project_name: &str,
                                      author_name: &str, author_email: &Option<String>) -> Result<()> {
    let project_dir = project_dir.as_ref();
    for entry in fs::read_dir(project_dir)? {
        let entry = entry?;
        let path = entry.path();
        if path.is_file() && entry.file_name().to_string_lossy() == "Cargo.toml" {
            edit_cargo_toml(&path, project_name, author_name, author_email)?;
        }
    }
    Ok(())
}

fn cli() -> App<'static, 'static> {
    App::new("cargo-template")
        .author(crate_authors!())
        .version(crate_version!())
        .usage("cargo template [FLAGS] <TEMPLATE> <NAME>")
        .about("initialize new cargo projects from a predefined template")
        .arg(Arg::with_name("frozen")
                .long("frozen")
                .help("Asserts that we shouldn't touch the network"))
        .arg(Arg::with_name("CARGO_ADDS_THIS")
                .set(ArgSettings::Hidden)
                .required(true)
                .index(1))
        .arg(Arg::with_name("TEMPLATE")
                .help("The template to use")
                .required(true)
                .index(2))
        .arg(Arg::with_name("NAME")
                .help("the project name")
                .required(true)
                .index(3))
}

pub fn main() -> Result<()> {
    let matches = cli().get_matches();
    let frozen = matches.is_present("frozen");
    let template = matches.value_of("TEMPLATE").unwrap(); // If we've gotten here, clap has verified that we have this
    let project_name = matches.value_of("NAME").unwrap();
    let cwd = env::current_dir()?;
    let project_dir = cwd.join(project_name);
    if project_dir.exists() {
        return Err(ErrorKind::ExistsError(project_dir.to_string_lossy().into_owned()).into());
    }
    debug!("template: {:?}", template);
    debug!("project name: {:?}", project_name);
    let mut config = Config::new()?;
    let metadata = fs::metadata(template);
    let from = if metadata.is_ok() && metadata.unwrap().is_dir() {
        debug!("found template on filesystem");
        Path::new(template).to_path_buf()
    } else {
        let index = get_index(&mut config, frozen)?;
        let location = match index.get(template) {
            Some(loc) => loc,
            None => return Err(ErrorKind::TemplateDoesNotExist(template.into()).into())
        };
        debug!("template url is {:?}", location);
        let from = match get_template(template, location, &config.templates_path, frozen) {
            Ok(loc) => loc,
            Err(e) => {
                error!("Error getting template: {}", e);
                return Err(e);
            }
        };
        from
    };
    debug!("creating project at {:?}", project_dir);
    copy_dir(&from, &project_dir)?;
    debug!("substituting name & author values");
    // open new Cargo.toml && change the name & author lines
    let (author_name, author_email) = get_name_and_email()?;
    debug!("using author info `({:?}, {:?})`", author_name, author_email);
    find_cargo_toml(&project_dir, &project_name, &author_name, &author_email)?;
    debug!("adding project & author info to the Cargo.toml");
    Ok(())
}<|endoftext|>