<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! A work queue for scheduling units of work across threads in a fork-join fashion.
//!
//! Data associated with queues is simply a pair of unsigned integers. It is expected that a
//! higher-level API on top of this could allow safe fork-join parallelism.

use deque::{Abort, BufferPool, Data, Empty, Stealer, Worker};
use task::spawn_named;
use task_state;

use libc::funcs::posix88::unistd::usleep;
use rand::{Rng, weak_rng, XorShiftRng};
use std::mem;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::mpsc::{channel, Sender, Receiver};

/// A unit of work.
///
/// # Type parameters
///
/// - `QueueData`: global custom data for the entire work queue.
/// - `WorkData`: custom data specific to each unit of work.
pub struct WorkUnit<QueueData, WorkData> {
    /// The function to execute.
    pub fun: extern "Rust" fn(WorkData, &mut WorkerProxy<QueueData, WorkData>),
    /// Arbitrary data.
    pub data: WorkData,
}

/// Messages from the supervisor to the worker.
enum WorkerMsg<QueueData: 'static, WorkData: 'static> {
    /// Tells the worker to start work.
    Start(Worker<WorkUnit<QueueData, WorkData>>, *mut AtomicUsize, *const QueueData),
    /// Tells the worker to stop. It can be restarted again with a `WorkerMsg::Start`.
    Stop,
    /// Tells the worker to measure the heap size of its TLS using the supplied function.
    HeapSizeOfTLS(fn() -> usize),
    /// Tells the worker thread to terminate.
    Exit,
}

unsafe impl<QueueData: 'static, WorkData: 'static> Send for WorkerMsg<QueueData, WorkData> {}

/// Messages to the supervisor.
enum SupervisorMsg<QueueData: 'static, WorkData: 'static> {
    Finished,
    HeapSizeOfTLS(usize),
    ReturnDeque(usize, Worker<WorkUnit<QueueData, WorkData>>),
}

unsafe impl<QueueData: 'static, WorkData: 'static> Send for SupervisorMsg<QueueData, WorkData> {}

/// Information that the supervisor thread keeps about the worker threads.
struct WorkerInfo<QueueData: 'static, WorkData: 'static> {
    /// The communication channel to the workers.
    chan: Sender<WorkerMsg<QueueData, WorkData>>,
    /// The worker end of the deque, if we have it.
    deque: Option<Worker<WorkUnit<QueueData, WorkData>>>,
    /// The thief end of the work-stealing deque.
    thief: Stealer<WorkUnit<QueueData, WorkData>>,
}

/// Information specific to each worker thread that the thread keeps.
struct WorkerThread<QueueData: 'static, WorkData: 'static> {
    /// The index of this worker.
    index: usize,
    /// The communication port from the supervisor.
    port: Receiver<WorkerMsg<QueueData, WorkData>>,
    /// The communication channel on which messages are sent to the supervisor.
    chan: Sender<SupervisorMsg<QueueData, WorkData>>,
    /// The thief end of the work-stealing deque for all other workers.
    other_deques: Vec<Stealer<WorkUnit<QueueData, WorkData>>>,
    /// The random number generator for this worker.
    rng: XorShiftRng,
}

unsafe impl<QueueData: 'static, WorkData: 'static> Send for WorkerThread<QueueData, WorkData> {}

const SPINS_UNTIL_BACKOFF: u32 = 128;
const BACKOFF_INCREMENT_IN_US: u32 = 5;
const BACKOFFS_UNTIL_CONTROL_CHECK: u32 = 6;

fn next_power_of_two(mut v: u32) -> u32 {
    v -= 1;
    v |= v >> 1;
    v |= v >> 2;
    v |= v >> 4;
    v |= v >> 8;
    v |= v >> 16;
    v += 1;
    v
}

impl<QueueData: Send, WorkData: Send> WorkerThread<QueueData, WorkData> {
    /// The main logic. This function starts up the worker and listens for
    /// messages.
    fn start(&mut self) {
        let deque_index_mask = next_power_of_two(self.other_deques.len() as u32) - 1;
        loop {
            // Wait for a start message.
            let (mut deque, ref_count, queue_data) = match self.port.recv().unwrap() {
                WorkerMsg::Start(deque, ref_count, queue_data) => (deque, ref_count, queue_data),
                WorkerMsg::Stop => panic!("unexpected stop message"),
                WorkerMsg::Exit => return,
                WorkerMsg::HeapSizeOfTLS(f) => {
                    self.chan.send(SupervisorMsg::HeapSizeOfTLS(f())).unwrap();
                    continue;
                }
            };

            let mut back_off_sleep = 0 as u32;

            // We're off!
            //
            // FIXME(pcwalton): Can't use labeled break or continue cross-crate due to a Rust bug.
            loop {
                // FIXME(pcwalton): Nasty workaround for the lack of labeled break/continue
                // cross-crate.
                let mut work_unit = unsafe {
                    mem::uninitialized()
                };
                match deque.pop() {
                    Some(work) => work_unit = work,
                    None => {
                        // Become a thief.
                        let mut i = 0;
                        let mut should_continue = true;
                        loop {
                            // Don't just use `rand % len` because that's slow on ARM.
                            let mut victim;
                            loop {
                                victim = self.rng.next_u32() & deque_index_mask;
                                if (victim as usize) < self.other_deques.len() {
                                    break
                                }
                            }

                            match self.other_deques[victim as usize].steal() {
                                Empty | Abort => {
                                    // Continue.
                                }
                                Data(work) => {
                                    work_unit = work;
                                    back_off_sleep = 0 as u32;
                                    break
                                }
                            }

                            if i > SPINS_UNTIL_BACKOFF {
                                if back_off_sleep >= BACKOFF_INCREMENT_IN_US *
                                        BACKOFFS_UNTIL_CONTROL_CHECK {
                                    match self.port.try_recv() {
                                        Ok(WorkerMsg::Stop) => {
                                            should_continue = false;
                                            break
                                        }
                                        Ok(WorkerMsg::Exit) => return,
                                        Ok(_) => panic!("unexpected message"),
                                        _ => {}
                                    }
                                }

                                unsafe {
                                    usleep(back_off_sleep as u32);
                                }
                                back_off_sleep += BACKOFF_INCREMENT_IN_US;
                                i = 0
                            } else {
                                i += 1
                            }
                        }

                        if !should_continue {
                            break
                        }
                    }
                }

                // At this point, we have some work. Perform it.
                let mut proxy = WorkerProxy {
                    worker: &mut deque,
                    ref_count: ref_count,
                    queue_data: queue_data,
                    worker_index: self.index as u8,
                };
                (work_unit.fun)(work_unit.data, &mut proxy);

                // The work is done. Now decrement the count of outstanding work items. If this was
                // the last work unit in the queue, then send a message on the channel.
                unsafe {
                    if (*ref_count).fetch_sub(1, Ordering::Release) == 1 {
                        self.chan.send(SupervisorMsg::Finished).unwrap()
                    }
                }
            }

            // Give the deque back to the supervisor.
            self.chan.send(SupervisorMsg::ReturnDeque(self.index, deque)).unwrap()
        }
    }
}

/// A handle to the work queue that individual work units have.
pub struct WorkerProxy<'a, QueueData: 'a, WorkData: 'a> {
    worker: &'a mut Worker<WorkUnit<QueueData, WorkData>>,
    ref_count: *mut AtomicUsize,
    queue_data: *const QueueData,
    worker_index: u8,
}

impl<'a, QueueData: 'static, WorkData: Send + 'static> WorkerProxy<'a, QueueData, WorkData> {
    /// Enqueues a block into the work queue.
    #[inline]
    pub fn push(&mut self, work_unit: WorkUnit<QueueData, WorkData>) {
        unsafe {
            drop((*self.ref_count).fetch_add(1, Ordering::Relaxed));
        }
        self.worker.push(work_unit);
    }

    /// Retrieves the queue user data.
    #[inline]
    pub fn user_data<'b>(&'b self) -> &'b QueueData {
        unsafe {
            mem::transmute(self.queue_data)
        }
    }

    /// Retrieves the index of the worker.
    #[inline]
    pub fn worker_index(&self) -> u8 {
        self.worker_index
    }
}

/// A work queue on which units of work can be submitted.
pub struct WorkQueue<QueueData: 'static, WorkData: 'static> {
    /// Information about each of the workers.
    workers: Vec<WorkerInfo<QueueData, WorkData>>,
    /// A port on which deques can be received from the workers.
    port: Receiver<SupervisorMsg<QueueData, WorkData>>,
    /// The amount of work that has been enqueued.
    work_count: usize,
    /// Arbitrary user data.
    pub data: QueueData,
}

impl<QueueData: Send, WorkData: Send> WorkQueue<QueueData, WorkData> {
    /// Creates a new work queue and spawns all the threads associated with
    /// it.
    pub fn new(task_name: &'static str,
               state: task_state::TaskState,
               thread_count: usize,
               user_data: QueueData) -> WorkQueue<QueueData, WorkData> {
        // Set up data structures.
        let (supervisor_chan, supervisor_port) = channel();
        let (mut infos, mut threads) = (vec!(), vec!());
        for i in 0..thread_count {
            let (worker_chan, worker_port) = channel();
            let pool = BufferPool::new();
            let (worker, thief) = pool.deque();
            infos.push(WorkerInfo {
                chan: worker_chan,
                deque: Some(worker),
                thief: thief,
            });
            threads.push(WorkerThread {
                index: i,
                port: worker_port,
                chan: supervisor_chan.clone(),
                other_deques: vec!(),
                rng: weak_rng(),
            });
        }

        // Connect workers to one another.
        for i in 0..thread_count {
            for j in 0..thread_count {
                if i != j {
                    threads[i].other_deques.push(infos[j].thief.clone())
                }
            }
            assert!(threads[i].other_deques.len() == thread_count - 1)
        }

        // Spawn threads.
        for (i, thread) in threads.into_iter().enumerate() {

            spawn_named(
                format!("{} worker {}/{}", task_name, i+1, thread_count),
                move || {
                    task_state::initialize(state | task_state::IN_WORKER);
                    let mut thread = thread;
                    thread.start()
                })
        }

        WorkQueue {
            workers: infos,
            port: supervisor_port,
            work_count: 0,
            data: user_data,
        }
    }

