<commit_before>//! A simple timer, used to enqueue operations meant to be executed at
//! a given time or after a given delay.

extern crate chrono;

use std::cmp::Ordering;
use std::thread;
use std::sync::{Arc, Mutex, Condvar};
use std::sync::mpsc::{channel, Sender};
use std::collections::BinaryHeap;

use chrono::{Duration, DateTime, UTC};

/// An item scheduled for delayed execution.
struct Schedule {
    /// The instant at which to execute.
    date: DateTime<UTC>,

    /// The callback to execute.
    cb: Box<Fn() + Send>
}
impl Ord for Schedule {
    fn cmp(&self, other: &Self) -> Ordering {
        self.date.cmp(&other.date).reverse()
    }
}
impl PartialOrd for Schedule {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.date.partial_cmp(&other.date).map(|ord| ord.reverse())
    }
}
impl Eq for Schedule {
}
impl PartialEq for Schedule {
    fn eq(&self, other: &Self) -> bool {
        self.date.eq(&other.date)
    }
}

/// An operation to be sent across threads.
enum Op {
    /// Schedule a new item for execution.
    Schedule(Schedule),

    /// Stop the thread.
    Stop
}

/// A timer, used to schedule execution of callbacks at a later date.
///
/// In the current implementation, each timer is executed as two
/// threads. The _Scheduler_ thread is in charge of maintaining the
/// queue of callbacks to execute and of actually executing them. The
/// _Communication_ thread is in charge of communicating with the
/// _Scheduler_ thread (which requires acquiring a possibly-long-held
/// Mutex) without blocking the caller thread.
pub struct Timer {
    tx: Sender<Op>
}

impl Drop for Timer {
    fn drop(&mut self) {
        self.tx.send(Op::Stop).unwrap();
    }
}

impl Timer {
    /// Create a timer.
    ///
    /// This immediatey launches two threads, which will remain
    /// launched until the timer is dropped. As expected, the threads
    /// spend most of their life waiting for instructions.
    pub fn new() -> Self {
        Self::with_capacity(32)
    }

    /// As `new()`, but with a manually specified initial capaicty.
    pub fn with_capacity(capacity: usize) -> Self {
        let waiter_rcv = Arc::new((Mutex::new(Vec::with_capacity(capacity)), Condvar::new()));
        let waiter_snd = waiter_rcv.clone();

        // Spawn a first thread, whose sole role is to dispatch
        // messages to the second thread without having to wait too
        // long for the mutex.
        let (tx, rx) = channel();
        thread::spawn(move || {
            use Op::*;
            for msg in rx.iter() {
                let (ref mutex, ref condvar) = *waiter_snd;
                let mut vec = mutex.lock().unwrap();
                match msg {
                    Schedule(sched) => {
                        vec.push(Schedule(sched));
                        condvar.notify_one();
                    }
                    Stop => {
                        vec.clear();
                        vec.push(Op::Stop);
                        condvar.notify_one();
                        return;
                    }
                }
            }
        });

        // Spawn a second thread, in charge of scheduling.
        let mut heap = BinaryHeap::with_capacity(capacity);
        thread::Builder::new().name("Timer thread".to_owned()).spawn(move || {
            let (ref mutex, ref condvar) = *waiter_rcv;
            loop {
                let mut lock = mutex.lock().unwrap();

                // Pop all messages.
                for msg in lock.drain(..) {
                    match msg {
                        Op::Stop => return,
                        Op::Schedule(sched) => heap.push(sched),
                    }
                }

                // Pop all the callbacks that are ready.
                let mut delay = None;
                loop {
                    let now = UTC::now();
                    if let Some(sched) = heap.peek() {
                        if sched.date > now {
                            // First item is not ready yet, so nothing is ready.
                            // We assume that `sched.date > now` is still true.
                            delay = Some(sched.date - now);
                            break;
                        }
                    } else {
                        // No item at all.
                        break;
                    }
                    let sched = heap.pop().unwrap(); // We just checked that the heap is not empty.
                    (sched.cb)();
                }

                match delay {
                    None => {
                        let _ = condvar.wait(lock);
                    },
                    Some(delay) => {
                        let sec = delay.num_seconds();
                        let ns = (delay - Duration::seconds(sec)).num_nanoseconds().unwrap(); // Cannot be > 1_000_000_000.
                        let duration = std::time::Duration::new(sec as u64, ns as u32);
                        let _ = condvar.wait_timeout(lock, duration);
                    }
                }
            }
        }).unwrap();
        Timer {
            tx: tx
        }
    }

    /// Schedule a callback for execution after a delay.
    ///
    /// Callbacks are guaranteed to never be called before the
    /// delay. However, it is possible that they will be called a
    /// little after the delay.
    ///
    /// If the delay is negative, the callback is executed as soon as
    /// possible.
    ///
    /// # Performance
    ///
    /// The callback is executed on the Scheduler thread. It should
    /// therefore terminate very quickly, or risk causing delaying
    /// other callbacks.
    ///
    /// # Failures
    ///
    /// Any failure in `cb` will scheduler thread and progressively
    /// contaminate the Timer and the calling thread itself. You have
    /// been warned.
    ///
    /// # Example
    ///
    /// ```
    /// extern crate timer;
    /// extern crate chrono;
    /// use std::sync::mpsc::channel;
    ///
    /// let timer = timer::Timer::new();
    /// let (tx, rx) = channel();
    ///
    /// timer.schedule_with_delay(chrono::Duration::seconds(3), move || {
    ///   // This closure is executed on the scheduler thread,
    ///   // so we want to move it away asap.
    ///
    ///   let _ignored = tx.send(()); // Avoid unwrapping here.
    /// });
    ///
    /// rx.recv().unwrap();
    /// println!("This code has been executed after 3 seconds");
    /// ```
    pub fn schedule_with_delay<F>(&self, delay: Duration, cb: F)
        where F: 'static + Fn() + Send {
        self.schedule_with_date(UTC::now() + delay, cb)
    }

    /// Schedule a callback for execution at a given date.
    ///
    /// Callbacks are guaranteed to never be called before their
    /// date. However, it is possible that they will be called a
    /// little after it.
    ///
    /// If the date is in the past, the callback is executed as soon
    /// as possible.
    ///
    /// # Performance
    ///
    /// The callback is executed on the Scheduler thread. It should
    /// therefore terminate very quickly, or risk causing delaying
    /// other callbacks.
    ///
    /// # Failures
    ///
    /// Any failure in `cb` will scheduler thread and progressively
    /// contaminate the Timer and the calling thread itself. You have
    /// been warned.
    pub fn schedule_with_date<F>(&self, date: DateTime<UTC>, cb: F)
        where F: 'static + Fn() + Send {
        self.tx.send(Op::Schedule(Schedule {
            date: date,
            cb: Box::new(cb)
        })).unwrap();
    }
}

#[test]
fn test_schedule_with_delay() {
    let timer = Timer::new();
    let (tx, rx) = channel();

    // Schedule a number of callbacks in an arbitrary order, make sure
    // that they are executed in the right order.
    let mut delays = vec![1, 5, 3, -1];
    let start = UTC::now();
    for i in delays.clone() {
        println!("Scheduling for execution in {} seconds", i);
        let tx = tx.clone();
        timer.schedule_with_delay(Duration::seconds(i), move || {
            println!("Callback {}", i);
            tx.send(i).unwrap();
        });
    }

    delays.sort();
    for (i, msg) in (0..delays.len()).zip(rx.iter()) {
        let elapsed = (UTC::now() - start).num_seconds();
        println!("Received message {} after {} seconds", msg, elapsed);
        assert_eq!(msg, delays[i]);
        assert!(delays[i] <= elapsed && elapsed <= delays[i] + 3, "We have waited {} seconds, expecting [{}, {}]", elapsed, delays[i], delays[i] + 3);
    }

    // Now make sure that callbacks that are designed to be executed
    // immediately are executed quickly.
    let start = UTC::now();
    for i in vec![10, 0] {
        println!("Scheduling for execution in {} seconds", i);
        let tx = tx.clone();
        timer.schedule_with_delay(Duration::seconds(i), move || {
            println!("Callback {}", i);
            tx.send(i).unwrap();
        });
    }

    assert_eq!(rx.recv().unwrap(), 0);
    assert!(UTC::now() - start <= Duration::seconds(1));
}
<commit_msg>Isolated LockingChannel<commit_after>//! A simple timer, used to enqueue operations meant to be executed at
//! a given time or after a given delay.

extern crate chrono;

use std::cmp::Ordering;
use std::thread;
use std::sync::{Arc, Mutex, Condvar};
use std::sync::mpsc::{channel, Sender};
use std::collections::BinaryHeap;

use chrono::{Duration, DateTime, UTC};

/// An item scheduled for delayed execution.
struct Schedule {
    /// The instant at which to execute.
    date: DateTime<UTC>,

    /// The callback to execute.
    cb: Box<Fn() + Send>
}
impl Ord for Schedule {
    fn cmp(&self, other: &Self) -> Ordering {
        self.date.cmp(&other.date).reverse()
    }
}
impl PartialOrd for Schedule {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.date.partial_cmp(&other.date).map(|ord| ord.reverse())
    }
}
impl Eq for Schedule {
}
impl PartialEq for Schedule {
    fn eq(&self, other: &Self) -> bool {
        self.date.eq(&other.date)
    }
}

/// An operation to be sent across threads.
enum Op {
    /// Schedule a new item for execution.
    Schedule(Schedule),

    /// Stop the thread.
    Stop
}

/// A mutex-based kind-of-channel used to communicate between the
/// Communication thread and the Scheuler thread.
struct LockingChannel {
    /// Pending messages.
    messages: Mutex<Vec<Op>>,
    /// A condition variable used for waiting.
    condvar: Condvar,
}
impl LockingChannel {
    fn with_capacity(cap: usize) -> Self {
        LockingChannel {
            messages: Mutex::new(Vec::with_capacity(cap)),
            condvar: Condvar::new(),
        }
    }
}

/*
struct Scheduler {

}

impl Scheduler {
    fn new() -> Self {
    }
    fn run(&self) {
    }
}
 */

/// A timer, used to schedule execution of callbacks at a later date.
///
/// In the current implementation, each timer is executed as two
/// threads. The _Scheduler_ thread is in charge of maintaining the
/// queue of callbacks to execute and of actually executing them. The
/// _Communication_ thread is in charge of communicating with the
/// _Scheduler_ thread (which requires acquiring a possibly-long-held
/// Mutex) without blocking the caller thread.
pub struct Timer {
    /// Sender used to communicate with the _Communication_ thread. In
    /// turn, this thread will send
    tx: Sender<Op>
}

impl Drop for Timer {
    fn drop(&mut self) {
        self.tx.send(Op::Stop).unwrap();
    }
}

impl Timer {
    /// Create a timer.
    ///
    /// This immediatey launches two threads, which will remain
    /// launched until the timer is dropped. As expected, the threads
    /// spend most of their life waiting for instructions.
    pub fn new() -> Self {
        Self::with_capacity(32)
    }

