<commit_before>mod components;
mod buffer;
mod square;
mod triangle;
mod noise;
mod dmc;

use super::memory::MemSegment;
use audio::AudioOut;
use std::cmp;
use cpu::IrqInterrupt;
use std::cell::RefCell;
use std::rc::Rc;
use apu::buffer::*;
use apu::square::*;
use apu::triangle::*;
use apu::noise::*;
use apu::dmc::*;

pub type Sample = i16;

static NTSC_TICK_LENGTH_TABLE: [[u64; 6]; 2] = [[7459, 7456, 7458, 7458, 7458, 0000],
                                                [0001, 7458, 7456, 7458, 7458, 7452]];

const VOLUME_MULT: i32 = ((32767i16 / 16) / 2) as i32;

bitflags! {
    flags Frame : u8 {
        const MODE = 0b1000_0000, //0 = 4-step, 1 = 5-step
        const SUPPRESS_IRQ  = 0b0100_0000, //0 = disabled, 1 = enabled
    }
}

impl Frame {
    fn mode(&self) -> usize {
        if self.contains(MODE) {
            return 1;
        } else {
            return 0;
        }
    }
}

trait Writable {
    fn write(&mut self, idx: u16, val: u8);
}

enum Jitter {
    Delay(u64, u8),
    None,
}

pub struct APU {
    square1: Square,
    square2: Square,
    triangle: Triangle,
    noise: Noise,
    dmc: DMC,
    frame: Frame,

    square_buffer: Rc<RefCell<SampleBuffer>>,
    tnd_buffer: Rc<RefCell<SampleBuffer>>,

    device: Box<AudioOut>,

    global_cyc: u64,
    tick: u8,
    next_tick_cyc: u64,
    next_transfer_cyc: u64,
    last_frame_cyc: u64,

    irq_requested: bool,

    jitter: Jitter,
}

impl APU {
    pub fn new(device: Box<AudioOut>) -> APU {
        let sample_rate = device.sample_rate();

        let square_buffer = Rc::new(RefCell::new(SampleBuffer::new(sample_rate)));
        let tnd_buffer = Rc::new(RefCell::new(SampleBuffer::new(sample_rate)));
        let clocks_needed = square_buffer.borrow().clocks_needed() as u64;

        APU {
            square1: Square::new(false, Waveform::new(square_buffer.clone(), VOLUME_MULT)),
            square2: Square::new(true, Waveform::new(square_buffer.clone(), VOLUME_MULT)),
            triangle: Triangle::new(Waveform::new(tnd_buffer.clone(), VOLUME_MULT)),
            noise: Noise::new(),
            dmc: DMC::new(),
            frame: Frame::empty(),

            square_buffer: square_buffer,
            tnd_buffer: tnd_buffer,

            device: device,

            global_cyc: 0,
            tick: 0,
            next_tick_cyc: NTSC_TICK_LENGTH_TABLE[0][0],
            next_transfer_cyc: clocks_needed,
            last_frame_cyc: 0,

            irq_requested: false,

            jitter: Jitter::None,
        }
    }

    pub fn run_to(&mut self, cpu_cycle: u64) -> IrqInterrupt {
        let mut interrupt = IrqInterrupt::None;

        while self.global_cyc < cpu_cycle {
            let current_cycle = self.global_cyc;

            let mut next_step = cmp::min(cpu_cycle, self.next_tick_cyc);
            next_step = cmp::min(next_step, self.next_transfer_cyc);

            if let Jitter::Delay(time, _) = self.jitter {
                next_step = cmp::min(next_step, time);
            }

            self.play(current_cycle, next_step);
            self.global_cyc = next_step;

            if let Jitter::Delay(time, val) = self.jitter {
                if self.global_cyc == time {
                    self.set_4017(val);
                    self.jitter = Jitter::None;
                }
            }
            if self.global_cyc == self.next_tick_cyc {
                interrupt = interrupt.or(self.tick());
            }
            if self.global_cyc == self.next_transfer_cyc {
                self.transfer();
            }
        }
        interrupt
    }

    /// Represents the 240Hz output of the frame sequencer's divider
    fn tick(&mut self) -> IrqInterrupt {
        self.tick += 1;
        let mode = self.frame.mode();
        self.next_tick_cyc = self.global_cyc + NTSC_TICK_LENGTH_TABLE[mode][self.tick as usize];

        match mode {
            0 => {
                match self.tick {
                    1 => {
                        self.envelope_tick();
                    }
                    2 => {
                        self.envelope_tick();
                        self.length_tick();
                    }
                    3 => {
                        self.envelope_tick();
                    }
                    4 => {
                        self.tick = 0;
                        self.envelope_tick();
                        self.length_tick();
                        return self.raise_irq();
                    }
                    _ => {
                        self.tick = 0;
                    }
                }
            }
            1 => {
                match self.tick {
                    1 => {
                        self.envelope_tick();
                        self.length_tick()
                    }
                    2 => {
                        self.envelope_tick();
                    }
                    3 => {
                        self.envelope_tick();
                        self.length_tick()
                    }
                    4 => {
                        self.envelope_tick();
                    }
                    5 => {
                        self.tick = 0;
                    } //4 is the actual last tick in the cycle.
                    _ => {
                        self.tick = 0;
                    }
                }
            }
            _ => (),
        }
        IrqInterrupt::None
    }

    fn envelope_tick(&mut self) {
        self.square1.envelope_tick();
        self.square2.envelope_tick();
        self.triangle.envelope_tick();
        self.noise.envelope_tick();
    }

    fn length_tick(&mut self) {
        self.square1.length_tick();
        self.square2.length_tick();
        self.triangle.length_tick();
        self.noise.length_tick();
    }

    fn raise_irq(&mut self) -> IrqInterrupt {
        if !self.frame.contains(SUPPRESS_IRQ) {
            self.irq_requested = true;
            return IrqInterrupt::IRQ;
        }
        return IrqInterrupt::None;
    }

    fn play(&mut self, from_cyc: u64, to_cyc: u64) {
        let from = (from_cyc - self.last_frame_cyc) as u32;
        let to = (to_cyc - self.last_frame_cyc) as u32;
        self.square1.play(from, to);
        self.square2.play(from, to);
        self.triangle.play(from, to);
        self.noise.play(from, to);
        self.dmc.play(from, to);
    }

    fn transfer(&mut self) {
        let cpu_cyc = self.global_cyc;
        let cycles_since_last_frame = (cpu_cyc - self.last_frame_cyc) as u32;
        self.last_frame_cyc = cpu_cyc;

        let mut square_buf = self.square_buffer.borrow_mut();
        let mut tnd_buf = self.tnd_buffer.borrow_mut();
        square_buf.end_frame(cycles_since_last_frame);
        tnd_buf.end_frame(cycles_since_last_frame);
        let samples: Vec<Sample> = {
            let iter1 = square_buf.read().iter().cloned();
            let iter2 = tnd_buf.read().iter().cloned();
            iter1.zip(iter2)
                .map(|(s, t)| s + t) //TODO: Add proper nonlinear mixing.
                .collect()
        };
        self.next_transfer_cyc = cpu_cyc + square_buf.clocks_needed() as u64;
        self.device.play(&samples);
    }

    ///Returns the cycle number representing the next time the CPU should run the APU.
    ///Min of the next APU IRQ, the next DMC IRQ, and the next tick time. When the CPU cycle reaches
    ///this number, the CPU must run the APU.
    pub fn requested_run_cycle(&self) -> u64 {
        // In practice, the next tick time should cover the APU IRQ as well, since the
        // IRQ happens on tick boundaries. The DMC IRQ isn't implemented yet.
        // Using the tick time ensures that the APU will never get too far behind the
        // CPU.
        self.next_tick_cyc
    }

    fn set_4017(&mut self, val: u8) {
        self.frame = Frame::from_bits_truncate(val);
        if self.frame.contains(SUPPRESS_IRQ) {
            self.irq_requested = false;
        }

        self.tick = 0;
        self.next_tick_cyc = self.global_cyc + NTSC_TICK_LENGTH_TABLE[self.frame.mode()][0];
    }

    #[cfg_attr(rustfmt, rustfmt_skip)]
    pub fn read_status(&mut self, cycle: u64) -> (IrqInterrupt, u8) {
        let interrupt = self.run_to(cycle - 1);

        let mut status: u8 = 0;
        status = status | (self.square1.length.active() << 0);
        status = status | (self.square2.length.active() << 1);
        status = status | (self.triangle.length.active() << 2);
        status = status | (self.noise.length.active() << 3);
        status = status | if self.irq_requested { 1 << 6 } else { 0 };
    // TODO add DMC status
    // TODO add DMC interrupt flag
        self.irq_requested = false;

        (interrupt.or(self.run_to(cycle)), status)
    }

    pub fn write(&mut self, idx: u16, val: u8) {
        match idx % 0x20 {
            x @ 0x00...0x03 => self.square1.write(x, val),
            x @ 0x04...0x07 => self.square2.write(x, val),
            x @ 0x08...0x0B => self.triangle.write(x, val),
            x @ 0x0C...0x0F => self.noise.write(x, val),
            x @ 0x10...0x13 => self.dmc.write(x, val),
            0x0014 => (),
            0x0015 => {
                self.noise.length.set_enable(val & 0b0000_1000 != 0);
                self.triangle.length.set_enable(val & 0b0000_0100 != 0);
                self.square2.length.set_enable(val & 0b0000_0010 != 0);
                self.square1.length.set_enable(val & 0b0000_0001 != 0);
            }
            0x0016 => (),
            0x0017 => {
                if self.global_cyc % 2 == 0 {
                    self.set_4017(val);
                } else {
                    self.jitter = Jitter::Delay(self.global_cyc + 1, val);
                }
            }
            _ => (),
        }
    }
}
<commit_msg>Prevent overflow in audio mixing code.<commit_after>mod components;
mod buffer;
mod square;
mod triangle;
mod noise;
mod dmc;

use super::memory::MemSegment;
use audio::AudioOut;
use std::cmp;
use cpu::IrqInterrupt;
use std::cell::RefCell;
use std::rc::Rc;
use apu::buffer::*;
use apu::square::*;
use apu::triangle::*;
use apu::noise::*;
use apu::dmc::*;

pub type Sample = i16;

static NTSC_TICK_LENGTH_TABLE: [[u64; 6]; 2] = [[7459, 7456, 7458, 7458, 7458, 0000],
                                                [0001, 7458, 7456, 7458, 7458, 7452]];

const VOLUME_MULT: i32 = ((32767i16 / 16) / 3) as i32;

bitflags! {
    flags Frame : u8 {
        const MODE = 0b1000_0000, //0 = 4-step, 1 = 5-step
        const SUPPRESS_IRQ  = 0b0100_0000, //0 = disabled, 1 = enabled
    }
}

impl Frame {
    fn mode(&self) -> usize {
        if self.contains(MODE) {
            return 1;
        } else {
            return 0;
        }
    }
}

trait Writable {
    fn write(&mut self, idx: u16, val: u8);
}

enum Jitter {
    Delay(u64, u8),
    None,
}

pub struct APU {
    square1: Square,
    square2: Square,
    triangle: Triangle,
    noise: Noise,
    dmc: DMC,
    frame: Frame,

    square_buffer: Rc<RefCell<SampleBuffer>>,
    tnd_buffer: Rc<RefCell<SampleBuffer>>,

    device: Box<AudioOut>,

    global_cyc: u64,
    tick: u8,
    next_tick_cyc: u64,
    next_transfer_cyc: u64,
    last_frame_cyc: u64,

