<commit_before>use std::collections::BinaryHeap;
use std::iter::IntoIterator;
use std::{marker, mem};
use std::sync::{mpsc, atomic};
use std::thread;
use std::thunk::Invoke;

type JobInner<'b> =  Box<for<'a> Invoke<&'a [mpsc::Sender<Work>], ()> + Send + 'b>;
struct Job {
    func: JobInner<'static>,
}

/// A thread pool.
///
/// This pool allows one to spawn several threads in one go, and then
/// execute any number of jobs on those threads, without having to pay
/// the thread spawning cost, or risk exhausting system resources.
///
/// The pool attempts to expose an API that is a generalised version
/// of `std::thread::scoped`: at the lowest-level a submitted job
/// returns a handle that ensures that job is finished before any data
/// the job might reference is invalidated (i.e. manages the
/// lifetimes). Higher-level functions will usually wrap or otherwise
/// hide the handle. The current implementation only exposes "batch"
/// jobs like `for_` and `map`, which take control of the whole pool,
/// there is no way to incrementally submit jobs.
///
/// The pool currently consists of some number of worker threads
/// (dynamic, chosen at creation time) along with a single supervisor
/// thread.
pub struct Pool {
    job_queue: mpsc::Sender<Option<Job>>,
    job_finished: mpsc::Receiver<Result<(), ()>>,
    n_threads: usize,
}
#[derive(Copy)]
struct WorkerId { n: usize }

type WorkInner<'a> = &'a mut (FnMut(WorkerId) + Send + 'a);
struct Work {
    func: WorkInner<'static>
}

/// A token representing a job submitted to the thread pool.
///
/// This ensures that a job is finished before borrowed resources in
/// the job (and the pool itself) are invalidated.
///
/// If the job panics, this handle will ensure the main thread also
/// panics (either via `wait` or in the destructor).
pub struct JobHandle<'pool, 'f> {
    pool: &'pool mut Pool,
    wait: bool,
    _funcs: marker::PhantomData<&'f ()>,
}
impl<'pool, 'f> JobHandle<'pool, 'f> {
    /// Block until the job is finished.
    ///
    /// # Panics
    ///
    /// This will panic if the job panicked.
    pub fn wait(mut self) {
        self.wait = false;
        self.pool.job_finished.recv().unwrap().unwrap();
    }
}
#[unsafe_destructor]
impl<'pool, 'f> Drop for JobHandle<'pool, 'f> {
    fn drop(&mut self) {
        if self.wait {
            self.pool.job_finished.recv().unwrap().unwrap();
        }
    }
}

impl Drop for Pool {
    fn drop(&mut self) {
        self.job_queue.send(None).unwrap();
        self.job_finished.recv().unwrap().unwrap();
    }
}
struct PanicHandler {
    tx: mpsc::Sender<Result<(), ()>>
}
impl Drop for PanicHandler {
    fn drop(&mut self) {
        let msg = if thread::panicking() { Err(()) } else { Ok(()) };
        self.tx.send(msg).unwrap();
    }
}
struct PanicCanary<'a> {
    flag: &'a atomic::AtomicBool
}
#[unsafe_destructor]
impl<'a> Drop for PanicCanary<'a> {
    fn drop(&mut self) {
        if thread::panicking() {
            self.flag.store(true, atomic::Ordering::SeqCst)
        }
    }
}
impl Pool {
    /// Create a new thread pool with `n_threads` worker threads.
    pub fn new(n_threads: usize) -> Pool {
        let (tx, rx) = mpsc::channel::<Option<Job>>();
        let (finished_tx, finished_rx) = mpsc::channel();

        thread::spawn(move || {
            let ref panicked = atomic::AtomicBool::new(false);

            let mut _guards = Vec::with_capacity(n_threads);
            let mut txs = Vec::with_capacity(n_threads);
            let finished_tx = PanicHandler {
                tx: finished_tx,
            };

            for i in 0..n_threads {
                let id = WorkerId { n: i };
                let (subtx, subrx) = mpsc::channel::<Work>();
                txs.push(subtx);

                _guards.push(thread::scoped(move || {
                    let _canary = PanicCanary {
                        flag: panicked
                    };
                    loop {
                        match subrx.recv() {
                            Ok(mut work) => {
                                (work.func)(id)
                            }
                            Err(_) => break,
                        }
                    }
                }))
            }

            while let Ok(Some(job)) = rx.recv() {
                job.func.invoke(&txs);
                let job_panicked = panicked.load(atomic::Ordering::SeqCst);
                let msg = if job_panicked { Err(()) } else { Ok(()) };
                finished_tx.tx.send(msg).unwrap();

                if job_panicked { break }
            }
        });

        Pool {
            job_queue: tx,
            job_finished: finished_rx,
            n_threads: n_threads,
        }
    }

    /// Run a job on the thread pool.
    ///
    /// `gen_fn` is called `self.n_threads` times to create the
    /// functions to execute on the worker threads. Each of these is
    /// immediately called exactly once on a worker thread (that is,
    /// they are semantically `FnOnce`), and `main_fn` is also called,
    /// on the supervisor thread. It is expected that the workers and
    /// `main_fn` will manage any internal coordination required to
    /// distribute chunks of work.
    ///
    /// The job must take pains to ensure `main_fn` doesn't quit
    /// before the workers do.
    pub unsafe fn execute<'pool, 'f, A, GenFn, WorkerFn, MainFn>(
        &'pool mut self, data: A, gen_fn: GenFn, main_fn: MainFn) -> JobHandle<'pool, 'f>

        where A: 'f + Send,
              GenFn: 'f + FnMut(&mut A) -> WorkerFn + Send,
              WorkerFn: 'f + FnMut(WorkerId) + Send,
              MainFn: 'f + FnOnce(A) + Send,
    {
        self.execute_nonunsafe(data, gen_fn, main_fn)
    }

    // separate function to ensure we get `unsafe` checking inside this one
    fn execute_nonunsafe<'pool, 'f, A, GenFn, WorkerFn, MainFn>(
        &'pool mut self, mut data: A,
        mut gen_fn: GenFn, main_fn: MainFn) -> JobHandle<'pool, 'f>

        where A: 'f + Send,
              GenFn: 'f + FnMut(&mut A) -> WorkerFn + Send,
              WorkerFn: 'f + FnMut(WorkerId) + Send,
              MainFn: 'f + FnOnce(A) + Send,
    {
        let n_threads = self.n_threads;
        // transmutes scary? only a little: the returned `JobHandle`
        // ensures safety by connecting this job to the outside stack
        // frame.
        let func: JobInner<'f> = Box::new(move |workers: &[mpsc::Sender<Work>]| {
            assert_eq!(workers.len(), n_threads);
            let mut worker_fns: Vec<_> = (0..n_threads).map(|_| gen_fn(&mut data)).collect();

            for (func, worker) in worker_fns.iter_mut().zip(workers.iter()) {
                let func: WorkInner = func;
                let func: WorkInner<'static> = unsafe {
                    mem::transmute(func)
                };
                worker.send(Work { func: func }).unwrap();
            }

            main_fn(data)
        });
        let func: JobInner<'static> = unsafe {
            mem::transmute(func)
        };
        self.job_queue.send(Some(Job { func: func })).unwrap();

        JobHandle {
            pool: self,
            wait: true,
            _funcs: marker::PhantomData,
        }
    }

    /// Execute `f` on each element of `iter`.
    ///
    /// This panics if `f` panics, although the precise time and
    /// number of elements consumed after the element that panics is
    /// not specified.
    pub fn for_<Iter: IntoIterator, F>(&mut self, iter: Iter, ref f: F)
        where Iter::Item: Send,
              Iter: Send,
              F: Fn(Iter::Item) + Sync

    {
        let (needwork_tx, needwork_rx) = mpsc::channel();
        let mut work_txs = Vec::with_capacity(self.n_threads);
        let mut work_rxs = Vec::with_capacity(self.n_threads);
        for _ in 0..self.n_threads {
            let (t, r) = mpsc::channel();
            work_txs.push(t);
            work_rxs.push(r);
        }

        let mut work_rxs = work_rxs.into_iter();

        unsafe {
            let handle = self.execute(
                needwork_tx,
                |needwork_tx| {
                    let mut needwork_tx = Some(needwork_tx.clone());
                    let mut work_rx = Some(work_rxs.next().unwrap());
                    move |id| {
                        let work_rx = work_rx.take().unwrap();
                        let needwork = needwork_tx.take().unwrap();
                        loop {
                            needwork.send(id).unwrap();
                            match work_rx.recv() {
                                Ok(Some(elem)) => {
                                    f(elem);
                                }
                                Ok(None) | Err(_) => break
                            }
                        }
                    }
                },
                move |needwork_tx| {
                    let mut iter = iter.into_iter().fuse();
                    drop(needwork_tx);
                    loop {
                        match needwork_rx.recv() {
                            // closed, done!
                            Err(_) => break,
                            Ok(id) => {
                                work_txs[id.n].send(iter.next()).unwrap();
                            }
                        }
                    }
                });

            handle.wait();
        }
    }

    /// Execute `f` on each element in `iter` in parallel across the
    /// pool's threads, with unspecified yield order.
    ///
    /// This behaves like `map`, but does not make efforts to ensure
    /// that the elements are returned in the order of `iter`, hence
    /// this is cheaper.
    pub fn unordered_map<'pool, 'a, I: IntoIterator, F, T>(&'pool mut self, iter: I, f: &'a F)
        -> UnorderedParMap<'pool, 'a, T>
        where I: 'a + Send,
              I::Item: Send + 'a,
              F: 'a + Sync + Fn(I::Item) -> T,
              T: Send + 'a
    {
        let (needwork_tx, needwork_rx) = mpsc::channel();
        let mut work_txs = Vec::with_capacity(self.n_threads);
        let mut work_rxs = Vec::with_capacity(self.n_threads);
        for _ in 0..self.n_threads {
            let (t, r) = mpsc::channel();
            work_txs.push(t);
            work_rxs.push(r);
        }

        let mut work_rxs = work_rxs.into_iter();

        let (tx, rx) = mpsc::channel();

        let handle = unsafe {
            self.execute(needwork_tx,
                         move |needwork_tx| {
                             let mut needwork_tx = Some(needwork_tx.clone());
                             let mut work_rx = Some(work_rxs.next().unwrap());
                             let tx = tx.clone();
                             move |id| {
                                 let work_rx = work_rx.take().unwrap();
                                 let needwork = needwork_tx.take().unwrap();
                                 loop {
                                     needwork.send(id).unwrap();
                                     match work_rx.recv() {
                                         Ok(Some((idx, elem))) => {
                                             let data = f(elem);
                                             let status = tx.send(Packet {
                                                 idx: idx, data: Some(data)
                                             });
                                             // the user disconnected,
                                             // so there's no point
                                             // computing more.
                                             if status.is_err() {
                                                 break
                                             }
                                         }
                                         Ok(None) | Err(_) => break
                                     }
                                 }
                             }
                         },
                         move |needwork_tx| {
                             let mut iter = iter.into_iter().fuse().enumerate();
                             drop(needwork_tx);
                             loop {
                                 match needwork_rx.recv() {
                                     // closed, done!
                                     Err(_) => break,
                                     Ok(id) => {
                                         work_txs[id.n].send(iter.next()).unwrap();
                                     }
                                 }
                             }
                         })
        };

        UnorderedParMap {
            rx: rx,
            _guard: handle,
        }
    }

    /// Execute `f` on `iter` in parallel across the pool's threads,
    /// returning an iterator that yields the results in the order of
    /// the elements of `iter` to which they correspond.
    ///
    /// This is a drop-in replacement for `iter.map(f)`, that runs in
    /// parallel, and consumes `iter` as the pool's threads complete
    /// their previous tasks.
    pub fn map<'pool, 'a, I: IntoIterator, F, T>(&'pool mut self, iter: I, f: &'a F)
        -> ParMap<'pool, 'a, T>
        where I: 'a + Send,
              I::Item: Send + 'a,
              F: 'a + Sync + Fn(I::Item) -> T,
              T: Send + 'a
    {
        ParMap {
            unordered: self.unordered_map(iter, f),
            looking_for: 0,
            queue: BinaryHeap::new(),
        }
    }
}

