<commit_before>#![allow(clippy::module_name_repetitions)]

use crate::{EnumArray, EnumMap};
use core::iter::{Enumerate, FusedIterator};
use core::marker::PhantomData;
use core::mem::ManuallyDrop;
use core::ops::Range;
use core::ptr;
use core::slice;

/// Immutable enum map iterator
///
/// This struct is created by `iter` method or `into_iter` on a reference
/// to `EnumMap`.
///
/// # Examples
///
/// ```
/// # extern crate enum_map;
/// use enum_map::{enum_map, Enum};
///
/// #[derive(Enum)]
/// enum Example {
///     A,
///     B,
///     C,
/// }
///
/// let mut map = enum_map! { Example::A => 3, _ => 0 };
/// assert_eq!(map[Example::A], 3);
/// for (key, &value) in &map {
///     assert_eq!(value, match key {
///         Example::A => 3,
///         _ => 0,
///     });
/// }
/// ```
#[derive(Debug)]
pub struct Iter<'a, K, V: 'a> {
    _phantom: PhantomData<fn() -> K>,
    iterator: Enumerate<slice::Iter<'a, V>>,
}

impl<'a, K: EnumArray<V>, V> Clone for Iter<'a, K, V> {
    fn clone(&self) -> Self {
        Iter {
            _phantom: PhantomData,
            iterator: self.iterator.clone(),
        }
    }
}

impl<'a, K: EnumArray<V>, V> Iterator for Iter<'a, K, V> {
    type Item = (K, &'a V);
    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.iterator
            .next()
            .map(|(index, item)| (K::from_usize(index), item))
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iterator.size_hint()
    }

    fn fold<B, F>(self, init: B, f: F) -> B
    where
        F: FnMut(B, Self::Item) -> B,
    {
        self.iterator
            .map(|(index, item)| (K::from_usize(index), item))
            .fold(init, f)
    }
}

impl<'a, K: EnumArray<V>, V> DoubleEndedIterator for Iter<'a, K, V> {
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item> {
        self.iterator
            .next_back()
            .map(|(index, item)| (K::from_usize(index), item))
    }
}

impl<'a, K: EnumArray<V>, V> ExactSizeIterator for Iter<'a, K, V> {}

impl<'a, K: EnumArray<V>, V> FusedIterator for Iter<'a, K, V> {}

impl<'a, K: EnumArray<V>, V> IntoIterator for &'a EnumMap<K, V> {
    type Item = (K, &'a V);
    type IntoIter = Iter<'a, K, V>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        Iter {
            _phantom: PhantomData,
            iterator: self.as_slice().iter().enumerate(),
        }
    }
}

/// Mutable map iterator
///
/// This struct is created by `iter_mut` method or `into_iter` on a mutable
/// reference to `EnumMap`.
///
/// # Examples
///
/// ```
/// # extern crate enum_map;
/// use enum_map::{enum_map, Enum};
///
/// #[derive(Debug, Enum)]
/// enum Example {
///     A,
///     B,
///     C,
/// }
///
/// let mut map = enum_map! { Example::A => 3, _ => 0 };
/// for (_, value) in &mut map {
///     *value += 1;
/// }
/// assert_eq!(map, enum_map! { Example::A => 4, _ => 1 });
/// ```
#[derive(Debug)]
pub struct IterMut<'a, K, V: 'a> {
    _phantom: PhantomData<fn() -> K>,
    iterator: Enumerate<slice::IterMut<'a, V>>,
}

impl<'a, K: EnumArray<V>, V> Iterator for IterMut<'a, K, V> {
    type Item = (K, &'a mut V);
    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.iterator
            .next()
            .map(|(index, item)| (K::from_usize(index), item))
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iterator.size_hint()
    }

    fn fold<B, F>(self, init: B, f: F) -> B
    where
        F: FnMut(B, Self::Item) -> B,
    {
        self.iterator
            .map(|(index, item)| (K::from_usize(index), item))
            .fold(init, f)
    }
}

impl<'a, K: EnumArray<V>, V> DoubleEndedIterator for IterMut<'a, K, V> {
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item> {
        self.iterator
            .next_back()
            .map(|(index, item)| (K::from_usize(index), item))
    }
}

impl<'a, K: EnumArray<V>, V> ExactSizeIterator for IterMut<'a, K, V> {}

impl<'a, K: EnumArray<V>, V> FusedIterator for IterMut<'a, K, V> {}

impl<'a, K: EnumArray<V>, V> IntoIterator for &'a mut EnumMap<K, V> {
    type Item = (K, &'a mut V);
    type IntoIter = IterMut<'a, K, V>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        IterMut {
            _phantom: PhantomData,
            iterator: self.as_mut_slice().iter_mut().enumerate(),
        }
    }
}

/// A map iterator that moves out of map.
///
/// This struct is created by `into_iter` on `EnumMap`.
///
/// # Examples
///
/// ```
/// # extern crate enum_map;
/// use enum_map::{enum_map, Enum};
///
/// #[derive(Debug, Enum)]
/// enum Example {
///     A,
///     B,
/// }
///
/// let map = enum_map! { Example::A | Example::B => String::from("123") };
/// for (_, value) in map {
///     assert_eq!(value + "4", "1234");
/// }
/// ```
pub struct IntoIter<K: EnumArray<V>, V> {
    map: ManuallyDrop<EnumMap<K, V>>,
    alive: Range<usize>,
}

impl<K: EnumArray<V>, V> Iterator for IntoIter<K, V> {
    type Item = (K, V);
    fn next(&mut self) -> Option<(K, V)> {
        let position = self.alive.next()?;
        Some((K::from_usize(position), unsafe {
            ptr::read(&self.map.as_slice()[position])
        }))
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.alive.size_hint()
    }
}

impl<K: EnumArray<V>, V> DoubleEndedIterator for IntoIter<K, V> {
    fn next_back(&mut self) -> Option<(K, V)> {
        let position = self.alive.next_back()?;
        Some((K::from_usize(position), unsafe {
            ptr::read(&self.map.as_slice()[position])
        }))
    }
}

impl<K: EnumArray<V>, V> ExactSizeIterator for IntoIter<K, V> {}

impl<K: EnumArray<V>, V> FusedIterator for IntoIter<K, V> {}

impl<K: EnumArray<V>, V> Drop for IntoIter<K, V> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            ptr::drop_in_place(&mut self.map.as_mut_slice()[self.alive.clone()]);
        }
    }
}

impl<K: EnumArray<V>, V> IntoIterator for EnumMap<K, V> {
    type Item = (K, V);
    type IntoIter = IntoIter<K, V>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        let len = self.len();
        IntoIter {
            map: ManuallyDrop::new(self),
            alive: 0..len,
        }
    }
}

impl<K: EnumArray<V>, V> EnumMap<K, V> {
    /// An iterator visiting all values. The iterator type is `&V`.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate enum_map;
    /// use enum_map::enum_map;
    ///
    /// let map = enum_map! { false => 3, true => 4 };
    /// let mut values = map.values();
    /// assert_eq!(values.next(), Some(&3));
    /// assert_eq!(values.next(), Some(&4));
    /// assert_eq!(values.next(), None);
    /// ```
    #[inline]
    pub fn values(&self) -> Values<V> {
        Values(self.as_slice().iter())
    }

    /// An iterator visiting all values mutably. The iterator type is `&mut V`.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate enum_map;
    /// use enum_map::enum_map;
    ///
    /// let mut map = enum_map! { _ => 2 };
    /// for value in map.values_mut() {
    ///     *value += 2;
    /// }
    /// assert_eq!(map[false], 4);
    /// assert_eq!(map[true], 4);
    /// ```
    #[inline]
    pub fn values_mut(&mut self) -> ValuesMut<V> {
        ValuesMut(self.as_mut_slice().iter_mut())
    }

    /// Creates a consuming iterator visiting all the values. The map
    /// cannot be used after calling this. The iterator element type
    /// is `V`.
    #[inline]
    pub fn into_values(self) -> IntoValues<K, V> {
        IntoValues {
            inner: self.into_iter(),
        }
    }
}

/// An iterator over the values of `EnumMap`.
///
/// This `struct` is created by the `values` method of `EnumMap`.
/// See its documentation for more.
pub struct Values<'a, V: 'a>(slice::Iter<'a, V>);

impl<'a, V> Clone for Values<'a, V> {
    fn clone(&self) -> Self {
        Values(self.0.clone())
    }
}

impl<'a, V: 'a> Iterator for Values<'a, V> {
    type Item = &'a V;
    #[inline]
    fn next(&mut self) -> Option<&'a V> {
        self.0.next()
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

impl<'a, V: 'a> DoubleEndedIterator for Values<'a, V> {
    #[inline]
    fn next_back(&mut self) -> Option<&'a V> {
        self.0.next_back()
    }
}

impl<'a, V: 'a> ExactSizeIterator for Values<'a, V> {}

impl<'a, V: 'a> FusedIterator for Values<'a, V> {}

/// A mutable iterator over the values of `EnumMap`.
///
/// This `struct` is created by the `values_mut` method of `EnumMap`.
/// See its documentation for more.
pub struct ValuesMut<'a, V: 'a>(slice::IterMut<'a, V>);

impl<'a, V: 'a> Iterator for ValuesMut<'a, V> {
    type Item = &'a mut V;
    #[inline]
    fn next(&mut self) -> Option<&'a mut V> {
        self.0.next()
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

impl<'a, V: 'a> DoubleEndedIterator for ValuesMut<'a, V> {
    #[inline]
    fn next_back(&mut self) -> Option<&'a mut V> {
        self.0.next_back()
    }
}

impl<'a, V: 'a> ExactSizeIterator for ValuesMut<'a, V> {}

impl<'a, V: 'a> FusedIterator for ValuesMut<'a, V> {}

/// An owning iterator over the values of an `EnumMap`.
///
/// This `struct` is created by the `into_values` method of `EnumMap`.
/// See its documentation for more.
pub struct IntoValues<K: EnumArray<V>, V> {
    inner: IntoIter<K, V>,
}

impl<K, V> Iterator for IntoValues<K, V>
where
    K: EnumArray<V>,
{
    type Item = V;

    fn next(&mut self) -> Option<V> {
        Some(self.inner.next()?.1)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.inner.size_hint()
    }
}

impl<K: EnumArray<V>, V> DoubleEndedIterator for IntoValues<K, V> {
    fn next_back(&mut self) -> Option<V> {
        Some(self.inner.next_back()?.1)
    }
}

impl<K, V> ExactSizeIterator for IntoValues<K, V> where K: EnumArray<V> {}

impl<K, V> FusedIterator for IntoValues<K, V> where K: EnumArray<V> {}
<commit_msg>Provide documentation for into_values<commit_after>#![allow(clippy::module_name_repetitions)]

use crate::{EnumArray, EnumMap};
use core::iter::{Enumerate, FusedIterator};
use core::marker::PhantomData;
use core::mem::ManuallyDrop;
use core::ops::Range;
use core::ptr;
use core::slice;

/// Immutable enum map iterator
///
/// This struct is created by `iter` method or `into_iter` on a reference
/// to `EnumMap`.
///
/// # Examples
///
/// ```
/// # extern crate enum_map;
/// use enum_map::{enum_map, Enum};
///
/// #[derive(Enum)]
/// enum Example {
///     A,
///     B,
///     C,
/// }
///
/// let mut map = enum_map! { Example::A => 3, _ => 0 };
/// assert_eq!(map[Example::A], 3);
/// for (key, &value) in &map {
///     assert_eq!(value, match key {
///         Example::A => 3,
///         _ => 0,
///     });
/// }
/// ```
#[derive(Debug)]
pub struct Iter<'a, K, V: 'a> {
    _phantom: PhantomData<fn() -> K>,
    iterator: Enumerate<slice::Iter<'a, V>>,
}