    /// As `new()`, but with a manually specified initial capaicty.
    pub fn with_capacity(capacity: usize) -> Self {
        let waiter_rcv = Arc::new(LockingChannel::with_capacity(capacity));
        let waiter_snd = waiter_rcv.clone();

        // Spawn a first thread, whose sole role is to dispatch
        // messages to the second thread without having to wait too
        // long for the mutex.
        let (tx, rx) = channel();
        thread::spawn(move || {
            use Op::*;
            let ref locking = *waiter_snd;
            for msg in rx.iter() {
                let mut vec = locking.messages.lock().unwrap();
                match msg {
                    Schedule(sched) => {
                        vec.push(Schedule(sched));
                        locking.condvar.notify_one();
                    }
                    Stop => {
                        vec.clear();
                        vec.push(Op::Stop);
                        locking.condvar.notify_one();
                        return;
                    }
                }
            }
        });

        // Spawn a second thread, in charge of scheduling.
        let mut heap = BinaryHeap::with_capacity(capacity);
        thread::Builder::new().name("Timer thread".to_owned()).spawn(move || {
            let ref locking = *waiter_rcv;
            loop {
                let mut lock = locking.messages.lock().unwrap();

                // Pop all messages.
                for msg in lock.drain(..) {
                    match msg {
                        Op::Stop => {
                            return;
                        }
                        Op::Schedule(sched) => heap.push(sched),
                    }
                }

                // Pop all the callbacks that are ready.
                let mut delay = None;
                loop {
                    let now = UTC::now();
                    if let Some(sched) = heap.peek() {
                        if sched.date > now {
                            // First item is not ready yet, so nothing is ready.
                            // We assume that `sched.date > now` is still true.
                            delay = Some(sched.date - now);
                            break;
                        }
                    } else {
                        // No item at all.
                        break;
                    }
                    let sched = heap.pop().unwrap(); // We just checked that the heap is not empty.
                    (sched.cb)();
                }

                match delay {
                    None => {
                        let _ = locking.condvar.wait(lock);
                    },
                    Some(delay) => {
                        let sec = delay.num_seconds();
                        let ns = (delay - Duration::seconds(sec)).num_nanoseconds().unwrap(); // This `unwrap()` asserts that the number of ns is not > 1_000_000_000. Since we just substracted the number of seconds, the assertion should always pass.
                        let duration = std::time::Duration::new(sec as u64, ns as u32);
                        let _ = locking.condvar.wait_timeout(lock, duration);
                    }
                }
            }
        }).unwrap();

        Timer {
            tx: tx
        }
    }

    /// Schedule a callback for execution after a delay.
    ///
    /// Callbacks are guaranteed to never be called before the
    /// delay. However, it is possible that they will be called a
    /// little after the delay.
    ///
    /// If the delay is negative, the callback is executed as soon as
    /// possible.
    ///
    /// # Performance
    ///
    /// The callback is executed on the Scheduler thread. It should
    /// therefore terminate very quickly, or risk causing delaying
    /// other callbacks.
    ///
    /// # Failures
    ///
    /// Any failure in `cb` will scheduler thread and progressively
    /// contaminate the Timer and the calling thread itself. You have
    /// been warned.
    ///
    /// # Example
    ///
    /// ```
    /// extern crate timer;
    /// extern crate chrono;
    /// use std::sync::mpsc::channel;
    ///
    /// let timer = timer::Timer::new();
    /// let (tx, rx) = channel();
    ///
    /// timer.schedule_with_delay(chrono::Duration::seconds(3), move || {
    ///   // This closure is executed on the scheduler thread,
    ///   // so we want to move it away asap.
    ///
    ///   let _ignored = tx.send(()); // Avoid unwrapping here.
    /// });
    ///
    /// rx.recv().unwrap();
    /// println!("This code has been executed after 3 seconds");
    /// ```
    pub fn schedule_with_delay<F>(&self, delay: Duration, cb: F)
        where F: 'static + Fn() + Send {
        self.schedule_with_date(UTC::now() + delay, cb)
    }

    /// Schedule a callback for execution at a given date.
    ///
    /// Callbacks are guaranteed to never be called before their
    /// date. However, it is possible that they will be called a
    /// little after it.
    ///
    /// If the date is in the past, the callback is executed as soon
    /// as possible.
    ///
    /// # Performance
    ///
    /// The callback is executed on the Scheduler thread. It should
    /// therefore terminate very quickly, or risk causing delaying
    /// other callbacks.
    ///
    /// # Failures
    ///
    /// Any failure in `cb` will scheduler thread and progressively
    /// contaminate the Timer and the calling thread itself. You have
    /// been warned.
    pub fn schedule_with_date<F>(&self, date: DateTime<UTC>, cb: F)
        where F: 'static + Fn() + Send {
        self.tx.send(Op::Schedule(Schedule {
            date: date,
            cb: Box::new(cb)
        })).unwrap();
    }
}

#[test]
fn test_schedule_with_delay() {
    let timer = Timer::new();
    let (tx, rx) = channel();

    // Schedule a number of callbacks in an arbitrary order, make sure
    // that they are executed in the right order.
    let mut delays = vec![1, 5, 3, -1];
    let start = UTC::now();
    for i in delays.clone() {
        println!("Scheduling for execution in {} seconds", i);
        let tx = tx.clone();
        timer.schedule_with_delay(Duration::seconds(i), move || {
            println!("Callback {}", i);
            tx.send(i).unwrap();
        });
    }

    delays.sort();
    for (i, msg) in (0..delays.len()).zip(rx.iter()) {
        let elapsed = (UTC::now() - start).num_seconds();
        println!("Received message {} after {} seconds", msg, elapsed);
        assert_eq!(msg, delays[i]);
        assert!(delays[i] <= elapsed && elapsed <= delays[i] + 3, "We have waited {} seconds, expecting [{}, {}]", elapsed, delays[i], delays[i] + 3);
    }

    // Now make sure that callbacks that are designed to be executed
    // immediately are executed quickly.
    let start = UTC::now();
    for i in vec![10, 0] {
        println!("Scheduling for execution in {} seconds", i);
        let tx = tx.clone();
        timer.schedule_with_delay(Duration::seconds(i), move || {
            println!("Callback {}", i);
            tx.send(i).unwrap();
        });
    }

    assert_eq!(rx.recv().unwrap(), 0);
    assert!(UTC::now() - start <= Duration::seconds(1));
}

#[test]
fn test_schedule_and_panic() {
    let timer = Timer::new();
    for i in 0..1000 {
        let (tx, rx) = channel();
        timer.schedule_with_delay(Duration::milliseconds(i), move || {
            println!("Received callback {}, preparing to panic", i);
            if true {
                panic!("Testing the behavior in presence of a panic");
            } else {
                tx.send(()).unwrap();
            }
        });
        assert!(rx.try_recv().is_err());
    }

    let (tx, rx) = channel();
    timer.schedule_with_delay(Duration::seconds(1), move || {
        println!("Received final callback, don't panic");
        tx.send(()).unwrap();
    });
    rx.try_recv().unwrap();
}
<|endoftext|>


<commit_before>pub fn quicksort<T: PartialOrd>(vec: &mut [T]) {
    if vec.len() <= 1 {
        return;
    }
    let pivot: usize = 0;
    let mut first_opened = Vec::new();
    let mut last_closed: usize = 0;

    for i in 1..vec.len() {
        first_opened.push(i);
        if vec[i] < vec[pivot] {
            let to = first_opened.remove(0);
            vec.swap(i, to);
            last_closed = to;
        }
    }

    vec.swap(pivot, last_closed);
    quicksort(&mut vec[0..last_closed]);
    quicksort(&mut vec[last_closed+1..]);
}

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

    #[test]
    fn test_vec_of_u64() {
        let sorted: Vec<u64> = vec![1, 1, 2, 3, 3, 4, 5, 5, 6, 9];
        let mut unsorted: Vec<u64> = vec![3, 1, 4, 1, 5, 9, 2, 6, 5, 3];
        quicksort(&mut unsorted);

        assert_eq!(unsorted, sorted.as_slice());
    }

    #[test]
    fn test_vec_of_u8() {
        let sorted = "        Tabcdeeefghhijklmnoooopqrrstuuvwxyz".to_string().into_bytes();
        let mut unsorted = "The quick brown fox jumps over the lazy dog".to_string().into_bytes();
        quicksort(&mut unsorted);

        assert_eq!(sorted, unsorted);
    }

    #[test]
    fn test_array_of_u8() {
        let sorted: [u8; 10] = [1, 2, 3, 4, 5, 5, 5, 7, 9, 10];
        let mut unsorted: [u8; 10] = [7, 5, 3, 2, 5, 1, 4, 5, 9, 10];
        quicksort(&mut unsorted);

        assert_eq!(sorted, unsorted);
    }
}
<commit_msg>Rename test variables<commit_after>pub fn quicksort<T: PartialOrd>(vec: &mut [T]) {
    if vec.len() <= 1 {
        return;
    }
    let pivot: usize = 0;
    let mut first_opened = Vec::new();
    let mut last_closed: usize = 0;

    for i in 1..vec.len() {
        first_opened.push(i);
        if vec[i] < vec[pivot] {
            let to = first_opened.remove(0);
            vec.swap(i, to);
            last_closed = to;
        }
    }

    vec.swap(pivot, last_closed);
    quicksort(&mut vec[0..last_closed]);
    quicksort(&mut vec[last_closed+1..]);
}

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

    #[test]
    fn test_vec_of_u64() {
        let presorted: Vec<u64> = vec![1, 1, 2, 3, 3, 4, 5, 5, 6, 9];
        let mut vector: Vec<u64> = vec![3, 1, 4, 1, 5, 9, 2, 6, 5, 3];
        quicksort(&mut vector);

        assert_eq!(vector, presorted.as_slice());
    }

    #[test]
    fn test_vec_of_u8() {
        let presorted = "        Tabcdeeefghhijklmnoooopqrrstuuvwxyz".to_string().into_bytes();
        let mut vector = "The quick brown fox jumps over the lazy dog".to_string().into_bytes();
        quicksort(&mut vector);

        assert_eq!(presorted, vector);
    }

    #[test]
    fn test_array_of_u8() {
        let presorted: [u8; 10] = [1, 2, 3, 4, 5, 5, 5, 7, 9, 10];
        let mut vector: [u8; 10] = [7, 5, 3, 2, 5, 1, 4, 5, 9, 10];
        quicksort(&mut vector);

        assert_eq!(presorted, vector);
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Nicholas Bishop
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Vec2D is a very simple 2D container for storing rectangular data

#![deny(missing_docs)]

/// 2D coordinate
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Coord {
    /// X component
    pub x: usize,

    /// Y component
    pub y: usize
}

/// Rectangle defined by inclusive minimum and maximum coordinates
#[derive(Clone, Copy, Eq, Debug, PartialEq)]
pub struct Rect {
    /// Minimum coordinate (inclusive)
    min_coord: Coord,

    /// Maximum coordinate (inclusive)
    max_coord: Coord
}

/// Rectangle dimensions
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Size {
    /// Width of rectangle
    pub width: usize,
    /// Height of rectangle
    pub height: usize
}

/// Container for 2D data
pub struct Vec2D<T> {
    elems: Vec<T>,
    size: Size
}

/// Mutable iterator over a Vec2D
pub struct RectIterMut<'a, Elem: 'a> {
    grid: std::marker::PhantomData<&'a mut Vec2D<Elem>>,

    rect: Rect,
    cur_elem: *mut Elem,
    cur_coord: Coord,
    stride: isize
}

impl Coord {
    /// Create a coordinate at (x, y)
    pub fn new(x: usize, y: usize) -> Coord {
        Coord {
            x: x,
            y: y
        }
    }
}

impl Rect {
    /// Calculate rectangle width
    pub fn width(&self) -> usize {
        return self.max_coord.x - self.min_coord.x + 1;
    }

    /// Calculate rectangle height
    pub fn height(&self) -> usize {
        return self.max_coord.y - self.min_coord.y + 1;
    }

    /// Calculate rectangle size
    pub fn size(&self) -> Size {
        Size::new(self.width(), self.height())
    }
}

impl Size {
    /// Create a 2D size of (width, height)
    pub fn new(width: usize, height: usize) -> Size {
        Size {
            width: width,
            height: height
        }
    }

    /// width * height
    pub fn area(&self) -> usize {
        self.width * self.height
    }

    /// Return true if the coordinate fits within self's width and
    /// height, false otherwise.
    pub fn contains_coord(&self, coord: Coord) -> bool {
        coord.x < self.width && coord.y < self.height
    }
}

impl<Elem: Copy> Vec2D<Elem> {
    /// Create a Vec2D with the given `size`. All elements are
    /// initialized as copies of the `example` element.
    pub fn from_example(size: Size, example: &Elem) -> Vec2D<Elem> {
        Vec2D {
            elems: vec![*example; size.area()],
            size: size
        }
    }

    /// Create a Vec2D with the given `size`. The contents are set to
    /// `src`. None is returned if the `size` does not match the
    /// length of `src`.
    pub fn from_vec(size: Size, src: Vec<Elem>) -> Option<Vec2D<Elem>> {
        if size.area() == src.len() {
            Some(Vec2D {
                elems: src,
                size: size
            })
        }
        else {
            None
        }
    }

    /// Create a mutable iterator over a rectangular region of the
    /// Vec2D. None is returned if the given `rect` does not fit
    /// entirely within the Vec2D.
    pub fn rect_iter_mut<'a>(&'a mut self, rect: Rect) -> Option<RectIterMut<'a, Elem>> {
        if self.size.contains_coord(rect.max_coord) {
            Some(RectIterMut {
                grid: std::marker::PhantomData,
                stride: (self.size.width - rect.width() + 1) as isize,
                cur_elem: self.elems.as_mut_ptr(),
                rect: rect,
                cur_coord: rect.min_coord
            })
        }
        else {
            None
        }
    }
}