    irq_requested: bool,

    jitter: Jitter,
}

impl APU {
    pub fn new(device: Box<AudioOut>) -> APU {
        let sample_rate = device.sample_rate();

        let square_buffer = Rc::new(RefCell::new(SampleBuffer::new(sample_rate)));
        let tnd_buffer = Rc::new(RefCell::new(SampleBuffer::new(sample_rate)));
        let clocks_needed = square_buffer.borrow().clocks_needed() as u64;

        APU {
            square1: Square::new(false, Waveform::new(square_buffer.clone(), VOLUME_MULT)),
            square2: Square::new(true, Waveform::new(square_buffer.clone(), VOLUME_MULT)),
            triangle: Triangle::new(Waveform::new(tnd_buffer.clone(), VOLUME_MULT)),
            noise: Noise::new(),
            dmc: DMC::new(),
            frame: Frame::empty(),

            square_buffer: square_buffer,
            tnd_buffer: tnd_buffer,

            device: device,

            global_cyc: 0,
            tick: 0,
            next_tick_cyc: NTSC_TICK_LENGTH_TABLE[0][0],
            next_transfer_cyc: clocks_needed,
            last_frame_cyc: 0,

            irq_requested: false,

            jitter: Jitter::None,
        }
    }

    pub fn run_to(&mut self, cpu_cycle: u64) -> IrqInterrupt {
        let mut interrupt = IrqInterrupt::None;

        while self.global_cyc < cpu_cycle {
            let current_cycle = self.global_cyc;

            let mut next_step = cmp::min(cpu_cycle, self.next_tick_cyc);
            next_step = cmp::min(next_step, self.next_transfer_cyc);

            if let Jitter::Delay(time, _) = self.jitter {
                next_step = cmp::min(next_step, time);
            }

            self.play(current_cycle, next_step);
            self.global_cyc = next_step;

            if let Jitter::Delay(time, val) = self.jitter {
                if self.global_cyc == time {
                    self.set_4017(val);
                    self.jitter = Jitter::None;
                }
            }
            if self.global_cyc == self.next_tick_cyc {
                interrupt = interrupt.or(self.tick());
            }
            if self.global_cyc == self.next_transfer_cyc {
                self.transfer();
            }
        }
        interrupt
    }

    /// Represents the 240Hz output of the frame sequencer's divider
    fn tick(&mut self) -> IrqInterrupt {
        self.tick += 1;
        let mode = self.frame.mode();
        self.next_tick_cyc = self.global_cyc + NTSC_TICK_LENGTH_TABLE[mode][self.tick as usize];

        match mode {
            0 => {
                match self.tick {
                    1 => {
                        self.envelope_tick();
                    }
                    2 => {
                        self.envelope_tick();
                        self.length_tick();
                    }
                    3 => {
                        self.envelope_tick();
                    }
                    4 => {
                        self.tick = 0;
                        self.envelope_tick();
                        self.length_tick();
                        return self.raise_irq();
                    }
                    _ => {
                        self.tick = 0;
                    }
                }
            }
            1 => {
                match self.tick {
                    1 => {
                        self.envelope_tick();
                        self.length_tick()
                    }
                    2 => {
                        self.envelope_tick();
                    }
                    3 => {
                        self.envelope_tick();
                        self.length_tick()
                    }
                    4 => {
                        self.envelope_tick();
                    }
                    5 => {
                        self.tick = 0;
                    } //4 is the actual last tick in the cycle.
                    _ => {
                        self.tick = 0;
                    }
                }
            }
            _ => (),
        }
        IrqInterrupt::None
    }

    fn envelope_tick(&mut self) {
        self.square1.envelope_tick();
        self.square2.envelope_tick();
        self.triangle.envelope_tick();
        self.noise.envelope_tick();
    }

    fn length_tick(&mut self) {
        self.square1.length_tick();
        self.square2.length_tick();
        self.triangle.length_tick();
        self.noise.length_tick();
    }

    fn raise_irq(&mut self) -> IrqInterrupt {
        if !self.frame.contains(SUPPRESS_IRQ) {
            self.irq_requested = true;
            return IrqInterrupt::IRQ;
        }
        return IrqInterrupt::None;
    }

    fn play(&mut self, from_cyc: u64, to_cyc: u64) {
        let from = (from_cyc - self.last_frame_cyc) as u32;
        let to = (to_cyc - self.last_frame_cyc) as u32;
        self.square1.play(from, to);
        self.square2.play(from, to);
        self.triangle.play(from, to);
        self.noise.play(from, to);
        self.dmc.play(from, to);
    }

    fn transfer(&mut self) {
        let cpu_cyc = self.global_cyc;
        let cycles_since_last_frame = (cpu_cyc - self.last_frame_cyc) as u32;
        self.last_frame_cyc = cpu_cyc;

        let mut square_buf = self.square_buffer.borrow_mut();
        let mut tnd_buf = self.tnd_buffer.borrow_mut();
        square_buf.end_frame(cycles_since_last_frame);
        tnd_buf.end_frame(cycles_since_last_frame);
        let samples: Vec<Sample> = {
            let iter1 = square_buf.read().iter().cloned();
            let iter2 = tnd_buf.read().iter().cloned();
            iter1.zip(iter2)
                .map(|(s, t)| s + t) //TODO: Add proper nonlinear mixing.
                .collect()
        };
        self.next_transfer_cyc = cpu_cyc + square_buf.clocks_needed() as u64;
        self.device.play(&samples);
    }

    ///Returns the cycle number representing the next time the CPU should run the APU.
    ///Min of the next APU IRQ, the next DMC IRQ, and the next tick time. When the CPU cycle reaches
    ///this number, the CPU must run the APU.
    pub fn requested_run_cycle(&self) -> u64 {
        // In practice, the next tick time should cover the APU IRQ as well, since the
        // IRQ happens on tick boundaries. The DMC IRQ isn't implemented yet.
        // Using the tick time ensures that the APU will never get too far behind the
        // CPU.
        self.next_tick_cyc
    }

    fn set_4017(&mut self, val: u8) {
        self.frame = Frame::from_bits_truncate(val);
        if self.frame.contains(SUPPRESS_IRQ) {
            self.irq_requested = false;
        }

        self.tick = 0;
        self.next_tick_cyc = self.global_cyc + NTSC_TICK_LENGTH_TABLE[self.frame.mode()][0];
    }

    #[cfg_attr(rustfmt, rustfmt_skip)]
    pub fn read_status(&mut self, cycle: u64) -> (IrqInterrupt, u8) {
        let interrupt = self.run_to(cycle - 1);

        let mut status: u8 = 0;
        status = status | (self.square1.length.active() << 0);
        status = status | (self.square2.length.active() << 1);
        status = status | (self.triangle.length.active() << 2);
        status = status | (self.noise.length.active() << 3);
        status = status | if self.irq_requested { 1 << 6 } else { 0 };
    // TODO add DMC status
    // TODO add DMC interrupt flag
        self.irq_requested = false;

        (interrupt.or(self.run_to(cycle)), status)
    }