impl<'a, K: EnumArray<V>, V> Clone for Iter<'a, K, V> {
    fn clone(&self) -> Self {
        Iter {
            _phantom: PhantomData,
            iterator: self.iterator.clone(),
        }
    }
}

impl<'a, K: EnumArray<V>, V> Iterator for Iter<'a, K, V> {
    type Item = (K, &'a V);
    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.iterator
            .next()
            .map(|(index, item)| (K::from_usize(index), item))
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iterator.size_hint()
    }

    fn fold<B, F>(self, init: B, f: F) -> B
    where
        F: FnMut(B, Self::Item) -> B,
    {
        self.iterator
            .map(|(index, item)| (K::from_usize(index), item))
            .fold(init, f)
    }
}

impl<'a, K: EnumArray<V>, V> DoubleEndedIterator for Iter<'a, K, V> {
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item> {
        self.iterator
            .next_back()
            .map(|(index, item)| (K::from_usize(index), item))
    }
}

impl<'a, K: EnumArray<V>, V> ExactSizeIterator for Iter<'a, K, V> {}

impl<'a, K: EnumArray<V>, V> FusedIterator for Iter<'a, K, V> {}

impl<'a, K: EnumArray<V>, V> IntoIterator for &'a EnumMap<K, V> {
    type Item = (K, &'a V);
    type IntoIter = Iter<'a, K, V>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        Iter {
            _phantom: PhantomData,
            iterator: self.as_slice().iter().enumerate(),
        }
    }
}

/// Mutable map iterator
///
/// This struct is created by `iter_mut` method or `into_iter` on a mutable
/// reference to `EnumMap`.
///
/// # Examples
///
/// ```
/// # extern crate enum_map;
/// use enum_map::{enum_map, Enum};
///
/// #[derive(Debug, Enum)]
/// enum Example {
///     A,
///     B,
///     C,
/// }
///
/// let mut map = enum_map! { Example::A => 3, _ => 0 };
/// for (_, value) in &mut map {
///     *value += 1;
/// }
/// assert_eq!(map, enum_map! { Example::A => 4, _ => 1 });
/// ```
#[derive(Debug)]
pub struct IterMut<'a, K, V: 'a> {
    _phantom: PhantomData<fn() -> K>,
    iterator: Enumerate<slice::IterMut<'a, V>>,
}

impl<'a, K: EnumArray<V>, V> Iterator for IterMut<'a, K, V> {
    type Item = (K, &'a mut V);
    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.iterator
            .next()
            .map(|(index, item)| (K::from_usize(index), item))
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iterator.size_hint()
    }

    fn fold<B, F>(self, init: B, f: F) -> B
    where
        F: FnMut(B, Self::Item) -> B,
    {
        self.iterator
            .map(|(index, item)| (K::from_usize(index), item))
            .fold(init, f)
    }
}

impl<'a, K: EnumArray<V>, V> DoubleEndedIterator for IterMut<'a, K, V> {
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item> {
        self.iterator
            .next_back()
            .map(|(index, item)| (K::from_usize(index), item))
    }
}

impl<'a, K: EnumArray<V>, V> ExactSizeIterator for IterMut<'a, K, V> {}

impl<'a, K: EnumArray<V>, V> FusedIterator for IterMut<'a, K, V> {}

impl<'a, K: EnumArray<V>, V> IntoIterator for &'a mut EnumMap<K, V> {
    type Item = (K, &'a mut V);
    type IntoIter = IterMut<'a, K, V>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        IterMut {
            _phantom: PhantomData,
            iterator: self.as_mut_slice().iter_mut().enumerate(),
        }
    }
}

/// A map iterator that moves out of map.
///
/// This struct is created by `into_iter` on `EnumMap`.
///
/// # Examples
///
/// ```
/// # extern crate enum_map;
/// use enum_map::{enum_map, Enum};
///
/// #[derive(Debug, Enum)]
/// enum Example {
///     A,
///     B,
/// }
///
/// let map = enum_map! { Example::A | Example::B => String::from("123") };
/// for (_, value) in map {
///     assert_eq!(value + "4", "1234");
/// }
/// ```
pub struct IntoIter<K: EnumArray<V>, V> {
    map: ManuallyDrop<EnumMap<K, V>>,
    alive: Range<usize>,
}

impl<K: EnumArray<V>, V> Iterator for IntoIter<K, V> {
    type Item = (K, V);
    fn next(&mut self) -> Option<(K, V)> {
        let position = self.alive.next()?;
        Some((K::from_usize(position), unsafe {
            ptr::read(&self.map.as_slice()[position])
        }))
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.alive.size_hint()
    }
}

impl<K: EnumArray<V>, V> DoubleEndedIterator for IntoIter<K, V> {
    fn next_back(&mut self) -> Option<(K, V)> {
        let position = self.alive.next_back()?;
        Some((K::from_usize(position), unsafe {
            ptr::read(&self.map.as_slice()[position])
        }))
    }
}

impl<K: EnumArray<V>, V> ExactSizeIterator for IntoIter<K, V> {}

impl<K: EnumArray<V>, V> FusedIterator for IntoIter<K, V> {}

impl<K: EnumArray<V>, V> Drop for IntoIter<K, V> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            ptr::drop_in_place(&mut self.map.as_mut_slice()[self.alive.clone()]);
        }
    }
}

impl<K: EnumArray<V>, V> IntoIterator for EnumMap<K, V> {
    type Item = (K, V);
    type IntoIter = IntoIter<K, V>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        let len = self.len();
        IntoIter {
            map: ManuallyDrop::new(self),
            alive: 0..len,
        }
    }
}

impl<K: EnumArray<V>, V> EnumMap<K, V> {
    /// An iterator visiting all values. The iterator type is `&V`.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate enum_map;
    /// use enum_map::enum_map;
    ///
    /// let map = enum_map! { false => 3, true => 4 };
    /// let mut values = map.values();
    /// assert_eq!(values.next(), Some(&3));
    /// assert_eq!(values.next(), Some(&4));
    /// assert_eq!(values.next(), None);
    /// ```
    #[inline]
    pub fn values(&self) -> Values<V> {
        Values(self.as_slice().iter())
    }

    /// An iterator visiting all values mutably. The iterator type is `&mut V`.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate enum_map;
    /// use enum_map::enum_map;
    ///
    /// let mut map = enum_map! { _ => 2 };
    /// for value in map.values_mut() {
    ///     *value += 2;
    /// }
    /// assert_eq!(map[false], 4);
    /// assert_eq!(map[true], 4);
    /// ```
    #[inline]
    pub fn values_mut(&mut self) -> ValuesMut<V> {
        ValuesMut(self.as_mut_slice().iter_mut())
    }

    /// Creates a consuming iterator visiting all the values. The map
    /// cannot be used after calling this. The iterator element type
    /// is `V`.
    ///
    /// # Examples
    ///
    /// ```
    /// use enum_map::enum_map;
    ///
    /// let mut map = enum_map! { false => "hello", true => "goodbye" };
    /// assert_eq!(map.into_values().collect::<Vec<_>>(), ["hello", "goodbye"]);
    /// ```
    #[inline]
    pub fn into_values(self) -> IntoValues<K, V> {
        IntoValues {
            inner: self.into_iter(),
        }
    }
}

/// An iterator over the values of `EnumMap`.
///
/// This `struct` is created by the `values` method of `EnumMap`.
/// See its documentation for more.
pub struct Values<'a, V: 'a>(slice::Iter<'a, V>);

impl<'a, V> Clone for Values<'a, V> {
    fn clone(&self) -> Self {
        Values(self.0.clone())
    }
}

impl<'a, V: 'a> Iterator for Values<'a, V> {
    type Item = &'a V;
    #[inline]
    fn next(&mut self) -> Option<&'a V> {
        self.0.next()
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

impl<'a, V: 'a> DoubleEndedIterator for Values<'a, V> {
    #[inline]
    fn next_back(&mut self) -> Option<&'a V> {
        self.0.next_back()
    }
}

impl<'a, V: 'a> ExactSizeIterator for Values<'a, V> {}

impl<'a, V: 'a> FusedIterator for Values<'a, V> {}

/// A mutable iterator over the values of `EnumMap`.
///
/// This `struct` is created by the `values_mut` method of `EnumMap`.
/// See its documentation for more.
pub struct ValuesMut<'a, V: 'a>(slice::IterMut<'a, V>);

impl<'a, V: 'a> Iterator for ValuesMut<'a, V> {
    type Item = &'a mut V;
    #[inline]
    fn next(&mut self) -> Option<&'a mut V> {
        self.0.next()
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

impl<'a, V: 'a> DoubleEndedIterator for ValuesMut<'a, V> {
    #[inline]
    fn next_back(&mut self) -> Option<&'a mut V> {
        self.0.next_back()
    }
}

impl<'a, V: 'a> ExactSizeIterator for ValuesMut<'a, V> {}

impl<'a, V: 'a> FusedIterator for ValuesMut<'a, V> {}

/// An owning iterator over the values of an `EnumMap`.
///
/// This `struct` is created by the `into_values` method of `EnumMap`.
/// See its documentation for more.
pub struct IntoValues<K: EnumArray<V>, V> {
    inner: IntoIter<K, V>,
}

impl<K, V> Iterator for IntoValues<K, V>
where
    K: EnumArray<V>,
{
    type Item = V;

    fn next(&mut self) -> Option<V> {
        Some(self.inner.next()?.1)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.inner.size_hint()
    }
}

impl<K: EnumArray<V>, V> DoubleEndedIterator for IntoValues<K, V> {
    fn next_back(&mut self) -> Option<V> {
        Some(self.inner.next_back()?.1)
    }
}

impl<K, V> ExactSizeIterator for IntoValues<K, V> where K: EnumArray<V> {}

impl<K, V> FusedIterator for IntoValues<K, V> where K: EnumArray<V> {}
<|endoftext|>


<commit_before>// Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use glib;
use gst;
use gst::prelude::*;
use gst_audio;

use gst_plugin::properties::*;
use gst_plugin::object::*;
use gst_plugin::element::*;
use gst_plugin::base_transform::*;

use std::{cmp, iter, i32, u64};
use std::sync::Mutex;

use byte_slice_cast::*;

use num_traits::float::Float;
use num_traits::cast::{FromPrimitive, ToPrimitive};

const DEFAULT_MAX_DELAY: u64 = gst::SECOND_VAL;
const DEFAULT_DELAY: u64 = 500 * gst::MSECOND_VAL;
const DEFAULT_INTENSITY: f64 = 0.5;
const DEFAULT_FEEDBACK: f64 = 0.0;

#[derive(Debug, Clone, Copy)]
struct Settings {
    pub max_delay: u64,
    pub delay: u64,
    pub intensity: f64,
    pub feedback: f64,
}

impl Default for Settings {
    fn default() -> Self {
        Settings {
            max_delay: DEFAULT_MAX_DELAY,
            delay: DEFAULT_DELAY,
            intensity: DEFAULT_INTENSITY,
            feedback: DEFAULT_FEEDBACK,
        }
    }
}

struct State {
    info: gst_audio::AudioInfo,
    buffer: RingBuffer,
}

struct AudioEcho {
    cat: gst::DebugCategory,
    settings: Mutex<Settings>,
    state: Mutex<Option<State>>,
}