use std::cmp::Ordering;

struct Packet<T> {
    // this should be unique for a given instance of `*ParMap`
    idx: usize,
    data: Option<T>,
}
impl<T> PartialOrd for Packet<T> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
}
impl<T> Ord for Packet<T> {
    // reverse the ordering, to work with the max-heap
    fn cmp(&self, other: &Self) -> Ordering { other.idx.cmp(&self.idx) }
}
impl<T> PartialEq for Packet<T> {
    fn eq(&self, other: &Self) -> bool { self.idx == other.idx }
}
impl<T> Eq for Packet<T> {}

/// A parallel-mapping iterator, that yields elements in the order
/// they are computed, not the order from which they are yielded by
/// the underlying iterator.
pub struct UnorderedParMap<'pool, 'a, T: 'a + Send> {
    rx: mpsc::Receiver<Packet<T>>,
    _guard: JobHandle<'pool, 'a>,
}
impl<'pool, 'a,T: 'a + Send> Iterator for UnorderedParMap<'pool , 'a, T> {
    type Item = (usize, T);

    fn next(&mut self) -> Option<(usize, T)> {
        match self.rx.recv() {
            Ok(Packet { data: Some(x), idx }) => Some((idx, x)),
            Ok(Packet { data: None, .. }) => {
                panic!("simple_parallel::unordered_map: closure panicked")
            }
            Err(mpsc::RecvError) => None,
        }
    }
}

/// A parallel-mapping iterator, that yields elements in the order
/// they are yielded by the underlying iterator.
pub struct ParMap<'pool, 'a, T: 'a + Send> {
    unordered: UnorderedParMap<'pool, 'a, T>,
    looking_for: usize,
    queue: BinaryHeap<Packet<T>>
}

impl<'pool, 'a, T: Send + 'a> Iterator for ParMap<'pool, 'a, T> {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        loop {
            if self.queue.peek().map_or(false, |x| x.idx == self.looking_for) {
                // we've found what we want, so lets return it

                let packet = self.queue.pop().unwrap();
                self.looking_for += 1;
                match packet.data {
                    Some(x) => return Some(x),
                    None => panic!("simple_parallel::map: closure panicked")
                }
            }
            match self.unordered.rx.recv() {
                // this could be optimised to check for `packet.idx ==
                // self.looking_for` to avoid the BinaryHeap
                // interaction if its what we want.
                Ok(packet) => self.queue.push(packet),
                // all done
                Err(mpsc::RecvError) => return None,
            }
        }
    }
}
<commit_msg>Move `Pool::execute` way from the main docs.<commit_after>use std::collections::BinaryHeap;
use std::iter::IntoIterator;
use std::{marker, mem};
use std::sync::{mpsc, atomic};
use std::thread;
use std::thunk::Invoke;

type JobInner<'b> =  Box<for<'a> Invoke<&'a [mpsc::Sender<Work>], ()> + Send + 'b>;
struct Job {
    func: JobInner<'static>,
}

/// A thread pool.
///
/// This pool allows one to spawn several threads in one go, and then
/// execute any number of jobs on those threads, without having to pay
/// the thread spawning cost, or risk exhausting system resources.
///
/// The pool attempts to expose an API that is a generalised version
/// of `std::thread::scoped`: at the lowest-level a submitted job
/// returns a handle that ensures that job is finished before any data
/// the job might reference is invalidated (i.e. manages the
/// lifetimes). Higher-level functions will usually wrap or otherwise
/// hide the handle. The current implementation only exposes "batch"
/// jobs like `for_` and `map`, which take control of the whole pool,
/// there is no way to incrementally submit jobs.
///
/// The pool currently consists of some number of worker threads
/// (dynamic, chosen at creation time) along with a single supervisor
/// thread.
pub struct Pool {
    job_queue: mpsc::Sender<Option<Job>>,
    job_finished: mpsc::Receiver<Result<(), ()>>,
    n_threads: usize,
}
#[derive(Copy)]
struct WorkerId { n: usize }

type WorkInner<'a> = &'a mut (FnMut(WorkerId) + Send + 'a);
struct Work {
    func: WorkInner<'static>
}

/// A token representing a job submitted to the thread pool.
///
/// This ensures that a job is finished before borrowed resources in
/// the job (and the pool itself) are invalidated.
///
/// If the job panics, this handle will ensure the main thread also
/// panics (either via `wait` or in the destructor).
pub struct JobHandle<'pool, 'f> {
    pool: &'pool mut Pool,
    wait: bool,
    _funcs: marker::PhantomData<&'f ()>,
}
impl<'pool, 'f> JobHandle<'pool, 'f> {
    /// Block until the job is finished.
    ///
    /// # Panics
    ///
    /// This will panic if the job panicked.
    pub fn wait(mut self) {
        self.wait = false;
        self.pool.job_finished.recv().unwrap().unwrap();
    }
}
#[unsafe_destructor]
impl<'pool, 'f> Drop for JobHandle<'pool, 'f> {
    fn drop(&mut self) {
        if self.wait {
            self.pool.job_finished.recv().unwrap().unwrap();
        }
    }
}

impl Drop for Pool {
    fn drop(&mut self) {
        self.job_queue.send(None).unwrap();
        self.job_finished.recv().unwrap().unwrap();
    }
}
struct PanicHandler {
    tx: mpsc::Sender<Result<(), ()>>
}
impl Drop for PanicHandler {
    fn drop(&mut self) {
        let msg = if thread::panicking() { Err(()) } else { Ok(()) };
        self.tx.send(msg).unwrap();
    }
}
struct PanicCanary<'a> {
    flag: &'a atomic::AtomicBool
}
#[unsafe_destructor]
impl<'a> Drop for PanicCanary<'a> {
    fn drop(&mut self) {
        if thread::panicking() {
            self.flag.store(true, atomic::Ordering::SeqCst)
        }
    }
}
impl Pool {
    /// Create a new thread pool with `n_threads` worker threads.
    pub fn new(n_threads: usize) -> Pool {
        let (tx, rx) = mpsc::channel::<Option<Job>>();
        let (finished_tx, finished_rx) = mpsc::channel();

        thread::spawn(move || {
            let ref panicked = atomic::AtomicBool::new(false);

            let mut _guards = Vec::with_capacity(n_threads);
            let mut txs = Vec::with_capacity(n_threads);
            let finished_tx = PanicHandler {
                tx: finished_tx,
            };

            for i in 0..n_threads {
                let id = WorkerId { n: i };
                let (subtx, subrx) = mpsc::channel::<Work>();
                txs.push(subtx);

                _guards.push(thread::scoped(move || {
                    let _canary = PanicCanary {
                        flag: panicked
                    };
                    loop {
                        match subrx.recv() {
                            Ok(mut work) => {
                                (work.func)(id)
                            }
                            Err(_) => break,
                        }
                    }
                }))
            }

            while let Ok(Some(job)) = rx.recv() {
                job.func.invoke(&txs);
                let job_panicked = panicked.load(atomic::Ordering::SeqCst);
                let msg = if job_panicked { Err(()) } else { Ok(()) };
                finished_tx.tx.send(msg).unwrap();

                if job_panicked { break }
            }
        });

        Pool {
            job_queue: tx,
            job_finished: finished_rx,
            n_threads: n_threads,
        }
    }

    /// Execute `f` on each element of `iter`.
    ///
    /// This panics if `f` panics, although the precise time and
    /// number of elements consumed after the element that panics is
    /// not specified.
    pub fn for_<Iter: IntoIterator, F>(&mut self, iter: Iter, ref f: F)
        where Iter::Item: Send,
              Iter: Send,
              F: Fn(Iter::Item) + Sync

    {
        let (needwork_tx, needwork_rx) = mpsc::channel();
        let mut work_txs = Vec::with_capacity(self.n_threads);
        let mut work_rxs = Vec::with_capacity(self.n_threads);
        for _ in 0..self.n_threads {
            let (t, r) = mpsc::channel();
            work_txs.push(t);
            work_rxs.push(r);
        }

        let mut work_rxs = work_rxs.into_iter();

        unsafe {
            let handle = self.execute(
                needwork_tx,
                |needwork_tx| {
                    let mut needwork_tx = Some(needwork_tx.clone());
                    let mut work_rx = Some(work_rxs.next().unwrap());
                    move |id| {
                        let work_rx = work_rx.take().unwrap();
                        let needwork = needwork_tx.take().unwrap();
                        loop {
                            needwork.send(id).unwrap();
                            match work_rx.recv() {
                                Ok(Some(elem)) => {
                                    f(elem);
                                }
                                Ok(None) | Err(_) => break
                            }
                        }
                    }
                },
                move |needwork_tx| {
                    let mut iter = iter.into_iter().fuse();
                    drop(needwork_tx);
                    loop {
                        match needwork_rx.recv() {
                            // closed, done!
                            Err(_) => break,
                            Ok(id) => {
                                work_txs[id.n].send(iter.next()).unwrap();
                            }
                        }
                    }
                });

            handle.wait();
        }
    }

    /// Execute `f` on each element in `iter` in parallel across the
    /// pool's threads, with unspecified yield order.
    ///
    /// This behaves like `map`, but does not make efforts to ensure
    /// that the elements are returned in the order of `iter`, hence
    /// this is cheaper.
    pub fn unordered_map<'pool, 'a, I: IntoIterator, F, T>(&'pool mut self, iter: I, f: &'a F)
        -> UnorderedParMap<'pool, 'a, T>
        where I: 'a + Send,
              I::Item: Send + 'a,
              F: 'a + Sync + Fn(I::Item) -> T,
              T: Send + 'a
    {
        let (needwork_tx, needwork_rx) = mpsc::channel();
        let mut work_txs = Vec::with_capacity(self.n_threads);
        let mut work_rxs = Vec::with_capacity(self.n_threads);
        for _ in 0..self.n_threads {
            let (t, r) = mpsc::channel();
            work_txs.push(t);
            work_rxs.push(r);
        }

        let mut work_rxs = work_rxs.into_iter();

        let (tx, rx) = mpsc::channel();

        let handle = unsafe {
            self.execute(needwork_tx,
                         move |needwork_tx| {
                             let mut needwork_tx = Some(needwork_tx.clone());
                             let mut work_rx = Some(work_rxs.next().unwrap());
                             let tx = tx.clone();
                             move |id| {
                                 let work_rx = work_rx.take().unwrap();
                                 let needwork = needwork_tx.take().unwrap();
                                 loop {
                                     needwork.send(id).unwrap();
                                     match work_rx.recv() {
                                         Ok(Some((idx, elem))) => {
                                             let data = f(elem);
                                             let status = tx.send(Packet {
                                                 idx: idx, data: Some(data)
                                             });
                                             // the user disconnected,
                                             // so there's no point
                                             // computing more.
                                             if status.is_err() {
                                                 break
                                             }
                                         }
                                         Ok(None) | Err(_) => break
                                     }
                                 }
                             }
                         },
                         move |needwork_tx| {
                             let mut iter = iter.into_iter().fuse().enumerate();
                             drop(needwork_tx);
                             loop {
                                 match needwork_rx.recv() {
                                     // closed, done!
                                     Err(_) => break,
                                     Ok(id) => {
                                         work_txs[id.n].send(iter.next()).unwrap();
                                     }
                                 }
                             }
                         })
        };

        UnorderedParMap {
            rx: rx,
            _guard: handle,
        }
    }