    pub fn write(&mut self, idx: u16, val: u8) {
        match idx % 0x20 {
            x @ 0x00...0x03 => self.square1.write(x, val),
            x @ 0x04...0x07 => self.square2.write(x, val),
            x @ 0x08...0x0B => self.triangle.write(x, val),
            x @ 0x0C...0x0F => self.noise.write(x, val),
            x @ 0x10...0x13 => self.dmc.write(x, val),
            0x0014 => (),
            0x0015 => {
                self.noise.length.set_enable(val & 0b0000_1000 != 0);
                self.triangle.length.set_enable(val & 0b0000_0100 != 0);
                self.square2.length.set_enable(val & 0b0000_0010 != 0);
                self.square1.length.set_enable(val & 0b0000_0001 != 0);
            }
            0x0016 => (),
            0x0017 => {
                if self.global_cyc % 2 == 0 {
                    self.set_4017(val);
                } else {
                    self.jitter = Jitter::Delay(self.global_cyc + 1, val);
                }
            }
            _ => (),
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>fail on non-sym<commit_after><|endoftext|>


<commit_before>// Copyright 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 core::sync::atomic::{spin_loop_hint as cpu_relax};

use crate::Mutex;

/// A primitive that synchronizes the execution of multiple threads.
///
/// # Example
///
/// ```
/// use spin;
/// use std::sync::Arc;
/// use std::thread;
///
/// let mut handles = Vec::with_capacity(10);
/// let barrier = Arc::new(spin::Barrier::new(10));
/// for _ in 0..10 {
///     let c = barrier.clone();
///     // The same messages will be printed together.
///     // You will NOT see any interleaving.
///     handles.push(thread::spawn(move|| {
///         println!("before wait");
///         c.wait();
///         println!("after wait");
///     }));
/// }
/// // Wait for other threads to finish.
/// for handle in handles {
///     handle.join().unwrap();
/// }
/// ```
pub struct Barrier {
    lock: Mutex<BarrierState>,
    num_threads: usize,
}

// The inner state of a double barrier
struct BarrierState {
    count: usize,
    generation_id: usize,
}

/// A `BarrierWaitResult` is returned by [`wait`] when all threads in the [`Barrier`]
/// have rendezvoused.
///
/// [`wait`]: struct.Barrier.html#method.wait
/// [`Barrier`]: struct.Barrier.html
///
/// # Examples
///
/// ```
/// use spin;
///
/// let barrier = spin::Barrier::new(1);
/// let barrier_wait_result = barrier.wait();
/// ```
pub struct BarrierWaitResult(bool);

impl Barrier {
    /// Creates a new barrier that can block a given number of threads.
    ///
    /// A barrier will block `n`-1 threads which call [`wait`] and then wake up
    /// all threads at once when the `n`th thread calls [`wait`]. A Barrier created
    /// with n = 0 will behave identically to one created with n = 1.
    ///
    /// [`wait`]: #method.wait
    ///
    /// # Examples
    ///
    /// ```
    /// use spin;
    ///
    /// let barrier = spin::Barrier::new(10);
    /// ```
    pub const fn new(n: usize) -> Barrier {
        Barrier {
            lock: Mutex::new(BarrierState {
                count: 0,
                generation_id: 0,
            }),
            num_threads: n,
        }
    }

    /// Blocks the current thread until all threads have rendezvoused here.
    ///
    /// Barriers are re-usable after all threads have rendezvoused once, and can
    /// be used continuously.
    ///
    /// A single (arbitrary) thread will receive a [`BarrierWaitResult`] that
    /// returns `true` from [`is_leader`] when returning from this function, and
    /// all other threads will receive a result that will return `false` from
    /// [`is_leader`].
    ///
    /// [`BarrierWaitResult`]: struct.BarrierWaitResult.html
    /// [`is_leader`]: struct.BarrierWaitResult.html#method.is_leader
    ///
    /// # Examples
    ///
    /// ```
    /// use spin;
    /// use std::sync::Arc;
    /// use std::thread;
    ///
    /// let mut handles = Vec::with_capacity(10);
    /// let barrier = Arc::new(spin::Barrier::new(10));
    /// for _ in 0..10 {
    ///     let c = barrier.clone();
    ///     // The same messages will be printed together.
    ///     // You will NOT see any interleaving.
    ///     handles.push(thread::spawn(move|| {
    ///         println!("before wait");
    ///         c.wait();
    ///         println!("after wait");
    ///     }));
    /// }
    /// // Wait for other threads to finish.
    /// for handle in handles {
    ///     handle.join().unwrap();
    /// }
    /// ```
    pub fn wait(&self) -> BarrierWaitResult {
        let mut lock = self.lock.lock();
        lock.count += 1;

        if lock.count < self.num_threads {
            // not the leader
            let local_gen = lock.generation_id;

            while local_gen == lock.generation_id &&
                lock.count < self.num_threads {
                drop(lock);
                cpu_relax();
                lock = self.lock.lock();
            }
            return BarrierWaitResult(false);
        } else {
            // this thread is the leader,
            //   and is responsible for incrementing the generation
            lock.count = 0;
            lock.generation_id = lock.generation_id.wrapping_add(1);
            return BarrierWaitResult(true);
        }
    }
}

impl BarrierWaitResult {
    /// Returns whether this thread from [`wait`] is the "leader thread".
    ///
    /// Only one thread will have `true` returned from their result, all other
    /// threads will have `false` returned.
    ///
    /// [`wait`]: struct.Barrier.html#method.wait
    ///
    /// # Examples
    ///
    /// ```
    /// use spin;
    ///
    /// let barrier = spin::Barrier::new(1);
    /// let barrier_wait_result = barrier.wait();
    /// println!("{:?}", barrier_wait_result.is_leader());
    /// ```
    pub fn is_leader(&self) -> bool { self.0 }
}

#[cfg(test)]
mod tests {
    use std::prelude::v1::*;

    use std::sync::mpsc::{channel, TryRecvError};
    use std::sync::Arc;
    use std::thread;

    use super::Barrier;

    fn use_barrier(n: usize, barrier: Arc<Barrier>) {
        let (tx, rx) = channel();

        for _ in 0..n - 1 {
            let c = barrier.clone();
            let tx = tx.clone();
            thread::spawn(move|| {
                tx.send(c.wait().is_leader()).unwrap();
            });
        }

        // At this point, all spawned threads should be blocked,
        // so we shouldn't get anything from the port
        assert!(match rx.try_recv() {
            Err(TryRecvError::Empty) => true,
            _ => false,
        });

        let mut leader_found = barrier.wait().is_leader();

        // Now, the barrier is cleared and we should get data.
        for _ in 0..n - 1 {
            if rx.recv().unwrap() {
                assert!(!leader_found);
                leader_found = true;
            }
        }
        assert!(leader_found);
    }

    #[test]
    fn test_barrier() {
        const N: usize = 10;

        let barrier = Arc::new(Barrier::new(N));

        use_barrier(N, barrier.clone());

        // use barrier twice to ensure it is reusable
        use_barrier(N, barrier.clone());
    }
}
<commit_msg>add doc comment, fix minor lint<commit_after>//! Synchronization primitive allowing multiple threads to synchronize the
//! beginning of some computation.
//!
//! Implementation adopted the 'Barrier' type of the standard library. See:
//! https://doc.rust-lang.org/std/sync/struct.Barrier.html
//!
//! Copyright 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 core::sync::atomic::spin_loop_hint as cpu_relax;

use crate::Mutex;

/// A primitive that synchronizes the execution of multiple threads.
///
/// # Example
///
/// ```
/// use spin;
/// use std::sync::Arc;
/// use std::thread;
///
/// let mut handles = Vec::with_capacity(10);
/// let barrier = Arc::new(spin::Barrier::new(10));
/// for _ in 0..10 {
///     let c = barrier.clone();
///     // The same messages will be printed together.
///     // You will NOT see any interleaving.
///     handles.push(thread::spawn(move|| {
///         println!("before wait");
///         c.wait();
///         println!("after wait");
///     }));
/// }
/// // Wait for other threads to finish.
/// for handle in handles {
///     handle.join().unwrap();
/// }
/// ```
pub struct Barrier {
    lock: Mutex<BarrierState>,
    num_threads: usize,
}

// The inner state of a double barrier
struct BarrierState {
    count: usize,
    generation_id: usize,
}

/// A `BarrierWaitResult` is returned by [`wait`] when all threads in the [`Barrier`]
/// have rendezvoused.
///
/// [`wait`]: struct.Barrier.html#method.wait
/// [`Barrier`]: struct.Barrier.html
///
/// # Examples
///
/// ```
/// use spin;
///
/// let barrier = spin::Barrier::new(1);
/// let barrier_wait_result = barrier.wait();
/// ```
pub struct BarrierWaitResult(bool);

impl Barrier {
    /// Creates a new barrier that can block a given number of threads.
    ///
    /// A barrier will block `n`-1 threads which call [`wait`] and then wake up
    /// all threads at once when the `n`th thread calls [`wait`]. A Barrier created
    /// with n = 0 will behave identically to one created with n = 1.
    ///
    /// [`wait`]: #method.wait
    ///
    /// # Examples
    ///
    /// ```
    /// use spin;
    ///
    /// let barrier = spin::Barrier::new(10);
    /// ```
    pub const fn new(n: usize) -> Barrier {
        Barrier {
            lock: Mutex::new(BarrierState {
                count: 0,
                generation_id: 0,
            }),
            num_threads: n,
        }
    }

    /// Blocks the current thread until all threads have rendezvoused here.
    ///
    /// Barriers are re-usable after all threads have rendezvoused once, and can
    /// be used continuously.
    ///
    /// A single (arbitrary) thread will receive a [`BarrierWaitResult`] that
    /// returns `true` from [`is_leader`] when returning from this function, and
    /// all other threads will receive a result that will return `false` from
    /// [`is_leader`].
    ///
    /// [`BarrierWaitResult`]: struct.BarrierWaitResult.html
    /// [`is_leader`]: struct.BarrierWaitResult.html#method.is_leader
    ///
    /// # Examples
    ///
    /// ```
    /// use spin;
    /// use std::sync::Arc;
    /// use std::thread;
    ///
    /// let mut handles = Vec::with_capacity(10);
    /// let barrier = Arc::new(spin::Barrier::new(10));
    /// for _ in 0..10 {
    ///     let c = barrier.clone();
    ///     // The same messages will be printed together.
    ///     // You will NOT see any interleaving.
    ///     handles.push(thread::spawn(move|| {
    ///         println!("before wait");
    ///         c.wait();
    ///         println!("after wait");
    ///     }));
    /// }
    /// // Wait for other threads to finish.
    /// for handle in handles {
    ///     handle.join().unwrap();
    /// }
    /// ```
    pub fn wait(&self) -> BarrierWaitResult {
        let mut lock = self.lock.lock();
        lock.count += 1;

        if lock.count < self.num_threads {
            // not the leader
            let local_gen = lock.generation_id;

            while local_gen == lock.generation_id &&
                lock.count < self.num_threads {
                drop(lock);
                cpu_relax();
                lock = self.lock.lock();
            }
            BarrierWaitResult(false)
        } else {
            // this thread is the leader,
            //   and is responsible for incrementing the generation
            lock.count = 0;
            lock.generation_id = lock.generation_id.wrapping_add(1);
            BarrierWaitResult(true)
        }
    }
}

impl BarrierWaitResult {
    /// Returns whether this thread from [`wait`] is the "leader thread".
    ///
    /// Only one thread will have `true` returned from their result, all other
    /// threads will have `false` returned.
    ///
    /// [`wait`]: struct.Barrier.html#method.wait
    ///
    /// # Examples
    ///
    /// ```
    /// use spin;
    ///
    /// let barrier = spin::Barrier::new(1);
    /// let barrier_wait_result = barrier.wait();
    /// println!("{:?}", barrier_wait_result.is_leader());
    /// ```
    pub fn is_leader(&self) -> bool { self.0 }
}

#[cfg(test)]
mod tests {
    use std::prelude::v1::*;

    use std::sync::mpsc::{channel, TryRecvError};
    use std::sync::Arc;
    use std::thread;

    use super::Barrier;

    fn use_barrier(n: usize, barrier: Arc<Barrier>) {
        let (tx, rx) = channel();

        for _ in 0..n - 1 {
            let c = barrier.clone();
            let tx = tx.clone();
            thread::spawn(move|| {
                tx.send(c.wait().is_leader()).unwrap();
            });
        }

        // At this point, all spawned threads should be blocked,
        // so we shouldn't get anything from the port
        assert!(match rx.try_recv() {
            Err(TryRecvError::Empty) => true,
            _ => false,
        });

        let mut leader_found = barrier.wait().is_leader();

        // Now, the barrier is cleared and we should get data.
        for _ in 0..n - 1 {
            if rx.recv().unwrap() {
                assert!(!leader_found);
                leader_found = true;
            }
        }
        assert!(leader_found);
    }

    #[test]
    fn test_barrier() {
        const N: usize = 10;

        let barrier = Arc::new(Barrier::new(N));

        use_barrier(N, barrier.clone());

        // use barrier twice to ensure it is reusable
        use_barrier(N, barrier.clone());
    }
}
<|endoftext|>


<commit_before>#![allow(unused_imports, unused_must_use, unused_variables, dead_code)]

extern crate combine;

use std::io::prelude::*;
use std::fs::File;
use std::path::Path;
use std::str;
use std::marker::PhantomData;
use combine::{spaces, parser, between, many, many1, digit, char, any, string, token, Parser, ParserExt, ParseError};
use combine::primitives::{State, Stream, ParseResult, Consumed};
use combine::combinator::{Between, Token, FnParser, satisfy};

//my own bencode stuff!
//
fn open_file <P: AsRef<Path>>(path: P) -> Vec<u8> {
    let mut fd = File::open(path).unwrap();
    let mut buffer:Vec<u8> = Vec::new();
    fd.read_to_end(&mut buffer);
    buffer
}

#[derive(Debug, Eq, PartialEq)]
enum Bencode {
    Int(i64),
    String(String),
    List(Vec<Bencode>)
}

fn bencode_integer<I>(input: State<I>) -> ParseResult<Bencode, I> where I:Stream<Item=char> {
    let (open, close) = (char('i'), char('e'));
    let mut int = between(open, close, many1::<String, _>(digit())).map(|x| {
        Bencode::Int(x.parse::<i64>().unwrap())
    });
    int.parse_state(input)
}

fn bencode_string<I>(input: State<I>) -> ParseResult<Bencode, I> where I:Stream<Item=char> {
    let (len, input_) = try!(bencode_string_length_prefix(input));
    input_.combine(|input__| take(len).map(|x| Bencode::String(x)).parse_state(input__))
}

fn bencode_string_length_prefix<I>(input: State<I>) -> ParseResult<i32, I> where I:Stream<Item=char> {
    let many_digit = many1::<String, _>(digit());
    let mut get_len = (many_digit, char(':')).map(|(length, _)| length.parse::<i32>().unwrap());
    get_len.parse_state(input)
}

fn bencode_list<I>(input: State<I>) -> ParseResult<Bencode, I> where I:Stream<Item=char> {
    let (open, close) = (char('l'), char('e'));
    let bencode_types = parser(bencode_integer)
                            .or(parser(bencode_string))
                            .or(parser(bencode_list));
    let list_contents = many(bencode_types);
    let mut list = between(open, close, list_contents).map(|x| Bencode::List(x));
    list.parse_state(input)
}

fn bencode_dict<I>(input: State<I>) -> ParseResult<Bencode, I> where I:Stream<Item=char> {
    let (open, close) = (char('d'), char('e'));
    let dict_contents = parser(bencode_integer)
                            .or(parser(bencode_string))
                            .or(parser(bencode_list));
    let pairs = (parser(bencode_string), dict_contents);
    let mut dict = between(open, close, many(pairs)).map(|x:Vec<(Bencode, Bencode)>|{
        println!("len: {}", x.len());
        /*let temp_vec =
        for v in x {

        }*/
        Bencode::String("abc".to_string())
    });

    dict.parse_state(input)
}

fn take <I> (num: i32) -> SizedBuffer<I> where I: Stream<Item=char> {
    SizedBuffer(num, PhantomData)
}

#[derive(Clone)]
pub struct SizedBuffer <I>(i32, PhantomData<I>);
impl <I> Parser for SizedBuffer<I> where I: Stream<Item=char> {
    type Input = I;
    type Output = String;
    fn parse_lazy(&mut self, mut input: State<I>) -> ParseResult<String, I> {
        let start = input.position;
        let mut vec_buf:Vec<char> = Vec::new();
        for _ in 0..self.0 {
            match input.uncons() {
                Ok((other, rest)) => {
                    vec_buf.push(other);
                    input = rest.into_inner();
                }
                Err(error) => {
                    return error.combine(|mut error| {
                        error.position = start;
                        Err(Consumed::Consumed(error))
                    })
                }
            };
        }
        Ok((vec_buf.into_iter().collect(), Consumed::Consumed(input)))
    }
}

fn main () {
    let file_contents = open_file("t-test.torrent");

    match str::from_utf8(&file_contents) {
        Ok(v) => println!("file: {}", v),
        Err(e) => panic!("Not a UTF-8 String: {}", e)
    };

    let result = parser(bencode_dict).parse("d3:abci4ee");
}

#[test]
fn test_integer() {
    let result = parser(bencode_integer).parse("i57e");
    assert_eq!(result, Ok((Bencode::Int(57),"")));
}

#[test]
fn test_string() {
    let result = parser(bencode_string).parse("5:abcde");
    assert_eq!(result, Ok((Bencode::String("abcde".to_string()), "")));;
}

#[test]
fn test_list() {
    let homogenous_int_list = parser(bencode_list).parse("li57ei32ee");
    assert_eq!(homogenous_int_list, Ok((Bencode::List(vec![Bencode::Int(57), Bencode::Int(32)]), "")));

    let homogenous_str_list = parser(bencode_list).parse("l3:abc5:defghe");
    assert_eq!(homogenous_str_list, Ok((Bencode::List(vec![Bencode::String("abc".to_string()), Bencode::String("defgh".to_string())]), "")));

    let hetero_list = parser(bencode_list).parse("li32e3:abce");
    assert_eq!(hetero_list, Ok((Bencode::List(vec![Bencode::Int(32), Bencode::String("abc".to_string())]), "")));
}

<commit_msg>adding bencode dict. type signatures are better but compilation time suffers<commit_after>#![allow(unused_imports, unused_must_use, unused_variables, dead_code)]

extern crate combine;

use std::io::prelude::*;
use std::fs::File;
use std::path::Path;
use std::str;
use std::collections::HashMap;
use std::marker::PhantomData;
use combine::{spaces, parser, between, many, many1, digit, char, any, string, token, Parser, ParserExt, ParseError};
use combine::primitives::{State, Stream, ParseResult, Consumed};
use combine::combinator::{Between, Token, FnParser, satisfy};

//my own bencode stuff!
//
fn open_file <P: AsRef<Path>>(path: P) -> Vec<u8> {
    let mut fd = File::open(path).unwrap();
    let mut buffer:Vec<u8> = Vec::new();
    fd.read_to_end(&mut buffer);
    buffer
}

#[derive(Debug, Eq, PartialEq)]
enum Bencode {
    Int(i64),
    String(String),
    List(Vec<Bencode>),
    Dict(HashMap<String, Bencode>)
}

fn bencode_integer<I>(input: State<I>) -> ParseResult<i64, I> where I:Stream<Item=char> {
    let (open, close) = (char('i'), char('e'));
    let mut int = between(open, close, many1::<String, _>(digit())).map(|x| {
        x.parse::<i64>().unwrap()
    });
    int.parse_state(input)
}

fn bencode_string<I>(input: State<I>) -> ParseResult<String, I> where I:Stream<Item=char> {
    let (len, input_) = try!(bencode_string_length_prefix(input));
    input_.combine(|input__| take(len).parse_state(input__))
}

fn bencode_string_length_prefix<I>(input: State<I>) -> ParseResult<i32, I> where I:Stream<Item=char> {
    let many_digit = many1::<String, _>(digit());
    let mut get_len = (many_digit, char(':')).map(|(length, _)| length.parse::<i32>().unwrap());
    get_len.parse_state(input)
}

fn bencode_list<I>(input: State<I>) -> ParseResult<Vec<Bencode>, I> where I:Stream<Item=char> {
    let (open, close) = (char('l'), char('e'));
    let bencode_types = parser(bencode_integer).map(Bencode::Int)
                            .or(parser(bencode_string).map(Bencode::String))
                            .or(parser(bencode_list).map(Bencode::List))
                            .or(parser(bencode_dict).map(Bencode::Dict));
    let list_contents = many::<Vec<Bencode>, _>(bencode_types);
    let mut list = between(open, close, list_contents);
    list.parse_state(input)
}

fn bencode_dict<I>(input: State<I>) -> ParseResult<HashMap<String, Bencode>, I> where I:Stream<Item=char> {
    let (open, close) = (char('d'), char('e'));
    let dict_contents = parser(bencode_integer).map(Bencode::Int)
                            .or(parser(bencode_string).map(Bencode::String))
                            .or(parser(bencode_list).map(Bencode::List))
                            .or(parser(bencode_dict).map(Bencode::Dict));
    let pairs = (parser(bencode_string), dict_contents);
    let mut dict = between(open, close, many(pairs)).map(|entries:Vec<(String, Bencode)>|{
        let mut hash_map = HashMap::new();
        for (k, v) in entries {
            hash_map.insert(k, v);
        }
        hash_map
    });
    dict.parse_state(input)
}

fn take <I> (num: i32) -> SizedBuffer<I> where I: Stream<Item=char> {
    SizedBuffer(num, PhantomData)
}

#[derive(Clone)]
pub struct SizedBuffer <I>(i32, PhantomData<I>);
impl <I> Parser for SizedBuffer<I> where I: Stream<Item=char> {
    type Input = I;
    type Output = String;
    fn parse_lazy(&mut self, mut input: State<I>) -> ParseResult<String, I> {
        let start = input.position;
        let mut vec_buf:Vec<char> = Vec::new();
        for _ in 0..self.0 {
            match input.uncons() {
                Ok((other, rest)) => {
                    vec_buf.push(other);
                    input = rest.into_inner();
                }
                Err(error) => {
                    return error.combine(|mut error| {
                        error.position = start;
                        Err(Consumed::Consumed(error))
                    })
                }
            };
        }
        Ok((vec_buf.into_iter().collect(), Consumed::Consumed(input)))
    }
}

fn main () {
    let file_contents = open_file("t-test.torrent");

    match str::from_utf8(&file_contents) {
        Ok(v) => println!("file: {}", v),
        Err(e) => panic!("Not a UTF-8 String: {}", e)
    };

    let result = parser(bencode_dict).parse("d3:abci4ee");
}

#[test]
fn test_integer() {
    let result = parser(bencode_integer).parse("i57e");
    assert_eq!(result, Ok((57,"")));
}

#[test]
fn test_string() {
    let result = parser(bencode_string).parse("5:abcde");
    assert_eq!(result, Ok(("abcde".to_string(), "")));;
}

#[test]
fn test_list() {
    let homogenous_int_list = parser(bencode_list).parse("li57ei32ee");
    assert_eq!(homogenous_int_list, Ok((vec![Bencode::Int(57), Bencode::Int(32)], "")));

    let homogenous_str_list = parser(bencode_list).parse("l3:abc5:defghe");
    assert_eq!(homogenous_str_list, Ok((vec![Bencode::String("abc".to_string()), Bencode::String("defgh".to_string())], "")));

    let hetero_list = parser(bencode_list).parse("li32e3:abce");
    assert_eq!(hetero_list, Ok((vec![Bencode::Int(32), Bencode::String("abc".to_string())], "")));
}

#[test]
fn test_dict() {

}
<|endoftext|>


<commit_before>use rss::ChannelBuilder;
use rss::Item;
use std::fs;

mod decoration;
mod markdown;
mod paths;
mod printing;

fn main() {
    printing::heading("Creating website build directory.");

    printing::subheading("Cleaning the build directory.");
    paths::remove_dir(&paths::build());

    printing::subheading("Generating the build directory.");
    paths::create_dir(&paths::build());
    generate_pages();
}

fn generate_pages() {
    let mut markdown_links_to_routes = Vec::new();
    let mut rss_items = Vec::new();

    match fs::read_dir(&paths::pages()) {
        Ok(markdown_files) => {
            for markdown_file in markdown_files {
                let markdown_file = match &markdown_file {
                    Ok(markdown_file) => markdown_file.path(),
                    Err(error) => panic!("There was a problem: {:?}", error),
                };

                let markdown_file_contents = match fs::read_to_string(&markdown_file) {
                    Ok(contents) => contents,
                    Err(error) => panic!("There was a problem: {:?}", error),
                };

                let route = &paths::file_stem(markdown_file);

                let mut lines = markdown_file_contents.lines();

                let title = match lines.next() {
                    Some(title) => title.replace("# ", ""),
                    None => panic!("Cannot find a title in {}.", &route),
                };

                match lines.next() {
                    Some(_) => (),
                    None => panic!(
                        "Cannot find a break between title and description in {}.",
                        &route
                    ),
                };

                let description = match lines.next() {
                    Some(description) => description.replace("_", "").replace(".", ""),
                    None => panic!("Cannot find a description in {}.", &route),
                };

                paths::create_dir(&paths::build().join(route));
                paths::create_file(
                    &paths::build().join(route).join("index.html"),
                    &markdown::to_html(&markdown_file_contents, &title, &format!("{}.", &description).to_string()),
                );

                let is_post = route != "about" && route != "resume" && route != "projects";

                if is_post {
                    markdown_links_to_routes.push(
                        format!("- [{}: {}](/{}/).", &title, &description, &route).to_string(),
                    );

                    let mut rss_item = Item::default();
                    rss_item.set_link(format!("https://trevordmiller.com/{}/", &route));
                    rss_item.set_title(title);
                    rss_item.set_description(format!("{}.", description));
                    rss_item.set_author("Trevor D. Miller".to_string());
                    rss_items.push(rss_item);
                }
            }
        }
        Err(error) => panic!("There was a problem: {:?}", error),
    };

    let markdown_index_contents = format!(
        "# Posts\n_My posts about software development._\n{}",
        markdown_links_to_routes.join("\n")
    );

    paths::create_file(
        &paths::build().join("index.html"),
        &markdown::to_html(
            &markdown_index_contents,
            "Posts",
            "My posts about software development.",
        ),
    );

    let channel = match ChannelBuilder::default()
        .language("en-us".to_string())
        .link("https://trevordmiller.com")
        .title("trevordmiller")
        .description("trevordmiller RSS feed.")
        .items(rss_items)
        .build()
    {
        Ok(channel) => channel.to_string(),
        Err(error) => panic!("There was a problem: {:?}", error),
    };

    paths::create_file(&paths::build().join("rss.xml"), &channel);
}
<commit_msg>Format<commit_after>use rss::ChannelBuilder;
use rss::Item;
use std::fs;

mod decoration;
mod markdown;
mod paths;
mod printing;

fn main() {
    printing::heading("Creating website build directory.");

    printing::subheading("Cleaning the build directory.");
    paths::remove_dir(&paths::build());

    printing::subheading("Generating the build directory.");
    paths::create_dir(&paths::build());
    generate_pages();
}

fn generate_pages() {
    let mut markdown_links_to_routes = Vec::new();
    let mut rss_items = Vec::new();

    match fs::read_dir(&paths::pages()) {
        Ok(markdown_files) => {
            for markdown_file in markdown_files {
                let markdown_file = match &markdown_file {
                    Ok(markdown_file) => markdown_file.path(),
                    Err(error) => panic!("There was a problem: {:?}", error),
                };

                let markdown_file_contents = match fs::read_to_string(&markdown_file) {
                    Ok(contents) => contents,
                    Err(error) => panic!("There was a problem: {:?}", error),
                };

                let route = &paths::file_stem(markdown_file);

                let mut lines = markdown_file_contents.lines();

                let title = match lines.next() {
                    Some(title) => title.replace("# ", ""),
                    None => panic!("Cannot find a title in {}.", &route),
                };

                match lines.next() {
                    Some(_) => (),
                    None => panic!(
                        "Cannot find a break between title and description in {}.",
                        &route
                    ),
                };

                let description = match lines.next() {
                    Some(description) => description.replace("_", "").replace(".", ""),
                    None => panic!("Cannot find a description in {}.", &route),
                };

                paths::create_dir(&paths::build().join(route));
                paths::create_file(
                    &paths::build().join(route).join("index.html"),
                    &markdown::to_html(
                        &markdown_file_contents,
                        &title,
                        &format!("{}.", &description).to_string(),
                    ),
                );

                let is_post = route != "about" && route != "resume" && route != "projects";

                if is_post {
                    markdown_links_to_routes.push(
                        format!("- [{}: {}](/{}/).", &title, &description, &route).to_string(),
                    );

                    let mut rss_item = Item::default();
                    rss_item.set_link(format!("https://trevordmiller.com/{}/", &route));
                    rss_item.set_title(title);
                    rss_item.set_description(format!("{}.", description));
                    rss_item.set_author("Trevor D. Miller".to_string());
                    rss_items.push(rss_item);
                }
            }
        }
        Err(error) => panic!("There was a problem: {:?}", error),
    };

    let markdown_index_contents = format!(
        "# Posts\n_My posts about software development._\n{}",
        markdown_links_to_routes.join("\n")
    );

    paths::create_file(
        &paths::build().join("index.html"),
        &markdown::to_html(
            &markdown_index_contents,
            "Posts",
            "My posts about software development.",
        ),
    );

    let channel = match ChannelBuilder::default()
        .language("en-us".to_string())
        .link("https://trevordmiller.com")
        .title("trevordmiller")
        .description("trevordmiller RSS feed.")
        .items(rss_items)
        .build()
    {
        Ok(channel) => channel.to_string(),
        Err(error) => panic!("There was a problem: {:?}", error),
    };

    paths::create_file(&paths::build().join("rss.xml"), &channel);
}
<|endoftext|>


<commit_before><commit_msg>fix doctests, note flgs for current stable compiler<commit_after><|endoftext|>


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

use dom::bindings::callback::ExceptionHandling::Report;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::FunctionBinding::Function;
use dom::bindings::reflector::Reflectable;
use dom::bindings::trace::JSTraceable;
use dom::window::ScriptHelpers;
use euclid::length::Length;
use heapsize::HeapSizeOf;
use ipc_channel::ipc::IpcSender;
use js::jsapi::{HandleValue, Heap, RootedValue};
use js::jsval::{JSVal, UndefinedValue};
use num::traits::Saturating;
use script_traits::{MsDuration, precise_time_ms};
use script_traits::{TimerEvent, TimerEventId, TimerEventRequest, TimerSource};
use std::cell::Cell;
use std::cmp::{self, Ord, Ordering};
use std::default::Default;
use std::rc::Rc;
use util::str::DOMString;

#[derive(JSTraceable, PartialEq, Eq, Copy, Clone, HeapSizeOf, Hash, PartialOrd, Ord, Debug)]
pub struct TimerHandle(i32);

#[derive(JSTraceable, HeapSizeOf)]
#[privatize]
pub struct ActiveTimers {
    #[ignore_heap_size_of = "Defined in std"]
    timer_event_chan: IpcSender<TimerEvent>,
    #[ignore_heap_size_of = "Defined in std"]
    scheduler_chan: IpcSender<TimerEventRequest>,
    next_timer_handle: Cell<TimerHandle>,
    timers: DOMRefCell<Vec<Timer>>,
    suspended_since: Cell<Option<MsDuration>>,
    /// Initially 0, increased whenever the associated document is reactivated
    /// by the amount of ms the document was inactive. The current time can be
    /// offset back by this amount for a coherent time across document
    /// activations.
    suspension_offset: Cell<MsDuration>,
    /// Calls to `fire_timer` with a different argument than this get ignored.
    /// They were previously scheduled and got invalidated when
    ///  - timers were suspended,
    ///  - the timer it was scheduled for got canceled or
    ///  - a timer was added with an earlier callback time. In this case the
    ///    original timer is rescheduled when it is the next one to get called.
    expected_event_id: Cell<TimerEventId>,
    /// The nesting level of the currently executing timer thread or 0.
    nesting_level: Cell<u32>,
}

// Holder for the various JS values associated with setTimeout
// (ie. function value to invoke and all arguments to pass
//      to the function when calling it)
// TODO: Handle rooting during fire_timer when movable GC is turned on
#[derive(JSTraceable, HeapSizeOf)]
#[privatize]
struct Timer {
    handle: TimerHandle,
    source: TimerSource,
    callback: InternalTimerCallback,
    is_interval: IsInterval,
    nesting_level: u32,
    duration: MsDuration,
    next_call: MsDuration,
}

// Enum allowing more descriptive values for the is_interval field
#[derive(JSTraceable, PartialEq, Copy, Clone, HeapSizeOf)]
pub enum IsInterval {
    Interval,
    NonInterval,
}

impl Ord for Timer {
    fn cmp(&self, other: &Timer) -> Ordering {
        match self.next_call.cmp(&other.next_call).reverse() {
            Ordering::Equal => self.handle.cmp(&other.handle).reverse(),
            res => res
        }
    }
}

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

impl Eq for Timer {}
impl PartialEq for Timer {
    fn eq(&self, other: &Timer) -> bool {
        self as *const Timer == other as *const Timer
    }
}

#[derive(Clone)]
pub enum TimerCallback {
    StringTimerCallback(DOMString),
    FunctionTimerCallback(Rc<Function>),
}

#[derive(JSTraceable, Clone)]
enum InternalTimerCallback {
    StringTimerCallback(DOMString),
    FunctionTimerCallback(Rc<Function>, Rc<Vec<Heap<JSVal>>>),
    InternalCallback(Box<ScheduledCallback>),
}

impl HeapSizeOf for InternalTimerCallback {
    fn heap_size_of_children(&self) -> usize {
        // FIXME: Rc<T> isn't HeapSizeOf and we can't ignore it due to #6870 and #6871
        0
    }
}

pub trait ScheduledCallback: JSTraceable + HeapSizeOf {
    fn invoke(self: Box<Self>);

    fn box_clone(&self) -> Box<ScheduledCallback>;
}

impl Clone for Box<ScheduledCallback> {
    fn clone(&self) -> Box<ScheduledCallback> {
        self.box_clone()
    }
}

impl ActiveTimers {
    pub fn new(timer_event_chan: IpcSender<TimerEvent>,
               scheduler_chan: IpcSender<TimerEventRequest>)
               -> ActiveTimers {
        ActiveTimers {
            timer_event_chan: timer_event_chan,
            scheduler_chan: scheduler_chan,
            next_timer_handle: Cell::new(TimerHandle(1)),
            timers: DOMRefCell::new(Vec::new()),
            suspended_since: Cell::new(None),
            suspension_offset: Cell::new(Length::new(0)),
            expected_event_id: Cell::new(TimerEventId(0)),
            nesting_level: Cell::new(0),
        }
    }

    // see https://html.spec.whatwg.org/multipage/#timer-initialisation-steps
    pub fn set_timeout_or_interval(&self,
                               callback: TimerCallback,
                               arguments: Vec<HandleValue>,
                               timeout: i32,
                               is_interval: IsInterval,
                               source: TimerSource)
                               -> i32 {
        let callback = match callback {
            TimerCallback::StringTimerCallback(code_str) =>
                InternalTimerCallback::StringTimerCallback(code_str),
            TimerCallback::FunctionTimerCallback(function) => {
                // This is a bit complicated, but this ensures that the vector's
                // buffer isn't reallocated (and moved) after setting the Heap values
                let mut args = Vec::with_capacity(arguments.len());
                for _ in 0..arguments.len() {
                    args.push(Heap::default());
                }
                for (i, item) in arguments.iter().enumerate() {
                    args.get_mut(i).unwrap().set(item.get());
                }
                InternalTimerCallback::FunctionTimerCallback(function, Rc::new(args))
            }
        };

        let timeout = cmp::max(0, timeout);
        // step 7
        let duration = self.clamp_duration(Length::new(timeout as u64));

        let TimerHandle(handle) = self.schedule_internal_callback(callback, duration, is_interval, source);
        handle
    }

    pub fn schedule_callback(&self,
                             callback: Box<ScheduledCallback>,
                             duration: MsDuration,
                             source: TimerSource) -> TimerHandle {
        self.schedule_internal_callback(InternalTimerCallback::InternalCallback(callback),
                                        duration,
                                        IsInterval::NonInterval,
                                        source)
    }

    // see https://html.spec.whatwg.org/multipage/#timer-initialisation-steps
    fn schedule_internal_callback(&self,
                                  callback: InternalTimerCallback,
                                  duration: MsDuration,
                                  is_interval: IsInterval,
                                  source: TimerSource) -> TimerHandle {
        // step 3
        let TimerHandle(new_handle) = self.next_timer_handle.get();
        self.next_timer_handle.set(TimerHandle(new_handle + 1));

        let next_call = self.base_time() + duration;

        let timer = Timer {
            handle: TimerHandle(new_handle),
            source: source,
            callback: callback,
            is_interval: is_interval,
            duration: duration,
            // step 6
            nesting_level: self.nesting_level.get() + 1,
            next_call: next_call,
        };

        self.insert_timer(timer);

        let TimerHandle(max_handle) = self.timers.borrow().last().unwrap().handle;
        if max_handle == new_handle {
            self.schedule_timer_call();
        }

        // step 10
        TimerHandle(new_handle)
    }

    pub fn clear_timeout_or_interval(&self, handle: i32) {
        self.unschedule_callback(TimerHandle(handle));
    }

    pub fn unschedule_callback(&self, handle: TimerHandle) {
        let was_next = self.is_next_timer(handle);

        self.timers.borrow_mut().retain(|t| t.handle != handle);

        if was_next {
            self.invalidate_expected_event_id();
            self.schedule_timer_call();
        }
    }

    // see https://html.spec.whatwg.org/multipage/#timer-initialisation-steps
    #[allow(unsafe_code)]
    pub fn fire_timer<T: Reflectable>(&self, id: TimerEventId, this: &T) {
        let expected_id = self.expected_event_id.get();
        if expected_id != id {
            debug!("ignoring timer fire event {:?} (expected {:?}", id, expected_id);
            return;
        }

        assert!(self.suspended_since.get().is_none());

        let base_time = self.base_time();

        // Since the event id was the expected one, at least one timer should be due.
        assert!(base_time >= self.timers.borrow().last().unwrap().next_call);

        // select timers to run to prevent firing timers
        // that were installed during fire of another timer
        let mut timers_to_run: Vec<Timer> = Vec::new();

        loop {
            let mut timers = self.timers.borrow_mut();

            if timers.is_empty() || timers.last().unwrap().next_call > base_time {
                break;
            }

            timers_to_run.push(timers.pop().unwrap());
        }

        for timer in timers_to_run {

            let callback = timer.callback.clone();

            // prep for step 6 in nested set_timeout_or_interval calls
            self.nesting_level.set(timer.nesting_level);

            // step 4.3
            if timer.is_interval == IsInterval::Interval {
                let mut timer = timer;

                // step 7
                timer.duration = self.clamp_duration(timer.duration);
                // step 8, 9
                timer.nesting_level += 1;
                timer.next_call = base_time + timer.duration;
                self.insert_timer(timer);
            }

            // step 14
            match callback {
                InternalTimerCallback::StringTimerCallback(code_str) => {
                    let cx = this.global().r().get_cx();
                    let mut rval = RootedValue::new(cx, UndefinedValue());

                    this.evaluate_js_on_global_with_result(&code_str, rval.handle_mut());
                },
                InternalTimerCallback::FunctionTimerCallback(function, arguments) => {
                    let arguments: Vec<JSVal> = arguments.iter().map(|arg| arg.get()).collect();
                    let arguments = arguments.iter().by_ref().map(|arg| unsafe {
                        HandleValue::from_marked_location(arg)
                    }).collect();

                    let _ = function.Call_(this, arguments, Report);
                },
                InternalTimerCallback::InternalCallback(callback) => {
                    callback.invoke();
                },
            };

            self.nesting_level.set(0);
        }

        self.schedule_timer_call();
    }

    fn insert_timer(&self, timer: Timer) {
        let mut timers = self.timers.borrow_mut();
        let insertion_index = timers.binary_search(&timer).err().unwrap();
        timers.insert(insertion_index, timer);
    }

    fn is_next_timer(&self, handle: TimerHandle) -> bool {
        match self.timers.borrow().last() {
            None => false,
            Some(ref max_timer) => max_timer.handle == handle
        }
    }

    fn schedule_timer_call(&self) {
        if self.suspended_since.get().is_some() {
            // The timer will be scheduled when the pipeline is thawed.
            return;
        }

        let timers = self.timers.borrow();

        if let Some(timer) = timers.last() {
            let expected_event_id = self.invalidate_expected_event_id();

            let delay = Length::new(timer.next_call.get().saturating_sub(precise_time_ms().get()));
            let request = TimerEventRequest(self.timer_event_chan.clone(), timer.source,
                                            expected_event_id, delay);
            self.scheduler_chan.send(request).unwrap();
        }
    }

    pub fn suspend(&self) {
        assert!(self.suspended_since.get().is_none());

        self.suspended_since.set(Some(precise_time_ms()));
        self.invalidate_expected_event_id();
    }

    pub fn resume(&self) {
        assert!(self.suspended_since.get().is_some());

        let additional_offset = match self.suspended_since.get() {
            Some(suspended_since) => precise_time_ms() - suspended_since,
            None => panic!("Timers are not suspended.")
        };

        self.suspension_offset.set(self.suspension_offset.get() + additional_offset);

        self.schedule_timer_call();
    }

    fn base_time(&self) -> MsDuration {
        let offset = self.suspension_offset.get();

        match self.suspended_since.get() {
            Some(time) => time - offset,
            None => precise_time_ms() - offset,
        }
    }

    // see step 7 of https://html.spec.whatwg.org/multipage/#timer-initialisation-steps
    fn clamp_duration(&self, unclamped: MsDuration) -> MsDuration {
        let ms = if self.nesting_level.get() > 5 {
            4
        } else {
            0
        };

        cmp::max(Length::new(ms), unclamped)
    }

    fn invalidate_expected_event_id(&self) -> TimerEventId {
        let TimerEventId(currently_expected) = self.expected_event_id.get();
        let next_id = TimerEventId(currently_expected + 1);
        debug!("invalidating expected timer (was {:?}, now {:?}", currently_expected, next_id);
        self.expected_event_id.set(next_id);
        next_id
    }
}
<commit_msg>Auto merge of #9471 - peterkort:patch-1, r=jdm<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/. */

use dom::bindings::callback::ExceptionHandling::Report;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::FunctionBinding::Function;
use dom::bindings::reflector::Reflectable;
use dom::bindings::trace::JSTraceable;
use dom::window::ScriptHelpers;
use euclid::length::Length;
use heapsize::HeapSizeOf;
use ipc_channel::ipc::IpcSender;
use js::jsapi::{HandleValue, Heap, RootedValue};
use js::jsval::{JSVal, UndefinedValue};
use num::traits::Saturating;
use script_traits::{MsDuration, precise_time_ms};
use script_traits::{TimerEvent, TimerEventId, TimerEventRequest, TimerSource};
use std::cell::Cell;
use std::cmp::{self, Ord, Ordering};
use std::default::Default;
use std::rc::Rc;
use util::str::DOMString;

#[derive(JSTraceable, PartialEq, Eq, Copy, Clone, HeapSizeOf, Hash, PartialOrd, Ord, Debug)]
pub struct TimerHandle(i32);

#[derive(JSTraceable, HeapSizeOf)]
#[privatize]
pub struct ActiveTimers {
    #[ignore_heap_size_of = "Defined in std"]
    timer_event_chan: IpcSender<TimerEvent>,
    #[ignore_heap_size_of = "Defined in std"]
    scheduler_chan: IpcSender<TimerEventRequest>,
    next_timer_handle: Cell<TimerHandle>,
    timers: DOMRefCell<Vec<Timer>>,
    suspended_since: Cell<Option<MsDuration>>,
    /// Initially 0, increased whenever the associated document is reactivated
    /// by the amount of ms the document was inactive. The current time can be
    /// offset back by this amount for a coherent time across document
    /// activations.
    suspension_offset: Cell<MsDuration>,
    /// Calls to `fire_timer` with a different argument than this get ignored.
    /// They were previously scheduled and got invalidated when
    ///  - timers were suspended,
    ///  - the timer it was scheduled for got canceled or
    ///  - a timer was added with an earlier callback time. In this case the
    ///    original timer is rescheduled when it is the next one to get called.
    expected_event_id: Cell<TimerEventId>,
    /// The nesting level of the currently executing timer thread or 0.
    nesting_level: Cell<u32>,
}

// Holder for the various JS values associated with setTimeout
// (ie. function value to invoke and all arguments to pass
//      to the function when calling it)
// TODO: Handle rooting during fire_timer when movable GC is turned on
#[derive(JSTraceable, HeapSizeOf)]
#[privatize]
struct Timer {
    handle: TimerHandle,
    source: TimerSource,
    callback: InternalTimerCallback,
    is_interval: IsInterval,
    nesting_level: u32,
    duration: MsDuration,
    next_call: MsDuration,
}

// Enum allowing more descriptive values for the is_interval field
#[derive(JSTraceable, PartialEq, Copy, Clone, HeapSizeOf)]
pub enum IsInterval {
    Interval,
    NonInterval,
}

impl Ord for Timer {
    fn cmp(&self, other: &Timer) -> Ordering {
        match self.next_call.cmp(&other.next_call).reverse() {
            Ordering::Equal => self.handle.cmp(&other.handle).reverse(),
            res => res
        }
    }
}

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

impl Eq for Timer {}
impl PartialEq for Timer {
    fn eq(&self, other: &Timer) -> bool {
        self as *const Timer == other as *const Timer
    }
}

#[derive(Clone)]
pub enum TimerCallback {
    StringTimerCallback(DOMString),
    FunctionTimerCallback(Rc<Function>),
}

#[derive(JSTraceable, Clone)]
enum InternalTimerCallback {
    StringTimerCallback(DOMString),
    FunctionTimerCallback(Rc<Function>, Rc<Vec<Heap<JSVal>>>),
    InternalCallback(Box<ScheduledCallback>),
}

impl HeapSizeOf for InternalTimerCallback {
    fn heap_size_of_children(&self) -> usize {
        // FIXME: Rc<T> isn't HeapSizeOf and we can't ignore it due to #6870 and #6871
        0
    }
}

pub trait ScheduledCallback: JSTraceable + HeapSizeOf {
    fn invoke(self: Box<Self>);

    fn box_clone(&self) -> Box<ScheduledCallback>;
}

impl Clone for Box<ScheduledCallback> {
    fn clone(&self) -> Box<ScheduledCallback> {
        self.box_clone()
    }
}

impl ActiveTimers {
    pub fn new(timer_event_chan: IpcSender<TimerEvent>,
               scheduler_chan: IpcSender<TimerEventRequest>)
               -> ActiveTimers {
        ActiveTimers {
            timer_event_chan: timer_event_chan,
            scheduler_chan: scheduler_chan,
            next_timer_handle: Cell::new(TimerHandle(1)),
            timers: DOMRefCell::new(Vec::new()),
            suspended_since: Cell::new(None),
            suspension_offset: Cell::new(Length::new(0)),
            expected_event_id: Cell::new(TimerEventId(0)),
            nesting_level: Cell::new(0),
        }
    }

    // see https://html.spec.whatwg.org/multipage/#timer-initialisation-steps
    pub fn set_timeout_or_interval(&self,
                               callback: TimerCallback,
                               arguments: Vec<HandleValue>,
                               timeout: i32,
                               is_interval: IsInterval,
                               source: TimerSource)
                               -> i32 {
        let callback = match callback {
            TimerCallback::StringTimerCallback(code_str) =>
                InternalTimerCallback::StringTimerCallback(code_str),
            TimerCallback::FunctionTimerCallback(function) => {
                // This is a bit complicated, but this ensures that the vector's
                // buffer isn't reallocated (and moved) after setting the Heap values
                let mut args = Vec::with_capacity(arguments.len());
                for _ in 0..arguments.len() {
                    args.push(Heap::default());
                }
                for (i, item) in arguments.iter().enumerate() {
                    args.get_mut(i).unwrap().set(item.get());
                }
                InternalTimerCallback::FunctionTimerCallback(function, Rc::new(args))
            }
        };

        let timeout = cmp::max(0, timeout);
        // step 7
        let duration = self.clamp_duration(Length::new(timeout as u64));

        let TimerHandle(handle) = self.schedule_internal_callback(callback, duration, is_interval, source);
        handle
    }

    pub fn schedule_callback(&self,
                             callback: Box<ScheduledCallback>,
                             duration: MsDuration,
                             source: TimerSource) -> TimerHandle {
        self.schedule_internal_callback(InternalTimerCallback::InternalCallback(callback),
                                        duration,
                                        IsInterval::NonInterval,
                                        source)
    }

    // see https://html.spec.whatwg.org/multipage/#timer-initialisation-steps
    fn schedule_internal_callback(&self,
                                  callback: InternalTimerCallback,
                                  duration: MsDuration,
                                  is_interval: IsInterval,
                                  source: TimerSource) -> TimerHandle {
        // step 3
        let TimerHandle(new_handle) = self.next_timer_handle.get();
        self.next_timer_handle.set(TimerHandle(new_handle + 1));

        let next_call = self.base_time() + duration;

        let timer = Timer {
            handle: TimerHandle(new_handle),
            source: source,
            callback: callback,
            is_interval: is_interval,
            duration: duration,
            // step 6
            nesting_level: self.nesting_level.get() + 1,
            next_call: next_call,
        };

        self.insert_timer(timer);

        let TimerHandle(max_handle) = self.timers.borrow().last().unwrap().handle;
        if max_handle == new_handle {
            self.schedule_timer_call();
        }

        // step 10
        TimerHandle(new_handle)
    }

    pub fn clear_timeout_or_interval(&self, handle: i32) {
        self.unschedule_callback(TimerHandle(handle));
    }

    pub fn unschedule_callback(&self, handle: TimerHandle) {
        let was_next = self.is_next_timer(handle);

        self.timers.borrow_mut().retain(|t| t.handle != handle);

        if was_next {
            self.invalidate_expected_event_id();
            self.schedule_timer_call();
        }
    }

    // see https://html.spec.whatwg.org/multipage/#timer-initialisation-steps
    #[allow(unsafe_code)]
    pub fn fire_timer<T: Reflectable>(&self, id: TimerEventId, this: &T) {
        let expected_id = self.expected_event_id.get();
        if expected_id != id {
            debug!("ignoring timer fire event {:?} (expected {:?}", id, expected_id);
            return;
        }

        assert!(self.suspended_since.get().is_none());

        let base_time = self.base_time();

        // Since the event id was the expected one, at least one timer should be due.
        assert!(base_time >= self.timers.borrow().last().unwrap().next_call);

        // select timers to run to prevent firing timers
        // that were installed during fire of another timer
        let mut timers_to_run: Vec<Timer> = Vec::new();

        loop {
            let mut timers = self.timers.borrow_mut();

            if timers.is_empty() || timers.last().unwrap().next_call > base_time {
                break;
            }

            timers_to_run.push(timers.pop().unwrap());
        }

        for timer in timers_to_run {

            let callback = timer.callback.clone();

            // prep for step 6 in nested set_timeout_or_interval calls
            self.nesting_level.set(timer.nesting_level);

            // step 4.3
            if timer.is_interval == IsInterval::Interval {
                let mut timer = timer;

                // step 7
                timer.duration = self.clamp_duration(timer.duration);
                // step 8, 9
                timer.nesting_level += 1;
                timer.next_call = base_time + timer.duration;
                self.insert_timer(timer);
            }

            // step 14
            match callback {
                InternalTimerCallback::StringTimerCallback(code_str) => {
                    let cx = this.global().r().get_cx();
                    let mut rval = RootedValue::new(cx, UndefinedValue());

                    this.evaluate_js_on_global_with_result(&code_str, rval.handle_mut());
                },
                InternalTimerCallback::FunctionTimerCallback(function, arguments) => {
                    let arguments: Vec<JSVal> = arguments.iter().map(|arg| arg.get()).collect();
                    let arguments = arguments.iter().by_ref().map(|arg| unsafe {
                        HandleValue::from_marked_location(arg)
                    }).collect();

                    let _ = function.Call_(this, arguments, Report);
                },
                InternalTimerCallback::InternalCallback(callback) => {
                    callback.invoke();
                },
            };

            self.nesting_level.set(0);
        }

        self.schedule_timer_call();
    }

    fn insert_timer(&self, timer: Timer) {
        let mut timers = self.timers.borrow_mut();
        let insertion_index = timers.binary_search(&timer).err().unwrap();
        timers.insert(insertion_index, timer);
    }

    fn is_next_timer(&self, handle: TimerHandle) -> bool {
        match self.timers.borrow().last() {
            None => false,
            Some(ref max_timer) => max_timer.handle == handle
        }
    }

    fn schedule_timer_call(&self) {
        if self.suspended_since.get().is_some() {
            // The timer will be scheduled when the pipeline is thawed.
            return;
        }

        let timers = self.timers.borrow();

        if let Some(timer) = timers.last() {
            let expected_event_id = self.invalidate_expected_event_id();

            let delay = Length::new(timer.next_call.get().saturating_sub(precise_time_ms().get()));
            let request = TimerEventRequest(self.timer_event_chan.clone(), timer.source,
                                            expected_event_id, delay);
            self.scheduler_chan.send(request).unwrap();
        }
    }

    pub fn suspend(&self) {
        assert!(self.suspended_since.get().is_none());

        self.suspended_since.set(Some(precise_time_ms()));
        self.invalidate_expected_event_id();
    }

    pub fn resume(&self) {
        assert!(self.suspended_since.get().is_some());

        let additional_offset = match self.suspended_since.get() {
            Some(suspended_since) => precise_time_ms() - suspended_since,
            None => panic!("Timers are not suspended.")
        };

        self.suspension_offset.set(self.suspension_offset.get() + additional_offset);
        self.suspended_since.set(None);

        self.schedule_timer_call();
    }

    fn base_time(&self) -> MsDuration {
        let offset = self.suspension_offset.get();

        match self.suspended_since.get() {
            Some(time) => time - offset,
            None => precise_time_ms() - offset,
        }
    }

    // see step 7 of https://html.spec.whatwg.org/multipage/#timer-initialisation-steps
    fn clamp_duration(&self, unclamped: MsDuration) -> MsDuration {
        let ms = if self.nesting_level.get() > 5 {
            4
        } else {
            0
        };

        cmp::max(Length::new(ms), unclamped)
    }

    fn invalidate_expected_event_id(&self) -> TimerEventId {
        let TimerEventId(currently_expected) = self.expected_event_id.get();
        let next_id = TimerEventId(currently_expected + 1);
        debug!("invalidating expected timer (was {:?}, now {:?}", currently_expected, next_id);
        self.expected_event_id.set(next_id);
        next_id
    }
}
<|endoftext|>


<commit_before>
extern crate rand;

extern crate intmap;

use intmap::IntMap;

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

    fn get_random_range(count: usize) -> Vec<u64> {
        use rand::{Rng, SeedableRng, StdRng};

        let mut vec = Vec::new();

        let seed: &[_] = &[4, 2, 4, 2];
        let mut rng: StdRng = SeedableRng::from_seed(seed);

        for _ in 0..count {
            vec.push(rng.gen::<u64>());
        }

        vec.sort();
        vec.dedup();

        vec
    }

    #[test]
    fn intmap_get_insert_impl() {
        let count = 20_000;
        let data = get_random_range(count as usize);
        let mut map: IntMap<u64> = IntMap::new();

        println!("");
        println!("Starting test");

        for s in data.iter() {
            assert!(map.insert(*s, *s), "intmap insert failed! ix: {:?}", s);
        }

        assert_eq!(map.len(), count);
        assert!(map.assert_count());

        for s in data.iter() {
            assert_eq!(*map.get(*s).unwrap(), *s, "intmap get failed! key: {:?}", s);
        }

        assert_eq!(map.len(), count);

        for s in data.iter() {
            assert!(map.contains_key(*s), "intmap contains_key failed! key: {:?}", s);
        }

        assert_eq!(map.len(), count);

        for s in data.iter() {
            let val = map.remove(*s).unwrap();
            assert_eq!(val, *s, "intmap remove failed! key: {:?}", s);
        }

        assert_eq!(map.len(), 0);
        assert!(map.assert_count());
    }

    #[test]
    fn add_string() {
        let mut map = IntMap::new();

        for i in 0..20_000 {
            map.insert(i, format!("item: {:?}", i));
        }
    }

    #[test]
    fn single_add_get() {
        let mut map: IntMap<u64> = IntMap::new();
        map.insert(21, 42);
        let val = map.get(21);
        assert!(val.is_some());
        assert_eq!(*val.unwrap(), 42);
    }

    #[test]
    fn map_iter() {
        let count = 20_000;
        let mut map: IntMap<u64> = IntMap::new();

        for i in 0..count {
            map.insert(i, i);
        }

        for (k, v) in map.iter() {
            assert_eq!(*k, *v);
        }
    }

    #[test]
    fn map_iter_keys() {
        let count = 20_000;
        let data: Vec<_> = (0..count).collect();
        let mut map: IntMap<u64> = IntMap::new();

        for i in 0..count {
            map.insert(i, i);
        }

        for k in map.keys() {
            assert_eq!(*k, data[*k as usize]);
        }
    }

    #[test]
    fn map_iter_values() {
        let count = 20_000;
        let data: Vec<_> = (0..count).collect();
        let mut map: IntMap<u64> = IntMap::new();

        for i in 0..count {
            map.insert(i, i);
        }

        for v in map.values() {
            assert_eq!(*v, data[*v as usize]);
        }
    }

    #[test]
    fn map_mut_iter_values() {
        let count = 20_000;
        let mut map: IntMap<u64> = IntMap::new();

        for i in 0..count {
            map.insert(i, i);
        }

        for kv in map.iter_mut() {
            *kv.1 += 1;
        }

        for n in 0..count {
            assert_eq!(n+1, *map.get(n).expect("Failed to get number!"));
        }

    }
}
<commit_msg>Added test for iter on empty map<commit_after>
extern crate rand;

extern crate intmap;

use intmap::IntMap;

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

    fn get_random_range(count: usize) -> Vec<u64> {
        use rand::{Rng, SeedableRng, StdRng};

        let mut vec = Vec::new();

        let seed: &[_] = &[4, 2, 4, 2];
        let mut rng: StdRng = SeedableRng::from_seed(seed);

        for _ in 0..count {
            vec.push(rng.gen::<u64>());
        }

        vec.sort();
        vec.dedup();

        vec
    }

    #[test]
    fn intmap_get_insert_impl() {
        let count = 20_000;
        let data = get_random_range(count as usize);
        let mut map: IntMap<u64> = IntMap::new();

        println!("");
        println!("Starting test");

        for s in data.iter() {
            assert!(map.insert(*s, *s), "intmap insert failed! ix: {:?}", s);
        }

        assert_eq!(map.len(), count);
        assert!(map.assert_count());

        for s in data.iter() {
            assert_eq!(*map.get(*s).unwrap(), *s, "intmap get failed! key: {:?}", s);
        }

        assert_eq!(map.len(), count);

        for s in data.iter() {
            assert!(map.contains_key(*s), "intmap contains_key failed! key: {:?}", s);
        }

        assert_eq!(map.len(), count);

        for s in data.iter() {
            let val = map.remove(*s).unwrap();
            assert_eq!(val, *s, "intmap remove failed! key: {:?}", s);
        }

        assert_eq!(map.len(), 0);
        assert!(map.assert_count());
    }

    #[test]
    fn add_string() {
        let mut map = IntMap::new();

        for i in 0..20_000 {
            map.insert(i, format!("item: {:?}", i));
        }
    }

    #[test]
    fn single_add_get() {
        let mut map: IntMap<u64> = IntMap::new();
        map.insert(21, 42);
        let val = map.get(21);
        assert!(val.is_some());
        assert_eq!(*val.unwrap(), 42);
    }

    #[test]
    fn map_iter() {
        let count = 20_000;
        let mut map: IntMap<u64> = IntMap::new();

        for i in 0..count {
            map.insert(i, i);
        }

        for (k, v) in map.iter() {
            assert_eq!(*k, *v);
        }
    }

    #[test]
    fn map_iter_keys() {
        let count = 20_000;
        let data: Vec<_> = (0..count).collect();
        let mut map: IntMap<u64> = IntMap::new();

        for i in 0..count {
            map.insert(i, i);
        }

        for k in map.keys() {
            assert_eq!(*k, data[*k as usize]);
        }
    }

    #[test]
    fn map_iter_values() {
        let count = 20_000;
        let data: Vec<_> = (0..count).collect();
        let mut map: IntMap<u64> = IntMap::new();

        for i in 0..count {
            map.insert(i, i);
        }

        for v in map.values() {
            assert_eq!(*v, data[*v as usize]);
        }
    }

    #[test]
    fn map_mut_iter() {
        let count = 20_000;
        let mut map: IntMap<u64> = IntMap::new();

        for i in 0..count {
            map.insert(i, i);
        }

        for kv in map.iter_mut() {
            *kv.1 += 1;
        }

        for n in 0..count {
            assert_eq!(n+1, *map.get(n).expect("Failed to get number!"));
        }

    }

    #[test]
    fn map_iter_empty() {
        let mut map: IntMap<u64> = IntMap::new();

        for kv in map.iter_mut() {
            *kv.1 += 1;
        }
    }

    #[test]
    fn map_mut_iter_empty() {
        let mut map: IntMap<u64> = IntMap::new();

        for kv in map.iter_mut() {
            *kv.1 += 1;
        }
    }
}
<|endoftext|>


<commit_before>//! Rusty types for manipulating FFTW

use bitflags::bitflags;
pub use ffi::fftw_complex as c64;
pub use ffi::fftwf_complex as c32;

/// Expose the kinds of real-to-real transformations
pub use ffi::fftw_r2r_kind as R2RKind;

/// Direction of Complex-to-Complex transformation
#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Sign {
    Forward = -1,
    Backward = 1,
}