static PROPERTIES: [Property; 4] = [
    Property::UInt64(
        "max-delay",
        "Maximum Delay",
        "Maximum delay of the echo in nanoseconds (can't be changed in PLAYING or PAUSED state)",
        (0, u64::MAX),
        DEFAULT_MAX_DELAY,
        PropertyMutability::ReadWrite,
    ),
    Property::UInt64(
        "delay",
        "Delay",
        "Delay of the echo in nanoseconds",
        (0, u64::MAX),
        DEFAULT_DELAY,
        PropertyMutability::ReadWrite,
    ),
    Property::Double(
        "intensity",
        "Intensity",
        "Intensity of the echo",
        (0.0, 1.0),
        DEFAULT_INTENSITY,
        PropertyMutability::ReadWrite,
    ),
    Property::Double(
        "feedback",
        "Feedback",
        "Amount of feedback",
        (0.0, 1.0),
        DEFAULT_FEEDBACK,
        PropertyMutability::ReadWrite,
    ),
];

impl AudioEcho {
    fn new(_transform: &BaseTransform) -> Self {
        Self {
            cat: gst::DebugCategory::new(
                "rsaudiofx",
                gst::DebugColorFlags::empty(),
                "Rust audiofx effect",
            ),
            settings: Mutex::new(Default::default()),
            state: Mutex::new(None),
        }
    }

    fn class_init(klass: &mut BaseTransformClass) {
        klass.set_metadata(
            "Audio echo",
            "Filter/Effect/Audio",
            "Adds an echo or reverb effect to an audio stream",
            "Sebastian Dröge <sebastian@centricular.com>",
        );

        let caps = gst::Caps::new_simple(
            "audio/x-raw",
            &[
                (
                    "format",
                    &gst::List::new(&[
                        &gst_audio::AUDIO_FORMAT_F32.to_string(),
                        &gst_audio::AUDIO_FORMAT_F64.to_string(),
                    ]),
                ),
                ("rate", &gst::IntRange::<i32>::new(0, i32::MAX)),
                ("channels", &gst::IntRange::<i32>::new(0, i32::MAX)),
                ("layout", &"interleaved"),
            ],
        );
        let src_pad_template = gst::PadTemplate::new(
            "src",
            gst::PadDirection::Src,
            gst::PadPresence::Always,
            &caps,
        );
        klass.add_pad_template(src_pad_template);

        let sink_pad_template = gst::PadTemplate::new(
            "sink",
            gst::PadDirection::Sink,
            gst::PadPresence::Always,
            &caps,
        );
        klass.add_pad_template(sink_pad_template);

        klass.install_properties(&PROPERTIES);

        klass.configure(BaseTransformMode::AlwaysInPlace, false, false);
    }

    fn init(element: &BaseTransform) -> Box<BaseTransformImpl<BaseTransform>> {
        let imp = Self::new(element);
        Box::new(imp)
    }

    fn process<F: Float + ToPrimitive + FromPrimitive>(
        data: &mut [F],
        state: &mut State,
        settings: &Settings,
    ) {
        let delay_frames = (settings.delay as usize) * (state.info.channels() as usize)
            * (state.info.rate() as usize) / (gst::SECOND_VAL as usize);

        for (i, (o, e)) in data.iter_mut().zip(state.buffer.iter(delay_frames)) {
            let inp = (*i).to_f64().unwrap();
            let out = inp + settings.intensity * e;
            *o = inp + settings.feedback * e;
            *i = FromPrimitive::from_f64(out).unwrap();
        }
    }
}

impl ObjectImpl<BaseTransform> for AudioEcho {
    fn set_property(&self, _obj: &glib::Object, id: u32, value: &glib::Value) {
        let prop = &PROPERTIES[id as usize];

        match *prop {
            Property::UInt64("max-delay", ..) => {
                let mut settings = self.settings.lock().unwrap();
                settings.max_delay = value.get().unwrap();
            }
            Property::UInt64("delay", ..) => {
                let mut settings = self.settings.lock().unwrap();
                settings.delay = value.get().unwrap();
            }
            Property::Double("intensity", ..) => {
                let mut settings = self.settings.lock().unwrap();
                settings.intensity = value.get().unwrap();
            }
            Property::Double("feedback", ..) => {
                let mut settings = self.settings.lock().unwrap();
                settings.feedback = value.get().unwrap();
            }
            _ => unimplemented!(),
        }
    }

    fn get_property(&self, _obj: &glib::Object, id: u32) -> Result<glib::Value, ()> {
        let prop = &PROPERTIES[id as usize];

        match *prop {
            Property::UInt64("max-delay", ..) => {
                let settings = self.settings.lock().unwrap();
                if self.state.lock().unwrap().is_none() {
                    Ok(settings.max_delay.to_value())
                } else {
                    Err(())
                }
            }
            Property::UInt64("delay", ..) => {
                let settings = self.settings.lock().unwrap();
                Ok(settings.delay.to_value())
            }
            Property::Double("intensity", ..) => {
                let settings = self.settings.lock().unwrap();
                Ok(settings.intensity.to_value())
            }
            Property::Double("feedback", ..) => {
                let settings = self.settings.lock().unwrap();
                Ok(settings.feedback.to_value())
            }
            _ => unimplemented!(),
        }
    }
}

impl ElementImpl<BaseTransform> for AudioEcho {}

impl BaseTransformImpl<BaseTransform> for AudioEcho {
    fn transform_ip(&self, _element: &BaseTransform, buf: &mut gst::BufferRef) -> gst::FlowReturn {
        let mut settings = *self.settings.lock().unwrap();
        settings.delay = cmp::min(settings.max_delay, settings.delay);

        let mut state_guard = self.state.lock().unwrap();
        let state = match *state_guard {
            None => return gst::FlowReturn::NotNegotiated,
            Some(ref mut state) => state,
        };

        let mut map = match buf.map_writable() {
            None => return gst::FlowReturn::Error,
            Some(map) => map,
        };

        match state.info.format() {
            gst_audio::AUDIO_FORMAT_F64 => {
                let data = map.as_mut_slice().as_mut_slice_of::<f64>().unwrap();
                Self::process(data, state, &settings);
            }
            gst_audio::AUDIO_FORMAT_F32 => {
                let data = map.as_mut_slice().as_mut_slice_of::<f32>().unwrap();
                Self::process(data, state, &settings);
            }
            _ => return gst::FlowReturn::NotNegotiated,
        }

        gst::FlowReturn::Ok
    }

    fn set_caps(&self, _element: &BaseTransform, incaps: &gst::Caps, outcaps: &gst::Caps) -> bool {
        if incaps != outcaps {
            return false;
        }

        let info = match gst_audio::AudioInfo::from_caps(incaps) {
            None => return false,
            Some(info) => info,
        };

        let max_delay = self.settings.lock().unwrap().max_delay;
        let size = max_delay * (info.rate() as u64) / gst::SECOND_VAL;
        let buffer_size = size * (info.channels() as u64);

        *self.state.lock().unwrap() = Some(State {
            info: info,
            buffer: RingBuffer::new(buffer_size as usize),
        });

        true
    }

    fn stop(&self, _element: &BaseTransform) -> bool {
        // Drop state
        let _ = self.state.lock().unwrap().take();

        true
    }
}

struct AudioEchoStatic;

impl ImplTypeStatic<BaseTransform> for AudioEchoStatic {
    fn get_name(&self) -> &str {
        "AudioEcho"
    }

    fn new(&self, element: &BaseTransform) -> Box<BaseTransformImpl<BaseTransform>> {
        AudioEcho::init(element)
    }

    fn class_init(&self, klass: &mut BaseTransformClass) {
        AudioEcho::class_init(klass);
    }
}

pub fn register(plugin: &gst::Plugin) {
    let audioecho_static = AudioEchoStatic;
    let type_ = register_type(audioecho_static);
    gst::Element::register(plugin, "rsaudioecho", 0, type_);
}

struct RingBuffer {
    buffer: Box<[f64]>,
    pos: usize,
}

impl RingBuffer {
    fn new(size: usize) -> Self {
        let mut buffer = Vec::with_capacity(size as usize);
        buffer.extend(iter::repeat(0.0).take(size as usize));

        Self {
            buffer: buffer.into_boxed_slice(),
            pos: 0,
        }
    }

    fn iter(&mut self, delay: usize) -> RingBufferIter {
        RingBufferIter::new(self, delay)
    }
}

struct RingBufferIter<'a> {
    buffer: &'a mut [f64],
    buffer_pos: &'a mut usize,
    read_pos: usize,
    write_pos: usize,
}

impl<'a> RingBufferIter<'a> {
    fn new(buffer: &'a mut RingBuffer, delay: usize) -> RingBufferIter<'a> {
        let size = buffer.buffer.len();

        assert!(size >= delay);
        assert_ne!(size, 0);

        let read_pos = (size - delay + buffer.pos) % size;
        let write_pos = buffer.pos % size;

        let buffer_pos = &mut buffer.pos;
        let buffer = &mut buffer.buffer;

        RingBufferIter {
            buffer: buffer,
            buffer_pos: buffer_pos,
            read_pos: read_pos,
            write_pos: write_pos,
        }
    }
}

impl<'a> Iterator for RingBufferIter<'a> {
    type Item = (&'a mut f64, f64);

    fn next(&mut self) -> Option<Self::Item> {
        let res = unsafe {
            let r = *self.buffer.get_unchecked(self.read_pos);
            let w = self.buffer.get_unchecked_mut(self.write_pos);
            // Cast needed to get from &mut f64 to &'a mut f64
            (&mut *(w as *mut f64), r)
        };

        let size = self.buffer.len();
        self.write_pos = (self.write_pos + 1) % size;
        self.read_pos = (self.read_pos + 1) % size;

        Some(res)
    }
}

impl<'a> Drop for RingBufferIter<'a> {
    fn drop(&mut self) {
        *self.buffer_pos = self.write_pos;
    }
}
<commit_msg>audioecho: Minor cleanup and move code to the right place<commit_after>// Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use glib;
use gst;
use gst::prelude::*;
use gst_audio;

use gst_plugin::properties::*;
use gst_plugin::object::*;
use gst_plugin::element::*;
use gst_plugin::base_transform::*;

use std::{cmp, iter, i32, u64};
use std::sync::Mutex;

use byte_slice_cast::*;

use num_traits::float::Float;
use num_traits::cast::{FromPrimitive, ToPrimitive};

const DEFAULT_MAX_DELAY: u64 = gst::SECOND_VAL;
const DEFAULT_DELAY: u64 = 500 * gst::MSECOND_VAL;
const DEFAULT_INTENSITY: f64 = 0.5;
const DEFAULT_FEEDBACK: f64 = 0.0;

#[derive(Debug, Clone, Copy)]
struct Settings {
    pub max_delay: u64,
    pub delay: u64,
    pub intensity: f64,
    pub feedback: f64,
}

impl Default for Settings {
    fn default() -> Self {
        Settings {
            max_delay: DEFAULT_MAX_DELAY,
            delay: DEFAULT_DELAY,
            intensity: DEFAULT_INTENSITY,
            feedback: DEFAULT_FEEDBACK,
        }
    }
}

struct State {
    info: gst_audio::AudioInfo,
    buffer: RingBuffer,
}

struct AudioEcho {
    cat: gst::DebugCategory,
    settings: Mutex<Settings>,
    state: Mutex<Option<State>>,
}

static PROPERTIES: [Property; 4] = [
    Property::UInt64(
        "max-delay",
        "Maximum Delay",
        "Maximum delay of the echo in nanoseconds (can't be changed in PLAYING or PAUSED state)",
        (0, u64::MAX),
        DEFAULT_MAX_DELAY,
        PropertyMutability::ReadWrite,
    ),
    Property::UInt64(
        "delay",
        "Delay",
        "Delay of the echo in nanoseconds",
        (0, u64::MAX),
        DEFAULT_DELAY,
        PropertyMutability::ReadWrite,
    ),
    Property::Double(
        "intensity",
        "Intensity",
        "Intensity of the echo",
        (0.0, 1.0),
        DEFAULT_INTENSITY,
        PropertyMutability::ReadWrite,
    ),
    Property::Double(
        "feedback",
        "Feedback",
        "Amount of feedback",
        (0.0, 1.0),
        DEFAULT_FEEDBACK,
        PropertyMutability::ReadWrite,
    ),
];

impl AudioEcho {
    fn new(_transform: &BaseTransform) -> Self {
        Self {
            cat: gst::DebugCategory::new(
                "rsaudioecho",
                gst::DebugColorFlags::empty(),
                "Rust audioecho effect",
            ),
            settings: Mutex::new(Default::default()),
            state: Mutex::new(None),
        }
    }