    /// Execute `f` on `iter` in parallel across the pool's threads,
    /// returning an iterator that yields the results in the order of
    /// the elements of `iter` to which they correspond.
    ///
    /// This is a drop-in replacement for `iter.map(f)`, that runs in
    /// parallel, and consumes `iter` as the pool's threads complete
    /// their previous tasks.
    pub fn map<'pool, 'a, I: IntoIterator, F, T>(&'pool mut self, iter: I, f: &'a F)
        -> ParMap<'pool, 'a, T>
        where I: 'a + Send,
              I::Item: Send + 'a,
              F: 'a + Sync + Fn(I::Item) -> T,
              T: Send + 'a
    {
        ParMap {
            unordered: self.unordered_map(iter, f),
            looking_for: 0,
            queue: BinaryHeap::new(),
        }
    }
}

/// Low-level/internal functionality.
impl Pool {
    /// Run a job on the thread pool.
    ///
    /// `gen_fn` is called `self.n_threads` times to create the
    /// functions to execute on the worker threads. Each of these is
    /// immediately called exactly once on a worker thread (that is,
    /// they are semantically `FnOnce`), and `main_fn` is also called,
    /// on the supervisor thread. It is expected that the workers and
    /// `main_fn` will manage any internal coordination required to
    /// distribute chunks of work.
    ///
    /// The job must take pains to ensure `main_fn` doesn't quit
    /// before the workers do.
    pub unsafe fn execute<'pool, 'f, A, GenFn, WorkerFn, MainFn>(
        &'pool mut self, data: A, gen_fn: GenFn, main_fn: MainFn) -> JobHandle<'pool, 'f>

        where A: 'f + Send,
              GenFn: 'f + FnMut(&mut A) -> WorkerFn + Send,
              WorkerFn: 'f + FnMut(WorkerId) + Send,
              MainFn: 'f + FnOnce(A) + Send,
    {
        self.execute_nonunsafe(data, gen_fn, main_fn)
    }

    // separate function to ensure we get `unsafe` checking inside this one
    fn execute_nonunsafe<'pool, 'f, A, GenFn, WorkerFn, MainFn>(
        &'pool mut self, mut data: A,
        mut gen_fn: GenFn, main_fn: MainFn) -> JobHandle<'pool, 'f>

        where A: 'f + Send,
              GenFn: 'f + FnMut(&mut A) -> WorkerFn + Send,
              WorkerFn: 'f + FnMut(WorkerId) + Send,
              MainFn: 'f + FnOnce(A) + Send,
    {
        let n_threads = self.n_threads;
        // transmutes scary? only a little: the returned `JobHandle`
        // ensures safety by connecting this job to the outside stack
        // frame.
        let func: JobInner<'f> = Box::new(move |workers: &[mpsc::Sender<Work>]| {
            assert_eq!(workers.len(), n_threads);
            let mut worker_fns: Vec<_> = (0..n_threads).map(|_| gen_fn(&mut data)).collect();

            for (func, worker) in worker_fns.iter_mut().zip(workers.iter()) {
                let func: WorkInner = func;
                let func: WorkInner<'static> = unsafe {
                    mem::transmute(func)
                };
                worker.send(Work { func: func }).unwrap();
            }

            main_fn(data)
        });
        let func: JobInner<'static> = unsafe {
            mem::transmute(func)
        };
        self.job_queue.send(Some(Job { func: func })).unwrap();

        JobHandle {
            pool: self,
            wait: true,
            _funcs: marker::PhantomData,
        }
    }
}

use std::cmp::Ordering;

struct Packet<T> {
    // this should be unique for a given instance of `*ParMap`
    idx: usize,
    data: Option<T>,
}
impl<T> PartialOrd for Packet<T> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
}
impl<T> Ord for Packet<T> {
    // reverse the ordering, to work with the max-heap
    fn cmp(&self, other: &Self) -> Ordering { other.idx.cmp(&self.idx) }
}
impl<T> PartialEq for Packet<T> {
    fn eq(&self, other: &Self) -> bool { self.idx == other.idx }
}
impl<T> Eq for Packet<T> {}

/// A parallel-mapping iterator, that yields elements in the order
/// they are computed, not the order from which they are yielded by
/// the underlying iterator.
pub struct UnorderedParMap<'pool, 'a, T: 'a + Send> {
    rx: mpsc::Receiver<Packet<T>>,
    _guard: JobHandle<'pool, 'a>,
}
impl<'pool, 'a,T: 'a + Send> Iterator for UnorderedParMap<'pool , 'a, T> {
    type Item = (usize, T);

    fn next(&mut self) -> Option<(usize, T)> {
        match self.rx.recv() {
            Ok(Packet { data: Some(x), idx }) => Some((idx, x)),
            Ok(Packet { data: None, .. }) => {
                panic!("simple_parallel::unordered_map: closure panicked")
            }
            Err(mpsc::RecvError) => None,
        }
    }
}

/// A parallel-mapping iterator, that yields elements in the order
/// they are yielded by the underlying iterator.
pub struct ParMap<'pool, 'a, T: 'a + Send> {
    unordered: UnorderedParMap<'pool, 'a, T>,
    looking_for: usize,
    queue: BinaryHeap<Packet<T>>
}

impl<'pool, 'a, T: Send + 'a> Iterator for ParMap<'pool, 'a, T> {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        loop {
            if self.queue.peek().map_or(false, |x| x.idx == self.looking_for) {
                // we've found what we want, so lets return it

                let packet = self.queue.pop().unwrap();
                self.looking_for += 1;
                match packet.data {
                    Some(x) => return Some(x),
                    None => panic!("simple_parallel::map: closure panicked")
                }
            }
            match self.unordered.rx.recv() {
                // this could be optimised to check for `packet.idx ==
                // self.looking_for` to avoid the BinaryHeap
                // interaction if its what we want.
                Ok(packet) => self.queue.push(packet),
                // all done
                Err(mpsc::RecvError) => return None,
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::Write;
use std::marker::PhantomData;
use Event;

pub struct ReadHtml<'a, I> where I: Iterator<Item=Event<'a>> + 'a {
    events: I,
    current: Vec<u8>,
    phantom: PhantomData<&'a I>,
}

impl<'a, I> ReadHtml<'a, I> where I: Iterator<Item=Event<'a>> {
    pub fn new<II>(events: II) -> ReadHtml<'a, I> where II: IntoIterator<IntoIter=I, Item=Event<'a>> {
        ReadHtml {
            events: events.into_iter(),
            current: Vec::new(),
            phantom: PhantomData,
        }
    }
}

impl<'a, I> io::Read for ReadHtml<'a, I> where I: Iterator<Item=Event<'a>> {
    fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
        while self.current.len() < buf.len() {
            if let Some(next) = self.events.next() {
                try!(write!(&mut self.current, "{}", next));
            } else {
                break;
            }
        }

        if self.current.len() < buf.len() {
            let len = self.current.len();
            buf[..len].clone_from_slice(&self.current[..]);
            self.current.clear();
            Ok(len)
        } else {
            let leftover = self.current.split_off(buf.len());
            buf.clone_from_slice(&self.current[..]);
            self.current.clear();
            self.current.extend_from_slice(&leftover[..]);
            Ok(buf.len())
        }
    }
}

#[cfg(test)]
mod tests {
    use std::io::Read;
    use ReadHtml;

    #[test]
    fn test() {
        let events = vec![
            start_tag!("h1", attrs!["id" => "hello"]),
            text!("Hello, "),
            start_tag!("small", attrs!["id" => "world"]),
            text!("world"),
            end_tag!("small"),
            end_tag!("h1"),
        ];

        let mut result = String::new();
        ReadHtml::new(events).read_to_string(&mut result).unwrap();

        assert_eq!(result, "
Hello, world
");
    }
}
<commit_msg>ReadHtml::read simplify<commit_after>use std::io;
use std::io::Write;
use std::marker::PhantomData;
use Event;

pub struct ReadHtml<'a, I> where I: Iterator<Item=Event<'a>> + 'a {
    events: I,
    current: Vec<u8>,
    phantom: PhantomData<&'a I>,
}

impl<'a, I> ReadHtml<'a, I> where I: Iterator<Item=Event<'a>> {
    pub fn new<II>(events: II) -> ReadHtml<'a, I> where II: IntoIterator<IntoIter=I, Item=Event<'a>> {
        ReadHtml {
            events: events.into_iter(),
            current: Vec::new(),
            phantom: PhantomData,
        }
    }
}

impl<'a, I> io::Read for ReadHtml<'a, I> where I: Iterator<Item=Event<'a>> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        while self.current.len() == 0 {
            if let Some(event) = self.events.next() {
                // Possible to do better?
                try!(write!(&mut self.current, "{}", event));
            } else {
                return Ok(0)
            }
        }
        let curlen = self.current.len();
        let len = ::std::cmp::min(curlen, buf.len());
        buf[..len].clone_from_slice(&self.current[..len]);
        for i in len..curlen {
            self.current[i - len] = self.current[i];
        }
        self.current.truncate(curlen - len);
        Ok(len)
    }
}

#[cfg(test)]
mod tests {
    use std::io::Read;
    use ReadHtml;

    #[test]
    fn test() {
        let events = vec![
            start_tag!("h1", attrs!["id" => "hello"]),
            text!("Hello, "),
            ::Event::RawHtml("".into()), // empty event
            start_tag!("small", attrs!["id" => "world"]),
            text!("world"),
            end_tag!("small"),
            end_tag!("h1"),
        ];

        let mut result = String::new();
        ReadHtml::new(events).read_to_string(&mut result).unwrap();

        assert_eq!(result, "
Hello, world
");
    }
}
<|endoftext|>


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

use std::cmp;
use collections::HashSet;
use std::local_data;
use std::uint;
use syntax::ast;
use rustc::util::nodemap::NodeSet;

use clean;
use clean::Item;
use plugins;
use fold;
use fold::DocFolder;

/// Strip items marked `#[doc(hidden)]`
pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult {
    let mut stripped = HashSet::new();

    // strip all #[doc(hidden)] items
    let krate = {
        struct Stripper<'a> {
            stripped: &'a mut HashSet<ast::NodeId>
        };
        impl<'a> fold::DocFolder for Stripper<'a> {
            fn fold_item(&mut self, i: Item) -> Option<Item> {
                for attr in i.attrs.iter() {
                    match attr {
                        &clean::List(ref x, ref l) if "doc" == *x => {
                            for innerattr in l.iter() {
                                match innerattr {
                                    &clean::Word(ref s) if "hidden" == *s => {
                                        debug!("found one in strip_hidden; removing");
                                        self.stripped.insert(i.id);
                                        return None;
                                    },
                                    _ => (),
                                }
                            }
                        },
                        _ => ()
                    }
                }
                self.fold_item_recur(i)
            }
        }
        let mut stripper = Stripper{ stripped: &mut stripped };
        stripper.fold_crate(krate)
    };

    // strip any traits implemented on stripped items
    let krate = {
        struct ImplStripper<'a> {
            stripped: &'a mut HashSet<ast::NodeId>
        };
        impl<'a> fold::DocFolder for ImplStripper<'a> {
            fn fold_item(&mut self, i: Item) -> Option<Item> {
                match i.inner {
                    clean::ImplItem(clean::Impl{ for_: clean::ResolvedPath{ id: for_id, .. },
                                                 .. }) => {
                        if self.stripped.contains(&for_id) {
                            return None;
                        }
                    }
                    _ => {}
                }
                self.fold_item_recur(i)
            }
        }
        let mut stripper = ImplStripper{ stripped: &mut stripped };
        stripper.fold_crate(krate)
    };

    (krate, None)
}