impl ::std::ops::Neg for Sign {
    type Output = Sign;
    fn neg(self) -> Self::Output {
        match self {
            Sign::Forward => Sign::Backward,
            Sign::Backward => Sign::Forward,
        }
    }
}

/// Flags for creating plans and wisdom
///
/// This will be the most important part for fast FFT.
/// You should see the [Words of Wisdom] in the original document
///
/// [Words of Wisdom]: http://www.fftw.org/fftw3_doc/Words-of-Wisdom_002dSaving-Plans.html
bitflags! {
    #[derive(Default)]
    pub struct Flag: u32 {
        #[allow(non_upper_case_globals)] // FIXME for compatibility
        const Measure = 0;
        #[allow(non_upper_case_globals)] // FIXME for compatibility
        const DestroyInput = 1 ;
        #[allow(non_upper_case_globals)] // FIXME for compatibility
        const Unaligned = 1 << 1;
        #[allow(non_upper_case_globals)] // FIXME for compatibility
        const ConserveMemory = 1 << 2;
        #[allow(non_upper_case_globals)] // FIXME for compatibility
        const Exhausive = 1 << 3;
        #[allow(non_upper_case_globals)] // FIXME for compatibility
        const PreserveInput = 1 << 4;
        #[allow(non_upper_case_globals)] // FIXME for compatibility
        const Patient = 1 << 5;
        #[allow(non_upper_case_globals)] // FIXME for compatibility
        const Estimate = 1 << 6;
        #[allow(non_upper_case_globals)] // FIXME for compatibility
        const WisdowmOnly = 1 << 21;
    }
}
<commit_msg>Use upper case for flags<commit_after>//! Rusty types for manipulating FFTW