    fn class_init(klass: &mut BaseTransformClass) {
        klass.set_metadata(
            "Audio echo",
            "Filter/Effect/Audio",
            "Adds an echo or reverb effect to an audio stream",
            "Sebastian Dröge <sebastian@centricular.com>",
        );

        let caps = gst::Caps::new_simple(
            "audio/x-raw",
            &[
                (
                    "format",
                    &gst::List::new(&[
                        &gst_audio::AUDIO_FORMAT_F32.to_string(),
                        &gst_audio::AUDIO_FORMAT_F64.to_string(),
                    ]),
                ),
                ("rate", &gst::IntRange::<i32>::new(0, i32::MAX)),
                ("channels", &gst::IntRange::<i32>::new(0, i32::MAX)),
                ("layout", &"interleaved"),
            ],
        );
        let src_pad_template = gst::PadTemplate::new(
            "src",
            gst::PadDirection::Src,
            gst::PadPresence::Always,
            &caps,
        );
        klass.add_pad_template(src_pad_template);

        let sink_pad_template = gst::PadTemplate::new(
            "sink",
            gst::PadDirection::Sink,
            gst::PadPresence::Always,
            &caps,
        );
        klass.add_pad_template(sink_pad_template);

        klass.install_properties(&PROPERTIES);

        klass.configure(BaseTransformMode::AlwaysInPlace, false, false);
    }

    fn init(element: &BaseTransform) -> Box<BaseTransformImpl<BaseTransform>> {
        let imp = Self::new(element);
        Box::new(imp)
    }

    fn process<F: Float + ToPrimitive + FromPrimitive>(
        data: &mut [F],
        state: &mut State,
        settings: &Settings,
    ) {
        let delay_frames = (settings.delay as usize) * (state.info.channels() as usize)
            * (state.info.rate() as usize) / (gst::SECOND_VAL as usize);

        for (i, (o, e)) in data.iter_mut().zip(state.buffer.iter(delay_frames)) {
            let inp = (*i).to_f64().unwrap();
            let out = inp + settings.intensity * e;
            *o = inp + settings.feedback * e;
            *i = FromPrimitive::from_f64(out).unwrap();
        }
    }
}

impl ObjectImpl<BaseTransform> for AudioEcho {
    fn set_property(&self, _obj: &glib::Object, id: u32, value: &glib::Value) {
        let prop = &PROPERTIES[id as usize];

        match *prop {
            Property::UInt64("max-delay", ..) => {
                let mut settings = self.settings.lock().unwrap();
                if self.state.lock().unwrap().is_none() {
                    settings.max_delay = value.get().unwrap();
                }
            }
            Property::UInt64("delay", ..) => {
                let mut settings = self.settings.lock().unwrap();
                settings.delay = value.get().unwrap();
            }
            Property::Double("intensity", ..) => {
                let mut settings = self.settings.lock().unwrap();
                settings.intensity = value.get().unwrap();
            }
            Property::Double("feedback", ..) => {
                let mut settings = self.settings.lock().unwrap();
                settings.feedback = value.get().unwrap();
            }
            _ => unimplemented!(),
        }
    }

    fn get_property(&self, _obj: &glib::Object, id: u32) -> Result<glib::Value, ()> {
        let prop = &PROPERTIES[id as usize];

        match *prop {
            Property::UInt64("max-delay", ..) => {
                let settings = self.settings.lock().unwrap();
                Ok(settings.max_delay.to_value())
            }
            Property::UInt64("delay", ..) => {
                let settings = self.settings.lock().unwrap();
                Ok(settings.delay.to_value())
            }
            Property::Double("intensity", ..) => {
                let settings = self.settings.lock().unwrap();
                Ok(settings.intensity.to_value())
            }
            Property::Double("feedback", ..) => {
                let settings = self.settings.lock().unwrap();
                Ok(settings.feedback.to_value())
            }
            _ => unimplemented!(),
        }
    }
}

impl ElementImpl<BaseTransform> for AudioEcho {}

impl BaseTransformImpl<BaseTransform> for AudioEcho {
    fn transform_ip(&self, _element: &BaseTransform, buf: &mut gst::BufferRef) -> gst::FlowReturn {
        let mut settings = *self.settings.lock().unwrap();
        settings.delay = cmp::min(settings.max_delay, settings.delay);

        let mut state_guard = self.state.lock().unwrap();
        let state = match *state_guard {
            None => return gst::FlowReturn::NotNegotiated,
            Some(ref mut state) => state,
        };

        let mut map = match buf.map_writable() {
            None => return gst::FlowReturn::Error,
            Some(map) => map,
        };

        match state.info.format() {
            gst_audio::AUDIO_FORMAT_F64 => {
                let data = map.as_mut_slice().as_mut_slice_of::<f64>().unwrap();
                Self::process(data, state, &settings);
            }
            gst_audio::AUDIO_FORMAT_F32 => {
                let data = map.as_mut_slice().as_mut_slice_of::<f32>().unwrap();
                Self::process(data, state, &settings);
            }
            _ => return gst::FlowReturn::NotNegotiated,
        }

        gst::FlowReturn::Ok
    }

    fn set_caps(&self, _element: &BaseTransform, incaps: &gst::Caps, outcaps: &gst::Caps) -> bool {
        if incaps != outcaps {
            return false;
        }

        let info = match gst_audio::AudioInfo::from_caps(incaps) {
            None => return false,
            Some(info) => info,
        };

        let max_delay = self.settings.lock().unwrap().max_delay;
        let size = max_delay * (info.rate() as u64) / gst::SECOND_VAL;
        let buffer_size = size * (info.channels() as u64);

        *self.state.lock().unwrap() = Some(State {
            info: info,
            buffer: RingBuffer::new(buffer_size as usize),
        });

        true
    }

    fn stop(&self, _element: &BaseTransform) -> bool {
        // Drop state
        let _ = self.state.lock().unwrap().take();

        true
    }
}

struct AudioEchoStatic;

impl ImplTypeStatic<BaseTransform> for AudioEchoStatic {
    fn get_name(&self) -> &str {
        "AudioEcho"
    }

    fn new(&self, element: &BaseTransform) -> Box<BaseTransformImpl<BaseTransform>> {
        AudioEcho::init(element)
    }

    fn class_init(&self, klass: &mut BaseTransformClass) {
        AudioEcho::class_init(klass);
    }
}

pub fn register(plugin: &gst::Plugin) {
    let audioecho_static = AudioEchoStatic;
    let type_ = register_type(audioecho_static);
    gst::Element::register(plugin, "rsaudioecho", 0, type_);
}

struct RingBuffer {
    buffer: Box<[f64]>,
    pos: usize,
}

impl RingBuffer {
    fn new(size: usize) -> Self {
        let mut buffer = Vec::with_capacity(size as usize);
        buffer.extend(iter::repeat(0.0).take(size as usize));

        Self {
            buffer: buffer.into_boxed_slice(),
            pos: 0,
        }
    }