    /// Enqueues a block into the work queue.
    #[inline]
    pub fn push(&mut self, work_unit: WorkUnit<QueueData, WorkData>) {
        let deque = &mut self.workers[0].deque;
        match *deque {
            None => {
                panic!("tried to push a block but we don't have the deque?!")
            }
            Some(ref mut deque) => deque.push(work_unit),
        }
        self.work_count += 1
    }

    /// Synchronously runs all the enqueued tasks and waits for them to complete.
    pub fn run(&mut self) {
        // Tell the workers to start.
        let mut work_count = AtomicUsize::new(self.work_count);
        for worker in self.workers.iter_mut() {
            worker.chan.send(WorkerMsg::Start(worker.deque.take().unwrap(),
                                              &mut work_count,
                                              &self.data)).unwrap()
        }

        // Wait for the work to finish.
        drop(self.port.recv());
        self.work_count = 0;

        // Tell everyone to stop.
        for worker in self.workers.iter() {
            worker.chan.send(WorkerMsg::Stop).unwrap()
        }

        // Get our deques back.
        for _ in 0..self.workers.len() {
            match self.port.recv().unwrap() {
                SupervisorMsg::ReturnDeque(index, deque) => self.workers[index].deque = Some(deque),
                SupervisorMsg::HeapSizeOfTLS(_) => panic!("unexpected HeapSizeOfTLS message"),
                SupervisorMsg::Finished => panic!("unexpected finished message!"),
            }
        }
    }

    /// Synchronously measure memory usage of any thread-local storage.
    pub fn heap_size_of_tls(&self, f: fn() -> usize) -> Vec<usize> {
        // Tell the workers to measure themselves.
        for worker in self.workers.iter() {
            worker.chan.send(WorkerMsg::HeapSizeOfTLS(f)).unwrap()
        }

        // Wait for the workers to finish measuring themselves.
        let mut sizes = vec![];
        for _ in 0..self.workers.len() {
            match self.port.recv().unwrap() {
                SupervisorMsg::HeapSizeOfTLS(size) => {
                    sizes.push(size);
                }
                _ => panic!("unexpected message!"),
            }
        }
        sizes
    }

    pub fn shutdown(&mut self) {
        for worker in self.workers.iter() {
            worker.chan.send(WorkerMsg::Exit).unwrap()
        }
    }
}
<commit_msg>Move back to using a labeled break in WorkQueue.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! A work queue for scheduling units of work across threads in a fork-join fashion.
//!
//! Data associated with queues is simply a pair of unsigned integers. It is expected that a
//! higher-level API on top of this could allow safe fork-join parallelism.

use deque::{Abort, BufferPool, Data, Empty, Stealer, Worker};
use task::spawn_named;
use task_state;

use libc::funcs::posix88::unistd::usleep;
use rand::{Rng, weak_rng, XorShiftRng};
use std::mem;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::mpsc::{channel, Sender, Receiver};

/// A unit of work.
///
/// # Type parameters
///
/// - `QueueData`: global custom data for the entire work queue.
/// - `WorkData`: custom data specific to each unit of work.
pub struct WorkUnit<QueueData, WorkData> {
    /// The function to execute.
    pub fun: extern "Rust" fn(WorkData, &mut WorkerProxy<QueueData, WorkData>),
    /// Arbitrary data.
    pub data: WorkData,
}

/// Messages from the supervisor to the worker.
enum WorkerMsg<QueueData: 'static, WorkData: 'static> {
    /// Tells the worker to start work.
    Start(Worker<WorkUnit<QueueData, WorkData>>, *mut AtomicUsize, *const QueueData),
    /// Tells the worker to stop. It can be restarted again with a `WorkerMsg::Start`.
    Stop,
    /// Tells the worker to measure the heap size of its TLS using the supplied function.
    HeapSizeOfTLS(fn() -> usize),
    /// Tells the worker thread to terminate.
    Exit,
}

unsafe impl<QueueData: 'static, WorkData: 'static> Send for WorkerMsg<QueueData, WorkData> {}

/// Messages to the supervisor.
enum SupervisorMsg<QueueData: 'static, WorkData: 'static> {
    Finished,
    HeapSizeOfTLS(usize),
    ReturnDeque(usize, Worker<WorkUnit<QueueData, WorkData>>),
}

unsafe impl<QueueData: 'static, WorkData: 'static> Send for SupervisorMsg<QueueData, WorkData> {}

/// Information that the supervisor thread keeps about the worker threads.
struct WorkerInfo<QueueData: 'static, WorkData: 'static> {
    /// The communication channel to the workers.
    chan: Sender<WorkerMsg<QueueData, WorkData>>,
    /// The worker end of the deque, if we have it.
    deque: Option<Worker<WorkUnit<QueueData, WorkData>>>,
    /// The thief end of the work-stealing deque.
    thief: Stealer<WorkUnit<QueueData, WorkData>>,
}

/// Information specific to each worker thread that the thread keeps.
struct WorkerThread<QueueData: 'static, WorkData: 'static> {
    /// The index of this worker.
    index: usize,
    /// The communication port from the supervisor.
    port: Receiver<WorkerMsg<QueueData, WorkData>>,
    /// The communication channel on which messages are sent to the supervisor.
    chan: Sender<SupervisorMsg<QueueData, WorkData>>,
    /// The thief end of the work-stealing deque for all other workers.
    other_deques: Vec<Stealer<WorkUnit<QueueData, WorkData>>>,
    /// The random number generator for this worker.
    rng: XorShiftRng,
}

unsafe impl<QueueData: 'static, WorkData: 'static> Send for WorkerThread<QueueData, WorkData> {}

const SPINS_UNTIL_BACKOFF: u32 = 128;
const BACKOFF_INCREMENT_IN_US: u32 = 5;
const BACKOFFS_UNTIL_CONTROL_CHECK: u32 = 6;

fn next_power_of_two(mut v: u32) -> u32 {
    v -= 1;
    v |= v >> 1;
    v |= v >> 2;
    v |= v >> 4;
    v |= v >> 8;
    v |= v >> 16;
    v += 1;
    v
}

impl<QueueData: Send, WorkData: Send> WorkerThread<QueueData, WorkData> {
    /// The main logic. This function starts up the worker and listens for
    /// messages.
    fn start(&mut self) {
        let deque_index_mask = next_power_of_two(self.other_deques.len() as u32) - 1;
        loop {
            // Wait for a start message.
            let (mut deque, ref_count, queue_data) = match self.port.recv().unwrap() {
                WorkerMsg::Start(deque, ref_count, queue_data) => (deque, ref_count, queue_data),
                WorkerMsg::Stop => panic!("unexpected stop message"),
                WorkerMsg::Exit => return,
                WorkerMsg::HeapSizeOfTLS(f) => {
                    self.chan.send(SupervisorMsg::HeapSizeOfTLS(f())).unwrap();
                    continue;
                }
            };

            let mut back_off_sleep = 0 as u32;

            // We're off!
            'outer: loop {
                let work_unit;
                match deque.pop() {
                    Some(work) => work_unit = work,
                    None => {
                        // Become a thief.
                        let mut i = 0;
                        loop {
                            // Don't just use `rand % len` because that's slow on ARM.
                            let mut victim;
                            loop {
                                victim = self.rng.next_u32() & deque_index_mask;
                                if (victim as usize) < self.other_deques.len() {
                                    break
                                }
                            }

                            match self.other_deques[victim as usize].steal() {
                                Empty | Abort => {
                                    // Continue.
                                }
                                Data(work) => {
                                    work_unit = work;
                                    back_off_sleep = 0 as u32;
                                    break
                                }
                            }

                            if i > SPINS_UNTIL_BACKOFF {
                                if back_off_sleep >= BACKOFF_INCREMENT_IN_US *
                                        BACKOFFS_UNTIL_CONTROL_CHECK {
                                    match self.port.try_recv() {
                                        Ok(WorkerMsg::Stop) => break 'outer,
                                        Ok(WorkerMsg::Exit) => return,
                                        Ok(_) => panic!("unexpected message"),
                                        _ => {}
                                    }
                                }

                                unsafe {
                                    usleep(back_off_sleep as u32);
                                }
                                back_off_sleep += BACKOFF_INCREMENT_IN_US;
                                i = 0
                            } else {
                                i += 1
                            }
                        }
                    }
                }

                // At this point, we have some work. Perform it.
                let mut proxy = WorkerProxy {
                    worker: &mut deque,
                    ref_count: ref_count,
                    queue_data: queue_data,
                    worker_index: self.index as u8,
                };
                (work_unit.fun)(work_unit.data, &mut proxy);

                // The work is done. Now decrement the count of outstanding work items. If this was
                // the last work unit in the queue, then send a message on the channel.
                unsafe {
                    if (*ref_count).fetch_sub(1, Ordering::Release) == 1 {
                        self.chan.send(SupervisorMsg::Finished).unwrap()
                    }
                }
            }

            // Give the deque back to the supervisor.
            self.chan.send(SupervisorMsg::ReturnDeque(self.index, deque)).unwrap()
        }
    }
}