/// Strip private items from the point of view of a crate or externally from a
/// crate, specified by the `xcrate` flag.
pub fn strip_private(krate: clean::Crate) -> plugins::PluginResult {
    // This stripper collects all *retained* nodes.
    let mut retained = HashSet::new();
    let exported_items = local_data::get(super::analysiskey, |analysis| {
        analysis.unwrap().exported_items.clone()
    });
    let mut krate = krate;

    // strip all private items
    {
        let mut stripper = Stripper {
            retained: &mut retained,
            exported_items: &exported_items,
        };
        krate = stripper.fold_crate(krate);
    }

    // strip all private implementations of traits
    {
        let mut stripper = ImplStripper(&retained);
        krate = stripper.fold_crate(krate);
    }
    (krate, None)
}

struct Stripper<'a> {
    retained: &'a mut HashSet<ast::NodeId>,
    exported_items: &'a NodeSet,
}

impl<'a> fold::DocFolder for Stripper<'a> {
    fn fold_item(&mut self, i: Item) -> Option<Item> {
        match i.inner {
            // These items can all get re-exported
            clean::TypedefItem(..) | clean::StaticItem(..) |
            clean::StructItem(..) | clean::EnumItem(..) |
            clean::TraitItem(..) | clean::FunctionItem(..) |
            clean::VariantItem(..) | clean::MethodItem(..) |
            clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) => {
                if !self.exported_items.contains(&i.id) {
                    return None;
                }
            }

            clean::ViewItemItem(..) => {
                if i.visibility != Some(ast::Public) {
                    return None
                }
            }

            clean::StructFieldItem(..) => {
                if i.visibility == Some(ast::Private) {
                    return None;
                }
            }

            // handled below
            clean::ModuleItem(..) => {}

            // trait impls for private items should be stripped
            clean::ImplItem(clean::Impl{ for_: clean::ResolvedPath{ id: ref for_id, .. }, .. }) => {
                if !self.exported_items.contains(for_id) {
                    return None;
                }
            }
            clean::ImplItem(..) => {}

            // tymethods/macros have no control over privacy
            clean::MacroItem(..) | clean::TyMethodItem(..) => {}
        }

        let fastreturn = match i.inner {
            // nothing left to do for traits (don't want to filter their
            // methods out, visibility controlled by the trait)
            clean::TraitItem(..) => true,

            // implementations of traits are always public.
            clean::ImplItem(ref imp) if imp.trait_.is_some() => true,

            _ => false,
        };

        let i = if fastreturn {
            self.retained.insert(i.id);
            return Some(i);
        } else {
            self.fold_item_recur(i)
        };

        match i {
            Some(i) => {
                match i.inner {
                    // emptied modules/impls have no need to exist
                    clean::ModuleItem(ref m)
                        if m.items.len() == 0 &&
                           i.doc_value().is_none() => None,
                    clean::ImplItem(ref i) if i.methods.len() == 0 => None,
                    _ => {
                        self.retained.insert(i.id);
                        Some(i)
                    }
                }
            }
            None => None,
        }
    }
}

// This stripper discards all private impls of traits
struct ImplStripper<'a>(&'a HashSet<ast::NodeId>);
impl<'a> fold::DocFolder for ImplStripper<'a> {
    fn fold_item(&mut self, i: Item) -> Option<Item> {
        match i.inner {
            clean::ImplItem(ref imp) => {
                match imp.trait_ {
                    Some(clean::ResolvedPath{ id, .. }) => {
                        let ImplStripper(s) = *self;
                        if !s.contains(&id) {
                            return None;
                        }
                    }
                    Some(..) | None => {}
                }
            }
            _ => {}
        }
        self.fold_item_recur(i)
    }
}

pub fn unindent_comments(krate: clean::Crate) -> plugins::PluginResult {
    struct CommentCleaner;
    impl fold::DocFolder for CommentCleaner {
        fn fold_item(&mut self, i: Item) -> Option<Item> {
            let mut i = i;
            let mut avec: Vec<clean::Attribute> = Vec::new();
            for attr in i.attrs.iter() {
                match attr {
                    &clean::NameValue(ref x, ref s) if "doc" == *x => avec.push(
                        clean::NameValue(~"doc", unindent(*s))),
                    x => avec.push(x.clone())
                }
            }
            i.attrs = avec;
            self.fold_item_recur(i)
        }
    }
    let mut cleaner = CommentCleaner;
    let krate = cleaner.fold_crate(krate);
    (krate, None)
}

pub fn collapse_docs(krate: clean::Crate) -> plugins::PluginResult {
    struct Collapser;
    impl fold::DocFolder for Collapser {
        fn fold_item(&mut self, i: Item) -> Option<Item> {
            let mut docstr = ~"";
            let mut i = i;
            for attr in i.attrs.iter() {
                match *attr {
                    clean::NameValue(ref x, ref s) if "doc" == *x => {
                        docstr.push_str(s.clone());
                        docstr.push_char('\n');
                    },
                    _ => ()
                }
            }
            let mut a: Vec<clean::Attribute> = i.attrs.iter().filter(|&a| match a {
                &clean::NameValue(ref x, _) if "doc" == *x => false,
                _ => true
            }).map(|x| x.clone()).collect();
            if "" != docstr {
                a.push(clean::NameValue(~"doc", docstr));
            }
            i.attrs = a;
            self.fold_item_recur(i)
        }
    }
    let mut collapser = Collapser;
    let krate = collapser.fold_crate(krate);
    (krate, None)
}

pub fn unindent(s: &str) -> ~str {
    let lines = s.lines_any().collect::<Vec<&str> >();
    let mut saw_first_line = false;
    let mut saw_second_line = false;
    let min_indent = lines.iter().fold(uint::MAX, |min_indent, line| {

        // After we see the first non-whitespace line, look at
        // the line we have. If it is not whitespace, and therefore
        // part of the first paragraph, then ignore the indentation
        // level of the first line
        let ignore_previous_indents =
            saw_first_line &&
            !saw_second_line &&
            !line.is_whitespace();

        let min_indent = if ignore_previous_indents {
            uint::MAX
        } else {
            min_indent
        };

        if saw_first_line {
            saw_second_line = true;
        }

        if line.is_whitespace() {
            min_indent
        } else {
            saw_first_line = true;
            let mut spaces = 0;
            line.chars().all(|char| {
                // Only comparing against space because I wouldn't
                // know what to do with mixed whitespace chars
                if char == ' ' {
                    spaces += 1;
                    true
                } else {
                    false
                }
            });
            cmp::min(min_indent, spaces)
        }
    });

    if lines.len() >= 1 {
        let mut unindented = vec!( lines.get(0).trim() );
        unindented.push_all(lines.tail().iter().map(|&line| {
            if line.is_whitespace() {
                line
            } else {
                assert!(line.len() >= min_indent);
                line.slice_from(min_indent)
            }
        }).collect::<Vec<_>>().as_slice());
        unindented.connect("\n")
    } else {
        s.to_owned()
    }
}

#[cfg(test)]
mod unindent_tests {
    use super::unindent;

    #[test]
    fn should_unindent() {
        let s = ~"    line1\n    line2";
        let r = unindent(s);
        assert_eq!(r, ~"line1\nline2");
    }

    #[test]
    fn should_unindent_multiple_paragraphs() {
        let s = ~"    line1\n\n    line2";
        let r = unindent(s);
        assert_eq!(r, ~"line1\n\nline2");
    }

    #[test]
    fn should_leave_multiple_indent_levels() {
        // Line 2 is indented another level beyond the
        // base indentation and should be preserved
        let s = ~"    line1\n\n        line2";
        let r = unindent(s);
        assert_eq!(r, ~"line1\n\n    line2");
    }

    #[test]
    fn should_ignore_first_line_indent() {
        // Thi first line of the first paragraph may not be indented as
        // far due to the way the doc string was written:
        //
        // #[doc = "Start way over here
        //          and continue here"]
        let s = ~"line1\n    line2";
        let r = unindent(s);
        assert_eq!(r, ~"line1\nline2");
    }

    #[test]
    fn should_not_ignore_first_line_indent_in_a_single_line_para() {
        let s = ~"line1\n\n    line2";
        let r = unindent(s);
        assert_eq!(r, ~"line1\n\n    line2");
    }
}
<commit_msg>rustdoc: Fix hiding of private fields<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::cmp;
use collections::HashSet;
use std::local_data;
use std::uint;
use syntax::ast;
use rustc::util::nodemap::NodeSet;

use clean;
use clean::Item;
use plugins;
use fold;
use fold::DocFolder;

/// Strip items marked `#[doc(hidden)]`
pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult {
    let mut stripped = HashSet::new();

    // strip all #[doc(hidden)] items
    let krate = {
        struct Stripper<'a> {
            stripped: &'a mut HashSet<ast::NodeId>
        };
        impl<'a> fold::DocFolder for Stripper<'a> {
            fn fold_item(&mut self, i: Item) -> Option<Item> {
                for attr in i.attrs.iter() {
                    match attr {
                        &clean::List(ref x, ref l) if "doc" == *x => {
                            for innerattr in l.iter() {
                                match innerattr {
                                    &clean::Word(ref s) if "hidden" == *s => {
                                        debug!("found one in strip_hidden; removing");
                                        self.stripped.insert(i.id);
                                        return None;
                                    },
                                    _ => (),
                                }
                            }
                        },
                        _ => ()
                    }
                }
                self.fold_item_recur(i)
            }
        }
        let mut stripper = Stripper{ stripped: &mut stripped };
        stripper.fold_crate(krate)
    };

    // strip any traits implemented on stripped items
    let krate = {
        struct ImplStripper<'a> {
            stripped: &'a mut HashSet<ast::NodeId>
        };
        impl<'a> fold::DocFolder for ImplStripper<'a> {
            fn fold_item(&mut self, i: Item) -> Option<Item> {
                match i.inner {
                    clean::ImplItem(clean::Impl{ for_: clean::ResolvedPath{ id: for_id, .. },
                                                 .. }) => {
                        if self.stripped.contains(&for_id) {
                            return None;
                        }
                    }
                    _ => {}
                }
                self.fold_item_recur(i)
            }
        }
        let mut stripper = ImplStripper{ stripped: &mut stripped };
        stripper.fold_crate(krate)
    };

    (krate, None)
}

/// Strip private items from the point of view of a crate or externally from a
/// crate, specified by the `xcrate` flag.
pub fn strip_private(krate: clean::Crate) -> plugins::PluginResult {
    // This stripper collects all *retained* nodes.
    let mut retained = HashSet::new();
    let exported_items = local_data::get(super::analysiskey, |analysis| {
        analysis.unwrap().exported_items.clone()
    });
    let mut krate = krate;

    // strip all private items
    {
        let mut stripper = Stripper {
            retained: &mut retained,
            exported_items: &exported_items,
        };
        krate = stripper.fold_crate(krate);
    }

    // strip all private implementations of traits
    {
        let mut stripper = ImplStripper(&retained);
        krate = stripper.fold_crate(krate);
    }
    (krate, None)
}

struct Stripper<'a> {
    retained: &'a mut HashSet<ast::NodeId>,
    exported_items: &'a NodeSet,
}

impl<'a> fold::DocFolder for Stripper<'a> {
    fn fold_item(&mut self, i: Item) -> Option<Item> {
        match i.inner {
            // These items can all get re-exported
            clean::TypedefItem(..) | clean::StaticItem(..) |
            clean::StructItem(..) | clean::EnumItem(..) |
            clean::TraitItem(..) | clean::FunctionItem(..) |
            clean::VariantItem(..) | clean::MethodItem(..) |
            clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) => {
                if !self.exported_items.contains(&i.id) {
                    return None;
                }
            }

            clean::ViewItemItem(..) | clean::StructFieldItem(..) => {
                if i.visibility != Some(ast::Public) {
                    return None
                }
            }

            // handled below
            clean::ModuleItem(..) => {}

            // trait impls for private items should be stripped
            clean::ImplItem(clean::Impl{ for_: clean::ResolvedPath{ id: ref for_id, .. }, .. }) => {
                if !self.exported_items.contains(for_id) {
                    return None;
                }
            }
            clean::ImplItem(..) => {}

            // tymethods/macros have no control over privacy
            clean::MacroItem(..) | clean::TyMethodItem(..) => {}
        }