    fn iter(&mut self, delay: usize) -> RingBufferIter {
        RingBufferIter::new(self, delay)
    }
}

struct RingBufferIter<'a> {
    buffer: &'a mut [f64],
    buffer_pos: &'a mut usize,
    read_pos: usize,
    write_pos: usize,
}

impl<'a> RingBufferIter<'a> {
    fn new(buffer: &'a mut RingBuffer, delay: usize) -> RingBufferIter<'a> {
        let size = buffer.buffer.len();

        assert!(size >= delay);
        assert_ne!(size, 0);

        let read_pos = (size - delay + buffer.pos) % size;
        let write_pos = buffer.pos % size;

        let buffer_pos = &mut buffer.pos;
        let buffer = &mut buffer.buffer;

        RingBufferIter {
            buffer: buffer,
            buffer_pos: buffer_pos,
            read_pos: read_pos,
            write_pos: write_pos,
        }
    }
}

impl<'a> Iterator for RingBufferIter<'a> {
    type Item = (&'a mut f64, f64);

    fn next(&mut self) -> Option<Self::Item> {
        let res = unsafe {
            let r = *self.buffer.get_unchecked(self.read_pos);
            let w = self.buffer.get_unchecked_mut(self.write_pos);
            // Cast needed to get from &mut f64 to &'a mut f64
            (&mut *(w as *mut f64), r)
        };

        let size = self.buffer.len();
        self.write_pos = (self.write_pos + 1) % size;
        self.read_pos = (self.read_pos + 1) % size;

        Some(res)
    }
}

impl<'a> Drop for RingBufferIter<'a> {
    fn drop(&mut self) {
        *self.buffer_pos = self.write_pos;
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;

use ipc_channel::ipc::IpcError;
use serde::{Serialize, Deserialize};
use tokio::sync::{mpsc, RwLock, Mutex};
use thiserror::Error;

use crate::ipc_protocol::{ClientConnection, ConnectionError, ClientRequest, ServerResponse};
use crate::renderer_server_process::RendererServerProcess;

/// Signals that the IPC connection has been disconnected and therefore the window was probably
/// closed
#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
#[error("Cannot continue to run turtle commands after window is closed. This panic stops the thread, but is not necessarily an error.")]
struct Disconnected;

/// A unique ID used to multiplex responses on the client side
///
/// Treated as an opaque value on the server that is returned back to the client with the response
/// to a request.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ClientId(usize);

/// Spawns the server, and manages the IPC connection
///
/// Messages are sent though IPC and responses are dispatched back to the correct client based on
/// the received client ID.
#[derive(Debug)]
struct ClientDispatcher {
    /// The spawned server process
    ///
    /// When dropped, this will block until the server process has quit
    proc: RendererServerProcess,

    /// The IPC connection to the server process
    conn: Arc<ClientConnection>,

    /// Each `ClientId` indexes into this field
    ///
    /// Using `RwLock` allows sending multiple times concurrently using `read()` and also allows
    /// more clients to be added using `write()`.
    clients: Arc<RwLock<Vec<mpsc::UnboundedSender<Result<ServerResponse, Disconnected>>>>>,
}

impl ClientDispatcher {
    async fn new() -> Result<Self, ConnectionError> {
        let mut proc = RendererServerProcess::spawn()?;

        let conn = Arc::new(ClientConnection::new(&mut proc).await?);
        let clients = Arc::new(RwLock::new(Vec::<mpsc::UnboundedSender<_>>::new()));

        let task_conn = conn.clone();
        let task_clients = clients.clone();
        tokio::spawn(async move {
            loop {
                let (id, response) = match task_conn.recv().await {
                    Ok((id, response)) => (id, Ok(response)),

                    Err(IpcError::Disconnected) => {
                        // Alert all the clients of the disconnection
                        let clients = task_clients.read().await;
                        for client in &*clients {
                            match client.send(Err(Disconnected)) {
                                Ok(()) => {},
                                // This particular client connection must have gotten dropped
                                Err(_) => {},
                            }
                        }
                        break;
                    },

                    Err(err) => panic!("Error while receiving IPC message: {:?}", err),
                };

                let clients = task_clients.read().await;

                let ClientId(index) = id;
                match clients[index].send(response) {
                    Ok(()) => {},
                    // This particular client connection must have gotten dropped
                    Err(_) => {},
                }
            }
        });

        Ok(Self {proc, conn, clients})
    }

    async fn add_client(&self) -> (ClientId, mpsc::UnboundedReceiver<Result<ServerResponse, Disconnected>>) {
        let mut clients = self.clients.write().await;

        let id = ClientId(clients.len());
        let (sender, receiver) = mpsc::unbounded_channel();
        clients.push(sender);

        (id, receiver)
    }

    async fn send(&self, id: ClientId, req: ClientRequest) -> Result<(), ipc_channel::Error> {
        self.conn.send(id, req).await
    }
}

/// Represents a single connection to the server
#[derive(Debug)]
pub struct RendererClient {
    dispatcher: Arc<ClientDispatcher>,
    id: ClientId,
    receiver: Mutex<mpsc::UnboundedReceiver<Result<ServerResponse, Disconnected>>>,
}

impl RendererClient {
    /// Spawns a new server process and creates a connection to it
    pub async fn new() -> Result<Self, ConnectionError> {
        let dispatcher = Arc::new(ClientDispatcher::new().await?);
        let (id, receiver) = dispatcher.add_client().await;
        let receiver = Mutex::new(receiver);

        Ok(Self {dispatcher, id, receiver})
    }

    /// Creates a new renderer client that can also communicate to the same server
    pub async fn split(&self) -> Self {
        let dispatcher = self.dispatcher.clone();
        let (id, receiver) = dispatcher.add_client().await;
        let receiver = Mutex::new(receiver);

        Self {dispatcher, id, receiver}
    }

    /// Sends a message to the server process
    ///
    /// When possible, prefer using methods from `ProtocolClient` instead of using this directly
    pub async fn send(&self, req: ClientRequest) {
        // The error produced by send is a serialization error, so it signals a bug in this code,
        // not something that should be propagated to be handled elsewhere.
        self.dispatcher.send(self.id, req).await
            .expect("bug: error while sending message through IPC")
    }

    /// Receives a response from the server process
    ///
    /// When possible, prefer using methods from `ProtocolClient` instead of using this directly
    pub async fn recv(&self) -> ServerResponse {
        let mut receiver = self.receiver.lock().await;
        receiver.recv().await
            // Since this struct keeps a ref-counted copy of the senders, they can't have possibly
            // been dropped at this point.
            .expect("bug: client senders should not be dropped yet")
            // This panic causes the program to exit if turtle commands continue after the window
            // closes
            .unwrap_or_else(|err| panic!("IPC response not received: {}", err))
    }
}
<commit_msg>Somewhat misguided API for being able to handle when IPC is disconnected in the renderer client<commit_after>use std::sync::Arc;

use ipc_channel::ipc::IpcError;
use serde::{Serialize, Deserialize};
use tokio::sync::{mpsc, RwLock, Mutex};
use thiserror::Error;

use crate::ipc_protocol::{ClientConnection, ConnectionError, ClientRequest, ServerResponse};
use crate::renderer_server_process::RendererServerProcess;

/// Signals that the IPC connection has been disconnected and therefore the window was probably
/// closed
#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
#[error("Cannot continue to run turtle commands after window is closed. This panic stops the thread, but is not necessarily an error.")]
pub struct Disconnected;

/// A unique ID used to multiplex responses on the client side
///
/// Treated as an opaque value on the server that is returned back to the client with the response
/// to a request.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ClientId(usize);

/// Spawns the server, and manages the IPC connection
///
/// Messages are sent though IPC and responses are dispatched back to the correct client based on
/// the received client ID.
#[derive(Debug)]
struct ClientDispatcher {
    /// The spawned server process
    ///
    /// When dropped, this will block until the server process has quit
    proc: RendererServerProcess,

    /// The IPC connection to the server process
    conn: Arc<ClientConnection>,

    /// Each `ClientId` indexes into this field
    ///
    /// Using `RwLock` allows sending multiple times concurrently using `read()` and also allows
    /// more clients to be added using `write()`.
    clients: Arc<RwLock<Vec<mpsc::UnboundedSender<Result<ServerResponse, Disconnected>>>>>,
}

impl ClientDispatcher {
    async fn new() -> Result<Self, ConnectionError> {
        let mut proc = RendererServerProcess::spawn()?;

        let conn = Arc::new(ClientConnection::new(&mut proc).await?);
        let clients = Arc::new(RwLock::new(Vec::<mpsc::UnboundedSender<_>>::new()));

        let task_conn = conn.clone();
        let task_clients = clients.clone();
        tokio::spawn(async move {
            loop {
                let (id, response) = match task_conn.recv().await {
                    Ok((id, response)) => (id, Ok(response)),

                    Err(IpcError::Disconnected) => {
                        // Alert all the clients of the disconnection
                        let clients = task_clients.read().await;
                        for client in &*clients {
                            match client.send(Err(Disconnected)) {
                                Ok(()) => {},
                                // This particular client connection must have gotten dropped
                                Err(_) => {},
                            }
                        }
                        break;
                    },

                    Err(err) => panic!("Error while receiving IPC message: {:?}", err),
                };

                let clients = task_clients.read().await;

                let ClientId(index) = id;
                match clients[index].send(response) {
                    Ok(()) => {},
                    // This particular client connection must have gotten dropped
                    Err(_) => {},
                }
            }
        });

        Ok(Self {proc, conn, clients})
    }

    async fn add_client(&self) -> (ClientId, mpsc::UnboundedReceiver<Result<ServerResponse, Disconnected>>) {
        let mut clients = self.clients.write().await;

        let id = ClientId(clients.len());
        let (sender, receiver) = mpsc::unbounded_channel();
        clients.push(sender);

        (id, receiver)
    }

    async fn send(&self, id: ClientId, req: ClientRequest) -> Result<(), ipc_channel::Error> {
        self.conn.send(id, req).await
    }
}

/// Represents a single connection to the server
#[derive(Debug)]
pub struct RendererClient {
    dispatcher: Arc<ClientDispatcher>,
    id: ClientId,
    receiver: Mutex<mpsc::UnboundedReceiver<Result<ServerResponse, Disconnected>>>,
}

impl RendererClient {
    /// Spawns a new server process and creates a connection to it
    pub async fn new() -> Result<Self, ConnectionError> {
        let dispatcher = Arc::new(ClientDispatcher::new().await?);
        let (id, receiver) = dispatcher.add_client().await;
        let receiver = Mutex::new(receiver);

        Ok(Self {dispatcher, id, receiver})
    }

    /// Creates a new renderer client that can also communicate to the same server
    pub async fn split(&self) -> Self {
        let dispatcher = self.dispatcher.clone();
        let (id, receiver) = dispatcher.add_client().await;
        let receiver = Mutex::new(receiver);

        Self {dispatcher, id, receiver}
    }

    /// Sends a message to the server process
    ///
    /// When possible, prefer using methods from `ProtocolClient` instead of using this directly
    pub async fn send(&self, req: ClientRequest) {
        // The error produced by send is a serialization error, so it signals a bug in this code,
        // not something that should be propagated to be handled elsewhere.
        self.dispatcher.send(self.id, req).await
            .expect("bug: error while sending message through IPC")
    }

    /// Receives a response from the server process, panicking if the server has disconnected
    ///
    /// When possible, prefer using methods from `ProtocolClient` instead of using this directly.
    pub async fn recv(&self) -> ServerResponse {
        self.recv_disconnected().await
            // This panic causes the program to exit if turtle commands continue after the window
            // closes
            .unwrap_or_else(|err| panic!("IPC response not received: {}", err))
    }

    /// Receives a response from the server process, returning an error if the server has been
    /// disconnected
    ///
    /// If an error is produced, the window can be assumed to be closed
    ///
    /// When possible, prefer using methods from `ProtocolClient` instead of using this directly.
    pub async fn recv_disconnected(&self) -> Result<ServerResponse, Disconnected> {
        let mut receiver = self.receiver.lock().await;
        receiver.recv().await
            // Since this struct keeps a ref-counted copy of the senders, they can't have possibly
            // been dropped at this point.
            .expect("bug: client senders should not be dropped yet")
    }
}
<|endoftext|>


<commit_before>
use std::io::Write;
use std::io::Error as IoError;
use std::ascii::AsciiExt;
use super::{Parsable, ParseError, Streamable};
use super::types::{DateTime, MailboxList, Mailbox, AddressList};

macro_rules! req_name {
    ($rem:ident, $str:expr, $input:ident) => {
        let len: usize = $str.len();
        if $rem.len() < len || &(&$rem[0..len]).to_ascii_lowercase()!=$str {
            return Err(ParseError::NotFound);
        }
        $rem = &$rem[len..];
    };
}

macro_rules! req_crlf {
    ($rem:ident, $input:ident) => {
        if &$rem[..2] != b"\r\n" {
            return Err(ParseError::NotFound);
        }
        $rem = &$rem[2..];
    }
}

// 3.6.1
// orig-date       =   "Date:" date-time CRLF
#[derive(Debug, Clone, PartialEq)]
pub struct OrigDate(pub DateTime);
impl Parsable for OrigDate {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        if input.len() == 0 { return Err(ParseError::Eof); }
        let mut rem = input;
        req_name!(rem, b"date:", input);
        if let Ok(dt) = parse!(DateTime, rem) {
            req_crlf!(rem, input);
            Ok((OrigDate(dt), rem))
        } else {
            Err(ParseError::NotFound)
        }
    }
}
impl Streamable for OrigDate {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        Ok(try!(w.write(b"Date:"))
           + try!(self.0.stream(w))
           + try!(w.write(b"\r\n")))
    }
}

// 3.6.2
// from            =   "From:" mailbox-list CRLF
#[derive(Debug, Clone, PartialEq)]
pub struct From(pub MailboxList);
impl Parsable for From {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        if input.len() == 0 { return Err(ParseError::Eof); }
        let mut rem = input;
        req_name!(rem, b"from:", input);
        if let Ok(mbl) = parse!(MailboxList, rem) {
            req_crlf!(rem, input);
            return Ok((From(mbl), rem));
        }
        Err(ParseError::NotFound)
    }
}
impl Streamable for From {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        Ok(try!(w.write(b"From: "))
           + try!(self.0.stream(w))
           + try!(w.write(b"\r\n")))
    }
}

// 3.6.2
// sender          =   "Sender:" mailbox CRLF
#[derive(Debug, Clone, PartialEq)]
pub struct Sender(pub Mailbox);
impl Parsable for Sender {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        if input.len() == 0 { return Err(ParseError::Eof); }
        let mut rem = input;
        req_name!(rem, b"sender:", input);
        if let Ok(mb) = parse!(Mailbox, rem) {
            req_crlf!(rem, input);
            return Ok((Sender(mb), rem));
        }
        Err(ParseError::NotFound)
    }
}
impl Streamable for Sender {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        Ok(try!(w.write(b"Sender: "))
           + try!(self.0.stream(w))
           + try!(w.write(b"\r\n")))
    }
}