impl<'a, Elem> Iterator for RectIterMut<'a, Elem> {
    type Item = (Coord, &'a mut Elem);

    fn next(&mut self) -> Option<Self::Item> {
        if self.cur_coord.y <= self.rect.max_coord.y {
            let result = (self.cur_coord, unsafe { &mut *self.cur_elem });

            self.cur_coord.x += 1;
            if self.cur_coord.x <= self.rect.max_coord.x {
                unsafe { self.cur_elem = self.cur_elem.offset(1); }
            }
            else {
                self.cur_coord.x = self.rect.min_coord.x;
                self.cur_coord.y += 1;
                unsafe { self.cur_elem = self.cur_elem.offset(self.stride); }
            }
            Some(result)
        }
        else {
            None
        }
    }
}

impl Rect {
    /// Create a new Rect defined by inclusive minimum and maximum
    /// coordinates. If min_coord is greater than max_coord on either
    /// axis then None is returned.
    pub fn new(min_coord: Coord, max_coord: Coord) -> Option<Rect> {
        if min_coord.x <= max_coord.x && min_coord.y <= max_coord.y {
            Some(Rect {
                min_coord: min_coord,
                max_coord: max_coord
            })
        }
        else {
            None
        }
    }

}

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

    #[test]
    fn test_coord() {
        let coord = Coord::new(1, 2);
        assert_eq!(coord.x, 1);
        assert_eq!(coord.y, 2);
    }

    #[test]
    fn test_rect_iter_mut() {
        let elems = vec![1, 2, 3, 4];
        let mut grid = Vec2D::from_vec(Size::new(2, 2), elems).unwrap();
        let rect = Rect::new(Coord::new(0, 0), Coord::new(1, 1)).unwrap();

        let mut actual_coords = Vec::new();
        for (coord, elem) in grid.rect_iter_mut(rect).unwrap() {
            *elem = -(*elem);
            actual_coords.push((coord.x, coord.y));
        }
        assert_eq!(actual_coords, [(0, 0), (1, 0), (0, 1), (1, 1)]);
        assert_eq!(grid.elems, [-1, -2, -3, -4]);
    }
}
<commit_msg>Add missing derives<commit_after>// Copyright 2015 Nicholas Bishop
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Vec2D is a very simple 2D container for storing rectangular data

#![deny(missing_docs)]

/// 2D coordinate
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Coord {
    /// X component
    pub x: usize,

    /// Y component
    pub y: usize
}

/// Rectangle defined by inclusive minimum and maximum coordinates
#[derive(Clone, Copy, Eq, Debug, PartialEq)]
pub struct Rect {
    /// Minimum coordinate (inclusive)
    min_coord: Coord,

    /// Maximum coordinate (inclusive)
    max_coord: Coord
}

/// Rectangle dimensions
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Size {
    /// Width of rectangle
    pub width: usize,
    /// Height of rectangle
    pub height: usize
}

/// Container for 2D data
#[derive(Clone, Debug)]
pub struct Vec2D<T> {
    elems: Vec<T>,
    size: Size
}

/// Mutable iterator over a Vec2D
pub struct RectIterMut<'a, Elem: 'a> {
    grid: std::marker::PhantomData<&'a mut Vec2D<Elem>>,

    rect: Rect,
    cur_elem: *mut Elem,
    cur_coord: Coord,
    stride: isize
}

impl Coord {
    /// Create a coordinate at (x, y)
    pub fn new(x: usize, y: usize) -> Coord {
        Coord {
            x: x,
            y: y
        }
    }
}

impl Rect {
    /// Calculate rectangle width
    pub fn width(&self) -> usize {
        return self.max_coord.x - self.min_coord.x + 1;
    }

    /// Calculate rectangle height
    pub fn height(&self) -> usize {
        return self.max_coord.y - self.min_coord.y + 1;
    }

    /// Calculate rectangle size
    pub fn size(&self) -> Size {
        Size::new(self.width(), self.height())
    }
}

impl Size {
    /// Create a 2D size of (width, height)
    pub fn new(width: usize, height: usize) -> Size {
        Size {
            width: width,
            height: height
        }
    }

    /// width * height
    pub fn area(&self) -> usize {
        self.width * self.height
    }

    /// Return true if the coordinate fits within self's width and
    /// height, false otherwise.
    pub fn contains_coord(&self, coord: Coord) -> bool {
        coord.x < self.width && coord.y < self.height
    }
}

impl<Elem: Copy> Vec2D<Elem> {
    /// Create a Vec2D with the given `size`. All elements are
    /// initialized as copies of the `example` element.
    pub fn from_example(size: Size, example: &Elem) -> Vec2D<Elem> {
        Vec2D {
            elems: vec![*example; size.area()],
            size: size
        }
    }

    /// Create a Vec2D with the given `size`. The contents are set to
    /// `src`. None is returned if the `size` does not match the
    /// length of `src`.
    pub fn from_vec(size: Size, src: Vec<Elem>) -> Option<Vec2D<Elem>> {
        if size.area() == src.len() {
            Some(Vec2D {
                elems: src,
                size: size
            })
        }
        else {
            None
        }
    }

    /// Create a mutable iterator over a rectangular region of the
    /// Vec2D. None is returned if the given `rect` does not fit
    /// entirely within the Vec2D.
    pub fn rect_iter_mut<'a>(&'a mut self, rect: Rect) -> Option<RectIterMut<'a, Elem>> {
        if self.size.contains_coord(rect.max_coord) {
            Some(RectIterMut {
                grid: std::marker::PhantomData,
                stride: (self.size.width - rect.width() + 1) as isize,
                cur_elem: self.elems.as_mut_ptr(),
                rect: rect,
                cur_coord: rect.min_coord
            })
        }
        else {
            None
        }
    }
}

impl<'a, Elem> Iterator for RectIterMut<'a, Elem> {
    type Item = (Coord, &'a mut Elem);

    fn next(&mut self) -> Option<Self::Item> {
        if self.cur_coord.y <= self.rect.max_coord.y {
            let result = (self.cur_coord, unsafe { &mut *self.cur_elem });

            self.cur_coord.x += 1;
            if self.cur_coord.x <= self.rect.max_coord.x {
                unsafe { self.cur_elem = self.cur_elem.offset(1); }
            }
            else {
                self.cur_coord.x = self.rect.min_coord.x;
                self.cur_coord.y += 1;
                unsafe { self.cur_elem = self.cur_elem.offset(self.stride); }
            }
            Some(result)
        }
        else {
            None
        }
    }
}

impl Rect {
    /// Create a new Rect defined by inclusive minimum and maximum
    /// coordinates. If min_coord is greater than max_coord on either
    /// axis then None is returned.
    pub fn new(min_coord: Coord, max_coord: Coord) -> Option<Rect> {
        if min_coord.x <= max_coord.x && min_coord.y <= max_coord.y {
            Some(Rect {
                min_coord: min_coord,
                max_coord: max_coord
            })
        }
        else {
            None
        }
    }

}

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

    #[test]
    fn test_coord() {
        let coord = Coord::new(1, 2);
        assert_eq!(coord.x, 1);
        assert_eq!(coord.y, 2);
    }

    #[test]
    fn test_rect_iter_mut() {
        let elems = vec![1, 2, 3, 4];
        let mut grid = Vec2D::from_vec(Size::new(2, 2), elems).unwrap();
        let rect = Rect::new(Coord::new(0, 0), Coord::new(1, 1)).unwrap();

        let mut actual_coords = Vec::new();
        for (coord, elem) in grid.rect_iter_mut(rect).unwrap() {
            *elem = -(*elem);
            actual_coords.push((coord.x, coord.y));
        }
        assert_eq!(actual_coords, [(0, 0), (1, 0), (0, 1), (1, 1)]);
        assert_eq!(grid.elems, [-1, -2, -3, -4]);
    }
}
<|endoftext|>


<commit_before>//! The [Neon](https://www.neon-bindings.com/) crate provides bindings for writing Node.js plugins with a safe and fast Rust API.

extern crate neon_runtime;
extern crate cslice;
extern crate semver;

#[cfg(test)]
extern crate rustc_version;

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

pub mod context;
pub mod handle;
pub mod types;
pub mod object;
pub mod borrow;
pub mod result;
pub mod task;
pub mod meta;
pub mod prelude;

#[doc(hidden)]
pub mod macro_internal;