        let fastreturn = match i.inner {
            // nothing left to do for traits (don't want to filter their
            // methods out, visibility controlled by the trait)
            clean::TraitItem(..) => true,

            // implementations of traits are always public.
            clean::ImplItem(ref imp) if imp.trait_.is_some() => true,

            _ => false,
        };

        let i = if fastreturn {
            self.retained.insert(i.id);
            return Some(i);
        } else {
            self.fold_item_recur(i)
        };

        match i {
            Some(i) => {
                match i.inner {
                    // emptied modules/impls have no need to exist
                    clean::ModuleItem(ref m)
                        if m.items.len() == 0 &&
                           i.doc_value().is_none() => None,
                    clean::ImplItem(ref i) if i.methods.len() == 0 => None,
                    _ => {
                        self.retained.insert(i.id);
                        Some(i)
                    }
                }
            }
            None => None,
        }
    }
}

// This stripper discards all private impls of traits
struct ImplStripper<'a>(&'a HashSet<ast::NodeId>);
impl<'a> fold::DocFolder for ImplStripper<'a> {
    fn fold_item(&mut self, i: Item) -> Option<Item> {
        match i.inner {
            clean::ImplItem(ref imp) => {
                match imp.trait_ {
                    Some(clean::ResolvedPath{ id, .. }) => {
                        let ImplStripper(s) = *self;
                        if !s.contains(&id) {
                            return None;
                        }
                    }
                    Some(..) | None => {}
                }
            }
            _ => {}
        }
        self.fold_item_recur(i)
    }
}

pub fn unindent_comments(krate: clean::Crate) -> plugins::PluginResult {
    struct CommentCleaner;
    impl fold::DocFolder for CommentCleaner {
        fn fold_item(&mut self, i: Item) -> Option<Item> {
            let mut i = i;
            let mut avec: Vec<clean::Attribute> = Vec::new();
            for attr in i.attrs.iter() {
                match attr {
                    &clean::NameValue(ref x, ref s) if "doc" == *x => avec.push(
                        clean::NameValue(~"doc", unindent(*s))),
                    x => avec.push(x.clone())
                }
            }
            i.attrs = avec;
            self.fold_item_recur(i)
        }
    }
    let mut cleaner = CommentCleaner;
    let krate = cleaner.fold_crate(krate);
    (krate, None)
}

pub fn collapse_docs(krate: clean::Crate) -> plugins::PluginResult {
    struct Collapser;
    impl fold::DocFolder for Collapser {
        fn fold_item(&mut self, i: Item) -> Option<Item> {
            let mut docstr = ~"";
            let mut i = i;
            for attr in i.attrs.iter() {
                match *attr {
                    clean::NameValue(ref x, ref s) if "doc" == *x => {
                        docstr.push_str(s.clone());
                        docstr.push_char('\n');
                    },
                    _ => ()
                }
            }
            let mut a: Vec<clean::Attribute> = i.attrs.iter().filter(|&a| match a {
                &clean::NameValue(ref x, _) if "doc" == *x => false,
                _ => true
            }).map(|x| x.clone()).collect();
            if "" != docstr {
                a.push(clean::NameValue(~"doc", docstr));
            }
            i.attrs = a;
            self.fold_item_recur(i)
        }
    }
    let mut collapser = Collapser;
    let krate = collapser.fold_crate(krate);
    (krate, None)
}

pub fn unindent(s: &str) -> ~str {
    let lines = s.lines_any().collect::<Vec<&str> >();
    let mut saw_first_line = false;
    let mut saw_second_line = false;
    let min_indent = lines.iter().fold(uint::MAX, |min_indent, line| {

        // After we see the first non-whitespace line, look at
        // the line we have. If it is not whitespace, and therefore
        // part of the first paragraph, then ignore the indentation
        // level of the first line
        let ignore_previous_indents =
            saw_first_line &&
            !saw_second_line &&
            !line.is_whitespace();

        let min_indent = if ignore_previous_indents {
            uint::MAX
        } else {
            min_indent
        };

        if saw_first_line {
            saw_second_line = true;
        }

        if line.is_whitespace() {
            min_indent
        } else {
            saw_first_line = true;
            let mut spaces = 0;
            line.chars().all(|char| {
                // Only comparing against space because I wouldn't
                // know what to do with mixed whitespace chars
                if char == ' ' {
                    spaces += 1;
                    true
                } else {
                    false
                }
            });
            cmp::min(min_indent, spaces)
        }
    });

    if lines.len() >= 1 {
        let mut unindented = vec!( lines.get(0).trim() );
        unindented.push_all(lines.tail().iter().map(|&line| {
            if line.is_whitespace() {
                line
            } else {
                assert!(line.len() >= min_indent);
                line.slice_from(min_indent)
            }
        }).collect::<Vec<_>>().as_slice());
        unindented.connect("\n")
    } else {
        s.to_owned()
    }
}

#[cfg(test)]
mod unindent_tests {
    use super::unindent;

    #[test]
    fn should_unindent() {
        let s = ~"    line1\n    line2";
        let r = unindent(s);
        assert_eq!(r, ~"line1\nline2");
    }

    #[test]
    fn should_unindent_multiple_paragraphs() {
        let s = ~"    line1\n\n    line2";
        let r = unindent(s);
        assert_eq!(r, ~"line1\n\nline2");
    }

    #[test]
    fn should_leave_multiple_indent_levels() {
        // Line 2 is indented another level beyond the
        // base indentation and should be preserved
        let s = ~"    line1\n\n        line2";
        let r = unindent(s);
        assert_eq!(r, ~"line1\n\n    line2");
    }

    #[test]
    fn should_ignore_first_line_indent() {
        // Thi first line of the first paragraph may not be indented as
        // far due to the way the doc string was written:
        //
        // #[doc = "Start way over here
        //          and continue here"]
        let s = ~"line1\n    line2";
        let r = unindent(s);
        assert_eq!(r, ~"line1\nline2");
    }

    #[test]
    fn should_not_ignore_first_line_indent_in_a_single_line_para() {
        let s = ~"line1\n\n    line2";
        let r = unindent(s);
        assert_eq!(r, ~"line1\n\n    line2");
    }
}
<|endoftext|>


<commit_before>//!Constants and structures from time classes
//!
//! This includes include/uapi/linux/time.h, //include/linux/time.h, and /include/linux/time64.h

///A structure that contains the number of seconds and nanoseconds since an epoch.
///
///If in doubt, assume we're talking about the UNIX epoch.
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct timespec {
    ///The number of seconds contained in this timespec
    pub tv_sec: ::time_t,

    ///The number of nanoseconds contained in this timespec
    pub tv_nsec: ::c_long
}

impl timespec {

    ///Creates a new timespec with both values defaulting to zero
    pub fn new() -> timespec {
        timespec { tv_sec: 0, tv_nsec: 0 }
    }

    ///Clears this timespec, setting each value to zero
    pub fn clear(&mut self) {
        self.tv_sec = 0;
        self.tv_nsec = 0;
    }

}

///A structure that contains the number of seconds and microseconds since an epoch.
///
///If in doubt, assume we're talking about the UNIX epoch.
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct timeval {
    ///The number of seconds contained in this timeval
    pub tv_sec: ::time_t,

    ///The number of microseconds contained in this timeval
    pub tv_usec: ::suseconds_t
}

impl timeval {

    ///Creates a new timeval with both values defaulting to zero
    pub fn new() -> timeval {
        timeval { tv_sec: 0, tv_usec: 0 }
    }

    ///Clears this timeval, setting each value to zero
    pub fn clear(&mut self) {
        self.tv_sec = 0;
        self.tv_usec = 0;
    }

}

///A structure containing information on the time-based location of a timezone
///
///Please note that this does not include the name or country code, only the minutes west of Greenwich and the type of DST correction
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct timezone {
    ///The number of minutes west of Greenwich
    pub tz_minuteswest: ::c_int,

    ///The type of Daylight Savings Time correction
    pub tz_dsttime: ::c_int
}

//Names of the interval timers

///An interval timer that decrements in real time
///
///On expiration, a SIGALRM is delivered
pub const ITIMER_REAL: ::c_int = 0;

///An interval timer that decrements only when the process is executing.
///
///On expiration, a SIGVTALRM is delivered
pub const ITIMER_VIRTUAL: ::c_int = 1;

///Decrements both while the process is executing and while the system is executing on behalf of the process
///
///This is usually used to profile kernel-space and user-space concurrently.
///
///If coupled with ITIMER_VIRTUAL, you can separate the two values - What is left when ITIMER_VIRTUAL's value is removed is kernel time
pub const ITIMER_PROF: ::c_int = 2;

///An interval timer based on a `timespec`
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct itimerspec {
    ///The period of time this timer should run for (Need to verify)
    pub it_interval: timespec,

    ///The amount of time left until expiration (Need to verify)
    pub it_value: timespec
}

///An interval timer based on a `timeval`
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct itimerval {
    ///The period of time this timer should run for (Need to verify)
    pub it_interval: timeval,

    ///The amount of time left until expiration (Need to verify)
    pub it_value: timeval
}

///A system-wide clock that measures time from the "real world"
///
///This clock **is** affected by discontinuous jumps in system time, NTP, and user changes
pub const CLOCK_REALTIME: ::clockid_t = 0;

///A clock that measures monotonic time since an unspecified starting point
///
///Unless you manage to break your system, this unspecified point is usually when your computer powers on.
///
///This is not affected by user changes, but is by `adjtime` and NTP.
pub const CLOCK_MONOTONIC: ::clockid_t = 1;

///A high-resolution per-process timer from the processor.
pub const CLOCK_PROCESS_CPUTIME_ID: ::clockid_t = 2;

///A (high-resolution?) thread-specific timer from the processor
pub const CLOCK_THREAD_CPUTIME_ID: ::clockid_t = 3;

///A hardware-based version of `CLOCK_MONOTONIC` that is not subject to changes
pub const CLOCK_MONOTONIC_RAW: ::clockid_t = 4;

///A faster but less precise version of `CLOCK_REALTIME`, measuring time in the "real world"
pub const CLOCK_REALTIME_COARSE: ::clockid_t = 5;

///A faster but less precise version of `CLOCK_MONOTONIC`, measuring time since an unspecified starting point
pub const CLOCK_MONOTONIC_COARSE: ::clockid_t = 6;

///Identical to `CLOCK_MONOTONIC`, but includes any time that the system is suspended.
pub const CLOCK_BOOTIME: ::clockid_t = 7;

///Identical to `CLOCK_REALTIME`, but timers exposed via this will wake the system if suspended
pub const CLOCK_REALTIME_ALARM: ::clockid_t = 8;

///Identical to `CLOCK_BOOTIME`, but timers exposed via this will wake the system if suspended
pub const CLOCK_BOOTTIME_ALARM: ::clockid_t = 9;

///A clock used for SGI systems. Need to investigate
pub const CLOCK_SGI_CYCLE: ::clockid_t = 10;

///A clock that shows International Atomic Time
pub const CLOCK_TAI: ::clockid_t = 11;

///The maximum clock ID that the system is allowed to have
pub const MAX_CLOCKS: ::clockid_t = 16; //Resolves to c_int. Please let me know if this should be c_int on it's own

///A mask for supported clocks
///
///Needs to be investigated
pub const CLOCKS_MASK: ::clockid_t = CLOCK_REALTIME | CLOCK_MONOTONIC;

///A shorthand variant of CLOCK_MONOTONIC.
///
///This isn't used in the kernel. Is it left over from an old change that was reverted?
pub const CLOCKS_MONO: ::clockid_t = CLOCK_MONOTONIC;

///A flag indicating time is absolute
pub const TIMER_ABSTIME: ::c_int = 0x01;