/// A handle to the work queue that individual work units have.
pub struct WorkerProxy<'a, QueueData: 'a, WorkData: 'a> {
    worker: &'a mut Worker<WorkUnit<QueueData, WorkData>>,
    ref_count: *mut AtomicUsize,
    queue_data: *const QueueData,
    worker_index: u8,
}

impl<'a, QueueData: 'static, WorkData: Send + 'static> WorkerProxy<'a, QueueData, WorkData> {
    /// Enqueues a block into the work queue.
    #[inline]
    pub fn push(&mut self, work_unit: WorkUnit<QueueData, WorkData>) {
        unsafe {
            drop((*self.ref_count).fetch_add(1, Ordering::Relaxed));
        }
        self.worker.push(work_unit);
    }

    /// Retrieves the queue user data.
    #[inline]
    pub fn user_data<'b>(&'b self) -> &'b QueueData {
        unsafe {
            mem::transmute(self.queue_data)
        }
    }

    /// Retrieves the index of the worker.
    #[inline]
    pub fn worker_index(&self) -> u8 {
        self.worker_index
    }
}

/// A work queue on which units of work can be submitted.
pub struct WorkQueue<QueueData: 'static, WorkData: 'static> {
    /// Information about each of the workers.
    workers: Vec<WorkerInfo<QueueData, WorkData>>,
    /// A port on which deques can be received from the workers.
    port: Receiver<SupervisorMsg<QueueData, WorkData>>,
    /// The amount of work that has been enqueued.
    work_count: usize,
    /// Arbitrary user data.
    pub data: QueueData,
}

impl<QueueData: Send, WorkData: Send> WorkQueue<QueueData, WorkData> {
    /// Creates a new work queue and spawns all the threads associated with
    /// it.
    pub fn new(task_name: &'static str,
               state: task_state::TaskState,
               thread_count: usize,
               user_data: QueueData) -> WorkQueue<QueueData, WorkData> {
        // Set up data structures.
        let (supervisor_chan, supervisor_port) = channel();
        let (mut infos, mut threads) = (vec!(), vec!());
        for i in 0..thread_count {
            let (worker_chan, worker_port) = channel();
            let pool = BufferPool::new();
            let (worker, thief) = pool.deque();
            infos.push(WorkerInfo {
                chan: worker_chan,
                deque: Some(worker),
                thief: thief,
            });
            threads.push(WorkerThread {
                index: i,
                port: worker_port,
                chan: supervisor_chan.clone(),
                other_deques: vec!(),
                rng: weak_rng(),
            });
        }

        // Connect workers to one another.
        for i in 0..thread_count {
            for j in 0..thread_count {
                if i != j {
                    threads[i].other_deques.push(infos[j].thief.clone())
                }
            }
            assert!(threads[i].other_deques.len() == thread_count - 1)
        }

        // Spawn threads.
        for (i, thread) in threads.into_iter().enumerate() {

            spawn_named(
                format!("{} worker {}/{}", task_name, i+1, thread_count),
                move || {
                    task_state::initialize(state | task_state::IN_WORKER);
                    let mut thread = thread;
                    thread.start()
                })
        }

        WorkQueue {
            workers: infos,
            port: supervisor_port,
            work_count: 0,
            data: user_data,
        }
    }

    /// Enqueues a block into the work queue.
    #[inline]
    pub fn push(&mut self, work_unit: WorkUnit<QueueData, WorkData>) {
        let deque = &mut self.workers[0].deque;
        match *deque {
            None => {
                panic!("tried to push a block but we don't have the deque?!")
            }
            Some(ref mut deque) => deque.push(work_unit),
        }
        self.work_count += 1
    }

    /// Synchronously runs all the enqueued tasks and waits for them to complete.
    pub fn run(&mut self) {
        // Tell the workers to start.
        let mut work_count = AtomicUsize::new(self.work_count);
        for worker in self.workers.iter_mut() {
            worker.chan.send(WorkerMsg::Start(worker.deque.take().unwrap(),
                                              &mut work_count,
                                              &self.data)).unwrap()
        }

        // Wait for the work to finish.
        drop(self.port.recv());
        self.work_count = 0;

        // Tell everyone to stop.
        for worker in self.workers.iter() {
            worker.chan.send(WorkerMsg::Stop).unwrap()
        }

        // Get our deques back.
        for _ in 0..self.workers.len() {
            match self.port.recv().unwrap() {
                SupervisorMsg::ReturnDeque(index, deque) => self.workers[index].deque = Some(deque),
                SupervisorMsg::HeapSizeOfTLS(_) => panic!("unexpected HeapSizeOfTLS message"),
                SupervisorMsg::Finished => panic!("unexpected finished message!"),
            }
        }
    }

    /// Synchronously measure memory usage of any thread-local storage.
    pub fn heap_size_of_tls(&self, f: fn() -> usize) -> Vec<usize> {
        // Tell the workers to measure themselves.
        for worker in self.workers.iter() {
            worker.chan.send(WorkerMsg::HeapSizeOfTLS(f)).unwrap()
        }

        // Wait for the workers to finish measuring themselves.
        let mut sizes = vec![];
        for _ in 0..self.workers.len() {
            match self.port.recv().unwrap() {
                SupervisorMsg::HeapSizeOfTLS(size) => {
                    sizes.push(size);
                }
                _ => panic!("unexpected message!"),
            }
        }
        sizes
    }

    pub fn shutdown(&mut self) {
        for worker in self.workers.iter() {
            worker.chan.send(WorkerMsg::Exit).unwrap()
        }
    }
}
<|endoftext|>


<commit_before>use super::plain_summary_line;
use super::{ErrorCodes, IdMap, Ignore, LangString, Markdown, MarkdownHtml};
use rustc_span::edition::{Edition, DEFAULT_EDITION};
use std::cell::RefCell;

#[test]
fn test_unique_id() {
    let input = [
        "foo",
        "examples",
        "examples",
        "method.into_iter",
        "examples",
        "method.into_iter",
        "foo",
        "main",
        "search",
        "methods",
        "examples",
        "method.into_iter",
        "assoc_type.Item",
        "assoc_type.Item",
    ];
    let expected = [
        "foo",
        "examples",
        "examples-1",
        "method.into_iter",
        "examples-2",
        "method.into_iter-1",
        "foo-1",
        "main-1",
        "search-1",
        "methods",
        "examples-3",
        "method.into_iter-2",
        "assoc_type.Item",
        "assoc_type.Item-1",
    ];

    let map = RefCell::new(IdMap::new());
    let test = || {
        let mut map = map.borrow_mut();
        let actual: Vec<String> = input.iter().map(|s| map.derive(s.to_string())).collect();
        assert_eq!(&actual[..], expected);
    };
    test();
    map.borrow_mut().reset();
    test();
}

#[test]
fn test_lang_string_parse() {
    fn t(
        s: &str,
        should_panic: bool,
        no_run: bool,
        ignore: Ignore,
        rust: bool,
        test_harness: bool,
        compile_fail: bool,
        allow_fail: bool,
        error_codes: Vec<String>,
        edition: Option<Edition>,
    ) {
        assert_eq!(
            LangString::parse(s, ErrorCodes::Yes, true, None),
            LangString {
                should_panic,
                no_run,
                ignore,
                rust,
                test_harness,
                compile_fail,
                error_codes,
                original: s.to_owned(),
                allow_fail,
                edition,
            }
        )
    }
    let ignore_foo = Ignore::Some(vec!["foo".to_string()]);

    fn v() -> Vec<String> {
        Vec::new()
    }

    // marker                | should_panic | no_run | ignore | rust | test_harness
    //                       | compile_fail | allow_fail | error_codes | edition
    t("", false, false, Ignore::None, true, false, false, false, v(), None);
    t("rust", false, false, Ignore::None, true, false, false, false, v(), None);
    t("sh", false, false, Ignore::None, false, false, false, false, v(), None);
    t("ignore", false, false, Ignore::All, true, false, false, false, v(), None);
    t("ignore-foo", false, false, ignore_foo, true, false, false, false, v(), None);
    t("should_panic", true, false, Ignore::None, true, false, false, false, v(), None);
    t("no_run", false, true, Ignore::None, true, false, false, false, v(), None);
    t("test_harness", false, false, Ignore::None, true, true, false, false, v(), None);
    t("compile_fail", false, true, Ignore::None, true, false, true, false, v(), None);
    t("allow_fail", false, false, Ignore::None, true, false, false, true, v(), None);
    t("{.no_run .example}", false, true, Ignore::None, true, false, false, false, v(), None);
    t("{.sh .should_panic}", true, false, Ignore::None, false, false, false, false, v(), None);
    t("{.example .rust}", false, false, Ignore::None, true, false, false, false, v(), None);
    t("{.test_harness .rust}", false, false, Ignore::None, true, true, false, false, v(), None);
    t("text, no_run", false, true, Ignore::None, false, false, false, false, v(), None);
    t("text,no_run", false, true, Ignore::None, false, false, false, false, v(), None);
    t(
        "edition2015",
        false,
        false,
        Ignore::None,
        true,
        false,
        false,
        false,
        v(),
        Some(Edition::Edition2015),
    );
    t(
        "edition2018",
        false,
        false,
        Ignore::None,
        true,
        false,
        false,
        false,
        v(),
        Some(Edition::Edition2018),
    );
}

