<commit_before>//! The implementation is based on Dmitry Vyukov's bounded MPMC queue.
//!
//! Source:
//!   - http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue
//!
//! Copyright & License:
//!   - Copyright (c) 2010-2011 Dmitry Vyukov
//!   - Simplified BSD License and Apache License, Version 2.0
//!   - http://www.1024cores.net/home/code-license

use std::cell::UnsafeCell;
use std::fmt;
use std::marker::PhantomData;
use std::mem;
use std::ptr;
use std::sync::atomic::{self, AtomicUsize, Ordering};

use crossbeam_utils::{Backoff, CachePadded};

use err::{PopError, PushError};

/// A slot in a queue.
struct Slot<T> {
    /// The current stamp.
    ///
    /// If the stamp equals the tail, this node will be next written to. If it equals the head,
    /// this node will be next read from.
    stamp: AtomicUsize,

    /// The value in this slot.
    value: UnsafeCell<T>,
}

/// A bounded multi-producer multi-consumer queue.
///
/// This queue allocates a fixed-capacity buffer on construction, which is used to store pushed
/// elements. The queue cannot hold more elements than the buffer allows. Attempting to push an
/// element into a full queue will fail. Having a buffer allocated upfront makes this queue a bit
/// faster than [`SegQueue`].
///
/// [`SegQueue`]: struct.SegQueue.html
///
/// # Examples
///
/// ```
/// use crossbeam_queue::{ArrayQueue, PushError};
///
/// let q = ArrayQueue::new(2);
///
/// assert_eq!(q.push('a'), Ok(()));
/// assert_eq!(q.push('b'), Ok(()));
/// assert_eq!(q.push('c'), Err(PushError('c')));
/// assert_eq!(q.pop(), Ok('a'));
/// ```
pub struct ArrayQueue<T> {
    /// The head of the queue.
    ///
    /// This value is a "stamp" consisting of an index into the buffer and a lap, but packed into a
    /// single `usize`. The lower bits represent the index, while the upper bits represent the lap.
    ///
    /// Elements are popped from the head of the queue.
    head: CachePadded<AtomicUsize>,

    /// The tail of the queue.
    ///
    /// This value is a "stamp" consisting of an index into the buffer and a lap, but packed into a
    /// single `usize`. The lower bits represent the index, while the upper bits represent the lap.
    ///
    /// Elements are pushed into the tail of the queue.
    tail: CachePadded<AtomicUsize>,

    /// The buffer holding slots.
    buffer: *mut Slot<T>,

    /// The queue capacity.
    cap: usize,

    /// A stamp with the value of `{ lap: 1, index: 0 }`.
    one_lap: usize,

    /// Indicates that dropping an `ArrayQueue<T>` may drop elements of type `T`.
    _marker: PhantomData<T>,
}

unsafe impl<T: Send> Sync for ArrayQueue<T> {}
unsafe impl<T: Send> Send for ArrayQueue<T> {}

impl<T> ArrayQueue<T> {
    /// Creates a new bounded queue with the given capacity.
    ///
    /// # Panics
    ///
    /// Panics if the capacity is zero.
    ///
    /// # Examples
    ///
    /// ```
    /// use crossbeam_queue::ArrayQueue;
    ///
    /// let q = ArrayQueue::<i32>::new(100);
    /// ```
    pub fn new(cap: usize) -> ArrayQueue<T> {
        assert!(cap > 0, "capacity must be non-zero");

        // Head is initialized to `{ lap: 0, index: 0 }`.
        // Tail is initialized to `{ lap: 0, index: 0 }`.
        let head = 0;
        let tail = 0;

        // Allocate a buffer of `cap` slots.
        let buffer = {
            let mut v = Vec::<Slot<T>>::with_capacity(cap);
            let ptr = v.as_mut_ptr();
            mem::forget(v);
            ptr
        };

        // Initialize stamps in the slots.
        for i in 0..cap {
            unsafe {
                // Set the stamp to `{ lap: 0, index: i }`.
                let slot = buffer.add(i);
                ptr::write(&mut (*slot).stamp, AtomicUsize::new(i));
            }
        }

        // One lap is the smallest power of two greater than `cap`.
        let one_lap = (cap + 1).next_power_of_two();

        ArrayQueue {
            buffer,
            cap,
            one_lap,
            head: CachePadded::new(AtomicUsize::new(head)),
            tail: CachePadded::new(AtomicUsize::new(tail)),
            _marker: PhantomData,
        }
    }

    /// Attempts to push an element into the queue.
    ///
    /// If the queue is full, the element is returned back as an error.
    ///
    /// # Examples
    ///
    /// ```
    /// use crossbeam_queue::{ArrayQueue, PushError};
    ///
    /// let q = ArrayQueue::new(1);
    ///
    /// assert_eq!(q.push(10), Ok(()));
    /// assert_eq!(q.push(20), Err(PushError(20)));
    /// ```
    pub fn push(&self, value: T) -> Result<(), PushError<T>> {
        let backoff = Backoff::new();
        let mut tail = self.tail.load(Ordering::Relaxed);

        loop {
            // Deconstruct the tail.
            let index = tail & (self.one_lap - 1);
            let lap = tail & !(self.one_lap - 1);

            // Inspect the corresponding slot.
            let slot = unsafe { &*self.buffer.add(index) };
            let stamp = slot.stamp.load(Ordering::Acquire);

            // If the tail and the stamp match, we may attempt to push.
            if tail == stamp {
                let new_tail = if index + 1 < self.cap {
                    // Same lap, incremented index.
                    // Set to `{ lap: lap, index: index + 1 }`.
                    tail + 1
                } else {
                    // One lap forward, index wraps around to zero.
                    // Set to `{ lap: lap.wrapping_add(1), index: 0 }`.
                    lap.wrapping_add(self.one_lap)
                };

                // Try moving the tail.
                match self.tail.compare_exchange_weak(
                    tail,
                    new_tail,
                    Ordering::SeqCst,
                    Ordering::Relaxed,
                ) {
                    Ok(_) => {
                        // Write the value into the slot and update the stamp.
                        unsafe {
                            slot.value.get().write(value);
                        }
                        slot.stamp.store(tail + 1, Ordering::Release);
                        return Ok(());
                    }
                    Err(t) => {
                        tail = t;
                        backoff.spin();
                    }
                }
            } else if stamp.wrapping_add(self.one_lap) == tail + 1 {
                atomic::fence(Ordering::SeqCst);
                let head = self.head.load(Ordering::Relaxed);

                // If the head lags one lap behind the tail as well...
                if head.wrapping_add(self.one_lap) == tail {
                    // ...then the queue is full.
                    return Err(PushError(value));
                }

                backoff.spin();
                tail = self.tail.load(Ordering::Relaxed);
            } else {
                // Snooze because we need to wait for the stamp to get updated.
                backoff.snooze();
                tail = self.tail.load(Ordering::Relaxed);
            }
        }
    }

    /// Attempts to pop an element from the queue.
    ///
    /// If the queue is empty, an error is returned.
    ///
    /// # Examples
    ///
    /// ```
    /// use crossbeam_queue::{ArrayQueue, PopError};
    ///
    /// let q = ArrayQueue::new(1);
    /// assert_eq!(q.push(10), Ok(()));
    ///
    /// assert_eq!(q.pop(), Ok(10));
    /// assert_eq!(q.pop(), Err(PopError));
    /// ```
    pub fn pop(&self) -> Result<T, PopError> {
        let backoff = Backoff::new();
        let mut head = self.head.load(Ordering::Relaxed);

        loop {
            // Deconstruct the head.
            let index = head & (self.one_lap - 1);
            let lap = head & !(self.one_lap - 1);

            // Inspect the corresponding slot.
            let slot = unsafe { &*self.buffer.add(index) };
            let stamp = slot.stamp.load(Ordering::Acquire);

            // If the the stamp is ahead of the head by 1, we may attempt to pop.
            if head + 1 == stamp {
                let new = if index + 1 < self.cap {
                    // Same lap, incremented index.
                    // Set to `{ lap: lap, index: index + 1 }`.
                    head + 1
                } else {
                    // One lap forward, index wraps around to zero.
                    // Set to `{ lap: lap.wrapping_add(1), index: 0 }`.
                    lap.wrapping_add(self.one_lap)
                };

                // Try moving the head.
                match self.head.compare_exchange_weak(
                    head,
                    new,
                    Ordering::SeqCst,
                    Ordering::Relaxed,
                ) {
                    Ok(_) => {
                        // Read the value from the slot and update the stamp.
                        let msg = unsafe { slot.value.get().read() };
                        slot.stamp
                            .store(head.wrapping_add(self.one_lap), Ordering::Release);
                        return Ok(msg);
                    }
                    Err(h) => {
                        head = h;
                        backoff.spin();
                    }
                }
            } else if stamp == head {
                atomic::fence(Ordering::SeqCst);
                let tail = self.tail.load(Ordering::Relaxed);

                // If the tail equals the head, that means the channel is empty.
                if tail == head {
                    return Err(PopError);
                }

                backoff.spin();
                head = self.head.load(Ordering::Relaxed);
            } else {
                // Snooze because we need to wait for the stamp to get updated.
                backoff.snooze();
                head = self.head.load(Ordering::Relaxed);
            }
        }
    }

    /// Returns the capacity of the queue.
    ///
    /// # Examples
    ///
    /// ```
    /// use crossbeam_queue::{ArrayQueue, PopError};
    ///
    /// let q = ArrayQueue::<i32>::new(100);
    ///
    /// assert_eq!(q.capacity(), 100);
    /// ```
    pub fn capacity(&self) -> usize {
        self.cap
    }

    /// Returns `true` if the queue is empty.
    ///
    /// # Examples
    ///
    /// ```
    /// use crossbeam_queue::{ArrayQueue, PopError};
    ///
    /// let q = ArrayQueue::new(100);
    ///
    /// assert!(q.is_empty());
    /// q.push(1).unwrap();
    /// assert!(!q.is_empty());
    /// ```
    pub fn is_empty(&self) -> bool {
        let head = self.head.load(Ordering::SeqCst);
        let tail = self.tail.load(Ordering::SeqCst);

        // Is the tail lagging one lap behind head?
        // Is the tail equal to the head?
        //
        // Note: If the head changes just before we load the tail, that means there was a moment
        // when the channel was not empty, so it is safe to just return `false`.
        tail == head
    }

    /// Returns `true` if the queue is full.
    ///
    /// # Examples
    ///
    /// ```
    /// use crossbeam_queue::{ArrayQueue, PopError};
    ///
    /// let q = ArrayQueue::new(1);
    ///
    /// assert!(!q.is_full());
    /// q.push(1).unwrap();
    /// assert!(q.is_full());
    /// ```
    pub fn is_full(&self) -> bool {
        let tail = self.tail.load(Ordering::SeqCst);
        let head = self.head.load(Ordering::SeqCst);

        // Is the head lagging one lap behind tail?
        //
        // Note: If the tail changes just before we load the head, that means there was a moment
        // when the queue was not full, so it is safe to just return `false`.
        head.wrapping_add(self.one_lap) == tail
    }

    /// Returns the number of elements in the queue.
    ///
    /// # Examples
    ///
    /// ```
    /// use crossbeam_queue::{ArrayQueue, PopError};
    ///
    /// let q = ArrayQueue::new(100);
    /// assert_eq!(q.len(), 0);
    ///
    /// q.push(10).unwrap();
    /// assert_eq!(q.len(), 1);
    ///
    /// q.push(20).unwrap();
    /// assert_eq!(q.len(), 2);
    /// ```
    pub fn len(&self) -> usize {
        loop {
            // Load the tail, then load the head.
            let tail = self.tail.load(Ordering::SeqCst);
            let head = self.head.load(Ordering::SeqCst);

            // If the tail didn't change, we've got consistent values to work with.
            if self.tail.load(Ordering::SeqCst) == tail {
                let hix = head & (self.one_lap - 1);
                let tix = tail & (self.one_lap - 1);

                return if hix < tix {
                    tix - hix
                } else if hix > tix {
                    self.cap - hix + tix
                } else if tail == head {
                    0
                } else {
                    self.cap
                };
            }
        }
    }
}