// 3.6.2
// reply-to        =   "Reply-To:" address-list CRLF
#[derive(Debug, Clone, PartialEq)]
pub struct ReplyTo(pub AddressList);
impl Parsable for ReplyTo {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        if input.len() == 0 { return Err(ParseError::Eof); }
        let mut rem = input;
        req_name!(rem, b"reply-to:", input);
        if let Ok(x) = parse!(AddressList, rem) {
            req_crlf!(rem, input);
            return Ok((ReplyTo(x), rem));
        }
        Err(ParseError::NotFound)
    }
}
impl Streamable for ReplyTo {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        Ok(try!(w.write(b"Reply-To: "))
           + try!(self.0.stream(w))
           + try!(w.write(b"\r\n")))
    }
}
<commit_msg>rfc5322: 3.6.3 to<commit_after>
use std::io::Write;
use std::io::Error as IoError;
use std::ascii::AsciiExt;
use super::{Parsable, ParseError, Streamable};
use super::types::{DateTime, MailboxList, Mailbox, AddressList};

macro_rules! req_name {
    ($rem:ident, $str:expr, $input:ident) => {
        let len: usize = $str.len();
        if $rem.len() < len || &(&$rem[0..len]).to_ascii_lowercase()!=$str {
            return Err(ParseError::NotFound);
        }
        $rem = &$rem[len..];
    };
}

macro_rules! req_crlf {
    ($rem:ident, $input:ident) => {
        if &$rem[..2] != b"\r\n" {
            return Err(ParseError::NotFound);
        }
        $rem = &$rem[2..];
    }
}

// 3.6.1
// orig-date       =   "Date:" date-time CRLF
#[derive(Debug, Clone, PartialEq)]
pub struct OrigDate(pub DateTime);
impl Parsable for OrigDate {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        if input.len() == 0 { return Err(ParseError::Eof); }
        let mut rem = input;
        req_name!(rem, b"date:", input);
        if let Ok(dt) = parse!(DateTime, rem) {
            req_crlf!(rem, input);
            Ok((OrigDate(dt), rem))
        } else {
            Err(ParseError::NotFound)
        }
    }
}
impl Streamable for OrigDate {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        Ok(try!(w.write(b"Date:"))
           + try!(self.0.stream(w))
           + try!(w.write(b"\r\n")))
    }
}

// 3.6.2
// from            =   "From:" mailbox-list CRLF
#[derive(Debug, Clone, PartialEq)]
pub struct From(pub MailboxList);
impl Parsable for From {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        if input.len() == 0 { return Err(ParseError::Eof); }
        let mut rem = input;
        req_name!(rem, b"from:", input);
        if let Ok(mbl) = parse!(MailboxList, rem) {
            req_crlf!(rem, input);
            return Ok((From(mbl), rem));
        }
        Err(ParseError::NotFound)
    }
}
impl Streamable for From {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        Ok(try!(w.write(b"From: "))
           + try!(self.0.stream(w))
           + try!(w.write(b"\r\n")))
    }
}

// 3.6.2
// sender          =   "Sender:" mailbox CRLF
#[derive(Debug, Clone, PartialEq)]
pub struct Sender(pub Mailbox);
impl Parsable for Sender {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        if input.len() == 0 { return Err(ParseError::Eof); }
        let mut rem = input;
        req_name!(rem, b"sender:", input);
        if let Ok(mb) = parse!(Mailbox, rem) {
            req_crlf!(rem, input);
            return Ok((Sender(mb), rem));
        }
        Err(ParseError::NotFound)
    }
}
impl Streamable for Sender {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        Ok(try!(w.write(b"Sender: "))
           + try!(self.0.stream(w))
           + try!(w.write(b"\r\n")))
    }
}

// 3.6.2
// reply-to        =   "Reply-To:" address-list CRLF
#[derive(Debug, Clone, PartialEq)]
pub struct ReplyTo(pub AddressList);
impl Parsable for ReplyTo {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        if input.len() == 0 { return Err(ParseError::Eof); }
        let mut rem = input;
        req_name!(rem, b"reply-to:", input);
        if let Ok(x) = parse!(AddressList, rem) {
            req_crlf!(rem, input);
            return Ok((ReplyTo(x), rem));
        }
        Err(ParseError::NotFound)
    }
}
impl Streamable for ReplyTo {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        Ok(try!(w.write(b"Reply-To: "))
           + try!(self.0.stream(w))
           + try!(w.write(b"\r\n")))
    }
}

// 3.6.3
// to              =   "To:" address-list CRLF
#[derive(Debug, Clone, PartialEq)]
pub struct To(pub AddressList);
impl Parsable for To {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        if input.len() == 0 { return Err(ParseError::Eof); }
        let mut rem = input;
        req_name!(rem, b"to:", input);
        if let Ok(x) = parse!(AddressList, rem) {
            req_crlf!(rem, input);
            return Ok((To(x), rem));
        }
        Err(ParseError::NotFound)
    }
}
impl Streamable for To {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        Ok(try!(w.write(b"To: "))
           + try!(self.0.stream(w))
           + try!(w.write(b"\r\n")))
    }
}
<|endoftext|>


<commit_before>pub static RUSTUP_HELP: &'static str =
r"
rustup installs The Rust Programming Language from the official
release channels, enabling you to easily switch between stable, beta,
and nightly compilers and keep them updated. It makes cross-compiling
simpler with binary builds of the standard library for common platforms.

If you are new to Rust consider running `rustup doc --book`
to learn Rust.";

pub static SHOW_HELP: &'static str =
r"
Shows the name of the active toolchain and the version of `rustc`.

If the active toolchain has installed support for additional
compilation targets, then they are listed as well.

If there are multiple toolchains installed then all installed
toolchains are listed as well.";

pub static UPDATE_HELP: &'static str =
r"
With no toolchain specified, the `update` command updates each of the
installed toolchains from the official releasechannels, then updates
rustup itself.

If given a toolchain argument then `update` updates that toolchain,
the same as `rustup toolchain update`.

'toolchain' specifies a toolchain name, such as 'stable', 'nightly',
or '1.8.0'. For more information see `rustup help toolchain`.";

pub static TOOLCHAIN_INSTALL_HELP: &'static str =
r"
Installs a specific rust toolchain.

The 'install' command is an alias for 'rustup update <toolchain>'.

'toolchain' specifies a toolchain name, such as 'stable', 'nightly',
or '1.8.0'. For more information see `rustup help toolchain`.";

pub static DEFAULT_HELP: &'static str =
r"
Sets the default toolchain to the one specified. If the toolchain is
not already installed then it is installed first.";

pub static TOOLCHAIN_HELP: &'static str =
r"
Many `rustup` commands deal with *toolchains*, a single installation
of the Rust compiler. `rustup` supports multiple types of
toolchains. The most basic track the official release channels:
'stable', 'beta' and 'nightly'; but `rustup` can also install
toolchains from the official archives, for alternate host platforms,
and from local builds.

Standard release channel toolchain names have the following form:

    <channel>[-<date>][-<host>]

    <channel>       = stable|beta|nightly|<version>
    <date>          = YYYY-MM-DD
    <host>          = <target-triple>

'channel' is either a named release channel or an explicit version
number, such as '1.8.0'. Channel names can be optionally appended with
an archive date, as in 'nightly-2014-12-18', in which case the
toolchain is downloaded from the archive for that date.

Finally, the host may be specified as a target triple. This is most
useful for installing a 32-bit compiler on a 64-bit platform, or for
installing the [MSVC-based toolchain] on Windows. For example:

    rustup toolchain install stable-x86_64-pc-windows-msvc

For convenience, elements of the target triple that are omitted will be
inferred, so the above could be written:

    $ rustup default stable-msvc

Toolchain names that don't name a channel instead can be used to name
custom toolchains with the `rustup toolchain link` command.";

pub static OVERRIDE_HELP: &'static str =
r"
Overrides configure rustup to use a specific toolchain when
running in a specific directory.

Directories can be assigned their own Rust toolchain with
`rustup override`. When a directory has an override then
any time `rustc` or `cargo` is run inside that directory,
or one of its child directories, the override toolchain
will be invoked.

To pin to a specific nightly:

    rustup override add nightly-2014-12-18

Or a specific stable release:

    rustup override add 1.0.0

To see the active toolchain use `rustup show`. To remove the override
and use the default toolchain again, `rustup override remove`.";

pub static RUN_HELP: &'static str =
r"
Configures an environment to use the given toolchain and then runs
the specified program. The command may be any program, not just
rustc or cargo. This can be used for testing arbitrary toolchains
without setting an override.";

pub static DOC_HELP: &'static str =
r"
Opens the documentation for the currently active toolchain with the
default browser.

By default, it opens the documentation index. Use the various flags to
open specific pieces of documentation.";
<commit_msg>Fix typo in update helptext<commit_after>pub static RUSTUP_HELP: &'static str =
r"
rustup installs The Rust Programming Language from the official
release channels, enabling you to easily switch between stable, beta,
and nightly compilers and keep them updated. It makes cross-compiling
simpler with binary builds of the standard library for common platforms.

If you are new to Rust consider running `rustup doc --book`
to learn Rust.";

pub static SHOW_HELP: &'static str =
r"
Shows the name of the active toolchain and the version of `rustc`.

If the active toolchain has installed support for additional
compilation targets, then they are listed as well.

If there are multiple toolchains installed then all installed
toolchains are listed as well.";

pub static UPDATE_HELP: &'static str =
r"
With no toolchain specified, the `update` command updates each of the
installed toolchains from the official release channels, then updates
rustup itself.

If given a toolchain argument then `update` updates that toolchain,
the same as `rustup toolchain update`.

'toolchain' specifies a toolchain name, such as 'stable', 'nightly',
or '1.8.0'. For more information see `rustup help toolchain`.";

pub static TOOLCHAIN_INSTALL_HELP: &'static str =
r"
Installs a specific rust toolchain.

The 'install' command is an alias for 'rustup update <toolchain>'.

'toolchain' specifies a toolchain name, such as 'stable', 'nightly',
or '1.8.0'. For more information see `rustup help toolchain`.";

pub static DEFAULT_HELP: &'static str =
r"
Sets the default toolchain to the one specified. If the toolchain is
not already installed then it is installed first.";

pub static TOOLCHAIN_HELP: &'static str =
r"
Many `rustup` commands deal with *toolchains*, a single installation
of the Rust compiler. `rustup` supports multiple types of
toolchains. The most basic track the official release channels:
'stable', 'beta' and 'nightly'; but `rustup` can also install
toolchains from the official archives, for alternate host platforms,
and from local builds.

Standard release channel toolchain names have the following form:

    <channel>[-<date>][-<host>]

    <channel>       = stable|beta|nightly|<version>
    <date>          = YYYY-MM-DD
    <host>          = <target-triple>

'channel' is either a named release channel or an explicit version
number, such as '1.8.0'. Channel names can be optionally appended with
an archive date, as in 'nightly-2014-12-18', in which case the
toolchain is downloaded from the archive for that date.

Finally, the host may be specified as a target triple. This is most
useful for installing a 32-bit compiler on a 64-bit platform, or for
installing the [MSVC-based toolchain] on Windows. For example:

    rustup toolchain install stable-x86_64-pc-windows-msvc

For convenience, elements of the target triple that are omitted will be
inferred, so the above could be written:

    $ rustup default stable-msvc

Toolchain names that don't name a channel instead can be used to name
custom toolchains with the `rustup toolchain link` command.";

pub static OVERRIDE_HELP: &'static str =
r"
Overrides configure rustup to use a specific toolchain when
running in a specific directory.

Directories can be assigned their own Rust toolchain with
`rustup override`. When a directory has an override then
any time `rustc` or `cargo` is run inside that directory,
or one of its child directories, the override toolchain
will be invoked.

To pin to a specific nightly:

    rustup override add nightly-2014-12-18

Or a specific stable release:

    rustup override add 1.0.0

To see the active toolchain use `rustup show`. To remove the override
and use the default toolchain again, `rustup override remove`.";