#[test]
fn test_header() {
    fn t(input: &str, expect: &str) {
        let mut map = IdMap::new();
        let output =
            Markdown(input, &[], &mut map, ErrorCodes::Yes, DEFAULT_EDITION, &None).into_string();
        assert_eq!(output, expect, "original: {}", input);
    }

    t(
        "# Foo bar",
        "
Foo bar
",
    );
    t(
        "## Foo-bar_baz qux",
        "

         Foo-bar_baz qux
",
    );
    t(
        "### **Foo** *bar* baz!?!& -_qux_-%",
        "
\
            Foo \
            bar baz!?!& -qux-%\

",
    );
    t(
        "#### **Foo?** & \\*bar?!*  _`baz`_ ❤ #qux",
        "
\
             Foo? & *bar?!*  \
             baz ❤ #qux\

",
    );
}

#[test]
fn test_header_ids_multiple_blocks() {
    let mut map = IdMap::new();
    fn t(map: &mut IdMap, input: &str, expect: &str) {
        let output =
            Markdown(input, &[], map, ErrorCodes::Yes, DEFAULT_EDITION, &None).into_string();
        assert_eq!(output, expect, "original: {}", input);
    }

    t(
        &mut map,
        "# Example",
        "
Example
",
    );
    t(
        &mut map,
        "# Panics",
        "
Panics
",
    );
    t(
        &mut map,
        "# Example",
        "
Example
",
    );
    t(
        &mut map,
        "# Main",
        "
Main
",
    );
    t(
        &mut map,
        "# Example",
        "
Example
",
    );
    t(
        &mut map,
        "# Panics",
        "
Panics
",
    );
}

#[test]
fn test_plain_summary_line() {
    fn t(input: &str, expect: &str) {
        let output = plain_summary_line(input);
        assert_eq!(output, expect, "original: {}", input);
    }

    t("hello [Rust](https://www.rust-lang.org) :)", "hello Rust :)");
    t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)");
    t("code `let x = i32;` ...", "code `let x = i32;` ...");
    t("type `Type<'static>` ...", "type `Type<'static>` ...");
    t("# top header", "top header");
    t("## header", "header");
}

#[test]
fn test_markdown_html_escape() {
    fn t(input: &str, expect: &str) {
        let mut idmap = IdMap::new();
        let output =
            MarkdownHtml(input, &mut idmap, ErrorCodes::Yes, DEFAULT_EDITION, &None).into_string();
        assert_eq!(output, expect, "original: {}", input);
    }

    t("`Struct<'a, T>`", "
Struct<'a, T>
\n");
    t("Struct<'a, T>", "
Struct<'a, T>
\n");
    t("Struct
", "
Struct<br>
\n");
}
<commit_msg>Fix string<commit_after>use super::plain_summary_line;
use super::{ErrorCodes, IdMap, Ignore, LangString, Markdown, MarkdownHtml};
use rustc_span::edition::{Edition, DEFAULT_EDITION};
use std::cell::RefCell;

#[test]
fn test_unique_id() {
    let input = [
        "foo",
        "examples",
        "examples",
        "method.into_iter",
        "examples",
        "method.into_iter",
        "foo",
        "main",
        "search",
        "methods",
        "examples",
        "method.into_iter",
        "assoc_type.Item",
        "assoc_type.Item",
    ];
    let expected = [
        "foo",
        "examples",
        "examples-1",
        "method.into_iter",
        "examples-2",
        "method.into_iter-1",
        "foo-1",
        "main-1",
        "search-1",
        "methods",
        "examples-3",
        "method.into_iter-2",
        "assoc_type.Item",
        "assoc_type.Item-1",
    ];

    let map = RefCell::new(IdMap::new());
    let test = || {
        let mut map = map.borrow_mut();
        let actual: Vec<String> = input.iter().map(|s| map.derive(s.to_string())).collect();
        assert_eq!(&actual[..], expected);
    };
    test();
    map.borrow_mut().reset();
    test();
}

#[test]
fn test_lang_string_parse() {
    fn t(
        s: &str,
        should_panic: bool,
        no_run: bool,
        ignore: Ignore,
        rust: bool,
        test_harness: bool,
        compile_fail: bool,
        allow_fail: bool,
        error_codes: Vec<String>,
        edition: Option<Edition>,
    ) {
        assert_eq!(
            LangString::parse(s, ErrorCodes::Yes, true, None),
            LangString {
                should_panic,
                no_run,
                ignore,
                rust,
                test_harness,
                compile_fail,
                error_codes,
                original: s.to_owned(),
                allow_fail,
                edition,
            }
        )
    }
    let ignore_foo = Ignore::Some(vec!["foo".to_string()]);

    fn v() -> Vec<String> {
        Vec::new()
    }

    // marker                | should_panic | no_run | ignore | rust | test_harness
    //                       | compile_fail | allow_fail | error_codes | edition
    t("", false, false, Ignore::None, true, false, false, false, v(), None);
    t("rust", false, false, Ignore::None, true, false, false, false, v(), None);
    t("sh", false, false, Ignore::None, false, false, false, false, v(), None);
    t("ignore", false, false, Ignore::All, true, false, false, false, v(), None);
    t("ignore-foo", false, false, ignore_foo, true, false, false, false, v(), None);
    t("should_panic", true, false, Ignore::None, true, false, false, false, v(), None);
    t("no_run", false, true, Ignore::None, true, false, false, false, v(), None);
    t("test_harness", false, false, Ignore::None, true, true, false, false, v(), None);
    t("compile_fail", false, true, Ignore::None, true, false, true, false, v(), None);
    t("allow_fail", false, false, Ignore::None, true, false, false, true, v(), None);
    t("{.no_run .example}", false, true, Ignore::None, true, false, false, false, v(), None);
    t("{.sh .should_panic}", true, false, Ignore::None, false, false, false, false, v(), None);
    t("{.example .rust}", false, false, Ignore::None, true, false, false, false, v(), None);
    t("{.test_harness .rust}", false, false, Ignore::None, true, true, false, false, v(), None);
    t("text, no_run", false, true, Ignore::None, false, false, false, false, v(), None);
    t("text,no_run", false, true, Ignore::None, false, false, false, false, v(), None);
    t(
        "edition2015",
        false,
        false,
        Ignore::None,
        true,
        false,
        false,
        false,
        v(),
        Some(Edition::Edition2015),
    );
    t(
        "edition2018",
        false,
        false,
        Ignore::None,
        true,
        false,
        false,
        false,
        v(),
        Some(Edition::Edition2018),
    );
}

#[test]
fn test_header() {
    fn t(input: &str, expect: &str) {
        let mut map = IdMap::new();
        let output =
            Markdown(input, &[], &mut map, ErrorCodes::Yes, DEFAULT_EDITION, &None).into_string();
        assert_eq!(output, expect, "original: {}", input);
    }

    t(
        "# Foo bar",
        "
Foo bar
",
    );
    t(
        "## Foo-bar_baz qux",
        "
\
         Foo-bar_baz qux
",
    );
    t(
        "### **Foo** *bar* baz!?!& -_qux_-%",
        "
\
            Foo \
            bar baz!?!& -qux-%\

",
    );
    t(
        "#### **Foo?** & \\*bar?!*  _`baz`_ ❤ #qux",
        "
\
             Foo? & *bar?!*  \
             baz ❤ #qux\

",
    );
}

#[test]
fn test_header_ids_multiple_blocks() {
    let mut map = IdMap::new();
    fn t(map: &mut IdMap, input: &str, expect: &str) {
        let output =
            Markdown(input, &[], map, ErrorCodes::Yes, DEFAULT_EDITION, &None).into_string();
        assert_eq!(output, expect, "original: {}", input);
    }

    t(
        &mut map,
        "# Example",
        "
Example
",
    );
    t(
        &mut map,
        "# Panics",
        "
Panics
",
    );
    t(
        &mut map,
        "# Example",
        "
Example
",
    );
    t(
        &mut map,
        "# Main",
        "
Main
",
    );
    t(
        &mut map,
        "# Example",
        "
Example
",
    );
    t(
        &mut map,
        "# Panics",
        "
Panics
",
    );
}

#[test]
fn test_plain_summary_line() {
    fn t(input: &str, expect: &str) {
        let output = plain_summary_line(input);
        assert_eq!(output, expect, "original: {}", input);
    }

    t("hello [Rust](https://www.rust-lang.org) :)", "hello Rust :)");
    t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)");
    t("code `let x = i32;` ...", "code `let x = i32;` ...");
    t("type `Type<'static>` ...", "type `Type<'static>` ...");
    t("# top header", "top header");
    t("## header", "header");
}

#[test]
fn test_markdown_html_escape() {
    fn t(input: &str, expect: &str) {
        let mut idmap = IdMap::new();
        let output =
            MarkdownHtml(input, &mut idmap, ErrorCodes::Yes, DEFAULT_EDITION, &None).into_string();
        assert_eq!(output, expect, "original: {}", input);
    }

    t("`Struct<'a, T>`", "
Struct<'a, T>
\n");
    t("Struct<'a, T>", "
Struct<'a, T>
\n");
    t("Struct
", "
Struct<br>
\n");
}
<|endoftext|>


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

use libc;
use self::imp::{make_handler, drop_handler};

pub use self::imp::{init, cleanup};

pub struct Handler {
    _data: *mut libc::c_void
}

impl Handler {
    pub unsafe fn new() -> Handler {
        make_handler()
    }
}

impl Drop for Handler {
    fn drop(&mut self) {
        unsafe {
            drop_handler(self);
        }
    }
}

#[cfg(any(target_os = "linux",
          target_os = "macos",
          target_os = "bitrig",
          all(target_os = "netbsd", not(target_vendor = "rumprun")),
          target_os = "openbsd"))]
mod imp {
    use super::Handler;
    use sys_common::util::report_overflow;
    use mem;
    use ptr;
    use sys::c::{siginfo, sigaction, SIGBUS, SIG_DFL,
                 SA_SIGINFO, SA_ONSTACK, sigaltstack,
                 SIGSTKSZ, sighandler_t};
    use libc;
    use libc::funcs::posix88::mman::{mmap, munmap};
    use libc::{SIGSEGV, PROT_READ, PROT_WRITE, MAP_PRIVATE, MAP_ANON};
    use libc::MAP_FAILED;

    use sys_common::thread_info;

    // This is initialized in init() and only read from after
    static mut PAGE_SIZE: usize = 0;

    // Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages
    // (unmapped pages) at the end of every thread's stack, so if a thread ends
    // up running into the guard page it'll trigger this handler. We want to
    // detect these cases and print out a helpful error saying that the stack
    // has overflowed. All other signals, however, should go back to what they
    // were originally supposed to do.
    //
    // This handler currently exists purely to print an informative message
    // whenever a thread overflows its stack. When run the handler always
    // un-registers itself after running and then returns (to allow the original
    // signal to be delivered again). By returning we're ensuring that segfaults
    // do indeed look like segfaults.
    //
    // Returning from this kind of signal handler is technically not defined to
    // work when reading the POSIX spec strictly, but in practice it turns out
    // many large systems and all implementations allow returning from a signal
    // handler to work. For a more detailed explanation see the comments on
    // #26458.
    unsafe extern fn signal_handler(signum: libc::c_int,
                                    info: *mut siginfo,
                                    _data: *mut libc::c_void) {
        let guard = thread_info::stack_guard().unwrap_or(0);
        let addr = (*info).si_addr as usize;

        // If the faulting address is within the guard page, then we print a
        // message saying so.
        if guard != 0 && guard - PAGE_SIZE <= addr && addr < guard {
            report_overflow();
        }

        // Unregister ourselves by reverting back to the default behavior.
        let mut action: sigaction = mem::zeroed();
        action.sa_sigaction = SIG_DFL;
        sigaction(signum, &action, ptr::null_mut());

        // See comment above for why this function returns.
    }

    static mut MAIN_ALTSTACK: *mut libc::c_void = ptr::null_mut();

    pub unsafe fn init() {
        PAGE_SIZE = ::sys::os::page_size();

        let mut action: sigaction = mem::zeroed();
        action.sa_flags = SA_SIGINFO | SA_ONSTACK;
        action.sa_sigaction = signal_handler as sighandler_t;
        sigaction(SIGSEGV, &action, ptr::null_mut());
        sigaction(SIGBUS, &action, ptr::null_mut());

        let handler = make_handler();
        MAIN_ALTSTACK = handler._data;
        mem::forget(handler);
    }

    pub unsafe fn cleanup() {
        Handler { _data: MAIN_ALTSTACK };
    }

    pub unsafe fn make_handler() -> Handler {
        let alt_stack = mmap(ptr::null_mut(),
                             SIGSTKSZ,
                             PROT_READ | PROT_WRITE,
                             MAP_PRIVATE | MAP_ANON,
                             -1,
                             0);
        if alt_stack == MAP_FAILED {
            panic!("failed to allocate an alternative stack");
        }

        let mut stack: sigaltstack = mem::zeroed();

        stack.ss_sp = alt_stack;
        stack.ss_flags = 0;
        stack.ss_size = SIGSTKSZ;

        sigaltstack(&stack, ptr::null_mut());

        Handler { _data: alt_stack }
    }

    pub unsafe fn drop_handler(handler: &mut Handler) {
        munmap(handler._data, SIGSTKSZ);
    }
}

#[cfg(not(any(target_os = "linux",
              target_os = "macos",
              target_os = "bitrig",
              all(target_os = "netbsd", not(target_vendor = "rumprun")),
              target_os = "openbsd")))]