/// Register the current crate as a Node module, providing startup
/// logic for initializing the module object at runtime.
///
/// The first argument is a pattern bound to a `neon::context::ModuleContext`. This
/// is usually bound to a mutable variable `mut cx`, which can then be used to
/// pass to Neon APIs that require mutable access to an execution context.
///
/// Example:
///
/// ```rust,ignore
/// register_module!(mut cx, {
///     cx.export_function("foo", foo)?;
///     cx.export_function("bar", bar)?;
///     cx.export_function("baz", baz)?;
///     Ok(())
/// });
/// ```
#[macro_export]
macro_rules! register_module {
    ($module:pat, $init:block) => {
        // Mark this function as a global constructor (like C++).
        #[allow(improper_ctypes)]
        #[cfg_attr(target_os = "linux", link_section = ".ctors")]
        #[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
        #[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
        pub static __LOAD_NEON_MODULE: extern "C" fn() = {
            fn __init_neon_module($module: $crate::context::ModuleContext) -> $crate::result::NeonResult<()> $init

            extern "C" fn __load_neon_module() {
                // Put everything else in the ctor fn so the user fn can't see it.
                #[repr(C)]
                struct __NodeModule {
                    version: i32,
                    flags: u32,
                    dso_handle: *mut u8,
                    filename: *const u8,
                    register_func: Option<extern "C" fn(
                        $crate::handle::Handle<$crate::types::JsObject>, *mut u8, *mut u8)>,
                    context_register_func: Option<extern "C" fn(
                        $crate::handle::Handle<$crate::types::JsObject>, *mut u8, *mut u8, *mut u8)>,
                    modname: *const u8,
                    priv_data: *mut u8,
                    link: *mut __NodeModule
                }

                static mut __NODE_MODULE: __NodeModule = __NodeModule {
                    version: 0,
                    flags: 0,
                    dso_handle: 0 as *mut _,
                    filename: b"neon_source.rs\0" as *const u8,
                    register_func: Some(__register_neon_module),
                    context_register_func: None,
                    modname: b"neon_module\0" as *const u8,
                    priv_data: 0 as *mut _,
                    link: 0 as *mut _
                };

                extern "C" fn __register_neon_module(
                        m: $crate::handle::Handle<$crate::types::JsObject>, _: *mut u8, _: *mut u8) {
                    $crate::macro_internal::initialize_module(m, __init_neon_module);
                }

                extern "C" {
                    fn node_module_register(module: *mut __NodeModule);
                }

                // Suppress the default Rust panic hook, which prints diagnostics to stderr.
                ::std::panic::set_hook(::std::boxed::Box::new(|_| { }));

                unsafe {
                    // Set the ABI version based on the NODE_MODULE_VERSION constant provided by the current node headers.
                    __NODE_MODULE.version = $crate::macro_internal::runtime::module::get_version();
                    node_module_register(&mut __NODE_MODULE);
                }
            }

            __load_neon_module
        };
    }
}

#[doc(hidden)]
#[macro_export]
macro_rules! class_definition {
    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:tt ; $call_ctor:tt ; $new_ctor:tt ; $mnames:tt ; $mdefs:tt ; init($cx:pat) $body:block $($rest:tt)* ) => {
        class_definition!($cls ;
                          $cname ;
                          $typ ;
                          {
                              fn _______allocator_rust_y_u_no_hygienic_items_______($cx: $crate::context::CallContext<$crate::types::JsUndefined>) -> $crate::result::NeonResult<$typ> {
                                  $body
                              }

                              $crate::macro_internal::AllocateCallback(_______allocator_rust_y_u_no_hygienic_items_______)
                          } ;
                          $call_ctor ;
                          $new_ctor ;
                          $mnames ;
                          $mdefs ;
                          $($rest)*);
    };

    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:tt ; $call_ctor:tt ; $new_ctor:tt ; ($($mname:tt)*) ; ($($mdef:tt)*) ; method $name:ident($cx:pat) $body:block $($rest:tt)* ) => {
        class_definition!($cls ;
                          $cname ;
                          $typ ;
                          $allocator ;
                          $call_ctor ;
                          $new_ctor ;
                          ($($mname)* $name) ;
                          ($($mdef)* {
                              fn _______method_rust_y_u_no_hygienic_items_______($cx: $crate::context::CallContext<$cls>) -> $crate::result::JsResult<$crate::types::JsValue> {
                                  $body
                              }

                              $crate::macro_internal::MethodCallback(_______method_rust_y_u_no_hygienic_items_______)
                          }) ;
                          $($rest)*);
    };

    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:tt ; $call_ctor:tt ; $new_ctor:tt ; $mnames:tt ; $mdefs:tt ; constructor($cx:pat) $body:block $($rest:tt)* ) => {
        class_definition!($cls ;
                          $cname ;
                          $typ ;
                          $allocator ;
                          $call_ctor ;
                          ({
                              fn _______constructor_rust_y_u_no_hygienic_items_______($cx: $crate::context::CallContext<$cls>) -> $crate::result::NeonResult<Option<$crate::handle::Handle<$crate::types::JsObject>>> {
                                  $body
                              }

                              $crate::macro_internal::ConstructCallback(_______constructor_rust_y_u_no_hygienic_items_______)
                          }) ;
                          $mnames ;
                          $mdefs ;
                          $($rest)*);
    };

    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:tt ; $call_ctor:tt ; $new_ctor:tt ; $mnames:tt ; $mdefs:tt ; call($cx:pat) $body:block $($rest:tt)* ) => {
        class_definition!($cls ;
                          $cname ;
                          $typ ;
                          $allocator ;
                          ({
                              fn _______call_rust_y_u_no_hygienic_items_______($cx: $crate::context::CallContext<$crate::types::JsValue>) -> $crate::result::JsResult<$crate::types::JsValue> {
                                  $body
                              }

                              $crate::macro_internal::ConstructorCallCallback(_______call_rust_y_u_no_hygienic_items_______)
                          }) ;
                          $new_ctor ;
                          $mnames ;
                          $mdefs ;
                          $($rest)*);
    };

    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:block ; ($($call_ctor:block)*) ; ($($new_ctor:block)*) ; ($($mname:ident)*) ; ($($mdef:block)*) ; $($rest:tt)* ) => {
        impl $crate::object::Class for $cls {
            type Internals = $typ;

            fn setup<'a, C: $crate::context::Context<'a>>(_: &mut C) -> $crate::result::NeonResult<$crate::object::ClassDescriptor<'a, Self>> {
                ::std::result::Result::Ok(Self::describe(stringify!($cname), $allocator)
                                             $(.construct($new_ctor))*
                                             $(.call($call_ctor))*
                                             $(.method(stringify!($mname), $mdef))*)
            }
        }
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! impl_managed {
    ($cls:ident) => {
        impl $crate::handle::Managed for $cls {
            fn to_raw(self) -> $crate::macro_internal::runtime::raw::Local {
                let $cls(raw) = self;
                raw
            }

            fn from_raw(raw: $crate::macro_internal::runtime::raw::Local) -> Self {
                $cls(raw)
            }
        }
    }
}