///The type used for 64-bit time
pub type time64_t = i64;

///The number of milliseconds in a second
pub const MSEC_PER_SEC: ::c_long = 1000;

///The number of microseconds in a millisecond
pub const USEC_PER_MSEC: ::c_long = 1000;

///The number of nanoseconds in a microsecond
pub const NSEC_PER_USEC: ::c_long = 1000;

///The number of nanoseconds in a millisecond
pub const NSEC_PER_MSEC: ::c_long = 1000000;

///The number of microseconds in a second
pub const USEC_PER_SEC: ::c_long = 1000000;

///The number of nanoseconds in a second
pub const NSEC_PER_SEC: ::c_long = 1000000000;

///The number of femtoseconds in a second
pub const FSEC_PER_SEC: ::c_longlong = 1000000000000000;

///The maximim value of a time64_t
pub const TIME64_MAX: ::c_longlong = ((1u64 << 63) as i64);

///The maximum value of a ktime_t
pub const KTIME_MAX: ::c_longlong = 9_223_372_036_854_775_807;

///The maximum number of seconds in a ktime_t
pub const KTIME_SEC_MAX: ::c_longlong = 9_223_372_036;

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

    #[test]
    fn test_per_sec_accuracy() {
        assert_eq!(NSEC_PER_MSEC, NSEC_PER_USEC * USEC_PER_MSEC);
        assert_eq!(NSEC_PER_SEC, NSEC_PER_MSEC * MSEC_PER_SEC);
    }

    #[test]
    fn test_timeval_utility_functions() {
        let mut val: timeval = timeval::new();

        assert_eq!(0, val.tv_sec);

        val.tv_usec += 499;

        assert_eq!(499, val.tv_usec);

        val.clear();

        assert_eq!(0, val.tv_usec);
    }

    #[test]
    fn test_timespec_utility_functions() {
        let mut spec: timespec = timespec::new();

        assert_eq!(0, spec.tv_sec);

        spec.tv_nsec += 499;

        assert_eq!(499, spec.tv_nsec);

        spec.clear();

        assert_eq!(0, spec.tv_nsec);
    }
}<commit_msg>add from_seconds(::time_t) to timespec and timeval<commit_after>//!Constants and structures from time classes
//!
//! This includes include/uapi/linux/time.h, //include/linux/time.h, and /include/linux/time64.h

///A structure that contains the number of seconds and nanoseconds since an epoch.
///
///If in doubt, assume we're talking about the UNIX epoch.
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct timespec {
    ///The number of seconds contained in this timespec
    pub tv_sec: ::time_t,

    ///The number of nanoseconds contained in this timespec
    pub tv_nsec: ::c_long
}

impl timespec {

    ///Creates a new timespec with both values defaulting to zero
    pub fn new() -> timespec {
        timespec { tv_sec: 0, tv_nsec: 0 }
    }

    ///Creates a new timespec from the specified number of seconds
    pub fn from_seconds(seconds: ::time_t) -> timespec {
        timespec { tv_sec: seconds, tv_nsec: 0 }
    }

    ///Clears this timespec, setting each value to zero
    pub fn clear(&mut self) {
        self.tv_sec = 0;
        self.tv_nsec = 0;
    }

}

///A structure that contains the number of seconds and microseconds since an epoch.
///
///If in doubt, assume we're talking about the UNIX epoch.
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct timeval {
    ///The number of seconds contained in this timeval
    pub tv_sec: ::time_t,

    ///The number of microseconds contained in this timeval
    pub tv_usec: ::suseconds_t
}

impl timeval {

    ///Creates a new timeval with both values defaulting to zero
    pub fn new() -> timeval {
        timeval { tv_sec: 0, tv_usec: 0 }
    }

    ///Creates a new timeval from the specified number of seconds
    pub fn from_seconds(seconds: ::time_t) -> timeval {
        timeval { tv_sec: seconds, tv_usec: 0 }
    }

    ///Clears this timeval, setting each value to zero
    pub fn clear(&mut self) {
        self.tv_sec = 0;
        self.tv_usec = 0;
    }

}

///A structure containing information on the time-based location of a timezone
///
///Please note that this does not include the name or country code, only the minutes west of Greenwich and the type of DST correction
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct timezone {
    ///The number of minutes west of Greenwich
    pub tz_minuteswest: ::c_int,

    ///The type of Daylight Savings Time correction
    pub tz_dsttime: ::c_int
}

//Names of the interval timers

///An interval timer that decrements in real time
///
///On expiration, a SIGALRM is delivered
pub const ITIMER_REAL: ::c_int = 0;

///An interval timer that decrements only when the process is executing.
///
///On expiration, a SIGVTALRM is delivered
pub const ITIMER_VIRTUAL: ::c_int = 1;

///Decrements both while the process is executing and while the system is executing on behalf of the process
///
///This is usually used to profile kernel-space and user-space concurrently.
///
///If coupled with ITIMER_VIRTUAL, you can separate the two values - What is left when ITIMER_VIRTUAL's value is removed is kernel time
pub const ITIMER_PROF: ::c_int = 2;

///An interval timer based on a `timespec`
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct itimerspec {
    ///The period of time this timer should run for (Need to verify)
    pub it_interval: timespec,

    ///The amount of time left until expiration (Need to verify)
    pub it_value: timespec
}

///An interval timer based on a `timeval`
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct itimerval {
    ///The period of time this timer should run for (Need to verify)
    pub it_interval: timeval,

    ///The amount of time left until expiration (Need to verify)
    pub it_value: timeval
}

///A system-wide clock that measures time from the "real world"
///
///This clock **is** affected by discontinuous jumps in system time, NTP, and user changes
pub const CLOCK_REALTIME: ::clockid_t = 0;

///A clock that measures monotonic time since an unspecified starting point
///
///Unless you manage to break your system, this unspecified point is usually when your computer powers on.
///
///This is not affected by user changes, but is by `adjtime` and NTP.
pub const CLOCK_MONOTONIC: ::clockid_t = 1;

///A high-resolution per-process timer from the processor.
pub const CLOCK_PROCESS_CPUTIME_ID: ::clockid_t = 2;

///A (high-resolution?) thread-specific timer from the processor
pub const CLOCK_THREAD_CPUTIME_ID: ::clockid_t = 3;

///A hardware-based version of `CLOCK_MONOTONIC` that is not subject to changes
pub const CLOCK_MONOTONIC_RAW: ::clockid_t = 4;

///A faster but less precise version of `CLOCK_REALTIME`, measuring time in the "real world"
pub const CLOCK_REALTIME_COARSE: ::clockid_t = 5;

///A faster but less precise version of `CLOCK_MONOTONIC`, measuring time since an unspecified starting point
pub const CLOCK_MONOTONIC_COARSE: ::clockid_t = 6;

///Identical to `CLOCK_MONOTONIC`, but includes any time that the system is suspended.
pub const CLOCK_BOOTIME: ::clockid_t = 7;

///Identical to `CLOCK_REALTIME`, but timers exposed via this will wake the system if suspended
pub const CLOCK_REALTIME_ALARM: ::clockid_t = 8;

///Identical to `CLOCK_BOOTIME`, but timers exposed via this will wake the system if suspended
pub const CLOCK_BOOTTIME_ALARM: ::clockid_t = 9;

///A clock used for SGI systems. Need to investigate
pub const CLOCK_SGI_CYCLE: ::clockid_t = 10;

///A clock that shows International Atomic Time
pub const CLOCK_TAI: ::clockid_t = 11;

///The maximum clock ID that the system is allowed to have
pub const MAX_CLOCKS: ::clockid_t = 16; //Resolves to c_int. Please let me know if this should be c_int on it's own

///A mask for supported clocks
///
///Needs to be investigated
pub const CLOCKS_MASK: ::clockid_t = CLOCK_REALTIME | CLOCK_MONOTONIC;

///A shorthand variant of CLOCK_MONOTONIC.
///
///This isn't used in the kernel. Is it left over from an old change that was reverted?
pub const CLOCKS_MONO: ::clockid_t = CLOCK_MONOTONIC;

///A flag indicating time is absolute
pub const TIMER_ABSTIME: ::c_int = 0x01;

///The type used for 64-bit time
pub type time64_t = i64;

///The number of milliseconds in a second
pub const MSEC_PER_SEC: ::c_long = 1000;

///The number of microseconds in a millisecond
pub const USEC_PER_MSEC: ::c_long = 1000;

///The number of nanoseconds in a microsecond
pub const NSEC_PER_USEC: ::c_long = 1000;

///The number of nanoseconds in a millisecond
pub const NSEC_PER_MSEC: ::c_long = 1000000;

///The number of microseconds in a second
pub const USEC_PER_SEC: ::c_long = 1000000;

///The number of nanoseconds in a second
pub const NSEC_PER_SEC: ::c_long = 1000000000;

///The number of femtoseconds in a second
pub const FSEC_PER_SEC: ::c_longlong = 1000000000000000;

///The maximum value of a time64_t
//pub const TIME64_MAX: ::c_longlong = ((1u64 << 63) as i64);

///The maximum value of a ktime_t
pub const KTIME_MAX: ::c_longlong = 9_223_372_036_854_775_807;

///The maximum number of seconds in a ktime_t
pub const KTIME_SEC_MAX: ::c_longlong = 9_223_372_036;

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

    #[test]
    fn test_per_sec_accuracy() {
        assert_eq!(NSEC_PER_MSEC, NSEC_PER_USEC * USEC_PER_MSEC);
        assert_eq!(NSEC_PER_SEC, NSEC_PER_MSEC * MSEC_PER_SEC);
    }

    #[test]
    fn test_timeval_utility_functions() {
        let mut val: timeval = timeval::new();

        assert_eq!(0, val.tv_sec);

        val = timeval::from_seconds(100);

        assert_eq!(100, val.tv_sec);

        val.clear();

        assert_eq!(0, val.tv_sec);
    }

    #[test]
    fn test_timespec_utility_functions() {
        let mut spec: timespec = timespec::new();

        assert_eq!(0, spec.tv_sec);

        spec = timespec::from_seconds(164);

        assert_eq!(164, spec.tv_sec);

        spec.clear();

        assert_eq!(0, spec.tv_sec);
    }
}<|endoftext|>


<commit_before>extern crate chrono;
extern crate regex;
extern crate reqwest;
extern crate time;
extern crate url;

use std::fmt::Write;

use failure::Error;
use regex::{Captures, Regex};
use url::Url;

pub type Result<T> = ::std::result::Result<T, Error>;

pub fn print_error(e: &Error) {
    let mut output = String::new();
    writeln!(output, "Error: {}", e).unwrap();
    for cause in e.causes().skip(1) {
        writeln!(output, "  caused by: {}", cause).unwrap();
    }

    writeln!(output, "{}", e.backtrace()).unwrap();
    print!("{}", output);
}

pub fn format_duration(duration: i64) -> String {
    let mut rv = vec![];
    let mut duration = duration;
    if duration > 3600 {
        rv.push(format!("{}", duration / 3600));
        duration -= duration / 3600 * 3600;
    }
    if rv.is_empty() {
        rv.push(format!("{}", duration / 60));
    } else {
        rv.push(format!("{:02}", duration / 60));
    }
    duration -= duration / 60 * 60;
    rv.push(format!("{:02}", duration));
    rv.join(":").to_string()
}

pub fn format_description(description: &[String], base: &Url) -> String {
    lazy_static! {
      static ref HREF_RE: Regex = Regex::new("(src|href)=\"([^\"]*)\"").unwrap();
      static ref LANG_RE: Regex = Regex::new("(srcset|download|data-[^=]*)=\"[^\"]*\"").unwrap();
      static ref GARBAGE_RE: Regex = Regex::new("(Â®| â€.| ðŸ¦)").unwrap();
    }

    let mut rv = HREF_RE
        .replace_all(&description.join(""), |caps: &Captures| {
            format!("{}=\"{}\"", &caps[1], base.join(&caps[2]).unwrap())
        })
        .to_string();
    rv = LANG_RE.replace_all(&rv, "").to_string();
    rv = GARBAGE_RE.replace_all(&rv, "").to_string();
    rv
}