impl<T> Drop for ArrayQueue<T> {
    fn drop(&mut self) {
        // Get the index of the head.
        let hix = self.head.load(Ordering::Relaxed) & (self.one_lap - 1);

        // Loop over all slots that hold a message and drop them.
        for i in 0..self.len() {
            // Compute the index of the next slot holding a message.
            let index = if hix + i < self.cap {
                hix + i
            } else {
                hix + i - self.cap
            };

            unsafe {
                self.buffer.add(index).drop_in_place();
            }
        }

        // Finally, deallocate the buffer, but don't run any destructors.
        unsafe {
            Vec::from_raw_parts(self.buffer, 0, self.cap);
        }
    }
}

impl<T> fmt::Debug for ArrayQueue<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("ArrayQueue { .. }")
    }
}
<commit_msg>fix comment<commit_after>//! The implementation is based on Dmitry Vyukov's bounded MPMC queue.
//!
//! Source:
//!   - http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue
//!
//! Copyright & License:
//!   - Copyright (c) 2010-2011 Dmitry Vyukov
//!   - Simplified BSD License and Apache License, Version 2.0
//!   - http://www.1024cores.net/home/code-license

use std::cell::UnsafeCell;
use std::fmt;
use std::marker::PhantomData;
use std::mem;
use std::ptr;
use std::sync::atomic::{self, AtomicUsize, Ordering};

use crossbeam_utils::{Backoff, CachePadded};

use err::{PopError, PushError};

/// A slot in a queue.
struct Slot<T> {
    /// The current stamp.
    ///
    /// If the stamp equals the tail, this node will be next written to. If it equals head + 1,
    /// this node will be next read from.
    stamp: AtomicUsize,

    /// The value in this slot.
    value: UnsafeCell<T>,
}

/// A bounded multi-producer multi-consumer queue.
///
/// This queue allocates a fixed-capacity buffer on construction, which is used to store pushed
/// elements. The queue cannot hold more elements than the buffer allows. Attempting to push an
/// element into a full queue will fail. Having a buffer allocated upfront makes this queue a bit
/// faster than [`SegQueue`].
///
/// [`SegQueue`]: struct.SegQueue.html
///
/// # Examples
///
/// ```
/// use crossbeam_queue::{ArrayQueue, PushError};
///
/// let q = ArrayQueue::new(2);
///
/// assert_eq!(q.push('a'), Ok(()));
/// assert_eq!(q.push('b'), Ok(()));
/// assert_eq!(q.push('c'), Err(PushError('c')));
/// assert_eq!(q.pop(), Ok('a'));
/// ```
pub struct ArrayQueue<T> {
    /// The head of the queue.
    ///
    /// This value is a "stamp" consisting of an index into the buffer and a lap, but packed into a
    /// single `usize`. The lower bits represent the index, while the upper bits represent the lap.
    ///
    /// Elements are popped from the head of the queue.
    head: CachePadded<AtomicUsize>,

    /// The tail of the queue.
    ///
    /// This value is a "stamp" consisting of an index into the buffer and a lap, but packed into a
    /// single `usize`. The lower bits represent the index, while the upper bits represent the lap.
    ///
    /// Elements are pushed into the tail of the queue.
    tail: CachePadded<AtomicUsize>,

    /// The buffer holding slots.
    buffer: *mut Slot<T>,

    /// The queue capacity.
    cap: usize,

    /// A stamp with the value of `{ lap: 1, index: 0 }`.
    one_lap: usize,

    /// Indicates that dropping an `ArrayQueue<T>` may drop elements of type `T`.
    _marker: PhantomData<T>,
}

unsafe impl<T: Send> Sync for ArrayQueue<T> {}
unsafe impl<T: Send> Send for ArrayQueue<T> {}

impl<T> ArrayQueue<T> {
    /// Creates a new bounded queue with the given capacity.
    ///
    /// # Panics
    ///
    /// Panics if the capacity is zero.
    ///
    /// # Examples
    ///
    /// ```
    /// use crossbeam_queue::ArrayQueue;
    ///
    /// let q = ArrayQueue::<i32>::new(100);
    /// ```
    pub fn new(cap: usize) -> ArrayQueue<T> {
        assert!(cap > 0, "capacity must be non-zero");

        // Head is initialized to `{ lap: 0, index: 0 }`.
        // Tail is initialized to `{ lap: 0, index: 0 }`.
        let head = 0;
        let tail = 0;

        // Allocate a buffer of `cap` slots.
        let buffer = {
            let mut v = Vec::<Slot<T>>::with_capacity(cap);
            let ptr = v.as_mut_ptr();
            mem::forget(v);
            ptr
        };

        // Initialize stamps in the slots.
        for i in 0..cap {
            unsafe {
                // Set the stamp to `{ lap: 0, index: i }`.
                let slot = buffer.add(i);
                ptr::write(&mut (*slot).stamp, AtomicUsize::new(i));
            }
        }

        // One lap is the smallest power of two greater than `cap`.
        let one_lap = (cap + 1).next_power_of_two();

        ArrayQueue {
            buffer,
            cap,
            one_lap,
            head: CachePadded::new(AtomicUsize::new(head)),
            tail: CachePadded::new(AtomicUsize::new(tail)),
            _marker: PhantomData,
        }
    }

    /// Attempts to push an element into the queue.
    ///
    /// If the queue is full, the element is returned back as an error.
    ///
    /// # Examples
    ///
    /// ```
    /// use crossbeam_queue::{ArrayQueue, PushError};
    ///
    /// let q = ArrayQueue::new(1);
    ///
    /// assert_eq!(q.push(10), Ok(()));
    /// assert_eq!(q.push(20), Err(PushError(20)));
    /// ```
    pub fn push(&self, value: T) -> Result<(), PushError<T>> {
        let backoff = Backoff::new();
        let mut tail = self.tail.load(Ordering::Relaxed);

        loop {
            // Deconstruct the tail.
            let index = tail & (self.one_lap - 1);
            let lap = tail & !(self.one_lap - 1);

            // Inspect the corresponding slot.
            let slot = unsafe { &*self.buffer.add(index) };
            let stamp = slot.stamp.load(Ordering::Acquire);

            // If the tail and the stamp match, we may attempt to push.
            if tail == stamp {
                let new_tail = if index + 1 < self.cap {
                    // Same lap, incremented index.
                    // Set to `{ lap: lap, index: index + 1 }`.
                    tail + 1
                } else {
                    // One lap forward, index wraps around to zero.
                    // Set to `{ lap: lap.wrapping_add(1), index: 0 }`.
                    lap.wrapping_add(self.one_lap)
                };

                // Try moving the tail.
                match self.tail.compare_exchange_weak(
                    tail,
                    new_tail,
                    Ordering::SeqCst,
                    Ordering::Relaxed,
                ) {
                    Ok(_) => {
                        // Write the value into the slot and update the stamp.
                        unsafe {
                            slot.value.get().write(value);
                        }
                        slot.stamp.store(tail + 1, Ordering::Release);
                        return Ok(());
                    }
                    Err(t) => {
                        tail = t;
                        backoff.spin();
                    }
                }
            } else if stamp.wrapping_add(self.one_lap) == tail + 1 {
                atomic::fence(Ordering::SeqCst);
                let head = self.head.load(Ordering::Relaxed);

                // If the head lags one lap behind the tail as well...
                if head.wrapping_add(self.one_lap) == tail {
                    // ...then the queue is full.
                    return Err(PushError(value));
                }

                backoff.spin();
                tail = self.tail.load(Ordering::Relaxed);
            } else {
                // Snooze because we need to wait for the stamp to get updated.
                backoff.snooze();
                tail = self.tail.load(Ordering::Relaxed);
            }
        }
    }

    /// Attempts to pop an element from the queue.
    ///
    /// If the queue is empty, an error is returned.
    ///
    /// # Examples
    ///
    /// ```
    /// use crossbeam_queue::{ArrayQueue, PopError};
    ///
    /// let q = ArrayQueue::new(1);
    /// assert_eq!(q.push(10), Ok(()));
    ///
    /// assert_eq!(q.pop(), Ok(10));
    /// assert_eq!(q.pop(), Err(PopError));
    /// ```
    pub fn pop(&self) -> Result<T, PopError> {
        let backoff = Backoff::new();
        let mut head = self.head.load(Ordering::Relaxed);

        loop {
            // Deconstruct the head.
            let index = head & (self.one_lap - 1);
            let lap = head & !(self.one_lap - 1);

            // Inspect the corresponding slot.
            let slot = unsafe { &*self.buffer.add(index) };
            let stamp = slot.stamp.load(Ordering::Acquire);

            // If the the stamp is ahead of the head by 1, we may attempt to pop.
            if head + 1 == stamp {
                let new = if index + 1 < self.cap {
                    // Same lap, incremented index.
                    // Set to `{ lap: lap, index: index + 1 }`.
                    head + 1
                } else {
                    // One lap forward, index wraps around to zero.
                    // Set to `{ lap: lap.wrapping_add(1), index: 0 }`.
                    lap.wrapping_add(self.one_lap)
                };

                // Try moving the head.
                match self.head.compare_exchange_weak(
                    head,
                    new,
                    Ordering::SeqCst,
                    Ordering::Relaxed,
                ) {
                    Ok(_) => {
                        // Read the value from the slot and update the stamp.
                        let msg = unsafe { slot.value.get().read() };
                        slot.stamp
                            .store(head.wrapping_add(self.one_lap), Ordering::Release);
                        return Ok(msg);
                    }
                    Err(h) => {
                        head = h;
                        backoff.spin();
                    }
                }
            } else if stamp == head {
                atomic::fence(Ordering::SeqCst);
                let tail = self.tail.load(Ordering::Relaxed);

                // If the tail equals the head, that means the channel is empty.
                if tail == head {
                    return Err(PopError);
                }

                backoff.spin();
                head = self.head.load(Ordering::Relaxed);
            } else {
                // Snooze because we need to wait for the stamp to get updated.
                backoff.snooze();
                head = self.head.load(Ordering::Relaxed);
            }
        }
    }

    /// Returns the capacity of the queue.
    ///
    /// # Examples
    ///
    /// ```
    /// use crossbeam_queue::{ArrayQueue, PopError};
    ///
    /// let q = ArrayQueue::<i32>::new(100);
    ///
    /// assert_eq!(q.capacity(), 100);
    /// ```
    pub fn capacity(&self) -> usize {
        self.cap
    }

    /// Returns `true` if the queue is empty.
    ///
    /// # Examples
    ///
    /// ```
    /// use crossbeam_queue::{ArrayQueue, PopError};
    ///
    /// let q = ArrayQueue::new(100);
    ///
    /// assert!(q.is_empty());
    /// q.push(1).unwrap();
    /// assert!(!q.is_empty());
    /// ```
    pub fn is_empty(&self) -> bool {
        let head = self.head.load(Ordering::SeqCst);
        let tail = self.tail.load(Ordering::SeqCst);

        // Is the tail lagging one lap behind head?
        // Is the tail equal to the head?
        //
        // Note: If the head changes just before we load the tail, that means there was a moment
        // when the channel was not empty, so it is safe to just return `false`.
        tail == head
    }

    /// Returns `true` if the queue is full.
    ///
    /// # Examples
    ///
    /// ```
    /// use crossbeam_queue::{ArrayQueue, PopError};
    ///
    /// let q = ArrayQueue::new(1);
    ///
    /// assert!(!q.is_full());
    /// q.push(1).unwrap();
    /// assert!(q.is_full());
    /// ```
    pub fn is_full(&self) -> bool {
        let tail = self.tail.load(Ordering::SeqCst);
        let head = self.head.load(Ordering::SeqCst);

        // Is the head lagging one lap behind tail?
        //
        // Note: If the tail changes just before we load the head, that means there was a moment
        // when the queue was not full, so it is safe to just return `false`.
        head.wrapping_add(self.one_lap) == tail
    }