use bitflags::bitflags;
pub use ffi::fftw_complex as c64;
pub use ffi::fftwf_complex as c32;

/// Expose the kinds of real-to-real transformations
pub use ffi::fftw_r2r_kind as R2RKind;

/// Direction of Complex-to-Complex transformation
#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Sign {
    Forward = -1,
    Backward = 1,
}

impl ::std::ops::Neg for Sign {
    type Output = Sign;
    fn neg(self) -> Self::Output {
        match self {
            Sign::Forward => Sign::Backward,
            Sign::Backward => Sign::Forward,
        }
    }
}

bitflags! {
    /// Flags for creating plans and wisdom
    ///
    /// This will be the most important part for fast FFT.
    /// You should see the [Words of Wisdom] in the original document
    ///
    /// [Words of Wisdom]: http://www.fftw.org/fftw3_doc/Words-of-Wisdom_002dSaving-Plans.html
    #[derive(Default)]
    pub struct Flag: u32 {
        const MEASURE = 0;
        const DESTROYINPUT = 1 ;
        const UNALIGNED = 1 << 1;
        const CONSERVEMEMORY = 1 << 2;
        const EXHAUSIVE = 1 << 3;
        const PRESERVEINPUT = 1 << 4;
        const PATIENT = 1 << 5;
        const ESTIMATE = 1 << 6;
        const WISDOWMONLY = 1 << 21;
    }
}
<|endoftext|>