mod imp {
    use ptr;

    pub unsafe fn init() {
    }

    pub unsafe fn cleanup() {
    }

    pub unsafe fn make_handler() -> super::Handler {
        super::Handler { _data: ptr::null_mut() }
    }

    pub unsafe fn drop_handler(_handler: &mut super::Handler) {
    }
}
<commit_msg>Use guard-pages also on DragonFly/FreeBSD.<commit_after>// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use libc;
use self::imp::{make_handler, drop_handler};

pub use self::imp::{init, cleanup};

pub struct Handler {
    _data: *mut libc::c_void
}

impl Handler {
    pub unsafe fn new() -> Handler {
        make_handler()
    }
}

impl Drop for Handler {
    fn drop(&mut self) {
        unsafe {
            drop_handler(self);
        }
    }
}

#[cfg(any(target_os = "linux",
          target_os = "macos",
          target_os = "bitrig",
          target_os = "dragonfly",
          target_os = "freebsd",
          all(target_os = "netbsd", not(target_vendor = "rumprun")),
          target_os = "openbsd"))]
mod imp {
    use super::Handler;
    use sys_common::util::report_overflow;
    use mem;
    use ptr;
    use sys::c::{siginfo, sigaction, SIGBUS, SIG_DFL,
                 SA_SIGINFO, SA_ONSTACK, sigaltstack,
                 SIGSTKSZ, sighandler_t};
    use libc;
    use libc::funcs::posix88::mman::{mmap, munmap};
    use libc::{SIGSEGV, PROT_READ, PROT_WRITE, MAP_PRIVATE, MAP_ANON};
    use libc::MAP_FAILED;

    use sys_common::thread_info;

    // This is initialized in init() and only read from after
    static mut PAGE_SIZE: usize = 0;

    // Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages
    // (unmapped pages) at the end of every thread's stack, so if a thread ends
    // up running into the guard page it'll trigger this handler. We want to
    // detect these cases and print out a helpful error saying that the stack
    // has overflowed. All other signals, however, should go back to what they
    // were originally supposed to do.
    //
    // This handler currently exists purely to print an informative message
    // whenever a thread overflows its stack. When run the handler always
    // un-registers itself after running and then returns (to allow the original
    // signal to be delivered again). By returning we're ensuring that segfaults
    // do indeed look like segfaults.
    //
    // Returning from this kind of signal handler is technically not defined to
    // work when reading the POSIX spec strictly, but in practice it turns out
    // many large systems and all implementations allow returning from a signal
    // handler to work. For a more detailed explanation see the comments on
    // #26458.
    unsafe extern fn signal_handler(signum: libc::c_int,
                                    info: *mut siginfo,
                                    _data: *mut libc::c_void) {
        let guard = thread_info::stack_guard().unwrap_or(0);
        let addr = (*info).si_addr as usize;

        // If the faulting address is within the guard page, then we print a
        // message saying so.
        if guard != 0 && guard - PAGE_SIZE <= addr && addr < guard {
            report_overflow();
        }

        // Unregister ourselves by reverting back to the default behavior.
        let mut action: sigaction = mem::zeroed();
        action.sa_sigaction = SIG_DFL;
        sigaction(signum, &action, ptr::null_mut());

        // See comment above for why this function returns.
    }

    static mut MAIN_ALTSTACK: *mut libc::c_void = ptr::null_mut();

    pub unsafe fn init() {
        PAGE_SIZE = ::sys::os::page_size();

        let mut action: sigaction = mem::zeroed();
        action.sa_flags = SA_SIGINFO | SA_ONSTACK;
        action.sa_sigaction = signal_handler as sighandler_t;
        sigaction(SIGSEGV, &action, ptr::null_mut());
        sigaction(SIGBUS, &action, ptr::null_mut());

        let handler = make_handler();
        MAIN_ALTSTACK = handler._data;
        mem::forget(handler);
    }

    pub unsafe fn cleanup() {
        Handler { _data: MAIN_ALTSTACK };
    }

    pub unsafe fn make_handler() -> Handler {
        let alt_stack = mmap(ptr::null_mut(),
                             SIGSTKSZ,
                             PROT_READ | PROT_WRITE,
                             MAP_PRIVATE | MAP_ANON,
                             -1,
                             0);
        if alt_stack == MAP_FAILED {
            panic!("failed to allocate an alternative stack");
        }

        let mut stack: sigaltstack = mem::zeroed();

        stack.ss_sp = alt_stack;
        stack.ss_flags = 0;
        stack.ss_size = SIGSTKSZ;

        sigaltstack(&stack, ptr::null_mut());

        Handler { _data: alt_stack }
    }

    pub unsafe fn drop_handler(handler: &mut Handler) {
        munmap(handler._data, SIGSTKSZ);
    }
}

#[cfg(not(any(target_os = "linux",
              target_os = "macos",
              target_os = "bitrig",
              target_os = "dragonfly",
              target_os = "freebsd",
              all(target_os = "netbsd", not(target_vendor = "rumprun")),
              target_os = "openbsd")))]
mod imp {
    use ptr;

    pub unsafe fn init() {
    }

    pub unsafe fn cleanup() {
    }

    pub unsafe fn make_handler() -> super::Handler {
        super::Handler { _data: ptr::null_mut() }
    }

    pub unsafe fn drop_handler(_handler: &mut super::Handler) {
    }
}
<|endoftext|>


<commit_before>use std::thread;
use std::sync::mpsc;
use websocket::{Server, Message, Sender, Receiver};
use websocket::server::sender;
use websocket::stream::WebSocketStream;
use std::collections::{HashMap, BitSet};
use std::io::prelude::*;
use std::fs::OpenOptions;
use std::num::ToPrimitive;
use rustc_serialize::json::{Json, ToJson};

use value::{Value, Tuple};
use index;
use flow::{Changes, FlowState, Flow};
use compiler::{compile, World};

trait FromJson {
    fn from_json(json: &Json, next_eid: &mut u64) -> Self;
}