    /// Returns the number of elements in the queue.
    ///
    /// # Examples
    ///
    /// ```
    /// use crossbeam_queue::{ArrayQueue, PopError};
    ///
    /// let q = ArrayQueue::new(100);
    /// assert_eq!(q.len(), 0);
    ///
    /// q.push(10).unwrap();
    /// assert_eq!(q.len(), 1);
    ///
    /// q.push(20).unwrap();
    /// assert_eq!(q.len(), 2);
    /// ```
    pub fn len(&self) -> usize {
        loop {
            // Load the tail, then load the head.
            let tail = self.tail.load(Ordering::SeqCst);
            let head = self.head.load(Ordering::SeqCst);

            // If the tail didn't change, we've got consistent values to work with.
            if self.tail.load(Ordering::SeqCst) == tail {
                let hix = head & (self.one_lap - 1);
                let tix = tail & (self.one_lap - 1);

                return if hix < tix {
                    tix - hix
                } else if hix > tix {
                    self.cap - hix + tix
                } else if tail == head {
                    0
                } else {
                    self.cap
                };
            }
        }
    }
}

impl<T> Drop for ArrayQueue<T> {
    fn drop(&mut self) {
        // Get the index of the head.
        let hix = self.head.load(Ordering::Relaxed) & (self.one_lap - 1);

        // Loop over all slots that hold a message and drop them.
        for i in 0..self.len() {
            // Compute the index of the next slot holding a message.
            let index = if hix + i < self.cap {
                hix + i
            } else {
                hix + i - self.cap
            };

            unsafe {
                self.buffer.add(index).drop_in_place();
            }
        }

        // Finally, deallocate the buffer, but don't run any destructors.
        unsafe {
            Vec::from_raw_parts(self.buffer, 0, self.cap);
        }
    }
}

impl<T> fmt::Debug for ArrayQueue<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("ArrayQueue { .. }")
    }
}
<|endoftext|>


<commit_before>extern crate ratelimit_meter;
#[macro_use]
extern crate nonzero_ext;

use ratelimit_meter::{
    algorithms::Algorithm, test_utilities::current_moment, NegativeMultiDecision, NonConformance,
    GCRA,
};
use std::thread;
use std::time::Duration;

#[test]
fn accepts_first_cell() {
    let gcra = GCRA::construct(nonzero!(5u32), nonzero!(1u32), Duration::from_secs(1)).unwrap();
    let state = <GCRA as Algorithm>::BucketState::default();;
    let now = current_moment();
    assert_eq!(Ok(()), gcra.test_and_update(&state, now));
}

#[test]
fn rejects_too_many() {
    let gcra = GCRA::construct(nonzero!(1u32), nonzero!(1u32), Duration::from_secs(1)).unwrap();
    let state = <GCRA as Algorithm>::BucketState::default();;
    let now = current_moment();
    gcra.test_and_update(&state, now).unwrap();
    gcra.test_and_update(&state, now).unwrap();
    assert_ne!(
        Ok(()),
        gcra.test_and_update(&state, now),
        "{:?} {:?}",
        &state,
        &gcra
    );
}

#[test]
fn allows_after_interval() {
    let gcra = GCRA::construct(nonzero!(1u32), nonzero!(1u32), Duration::from_secs(1)).unwrap();
    let state = <GCRA as Algorithm>::BucketState::default();;
    let now = current_moment();
    let ms = Duration::from_millis(1);
    gcra.test_and_update(&state, now).unwrap();
    assert_eq!(Ok(()), gcra.test_and_update(&state, now + ms));
    assert_ne!(Ok(()), gcra.test_and_update(&state, now + ms * 2));
    // should be ok again in 1s:
    let next = now + Duration::from_secs(1);
    assert_eq!(Ok(()), gcra.test_and_update(&state, next));
}

#[test]
fn allows_n_after_interval() {
    let gcra = GCRA::construct(nonzero!(2u32), nonzero!(1u32), Duration::from_secs(1)).unwrap();
    let state = <GCRA as Algorithm>::BucketState::default();;
    let now = current_moment() + Duration::from_secs(1);
    let ms = Duration::from_millis(1);
    assert_eq!(Ok(()), gcra.test_n_and_update(&state, 2, now));
    assert!(!gcra.test_n_and_update(&state, 2, now + ms).is_ok());
    // should be ok again in 1.5s:
    let next = now + Duration::from_secs(1);
    assert_eq!(
        Ok(()),
        gcra.test_n_and_update(&state, 2, next),
        "now: {:?}",
        next
    );

    // should always accommodate 0 cells:
    assert_eq!(Ok(()), gcra.test_n_and_update(&state, 0, next));
}

#[test]
fn correctly_handles_per() {
    let ms = Duration::from_millis(1);
    let gcra = GCRA::construct(nonzero!(1u32), nonzero!(1u32), ms * 20).unwrap();
    let state = <GCRA as Algorithm>::BucketState::default();;
    let now = current_moment();

    assert_eq!(Ok(()), gcra.test_and_update(&state, now));
    assert_eq!(Ok(()), gcra.test_and_update(&state, now + ms));
    assert!(!gcra.test_and_update(&state, now + ms * 10).is_ok());
    assert_eq!(Ok(()), gcra.test_and_update(&state, now + ms * 20));
}

#[test]
fn never_allows_more_than_capacity() {
    let ms = Duration::from_millis(1);
    let gcra = GCRA::construct(nonzero!(5u32), nonzero!(1u32), Duration::from_secs(1)).unwrap();
    let state = <GCRA as Algorithm>::BucketState::default();
    let now = current_moment();

    // Should not allow the first 15 cells on a capacity 5 bucket:
    assert!(gcra.test_n_and_update(&state, 15, now).is_err());

    // After 3 and 20 seconds, it should not allow 15 on that bucket either:
    assert!(gcra
        .test_n_and_update(&state, 15, now + (ms * 3 * 1000))
        .is_err());

    let result = gcra.test_n_and_update(&state, 15, now + (ms * 20 * 1000));
    match result {
        Err(NegativeMultiDecision::InsufficientCapacity(n)) => assert_eq!(n, 15),
        _ => panic!("Did not expect {:?}", result),
    }
}

#[test]
fn correct_wait_time() {
    // Bucket adding a new element per 200ms:
    let gcra = GCRA::construct(nonzero!(5u32), nonzero!(1u32), Duration::from_secs(1)).unwrap();
    let state = <GCRA as Algorithm>::BucketState::default();
    let mut now = current_moment();
    let ms = Duration::from_millis(1);
    let mut conforming = 0;
    for _i in 0..20 {
        now += ms;
        let res = gcra.test_and_update(&state, now);
        match res {
            Ok(()) => {
                conforming += 1;
            }
            Err(wait) => {
                now += wait.wait_time_from(now);
                assert_eq!(Ok(()), gcra.test_and_update(&state, now));
                conforming += 1;
            }
        }
    }
    assert_eq!(20, conforming);
}

#[test]
fn actual_threadsafety() {
    let gcra = GCRA::construct(nonzero!(20u32), nonzero!(1u32), Duration::from_secs(1))
        .expect("can't build GCRA");
    let state = <GCRA as Algorithm>::BucketState::default();

    let now = current_moment() + Duration::from_secs(1);
    let ms = Duration::from_millis(1);
    let mut children = vec![];

    gcra.test_and_update(&state, now)
        .expect("first update should work");
    for _i in 0..20 {
        let state = state.clone();
        let gcra = gcra.clone();
        children.push(thread::spawn(move || gcra.test_and_update(&state, now)));
    }
    let results: Vec<Result<(), <ratelimit_meter::GCRA as Algorithm>::NegativeDecision>> = children
        .into_iter()
        .enumerate()
        .map(|(n, c)| c.join().expect(&format!("thread {} panicked", n)))
        .collect();
    let expected: Vec<Result<(), <ratelimit_meter::GCRA as Algorithm>::NegativeDecision>> =
        results.iter().map(|_| Ok(())).collect();
    assert_eq!(expected, results);

    assert_ne!(Ok(()), gcra.test_and_update(&state, now + ms * 2));
    assert_eq!(Ok(()), gcra.test_and_update(&state, now + ms * 1000));
}

#[test]
fn nonconformance_wait_time_from() {
    let gcra = GCRA::construct(nonzero!(1u32), nonzero!(1u32), Duration::from_secs(1)).unwrap();
    let state = <GCRA as Algorithm>::BucketState::default();
    let now = current_moment();
    let ms = Duration::from_millis(1);
    gcra.test_and_update(&state, now).unwrap();
    gcra.test_and_update(&state, now).unwrap();
    if let Err(failure) = gcra.test_and_update(&state, now) {
        assert_eq!(ms * 2000, failure.wait_time_from(now));
        assert_eq!(Duration::new(0, 0), failure.wait_time_from(now + ms * 2000));
        assert_eq!(Duration::new(0, 0), failure.wait_time_from(now + ms * 2001));
    } else {
        assert!(false, "Second attempt should fail");
    }
}
<commit_msg>Eliminate the double semicolons that tripped up rustfmt.<commit_after>extern crate ratelimit_meter;
#[macro_use]
extern crate nonzero_ext;

use ratelimit_meter::{
    algorithms::Algorithm, test_utilities::current_moment, NegativeMultiDecision, NonConformance,
    GCRA,
};
use std::thread;
use std::time::Duration;

#[test]
fn accepts_first_cell() {
    let gcra = GCRA::construct(nonzero!(5u32), nonzero!(1u32), Duration::from_secs(1)).unwrap();
    let state = <GCRA as Algorithm>::BucketState::default();
    let now = current_moment();
    assert_eq!(Ok(()), gcra.test_and_update(&state, now));
}

#[test]
fn rejects_too_many() {
    let gcra = GCRA::construct(nonzero!(1u32), nonzero!(1u32), Duration::from_secs(1)).unwrap();
    let state = <GCRA as Algorithm>::BucketState::default();
    let now = current_moment();
    gcra.test_and_update(&state, now).unwrap();
    gcra.test_and_update(&state, now).unwrap();
    assert_ne!(
        Ok(()),
        gcra.test_and_update(&state, now),
        "{:?} {:?}",
        &state,
        &gcra
    );
}

#[test]
fn allows_after_interval() {
    let gcra = GCRA::construct(nonzero!(1u32), nonzero!(1u32), Duration::from_secs(1)).unwrap();
    let state = <GCRA as Algorithm>::BucketState::default();
    let now = current_moment();
    let ms = Duration::from_millis(1);
    gcra.test_and_update(&state, now).unwrap();
    assert_eq!(Ok(()), gcra.test_and_update(&state, now + ms));
    assert_ne!(Ok(()), gcra.test_and_update(&state, now + ms * 2));
    // should be ok again in 1s:
    let next = now + Duration::from_secs(1);
    assert_eq!(Ok(()), gcra.test_and_update(&state, next));
}

#[test]
fn allows_n_after_interval() {
    let gcra = GCRA::construct(nonzero!(2u32), nonzero!(1u32), Duration::from_secs(1)).unwrap();
    let state = <GCRA as Algorithm>::BucketState::default();
    let now = current_moment() + Duration::from_secs(1);
    let ms = Duration::from_millis(1);
    assert_eq!(Ok(()), gcra.test_n_and_update(&state, 2, now));
    assert!(!gcra.test_n_and_update(&state, 2, now + ms).is_ok());
    // should be ok again in 1.5s:
    let next = now + Duration::from_secs(1);
    assert_eq!(
        Ok(()),
        gcra.test_n_and_update(&state, 2, next),
        "now: {:?}",
        next
    );

    // should always accommodate 0 cells:
    assert_eq!(Ok(()), gcra.test_n_and_update(&state, 0, next));
}

#[test]
fn correctly_handles_per() {
    let ms = Duration::from_millis(1);
    let gcra = GCRA::construct(nonzero!(1u32), nonzero!(1u32), ms * 20).unwrap();
    let state = <GCRA as Algorithm>::BucketState::default();
    let now = current_moment();

    assert_eq!(Ok(()), gcra.test_and_update(&state, now));
    assert_eq!(Ok(()), gcra.test_and_update(&state, now + ms));
    assert!(!gcra.test_and_update(&state, now + ms * 10).is_ok());
    assert_eq!(Ok(()), gcra.test_and_update(&state, now + ms * 20));
}