pub static RUN_HELP: &'static str =
r"
Configures an environment to use the given toolchain and then runs
the specified program. The command may be any program, not just
rustc or cargo. This can be used for testing arbitrary toolchains
without setting an override.";

pub static DOC_HELP: &'static str =
r"
Opens the documentation for the currently active toolchain with the
default browser.

By default, it opens the documentation index. Use the various flags to
open specific pieces of documentation.";
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::ops::Deref;
use std::path::PathBuf;
use std::collections::HashSet;
use cargo::core::Workspace;
use cargo::sources::PathSource;
use syntex_syntax::attr;
use syntex_syntax::visit::{self, Visitor, FnKind};
use syntex_syntax::codemap::{CodeMap, Span, FilePathMapping};
use syntex_syntax::ast::{NodeId, Mac, Attribute, Stmt, StmtKind, FnDecl, Mod,
    StructField, Block, Item, ItemKind};
use syntex_syntax::parse::{self, ParseSess};
use syntex_syntax::errors::Handler;
use syntex_syntax::errors::emitter::ColorConfig;
use syntex_syntax::ext::expand::MacroExpander;
use config::Config;

struct IgnoredLines<'a> {
    lines: Vec<(PathBuf, usize)>,
    covered: &'a HashSet<PathBuf>,
    codemap: &'a CodeMap,
    config: &'a Config,
}

/// Returns a list of files and line numbers to ignore (not indexes!)
pub fn get_lines_to_ignore(project: &Workspace, config: &Config) -> Vec<(PathBuf, usize)> {
    let mut result: Vec<(PathBuf, usize)> = Vec::new();

    let pkg = project.current().unwrap();
    let mut src = PathSource::new(pkg.root(), pkg.package_id().source_id(), project.config());
    if let Ok(package) = src.root_package() {

        let codemap = Rc::new(CodeMap::new(FilePathMapping::empty()));
        let handler = Handler::with_tty_emitter(ColorConfig::Auto, false, false, Some(codemap.clone()));
        let parse_session = ParseSess::with_span_handler(handler, codemap.clone());

        let mut done_files: HashSet<PathBuf> = HashSet::new();
        for target in package.targets() {
            let file = target.src_path();
            if !(config.ignore_tests && file.starts_with(project.root().join("tests"))) {
                let mut parser = parse::new_parser_from_file(&parse_session, file);
                if let Ok(krate) = parser.parse_crate_mod() {

                    let mut lines = {
                        let mut visitor = IgnoredLines::from_session(&parse_session, &done_files, config);
                        visitor.visit_mod(&krate.module, krate.span, &krate.attrs, NodeId::new(0));
                        visitor.lines
                    };

                    for l in &lines {
                        done_files.insert(l.0.clone());
                    }
                    result.append(&mut lines);
                }
            }
        }
    }
    result
}

impl<'a> IgnoredLines<'a> {
    /// Construct a new ignored lines object for the given project
    fn from_session(session: &'a ParseSess,
                    covered: &'a HashSet<PathBuf>,
                    config: &'a Config) -> IgnoredLines<'a> {
        IgnoredLines {
            lines: vec![],
            covered: covered,
            codemap: session.codemap(),
            config: config,
        }
    }

    /// Add lines to the line ignore list
    fn ignore_lines(&mut self, span: Span) {
        if let Ok(s) = self.codemap.span_to_lines(span) {
            for line in &s.lines {
                let pb = PathBuf::from(self.codemap.span_to_filename(span) as String);
                // Line number is index+1
                self.lines.push((pb, line.line_index + 1));
            }
        }
    }

    /// Looks for #[cfg(test)] attribute.
    fn contains_cfg_test(&mut self, attrs: &[Attribute]) -> bool {
        attrs.iter()
             .filter(|x| x.path == "cfg")
             .filter_map(|x| x.meta_item_list())
             .flat_map(|x| x)
             .any(|x| {
                 if let Some(w) = x.word() {
                    w.name().as_str() == "test"
                 } else {
                     false
                 }
             })
    }

    /// This function finds ignorable lines within actual coverable code.
    /// As opposed to other functions which find isolated lines that aren't
    /// executed or lines filtered by the user. These lines are things like
    /// close braces that are within coverable code but not coverable.
    fn find_ignorable_lines(&mut self, span: Span) {
        if let Ok(l) = self.codemap.span_to_lines(span) {
            for line in &l.lines {
                let pb = PathBuf::from(self.codemap.span_to_filename(span) as String);
                if let Some(s) = l.file.get_line(line.line_index) {
                    // Is this one of those pointless {, } or }; only lines?
                    if !s.chars().any(|x| !"{}[];\t ,".contains(x)) {
                        self.lines.push((pb, line.line_index + 1));
                    }
                }
            }
        }
    }
}

impl<'v, 'a> Visitor<'v> for IgnoredLines<'a> {

    fn visit_item(&mut self, i: &'v Item) {
        match i.node {
            ItemKind::ExternCrate(..) => self.ignore_lines(i.span),
            ItemKind::Fn(_, _, _, _, _, ref block) => {
                if attr::contains_name(&i.attrs, "test") && self.config.ignore_tests {
                    self.ignore_lines(i.span);
                    self.ignore_lines(block.deref().span);
                }
            },
            _ => {},
        }
        visit::walk_item(self, i);
    }

    fn visit_mod(&mut self, m: &'v Mod, s: Span, _attrs: &[Attribute], _n: NodeId) {
        // If mod is cfg(test) and --ignore-tests ignore contents!
        if let Ok(fl) = self.codemap.span_to_lines(s) {
            if self.config.ignore_tests && self.contains_cfg_test(_attrs) {
                self.ignore_lines(s);
                if fl.lines.len() == 1 {
                    // Ignore the file
                    self.ignore_lines(m.inner);
                }
            }
            else {
                if fl.lines.len() == 1 {
                    // mod imports show up as coverable. Ignore
                    self.ignore_lines(s);
                }
                let mod_path = PathBuf::from(self.codemap.span_to_filename(m.inner));
                if !self.covered.contains(&mod_path) {
                    visit::walk_mod(self, m);
                }
            }
        }
    }

    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, s: Span, _: NodeId) {
        visit::walk_fn(self, fk, fd, s);
    }

    fn visit_stmt(&mut self, s: &Stmt) {
        match s.node {
            StmtKind::Mac(_) => visit::walk_stmt(self, s),
            _ => {},
        }
    }

    fn visit_mac(&mut self, mac: &Mac) {
        // Use this to ignore unreachable lines
        let mac_text = &format!("{}", mac.node.path)[..];
        // TODO unimplemented should have extra logic to exclude the
        // function from coverage
        match mac_text {
            "unimplemented" => self.ignore_lines(mac.span),
            "unreachable" => self.ignore_lines(mac.span),
            _ => {},
        }
        visit::walk_mac(self, mac);
    }

    /// Ignores attributes which may get identified as coverable lines.
    fn visit_attribute(&mut self, attr: &Attribute) {
        if attr.check_name("derive") {
            self.ignore_lines(attr.span);
        }
    }

    /// Struct fields are mistakenly identified as instructions and uncoverable.
    fn visit_struct_field(&mut self, s: &'v StructField) {
        self.ignore_lines(s.span);
        visit::walk_struct_field(self, s);
    }

    fn visit_block(&mut self, b: &'v Block) {
        self.find_ignorable_lines(b.span);
        visit::walk_block(self, b);
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use syntex_syntax::parse::filemap_to_parser;
    use syntex_syntax::parse::parser::Parser;

    struct TestContext {
        conf: Config,
        codemap: Rc<CodeMap>,
        parse_session: ParseSess
    }

    impl TestContext {
        fn generate_parser(&self, filename: &str, src_string: &str) -> Parser {
            let filemap = self.codemap.new_filemap(filename.to_string(),
                                                   src_string.to_string());
            filemap_to_parser(&self.parse_session, filemap)
        }
    }

    impl Default for TestContext {
        fn default() -> TestContext {
            let codemap = Rc::new(CodeMap::new(FilePathMapping::empty()));
            let handler = Handler::with_tty_emitter(ColorConfig::Auto, false, false, Some(codemap.clone()));
            let parse_session = ParseSess::with_span_handler(handler, codemap.clone());
            TestContext {
                conf: Config::default(),
                codemap: codemap,
                parse_session: parse_session
            }
        }
    }

    fn parse_crate(ctx: &TestContext, parser: &mut Parser) -> Vec<usize>  {
        let krate = parser.parse_crate_mod();
        assert!(krate.is_ok());
        let krate = krate.unwrap();
        let unused: HashSet<PathBuf> = HashSet::new();
        let mut visitor = IgnoredLines::from_session(&ctx.parse_session, &unused, &ctx.conf);
        visitor.visit_mod(&krate.module, krate.span, &krate.attrs, NodeId::new(0));
        visitor.lines.iter().map(|x| x.1).collect::<Vec<_>>()
    }

    #[test]
    fn filter_struct_members() {
        let ctx = TestContext::default();
        let mut parser = ctx.generate_parser("struct_test.rs", "#[derive(Debug)]\npub struct Struct {\npub i: i32,\nj:String,\n}");
        let lines = parse_crate(&ctx, &mut parser);

        assert_eq!(lines.len(), 3);
        assert!(lines.contains(&1));
        assert!(lines.contains(&3));
        assert!(lines.contains(&4));
    }

    #[test]
    fn filter_mods() {
        let ctx = TestContext::default();
        let mut parser = ctx.generate_parser("test.rs", "mod foo {\nfn double(x:i32)->i32 {\n x*2\n}\n}");
        let lines = parse_crate(&ctx, &mut parser);
        assert!(!lines.contains(&3));

        let mut parser = ctx.generate_parser("test.rs", "mod foo{}");
        let lines = parse_crate(&ctx, &mut parser);
        assert!(lines.contains(&1));
    }

    #[test]
    fn filter_macros() {
        let ctx = TestContext::default();
        let mut parser = ctx.generate_parser("test.rs", "\n\nfn unused() {\nunimplemented!();\n}");

        let lines = parse_crate(&ctx, &mut parser);
        // Braces should be ignored so number could be higher
        assert!(lines.len() >= 1);
        assert!(lines.contains(&4));

        let mut parser = ctx.generate_parser("test.rs", "fn unused() {\nunreachable!();\n}");
        let lines = parse_crate(&ctx, &mut parser);
        assert!(lines.len() >= 1);
        assert!(lines.contains(&2));

        let mut parser = ctx.generate_parser("test.rs", "fn unused() {\nprintln!(\"text\");\n}");
        let lines = parse_crate(&ctx, &mut parser);
        assert!(!lines.contains(&2));
    }

    #[test]
    fn filter_tests() {
        let ctx = TestContext::default();
        let src_string = "#[cfg(test)]\nmod tests {\n fn boo(){\nassert!(true);\n}\n}";
        let mut parser = ctx.generate_parser("test.rs", src_string);
        let lines = parse_crate(&ctx, &mut parser);
        assert!(!lines.contains(&4));

        let mut ctx = TestContext::default();
        ctx.conf.ignore_tests = true;
        let mut parser = ctx.generate_parser("test.rs", src_string);
        let lines = parse_crate(&ctx, &mut parser);
        assert!(lines.contains(&4));

        let ctx = TestContext::default();
        let src_string = "#[test]\nfn mytest() { \n assert!(true);\n}";
        let mut parser = ctx.generate_parser("test.rs", src_string);
        let lines = parse_crate(&ctx, &mut parser);
        assert!(!lines.contains(&2));
        assert!(!lines.contains(&3));

        let mut ctx = TestContext::default();
        ctx.conf.ignore_tests = true;
        let mut parser = ctx.generate_parser("test.rs", src_string);
        let lines = parse_crate(&ctx, &mut parser);
        assert!(lines.contains(&2));
        assert!(lines.contains(&3));

    }
}
<commit_msg>Fixes macros sometimes not being excluded.<commit_after>use std::rc::Rc;
use std::ops::Deref;
use std::path::PathBuf;
use std::collections::HashSet;
use cargo::core::Workspace;
use cargo::sources::PathSource;
use syntex_syntax::attr;
use syntex_syntax::visit::{self, Visitor, FnKind};
use syntex_syntax::codemap::{CodeMap, Span, FilePathMapping};
use syntex_syntax::ast::{NodeId, Mac, Attribute, Stmt, StmtKind, FnDecl, Mod,
    StructField, Block, Item, ItemKind};
use syntex_syntax::parse::{self, ParseSess};
use syntex_syntax::errors::Handler;
use syntex_syntax::errors::emitter::ColorConfig;
use syntex_syntax::ext::expand::MacroExpander;
use config::Config;

struct IgnoredLines<'a> {
    lines: Vec<(PathBuf, usize)>,
    covered: &'a HashSet<PathBuf>,
    codemap: &'a CodeMap,
    config: &'a Config,
}