pub fn format_summary(summary: &[String]) -> String {
    lazy_static! {
      static ref GARBAGE_RE: Regex = Regex::new("(Â®| â€.| ðŸ¦)").unwrap();
    }

    let mut rv = summary.join("");
    rv = GARBAGE_RE.replace_all(&rv, "").to_string();
    rv = rv.replace("'", "’");

    if let Some((idx, _)) = rv.char_indices().nth(3990) {
        rv = rv[..idx].to_string();
        rv.push_str("…");
    }
    rv
}
<commit_msg>Print errors out to stdout.<commit_after>extern crate chrono;
extern crate regex;
extern crate reqwest;
extern crate time;
extern crate url;

use std::fmt::Write;

use failure::Error;
use regex::{Captures, Regex};
use url::Url;

pub type Result<T> = ::std::result::Result<T, Error>;

pub fn print_error(e: &Error) {
    let mut output = String::new();
    writeln!(output, "Error: {}", e).unwrap();
    for cause in e.causes().skip(1) {
        writeln!(output, "  caused by: {}", cause).unwrap();
    }

    writeln!(output, "{}", e.backtrace()).unwrap();
    eprint!("{}", output);
}

pub fn format_duration(duration: i64) -> String {
    let mut rv = vec![];
    let mut duration = duration;
    if duration > 3600 {
        rv.push(format!("{}", duration / 3600));
        duration -= duration / 3600 * 3600;
    }
    if rv.is_empty() {
        rv.push(format!("{}", duration / 60));
    } else {
        rv.push(format!("{:02}", duration / 60));
    }
    duration -= duration / 60 * 60;
    rv.push(format!("{:02}", duration));
    rv.join(":").to_string()
}

pub fn format_description(description: &[String], base: &Url) -> String {
    lazy_static! {
      static ref HREF_RE: Regex = Regex::new("(src|href)=\"([^\"]*)\"").unwrap();
      static ref LANG_RE: Regex = Regex::new("(srcset|download|data-[^=]*)=\"[^\"]*\"").unwrap();
      static ref GARBAGE_RE: Regex = Regex::new("(Â®| â€.| ðŸ¦)").unwrap();
    }

    let mut rv = HREF_RE
        .replace_all(&description.join(""), |caps: &Captures| {
            format!("{}=\"{}\"", &caps[1], base.join(&caps[2]).unwrap())
        })
        .to_string();
    rv = LANG_RE.replace_all(&rv, "").to_string();
    rv = GARBAGE_RE.replace_all(&rv, "").to_string();
    rv
}

pub fn format_summary(summary: &[String]) -> String {
    lazy_static! {
      static ref GARBAGE_RE: Regex = Regex::new("(Â®| â€.| ðŸ¦)").unwrap();
    }

    let mut rv = summary.join("");
    rv = GARBAGE_RE.replace_all(&rv, "").to_string();
    rv = rv.replace("'", "’");

    if let Some((idx, _)) = rv.char_indices().nth(3990) {
        rv = rv[..idx].to_string();
        rv.push_str("…");
    }
    rv
}
<|endoftext|>


<commit_before>use chrono::*;
use error::WorklogError;
use timeclock::now;

/// Helper fn for `parse_multi_time_fmt`
/// Parse time from various formats. Returns the current date combined with
/// the parsed time.
fn parse_time(timestr: &str) -> Result<DateTime<FixedOffset>, WorklogError> {
    let ctime = now();
    let cdate = ctime.date();
    let res = try!(NaiveTime::parse_from_str(&timestr, "%H:%M:%S%.f")
        .or(NaiveTime::parse_from_str(&timestr, "%I:%M:%S%.f %p"))
        .or(NaiveTime::parse_from_str(&timestr, "%I:%M %p"))
        .or(NaiveTime::parse_from_str(&timestr, "%H:%M")));

    // unwrap() here isn't ideal, but and_time() can panic anyway
    Ok(cdate.and_time(res).unwrap())
}

/// Helper fn for `parse_multi_time_fmt`
/// Parse a datetime from various formats.
fn parse_datetime(timestr: &str)
                  -> Result<DateTime<FixedOffset>, WorklogError> {
    let ctime = now();
    let offset = ctime.offset();
    // reduce the number of formats to check
    let timestr = timestr.replace("T", " ").replace("/", "-");
    let res = try!(offset.datetime_from_str(&timestr, "%Y-%m-%d %H:%M:%S%.f")
        .or(offset.datetime_from_str(&timestr, "%Y-%m-%d %H:%M:%S%.f"))
        // 2016/12/18 10:31 PM not parsable?
        // .or(offset.datetime_from_str(&timestr, "%Y-%m-%d %I:%M %p"))
        .or(offset.datetime_from_str(&timestr, "%Y-%m-%d %H:%M")));

    Ok(res)

}

/// Try to parse dates and times in as many formats as reasonable
pub fn parse_multi_time_fmt(timestr: &str)
                            -> Result<DateTime<FixedOffset>, WorklogError> {
    // We can pass "now" in and get the current time.
    // Simplifies dealing with -i and -o options
    if timestr == "now" {
        return Ok(now());
    }

    parse_time(timestr).or_else(|_| parse_datetime(timestr))
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::parse_datetime;
    use super::parse_time;

    #[test]
    fn util_parse_time_test() {
        assert!(parse_time("10:31").is_ok());
        assert!(parse_time("10:31AM").is_ok());
        assert!(parse_time("10:31 PM").is_ok());
        assert!(parse_time("10:31:12 PM").is_ok());
        assert!(parse_time("10:31:12.142134366").is_ok());
    }

    #[test]
    fn util_parse_datetime_test() {
        assert!(parse_datetime("2016-12-18 16:53:33.142134366").is_ok());
        assert!(parse_datetime("2016-12-18T16:53:33").is_ok());
        assert!(parse_datetime("2016-12-18T16:53").is_ok());
    }

    #[test]
    fn util_parse_multi_time_fmt_test() {
        assert!(parse_multi_time_fmt("now").is_ok());
        assert!(parse_multi_time_fmt("dfggfh").is_err());
    }
}
<commit_msg>Added round function<commit_after>use chrono::*;
use error::WorklogError;
use timeclock::now;

/// Helper fn for `parse_multi_time_fmt`
/// Parse time from various formats. Returns the current date combined with
/// the parsed time.
fn parse_time(timestr: &str) -> Result<DateTime<FixedOffset>, WorklogError> {
    let ctime = now();
    let cdate = ctime.date();
    let res = try!(NaiveTime::parse_from_str(&timestr, "%H:%M:%S%.f")
        .or(NaiveTime::parse_from_str(&timestr, "%I:%M:%S%.f %p"))
        .or(NaiveTime::parse_from_str(&timestr, "%I:%M %p"))
        .or(NaiveTime::parse_from_str(&timestr, "%H:%M")));

    // unwrap() here isn't ideal, but and_time() can panic anyway
    Ok(cdate.and_time(res).unwrap())
}

/// Helper fn for `parse_multi_time_fmt`
/// Parse a datetime from various formats.
fn parse_datetime(timestr: &str)
                  -> Result<DateTime<FixedOffset>, WorklogError> {
    let ctime = now();
    let offset = ctime.offset();
    // reduce the number of formats to check
    let timestr = timestr.replace("T", " ").replace("/", "-");
    let res = try!(offset.datetime_from_str(&timestr, "%Y-%m-%d %H:%M:%S%.f")
        .or(offset.datetime_from_str(&timestr, "%Y-%m-%d %H:%M:%S%.f"))
        // 2016/12/18 10:31 PM not parsable?
        // .or(offset.datetime_from_str(&timestr, "%Y-%m-%d %I:%M %p"))
        .or(offset.datetime_from_str(&timestr, "%Y-%m-%d %H:%M")));

    Ok(res)

}

/// Try to parse dates and times in as many formats as reasonable
pub fn parse_multi_time_fmt(timestr: &str)
                            -> Result<DateTime<FixedOffset>, WorklogError> {
    // We can pass "now" in and get the current time.
    // Simplifies dealing with -i and -o options
    if timestr == "now" {
        return Ok(now());
    }

    parse_time(timestr).or_else(|_| parse_datetime(timestr))
}

/// Rounding modes for round()
#[derive(Copy,Clone,Debug,PartialEq)]
pub enum Rounding {
    Up(f32),
    Down(f32),
    Half(f32),
    None,
}

/// Round f64 with Rounding mode
pub fn round(seconds: f64, rounding: Rounding) -> f64 {
    let res = match rounding {
        Rounding::Up(r) => (seconds / r as f64).ceil() * r as f64,
        Rounding::Down(r) => (seconds / r as f64).floor() * r as f64,
        Rounding::Half(r) => (seconds / r as f64).round() * r as f64,
        Rounding::None => seconds,
    };
    // don't return NaN
    if res.is_nan() { seconds } else { res }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::parse_datetime;
    use super::parse_time;

    #[test]
    fn util_parse_time_test() {
        assert!(parse_time("10:31").is_ok());
        assert!(parse_time("10:31AM").is_ok());
        assert!(parse_time("10:31 PM").is_ok());
        assert!(parse_time("10:31:12 PM").is_ok());
        assert!(parse_time("10:31:12.142134366").is_ok());
    }

    #[test]
    fn util_parse_datetime_test() {
        assert!(parse_datetime("2016-12-18 16:53:33.142134366").is_ok());
        assert!(parse_datetime("2016-12-18T16:53:33").is_ok());
        assert!(parse_datetime("2016-12-18T16:53").is_ok());
    }

    #[test]
    fn util_parse_multi_time_fmt_test() {
        assert!(parse_multi_time_fmt("now").is_ok());
        assert!(parse_multi_time_fmt("dfggfh").is_err());
    }

    #[test]
    fn round_up_test() {
        const TIME_ACTUAL: f64 = 38160.12345; // ~10:36am in seconds
        const TIME_UP: f64 = 38700.0; // 10:45am in seconds
        const TIME_DOWN: f64 = 37800.0; // 10:30am in seconds

        // round up
        let res = round(TIME_ACTUAL, Rounding::Up(900.0));
        assert_eq!(res, TIME_UP);
        let res = round(TIME_UP, Rounding::Up(900.0));
        assert_eq!(res, TIME_UP);
        let res = round(TIME_UP - 1.0, Rounding::Up(900.0));
        assert_eq!(res, TIME_UP);

        // round down
        let res = round(TIME_ACTUAL, Rounding::Down(900.0));
        assert_eq!(res, TIME_DOWN);
        let res = round(TIME_DOWN, Rounding::Down(900.0));
        assert_eq!(res, TIME_DOWN);
        let res = round(TIME_DOWN + 1.0, Rounding::Down(900.0));
        assert_eq!(res, TIME_DOWN);

        // round half
        let res = round(TIME_ACTUAL, Rounding::Half(900.0));
        assert_eq!(res, TIME_DOWN);
        let res = round(TIME_DOWN, Rounding::Half(900.0));
        assert_eq!(res, TIME_DOWN);

        // round to 1/4 sec
        let res = round(TIME_ACTUAL, Rounding::Up(0.25));
        assert_eq!(res, 38160.25);

        // round with zero
        let res = round(TIME_ACTUAL, Rounding::Up(0.0));
        assert_eq!(res, TIME_ACTUAL);

        // round None
        let res = round(TIME_ACTUAL, Rounding::None);
        assert_eq!(res, TIME_ACTUAL);

    }
}
<|endoftext|>


<commit_before>/* kernel::cstr.rs */
#[allow(unused_imports)];
use core::*;
use core::str::*;
use core::option::{Some, Option, None}; // Match statement
use core::iter::Iterator;
use kernel::*;
use super::super::platform::*;
use kernel::memory::Allocator;