#[test]
fn never_allows_more_than_capacity() {
    let ms = Duration::from_millis(1);
    let gcra = GCRA::construct(nonzero!(5u32), nonzero!(1u32), Duration::from_secs(1)).unwrap();
    let state = <GCRA as Algorithm>::BucketState::default();
    let now = current_moment();

    // Should not allow the first 15 cells on a capacity 5 bucket:
    assert!(gcra.test_n_and_update(&state, 15, now).is_err());

    // After 3 and 20 seconds, it should not allow 15 on that bucket either:
    assert!(gcra
        .test_n_and_update(&state, 15, now + (ms * 3 * 1000))
        .is_err());

    let result = gcra.test_n_and_update(&state, 15, now + (ms * 20 * 1000));
    match result {
        Err(NegativeMultiDecision::InsufficientCapacity(n)) => assert_eq!(n, 15),
        _ => panic!("Did not expect {:?}", result),
    }
}

#[test]
fn correct_wait_time() {
    // Bucket adding a new element per 200ms:
    let gcra = GCRA::construct(nonzero!(5u32), nonzero!(1u32), Duration::from_secs(1)).unwrap();
    let state = <GCRA as Algorithm>::BucketState::default();
    let mut now = current_moment();
    let ms = Duration::from_millis(1);
    let mut conforming = 0;
    for _i in 0..20 {
        now += ms;
        let res = gcra.test_and_update(&state, now);
        match res {
            Ok(()) => {
                conforming += 1;
            }
            Err(wait) => {
                now += wait.wait_time_from(now);
                assert_eq!(Ok(()), gcra.test_and_update(&state, now));
                conforming += 1;
            }
        }
    }
    assert_eq!(20, conforming);
}

#[test]
fn actual_threadsafety() {
    let gcra = GCRA::construct(nonzero!(20u32), nonzero!(1u32), Duration::from_secs(1))
        .expect("can't build GCRA");
    let state = <GCRA as Algorithm>::BucketState::default();

    let now = current_moment() + Duration::from_secs(1);
    let ms = Duration::from_millis(1);
    let mut children = vec![];

    gcra.test_and_update(&state, now)
        .expect("first update should work");
    for _i in 0..20 {
        let state = state.clone();
        let gcra = gcra.clone();
        children.push(thread::spawn(move || gcra.test_and_update(&state, now)));
    }
    let results: Vec<Result<(), <ratelimit_meter::GCRA as Algorithm>::NegativeDecision>> = children
        .into_iter()
        .enumerate()
        .map(|(n, c)| c.join().expect(&format!("thread {} panicked", n)))
        .collect();
    let expected: Vec<Result<(), <ratelimit_meter::GCRA as Algorithm>::NegativeDecision>> =
        results.iter().map(|_| Ok(())).collect();
    assert_eq!(expected, results);

    assert_ne!(Ok(()), gcra.test_and_update(&state, now + ms * 2));
    assert_eq!(Ok(()), gcra.test_and_update(&state, now + ms * 1000));
}

#[test]
fn nonconformance_wait_time_from() {
    let gcra = GCRA::construct(nonzero!(1u32), nonzero!(1u32), Duration::from_secs(1)).unwrap();
    let state = <GCRA as Algorithm>::BucketState::default();
    let now = current_moment();
    let ms = Duration::from_millis(1);
    gcra.test_and_update(&state, now).unwrap();
    gcra.test_and_update(&state, now).unwrap();
    if let Err(failure) = gcra.test_and_update(&state, now) {
        assert_eq!(ms * 2000, failure.wait_time_from(now));
        assert_eq!(Duration::new(0, 0), failure.wait_time_from(now + ms * 2000));
        assert_eq!(Duration::new(0, 0), failure.wait_time_from(now + ms * 2001));
    } else {
        assert!(false, "Second attempt should fail");
    }
}
<|endoftext|>


<commit_before>//! Test runner for the semver compatibility doc chapter.
//!
//! This extracts all the "rust" annotated code blocks and tests that they
//! either fail or succeed as expected. This also checks that the examples are
//! formatted correctly.
//!
//! An example with the word "MINOR" at the top is expected to successfully
//! build against the before and after. Otherwise it should fail. A comment of
//! "// Error:" will check that the given message appears in the error output.

use std::error::Error;
use std::fs;
use std::path::Path;
use std::process::Command;

fn main() {
    if let Err(e) = doit() {
        println!("error: {}", e);
        std::process::exit(1);
    }
}

const SEPARATOR: &str = "///////////////////////////////////////////////////////////";

fn doit() -> Result<(), Box<dyn Error>> {
    let filename = std::env::args()
        .skip(1)
        .next()
        .unwrap_or_else(|| "../src/reference/semver.md".to_string());
    let contents = fs::read_to_string(filename)?;
    let mut lines = contents.lines().enumerate();

    loop {
        // Find a rust block.
        let block_start = loop {
            match lines.next() {
                Some((lineno, line)) => {
                    if line.trim().starts_with("```rust") && !line.contains("skip") {
                        break lineno + 1;
                    }
                }
                None => return Ok(()),
            }
        };
        // Read in the code block.
        let mut block = Vec::new();
        loop {
            match lines.next() {
                Some((_, line)) => {
                    if line.trim() == "```" {
                        break;
                    }
                    block.push(line);
                }
                None => {
                    return Err(format!(
                        "rust block did not end for example starting on line {}",
                        block_start
                    )
                    .into());
                }
            }
        }
        // Split it into the separate source files.
        let parts: Vec<_> = block.split(|line| line.trim() == SEPARATOR).collect();
        if parts.len() != 4 {
            return Err(format!(
                "expected 4 sections in example starting on line {}, got {}:\n{:?}",
                block_start,
                parts.len(),
                parts
            )
            .into());
        }
        let join = |part: &[&str]| {
            let mut result = String::new();
            result.push_str("#![allow(unused)]\n#![deny(warnings)]\n");
            result.push_str(&part.join("\n"));
            if !result.ends_with('\n') {
                result.push('\n');
            }
            result
        };
        let expect_success = parts[0][0].contains("MINOR");
        println!("Running test from line {}", block_start);
        if let Err(e) = run_test(
            join(parts[1]),
            join(parts[2]),
            join(parts[3]),
            expect_success,
        ) {
            return Err(format!(
                "test failed for example starting on line {}: {}",
                block_start, e
            )
            .into());
        }
    }
}

const CRATE_NAME: &str = "updated_crate";

fn run_test(
    before: String,
    after: String,
    example: String,
    expect_success: bool,
) -> Result<(), Box<dyn Error>> {
    let tempdir = tempfile::TempDir::new()?;
    let before_p = tempdir.path().join("before.rs");
    let after_p = tempdir.path().join("after.rs");
    let example_p = tempdir.path().join("example.rs");
    compile(before, &before_p, CRATE_NAME, false, true)?;
    compile(example.clone(), &example_p, "example", true, true)?;
    compile(after, &after_p, CRATE_NAME, false, true)?;
    compile(example, &example_p, "example", true, expect_success)?;
    Ok(())
}

fn check_formatting(path: &Path) -> Result<(), Box<dyn Error>> {
    match Command::new("rustfmt")
        .args(&["--edition=2018", "--check"])
        .arg(path)
        .status()
    {
        Ok(status) => {
            if !status.success() {
                return Err(format!("failed to run rustfmt: {}", status).into());
            }
            return Ok(());
        }
        Err(e) => {
            return Err(format!("failed to run rustfmt: {}", e).into());
        }
    }
}

fn compile(
    mut contents: String,
    path: &Path,
    crate_name: &str,
    extern_path: bool,
    expect_success: bool,
) -> Result<(), Box<dyn Error>> {
    // If the example has an error message, remove it so that it can be
    // compared with the actual output, and also to avoid issues with rustfmt
    // moving it around.
    let expected_error = match contents.find("// Error:") {
        Some(index) => {
            let start = contents[..index].rfind(|ch| ch != ' ').unwrap();
            let end = contents[index..].find('\n').unwrap();
            let error = contents[index + 9..index + end].trim().to_string();
            contents.replace_range(start + 1..index + end, "");
            Some(error)
        }
        None => None,
    };
    let crate_type = if contents.contains("fn main()") {
        "bin"
    } else {
        "rlib"
    };

    fs::write(path, &contents)?;
    check_formatting(path)?;
    let out_dir = path.parent().unwrap();
    let mut cmd = Command::new("rustc");
    cmd.args(&[
        "--edition=2018",
        "--crate-type",
        crate_type,
        "--crate-name",
        crate_name,
        "--out-dir",
    ]);
    cmd.arg(&out_dir);
    if extern_path {
        let epath = out_dir.join(format!("lib{}.rlib", CRATE_NAME));
        cmd.arg("--extern")
            .arg(format!("{}={}", CRATE_NAME, epath.display()));
    }
    cmd.arg(path);
    let output = cmd.output()?;
    let stderr = std::str::from_utf8(&output.stderr).unwrap();
    match (output.status.success(), expect_success) {
        (true, true) => Ok(()),
        (true, false) => Err(format!(
            "expected failure, got success {}\n===== Contents:\n{}\n===== Output:\n{}\n",
            path.display(),
            contents,
            stderr
        )
        .into()),
        (false, true) => Err(format!(
            "expected success, got error {}\n===== Contents:\n{}\n===== Output:\n{}\n",
            path.display(),
            contents,
            stderr
        )
        .into()),
        (false, false) => {
            if expected_error.is_none() {
                return Err("failing test should have an \"// Error:\" annotation ".into());
            }
            let expected_error = expected_error.unwrap();
            if !stderr.contains(&expected_error) {
                Err(format!(
                    "expected error message not found in compiler output\nExpected: {}\nGot:\n{}\n",
                    expected_error, stderr
                )
                .into())
            } else {
                Ok(())
            }
        }
    }
}
<commit_msg>docs: add `run-fail` to semver check<commit_after>//! Test runner for the semver compatibility doc chapter.
//!
//! This extracts all the "rust" annotated code blocks and tests that they
//! either fail or succeed as expected. This also checks that the examples are
//! formatted correctly.
//!
//! An example with the word "MINOR" at the top is expected to successfully
//! build against the before and after. Otherwise it should fail. A comment of
//! "// Error:" will check that the given message appears in the error output.

use std::error::Error;
use std::fs;
use std::path::Path;
use std::process::{Command, Output};

fn main() {
    if let Err(e) = doit() {
        println!("error: {}", e);
        std::process::exit(1);
    }
}

const SEPARATOR: &str = "///////////////////////////////////////////////////////////";

fn doit() -> Result<(), Box<dyn Error>> {
    let filename = std::env::args()
        .nth(1)
        .unwrap_or_else(|| "../src/reference/semver.md".to_string());
    let contents = fs::read_to_string(filename)?;
    let mut lines = contents.lines().enumerate();

    loop {
        // Find a rust block.
        let (block_start, run_program) = loop {
            match lines.next() {
                Some((lineno, line)) => {
                    if line.trim().starts_with("```rust") && !line.contains("skip") {
                        break (lineno + 1, line.contains("run-fail"));
                    }
                }
                None => return Ok(()),
            }
        };
        // Read in the code block.
        let mut block = Vec::new();
        loop {
            match lines.next() {
                Some((_, line)) => {
                    if line.trim() == "```" {
                        break;
                    }
                    block.push(line);
                }
                None => {
                    return Err(format!(
                        "rust block did not end for example starting on line {}",
                        block_start
                    )
                    .into());
                }
            }
        }
        // Split it into the separate source files.
        let parts: Vec<_> = block.split(|line| line.trim() == SEPARATOR).collect();
        if parts.len() != 4 {
            return Err(format!(
                "expected 4 sections in example starting on line {}, got {}:\n{:?}",
                block_start,
                parts.len(),
                parts
            )
            .into());
        }
        let join = |part: &[&str]| {
            let mut result = String::new();
            result.push_str("#![allow(unused)]\n#![deny(warnings)]\n");
            result.push_str(&part.join("\n"));
            if !result.ends_with('\n') {
                result.push('\n');
            }
            result
        };
        let expect_success = parts[0][0].contains("MINOR");
        println!("Running test from line {}", block_start);

        let result = run_test(
            join(parts[1]),
            join(parts[2]),
            join(parts[3]),
            expect_success,
            run_program,
        );

        if let Err(e) = result {
            return Err(format!(
                "test failed for example starting on line {}: {}",
                block_start, e
            )
            .into());
        }
    }
}