impl ToJson for Value {
    fn to_json(&self) -> Json {
        match *self {
            Value::Bool(bool) => Json::Boolean(bool),
            Value::String(ref string) => Json::String(string.clone()),
            Value::Float(float) => Json::F64(float),
            Value::Tuple(ref tuple) => tuple.to_json(),
            Value::Relation(ref relation) => Json::Object(vec![
                ("relation".to_string(), relation.iter().map(ToJson::to_json).collect::<Vec<_>>().to_json())
                ].into_iter().collect()),
        }
    }
}

impl FromJson for Value {
    fn from_json(json: &Json, next_eid: &mut u64) -> Self {
        match *json {
            Json::Boolean(bool) => Value::Bool(bool),
            Json::String(ref string) => Value::String(string.clone()),
            Json::F64(float) => Value::Float(float),
            Json::I64(int) => Value::Float(int.to_f64().unwrap()),
            Json::U64(uint) => Value::Float(uint.to_f64().unwrap()),
            Json::Array(ref array) => Value::Tuple(array.iter().map(|j| Value::from_json(j, next_eid)).collect()),
            Json::Object(ref object) => {
                assert!(object.len() == 1);
                match object.get("eid") {
                    Some(value) => {
                        assert_eq!(value.as_string().unwrap(), "auto");
                        let eid = next_eid.to_f64().unwrap();
                        *next_eid += 1;
                        Value::Float(eid)
                    }
                    None => {
                        let relation: Vec<Tuple> = FromJson::from_json(&object["relation"], next_eid);
                        Value::Relation(relation.into_iter().collect())
                    }
                }
            },
            _ => panic!("Cannot decode {:?} as Value", json),
        }
    }
}

impl<T: FromJson> FromJson for Vec<T> {
    fn from_json(json: &Json, next_eid: &mut u64) -> Self {
        json.as_array().unwrap().iter().map(|t| FromJson::from_json(t, next_eid)).collect()
    }
}

pub struct Event {
    changes: Changes,
}

impl ToJson for Event {
    fn to_json(&self) -> Json {
        Json::Object(vec![
            ("changes".to_string(), Json::Object(
                self.changes.iter().map(|&(ref view_id, ref view_changes)| {
                    (view_id.to_string(), Json::Object(vec![
                        ("inserted".to_string(), view_changes.inserted.to_json()),
                        ("removed".to_string(), view_changes.removed.to_json()),
                        ].into_iter().collect()))
                }).collect()))].into_iter().collect())
    }
}

impl FromJson for Event {
    fn from_json(json: &Json, next_eid: &mut u64) -> Self {
        Event{
            changes: json.as_object().unwrap()["changes"]
            .as_object().unwrap().iter().map(|(view_id, view_changes)| {
                (view_id.to_string(), index::Changes{
                    inserted: FromJson::from_json(&view_changes.as_object().unwrap()["inserted"], next_eid),
                    removed: FromJson::from_json(&view_changes.as_object().unwrap()["removed"], next_eid),
                })
            }).collect()
        }
    }
}

struct Instance {
    input: World,
    flow: Flow,
    output: FlowState,
    next_eid: u64,
}

impl Instance {
    pub fn change(&mut self, changes: Changes) -> Changes {
        self.input.change(changes);
        let mut input_clone = self.input.clone();
        let (flow, mut output) = compile(&mut input_clone);
        flow.run(&mut output);
        let changes = flow.changes_since(&output, &self.flow, &self.output);
        self.flow = flow;
        self.output = output;
        changes
    }
}

pub enum ServerEvent {
    Message(String),
    NewClient(sender::Sender<WebSocketStream>),
}

// TODO holy crap why is everything blocking? this is a mess
pub fn serve() -> mpsc::Receiver<ServerEvent> {
    let (event_sender, event_receiver) = mpsc::channel();
    thread::spawn(move || {
        let server = Server::bind("0.0.0.0:2794").unwrap();
        for connection in server {
            let event_sender = event_sender.clone();
            thread::spawn(move || {
                // accept request
                let request = connection.unwrap().read_request().unwrap();
                request.validate().unwrap();
                let response = request.accept();
                let (mut sender, mut receiver) = response.send().unwrap().split();

                let ip = sender.get_mut().peer_addr().unwrap();
                println!("Connection from {}", ip);
                ::std::io::stdout().flush().unwrap(); // TODO is this actually necessary?

                // hand over sender
                event_sender.send(ServerEvent::NewClient(sender)).unwrap();

                // handle messages
                for message in receiver.incoming_messages() {
                    let message = message.unwrap();
                    match message {
                        Message::Text(text) => {
                            event_sender.send(ServerEvent::Message(text)).unwrap();
                        }
                        _ => println!("Unknown message: {:?}", message)
                    }
                }
            });
        }
    });
    event_receiver
}

pub fn run() {
    let empty_world = World{views: HashMap::new()};
    let empty_flow = Flow{nodes: Vec::new()};
    let empty_output = FlowState{outputs: Vec::new(), dirty: BitSet::new()};
    let mut instance = Instance{
        input: empty_world,
        flow: empty_flow.clone(),
        output: empty_output.clone(),
        next_eid: 0,
    };

    time!("reading saved state", {
        let mut events = OpenOptions::new().create(true).open("./events").unwrap();
        let mut old_events = String::new();
        events.read_to_string(&mut old_events).unwrap();
        for line in old_events.lines() {
            let event: Event = {
                let Instance {ref mut next_eid, ..} = instance;
                let json = Json::from_str(&line).unwrap();
                FromJson::from_json(&json, next_eid)
            };
            instance.change(event.changes);
        }
        drop(events);
        });
    let mut events = OpenOptions::new().write(true).append(true).open("./events").unwrap();

    let mut senders: Vec<sender::Sender<_>> = Vec::new();
    let event_receiver = serve();
    for event in event_receiver.iter() {
        match event {
            ServerEvent::NewClient(mut sender) => {
                time!("sending initial state", {
                    let changes = instance.flow.changes_since(&instance.output, &empty_flow, &empty_output);
                    let text = format!("{}", Event{changes: changes}.to_json());
                    match sender.send_message(Message::Text(text)) {
                        Ok(_) => (),
                        Err(error) => println!("Send error: {}", error),
                    };
                    senders.push(sender)
                })
            }
            ServerEvent::Message(input_text) => {
                time!("sending update", {
                    let input_event: Event = {
                        let Instance {ref mut next_eid, ..} = instance;
                        let json = Json::from_str(&input_text).unwrap();
                        FromJson::from_json(&json, next_eid)
                    };
                    let output_event = Event{changes: instance.change(input_event.changes)};
                    let output_text = format!("{}", output_event.to_json());
                    events.write_all(input_text.as_bytes()).unwrap();
                    events.write_all("\n".as_bytes()).unwrap();
                    events.flush().unwrap();
                    for sender in senders.iter_mut() {
                        match sender.send_message(Message::Text(output_text.clone())) {
                            Ok(_) => (),
                            Err(error) => println!("Send error: {}", error),
                        };
                    }
                })
            }
        }
    }
}
<commit_msg>Crude batching<commit_after>use std::thread;
use std::sync::mpsc;
use websocket::{Server, Message, Sender, Receiver};
use websocket::server::sender;
use websocket::stream::WebSocketStream;
use std::collections::{HashMap, BitSet};
use std::io::prelude::*;
use std::fs::OpenOptions;
use std::num::ToPrimitive;
use rustc_serialize::json::{Json, ToJson};

use value::{Value, Tuple};
use index;
use flow::{Changes, FlowState, Flow};
use compiler::{compile, World};

trait FromJson {
    fn from_json(json: &Json, next_eid: &mut u64) -> Self;
}

impl ToJson for Value {
    fn to_json(&self) -> Json {
        match *self {
            Value::Bool(bool) => Json::Boolean(bool),
            Value::String(ref string) => Json::String(string.clone()),
            Value::Float(float) => Json::F64(float),
            Value::Tuple(ref tuple) => tuple.to_json(),
            Value::Relation(ref relation) => Json::Object(vec![
                ("relation".to_string(), relation.iter().map(ToJson::to_json).collect::<Vec<_>>().to_json())
                ].into_iter().collect()),
        }
    }
}

impl FromJson for Value {
    fn from_json(json: &Json, next_eid: &mut u64) -> Self {
        match *json {
            Json::Boolean(bool) => Value::Bool(bool),
            Json::String(ref string) => Value::String(string.clone()),
            Json::F64(float) => Value::Float(float),
            Json::I64(int) => Value::Float(int.to_f64().unwrap()),
            Json::U64(uint) => Value::Float(uint.to_f64().unwrap()),
            Json::Array(ref array) => Value::Tuple(array.iter().map(|j| Value::from_json(j, next_eid)).collect()),
            Json::Object(ref object) => {
                assert!(object.len() == 1);
                match object.get("eid") {
                    Some(value) => {
                        assert_eq!(value.as_string().unwrap(), "auto");
                        let eid = next_eid.to_f64().unwrap();
                        *next_eid += 1;
                        Value::Float(eid)
                    }
                    None => {
                        let relation: Vec<Tuple> = FromJson::from_json(&object["relation"], next_eid);
                        Value::Relation(relation.into_iter().collect())
                    }
                }
            },
            _ => panic!("Cannot decode {:?} as Value", json),
        }
    }
}

impl<T: FromJson> FromJson for Vec<T> {
    fn from_json(json: &Json, next_eid: &mut u64) -> Self {
        json.as_array().unwrap().iter().map(|t| FromJson::from_json(t, next_eid)).collect()
    }
}

pub struct Event {
    changes: Changes,
}