/// Declare custom native JavaScript types with Rust implementations.
///
/// Example:
///
/// ```rust,ignore
/// pub struct Greeter {
///     greeting: String
/// }
///
/// declare_types! {
///
///     /// A class for generating greeting strings.
///     pub class JsGreeter for Greeter {
///         init(mut cx) {
///             let greeting = cx.argument(0)?.to_string(&mut cx)?.value();
///             Ok(Greeter {
///                 greeting: greeting
///             })
///         }
///
///         method hello(mut cx) {
///             let name = cx.argument(0)?.to_string(&mut cx)?.value();
///             let this = cx.this();
///             let msg = {
///                 let guard = cx.lock();
///                 let greeter = this.borrow(&guard);
///                 format!("{}, {}!", greeter.greeting, name)
///             };
///             Ok(cx.string(&msg[..])?.upcast())
///         }
///     }
///
/// }
/// ```
#[macro_export]
macro_rules! declare_types {
    { $(#[$attr:meta])* pub class $cls:ident for $typ:ident { $($body:tt)* } $($rest:tt)* } => {
        declare_types! { $(#[$attr])* pub class $cls as $typ for $typ { $($body)* } $($rest)* }
    };

    { $(#[$attr:meta])* class $cls:ident for $typ:ident { $($body:tt)* } $($rest:tt)* } => {
        declare_types! { $(#[$attr])* class $cls as $typ for $typ { $($body)* } $($rest)* }
    };

    { $(#[$attr:meta])* pub class $cls:ident as $cname:ident for $typ:ty { $($body:tt)* } $($rest:tt)* } => {
        #[derive(Copy, Clone)]
        #[repr(C)]
        $(#[$attr])*
        pub struct $cls($crate::macro_internal::runtime::raw::Local);

        impl_managed!($cls);

        class_definition!($cls ; $cname ; $typ ; () ; () ; () ; () ; () ; $($body)*);

        declare_types! { $($rest)* }
    };

    { $(#[$attr:meta])* class $cls:ident as $cname:ident for $typ:ty { $($body:tt)* } $($rest:tt)* } => {
        #[derive(Copy, Clone)]
        #[repr(C)]
        $(#[$attr])*
        struct $cls($crate::macro_internal::runtime::raw::Local);

        impl_managed!($cls);

        class_definition!($cls ; $cname ; $typ ; () ; () ; () ; () ; () ; $($body)*);

        declare_types! { $($rest)* }
    };

    { } => { };
}

#[cfg(all(windows, not(neon_profile = "release")))]
compile_error!("Neon only builds with --release. For tests, try `cargo test --release`.");

#[cfg(test)]
mod tests {
    use std::path::{Path, PathBuf};
    use std::process::Command;
    use std::sync::Mutex;

    use rustc_version::{version_meta, Channel};

    // Create a mutex to enforce sequential running of the tests.
    lazy_static! {
        static ref TEST_MUTEX: Mutex<()> = Mutex::new(());
    }

    fn project_root() -> PathBuf {
        Path::new(env!("CARGO_MANIFEST_DIR")).to_path_buf()
    }

    fn log(test_name: &str) {
        eprintln!("======================================================");
        eprintln!("Neon test: {}", test_name);
        eprintln!("======================================================");
    }

    fn run(cmd: &str, dir: &Path) {
        let (shell, command_flag) = if cfg!(windows) {
            ("cmd", "/C")
        } else {
            ("sh", "-c")
        };

        assert!(Command::new(&shell)
                        .current_dir(dir)
                        .args(&[&command_flag, cmd])
                        .status()
                        .expect("failed to execute test command")
                        .success());
    }

    fn cli_setup() {
        let cli = project_root().join("cli");

        run("npm install", &cli);
        run("npm run transpile", &cli);
    }

    #[test]
    fn cli_test() {
        let _guard = TEST_MUTEX.lock();

        log("cli_test");

        cli_setup();

        let test_cli = project_root().join("test").join("cli");
        run("npm install", &test_cli);
        run("npm run transpile", &test_cli);
        run("npm test", &test_cli);
    }

    #[cfg(not(windows))]
    #[test]
    fn static_test() {
        let _guard = TEST_MUTEX.lock();

        log("static_test");

        if version_meta().unwrap().channel != Channel::Nightly {
            return;
        }

        run("cargo test --release", &project_root().join("test").join("static"));
    }

    #[test]
    fn dynamic_test() {
        let _guard = TEST_MUTEX.lock();

        log("dynamic_test");

        cli_setup();

        let test_dynamic = project_root().join("test").join("dynamic");
        run("npm install", &test_dynamic);
        run("npm test", &test_dynamic);
    }
}
<commit_msg>Improves doctest for `declare_types`<commit_after>//! The [Neon](https://www.neon-bindings.com/) crate provides bindings for writing Node.js plugins with a safe and fast Rust API.

extern crate neon_runtime;
extern crate cslice;
extern crate semver;

#[cfg(test)]
extern crate rustc_version;

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

pub mod context;
pub mod handle;
pub mod types;
pub mod object;
pub mod borrow;
pub mod result;
pub mod task;
pub mod meta;
pub mod prelude;

#[doc(hidden)]
pub mod macro_internal;

/// Register the current crate as a Node module, providing startup
/// logic for initializing the module object at runtime.
///
/// The first argument is a pattern bound to a `neon::context::ModuleContext`. This
/// is usually bound to a mutable variable `mut cx`, which can then be used to
/// pass to Neon APIs that require mutable access to an execution context.
///
/// Example:
///
/// ```rust,ignore
/// register_module!(mut cx, {
///     cx.export_function("foo", foo)?;
///     cx.export_function("bar", bar)?;
///     cx.export_function("baz", baz)?;
///     Ok(())
/// });
/// ```
#[macro_export]
macro_rules! register_module {
    ($module:pat, $init:block) => {
        // Mark this function as a global constructor (like C++).
        #[allow(improper_ctypes)]
        #[cfg_attr(target_os = "linux", link_section = ".ctors")]
        #[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
        #[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
        pub static __LOAD_NEON_MODULE: extern "C" fn() = {
            fn __init_neon_module($module: $crate::context::ModuleContext) -> $crate::result::NeonResult<()> $init

            extern "C" fn __load_neon_module() {
                // Put everything else in the ctor fn so the user fn can't see it.
                #[repr(C)]
                struct __NodeModule {
                    version: i32,
                    flags: u32,
                    dso_handle: *mut u8,
                    filename: *const u8,
                    register_func: Option<extern "C" fn(
                        $crate::handle::Handle<$crate::types::JsObject>, *mut u8, *mut u8)>,
                    context_register_func: Option<extern "C" fn(
                        $crate::handle::Handle<$crate::types::JsObject>, *mut u8, *mut u8, *mut u8)>,
                    modname: *const u8,
                    priv_data: *mut u8,
                    link: *mut __NodeModule
                }

                static mut __NODE_MODULE: __NodeModule = __NodeModule {
                    version: 0,
                    flags: 0,
                    dso_handle: 0 as *mut _,
                    filename: b"neon_source.rs\0" as *const u8,
                    register_func: Some(__register_neon_module),
                    context_register_func: None,
                    modname: b"neon_module\0" as *const u8,
                    priv_data: 0 as *mut _,
                    link: 0 as *mut _
                };

                extern "C" fn __register_neon_module(
                        m: $crate::handle::Handle<$crate::types::JsObject>, _: *mut u8, _: *mut u8) {
                    $crate::macro_internal::initialize_module(m, __init_neon_module);
                }

                extern "C" {
                    fn node_module_register(module: *mut __NodeModule);
                }

                // Suppress the default Rust panic hook, which prints diagnostics to stderr.
                ::std::panic::set_hook(::std::boxed::Box::new(|_| { }));

                unsafe {
                    // Set the ABI version based on the NODE_MODULE_VERSION constant provided by the current node headers.
                    __NODE_MODULE.version = $crate::macro_internal::runtime::module::get_version();
                    node_module_register(&mut __NODE_MODULE);
                }
            }

            __load_neon_module
        };
    }
}

#[doc(hidden)]
#[macro_export]
macro_rules! class_definition {
    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:tt ; $call_ctor:tt ; $new_ctor:tt ; $mnames:tt ; $mdefs:tt ; init($cx:pat) $body:block $($rest:tt)* ) => {
        class_definition!($cls ;
                          $cname ;
                          $typ ;
                          {
                              fn _______allocator_rust_y_u_no_hygienic_items_______($cx: $crate::context::CallContext<$crate::types::JsUndefined>) -> $crate::result::NeonResult<$typ> {
                                  $body
                              }

                              $crate::macro_internal::AllocateCallback(_______allocator_rust_y_u_no_hygienic_items_______)
                          } ;
                          $call_ctor ;
                          $new_ctor ;
                          $mnames ;
                          $mdefs ;
                          $($rest)*);
    };

    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:tt ; $call_ctor:tt ; $new_ctor:tt ; ($($mname:tt)*) ; ($($mdef:tt)*) ; method $name:ident($cx:pat) $body:block $($rest:tt)* ) => {
        class_definition!($cls ;
                          $cname ;
                          $typ ;
                          $allocator ;
                          $call_ctor ;
                          $new_ctor ;
                          ($($mname)* $name) ;
                          ($($mdef)* {
                              fn _______method_rust_y_u_no_hygienic_items_______($cx: $crate::context::CallContext<$cls>) -> $crate::result::JsResult<$crate::types::JsValue> {
                                  $body
                              }

                              $crate::macro_internal::MethodCallback(_______method_rust_y_u_no_hygienic_items_______)
                          }) ;
                          $($rest)*);
    };

    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:tt ; $call_ctor:tt ; $new_ctor:tt ; $mnames:tt ; $mdefs:tt ; constructor($cx:pat) $body:block $($rest:tt)* ) => {
        class_definition!($cls ;
                          $cname ;
                          $typ ;
                          $allocator ;
                          $call_ctor ;
                          ({
                              fn _______constructor_rust_y_u_no_hygienic_items_______($cx: $crate::context::CallContext<$cls>) -> $crate::result::NeonResult<Option<$crate::handle::Handle<$crate::types::JsObject>>> {
                                  $body
                              }

                              $crate::macro_internal::ConstructCallback(_______constructor_rust_y_u_no_hygienic_items_______)
                          }) ;
                          $mnames ;
                          $mdefs ;
                          $($rest)*);
    };

    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:tt ; $call_ctor:tt ; $new_ctor:tt ; $mnames:tt ; $mdefs:tt ; call($cx:pat) $body:block $($rest:tt)* ) => {
        class_definition!($cls ;
                          $cname ;
                          $typ ;
                          $allocator ;
                          ({
                              fn _______call_rust_y_u_no_hygienic_items_______($cx: $crate::context::CallContext<$crate::types::JsValue>) -> $crate::result::JsResult<$crate::types::JsValue> {
                                  $body
                              }

                              $crate::macro_internal::ConstructorCallCallback(_______call_rust_y_u_no_hygienic_items_______)
                          }) ;
                          $new_ctor ;
                          $mnames ;
                          $mdefs ;
                          $($rest)*);
    };

    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:block ; ($($call_ctor:block)*) ; ($($new_ctor:block)*) ; ($($mname:ident)*) ; ($($mdef:block)*) ; $($rest:tt)* ) => {
        impl $crate::object::Class for $cls {
            type Internals = $typ;

            fn setup<'a, C: $crate::context::Context<'a>>(_: &mut C) -> $crate::result::NeonResult<$crate::object::ClassDescriptor<'a, Self>> {
                ::std::result::Result::Ok(Self::describe(stringify!($cname), $allocator)
                                             $(.construct($new_ctor))*
                                             $(.call($call_ctor))*
                                             $(.method(stringify!($mname), $mdef))*)
            }
        }
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! impl_managed {
    ($cls:ident) => {
        impl $crate::handle::Managed for $cls {
            fn to_raw(self) -> $crate::macro_internal::runtime::raw::Local {
                let $cls(raw) = self;
                raw
            }

            fn from_raw(raw: $crate::macro_internal::runtime::raw::Local) -> Self {
                $cls(raw)
            }
        }
    }
}

/// Declare custom native JavaScript types with Rust implementations.
///
/// Example:
///
/// ```rust
/// # #[macro_use] extern crate neon;
/// # use neon::prelude::*;
/// # fn main() {}
/// pub struct Greeter {
///     greeting: String
/// }
///
/// declare_types! {
///
///     /// A class for generating greeting strings.
///     pub class JsGreeter for Greeter {
///         init(mut cx) {
///             let greeting = cx.argument::<JsString>(0)?.to_string(&mut cx)?.value();
///             Ok(Greeter {
///                 greeting: greeting
///             })
///         }
///
///         method hello(mut cx) {
///             let name = cx.argument::<JsString>(0)?.to_string(&mut cx)?.value();
///             let this = cx.this();
///             let msg = {
///                 let guard = cx.lock();
///                 let greeter = this.borrow(&guard);
///                 format!("{}, {}!", greeter.greeting, name)
///             };
///             Ok(cx.string(&msg[..]).upcast())
///         }
///     }
///
/// }
/// ```
#[macro_export]
macro_rules! declare_types {
    { $(#[$attr:meta])* pub class $cls:ident for $typ:ident { $($body:tt)* } $($rest:tt)* } => {
        declare_types! { $(#[$attr])* pub class $cls as $typ for $typ { $($body)* } $($rest)* }
    };

    { $(#[$attr:meta])* class $cls:ident for $typ:ident { $($body:tt)* } $($rest:tt)* } => {
        declare_types! { $(#[$attr])* class $cls as $typ for $typ { $($body)* } $($rest)* }
    };

    { $(#[$attr:meta])* pub class $cls:ident as $cname:ident for $typ:ty { $($body:tt)* } $($rest:tt)* } => {
        #[derive(Copy, Clone)]
        #[repr(C)]
        $(#[$attr])*
        pub struct $cls($crate::macro_internal::runtime::raw::Local);

        impl_managed!($cls);

        class_definition!($cls ; $cname ; $typ ; () ; () ; () ; () ; () ; $($body)*);

        declare_types! { $($rest)* }
    };

    { $(#[$attr:meta])* class $cls:ident as $cname:ident for $typ:ty { $($body:tt)* } $($rest:tt)* } => {
        #[derive(Copy, Clone)]
        #[repr(C)]
        $(#[$attr])*
        struct $cls($crate::macro_internal::runtime::raw::Local);

        impl_managed!($cls);

        class_definition!($cls ; $cname ; $typ ; () ; () ; () ; () ; () ; $($body)*);

        declare_types! { $($rest)* }
    };

    { } => { };
}

#[cfg(all(windows, not(neon_profile = "release")))]
compile_error!("Neon only builds with --release. For tests, try `cargo test --release`.");

#[cfg(test)]
mod tests {
    use std::path::{Path, PathBuf};
    use std::process::Command;
    use std::sync::Mutex;

    use rustc_version::{version_meta, Channel};

    // Create a mutex to enforce sequential running of the tests.
    lazy_static! {
        static ref TEST_MUTEX: Mutex<()> = Mutex::new(());
    }

    fn project_root() -> PathBuf {
        Path::new(env!("CARGO_MANIFEST_DIR")).to_path_buf()
    }

    fn log(test_name: &str) {
        eprintln!("======================================================");
        eprintln!("Neon test: {}", test_name);
        eprintln!("======================================================");
    }

    fn run(cmd: &str, dir: &Path) {
        let (shell, command_flag) = if cfg!(windows) {
            ("cmd", "/C")
        } else {
            ("sh", "-c")
        };

        assert!(Command::new(&shell)
                        .current_dir(dir)
                        .args(&[&command_flag, cmd])
                        .status()
                        .expect("failed to execute test command")
                        .success());
    }

    fn cli_setup() {
        let cli = project_root().join("cli");

        run("npm install", &cli);
        run("npm run transpile", &cli);
    }

    #[test]
    fn cli_test() {
        let _guard = TEST_MUTEX.lock();

        log("cli_test");

        cli_setup();

        let test_cli = project_root().join("test").join("cli");
        run("npm install", &test_cli);
        run("npm run transpile", &test_cli);
        run("npm test", &test_cli);
    }

    #[cfg(not(windows))]
    #[test]
    fn static_test() {
        let _guard = TEST_MUTEX.lock();

        log("static_test");

        if version_meta().unwrap().channel != Channel::Nightly {
            return;
        }

        run("cargo test --release", &project_root().join("test").join("static"));
    }

    #[test]
    fn dynamic_test() {
        let _guard = TEST_MUTEX.lock();

        log("dynamic_test");

        cli_setup();

        let test_dynamic = project_root().join("test").join("dynamic");
        run("npm install", &test_dynamic);
        run("npm test", &test_dynamic);
    }
}
<|endoftext|>


<commit_before>use std::str::FromStr;

pub trait TryFrom<T>: Sized {
    type Err;
    fn try_from(T) -> Result<Self, Self::Err>;
}

pub trait TryInto<T>: Sized {
    type Err;
    fn try_into(self) -> Result<T, Self::Err>;
}

impl<T, U> TryInto<U> for T where U: TryFrom<T> {
    type Err = U::Err;
    fn try_into(self) -> Result<U, U::Err> {
        U::try_from(self)
    }
}

impl<'a, T> TryFrom<&'a str> for T where T: FromStr {
    type Err = T::Err;
    fn try_from(string: &'a str) -> Result<Self, Self::Err> {
        T::from_str(string)
    }
}

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

    #[test]
    fn should_have_try_from_impl_for_from_str() {
        let result = u32::try_from("3");
        assert_eq!(result.unwrap(), 3)
    }

    #[test]
    fn should_have_try_into_impl_for_from_str() {
        let result: Result<u32, num::ParseIntError> = "3".try_into();
        assert_eq!(result.unwrap(), 3)
    }
}
<commit_msg>add failure test<commit_after>use std::str::FromStr;

pub trait TryFrom<T>: Sized {
    type Err;
    fn try_from(T) -> Result<Self, Self::Err>;
}

pub trait TryInto<T>: Sized {
    type Err;
    fn try_into(self) -> Result<T, Self::Err>;
}

impl<T, U> TryInto<U> for T where U: TryFrom<T> {
    type Err = U::Err;
    fn try_into(self) -> Result<U, U::Err> {
        U::try_from(self)
    }
}

impl<'a, T> TryFrom<&'a str> for T where T: FromStr {
    type Err = T::Err;
    fn try_from(string: &'a str) -> Result<Self, Self::Err> {
        T::from_str(string)
    }
}

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

    #[test]
    fn should_have_try_from_impl_for_from_str() {
        let result = u32::try_from("3");
        assert_eq!(result.unwrap(), 3)
    }

    #[test]
    fn should_have_try_from_impl_for_from_str_that_handles_err() {
        let result = u32::try_from("hello");
        assert_eq!(format!("{}", result.unwrap_err()), "invalid digit found in string")
    }

    #[test]
    fn should_have_try_into_impl_for_from_str() {
        let result: Result<u32, num::ParseIntError> = "3".try_into();
        assert_eq!(result.unwrap(), 3)
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Used for `header!` macro which cannot be correctly resolved as it is exported as `hyper::header`
// which is also a module name.
#[macro_use]
extern crate hyper;
// Convenience importing of `debug!`/`info!` macros for entire crate.
#[macro_use]
extern crate log;

mod api_client;
mod error;
mod net;
pub mod proxy;
pub mod util;

pub use crate::api_client::ApiClient;
pub use crate::error::{Error, Result};

#[cfg(not(target_os = "macos"))]
mod ssl {
    use std::fs::{self, File};
    use std::io::Write;
    use std::path::Path;
    use std::str::FromStr;

    use habitat_core::env;
    use habitat_core::fs::cache_ssl_path;
    use habitat_core::package::{PackageIdent, PackageInstall};
    use openssl::ssl::SslContextBuilder;

    use crate::error::Result;

    const CACERTS_PKG_IDENT: &str = "core/cacerts";
    const CACERT_PEM: &str = include_str!(concat!(env!("OUT_DIR"), "/cacert.pem"));

    pub fn set_ca(ctx: &mut SslContextBuilder, fs_root_path: Option<&Path>) -> Result<()> {
        let cacerts_ident = PackageIdent::from_str(CACERTS_PKG_IDENT)?;

        if let Ok(_) = env::var("SSL_CERT_FILE") {
            ctx.set_default_verify_paths()?;
        } else if let Ok(_) = env::var("SSL_CERT_DIR") {
            ctx.set_default_verify_paths()?;
        } else if let Ok(pkg_install) = PackageInstall::load(&cacerts_ident, fs_root_path) {
            let pkg_certs = pkg_install.installed_path().join("ssl/cert.pem");
            debug!(
                "Setting CA file for SSL context to: {}",
                pkg_certs.display()
            );
            ctx.set_ca_file(pkg_certs)?;
        } else {
            let cached_certs = cache_ssl_path(fs_root_path).join("cert.pem");
            if !cached_certs.exists() {
                fs::create_dir_all(cache_ssl_path(fs_root_path))?;
                debug!("Creating cached cacert.pem at: {}", cached_certs.display());
                let mut file = File::create(&cached_certs)?;
                file.write_all(CACERT_PEM.as_bytes())?;
            }
            debug!(
                "Setting CA file for SSL context to: {}",
                cached_certs.display()
            );
            ctx.set_ca_file(cached_certs)?;
        }
        Ok(())
    }
}

#[cfg(target_os = "macos")]
mod ssl {
    use std::path::Path;

    use openssl::ssl::SslContextBuilder;

    use crate::error::Result;

    pub fn set_ca(ctx: &mut SslContextBuilder, _fs_root_path: Option<&Path>) -> Result<()> {
        ctx.set_default_verify_paths()?;
        Ok(())
    }
}
<commit_msg>Examine clippy::redundant_pattern_matching<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Used for `header!` macro which cannot be correctly resolved as it is exported as `hyper::header`
// which is also a module name.
#[macro_use]
extern crate hyper;
// Convenience importing of `debug!`/`info!` macros for entire crate.
#[macro_use]
extern crate log;

mod api_client;
mod error;
mod net;
pub mod proxy;
pub mod util;

pub use crate::api_client::ApiClient;
pub use crate::error::{Error, Result};

#[cfg(not(target_os = "macos"))]
mod ssl {
    use std::fs::{self, File};
    use std::io::Write;
    use std::path::Path;
    use std::str::FromStr;

    use habitat_core::env;
    use habitat_core::fs::cache_ssl_path;
    use habitat_core::package::{PackageIdent, PackageInstall};
    use openssl::ssl::SslContextBuilder;

    use crate::error::Result;

    const CACERTS_PKG_IDENT: &str = "core/cacerts";
    const CACERT_PEM: &str = include_str!(concat!(env!("OUT_DIR"), "/cacert.pem"));

    pub fn set_ca(ctx: &mut SslContextBuilder, fs_root_path: Option<&Path>) -> Result<()> {
        let cacerts_ident = PackageIdent::from_str(CACERTS_PKG_IDENT)?;

        if env::var("SSL_CERT_FILE").is_ok() || env::var("SSL_CERT_DIR").is_ok() {
            ctx.set_default_verify_paths()?;
        } else if let Ok(pkg_install) = PackageInstall::load(&cacerts_ident, fs_root_path) {
            let pkg_certs = pkg_install.installed_path().join("ssl/cert.pem");
            debug!(
                "Setting CA file for SSL context to: {}",
                pkg_certs.display()
            );
            ctx.set_ca_file(pkg_certs)?;
        } else {
            let cached_certs = cache_ssl_path(fs_root_path).join("cert.pem");
            if !cached_certs.exists() {
                fs::create_dir_all(cache_ssl_path(fs_root_path))?;
                debug!("Creating cached cacert.pem at: {}", cached_certs.display());
                let mut file = File::create(&cached_certs)?;
                file.write_all(CACERT_PEM.as_bytes())?;
            }
            debug!(
                "Setting CA file for SSL context to: {}",
                cached_certs.display()
            );
            ctx.set_ca_file(cached_certs)?;
        }
        Ok(())
    }
}

#[cfg(target_os = "macos")]
mod ssl {
    use std::path::Path;

    use openssl::ssl::SslContextBuilder;

    use crate::error::Result;

    pub fn set_ca(ctx: &mut SslContextBuilder, _fs_root_path: Option<&Path>) -> Result<()> {
        ctx.set_default_verify_paths()?;
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! This crate provides functionality to execute a daily schedule for home
//! automation purposes. It provided a variety to schedule tasks in a day.
//!
//! The purpose of this crate is only calculation of execution times, but
//! doesn't perform the actual execution of the schedule loop.
//!
//! It doesn't rely on system time on purpose to allow easier testing and
//! qualification, without considering the real-time aspects. All
//! calculated timestamps are UTC based and any local-time conversion are
//! based on the zoneinfo crate.
extern crate rand;
extern crate time;
extern crate zoneinfo;

use time::{Timespec, Duration, at_utc};
use std::collections::BTreeMap;
use std::rc::Rc;
use rand::{Rng, thread_rng};
use zoneinfo::{ZoneInfo, ZoneInfoElement};
use std::io::Result;

/// Represents a fixed moment in a day
pub enum Moment {
    /// Duration is offset in time based on local midnight
    LocalTime(Duration),
    /// Duration is offset in time based on UTC midnight
    UtcTime(Duration)
}

/// Local time definition
enum LocalTimeState {
    /// Zone-info state is not loaded yet
    Unknown,
    /// Current zone-info specifies no future daylight saving time change is expected
    NoChangePending(ZoneInfoElement),
    /// Daylight saving time change is pending
    ChangePending(Timespec, // transition time
                  ZoneInfoElement, // zone information before transition time
                  ZoneInfoElement) // zone information at and after transition time
}

impl Moment {
    /// Create a moment in a day
    pub fn new(h:u8, m:u8, s:u8) -> Moment {
        Moment::LocalTime(
            Duration::hours(h as i64) +
            Duration::minutes(m as i64) +
            Duration::seconds(s as i64))
    }

    /// Create a moment in a day based on Timespec
    pub fn new_from_timespec(ts: Timespec) -> Moment {
        let mut tm_utc = at_utc(ts);

        tm_utc.tm_hour = 0;
        tm_utc.tm_min = 0;
        tm_utc.tm_sec = 0;
        tm_utc.tm_nsec = 0;

        Moment::UtcTime(ts - tm_utc.to_timespec())
    }

    /// Convert schedule time to actual time stamp
    fn create_timestamp(&self, ut_midnight_reference: Timespec,
                        localtime: &LocalTimeState) -> Timespec {
        match self {
            // timestamp is simply a reference to UTC so just add the offset
            &Moment::UtcTime(offset) => ut_midnight_reference + offset,
            // timestamp is a reference to the moment in a day
            &Moment::LocalTime(offset) => {
                let pre_localtime_cor = ut_midnight_reference + offset;

                let ut_offset = match *localtime {
                    LocalTimeState::NoChangePending(ref info) => info.ut_offset,
                    LocalTimeState::ChangePending(transition_time, ref before, ref after) => {
                        let reftime = Timespec::new(pre_localtime_cor.sec - before.ut_offset as i64,
                                                    pre_localtime_cor.nsec);
                        if reftime < transition_time {
                            before.ut_offset
                        } else {
                            after.ut_offset
                        }
                    }
                    _ => unreachable!()
                };

                Timespec::new(pre_localtime_cor.sec - ut_offset as i64, pre_localtime_cor.nsec)
            }
        }
    }
}

impl std::fmt::Debug for Moment {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        let duration = match self {
            &Moment::UtcTime(d) => d,
            &Moment::LocalTime(d) => d,
        };
        try!(write!(fmt, "{:02}:{:02}:{:02}", duration.num_hours(), duration.num_minutes() % 60, duration.num_seconds() % 60));
        if let &Moment::UtcTime(_) = self {
            try!(write!(fmt, " (UTC)"));
        }
        Ok(())
    }
}

/// Weekday filter specifier
pub enum Filter {
    /// Always execute  event
    Always,
    /// Only execute Monday till Friday
    MonToFri,
    /// Only execute Saturday and Sunday
    Weekend // FIXME: more abstractions?
}

impl Filter {
    /// Indicate whether given time is valid to be scheduled based on weekday
    fn filter_days(&self, time: Timespec, zoneinfo: &ZoneInfoElement) -> bool {
        // make sure reference time is in the same weekday in UTC as it would be
        // in local time.
        let ref_time = Timespec::new(time.sec + zoneinfo.ut_offset as i64, time.nsec);
        let wday = at_utc(ref_time).tm_wday;
        let weekend = wday == 0 || wday == 6; // 0 = Sunday, 6 = Saturday

        match self {
            &Filter::Always => true,
            &Filter::MonToFri => !weekend,
            &Filter::Weekend => weekend
        }
    }

    /// Indicate whether given time is valid to be scheduled based on weekday
    fn day_scheduled(&self, time: Timespec, localtime: &LocalTimeState) -> bool {
        match self {
            &Filter::Always => true,
            &Filter::MonToFri|&Filter::Weekend => {
                let zoneinfo = match localtime {
                    &LocalTimeState::NoChangePending(ref zoneinfo) => zoneinfo,
                    &LocalTimeState::ChangePending(ref transition, ref z1, ref z2) => {
                        if time < *transition {
                            z1
                        } else {
                            z2
                        }
                    }
                    _ => unreachable!()
                };

                self.filter_days(time, zoneinfo)
            },
        }
    }
}

/// Represent a (abstract) moment in a day
pub enum DailyEvent {
    /// A fixed moment in a day
    Fixed(Filter, Moment),
    /// A random moment between two given fixed moments
    Fuzzy(Filter, Moment, Moment),
    /// A externally provided moment in time + variance
    ByClosure(Filter, Box<Fn(Timespec) -> Moment>, Duration)
}

impl std::fmt::Debug for DailyEvent {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            &DailyEvent::Fixed(_, ref t) => write!(fmt, "Fixed {:?}", t),
            &DailyEvent::Fuzzy(_, ref b, ref a) => write!(fmt, "Fuzzy {:?} ~ {:?}", b, a),
            &DailyEvent::ByClosure(_, _, ref variance) =>
                write!(fmt, "ByClosure ~{:?}s", variance.num_seconds()),
        }
    }
}

/// Represents a moment and an specific action in a day
struct Event<C: Eq+PartialEq, H: Handler<C>> {
    /// A moment in a day
    moment: DailyEvent,
    /// Reference to a action handler
    action: Rc<H>,
    /// Externally provided reference for the implementor
    context: C
}

impl<C: Eq+PartialEq, H: Handler<C>> Event<C, H> {
    /// Determine time-stamp for event
    fn create_timestamp(&self, ut_midnight_reference: Timespec,
                        localtime: &LocalTimeState) -> Option<Timespec> {
        let ts = match self.moment {
            DailyEvent::Fixed(_, ref moment) =>
                moment.create_timestamp(ut_midnight_reference, localtime),
            DailyEvent::Fuzzy(_, ref m1, ref m2) => {
                // pick a time between both given moment
                let mut rng = rand::thread_rng();
                let t1 = m1.create_timestamp(ut_midnight_reference, localtime);
                let t2 = m2.create_timestamp(ut_midnight_reference, localtime);
                let t_start = if t1 >= t2 {t2} else {t1};
                let t_end = if t1 >= t2 {t1} else {t2};
                let duration = t_end - t_start;
                if duration > Duration::seconds(0) {
                    t_start + Duration::seconds(rng.gen_range(0, duration.num_seconds()))
                } else {
                    t_start
                }
            }
            DailyEvent::ByClosure(_, ref func, ref variance) => {
                let moment = func(ut_midnight_reference);
                // generate a offset based on variance compared to the generated moment
                let mut rng = rand::thread_rng();
                let offset = if *variance > Duration::seconds(0) {
                    rng.gen_range(0, variance.num_seconds())
                } else {
                    0
                };
                let offset = Duration::seconds(variance.num_seconds() / 2 - offset);
                moment.create_timestamp(ut_midnight_reference, localtime) + offset
            }
        };
        let do_schedule = match self.moment {
            DailyEvent::Fixed(ref w, _) |
            DailyEvent::Fuzzy(ref w, _, _) |
            DailyEvent::ByClosure(ref w, _, _) => w.day_scheduled(ts, localtime)
        };

        if do_schedule {
            Some(ts)
        } else {
            None
        }
    }
}

/// Trait to be implemented by the event handler
pub trait Handler<C: Eq + PartialEq> {
    /// Hint for future events
    fn hint(&self, timestamp: &Timespec, context: &C);
    /// Perform a action (in a day)
    fn kick(&self, timestamp: &Timespec, context: &C);
}

/// Calculates and executes scheduled events every day
pub struct Schedule<C: Eq + PartialEq, H: Handler<C>> {
    // List of (abstract) moments in a day
    events: Vec<Rc<Event<C, H>>>,

    // Time zone related information
    zoneinfo: ZoneInfo,

    // Next zone change
    localtime: LocalTimeState,

    // Tree of actual scheduled moments and reference to the abstract moment in a day
    schedule: BTreeMap<Timespec, Vec<Rc<Event<C, H>>>>
}

impl<C: Eq + PartialEq, H: Handler<C>> Schedule<C, H> {
    /// Create a (empty) list of scheduled daily events
    pub fn new(zoneinfo: ZoneInfo) -> Schedule<C, H> {
        Schedule {
            events: vec![],
            zoneinfo: zoneinfo,
            localtime: LocalTimeState::Unknown,
            schedule: BTreeMap::new()
        }
    }

    /// Create a (empty) list of scheduled daily events based on the default zoneinfo (local time
    /// settings)
    pub fn new_local() -> Result<Schedule<C, H>> {
        Ok(Schedule::new(try!(ZoneInfo::get_local_zoneinfo())))
    }

    /// Add a (abstract) moment and action in a day
    pub fn add_event(&mut self,
                     moment: DailyEvent,
                     action: Rc<H>,
                     context: C) {
        self.events.push(Rc::new(Event {
            moment: moment,
            action: action,
            context: context
        }));
    }

    /// Determine next zone info state
    fn new_change_state(&self, timestamp: Timespec) -> LocalTimeState {
        // yes, a unwrap, since a serious problem be present when no zone-info could be retrieved
        let actual = self.zoneinfo.get_actual_zoneinfo(timestamp).unwrap();
        match self.zoneinfo.get_next_transition_time(timestamp) {
            Some((next_change, next)) =>
                LocalTimeState::ChangePending(next_change, actual, next),
            None => LocalTimeState::NoChangePending(actual)
        }
    }

    /// Update the schedule for 24 hours (only use with 24 hour incrementing timestamps,
    /// preferably every day)
    pub fn update_schedule(&mut self, ut_midnight_reference: Timespec) {
        match self.localtime {
            LocalTimeState::Unknown =>
                self.localtime = self.new_change_state(ut_midnight_reference),
            LocalTimeState::ChangePending(time, _, _) => {
                if time <= ut_midnight_reference {
                    self.localtime = self.new_change_state(ut_midnight_reference);
                }
            },
            _ => {}
        }

        for event in &self.events {
            let timestamp = event.create_timestamp(ut_midnight_reference, &self.localtime);
            if let Some(timestamp) = timestamp {
                event.action.hint(&timestamp, &event.context);

                let event_cloned = event.clone();

                if self.schedule.contains_key(&timestamp) {
                    self.schedule.get_mut(&timestamp).unwrap().push(event_cloned);
                } else {
                    self.schedule.insert(timestamp, vec![event_cloned]);
                }
            }
        }
    }

    /// Consume schedule until provided moment `now` and kick last or current event and returns next event time
    pub fn kick_event(&mut self, now: Timespec) -> Option<Timespec> {
        let past_events: Vec<Timespec> = self.schedule.keys().filter(|&k| *k <= now).cloned().collect();

        // kick the current event...
        if let Some(timestamp) = past_events.last() {
            if let Some(schedule_events) = self.schedule.get(timestamp) {
                for schedule_event in schedule_events {
                    schedule_event.action.kick(&timestamp, &schedule_event.context);
                }
            }
        }

        // ...and consume that and prior events
        for past_event in past_events {
            self.schedule.remove(&past_event);
        }

        self.schedule.keys().cloned().nth(0)
    }

    /// Peek when next event will happen
    pub fn peek_event(&self) -> Option<Timespec> {
        self.schedule.keys().cloned().nth(0)
    }
}
<commit_msg>Bugfix: kick every past scheduled event<commit_after>//! This crate provides functionality to execute a daily schedule for home
//! automation purposes. It provided a variety to schedule tasks in a day.
//!
//! The purpose of this crate is only calculation of execution times, but
//! doesn't perform the actual execution of the schedule loop.
//!
//! It doesn't rely on system time on purpose to allow easier testing and
//! qualification, without considering the real-time aspects. All
//! calculated timestamps are UTC based and any local-time conversion are
//! based on the zoneinfo crate.
extern crate rand;
extern crate time;
extern crate zoneinfo;

use time::{Timespec, Duration, at_utc};
use std::collections::BTreeMap;
use std::rc::Rc;
use rand::{Rng, thread_rng};
use zoneinfo::{ZoneInfo, ZoneInfoElement};
use std::io::Result;

/// Represents a fixed moment in a day
pub enum Moment {
    /// Duration is offset in time based on local midnight
    LocalTime(Duration),
    /// Duration is offset in time based on UTC midnight
    UtcTime(Duration)
}

/// Local time definition
enum LocalTimeState {
    /// Zone-info state is not loaded yet
    Unknown,
    /// Current zone-info specifies no future daylight saving time change is expected
    NoChangePending(ZoneInfoElement),
    /// Daylight saving time change is pending
    ChangePending(Timespec, // transition time
                  ZoneInfoElement, // zone information before transition time
                  ZoneInfoElement) // zone information at and after transition time
}

impl Moment {
    /// Create a moment in a day
    pub fn new(h:u8, m:u8, s:u8) -> Moment {
        Moment::LocalTime(
            Duration::hours(h as i64) +
            Duration::minutes(m as i64) +
            Duration::seconds(s as i64))
    }

    /// Create a moment in a day based on Timespec
    pub fn new_from_timespec(ts: Timespec) -> Moment {
        let mut tm_utc = at_utc(ts);

        tm_utc.tm_hour = 0;
        tm_utc.tm_min = 0;
        tm_utc.tm_sec = 0;
        tm_utc.tm_nsec = 0;

        Moment::UtcTime(ts - tm_utc.to_timespec())
    }

    /// Convert schedule time to actual time stamp
    fn create_timestamp(&self, ut_midnight_reference: Timespec,
                        localtime: &LocalTimeState) -> Timespec {
        match self {
            // timestamp is simply a reference to UTC so just add the offset
            &Moment::UtcTime(offset) => ut_midnight_reference + offset,
            // timestamp is a reference to the moment in a day
            &Moment::LocalTime(offset) => {
                let pre_localtime_cor = ut_midnight_reference + offset;

                let ut_offset = match *localtime {
                    LocalTimeState::NoChangePending(ref info) => info.ut_offset,
                    LocalTimeState::ChangePending(transition_time, ref before, ref after) => {
                        let reftime = Timespec::new(pre_localtime_cor.sec - before.ut_offset as i64,
                                                    pre_localtime_cor.nsec);
                        if reftime < transition_time {
                            before.ut_offset
                        } else {
                            after.ut_offset
                        }
                    }
                    _ => unreachable!()
                };

                Timespec::new(pre_localtime_cor.sec - ut_offset as i64, pre_localtime_cor.nsec)
            }
        }
    }
}

impl std::fmt::Debug for Moment {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        let duration = match self {
            &Moment::UtcTime(d) => d,
            &Moment::LocalTime(d) => d,
        };
        try!(write!(fmt, "{:02}:{:02}:{:02}", duration.num_hours(), duration.num_minutes() % 60, duration.num_seconds() % 60));
        if let &Moment::UtcTime(_) = self {
            try!(write!(fmt, " (UTC)"));
        }
        Ok(())
    }
}

/// Weekday filter specifier
pub enum Filter {
    /// Always execute  event
    Always,
    /// Only execute Monday till Friday
    MonToFri,
    /// Only execute Saturday and Sunday
    Weekend // FIXME: more abstractions?
}

impl Filter {
    /// Indicate whether given time is valid to be scheduled based on weekday
    fn filter_days(&self, time: Timespec, zoneinfo: &ZoneInfoElement) -> bool {
        // make sure reference time is in the same weekday in UTC as it would be
        // in local time.
        let ref_time = Timespec::new(time.sec + zoneinfo.ut_offset as i64, time.nsec);
        let wday = at_utc(ref_time).tm_wday;
        let weekend = wday == 0 || wday == 6; // 0 = Sunday, 6 = Saturday

        match self {
            &Filter::Always => true,
            &Filter::MonToFri => !weekend,
            &Filter::Weekend => weekend
        }
    }

    /// Indicate whether given time is valid to be scheduled based on weekday
    fn day_scheduled(&self, time: Timespec, localtime: &LocalTimeState) -> bool {
        match self {
            &Filter::Always => true,
            &Filter::MonToFri|&Filter::Weekend => {
                let zoneinfo = match localtime {
                    &LocalTimeState::NoChangePending(ref zoneinfo) => zoneinfo,
                    &LocalTimeState::ChangePending(ref transition, ref z1, ref z2) => {
                        if time < *transition {
                            z1
                        } else {
                            z2
                        }
                    }
                    _ => unreachable!()
                };

                self.filter_days(time, zoneinfo)
            },
        }
    }
}

/// Represent a (abstract) moment in a day
pub enum DailyEvent {
    /// A fixed moment in a day
    Fixed(Filter, Moment),
    /// A random moment between two given fixed moments
    Fuzzy(Filter, Moment, Moment),
    /// A externally provided moment in time + variance
    ByClosure(Filter, Box<Fn(Timespec) -> Moment>, Duration)
}

impl std::fmt::Debug for DailyEvent {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            &DailyEvent::Fixed(_, ref t) => write!(fmt, "Fixed {:?}", t),
            &DailyEvent::Fuzzy(_, ref b, ref a) => write!(fmt, "Fuzzy {:?} ~ {:?}", b, a),
            &DailyEvent::ByClosure(_, _, ref variance) =>
                write!(fmt, "ByClosure ~{:?}s", variance.num_seconds()),
        }
    }
}

/// Represents a moment and an specific action in a day
struct Event<C: Eq+PartialEq, H: Handler<C>> {
    /// A moment in a day
    moment: DailyEvent,
    /// Reference to a action handler
    action: Rc<H>,
    /// Externally provided reference for the implementor
    context: C
}

impl<C: Eq+PartialEq, H: Handler<C>> Event<C, H> {
    /// Determine time-stamp for event
    fn create_timestamp(&self, ut_midnight_reference: Timespec,
                        localtime: &LocalTimeState) -> Option<Timespec> {
        let ts = match self.moment {
            DailyEvent::Fixed(_, ref moment) =>
                moment.create_timestamp(ut_midnight_reference, localtime),
            DailyEvent::Fuzzy(_, ref m1, ref m2) => {
                // pick a time between both given moment
                let mut rng = rand::thread_rng();
                let t1 = m1.create_timestamp(ut_midnight_reference, localtime);
                let t2 = m2.create_timestamp(ut_midnight_reference, localtime);
                let t_start = if t1 >= t2 {t2} else {t1};
                let t_end = if t1 >= t2 {t1} else {t2};
                let duration = t_end - t_start;
                if duration > Duration::seconds(0) {
                    t_start + Duration::seconds(rng.gen_range(0, duration.num_seconds()))
                } else {
                    t_start
                }
            }
            DailyEvent::ByClosure(_, ref func, ref variance) => {
                let moment = func(ut_midnight_reference);
                // generate a offset based on variance compared to the generated moment
                let mut rng = rand::thread_rng();
                let offset = if *variance > Duration::seconds(0) {
                    rng.gen_range(0, variance.num_seconds())
                } else {
                    0
                };
                let offset = Duration::seconds(variance.num_seconds() / 2 - offset);
                moment.create_timestamp(ut_midnight_reference, localtime) + offset
            }
        };
        let do_schedule = match self.moment {
            DailyEvent::Fixed(ref w, _) |
            DailyEvent::Fuzzy(ref w, _, _) |
            DailyEvent::ByClosure(ref w, _, _) => w.day_scheduled(ts, localtime)
        };

        if do_schedule {
            Some(ts)
        } else {
            None
        }
    }
}

/// Trait to be implemented by the event handler
pub trait Handler<C: Eq + PartialEq> {
    /// Hint for future events
    fn hint(&self, timestamp: &Timespec, context: &C);
    /// Perform a action (in a day)
    fn kick(&self, timestamp: &Timespec, context: &C);
}

/// Calculates and executes scheduled events every day
pub struct Schedule<C: Eq + PartialEq, H: Handler<C>> {
    // List of (abstract) moments in a day
    events: Vec<Rc<Event<C, H>>>,

    // Time zone related information
    zoneinfo: ZoneInfo,

    // Next zone change
    localtime: LocalTimeState,

    // Tree of actual scheduled moments and reference to the abstract moment in a day
    schedule: BTreeMap<Timespec, Vec<Rc<Event<C, H>>>>
}

impl<C: Eq + PartialEq, H: Handler<C>> Schedule<C, H> {
    /// Create a (empty) list of scheduled daily events
    pub fn new(zoneinfo: ZoneInfo) -> Schedule<C, H> {
        Schedule {
            events: vec![],
            zoneinfo: zoneinfo,
            localtime: LocalTimeState::Unknown,
            schedule: BTreeMap::new()
        }
    }

    /// Create a (empty) list of scheduled daily events based on the default zoneinfo (local time
    /// settings)
    pub fn new_local() -> Result<Schedule<C, H>> {
        Ok(Schedule::new(try!(ZoneInfo::get_local_zoneinfo())))
    }

    /// Add a (abstract) moment and action in a day
    pub fn add_event(&mut self,
                     moment: DailyEvent,
                     action: Rc<H>,
                     context: C) {
        self.events.push(Rc::new(Event {
            moment: moment,
            action: action,
            context: context
        }));
    }

    /// Determine next zone info state
    fn new_change_state(&self, timestamp: Timespec) -> LocalTimeState {
        // yes, a unwrap, since a serious problem be present when no zone-info could be retrieved
        let actual = self.zoneinfo.get_actual_zoneinfo(timestamp).unwrap();
        match self.zoneinfo.get_next_transition_time(timestamp) {
            Some((next_change, next)) =>
                LocalTimeState::ChangePending(next_change, actual, next),
            None => LocalTimeState::NoChangePending(actual)
        }
    }

    /// Update the schedule for 24 hours (only use with 24 hour incrementing timestamps,
    /// preferably every day)
    pub fn update_schedule(&mut self, ut_midnight_reference: Timespec) {
        match self.localtime {
            LocalTimeState::Unknown =>
                self.localtime = self.new_change_state(ut_midnight_reference),
            LocalTimeState::ChangePending(time, _, _) => {
                if time <= ut_midnight_reference {
                    self.localtime = self.new_change_state(ut_midnight_reference);
                }
            },
            _ => {}
        }

        for event in &self.events {
            let timestamp = event.create_timestamp(ut_midnight_reference, &self.localtime);
            if let Some(timestamp) = timestamp {
                event.action.hint(&timestamp, &event.context);

                let event_cloned = event.clone();

                if self.schedule.contains_key(&timestamp) {
                    self.schedule.get_mut(&timestamp).unwrap().push(event_cloned);
                } else {
                    self.schedule.insert(timestamp, vec![event_cloned]);
                }
            }
        }
    }

    /// Consume schedule until provided moment `now` and kick last or current event and returns next event time
    pub fn kick_event(&mut self, now: Timespec) -> Option<Timespec> {
        let past_events: Vec<Timespec> = self.schedule.keys().filter(|&k| *k <= now).cloned().collect();

        // kick the current event...
        for timestamp in past_events.iter() {
            if let Some(schedule_events) = self.schedule.get(&timestamp) {
                for schedule_event in schedule_events {
                    schedule_event.action.kick(&timestamp, &schedule_event.context);
                }
            }
        }

        // ...and consume that and prior events
        for past_event in past_events {
            self.schedule.remove(&past_event);
        }

        self.schedule.keys().cloned().nth(0)
    }

    /// Peek when next event will happen
    pub fn peek_event(&self) -> Option<Timespec> {
        self.schedule.keys().cloned().nth(0)
    }
}
<|endoftext|>