const CRATE_NAME: &str = "updated_crate";

fn run_test(
    before: String,
    after: String,
    example: String,
    expect_success: bool,
    run_program: bool,
) -> Result<(), Box<dyn Error>> {
    let tempdir = tempfile::TempDir::new()?;
    let before_p = tempdir.path().join("before.rs");
    let after_p = tempdir.path().join("after.rs");
    let example_p = tempdir.path().join("example.rs");

    let check_fn = if run_program {
        run_check
    } else {
        compile_check
    };

    compile_check(before, &before_p, CRATE_NAME, false, true)?;
    check_fn(example.clone(), &example_p, "example", true, true)?;
    compile_check(after, &after_p, CRATE_NAME, false, true)?;
    check_fn(example, &example_p, "example", true, expect_success)?;
    Ok(())
}

fn check_formatting(path: &Path) -> Result<(), Box<dyn Error>> {
    match Command::new("rustfmt")
        .args(&["--edition=2018", "--check"])
        .arg(path)
        .status()
    {
        Ok(status) => {
            if !status.success() {
                return Err(format!("failed to run rustfmt: {}", status).into());
            }
            Ok(())
        }
        Err(e) => Err(format!("failed to run rustfmt: {}", e).into()),
    }
}

fn compile(
    contents: &str,
    path: &Path,
    crate_name: &str,
    extern_path: bool,
) -> Result<Output, Box<dyn Error>> {
    let crate_type = if contents.contains("fn main()") {
        "bin"
    } else {
        "rlib"
    };

    fs::write(path, &contents)?;
    check_formatting(path)?;
    let out_dir = path.parent().unwrap();
    let mut cmd = Command::new("rustc");
    cmd.args(&[
        "--edition=2021",
        "--crate-type",
        crate_type,
        "--crate-name",
        crate_name,
        "--out-dir",
    ]);
    cmd.arg(&out_dir);
    if extern_path {
        let epath = out_dir.join(format!("lib{}.rlib", CRATE_NAME));
        cmd.arg("--extern")
            .arg(format!("{}={}", CRATE_NAME, epath.display()));
    }
    cmd.arg(path);
    cmd.output().map_err(Into::into)
}

fn compile_check(
    mut contents: String,
    path: &Path,
    crate_name: &str,
    extern_path: bool,
    expect_success: bool,
) -> Result<(), Box<dyn Error>> {
    // If the example has an error message, remove it so that it can be
    // compared with the actual output, and also to avoid issues with rustfmt
    // moving it around.
    let expected_error = match contents.find("// Error:") {
        Some(index) => {
            let start = contents[..index].rfind(|ch| ch != ' ').unwrap();
            let end = contents[index..].find('\n').unwrap();
            let error = contents[index + 9..index + end].trim().to_string();
            contents.replace_range(start + 1..index + end, "");
            Some(error)
        }
        None => None,
    };

    let output = compile(&contents, path, crate_name, extern_path)?;

    let stderr = std::str::from_utf8(&output.stderr).unwrap();
    match (output.status.success(), expect_success) {
        (true, true) => Ok(()),
        (true, false) => Err(format!(
            "expected failure, got success {}\n===== Contents:\n{}\n===== Output:\n{}\n",
            path.display(),
            contents,
            stderr
        )
        .into()),
        (false, true) => Err(format!(
            "expected success, got error {}\n===== Contents:\n{}\n===== Output:\n{}\n",
            path.display(),
            contents,
            stderr
        )
        .into()),
        (false, false) => {
            if expected_error.is_none() {
                return Err("failing test should have an \"// Error:\" annotation ".into());
            }
            let expected_error = expected_error.unwrap();
            if !stderr.contains(&expected_error) {
                Err(format!(
                    "expected error message not found in compiler output\nExpected: {}\nGot:\n{}\n",
                    expected_error, stderr
                )
                .into())
            } else {
                Ok(())
            }
        }
    }
}

fn run_check(
    contents: String,
    path: &Path,
    crate_name: &str,
    extern_path: bool,
    expect_success: bool,
) -> Result<(), Box<dyn Error>> {
    let compile_output = compile(&contents, path, crate_name, extern_path)?;

    if !compile_output.status.success() {
        let stderr = std::str::from_utf8(&compile_output.stderr).unwrap();
        return Err(format!(
            "expected success, got error {}\n===== Contents:\n{}\n===== Output:\n{}\n",
            path.display(),
            contents,
            stderr
        )
        .into());
    }

    let binary_path = path.parent().unwrap().join(crate_name);

    let output = Command::new(binary_path).output()?;

    let stderr = std::str::from_utf8(&output.stderr).unwrap();

    match (output.status.success(), expect_success) {
        (true, false) => Err(format!(
            "expected panic, got success {}\n===== Contents:\n{}\n===== Output:\n{}\n",
            path.display(),
            contents,
            stderr
        )
        .into()),
        (false, true) => Err(format!(
            "expected success, got panic {}\n===== Contents:\n{}\n===== Output:\n{}\n",
            path.display(),
            contents,
            stderr,
        )
        .into()),
        (_, _) => Ok(()),
    }
}
<|endoftext|>


<commit_before>extern crate test;
extern crate ndarray;

use ndarray::Array;
use ndarray::{arr0, arr1, arr2};

use std::fmt;
use std::num::Float;

fn test_oper(op: &str, a: &[f32], b: &[f32], c: &[f32])
{
    let aa = arr1(a);
    let bb = arr1(b);
    let cc = arr1(c);
    test_oper_arr(op, aa.clone(), bb.clone(), cc.clone());
    let dim = (2, 2);
    let aa = aa.reshape(dim);
    let bb = bb.reshape(dim);
    let cc = cc.reshape(dim);
    test_oper_arr(op, aa.clone(), bb.clone(), cc.clone());
    let dim = (1, 2, 1, 2);
    let aa = aa.reshape(dim);
    let bb = bb.reshape(dim);
    let cc = cc.reshape(dim);
    test_oper_arr(op, aa.clone(), bb.clone(), cc.clone());
}

fn test_oper_arr<A: Float + fmt::Show, D: ndarray::Dimension>
    (op: &str, mut aa: Array<A,D>, bb: Array<A, D>, cc: Array<A, D>)
{
    match op {
        "+" => {
            assert_eq!(&aa + &bb, cc);
            aa.iadd(&bb);
            assert_eq!(aa, cc);
        },
        "-" => {
            assert_eq!(&aa - &bb, cc);
            aa.isub(&bb);
            assert_eq!(aa, cc);
        },
        "*" => {
            assert_eq!(&aa * &bb, cc);
            aa.imul(&bb);
            assert_eq!(aa, cc);
        },
        "/" => {
            assert_eq!(&aa / &bb, cc);
            aa.idiv(&bb);
            assert_eq!(aa, cc);
        },
        "%" => {
            assert_eq!(&aa % &bb, cc);
            aa.irem(&bb);
            assert_eq!(aa, cc);
        },
        "neg" => {
            assert_eq!(-aa, cc);
            aa.ineg();
            assert_eq!(aa, cc);
        },
        _ => panic!()
    }
}

#[test]
fn operations()
{
    test_oper("+", &[1.0,2.0,3.0,4.0], &[0.0, 1.0, 2.0, 3.0], &[1.0,3.0,5.0,7.0]);
    test_oper("-", &[1.0,2.0,3.0,4.0], &[0.0, 1.0, 2.0, 3.0], &[1.0,1.0,1.0,1.0]);
    test_oper("*", &[1.0,2.0,3.0,4.0], &[0.0, 1.0, 2.0, 3.0], &[0.0,2.0,6.0,12.0]);
    test_oper("/", &[1.0,2.0,3.0,4.0], &[1.0, 1.0, 2.0, 3.0], &[1.0,2.0,3.0/2.0,4.0/3.0]);
    test_oper("%", &[1.0,2.0,3.0,4.0], &[1.0, 1.0, 2.0, 3.0], &[0.0,0.0,1.0,1.0]);
    test_oper("neg", &[1.0,2.0,3.0,4.0], &[1.0, 1.0, 2.0, 3.0], &[-1.0,-2.0,-3.0,-4.0]);
}

#[test]
fn scalar_operations()
{
    let a = arr0::<f32>(1.);
    let b = arr1::<f32>(&[1., 1.]);
    let c = arr2::<f32>(&[&[1., 1.], &[1., 1.]]);

    {
        let mut x = a.clone();
        let mut y = arr0(0.);
        x.iadd_scalar(&1.);
        y.assign_scalar(&2.);
        assert_eq!(x, a + arr0(1.));
        assert_eq!(x, y);
    }

    {
        let mut x = b.clone();
        let mut y = arr1(&[0., 0.]);
        x.iadd_scalar(&1.);
        y.assign_scalar(&2.);
        assert_eq!(x, b + arr0(1.));
        assert_eq!(x, y);
    }

    {
        let mut x = c.clone();
        let mut y = Array::zeros((2, 2));
        x.iadd_scalar(&1.);
        y.assign_scalar(&2.);
        assert_eq!(x, c + arr0(1.));
        assert_eq!(x, y);
    }
}
<commit_msg>Update tests.<commit_after>extern crate test;
extern crate ndarray;

use ndarray::Array;
use ndarray::{arr0, arr1, arr2};

use std::fmt;
use std::num::Float;

fn test_oper(op: &str, a: &[f32], b: &[f32], c: &[f32])
{
    let aa = arr1(a);
    let bb = arr1(b);
    let cc = arr1(c);
    test_oper_arr(op, aa.clone(), bb.clone(), cc.clone());
    let dim = (2, 2);
    let aa = aa.reshape(dim);
    let bb = bb.reshape(dim);
    let cc = cc.reshape(dim);
    test_oper_arr(op, aa.clone(), bb.clone(), cc.clone());
    let dim = (1, 2, 1, 2);
    let aa = aa.reshape(dim);
    let bb = bb.reshape(dim);
    let cc = cc.reshape(dim);
    test_oper_arr(op, aa.clone(), bb.clone(), cc.clone());
}

fn test_oper_arr<A: Float + fmt::Show, D: ndarray::Dimension>
    (op: &str, mut aa: Array<A,D>, bb: Array<A, D>, cc: Array<A, D>)
{
    match op {
        "+" => {
            assert_eq!(&aa + &bb, cc);
            aa.iadd(&bb);
            assert_eq!(aa, cc);
        },
        "-" => {
            assert_eq!(&aa - &bb, cc);
            aa.isub(&bb);
            assert_eq!(aa, cc);
        },
        "*" => {
            assert_eq!(&aa * &bb, cc);
            aa.imul(&bb);
            assert_eq!(aa, cc);
        },
        "/" => {
            assert_eq!(&aa / &bb, cc);
            aa.idiv(&bb);
            assert_eq!(aa, cc);
        },
        "%" => {
            assert_eq!(&aa % &bb, cc);
            aa.irem(&bb);
            assert_eq!(aa, cc);
        },
        "neg" => {
            assert_eq!(-aa.clone(), cc);
            aa.ineg();
            assert_eq!(aa, cc);
        },
        _ => panic!()
    }
}

#[test]
fn operations()
{
    test_oper("+", &[1.0,2.0,3.0,4.0], &[0.0, 1.0, 2.0, 3.0], &[1.0,3.0,5.0,7.0]);
    test_oper("-", &[1.0,2.0,3.0,4.0], &[0.0, 1.0, 2.0, 3.0], &[1.0,1.0,1.0,1.0]);
    test_oper("*", &[1.0,2.0,3.0,4.0], &[0.0, 1.0, 2.0, 3.0], &[0.0,2.0,6.0,12.0]);
    test_oper("/", &[1.0,2.0,3.0,4.0], &[1.0, 1.0, 2.0, 3.0], &[1.0,2.0,3.0/2.0,4.0/3.0]);
    test_oper("%", &[1.0,2.0,3.0,4.0], &[1.0, 1.0, 2.0, 3.0], &[0.0,0.0,1.0,1.0]);
    test_oper("neg", &[1.0,2.0,3.0,4.0], &[1.0, 1.0, 2.0, 3.0], &[-1.0,-2.0,-3.0,-4.0]);
}