<commit_before>use fftw::plan::*;
use fftw::types::*;
use num_traits::Zero;

/// Check successive forward and backward transform equals to the identity
#[test]
fn c2c2c_identity() {
    let n = 32;
    let mut a = vec![c64::zero(); n];
    let mut b = vec![c64::zero(); n];
    let mut plan: C2CPlan64 =
        C2CPlan::new(&[n], &mut a, &mut b, Sign::Forward, Flag::MEASURE).unwrap();
    for i in 0..n {
        a[i] = c64::new(1.0, 0.0);
    }
    plan.c2c(&mut a, &mut b).unwrap();
    plan.c2c(&mut b, &mut a).unwrap();
    for v in a.iter() {
        let ans = c64::new(n as f64, 0.0);
        let dif = (v - ans).norm();
        if dif > 1e-7 {
            panic!("Large difference: v={}, dif={}", v, dif);
        }
    }
}

/// Check cos transform
#[test]
fn c2c_cos() {
    let n = 32;
    let mut a = vec![c64::zero(); n];
    let mut b = vec![c64::zero(); n];
    let mut plan: C2CPlan64 =
        C2CPlan::new(&[n], &mut a, &mut b, Sign::Forward, Flag::MEASURE).unwrap();
    let pi = ::std::f64::consts::PI;
    for i in 0..n {
        a[i] = c64::new((2.0 * pi * i as f64 / n as f64).cos(), 0.0);
    }
    plan.c2c(&mut a, &mut b).unwrap();
    for (i, v) in b.iter().enumerate() {
        let ans = if i == 1 || i == n - 1 {
            0.5 * n as f64
        } else {
            0.0
        };
        let dif = (v - ans).norm();
        if dif > 1e-7 {
            panic!(
                "Large difference: v={}, ans={}, dif={}, i={}",
                v, ans, dif, i
            );
        }
    }
}
<commit_msg>Fix c2c2c_identity test<commit_after>use fftw::plan::*;
use fftw::types::*;
use num_traits::Zero;