/// Returns a list of files and line numbers to ignore (not indexes!)
pub fn get_lines_to_ignore(project: &Workspace, config: &Config) -> Vec<(PathBuf, usize)> {
    let mut result: Vec<(PathBuf, usize)> = Vec::new();

    let pkg = project.current().unwrap();
    let mut src = PathSource::new(pkg.root(), pkg.package_id().source_id(), project.config());
    if let Ok(package) = src.root_package() {

        let codemap = Rc::new(CodeMap::new(FilePathMapping::empty()));
        let handler = Handler::with_tty_emitter(ColorConfig::Auto, false, false, Some(codemap.clone()));
        let parse_session = ParseSess::with_span_handler(handler, codemap.clone());

        let mut done_files: HashSet<PathBuf> = HashSet::new();
        for target in package.targets() {
            let file = target.src_path();
            if !(config.ignore_tests && file.starts_with(project.root().join("tests"))) {
                let mut parser = parse::new_parser_from_file(&parse_session, file);
                if let Ok(krate) = parser.parse_crate_mod() {

                    let mut lines = {
                        let mut visitor = IgnoredLines::from_session(&parse_session, &done_files, config);
                        visitor.visit_mod(&krate.module, krate.span, &krate.attrs, NodeId::new(0));
                        visitor.lines
                    };

                    for l in &lines {
                        done_files.insert(l.0.clone());
                    }
                    result.append(&mut lines);
                }
            }
        }
    }
    result
}

impl<'a> IgnoredLines<'a> {
    /// Construct a new ignored lines object for the given project
    fn from_session(session: &'a ParseSess,
                    covered: &'a HashSet<PathBuf>,
                    config: &'a Config) -> IgnoredLines<'a> {
        IgnoredLines {
            lines: vec![],
            covered: covered,
            codemap: session.codemap(),
            config: config,
        }
    }

    /// Add lines to the line ignore list
    fn ignore_lines(&mut self, span: Span) {
        if let Ok(s) = self.codemap.span_to_lines(span) {
            for line in &s.lines {
                let pb = PathBuf::from(self.codemap.span_to_filename(span) as String);
                // Line number is index+1
                self.lines.push((pb, line.line_index + 1));
            }
        }
    }

    /// Looks for #[cfg(test)] attribute.
    fn contains_cfg_test(&mut self, attrs: &[Attribute]) -> bool {
        attrs.iter()
             .filter(|x| x.path == "cfg")
             .filter_map(|x| x.meta_item_list())
             .flat_map(|x| x)
             .any(|x| {
                 if let Some(w) = x.word() {
                    w.name().as_str() == "test"
                 } else {
                     false
                 }
             })
    }

    /// This function finds ignorable lines within actual coverable code.
    /// As opposed to other functions which find isolated lines that aren't
    /// executed or lines filtered by the user. These lines are things like
    /// close braces that are within coverable code but not coverable.
    fn find_ignorable_lines(&mut self, span: Span) {
        if let Ok(l) = self.codemap.span_to_lines(span) {
            for line in &l.lines {
                let pb = PathBuf::from(self.codemap.span_to_filename(span) as String);
                if let Some(s) = l.file.get_line(line.line_index) {
                    // Is this one of those pointless {, } or }; only lines?
                    if !s.chars().any(|x| !"{}[];\t ,".contains(x)) {
                        self.lines.push((pb, line.line_index + 1));
                    }
                }
            }
        }
    }
}

impl<'v, 'a> Visitor<'v> for IgnoredLines<'a> {

    fn visit_item(&mut self, i: &'v Item) {
        match i.node {
            ItemKind::ExternCrate(..) => self.ignore_lines(i.span),
            ItemKind::Fn(_, _, _, _, _, ref block) => {
                if attr::contains_name(&i.attrs, "test") && self.config.ignore_tests {
                    self.ignore_lines(i.span);
                    self.ignore_lines(block.deref().span);
                }
            },
            _ => {},
        }
        visit::walk_item(self, i);
    }

    fn visit_mod(&mut self, m: &'v Mod, s: Span, _attrs: &[Attribute], _n: NodeId) {
        // If mod is cfg(test) and --ignore-tests ignore contents!
        if let Ok(fl) = self.codemap.span_to_lines(s) {
            if self.config.ignore_tests && self.contains_cfg_test(_attrs) {
                self.ignore_lines(s);
                if fl.lines.len() == 1 {
                    // Ignore the file
                    self.ignore_lines(m.inner);
                }
            }
            else {
                if fl.lines.len() == 1 {
                    // mod imports show up as coverable. Ignore
                    self.ignore_lines(s);
                }
                let mod_path = PathBuf::from(self.codemap.span_to_filename(m.inner));
                if !self.covered.contains(&mod_path) {
                    visit::walk_mod(self, m);
                }
            }
        }
    }

    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, s: Span, _: NodeId) {
        visit::walk_fn(self, fk, fd, s);
    }

    fn visit_mac(&mut self, mac: &Mac) {
        // Use this to ignore unreachable lines
        let mac_text = &format!("{}", mac.node.path)[..];
        // TODO unimplemented should have extra logic to exclude the
        // function from coverage
        match mac_text {
            "unimplemented" => self.ignore_lines(mac.span),
            "unreachable" => self.ignore_lines(mac.span),
            _ => {},
        }
        visit::walk_mac(self, mac);
    }

    /// Ignores attributes which may get identified as coverable lines.
    fn visit_attribute(&mut self, attr: &Attribute) {
        if attr.check_name("derive") {
            self.ignore_lines(attr.span);
        }
    }

    /// Struct fields are mistakenly identified as instructions and uncoverable.
    fn visit_struct_field(&mut self, s: &'v StructField) {
        self.ignore_lines(s.span);
        visit::walk_struct_field(self, s);
    }

    fn visit_block(&mut self, b: &'v Block) {
        self.find_ignorable_lines(b.span);
        visit::walk_block(self, b);
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use syntex_syntax::parse::filemap_to_parser;
    use syntex_syntax::parse::parser::Parser;

    struct TestContext {
        conf: Config,
        codemap: Rc<CodeMap>,
        parse_session: ParseSess
    }

    impl TestContext {
        fn generate_parser(&self, filename: &str, src_string: &str) -> Parser {
            let filemap = self.codemap.new_filemap(filename.to_string(),
                                                   src_string.to_string());
            filemap_to_parser(&self.parse_session, filemap)
        }
    }

    impl Default for TestContext {
        fn default() -> TestContext {
            let codemap = Rc::new(CodeMap::new(FilePathMapping::empty()));
            let handler = Handler::with_tty_emitter(ColorConfig::Auto, false, false, Some(codemap.clone()));
            let parse_session = ParseSess::with_span_handler(handler, codemap.clone());
            TestContext {
                conf: Config::default(),
                codemap: codemap,
                parse_session: parse_session
            }
        }
    }

    fn parse_crate(ctx: &TestContext, parser: &mut Parser) -> Vec<usize>  {
        let krate = parser.parse_crate_mod();
        assert!(krate.is_ok());
        let krate = krate.unwrap();
        let unused: HashSet<PathBuf> = HashSet::new();
        let mut visitor = IgnoredLines::from_session(&ctx.parse_session, &unused, &ctx.conf);
        visitor.visit_mod(&krate.module, krate.span, &krate.attrs, NodeId::new(0));
        visitor.lines.iter().map(|x| x.1).collect::<Vec<_>>()
    }

    #[test]
    fn filter_struct_members() {
        let ctx = TestContext::default();
        let mut parser = ctx.generate_parser("struct_test.rs", "#[derive(Debug)]\npub struct Struct {\npub i: i32,\nj:String,\n}");
        let lines = parse_crate(&ctx, &mut parser);

        assert_eq!(lines.len(), 3);
        assert!(lines.contains(&1));
        assert!(lines.contains(&3));
        assert!(lines.contains(&4));
    }

    #[test]
    fn filter_mods() {
        let ctx = TestContext::default();
        let mut parser = ctx.generate_parser("test.rs", "mod foo {\nfn double(x:i32)->i32 {\n x*2\n}\n}");
        let lines = parse_crate(&ctx, &mut parser);
        assert!(!lines.contains(&3));

        let mut parser = ctx.generate_parser("test.rs", "mod foo{}");
        let lines = parse_crate(&ctx, &mut parser);
        assert!(lines.contains(&1));
    }

    #[test]
    fn filter_macros() {
        let ctx = TestContext::default();
        let mut parser = ctx.generate_parser("test.rs", "\n\nfn unused() {\nunimplemented!();\n}");

        let lines = parse_crate(&ctx, &mut parser);
        // Braces should be ignored so number could be higher
        assert!(lines.len() >= 1);
        assert!(lines.contains(&4));

        let mut parser = ctx.generate_parser("test.rs", "fn unused() {\nunreachable!();\n}");
        let lines = parse_crate(&ctx, &mut parser);
        assert!(lines.len() >= 1);
        assert!(lines.contains(&2));

        let mut parser = ctx.generate_parser("test.rs", "fn unused() {\nprintln!(\"text\");\n}");
        let lines = parse_crate(&ctx, &mut parser);
        assert!(!lines.contains(&2));
    }

    #[test]
    fn filter_tests() {
        let ctx = TestContext::default();
        let src_string = "#[cfg(test)]\nmod tests {\n fn boo(){\nassert!(true);\n}\n}";
        let mut parser = ctx.generate_parser("test.rs", src_string);
        let lines = parse_crate(&ctx, &mut parser);
        assert!(!lines.contains(&4));

        let mut ctx = TestContext::default();
        ctx.conf.ignore_tests = true;
        let mut parser = ctx.generate_parser("test.rs", src_string);
        let lines = parse_crate(&ctx, &mut parser);
        assert!(lines.contains(&4));

        let ctx = TestContext::default();
        let src_string = "#[test]\nfn mytest() { \n assert!(true);\n}";
        let mut parser = ctx.generate_parser("test.rs", src_string);
        let lines = parse_crate(&ctx, &mut parser);
        assert!(!lines.contains(&2));
        assert!(!lines.contains(&3));

        let mut ctx = TestContext::default();
        ctx.conf.ignore_tests = true;
        let mut parser = ctx.generate_parser("test.rs", src_string);
        let lines = parse_crate(&ctx, &mut parser);
        assert!(lines.contains(&2));
        assert!(lines.contains(&3));

    }
}
<|endoftext|>