#[test]
fn scalar_operations()
{
    let a = arr0::<f32>(1.);
    let b = arr1::<f32>(&[1., 1.]);
    let c = arr2::<f32>(&[&[1., 1.], &[1., 1.]]);

    {
        let mut x = a.clone();
        let mut y = arr0(0.);
        x.iadd_scalar(&1.);
        y.assign_scalar(&2.);
        assert_eq!(x, a + arr0(1.));
        assert_eq!(x, y);
    }

    {
        let mut x = b.clone();
        let mut y = arr1(&[0., 0.]);
        x.iadd_scalar(&1.);
        y.assign_scalar(&2.);
        assert_eq!(x, b + arr0(1.));
        assert_eq!(x, y);
    }

    {
        let mut x = c.clone();
        let mut y = Array::zeros((2, 2));
        x.iadd_scalar(&1.);
        y.assign_scalar(&2.);
        assert_eq!(x, c + arr0(1.));
        assert_eq!(x, y);
    }
}
<|endoftext|>


<commit_before>#![cfg(feature = "rand")]

extern crate num_bigint;
extern crate num_traits;
extern crate rand;

mod biguint {
    use rand::thread_rng;
    use num_bigint::{BigUint, RandBigInt};
    use num_traits::{FromPrimitive, Zero};

    #[test]
    fn test_rand() {
        let mut rng = thread_rng();
        let _n: BigUint = rng.gen_biguint(137);
        assert!(rng.gen_biguint(0).is_zero());
    }

    #[test]
    fn test_rand_range() {
        let mut rng = thread_rng();

        for _ in 0..10 {
            assert_eq!(rng.gen_bigint_range(&FromPrimitive::from_usize(236).unwrap(),
                                            &FromPrimitive::from_usize(237).unwrap()),
                       FromPrimitive::from_usize(236).unwrap());
        }

        let l = FromPrimitive::from_usize(403469000 + 2352).unwrap();
        let u = FromPrimitive::from_usize(403469000 + 3513).unwrap();
        for _ in 0..1000 {
            let n: BigUint = rng.gen_biguint_below(&u);
            assert!(n < u);

            let n: BigUint = rng.gen_biguint_range(&l, &u);
            assert!(n >= l);
            assert!(n < u);
        }
    }

    #[test]
    #[should_panic]
    fn test_zero_rand_range() {
        thread_rng().gen_biguint_range(&FromPrimitive::from_usize(54).unwrap(),
                                       &FromPrimitive::from_usize(54).unwrap());
    }

    #[test]
    #[should_panic]
    fn test_negative_rand_range() {
        let mut rng = thread_rng();
        let l = FromPrimitive::from_usize(2352).unwrap();
        let u = FromPrimitive::from_usize(3513).unwrap();
        // Switching u and l should fail:
        let _n: BigUint = rng.gen_biguint_range(&u, &l);
    }
}

mod bigint {
    use rand::thread_rng;
    use num_bigint::{BigInt, RandBigInt};
    use num_traits::{FromPrimitive, Zero};

    #[test]
    fn test_rand() {
        let mut rng = thread_rng();
        let _n: BigInt = rng.gen_bigint(137);
        assert!(rng.gen_bigint(0).is_zero());
    }

    #[test]
    fn test_rand_range() {
        let mut rng = thread_rng();

        for _ in 0..10 {
            assert_eq!(rng.gen_bigint_range(&FromPrimitive::from_usize(236).unwrap(),
            &FromPrimitive::from_usize(237).unwrap()),
            FromPrimitive::from_usize(236).unwrap());
        }

        fn check(l: BigInt, u: BigInt) {
            let mut rng = thread_rng();
            for _ in 0..1000 {
                let n: BigInt = rng.gen_bigint_range(&l, &u);
                assert!(n >= l);
                assert!(n < u);
            }
        }
        let l: BigInt = FromPrimitive::from_usize(403469000 + 2352).unwrap();
        let u: BigInt = FromPrimitive::from_usize(403469000 + 3513).unwrap();
        check(l.clone(), u.clone());
        check(-l.clone(), u.clone());
        check(-u.clone(), -l.clone());
    }

    #[test]
    #[should_panic]
    fn test_zero_rand_range() {
        thread_rng().gen_bigint_range(&FromPrimitive::from_isize(54).unwrap(),
        &FromPrimitive::from_isize(54).unwrap());
    }

    #[test]
    #[should_panic]
    fn test_negative_rand_range() {
        let mut rng = thread_rng();
        let l = FromPrimitive::from_usize(2352).unwrap();
        let u = FromPrimitive::from_usize(3513).unwrap();
        // Switching u and l should fail:
        let _n: BigInt = rng.gen_bigint_range(&u, &l);
    }
}
<commit_msg>refactor tests/rand.rs<commit_after>#![cfg(feature = "rand")]

extern crate num_bigint;
extern crate num_traits;
extern crate rand;

mod biguint {
    use num_bigint::{BigUint, RandBigInt};
    use num_traits::Zero;
    use rand::thread_rng;

    #[test]
    fn test_rand() {
        let mut rng = thread_rng();
        let _n: BigUint = rng.gen_biguint(137);
        assert!(rng.gen_biguint(0).is_zero());
    }

    #[test]
    fn test_rand_range() {
        let mut rng = thread_rng();

        for _ in 0..10 {
            assert_eq!(
                rng.gen_biguint_range(&BigUint::from(236u32), &BigUint::from(237u32)),
                BigUint::from(236u32)
            );
        }

        let l = BigUint::from(403469000u32 + 2352);
        let u = BigUint::from(403469000u32 + 3513);
        for _ in 0..1000 {
            let n: BigUint = rng.gen_biguint_below(&u);
            assert!(n < u);

            let n: BigUint = rng.gen_biguint_range(&l, &u);
            assert!(n >= l);
            assert!(n < u);
        }
    }

    #[test]
    #[should_panic]
    fn test_zero_rand_range() {
        thread_rng().gen_biguint_range(&BigUint::from(54u32), &BigUint::from(54u32));
    }

    #[test]
    #[should_panic]
    fn test_negative_rand_range() {
        let mut rng = thread_rng();
        let l = BigUint::from(2352u32);
        let u = BigUint::from(3513u32);
        // Switching u and l should fail:
        let _n: BigUint = rng.gen_biguint_range(&u, &l);
    }
}

mod bigint {
    use num_bigint::{BigInt, RandBigInt};
    use num_traits::Zero;
    use rand::thread_rng;

    #[test]
    fn test_rand() {
        let mut rng = thread_rng();
        let _n: BigInt = rng.gen_bigint(137);
        assert!(rng.gen_bigint(0).is_zero());
    }

    #[test]
    fn test_rand_range() {
        let mut rng = thread_rng();

        for _ in 0..10 {
            assert_eq!(
                rng.gen_bigint_range(&BigInt::from(236), &BigInt::from(237)),
                BigInt::from(236)
            );
        }

        fn check(l: BigInt, u: BigInt) {
            let mut rng = thread_rng();
            for _ in 0..1000 {
                let n: BigInt = rng.gen_bigint_range(&l, &u);
                assert!(n >= l);
                assert!(n < u);
            }
        }
        let l: BigInt = BigInt::from(403469000 + 2352);
        let u: BigInt = BigInt::from(403469000 + 3513);
        check(l.clone(), u.clone());
        check(-l.clone(), u.clone());
        check(-u.clone(), -l.clone());
    }

    #[test]
    #[should_panic]
    fn test_zero_rand_range() {
        thread_rng().gen_bigint_range(&BigInt::from(54), &BigInt::from(54));
    }

    #[test]
    #[should_panic]
    fn test_negative_rand_range() {
        let mut rng = thread_rng();
        let l = BigInt::from(2352);
        let u = BigInt::from(3513);
        // Switching u and l should fail:
        let _n: BigInt = rng.gen_bigint_range(&u, &l);
    }
}
<|endoftext|>


<commit_before>use anyhow::{Result};
use sled;
use teloxide::{prelude::*, utils::command::BotCommand};
use uuid::Uuid;

use crate::db;

#[derive(BotCommand)]
#[command(rename = "lowercase", description = "these commands are available:")]
enum Command {
    #[command(description = "Add a video")]
    Add,
    #[command()]
    Help,
    #[command()]
    Start,
}

async fn add(cx: DispatcherHandlerCx<Message>) -> Result<()> {
    let text = if let Some(text) = cx.update.text() {
        text
    } else {
        cx.answer("please send me a video URL").send().await?;
        return Ok(());
    };
    let parts: Vec<&str> = text.split_whitespace().collect();
    if parts.len() > 2 {
        cx.answer("please send only one url").send().await?;
        return Ok(());
    } else if parts.len() < 2 {
        cx.answer("please send a video url").send().await?;
        return Ok(());
    }

    let url = parts[1];

    let tree = sled::open("db.sled")?;
    let chat_name = db::get_or_create_chat_name(cx.chat_id(), &tree)?;
    let uuid = Uuid::new_v4();
    let mut queue = db::get_or_create_queue(&tree, &chat_name)?;
    queue.push((uuid, url.into()));

    println!("{:?}", queue);

    tree.insert(&chat_name, bincode::serialize(&queue)?)?;

    Ok(())
}

async fn help(cx: DispatcherHandlerCx<Message>) -> Result<()> {
    cx.answer(Command::descriptions()).send().await?;
    Ok(())
}

async fn start(cx: DispatcherHandlerCx<Message>) -> Result<()> {
    let tree = sled::open("db.sled")?;
    let chat_name = db::get_or_create_chat_name(cx.chat_id(), &tree)?;
    cx.answer(format!(
        "Your chat ID is \"{}\". Use this when starting the mediaqbot client.",
        chat_name
    ))
    .send()
    .await?;
    Ok(())
}

async fn answer(cx: DispatcherHandlerCx<Message>, command: Command) -> Result<()> {
    match command {
        Command::Add => add(cx).await?,
        Command::Help => help(cx).await?,
        Command::Start => start(cx).await?,
    };

    Ok(())
}

async fn handle_commands(rx: DispatcherHandlerRx<Message>) {
    rx.commands::<Command, &str>("mediaqbot")
        .for_each_concurrent(None, |(cx, command, _)| async move {
            answer(cx, command).await.log_on_error().await;
        })
        .await;
}

pub async fn run(bot: std::sync::Arc<Bot>) -> Result<()> {
    Dispatcher::new(bot)
        .messages_handler(handle_commands)
        .dispatch()
        .await;

    Ok(())
}
<commit_msg>remove debug logs<commit_after>use anyhow::{Result};
use sled;
use teloxide::{prelude::*, utils::command::BotCommand};
use uuid::Uuid;

use crate::db;

#[derive(BotCommand)]
#[command(rename = "lowercase", description = "these commands are available:")]
enum Command {
    #[command(description = "Add a video")]
    Add,
    #[command()]
    Help,
    #[command()]
    Start,
}

async fn add(cx: DispatcherHandlerCx<Message>) -> Result<()> {
    let text = if let Some(text) = cx.update.text() {
        text
    } else {
        cx.answer("please send me a video URL").send().await?;
        return Ok(());
    };
    let parts: Vec<&str> = text.split_whitespace().collect();
    if parts.len() > 2 {
        cx.answer("please send only one url").send().await?;
        return Ok(());
    } else if parts.len() < 2 {
        cx.answer("please send a video url").send().await?;
        return Ok(());
    }

    let url = parts[1];

    let tree = sled::open("db.sled")?;
    let chat_name = db::get_or_create_chat_name(cx.chat_id(), &tree)?;
    let uuid = Uuid::new_v4();
    let mut queue = db::get_or_create_queue(&tree, &chat_name)?;
    queue.push((uuid, url.into()));

    tree.insert(&chat_name, bincode::serialize(&queue)?)?;

    Ok(())
}