impl ToJson for Event {
    fn to_json(&self) -> Json {
        Json::Object(vec![
            ("changes".to_string(), Json::Object(
                self.changes.iter().map(|&(ref view_id, ref view_changes)| {
                    (view_id.to_string(), Json::Object(vec![
                        ("inserted".to_string(), view_changes.inserted.to_json()),
                        ("removed".to_string(), view_changes.removed.to_json()),
                        ].into_iter().collect()))
                }).collect()))].into_iter().collect())
    }
}

impl FromJson for Event {
    fn from_json(json: &Json, next_eid: &mut u64) -> Self {
        Event{
            changes: json.as_object().unwrap()["changes"]
            .as_object().unwrap().iter().map(|(view_id, view_changes)| {
                (view_id.to_string(), index::Changes{
                    inserted: FromJson::from_json(&view_changes.as_object().unwrap()["inserted"], next_eid),
                    removed: FromJson::from_json(&view_changes.as_object().unwrap()["removed"], next_eid),
                })
            }).collect()
        }
    }
}

struct Instance {
    input: World,
    flow: Flow,
    output: FlowState,
    next_eid: u64,
}

impl Instance {
    pub fn run(&mut self) -> Changes {
        let mut input_clone = self.input.clone();
        let (flow, mut output) = compile(&mut input_clone);
        flow.run(&mut output);
        let changes = flow.changes_since(&output, &self.flow, &self.output);
        self.flow = flow;
        self.output = output;
        changes
    }
}

pub enum ServerEvent {
    Message(String),
    NewClient(sender::Sender<WebSocketStream>),
}

// TODO holy crap why is everything blocking? this is a mess
pub fn serve() -> mpsc::Receiver<ServerEvent> {
    let (event_sender, event_receiver) = mpsc::channel();
    thread::spawn(move || {
        let server = Server::bind("0.0.0.0:2794").unwrap();
        for connection in server {
            let event_sender = event_sender.clone();
            thread::spawn(move || {
                // accept request
                let request = connection.unwrap().read_request().unwrap();
                request.validate().unwrap();
                let response = request.accept();
                let (mut sender, mut receiver) = response.send().unwrap().split();

                let ip = sender.get_mut().peer_addr().unwrap();
                println!("Connection from {}", ip);
                ::std::io::stdout().flush().unwrap(); // TODO is this actually necessary?

                // hand over sender
                event_sender.send(ServerEvent::NewClient(sender)).unwrap();

                // handle messages
                for message in receiver.incoming_messages() {
                    let message = message.unwrap();
                    match message {
                        Message::Text(text) => {
                            event_sender.send(ServerEvent::Message(text)).unwrap();
                        }
                        _ => println!("Unknown message: {:?}", message)
                    }
                }
            });
        }
    });
    event_receiver
}

// TODO arbitrary limit - needs tuning
static MAX_BATCH_SIZE: usize = 100;

fn recv_batch(event_receiver: &mpsc::Receiver<ServerEvent>, server_events: &mut Vec<ServerEvent>) {
    server_events.push(event_receiver.recv().unwrap()); // block until first event
    for _ in 0..MAX_BATCH_SIZE {
        match event_receiver.try_recv() {
            Ok(event) => server_events.push(event),
            Err(mpsc::TryRecvError::Empty) => break,
            Err(mpsc::TryRecvError::Disconnected) => panic!(),
        }
    }
}

pub fn run() {
    let empty_world = World{views: HashMap::new()};
    let empty_flow = Flow{nodes: Vec::new()};
    let empty_output = FlowState{outputs: Vec::new(), dirty: BitSet::new()};
    let mut instance = Instance{
        input: empty_world,
        flow: empty_flow.clone(),
        output: empty_output.clone(),
        next_eid: 0,
    };

    time!("reading saved state", {
        let mut events = OpenOptions::new().create(true).open("./events").unwrap();
        let mut old_events = String::new();
        events.read_to_string(&mut old_events).unwrap();
        for line in old_events.lines() {
            let event: Event = {
                let Instance {ref mut next_eid, ..} = instance;
                let json = Json::from_str(&line).unwrap();
                FromJson::from_json(&json, next_eid)
            };
            instance.input.change(event.changes);
        }
        drop(events);
        instance.run();
        });

    let mut events = OpenOptions::new().write(true).append(true).open("./events").unwrap();
    let mut senders: Vec<sender::Sender<_>> = Vec::new();
    let mut server_events: Vec<ServerEvent> = Vec::with_capacity(MAX_BATCH_SIZE);
    let event_receiver = serve();
    loop {
        time!("entire batch", {
            recv_batch(&event_receiver, &mut server_events);
            println!("batch size: {:?}", server_events.len());

            for event in server_events.drain() {
                match event {
                    ServerEvent::NewClient(mut sender) => {
                        time!("sending initial state", {
                            let changes = instance.flow.changes_since(&instance.output, &empty_flow, &empty_output);
                            let text = format!("{}", Event{changes: changes}.to_json());
                            match sender.send_message(Message::Text(text)) {
                                Ok(_) => (),
                                Err(error) => println!("Send error: {}", error),
                            };
                            senders.push(sender)
                        })
                    }
                    ServerEvent::Message(input_text) => {
                        time!("sending update", {
                            let input_event: Event = {
                                let Instance {ref mut next_eid, ..} = instance;
                                let json = Json::from_str(&input_text).unwrap();
                                FromJson::from_json(&json, next_eid)
                            };
                            events.write_all(input_text.as_bytes()).unwrap();
                            events.write_all("\n".as_bytes()).unwrap();
                            instance.input.change(input_event.changes);
                        })
                    }
                }
            }

            let output_event = Event{changes: instance.run()};
            let output_text = format!("{}", output_event.to_json());
            events.flush().unwrap();
            for sender in senders.iter_mut() {
                match sender.send_message(Message::Text(output_text.clone())) {
                    Ok(_) => (),
                    Err(error) => println!("Send error: {}", error),
                };
            }
        })
    }
}
<|endoftext|>


<commit_before>use std::{
    collections::BTreeMap,
    convert::TryInto as _,
    env, fmt, fs,
    path::{Path, PathBuf},
};

use chrono::{Datelike as _, TimeZone as _, Utc};
use glob::glob;
use regex::Regex;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
struct Date {
    year: u32,
    month: u32,
}

impl Date {
    fn months_since(self, other: Date) -> Option<u32> {
        let self_chrono = Utc.ymd(self.year.try_into().unwrap(), self.month, 1);
        let other_chrono = Utc.ymd(other.year.try_into().unwrap(), other.month, 1);
        let duration_since = self_chrono.signed_duration_since(other_chrono);
        let months_since = duration_since.num_days() / 30;
        if months_since < 0 {
            None
        } else {
            Some(months_since.try_into().unwrap())
        }
    }
}

impl fmt::Display for Date {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:04}-{:02}", self.year, self.month)
    }
}

fn make_date_regex() -> Regex {
    Regex::new(
        r"(?x) # insignificant whitespace mode
        <!--\s*
        date:\s*
        (?P<y>\d{4}) # year
        -
        (?P<m>\d{2}) # month
        \s*-->",
    )
    .unwrap()
}

fn collect_dates_from_file(date_regex: &Regex, text: &str) -> Vec<(usize, Date)> {
    let mut line = 1;
    let mut end_of_last_cap = 0;
    date_regex
        .captures_iter(&text)
        .map(|cap| {
            (
                cap.get(0).unwrap().range(),
                Date {
                    year: cap["y"].parse().unwrap(),
                    month: cap["m"].parse().unwrap(),
                },
            )
        })
        .map(|(byte_range, date)| {
            line += text[end_of_last_cap..byte_range.end]
                .chars()
                .filter(|c| *c == '\n')
                .count();
            end_of_last_cap = byte_range.end;
            (line, date)
        })
        .collect()
}

fn collect_dates(paths: impl Iterator<Item = PathBuf>) -> BTreeMap<PathBuf, Vec<(usize, Date)>> {
    let date_regex = make_date_regex();
    let mut data = BTreeMap::new();
    for path in paths {
        let text = fs::read_to_string(&path).unwrap();
        let dates = collect_dates_from_file(&date_regex, &text);
        if !dates.is_empty() {
            data.insert(path, dates);
        }
    }
    data
}

fn filter_dates(
    current_month: Date,
    min_months_since: u32,
    dates_by_file: impl Iterator<Item = (PathBuf, Vec<(usize, Date)>)>,
) -> impl Iterator<Item = (PathBuf, Vec<(usize, Date)>)> {
    dates_by_file
        .map(move |(path, dates)| {
            (
                path,
                dates
                    .into_iter()
                    .filter(|(_, date)| {
                        current_month
                            .months_since(*date)
                            .expect("found date that is after current month")
                            >= min_months_since
                    })
                    .collect::<Vec<_>>(),
            )
        })
        .filter(|(_, dates)| !dates.is_empty())
}