/// Check successive forward and backward transform equals to the identity
#[test]
fn c2c2c_identity() {
    let n = 32;
    let mut a = vec![c64::zero(); n];
    let mut b = vec![c64::zero(); n];

    let mut plan_ab: C2CPlan64 =
        C2CPlan::new(&[n], &mut a, &mut b, Sign::Forward, Flag::MEASURE).unwrap();
    let mut plan_ba: C2CPlan64 =
        C2CPlan::new(&[n], &mut b, &mut a, Sign::Forward, Flag::MEASURE).unwrap();

    for i in 0..n {
        a[i] = c64::new(1.0, 0.0);
    }

    plan_ab.c2c(&mut a, &mut b).unwrap();
    plan_ba.c2c(&mut b, &mut a).unwrap();
    for v in a.iter() {
        let ans = c64::new(n as f64, 0.0);
        let dif = (v - ans).norm();
        if dif > 1e-7 {
            panic!("Large difference: v={}, dif={}", v, dif);
        }
    }
}

/// Check cos transform
#[test]
fn c2c_cos() {
    let n = 32;
    let mut a = vec![c64::zero(); n];
    let mut b = vec![c64::zero(); n];
    let mut plan: C2CPlan64 =
        C2CPlan::new(&[n], &mut a, &mut b, Sign::Forward, Flag::MEASURE).unwrap();
    let pi = ::std::f64::consts::PI;
    for i in 0..n {
        a[i] = c64::new((2.0 * pi * i as f64 / n as f64).cos(), 0.0);
    }
    plan.c2c(&mut a, &mut b).unwrap();
    for (i, v) in b.iter().enumerate() {
        let ans = if i == 1 || i == n - 1 {
            0.5 * n as f64
        } else {
            0.0
        };
        let dif = (v - ans).norm();
        if dif > 1e-7 {
            panic!(
                "Large difference: v={}, ans={}, dif={}, i={}",
                v, ans, dif, i
            );
        }
    }
}
<|endoftext|>