async fn help(cx: DispatcherHandlerCx<Message>) -> Result<()> {
    cx.answer(Command::descriptions()).send().await?;
    Ok(())
}

async fn start(cx: DispatcherHandlerCx<Message>) -> Result<()> {
    let tree = sled::open("db.sled")?;
    let chat_name = db::get_or_create_chat_name(cx.chat_id(), &tree)?;
    cx.answer(format!(
        "Your chat ID is \"{}\". Use this when starting the mediaqbot client.",
        chat_name
    ))
    .send()
    .await?;
    Ok(())
}

async fn answer(cx: DispatcherHandlerCx<Message>, command: Command) -> Result<()> {
    match command {
        Command::Add => add(cx).await?,
        Command::Help => help(cx).await?,
        Command::Start => start(cx).await?,
    };

    Ok(())
}

async fn handle_commands(rx: DispatcherHandlerRx<Message>) {
    rx.commands::<Command, &str>("mediaqbot")
        .for_each_concurrent(None, |(cx, command, _)| async move {
            answer(cx, command).await.log_on_error().await;
        })
        .await;
}

pub async fn run(bot: std::sync::Arc<Bot>) -> Result<()> {
    Dispatcher::new(bot)
        .messages_handler(handle_commands)
        .dispatch()
        .await;

    Ok(())
}
<|endoftext|>


<commit_before>/// External linking is a complex implementation to be able to serve a clean and easy-to-use
/// interface.
///
/// Internally, there are no such things as "external links" (plural). Each Entry in the store can
/// only have _one_ external link.
///
/// This library does the following therefor: It allows you to have several external links with one
/// entry, which are internally one file in the store for each link, linked with "internal
/// linking".
///
/// This helps us greatly with deduplication of URLs.
///

use std::ops::DerefMut;
use std::collections::BTreeMap;

use libimagstore::store::Entry;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use libimagstore::storeid::StoreId;
use libimagstore::storeid::IntoStoreId;

use error::LinkError as LE;
use error::LinkErrorKind as LEK;
use result::Result;
use internal::InternalLinker;
use module_path::ModuleEntryPath;

use toml::Value;
use url::Url;
use crypto::sha1::Sha1;
use crypto::digest::Digest;

/// "Link" Type, just an abstraction over `FileLockEntry` to have some convenience internally.
pub struct Link<'a> {
    link: FileLockEntry<'a>
}

impl<'a> Link<'a> {

    pub fn new(fle: FileLockEntry<'a>) -> Link<'a> {
        Link { link: fle }
    }

    /// For interal use only. Load an Link from a store id, if this is actually a Link
    fn retrieve(store: &'a Store, id: StoreId) -> Result<Option<Link<'a>>> {
        store.retrieve(id)
            .map(|fle| Link::get_link_uri_from_filelockentry(&fle).map(|_| Link { link: fle }))
            .map_err(|e| LE::new(LEK::StoreReadError, Some(Box::new(e))))
    }

    /// Get a link Url object from a `FileLockEntry`, ignore errors.
    fn get_link_uri_from_filelockentry(file: &FileLockEntry<'a>) -> Option<Url> {
        file.get_header()
            .read("imag.content.uri")
            .ok()
            .and_then(|opt| match opt {
                Some(Value::String(s)) => Url::parse(&s[..]).ok(),
                _ => None
            })
    }

    pub fn get_url(&self) -> Result<Option<Url>> {
        let opt = self.link
            .get_header()
            .read("imag.content.uri");

        match opt {
            Ok(Some(Value::String(s))) => {
                Url::parse(&s[..])
                     .map(Some)
                     .map_err(|e| LE::new(LEK::EntryHeaderReadError, Some(Box::new(e))))
            },
            Ok(None) => Ok(None),
            _ => Err(LE::new(LEK::EntryHeaderReadError, None))
        }
    }

}

pub trait ExternalLinker : InternalLinker {

    /// Get the external links from the implementor object
    fn get_external_links(&self, store: &Store) -> Result<Vec<Url>>;

    /// Set the external links for the implementor object
    fn set_external_links(&mut self, store: &Store, links: Vec<Url>) -> Result<()>;

    /// Add an external link to the implementor object
    fn add_external_link(&mut self, store: &Store, link: Url) -> Result<()>;

    /// Remove an external link from the implementor object
    fn remove_external_link(&mut self, store: &Store, link: Url) -> Result<()>;

}

/// Check whether the StoreId starts with `/link/external/`
pub fn is_external_link_storeid(id: &StoreId) -> bool {
    debug!("Checking whether this is a /link/external/*: '{:?}'", id);
    id.to_str().map(|s| s.contains("/link/external/")).unwrap_or(false)
}

fn get_external_link_from_file(entry: &FileLockEntry) -> Result<Url> {
    Link::get_link_uri_from_filelockentry(entry) // TODO: Do not hide error by using this function
        .ok_or(LE::new(LEK::StoreReadError, None))
}

/// Implement `ExternalLinker` for `Entry`, hiding the fact that there is no such thing as an external
/// link in an entry, but internal links to other entries which serve as external links, as one
/// entry in the store can only have one external link.
impl ExternalLinker for Entry {

    /// Get the external links from the implementor object
    fn get_external_links(&self, store: &Store) -> Result<Vec<Url>> {
        // Iterate through all internal links and filter for FileLockEntries which live in
        // /link/external/<SHA> -> load these files and get the external link from their headers,
        // put them into the return vector.
        self.get_internal_links()
            .map(|vect| {
                debug!("Getting external links");
                vect.into_iter()
                    .filter(is_external_link_storeid)
                    .map(|id| {
                        debug!("Retrieving entry for id: '{:?}'", id);
                        match store.retrieve(id.clone()) {
                            Ok(f) => get_external_link_from_file(&f),
                            Err(e) => {
                                debug!("Retrieving entry for id: '{:?}' failed", id);
                                Err(LE::new(LEK::StoreReadError, Some(Box::new(e))))
                            }
                        }
                    })
                    .filter_map(|x| x.ok()) // TODO: Do not ignore error here
                    .collect()
            })
            .map_err(|e| LE::new(LEK::StoreReadError, Some(Box::new(e))))
    }

    /// Set the external links for the implementor object
    fn set_external_links(&mut self, store: &Store, links: Vec<Url>) -> Result<()> {
        // Take all the links, generate a SHA sum out of each one, filter out the already existing
        // store entries and store the other URIs in the header of one FileLockEntry each, in
        // the path /link/external/<SHA of the URL>

        debug!("Iterating {} links = {:?}", links.len(), links);
        for link in links { // for all links
            let hash = {
                let mut s = Sha1::new();
                s.input_str(&link.as_str()[..]);
                s.result_str()
            };
            let file_id = ModuleEntryPath::new(format!("external/{}", hash)).into_storeid();

            debug!("Link    = '{:?}'", link);
            debug!("Hash    = '{:?}'", hash);
            debug!("StoreId = '{:?}'", file_id);

            // retrieve the file from the store, which implicitely creates the entry if it does not
            // exist
            let file = store.retrieve(file_id.clone());
            if file.is_err() {
                debug!("Failed to create or retrieve an file for this link '{:?}'", link);
                return Err(LE::new(LEK::StoreWriteError, Some(Box::new(file.unwrap_err()))));
            }
            let mut file = file.unwrap();

            debug!("Generating header content!");
            {
                let mut hdr = file.deref_mut().get_header_mut();

                let mut table = match hdr.read("imag.content") {
                    Ok(Some(Value::Table(table))) => table,
                    Ok(Some(_)) => {
                        warn!("There is a value at 'imag.content' which is not a table.");
                        warn!("Going to override this value");
                        BTreeMap::new()
                    },
                    Ok(None) => BTreeMap::new(),
                    Err(e)   => return Err(LE::new(LEK::StoreWriteError, Some(Box::new(e)))),
                };

                let v = Value::String(link.into_string());

                debug!("setting URL = '{:?}", v);
                table.insert(String::from("url"), v);

                if let Err(e) = hdr.set("imag.content", Value::Table(table)) {
                    return Err(LE::new(LEK::StoreWriteError, Some(Box::new(e))));
                } else {
                    debug!("Setting URL worked");
                }
            }

            // then add an internal link to the new file or return an error if this fails
            if let Err(e) = self.add_internal_link(file.deref_mut()) {
                debug!("Error adding internal link");
                return Err(LE::new(LEK::StoreWriteError, Some(Box::new(e))));
            }
        }
        debug!("Ready iterating");
        Ok(())
    }

    /// Add an external link to the implementor object
    fn add_external_link(&mut self, store: &Store, link: Url) -> Result<()> {
        // get external links, add this one, save them
        debug!("Getting links");
        self.get_external_links(store)
            .and_then(|mut links| {
                debug!("Adding link = '{:?}' to links = {:?}", link, links);
                links.push(link);
                debug!("Setting {} links = {:?}", links.len(), links);
                self.set_external_links(store, links)
            })
    }

    /// Remove an external link from the implementor object
    fn remove_external_link(&mut self, store: &Store, link: Url) -> Result<()> {
        // get external links, remove this one, save them
        self.get_external_links(store)
            .and_then(|links| {
                debug!("Removing link = '{:?}' from links = {:?}", link, links);
                let links = links.into_iter()
                    .filter(|l| l.as_str() != link.as_str())
                    .collect();
                self.set_external_links(store, links)
            })
    }

}

<commit_msg>Add more robust version of is_external_link_storeid() helper function<commit_after>/// External linking is a complex implementation to be able to serve a clean and easy-to-use
/// interface.
///
/// Internally, there are no such things as "external links" (plural). Each Entry in the store can
/// only have _one_ external link.
///
/// This library does the following therefor: It allows you to have several external links with one
/// entry, which are internally one file in the store for each link, linked with "internal
/// linking".
///
/// This helps us greatly with deduplication of URLs.
///

use std::ops::DerefMut;
use std::collections::BTreeMap;

use libimagstore::store::Entry;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use libimagstore::storeid::StoreId;
use libimagstore::storeid::IntoStoreId;

use error::LinkError as LE;
use error::LinkErrorKind as LEK;
use result::Result;
use internal::InternalLinker;
use module_path::ModuleEntryPath;

use toml::Value;
use url::Url;
use crypto::sha1::Sha1;
use crypto::digest::Digest;

/// "Link" Type, just an abstraction over `FileLockEntry` to have some convenience internally.
pub struct Link<'a> {
    link: FileLockEntry<'a>
}

impl<'a> Link<'a> {