fn main() {
    let root_dir = env::args()
        .nth(1)
        .expect("expect root Markdown directory as CLI argument");
    let root_dir_path = Path::new(&root_dir);
    let glob_pat = format!("{}/**/*.md", root_dir);
    let today_chrono = Utc::today();
    let current_month = Date {
        year: today_chrono.year_ce().1,
        month: today_chrono.month(),
    };

    let dates_by_file = collect_dates(glob(&glob_pat).unwrap().map(Result::unwrap));
    let dates_by_file: BTreeMap<_, _> =
        filter_dates(current_month, 6, dates_by_file.into_iter()).collect();

    if dates_by_file.is_empty() {
        println!("empty");
    } else {
        println!("Date Reference Triage for {}", current_month);
        println!("## Procedure");
        println!();
        println!(
            "Each of these dates should be checked to see if the docs they annotate are \
             up-to-date. Each date should be updated (in the Markdown file where it appears) to \
             use the current month ({current_month}), or removed if the docs it annotates are not \
             expected to fall out of date quickly.",
            current_month = current_month
        );
        println!();
        println!(
            "Please check off each date once a PR to update it (and, if applicable, its \
             surrounding docs) has been merged. Please also mention that you are working on a \
             particular set of dates so duplicate work is avoided."
        );
        println!();
        println!("Finally, once all the dates have been updated, please close this issue.");
        println!();
        println!("## Dates");
        println!();

        for (path, dates) in dates_by_file {
            println!(
                "- [ ] {}",
                path.strip_prefix(&root_dir_path).unwrap().display()
            );
            for (line, date) in dates {
                println!("  - [ ] line {}: {}", line, date);
            }
        }
        println!();
    }
}

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

    #[test]
    fn test_months_since() {
        let date1 = Date {
            year: 2020,
            month: 3,
        };
        let date2 = Date {
            year: 2021,
            month: 1,
        };
        assert_eq!(date2.months_since(date1), Some(10));
    }

    #[test]
    fn test_date_regex() {
        let regex = make_date_regex();
        assert!(regex.is_match("foo <!-- date: 2021-01 --> bar"));
    }

    #[test]
    fn test_collect_dates_from_file() {
        let text = "Test1\n<!-- date: 2021-01 -->\nTest2\nFoo<!-- date: 2021-02 \
                    -->\nTest3\nTest4\nFoo<!-- date: 2021-03 -->Bar\n<!-- date: 2021-04 \
                    -->\nTest5\nTest6\nTest7\n<!-- date: \n\n2021-05 -->\nTest8
        ";
        assert_eq!(
            collect_dates_from_file(&make_date_regex(), text),
            vec![
                (
                    2,
                    Date {
                        year: 2021,
                        month: 1,
                    }
                ),
                (
                    4,
                    Date {
                        year: 2021,
                        month: 2,
                    }
                ),
                (
                    7,
                    Date {
                        year: 2021,
                        month: 3,
                    }
                ),
                (
                    8,
                    Date {
                        year: 2021,
                        month: 4,
                    }
                ),
                (
                    14,
                    Date {
                        year: 2021,
                        month: 5,
                    }
                ),
            ]
        );
    }
}
<commit_msg>date-check: Recognize capitalized 'Date' as well<commit_after>use std::{
    collections::BTreeMap,
    convert::TryInto as _,
    env, fmt, fs,
    path::{Path, PathBuf},
};

use chrono::{Datelike as _, TimeZone as _, Utc};
use glob::glob;
use regex::Regex;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
struct Date {
    year: u32,
    month: u32,
}

impl Date {
    fn months_since(self, other: Date) -> Option<u32> {
        let self_chrono = Utc.ymd(self.year.try_into().unwrap(), self.month, 1);
        let other_chrono = Utc.ymd(other.year.try_into().unwrap(), other.month, 1);
        let duration_since = self_chrono.signed_duration_since(other_chrono);
        let months_since = duration_since.num_days() / 30;
        if months_since < 0 {
            None
        } else {
            Some(months_since.try_into().unwrap())
        }
    }
}

impl fmt::Display for Date {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:04}-{:02}", self.year, self.month)
    }
}

fn make_date_regex() -> Regex {
    Regex::new(
        r"(?x) # insignificant whitespace mode
        <!--\s*
        [dD]ate:\s*
        (?P<y>\d{4}) # year
        -
        (?P<m>\d{2}) # month
        \s*-->",
    )
    .unwrap()
}

fn collect_dates_from_file(date_regex: &Regex, text: &str) -> Vec<(usize, Date)> {
    let mut line = 1;
    let mut end_of_last_cap = 0;
    date_regex
        .captures_iter(&text)
        .map(|cap| {
            (
                cap.get(0).unwrap().range(),
                Date {
                    year: cap["y"].parse().unwrap(),
                    month: cap["m"].parse().unwrap(),
                },
            )
        })
        .map(|(byte_range, date)| {
            line += text[end_of_last_cap..byte_range.end]
                .chars()
                .filter(|c| *c == '\n')
                .count();
            end_of_last_cap = byte_range.end;
            (line, date)
        })
        .collect()
}

fn collect_dates(paths: impl Iterator<Item = PathBuf>) -> BTreeMap<PathBuf, Vec<(usize, Date)>> {
    let date_regex = make_date_regex();
    let mut data = BTreeMap::new();
    for path in paths {
        let text = fs::read_to_string(&path).unwrap();
        let dates = collect_dates_from_file(&date_regex, &text);
        if !dates.is_empty() {
            data.insert(path, dates);
        }
    }
    data
}

fn filter_dates(
    current_month: Date,
    min_months_since: u32,
    dates_by_file: impl Iterator<Item = (PathBuf, Vec<(usize, Date)>)>,
) -> impl Iterator<Item = (PathBuf, Vec<(usize, Date)>)> {
    dates_by_file
        .map(move |(path, dates)| {
            (
                path,
                dates
                    .into_iter()
                    .filter(|(_, date)| {
                        current_month
                            .months_since(*date)
                            .expect("found date that is after current month")
                            >= min_months_since
                    })
                    .collect::<Vec<_>>(),
            )
        })
        .filter(|(_, dates)| !dates.is_empty())
}

fn main() {
    let root_dir = env::args()
        .nth(1)
        .expect("expect root Markdown directory as CLI argument");
    let root_dir_path = Path::new(&root_dir);
    let glob_pat = format!("{}/**/*.md", root_dir);
    let today_chrono = Utc::today();
    let current_month = Date {
        year: today_chrono.year_ce().1,
        month: today_chrono.month(),
    };

    let dates_by_file = collect_dates(glob(&glob_pat).unwrap().map(Result::unwrap));
    let dates_by_file: BTreeMap<_, _> =
        filter_dates(current_month, 6, dates_by_file.into_iter()).collect();

    if dates_by_file.is_empty() {
        println!("empty");
    } else {
        println!("Date Reference Triage for {}", current_month);
        println!("## Procedure");
        println!();
        println!(
            "Each of these dates should be checked to see if the docs they annotate are \
             up-to-date. Each date should be updated (in the Markdown file where it appears) to \
             use the current month ({current_month}), or removed if the docs it annotates are not \
             expected to fall out of date quickly.",
            current_month = current_month
        );
        println!();
        println!(
            "Please check off each date once a PR to update it (and, if applicable, its \
             surrounding docs) has been merged. Please also mention that you are working on a \
             particular set of dates so duplicate work is avoided."
        );
        println!();
        println!("Finally, once all the dates have been updated, please close this issue.");
        println!();
        println!("## Dates");
        println!();

        for (path, dates) in dates_by_file {
            println!(
                "- [ ] {}",
                path.strip_prefix(&root_dir_path).unwrap().display()
            );
            for (line, date) in dates {
                println!("  - [ ] line {}: {}", line, date);
            }
        }
        println!();
    }
}

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

    #[test]
    fn test_months_since() {
        let date1 = Date {
            year: 2020,
            month: 3,
        };
        let date2 = Date {
            year: 2021,
            month: 1,
        };
        assert_eq!(date2.months_since(date1), Some(10));
    }

    #[test]
    fn test_date_regex() {
        let regex = make_date_regex();
        assert!(regex.is_match("foo <!-- date: 2021-01 --> bar"));
    }

    #[test]
    fn test_date_regex_capitalized() {
        let regex = make_date_regex();
        assert!(regex.is_match("foo <!-- Date: 2021-08 --> bar"));
    }

    #[test]
    fn test_collect_dates_from_file() {
        let text = "Test1\n<!-- date: 2021-01 -->\nTest2\nFoo<!-- date: 2021-02 \
                    -->\nTest3\nTest4\nFoo<!-- date: 2021-03 -->Bar\n<!-- date: 2021-04 \
                    -->\nTest5\nTest6\nTest7\n<!-- date: \n\n2021-05 -->\nTest8
        ";
        assert_eq!(
            collect_dates_from_file(&make_date_regex(), text),
            vec![
                (
                    2,
                    Date {
                        year: 2021,
                        month: 1,
                    }
                ),
                (
                    4,
                    Date {
                        year: 2021,
                        month: 2,
                    }
                ),
                (
                    7,
                    Date {
                        year: 2021,
                        month: 3,
                    }
                ),
                (
                    8,
                    Date {
                        year: 2021,
                        month: 4,
                    }
                ),
                (
                    14,
                    Date {
                        year: 2021,
                        month: 5,
                    }
                ),
            ]
        );
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use seccomp::{Error, SeccompFilterContext};

/// The default context containing the white listed syscall rules required by `Firecracker` to
/// function.
pub fn default_context() -> Result<SeccompFilterContext, Error> {
    Ok(seccomp::SeccompFilterContext::new(
        vec![].into_iter().collect(),
        seccomp::SeccompAction::Trap,
    )
    .unwrap())
}

/// Applies the configured level of seccomp filtering to the current thread.
pub fn set_seccomp_level(seccomp_level: u32) -> Result<(), Error> {
    Ok(())
}
<commit_msg>seccomp/aarch64: disable build warning<commit_after>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use seccomp::{Error, SeccompFilterContext};

/// The default context containing the white listed syscall rules required by `Firecracker` to
/// function.
pub fn default_context() -> Result<SeccompFilterContext, Error> {
    Ok(seccomp::SeccompFilterContext::new(
        vec![].into_iter().collect(),
        seccomp::SeccompAction::Trap,
    )
    .unwrap())
}

/// Applies the configured level of seccomp filtering to the current thread.
pub fn set_seccomp_level(_seccomp_level: u32) -> Result<(), Error> {
    Ok(())
}
<|endoftext|>