<commit_before>//! Functions for interacting with browser processes.

use std::process::{Command, Child, Stdio};
use std::io::Result;

use url::Url;

/// Opens a browser window at the specified URL in a new process.
///
/// Returns an `io::Result` containing the child process.
///
/// This function uses platform-specific utilities to determine the user's default browser. The
/// following platforms are supported:
///
/// | Platform | Program    |
/// | -------- | ---------- |
/// | Linux    | `xdg-open` |
/// | OS X     | `open`     |
/// | Windows  | `start`    |
///
/// # Panics
/// Panics if called on an unsupported operating system.
pub fn open(url: &str) -> Result<Child> {
    let (browser, args) = if cfg!(target_os = "linux") {
        ("xdg-open", None)
    } else if cfg!(target_os = "macos") {
        ("open", Some(vec!["-g"]))
    } else if cfg!(target_os = "windows") {
        // `start` requires an empty string as its first parameter.
        ("start", Some(vec![""]))
    } else {
        panic!("unsupported OS")
    };
    open_specific(url, &browser, args)
}

/// Opens a specified browser in a new process.
///
/// The browser will be called with any supplied arguments in addition to the URL as an additional
/// argument.
///
/// Returns an `io::Result` containing the child process.
pub fn open_specific(url: &str, browser: &str, browser_args: Option<Vec<&str>>) -> Result<Child> {
    let url = Url::parse(url).unwrap();
    debug!("starting process '{:?}' with url {:?}", browser, url);

    Command::new(browser)
            .arg(url.to_string())
            .args(&browser_args.unwrap_or(Vec::new()))
            .stdout(Stdio::null())
            .stderr(Stdio::null())
            .spawn()
}
<commit_msg>use more idiomatic arguments for open<commit_after>//! Functions for interacting with browser processes.

use std::process::{Command, Child, Stdio};
use std::io::Result;

use url::Url;

/// Opens a browser window at the specified URL in a new process.
///
/// Returns an `io::Result` containing the child process.
///
/// This function uses platform-specific utilities to determine the user's default browser. The
/// following platforms are supported:
///
/// | Platform | Program    |
/// | -------- | ---------- |
/// | Linux    | `xdg-open` |
/// | OS X     | `open -g   |
/// | Windows  | `start`    |
///
/// # Panics
/// Panics if called on an unsupported operating system.
pub fn open(url: &str) -> Result<Child> {
    let (browser, args) = if cfg!(target_os = "linux") {
        ("xdg-open", vec![])
    } else if cfg!(target_os = "macos") {
        ("open", vec!["-g"])
    } else if cfg!(target_os = "windows") {
        // `start` requires an empty string as its first parameter.
        ("start", vec![""])
    } else {
        panic!("unsupported OS")
    };
    open_specific(url, &browser, &args)
}

/// Opens a specified browser in a new process.
///
/// The browser will be called with any supplied arguments in addition to the URL as an additional
/// argument.
///
/// Returns an `io::Result` containing the child process.
pub fn open_specific(url: &str, browser: &str, browser_args: &[&str]) -> Result<Child> {
    let url = Url::parse(url).unwrap();
    debug!("starting process '{:?}' with url {:?}", browser, url);

    Command::new(browser)
            .args(browser_args)
            .arg(url.to_string())
            .stdout(Stdio::null())
            .stderr(Stdio::null())
            .spawn()
}
<|endoftext|>