    pub fn new(fle: FileLockEntry<'a>) -> Link<'a> {
        Link { link: fle }
    }

    /// For interal use only. Load an Link from a store id, if this is actually a Link
    fn retrieve(store: &'a Store, id: StoreId) -> Result<Option<Link<'a>>> {
        store.retrieve(id)
            .map(|fle| Link::get_link_uri_from_filelockentry(&fle).map(|_| Link { link: fle }))
            .map_err(|e| LE::new(LEK::StoreReadError, Some(Box::new(e))))
    }

    /// Get a link Url object from a `FileLockEntry`, ignore errors.
    fn get_link_uri_from_filelockentry(file: &FileLockEntry<'a>) -> Option<Url> {
        file.get_header()
            .read("imag.content.uri")
            .ok()
            .and_then(|opt| match opt {
                Some(Value::String(s)) => Url::parse(&s[..]).ok(),
                _ => None
            })
    }

    pub fn get_url(&self) -> Result<Option<Url>> {
        let opt = self.link
            .get_header()
            .read("imag.content.uri");

        match opt {
            Ok(Some(Value::String(s))) => {
                Url::parse(&s[..])
                     .map(Some)
                     .map_err(|e| LE::new(LEK::EntryHeaderReadError, Some(Box::new(e))))
            },
            Ok(None) => Ok(None),
            _ => Err(LE::new(LEK::EntryHeaderReadError, None))
        }
    }

}

pub trait ExternalLinker : InternalLinker {

    /// Get the external links from the implementor object
    fn get_external_links(&self, store: &Store) -> Result<Vec<Url>>;

    /// Set the external links for the implementor object
    fn set_external_links(&mut self, store: &Store, links: Vec<Url>) -> Result<()>;

    /// Add an external link to the implementor object
    fn add_external_link(&mut self, store: &Store, link: Url) -> Result<()>;

    /// Remove an external link from the implementor object
    fn remove_external_link(&mut self, store: &Store, link: Url) -> Result<()>;

}

/// Check whether the StoreId starts with `/link/external/`
pub fn is_external_link_storeid(id: &StoreId) -> bool {
    debug!("Checking whether this is a /link/external/*: '{:?}'", id);
    id.parent().map(|par| par.ends_with("/link/external")).unwrap_or(false)
}

fn get_external_link_from_file(entry: &FileLockEntry) -> Result<Url> {
    Link::get_link_uri_from_filelockentry(entry) // TODO: Do not hide error by using this function
        .ok_or(LE::new(LEK::StoreReadError, None))
}

/// Implement `ExternalLinker` for `Entry`, hiding the fact that there is no such thing as an external
/// link in an entry, but internal links to other entries which serve as external links, as one
/// entry in the store can only have one external link.
impl ExternalLinker for Entry {

    /// Get the external links from the implementor object
    fn get_external_links(&self, store: &Store) -> Result<Vec<Url>> {
        // Iterate through all internal links and filter for FileLockEntries which live in
        // /link/external/<SHA> -> load these files and get the external link from their headers,
        // put them into the return vector.
        self.get_internal_links()
            .map(|vect| {
                debug!("Getting external links");
                vect.into_iter()
                    .filter(is_external_link_storeid)
                    .map(|id| {
                        debug!("Retrieving entry for id: '{:?}'", id);
                        match store.retrieve(id.clone()) {
                            Ok(f) => get_external_link_from_file(&f),
                            Err(e) => {
                                debug!("Retrieving entry for id: '{:?}' failed", id);
                                Err(LE::new(LEK::StoreReadError, Some(Box::new(e))))
                            }
                        }
                    })
                    .filter_map(|x| x.ok()) // TODO: Do not ignore error here
                    .collect()
            })
            .map_err(|e| LE::new(LEK::StoreReadError, Some(Box::new(e))))
    }

    /// Set the external links for the implementor object
    fn set_external_links(&mut self, store: &Store, links: Vec<Url>) -> Result<()> {
        // Take all the links, generate a SHA sum out of each one, filter out the already existing
        // store entries and store the other URIs in the header of one FileLockEntry each, in
        // the path /link/external/<SHA of the URL>

        debug!("Iterating {} links = {:?}", links.len(), links);
        for link in links { // for all links
            let hash = {
                let mut s = Sha1::new();
                s.input_str(&link.as_str()[..]);
                s.result_str()
            };
            let file_id = ModuleEntryPath::new(format!("external/{}", hash)).into_storeid();

            debug!("Link    = '{:?}'", link);
            debug!("Hash    = '{:?}'", hash);
            debug!("StoreId = '{:?}'", file_id);

            // retrieve the file from the store, which implicitely creates the entry if it does not
            // exist
            let file = store.retrieve(file_id.clone());
            if file.is_err() {
                debug!("Failed to create or retrieve an file for this link '{:?}'", link);
                return Err(LE::new(LEK::StoreWriteError, Some(Box::new(file.unwrap_err()))));
            }
            let mut file = file.unwrap();

            debug!("Generating header content!");
            {
                let mut hdr = file.deref_mut().get_header_mut();

                let mut table = match hdr.read("imag.content") {
                    Ok(Some(Value::Table(table))) => table,
                    Ok(Some(_)) => {
                        warn!("There is a value at 'imag.content' which is not a table.");
                        warn!("Going to override this value");
                        BTreeMap::new()
                    },
                    Ok(None) => BTreeMap::new(),
                    Err(e)   => return Err(LE::new(LEK::StoreWriteError, Some(Box::new(e)))),
                };

                let v = Value::String(link.into_string());

                debug!("setting URL = '{:?}", v);
                table.insert(String::from("url"), v);

                if let Err(e) = hdr.set("imag.content", Value::Table(table)) {
                    return Err(LE::new(LEK::StoreWriteError, Some(Box::new(e))));
                } else {
                    debug!("Setting URL worked");
                }
            }

            // then add an internal link to the new file or return an error if this fails
            if let Err(e) = self.add_internal_link(file.deref_mut()) {
                debug!("Error adding internal link");
                return Err(LE::new(LEK::StoreWriteError, Some(Box::new(e))));
            }
        }
        debug!("Ready iterating");
        Ok(())
    }

    /// Add an external link to the implementor object
    fn add_external_link(&mut self, store: &Store, link: Url) -> Result<()> {
        // get external links, add this one, save them
        debug!("Getting links");
        self.get_external_links(store)
            .and_then(|mut links| {
                debug!("Adding link = '{:?}' to links = {:?}", link, links);
                links.push(link);
                debug!("Setting {} links = {:?}", links.len(), links);
                self.set_external_links(store, links)
            })
    }

    /// Remove an external link from the implementor object
    fn remove_external_link(&mut self, store: &Store, link: Url) -> Result<()> {
        // get external links, remove this one, save them
        self.get_external_links(store)
            .and_then(|links| {
                debug!("Removing link = '{:?}' from links = {:?}", link, links);
                let links = links.into_iter()
                    .filter(|l| l.as_str() != link.as_str())
                    .collect();
                self.set_external_links(store, links)
            })
    }

}

<|endoftext|>


<commit_before>extern crate nalgebra;
extern crate acacia;

use std::rand::thread_rng;
use std::rand::distributions::{Range, IndependentSample};
use std::num::Float;
use nalgebra::{Pnt3, Vec3, FloatPnt, Norm, Orig, zero};
use acacia::ntree::NTree;
use acacia::tree::{DataQuery, Node, AssociatedData, Positionable};

/// Point mass
struct PointMass {
    mass: f64,
    position: Pnt3<f64>,
}

impl Positionable<Pnt3<f64>> for PointMass {
    fn position(&self) -> Pnt3<f64> {
        self.position
    }
}

/// Newton's law of gravity for two point masses (with G = 1)
fn newton(m: f64, p1: Pnt3<f64>, p2: Pnt3<f64>) -> Vec3<f64> {
    let diff: Vec3<f64> = p1 - p2;
    let r = diff.norm();
    diff * m / r.powi(3)
}

fn main() {
    // Shortcut
    let origin: Pnt3<f64> = Orig::orig();

    // Generate a number of particles
    let mut rng = thread_rng();
    let coord_range = Range::new(-5.0, 5.0);
    let particles: Vec<_> = range(0u, 1000).map(|_|
        PointMass { mass: 1.0, position: Pnt3::new(
            coord_range.ind_sample(&mut rng),
            coord_range.ind_sample(&mut rng),
            coord_range.ind_sample(&mut rng)) })
        .collect();

    // Construct the tree
    let tree = NTree::from_iter(

        // Pass in an iterator over the objects to store in the tree
        // In this case we pass in &PointMass, which implements Positionable.
        particles.iter(),

        // The value for the associated data of empty nodes. Here, we associate
        // a center of mass and a total mass to each node.
        (origin, 0.0),

        // This closure associates data to a leaf node from its object.
        &|obj| (obj.position, obj.mass),

        // This combines two pieces of associated data and thus prescribes how
        // branch nodes on higher levels get their associated data.
        &|&(com1, m1), &(com2, m2)|
            if m1 + m2 > 0.0 {(
                origin + (com1.to_vec() * m1 + com2.to_vec() * m2) / (m1 + m2),
                m1 + m2,
            )}
            else {
                (origin, 0.0)
            }
    );

    // This is the point, at which we want to know the gravitational
    // acceleration.
    let test_point = Pnt3::new(2.3, -4.1, 1.6);

    let mut tree_gravity: Vec3<f64> = zero();
    tree.query_data(

        // This is the recursion criterion. If a branch node passes this, the
        // query continues on its children.
        &|node| {
            let &(ref center_of_mass, _) = node.data();
            let d = test_point.dist(center_of_mass);
            let delta: f64 = node.center().dist(center_of_mass);
            d < 2.0 * *node.width() + delta
        },

        // This collects our force term from each piece of associated data the
        // tree encounters during recursion.
        &mut |&(center_of_mass, mass)| {
            tree_gravity = tree_gravity + newton(mass, center_of_mass, test_point);
        },
    );

    // Calculate gravity exactly for comparison
    let exact_gravity = particles.iter()
        .map(|particle| newton(particle.mass, particle.position, test_point))
        .fold(zero(), |a: Vec3<f64>, b| a + b);

    // Print result of calculation
    println!("Tree-computed gravity at {} is {} (exact: {})",
        test_point, tree_gravity, exact_gravity
    );
}
<commit_msg>Adapt gravity example to the new API<commit_after>#![allow(unstable)]

extern crate nalgebra;
extern crate acacia;

use std::rand::thread_rng;
use std::rand::distributions::{Range, IndependentSample};
use std::num::Float;
use nalgebra::{Pnt3, Vec3, FloatPnt, Norm, Orig, zero};
use acacia::ntree::Tree;
use acacia::tree::{DataQuery, Node, AssociatedData, Position};
use acacia::partition::Ncube;

/// Point mass
struct PointMass {
    mass: f64,
    position: Pnt3<f64>,
}

impl Position for PointMass {
    type Point = Pnt3<f64>;
    fn position(&self) -> Pnt3<f64> {
        self.position
    }
}

/// Newton's law of gravity for two point masses (with G = 1)
fn newton(m: f64, p1: Pnt3<f64>, p2: Pnt3<f64>) -> Vec3<f64> {
    let diff: Vec3<f64> = p1 - p2;
    let r = diff.norm();
    diff * m / r.powi(3)
}

fn main() {
    // Shortcut
    let origin: Pnt3<f64> = Orig::orig();

    // Generate a number of particles
    let mut rng = thread_rng();
    let coord_range = Range::new(-5.0, 5.0);
    let particles: Vec<_> = (0..1000).map(|_|
        PointMass { mass: 1.0, position: Pnt3::new(
            coord_range.ind_sample(&mut rng),
            coord_range.ind_sample(&mut rng),
            coord_range.ind_sample(&mut rng)) })
        .collect();

    // Construct the tree
    let tree = Tree::new(

        // Pass in an iterator over the objects to store in the tree
        // In this case we pass in &PointMass, which implements Positionable.
        particles.iter(),

        // Shape of the root node
        Ncube::new(origin, 11.0),

        // The value for the associated data of empty nodes. Here, we associate
        // a center of mass and a total mass to each node.
        (origin, 0.0),

        // This closure associates data to a leaf node from its object.
        &|obj| (obj.position, obj.mass),

        // This combines two pieces of associated data and thus prescribes how
        // branch nodes on higher levels get their associated data.
        &|&(com1, m1), &(com2, m2)|
            if m1 + m2 > 0.0 {(
                origin + (com1.to_vec() * m1 + com2.to_vec() * m2) / (m1 + m2),
                m1 + m2,
            )}
            else {
                (origin, 0.0)
            }
    );

    // This is the point, at which we want to know the gravitational
    // acceleration.
    let test_point = Pnt3::new(2.3, -4.1, 1.6);

    let mut tree_gravity: Vec3<f64> = zero();
    tree.query_data(

        // This is the recursion criterion. If a branch node passes this, the
        // query continues on its children.
        &|node| {
            let &(ref center_of_mass, _) = node.data();
            let d = test_point.dist(center_of_mass);
            let delta: f64 = node.partition().center().dist(center_of_mass);
            d < 2.0 * node.partition().width() + delta
        },

        // This collects our force term from each piece of associated data the
        // tree encounters during recursion.
        &mut |&(center_of_mass, mass)| {
            tree_gravity = tree_gravity + newton(mass, center_of_mass, test_point);
        },
    );

    // Calculate gravity exactly for comparison
    let exact_gravity = particles.iter()
        .map(|particle| newton(particle.mass, particle.position, test_point))
        .fold(zero(), |a: Vec3<f64>, b| a + b);

    // Print result of calculation
    println!("Tree-computed gravity at {:?} is {:?} (exact: {:?})",
        test_point, tree_gravity, exact_gravity
    );
}
<|endoftext|>