pub static DEFAULT_STRLEN: uint = 256;
pub static mut first: bool = true;

pub struct cstr {
    p: *mut u8,
    p_cstr_i: uint,
    size: uint
}

impl cstr {
    pub fn new() -> cstr {
        unsafe {
            cstr::news(DEFAULT_STRLEN)
        }
    }

    pub unsafe fn news(size: uint) -> cstr {
        // Sometimes this doesn't allocate enough memory and gets stuck...
        if first { let (_, _) = heap.alloc(size); }
        first = false;
        let (x, y) = heap.alloc(size);
        let this = cstr {
            p: x,
            p_cstr_i: 0,
            size: y
        };
        *(((this.p as uint)) as *mut char) = '\0';
        this
    }

    pub fn from_str(s: &str) -> cstr {
        let mut this = cstr::new();
        for c in slice::iter(as_bytes(s)) {
            this.add_u8(*c);
        };
        this
    }

    pub fn map_u8(&mut self, f: |u8|) {
        self.map(|c: char| {
            f(c as u8)
        });
    }

    pub fn map(&self, f: |char|) {
        let mut i = 0;
        while i < self.len() && self.get_char(i) != '\0' {
            f(self.get_char(i));
            i += 1;
        }
    }

    pub unsafe fn join(&self, other: cstr) -> cstr {
        let mut len = DEFAULT_STRLEN;
        while len < self.len() + other.len() {
            len += DEFAULT_STRLEN;
        }
        let mut new = cstr::news(len);
        self.map(|c| { new.add_char(c); } );
        other.map(|c| { new.add_char(c); } );
        new
    }

    pub unsafe fn trim(&mut self) -> cstr {
        let mut new = cstr::new();
        if self.len() == 0 || self.size > new.size {
            return new;
        }
        // Kill beginning whitespace.
        let mut beginwhite = true;
        let mut i = 0;
        while i < self.len() {
            let c = self.get_char(i);
            let iswhite = (c == (' ') || c == ('\n'));
            if !iswhite || !beginwhite {
                beginwhite = false;
                new.add_char(c);
            }
            i += 1;
        }
        // Kill trailing whitespace.
        i = self.len();
        let mut endwhite = true;
        while (endwhite && i > 0) {
            let c = self.get_char(i);
            let iswhite = (c == (' ') || c == ('\n'));
            if !iswhite {
                endwhite = false;
            }
            else {
                new.delete_char();
            }
            i -= 1;
        }
        return new;
    }

    pub unsafe fn clone(&mut self) -> cstr {
        let mut ind: uint = 0;
        let mut s = cstr::news(self.size);
        loop {
            if (self.len() == 0 || ind == self.len()) {
                return s;
            }
            s.add_u8(self.get_char(ind) as u8);
            ind += 1;
            if (ind == self.size) {
                return s;
            }
        }
    }

    pub fn len(&self) -> uint {
        self.p_cstr_i
    }

    pub unsafe fn destroy(&self) {
        heap.free(self.p);
    }

    pub fn get_p(&self, idx: uint) -> Option<uint> {
        if idx > self.len() || idx > self.size || self.p_cstr_i > self.size {
            return None;
        }
        Some((self.p as uint) + idx)
    }

    pub fn get_char(&self, idx: uint) -> char {
        if idx > self.len() || idx > self.size || self.p_cstr_i > self.size {
            return '\0';
        }
        unsafe {
            *(((self.p as uint) + idx) as *char)
        }
    }

    pub fn add_char(&mut self, c: char) -> bool {
        self.add_u8(c as u8)
    }

    pub fn add_u8(&mut self, x: u8) -> bool {
        if (self.p_cstr_i + 1 >= self.size) {
            return false;
        }
        unsafe {
            *(((self.p as uint) + self.p_cstr_i) as *mut u8) = x;
            self.p_cstr_i += 1;
            *(((self.p as uint) + self.p_cstr_i) as *mut char) = '\0';
        }
        true
    }

    pub unsafe fn delete_char(&mut self) -> bool {
        if (self.p_cstr_i == 0) {
            return false;
        }
        self.p_cstr_i -= 1;
        *(((self.p as uint)+self.p_cstr_i) as *mut char) = '\0';
        true
    }

    pub unsafe fn reset(&mut self) {
        self.p_cstr_i = 0;
        *(self.p as *mut char) = '\0';
    }

    pub unsafe fn eq(&self, other: &cstr) -> bool {
        if (self.len() != other.len()) { return false; }
        else {
            let mut x = 0;
            let mut selfp: uint = self.p as uint;
            let mut otherp: uint = other.p as uint;
            while x < self.len() {
                if (*(selfp as *char) != *(otherp as *char)) { return false; }
                selfp += 1;
                otherp += 1;
                x += 1;
            }
            true
        }
    }

    pub unsafe fn streq(&self, other: &str) -> bool {
        let mut i = 0;
        for c in slice::iter(as_bytes(other)) {
            if i > self.len() || *c != (self.get_char(i) as u8) {
                return false;
            }
            i += 1;
        };
        true
    }

    #[allow(dead_code)]
    pub unsafe fn split(&self, delim: char) -> (cstr, cstr) {
        let mut i = 0;
        let mut beg = cstr::news(self.size);
        let mut end = cstr::news(self.size);
        self.map(|c| {beg.add_char(c);});
        let mut found = false;
        while i < self.len() && !found {
            if (!found && beg.get_char(i) as u8 == delim as u8) {
                found = true;
                match beg.get_p(i) {
                    Some(p) => *(p as *mut char) = '\0',
                    None => {},
                }
                beg.p_cstr_i = i;
            }
            i += 1;
        }
        while i < self.len() {
            end.add_char(self.get_char(i));
            i += 1;
        }
        (beg, end)
    }
}
<commit_msg>don't count partial string matches as equal<commit_after>/* kernel::cstr.rs */
#[allow(unused_imports)];
use core::*;
use core::str::*;
use core::option::{Some, Option, None}; // Match statement
use core::iter::Iterator;
use kernel::*;
use super::super::platform::*;
use kernel::memory::Allocator;

pub static DEFAULT_STRLEN: uint = 256;
pub static mut first: bool = true;

pub struct cstr {
    p: *mut u8,
    p_cstr_i: uint,
    size: uint
}

impl cstr {
    pub fn new() -> cstr {
        unsafe {
            cstr::news(DEFAULT_STRLEN)
        }
    }

    pub unsafe fn news(size: uint) -> cstr {
        // Sometimes this doesn't allocate enough memory and gets stuck...
        if first { let (_, _) = heap.alloc(size); }
        first = false;
        let (x, y) = heap.alloc(size);
        let this = cstr {
            p: x,
            p_cstr_i: 0,
            size: y
        };
        *(((this.p as uint)) as *mut char) = '\0';
        this
    }

    pub fn from_str(s: &str) -> cstr {
        let mut this = cstr::new();
        for c in slice::iter(as_bytes(s)) {
            this.add_u8(*c);
        };
        this
    }

    pub fn map_u8(&mut self, f: |u8|) {
        self.map(|c: char| {
            f(c as u8)
        });
    }

    pub fn map(&self, f: |char|) {
        let mut i = 0;
        while i < self.len() && self.get_char(i) != '\0' {
            f(self.get_char(i));
            i += 1;
        }
    }

    pub unsafe fn join(&self, other: cstr) -> cstr {
        let mut len = DEFAULT_STRLEN;
        while len < self.len() + other.len() {
            len += DEFAULT_STRLEN;
        }
        let mut new = cstr::news(len);
        self.map(|c| { new.add_char(c); } );
        other.map(|c| { new.add_char(c); } );
        new
    }

    pub unsafe fn trim(&mut self) -> cstr {
        let mut new = cstr::new();
        if self.len() == 0 || self.size > new.size {
            return new;
        }
        // Kill beginning whitespace.
        let mut beginwhite = true;
        let mut i = 0;
        while i < self.len() {
            let c = self.get_char(i);
            let iswhite = (c == (' ') || c == ('\n'));
            if !iswhite || !beginwhite {
                beginwhite = false;
                new.add_char(c);
            }
            i += 1;
        }
        // Kill trailing whitespace.
        i = self.len();
        let mut endwhite = true;
        while (endwhite && i > 0) {
            let c = self.get_char(i);
            let iswhite = (c == (' ') || c == ('\n'));
            if !iswhite {
                endwhite = false;
            }
            else {
                new.delete_char();
            }
            i -= 1;
        }
        return new;
    }

    pub unsafe fn clone(&mut self) -> cstr {
        let mut ind: uint = 0;
        let mut s = cstr::news(self.size);
        loop {
            if (self.len() == 0 || ind == self.len()) {
                return s;
            }
            s.add_u8(self.get_char(ind) as u8);
            ind += 1;
            if (ind == self.size) {
                return s;
            }
        }
    }

    pub fn len(&self) -> uint {
        self.p_cstr_i
    }

    pub unsafe fn destroy(&self) {
        heap.free(self.p);
    }

    pub fn get_p(&self, idx: uint) -> Option<uint> {
        if idx > self.len() || idx > self.size || self.p_cstr_i > self.size {
            return None;
        }
        Some((self.p as uint) + idx)
    }

    pub fn get_char(&self, idx: uint) -> char {
        if idx > self.len() || idx > self.size || self.p_cstr_i > self.size {
            return '\0';
        }
        unsafe {
            *(((self.p as uint) + idx) as *char)
        }
    }

    pub fn add_char(&mut self, c: char) -> bool {
        self.add_u8(c as u8)
    }

    pub fn add_u8(&mut self, x: u8) -> bool {
        if (self.p_cstr_i + 1 >= self.size) {
            return false;
        }
        unsafe {
            *(((self.p as uint) + self.p_cstr_i) as *mut u8) = x;
            self.p_cstr_i += 1;
            *(((self.p as uint) + self.p_cstr_i) as *mut char) = '\0';
        }
        true
    }

    pub unsafe fn delete_char(&mut self) -> bool {
        if (self.p_cstr_i == 0) {
            return false;
        }
        self.p_cstr_i -= 1;
        *(((self.p as uint)+self.p_cstr_i) as *mut char) = '\0';
        true
    }

    pub unsafe fn reset(&mut self) {
        self.p_cstr_i = 0;
        *(self.p as *mut char) = '\0';
    }

    pub unsafe fn eq(&self, other: &cstr) -> bool {
        if (self.len() != other.len()) { return false; }
        else {
            let mut x = 0;
            let mut selfp: uint = self.p as uint;
            let mut otherp: uint = other.p as uint;
            while x < self.len() {
                if (*(selfp as *char) != *(otherp as *char)) { return false; }
                selfp += 1;
                otherp += 1;
                x += 1;
            }
            true
        }
    }

    pub unsafe fn streq(&self, other: &str) -> bool {
        let mut i = 0;
        for c in slice::iter(as_bytes(other)) {
            if i > self.len() || *c != (self.get_char(i) as u8) {
                return false;
            }
            i += 1;
        };
        i == self.len()
    }

    #[allow(dead_code)]
    pub unsafe fn split(&self, delim: char) -> (cstr, cstr) {
        let mut i = 0;
        let mut beg = cstr::news(self.size);
        let mut end = cstr::news(self.size);
        self.map(|c| {beg.add_char(c);});
        let mut found = false;
        while i < self.len() && !found {
            if (!found && beg.get_char(i) as u8 == delim as u8) {
                found = true;
                match beg.get_p(i) {
                    Some(p) => *(p as *mut char) = '\0',
                    None => {},
                }
                beg.p_cstr_i = i;
            }
            i += 1;
        }
        while i < self.len() {
            end.add_char(self.get_char(i));
            i += 1;
        }
        (beg, end)
    }
}
<|endoftext|>