<commit_before>use crate::fmt;
use crate::ops::Try;

use super::super::{DoubleEndedIterator, Fuse, FusedIterator, Iterator};
use super::Map;

/// An iterator that maps each element to an iterator, and yields the elements
/// of the produced iterators.
///
/// This `struct` is created by the [`flat_map`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`flat_map`]: trait.Iterator.html#method.flat_map
/// [`Iterator`]: trait.Iterator.html
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct FlatMap<I, U: IntoIterator, F> {
    inner: FlattenCompat<Map<I, F>, <U as IntoIterator>::IntoIter>,
}
impl<I: Iterator, U: IntoIterator, F: FnMut(I::Item) -> U> FlatMap<I, U, F> {
    pub(in super::super) fn new(iter: I, f: F) -> FlatMap<I, U, F> {
        FlatMap { inner: FlattenCompat::new(iter.map(f)) }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Clone, U, F: Clone> Clone for FlatMap<I, U, F>
where
    U: Clone + IntoIterator<IntoIter: Clone>,
{
    fn clone(&self) -> Self {
        FlatMap { inner: self.inner.clone() }
    }
}

#[stable(feature = "core_impl_debug", since = "1.9.0")]
impl<I: fmt::Debug, U, F> fmt::Debug for FlatMap<I, U, F>
where
    U: IntoIterator<IntoIter: fmt::Debug>,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("FlatMap").field("inner", &self.inner).finish()
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator, U: IntoIterator, F> Iterator for FlatMap<I, U, F>
where
    F: FnMut(I::Item) -> U,
{
    type Item = U::Item;

    #[inline]
    fn next(&mut self) -> Option<U::Item> {
        self.inner.next()
    }

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

    #[inline]
    fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        self.inner.try_fold(init, fold)
    }

    #[inline]
    fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        self.inner.fold(init, fold)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: DoubleEndedIterator, U, F> DoubleEndedIterator for FlatMap<I, U, F>
where
    F: FnMut(I::Item) -> U,
    U: IntoIterator<IntoIter: DoubleEndedIterator>,
{
    #[inline]
    fn next_back(&mut self) -> Option<U::Item> {
        self.inner.next_back()
    }

    #[inline]
    fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        self.inner.try_rfold(init, fold)
    }

    #[inline]
    fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        self.inner.rfold(init, fold)
    }
}

#[stable(feature = "fused", since = "1.26.0")]
impl<I, U, F> FusedIterator for FlatMap<I, U, F>
where
    I: FusedIterator,
    U: IntoIterator,
    F: FnMut(I::Item) -> U,
{
}

/// An iterator that flattens one level of nesting in an iterator of things
/// that can be turned into iterators.
///
/// This `struct` is created by the [`flatten`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`flatten`]: trait.Iterator.html#method.flatten
/// [`Iterator`]: trait.Iterator.html
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "iterator_flatten", since = "1.29.0")]
pub struct Flatten<I: Iterator<Item: IntoIterator>> {
    inner: FlattenCompat<I, <I::Item as IntoIterator>::IntoIter>,
}

impl<I: Iterator<Item: IntoIterator>> Flatten<I> {
    pub(in super::super) fn new(iter: I) -> Flatten<I> {
        Flatten { inner: FlattenCompat::new(iter) }
    }
}

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> fmt::Debug for Flatten<I>
where
    I: fmt::Debug + Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: fmt::Debug + Iterator,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Flatten").field("inner", &self.inner).finish()
    }
}

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> Clone for Flatten<I>
where
    I: Clone + Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: Clone + Iterator,
{
    fn clone(&self) -> Self {
        Flatten { inner: self.inner.clone() }
    }
}

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> Iterator for Flatten<I>
where
    I: Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: Iterator,
{
    type Item = U::Item;

    #[inline]
    fn next(&mut self) -> Option<U::Item> {
        self.inner.next()
    }

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

    #[inline]
    fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        self.inner.try_fold(init, fold)
    }

    #[inline]
    fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        self.inner.fold(init, fold)
    }
}

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> DoubleEndedIterator for Flatten<I>
where
    I: DoubleEndedIterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: DoubleEndedIterator,
{
    #[inline]
    fn next_back(&mut self) -> Option<U::Item> {
        self.inner.next_back()
    }

    #[inline]
    fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        self.inner.try_rfold(init, fold)
    }

    #[inline]
    fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        self.inner.rfold(init, fold)
    }
}

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> FusedIterator for Flatten<I>
where
    I: FusedIterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: Iterator,
{
}

/// Real logic of both `Flatten` and `FlatMap` which simply delegate to
/// this type.
#[derive(Clone, Debug)]
struct FlattenCompat<I, U> {
    iter: Fuse<I>,
    frontiter: Option<U>,
    backiter: Option<U>,
}
impl<I, U> FlattenCompat<I, U>
where
    I: Iterator,
{
    /// Adapts an iterator by flattening it, for use in `flatten()` and `flat_map()`.
    fn new(iter: I) -> FlattenCompat<I, U> {
        FlattenCompat { iter: iter.fuse(), frontiter: None, backiter: None }
    }
}

impl<I, U> Iterator for FlattenCompat<I, U>
where
    I: Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: Iterator,
{
    type Item = U::Item;

    #[inline]
    fn next(&mut self) -> Option<U::Item> {
        loop {
            if let Some(ref mut inner) = self.frontiter {
                match inner.next() {
                    None => self.frontiter = None,
                    elt @ Some(_) => return elt,
                }
            }
            match self.iter.next() {
                None => return self.backiter.as_mut()?.next(),
                Some(inner) => self.frontiter = Some(inner.into_iter()),
            }
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let (flo, fhi) = self.frontiter.as_ref().map_or((0, Some(0)), U::size_hint);
        let (blo, bhi) = self.backiter.as_ref().map_or((0, Some(0)), U::size_hint);
        let lo = flo.saturating_add(blo);
        match (self.iter.size_hint(), fhi, bhi) {
            ((0, Some(0)), Some(a), Some(b)) => (lo, a.checked_add(b)),
            _ => (lo, None),
        }
    }

    #[inline]
    fn try_fold<Acc, Fold, R>(&mut self, mut init: Acc, mut fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        #[inline]
        fn flatten<'a, T: IntoIterator, Acc, R: Try<Ok = Acc>>(
            frontiter: &'a mut Option<T::IntoIter>,
            fold: &'a mut impl FnMut(Acc, T::Item) -> R,
        ) -> impl FnMut(Acc, T) -> R + 'a {
            move |acc, x| {
                let mut mid = x.into_iter();
                let r = mid.try_fold(acc, &mut *fold);
                *frontiter = Some(mid);
                r
            }
        }

        if let Some(ref mut front) = self.frontiter {
            init = front.try_fold(init, &mut fold)?;
        }
        self.frontiter = None;

        init = self.iter.try_fold(init, flatten(&mut self.frontiter, &mut fold))?;
        self.frontiter = None;

        if let Some(ref mut back) = self.backiter {
            init = back.try_fold(init, &mut fold)?;
        }
        self.backiter = None;

        Try::from_ok(init)
    }

    #[inline]
    fn fold<Acc, Fold>(self, init: Acc, ref mut fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        #[inline]
        fn flatten<U: Iterator, Acc>(
            fold: &mut impl FnMut(Acc, U::Item) -> Acc,
        ) -> impl FnMut(Acc, U) -> Acc + '_ {
            move |acc, iter| iter.fold(acc, &mut *fold)
        }

        self.frontiter
            .into_iter()
            .chain(self.iter.map(IntoIterator::into_iter))
            .chain(self.backiter)
            .fold(init, flatten(fold))
    }
}

impl<I, U> DoubleEndedIterator for FlattenCompat<I, U>
where
    I: DoubleEndedIterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: DoubleEndedIterator,
{
    #[inline]
    fn next_back(&mut self) -> Option<U::Item> {
        loop {
            if let Some(ref mut inner) = self.backiter {
                match inner.next_back() {
                    None => self.backiter = None,
                    elt @ Some(_) => return elt,
                }
            }
            match self.iter.next_back() {
                None => return self.frontiter.as_mut()?.next_back(),
                next => self.backiter = next.map(IntoIterator::into_iter),
            }
        }
    }

    #[inline]
    fn try_rfold<Acc, Fold, R>(&mut self, mut init: Acc, mut fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        #[inline]
        fn flatten<'a, T: IntoIterator, Acc, R: Try<Ok = Acc>>(
            backiter: &'a mut Option<T::IntoIter>,
            fold: &'a mut impl FnMut(Acc, T::Item) -> R,
        ) -> impl FnMut(Acc, T) -> R + 'a
        where
            T::IntoIter: DoubleEndedIterator,
        {
            move |acc, x| {
                let mut mid = x.into_iter();
                let r = mid.try_rfold(acc, &mut *fold);
                *backiter = Some(mid);
                r
            }
        }

        if let Some(ref mut back) = self.backiter {
            init = back.try_rfold(init, &mut fold)?;
        }
        self.backiter = None;

        init = self.iter.try_rfold(init, flatten(&mut self.backiter, &mut fold))?;
        self.backiter = None;

        if let Some(ref mut front) = self.frontiter {
            init = front.try_rfold(init, &mut fold)?;
        }
        self.frontiter = None;

        Try::from_ok(init)
    }

    #[inline]
    fn rfold<Acc, Fold>(self, init: Acc, ref mut fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        #[inline]
        fn flatten<U: DoubleEndedIterator, Acc>(
            fold: &mut impl FnMut(Acc, U::Item) -> Acc,
        ) -> impl FnMut(Acc, U) -> Acc + '_ {
            move |acc, iter| iter.rfold(acc, &mut *fold)
        }

        self.frontiter
            .into_iter()
            .chain(self.iter.map(IntoIterator::into_iter))
            .chain(self.backiter)
            .rfold(init, flatten(fold))
    }
}
<commit_msg>Rollup merge of #76707 - pickfire:patch-4, r=jonas-schievink<commit_after>use crate::fmt;
use crate::ops::Try;

use super::super::{DoubleEndedIterator, Fuse, FusedIterator, Iterator};
use super::Map;

/// An iterator that maps each element to an iterator, and yields the elements
/// of the produced iterators.
///
/// This `struct` is created by [`Iterator::flat_map`]. See its documentation
/// for more.
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct FlatMap<I, U: IntoIterator, F> {
    inner: FlattenCompat<Map<I, F>, <U as IntoIterator>::IntoIter>,
}
impl<I: Iterator, U: IntoIterator, F: FnMut(I::Item) -> U> FlatMap<I, U, F> {
    pub(in super::super) fn new(iter: I, f: F) -> FlatMap<I, U, F> {
        FlatMap { inner: FlattenCompat::new(iter.map(f)) }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Clone, U, F: Clone> Clone for FlatMap<I, U, F>
where
    U: Clone + IntoIterator<IntoIter: Clone>,
{
    fn clone(&self) -> Self {
        FlatMap { inner: self.inner.clone() }
    }
}

#[stable(feature = "core_impl_debug", since = "1.9.0")]
impl<I: fmt::Debug, U, F> fmt::Debug for FlatMap<I, U, F>
where
    U: IntoIterator<IntoIter: fmt::Debug>,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("FlatMap").field("inner", &self.inner).finish()
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator, U: IntoIterator, F> Iterator for FlatMap<I, U, F>
where
    F: FnMut(I::Item) -> U,
{
    type Item = U::Item;

    #[inline]
    fn next(&mut self) -> Option<U::Item> {
        self.inner.next()
    }

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

    #[inline]
    fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        self.inner.try_fold(init, fold)
    }

    #[inline]
    fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        self.inner.fold(init, fold)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: DoubleEndedIterator, U, F> DoubleEndedIterator for FlatMap<I, U, F>
where
    F: FnMut(I::Item) -> U,
    U: IntoIterator<IntoIter: DoubleEndedIterator>,
{
    #[inline]
    fn next_back(&mut self) -> Option<U::Item> {
        self.inner.next_back()
    }

    #[inline]
    fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        self.inner.try_rfold(init, fold)
    }

    #[inline]
    fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        self.inner.rfold(init, fold)
    }
}

#[stable(feature = "fused", since = "1.26.0")]
impl<I, U, F> FusedIterator for FlatMap<I, U, F>
where
    I: FusedIterator,
    U: IntoIterator,
    F: FnMut(I::Item) -> U,
{
}

/// An iterator that flattens one level of nesting in an iterator of things
/// that can be turned into iterators.
///
/// This `struct` is created by the [`flatten`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`flatten`]: trait.Iterator.html#method.flatten
/// [`Iterator`]: trait.Iterator.html
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "iterator_flatten", since = "1.29.0")]
pub struct Flatten<I: Iterator<Item: IntoIterator>> {
    inner: FlattenCompat<I, <I::Item as IntoIterator>::IntoIter>,
}

impl<I: Iterator<Item: IntoIterator>> Flatten<I> {
    pub(in super::super) fn new(iter: I) -> Flatten<I> {
        Flatten { inner: FlattenCompat::new(iter) }
    }
}

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> fmt::Debug for Flatten<I>
where
    I: fmt::Debug + Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: fmt::Debug + Iterator,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Flatten").field("inner", &self.inner).finish()
    }
}

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> Clone for Flatten<I>
where
    I: Clone + Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: Clone + Iterator,
{
    fn clone(&self) -> Self {
        Flatten { inner: self.inner.clone() }
    }
}

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> Iterator for Flatten<I>
where
    I: Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: Iterator,
{
    type Item = U::Item;

    #[inline]
    fn next(&mut self) -> Option<U::Item> {
        self.inner.next()
    }

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

    #[inline]
    fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        self.inner.try_fold(init, fold)
    }

    #[inline]
    fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        self.inner.fold(init, fold)
    }
}

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> DoubleEndedIterator for Flatten<I>
where
    I: DoubleEndedIterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: DoubleEndedIterator,
{
    #[inline]
    fn next_back(&mut self) -> Option<U::Item> {
        self.inner.next_back()
    }

    #[inline]
    fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        self.inner.try_rfold(init, fold)
    }

    #[inline]
    fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        self.inner.rfold(init, fold)
    }
}

#[stable(feature = "iterator_flatten", since = "1.29.0")]
impl<I, U> FusedIterator for Flatten<I>
where
    I: FusedIterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: Iterator,
{
}

/// Real logic of both `Flatten` and `FlatMap` which simply delegate to
/// this type.
#[derive(Clone, Debug)]
struct FlattenCompat<I, U> {
    iter: Fuse<I>,
    frontiter: Option<U>,
    backiter: Option<U>,
}
impl<I, U> FlattenCompat<I, U>
where
    I: Iterator,
{
    /// Adapts an iterator by flattening it, for use in `flatten()` and `flat_map()`.
    fn new(iter: I) -> FlattenCompat<I, U> {
        FlattenCompat { iter: iter.fuse(), frontiter: None, backiter: None }
    }
}

impl<I, U> Iterator for FlattenCompat<I, U>
where
    I: Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: Iterator,
{
    type Item = U::Item;

    #[inline]
    fn next(&mut self) -> Option<U::Item> {
        loop {
            if let Some(ref mut inner) = self.frontiter {
                match inner.next() {
                    None => self.frontiter = None,
                    elt @ Some(_) => return elt,
                }
            }
            match self.iter.next() {
                None => return self.backiter.as_mut()?.next(),
                Some(inner) => self.frontiter = Some(inner.into_iter()),
            }
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let (flo, fhi) = self.frontiter.as_ref().map_or((0, Some(0)), U::size_hint);
        let (blo, bhi) = self.backiter.as_ref().map_or((0, Some(0)), U::size_hint);
        let lo = flo.saturating_add(blo);
        match (self.iter.size_hint(), fhi, bhi) {
            ((0, Some(0)), Some(a), Some(b)) => (lo, a.checked_add(b)),
            _ => (lo, None),
        }
    }

    #[inline]
    fn try_fold<Acc, Fold, R>(&mut self, mut init: Acc, mut fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        #[inline]
        fn flatten<'a, T: IntoIterator, Acc, R: Try<Ok = Acc>>(
            frontiter: &'a mut Option<T::IntoIter>,
            fold: &'a mut impl FnMut(Acc, T::Item) -> R,
        ) -> impl FnMut(Acc, T) -> R + 'a {
            move |acc, x| {
                let mut mid = x.into_iter();
                let r = mid.try_fold(acc, &mut *fold);
                *frontiter = Some(mid);
                r
            }
        }

        if let Some(ref mut front) = self.frontiter {
            init = front.try_fold(init, &mut fold)?;
        }
        self.frontiter = None;

        init = self.iter.try_fold(init, flatten(&mut self.frontiter, &mut fold))?;
        self.frontiter = None;

        if let Some(ref mut back) = self.backiter {
            init = back.try_fold(init, &mut fold)?;
        }
        self.backiter = None;

        Try::from_ok(init)
    }

    #[inline]
    fn fold<Acc, Fold>(self, init: Acc, ref mut fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        #[inline]
        fn flatten<U: Iterator, Acc>(
            fold: &mut impl FnMut(Acc, U::Item) -> Acc,
        ) -> impl FnMut(Acc, U) -> Acc + '_ {
            move |acc, iter| iter.fold(acc, &mut *fold)
        }

        self.frontiter
            .into_iter()
            .chain(self.iter.map(IntoIterator::into_iter))
            .chain(self.backiter)
            .fold(init, flatten(fold))
    }
}

impl<I, U> DoubleEndedIterator for FlattenCompat<I, U>
where
    I: DoubleEndedIterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
    U: DoubleEndedIterator,
{
    #[inline]
    fn next_back(&mut self) -> Option<U::Item> {
        loop {
            if let Some(ref mut inner) = self.backiter {
                match inner.next_back() {
                    None => self.backiter = None,
                    elt @ Some(_) => return elt,
                }
            }
            match self.iter.next_back() {
                None => return self.frontiter.as_mut()?.next_back(),
                next => self.backiter = next.map(IntoIterator::into_iter),
            }
        }
    }

    #[inline]
    fn try_rfold<Acc, Fold, R>(&mut self, mut init: Acc, mut fold: Fold) -> R
    where
        Self: Sized,
        Fold: FnMut(Acc, Self::Item) -> R,
        R: Try<Ok = Acc>,
    {
        #[inline]
        fn flatten<'a, T: IntoIterator, Acc, R: Try<Ok = Acc>>(
            backiter: &'a mut Option<T::IntoIter>,
            fold: &'a mut impl FnMut(Acc, T::Item) -> R,
        ) -> impl FnMut(Acc, T) -> R + 'a
        where
            T::IntoIter: DoubleEndedIterator,
        {
            move |acc, x| {
                let mut mid = x.into_iter();
                let r = mid.try_rfold(acc, &mut *fold);
                *backiter = Some(mid);
                r
            }
        }

        if let Some(ref mut back) = self.backiter {
            init = back.try_rfold(init, &mut fold)?;
        }
        self.backiter = None;

        init = self.iter.try_rfold(init, flatten(&mut self.backiter, &mut fold))?;
        self.backiter = None;

        if let Some(ref mut front) = self.frontiter {
            init = front.try_rfold(init, &mut fold)?;
        }
        self.frontiter = None;

        Try::from_ok(init)
    }

    #[inline]
    fn rfold<Acc, Fold>(self, init: Acc, ref mut fold: Fold) -> Acc
    where
        Fold: FnMut(Acc, Self::Item) -> Acc,
    {
        #[inline]
        fn flatten<U: DoubleEndedIterator, Acc>(
            fold: &mut impl FnMut(Acc, U::Item) -> Acc,
        ) -> impl FnMut(Acc, U) -> Acc + '_ {
            move |acc, iter| iter.rfold(acc, &mut *fold)
        }

        self.frontiter
            .into_iter()
            .chain(self.iter.map(IntoIterator::into_iter))
            .chain(self.backiter)
            .rfold(init, flatten(fold))
    }
}
<|endoftext|>


<commit_before>#![crate_id(name="cp", vers="1.0.0", author="Jordy Dickinson")]
#![feature(macro_rules)]
#![feature(phase)]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jordy Dickinson <jordy.dickinson@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE file
 * that was distributed with this source code.
 */

extern crate getopts;
#[phase(syntax, link)] extern crate log;

use std::os;
use std::io;
use std::io::fs;

use getopts::{
    getopts,
    optflag,
    usage,
};

#[deriving(Eq, PartialEq)]
pub enum Mode {
    Copy,
    Help,
    Version,
}

#[allow(dead_code)]
fn main() { uumain(os::args()); }

pub fn uumain(args: Vec<String>) {
    let opts = [
        optflag("h", "help", "display this help and exit"),
        optflag("", "version", "output version information and exit"),
    ];
    let matches = match getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(e) => {
            error!("error: {:s}", e.to_err_msg());
            fail!()
        },
    };

    let progname = args.get(0);
    let usage = usage("Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.", opts);
    let mode = if matches.opt_present("version") {
        Version
    } else if matches.opt_present("help") {
        Help
    } else {
        Copy
    };

    match mode {
        Copy    => copy(matches),
        Help    => help(progname.as_slice(), usage.as_slice()),
        Version => version(),
    }
}

fn version() {
    println!("cp 1.0.0");
}

fn help(progname: &str, usage: &str) {
    let msg = format!("Usage: {0} SOURCE DEST\n  \
                         or:  {0} SOURCE... DIRECTORY\n  \
                         or:  {0} -t DIRECTORY SOURCE\n\
                       \n\
                       {1}", progname, usage);
    println!("{}", msg);
}

fn copy(matches: getopts::Matches) {
    let sources : Vec<Path> = if matches.free.len() < 1 {
        error!("error: Missing SOURCE argument. Try --help.");
        fail!()
    } else {
        // All but the last argument:
        matches.free.slice(0, matches.free.len() - 2).iter()
            .map(|arg| Path::new(arg.clone())).collect()
    };
    let dest = if matches.free.len() < 2 {
        error!("error: Missing DEST argument. Try --help.");
        fail!()
    } else {
        // Only the last argument:
        Path::new(matches.free.get(matches.free.len() - 1).as_slice())
    };

    assert!(sources.len() >= 1);

    if sources.len() == 1 {
        let source = sources.get(0);
        let same_file = match paths_refer_to_same_file(source, &dest) {
            Ok(b)  => b,
            Err(e) => if e.kind == io::FileNotFound {
                false
            } else {
                error!("error: {:s}", e.to_str());
                fail!()
            }
        };

        if same_file {
            error!("error: \"{:s}\" and \"{:s}\" are the same file",
                source.display().to_str(),
                dest.display().to_str());
            fail!();
        }

        let io_result = fs::copy(source, &dest);

        if io_result.is_err() {
            let err = io_result.unwrap_err();
            error!("error: {:s}", err.to_str());
            fail!();
        }
    } else {
        if fs::stat(&dest).unwrap().kind != io::TypeDirectory {
            error!("error: TARGET must be a directory");
            fail!();
        }

        for source in sources.iter() {
            if fs::stat(source).unwrap().kind != io::TypeFile {
                error!("error: \"{:s}\" is not a file", source.display().to_str());
                continue;
            }

            let mut full_dest = dest.clone();

            full_dest.push(source.filename_str().unwrap());

            println!("{:s}", full_dest.display().to_str());

            let io_result = fs::copy(source, &full_dest);

            if io_result.is_err() {
                let err = io_result.unwrap_err();
                error!("error: {:s}", err.to_str());
                fail!()
            }
        }
    }
}

pub fn paths_refer_to_same_file(p1: &Path, p2: &Path) -> io::IoResult<bool> {
    let mut raw_p1 = p1.clone();
    let mut raw_p2 = p2.clone();

    let p1_lstat = match fs::lstat(&raw_p1) {
        Ok(stat) => stat,
        Err(e)   => return Err(e),
    };

    let p2_lstat = match fs::lstat(&raw_p2) {
        Ok(stat) => stat,
        Err(e)   => return Err(e),
    };

    // We have to take symlinks and relative paths into account.
    if p1_lstat.kind == io::TypeSymlink {
        raw_p1 = fs::readlink(&raw_p1).unwrap();
    }
    raw_p1 = os::make_absolute(&raw_p1);

    if p2_lstat.kind == io::TypeSymlink {
        raw_p2 = fs::readlink(&raw_p2).unwrap();
    }
    raw_p2 = os::make_absolute(&raw_p2);

    Ok(raw_p1 == raw_p2)
}
<commit_msg>cp: fix argument parsing<commit_after>#![crate_id(name="cp", vers="1.0.0", author="Jordy Dickinson")]
#![feature(macro_rules)]
#![feature(phase)]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jordy Dickinson <jordy.dickinson@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE file
 * that was distributed with this source code.
 */

extern crate getopts;
#[phase(syntax, link)] extern crate log;

use std::os;
use std::io;
use std::io::fs;

use getopts::{
    getopts,
    optflag,
    usage,
};

#[deriving(Eq, PartialEq)]
pub enum Mode {
    Copy,
    Help,
    Version,
}

#[allow(dead_code)]
fn main() { uumain(os::args()); }

pub fn uumain(args: Vec<String>) {
    let opts = [
        optflag("h", "help", "display this help and exit"),
        optflag("", "version", "output version information and exit"),
    ];
    let matches = match getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(e) => {
            error!("error: {:s}", e.to_err_msg());
            fail!()
        },
    };

    let progname = args.get(0);
    let usage = usage("Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.", opts);
    let mode = if matches.opt_present("version") {
        Version
    } else if matches.opt_present("help") {
        Help
    } else {
        Copy
    };

    match mode {
        Copy    => copy(matches),
        Help    => help(progname.as_slice(), usage.as_slice()),
        Version => version(),
    }
}

fn version() {
    println!("cp 1.0.0");
}

fn help(progname: &str, usage: &str) {
    let msg = format!("Usage: {0} SOURCE DEST\n  \
                         or:  {0} SOURCE... DIRECTORY\n  \
                         or:  {0} -t DIRECTORY SOURCE\n\
                       \n\
                       {1}", progname, usage);
    println!("{}", msg);
}

fn copy(matches: getopts::Matches) {
    let sources : Vec<Path> = if matches.free.len() < 1 {
        error!("error: Missing SOURCE argument. Try --help.");
        fail!()
    } else {
        // All but the last argument:
        matches.free.slice(0, matches.free.len() - 1).iter()
            .map(|arg| Path::new(arg.clone())).collect()
    };
    let dest = if matches.free.len() < 2 {
        error!("error: Missing DEST argument. Try --help.");
        fail!()
    } else {
        // Only the last argument:
        Path::new(matches.free.get(matches.free.len() - 1).as_slice())
    };

    assert!(sources.len() >= 1);

    if sources.len() == 1 {
        let source = sources.get(0);
        let same_file = match paths_refer_to_same_file(source, &dest) {
            Ok(b)  => b,
            Err(e) => if e.kind == io::FileNotFound {
                false
            } else {
                error!("error: {:s}", e.to_str());
                fail!()
            }
        };

        if same_file {
            error!("error: \"{:s}\" and \"{:s}\" are the same file",
                source.display().to_str(),
                dest.display().to_str());
            fail!();
        }

        let io_result = fs::copy(source, &dest);

        if io_result.is_err() {
            let err = io_result.unwrap_err();
            error!("error: {:s}", err.to_str());
            fail!();
        }
    } else {
        if fs::stat(&dest).unwrap().kind != io::TypeDirectory {
            error!("error: TARGET must be a directory");
            fail!();
        }

        for source in sources.iter() {
            if fs::stat(source).unwrap().kind != io::TypeFile {
                error!("error: \"{:s}\" is not a file", source.display().to_str());
                continue;
            }

            let mut full_dest = dest.clone();

            full_dest.push(source.filename_str().unwrap());

            println!("{:s}", full_dest.display().to_str());

            let io_result = fs::copy(source, &full_dest);

            if io_result.is_err() {
                let err = io_result.unwrap_err();
                error!("error: {:s}", err.to_str());
                fail!()
            }
        }
    }
}

pub fn paths_refer_to_same_file(p1: &Path, p2: &Path) -> io::IoResult<bool> {
    let mut raw_p1 = p1.clone();
    let mut raw_p2 = p2.clone();

    let p1_lstat = match fs::lstat(&raw_p1) {
        Ok(stat) => stat,
        Err(e)   => return Err(e),
    };

    let p2_lstat = match fs::lstat(&raw_p2) {
        Ok(stat) => stat,
        Err(e)   => return Err(e),
    };

    // We have to take symlinks and relative paths into account.
    if p1_lstat.kind == io::TypeSymlink {
        raw_p1 = fs::readlink(&raw_p1).unwrap();
    }
    raw_p1 = os::make_absolute(&raw_p1);

    if p2_lstat.kind == io::TypeSymlink {
        raw_p2 = fs::readlink(&raw_p2).unwrap();
    }
    raw_p2 = os::make_absolute(&raw_p2);

    Ok(raw_p1 == raw_p2)
}
<|endoftext|>


<commit_before>
extern crate ndarray;
extern crate ndarray_linalg as linalg;
extern crate num_traits;

use ndarray::prelude::*;
use linalg::Matrix;
use num_traits::float::Float;

fn assert_almost_eq(a: f64, b: f64) {
    let rel_dev = (a - b).abs() / (a.abs() + b.abs());
    if rel_dev > 1.0e-7 {
        panic!("a={:?}, b={:?} are not almost equal", a, b);
    }
}

#[test]
fn test_matrix_norm_square() {
    let a = Array::range(1., 10., 1.).into_shape((3, 3)).unwrap();
    assert_almost_eq(a.norm_1(), 18.0);
    assert_almost_eq(a.norm_i(), 24.0);
    assert_almost_eq(a.norm_f(), 285.0.sqrt());
}

#[test]
fn test_matrix_norm_square_t() {
    let a = Array::range(1., 10., 1.).into_shape((3, 3)).unwrap().reversed_axes();
    assert_almost_eq(a.norm_1(), 24.0);
    assert_almost_eq(a.norm_i(), 18.0);
    assert_almost_eq(a.norm_f(), 285.0.sqrt());
}

#[test]
fn test_matrix_norm_3x4() {
    let a = Array::range(1., 13., 1.).into_shape((3, 4)).unwrap();
    assert_almost_eq(a.norm_1(), 24.0);
    assert_almost_eq(a.norm_i(), 42.0);
    assert_almost_eq(a.norm_f(), 650.0.sqrt());
}

#[test]
fn test_matrix_norm_3x4_t() {
    let a = Array::range(1., 13., 1.)
        .into_shape((3, 4))
        .unwrap()
        .reversed_axes();
    assert_almost_eq(a.norm_1(), 42.0);
    assert_almost_eq(a.norm_i(), 24.0);
    assert_almost_eq(a.norm_f(), 650.0.sqrt());
}

#[test]
fn test_matrix_norm_4x3() {
    let a = Array::range(1., 13., 1.).into_shape((4, 3)).unwrap();
    assert_almost_eq(a.norm_1(), 30.0);
    assert_almost_eq(a.norm_i(), 33.0);
    assert_almost_eq(a.norm_f(), 650.0.sqrt());
}

#[test]
fn test_matrix_norm_4x3_t() {
    let a = Array::range(1., 13., 1.)
        .into_shape((4, 3))
        .unwrap()
        .reversed_axes();
    assert_almost_eq(a.norm_1(), 33.0);
    assert_almost_eq(a.norm_i(), 30.0);
    assert_almost_eq(a.norm_f(), 650.0.sqrt());
}
<commit_msg>Remove "test_" prefix from test functions<commit_after>
extern crate ndarray;
extern crate ndarray_linalg as linalg;
extern crate num_traits;

use ndarray::prelude::*;
use linalg::Matrix;
use num_traits::float::Float;

fn assert_almost_eq(a: f64, b: f64) {
    let rel_dev = (a - b).abs() / (a.abs() + b.abs());
    if rel_dev > 1.0e-7 {
        panic!("a={:?}, b={:?} are not almost equal", a, b);
    }
}

#[test]
fn matrix_norm_square() {
    let a = Array::range(1., 10., 1.).into_shape((3, 3)).unwrap();
    assert_almost_eq(a.norm_1(), 18.0);
    assert_almost_eq(a.norm_i(), 24.0);
    assert_almost_eq(a.norm_f(), 285.0.sqrt());
}

#[test]
fn matrix_norm_square_t() {
    let a = Array::range(1., 10., 1.).into_shape((3, 3)).unwrap().reversed_axes();
    assert_almost_eq(a.norm_1(), 24.0);
    assert_almost_eq(a.norm_i(), 18.0);
    assert_almost_eq(a.norm_f(), 285.0.sqrt());
}

#[test]
fn matrix_norm_3x4() {
    let a = Array::range(1., 13., 1.).into_shape((3, 4)).unwrap();
    assert_almost_eq(a.norm_1(), 24.0);
    assert_almost_eq(a.norm_i(), 42.0);
    assert_almost_eq(a.norm_f(), 650.0.sqrt());
}

#[test]
fn matrix_norm_3x4_t() {
    let a = Array::range(1., 13., 1.)
        .into_shape((3, 4))
        .unwrap()
        .reversed_axes();
    assert_almost_eq(a.norm_1(), 42.0);
    assert_almost_eq(a.norm_i(), 24.0);
    assert_almost_eq(a.norm_f(), 650.0.sqrt());
}

#[test]
fn matrix_norm_4x3() {
    let a = Array::range(1., 13., 1.).into_shape((4, 3)).unwrap();
    assert_almost_eq(a.norm_1(), 30.0);
    assert_almost_eq(a.norm_i(), 33.0);
    assert_almost_eq(a.norm_f(), 650.0.sqrt());
}

#[test]
fn matrix_norm_4x3_t() {
    let a = Array::range(1., 13., 1.)
        .into_shape((4, 3))
        .unwrap()
        .reversed_axes();
    assert_almost_eq(a.norm_1(), 33.0);
    assert_almost_eq(a.norm_i(), 30.0);
    assert_almost_eq(a.norm_f(), 650.0.sqrt());
}
<|endoftext|>


<commit_before>//! The state of the game itself.

use message;

use std::collections::HashMap;
use std::sync::mpsc;

use math::distance_between;
use rand::{thread_rng, Rng};

use self::super::Client;
use self::super::WebSocketEvent;

static BULLET_RADIUS: f32 = 5.0;
static PLAYER_RADIUS: f32 = 10.0;
static MAP_WIDTH: f32 = 500.0;
static MAP_HEIGHT: f32 = 500.0;

/// The `GameState` contains the whole state of the game.
///
/// It consists of both players, and all the clients which are currently connected.
#[derive(Debug)]
pub struct GameState {
    players: HashMap<u32, message::Player>,
    bullets: HashMap<u32, message::Bullet>,
    clients: HashMap<u32, Client>,
    next_bullet_id: u32,
}

impl GameState {
    /// Create a new game state.
    pub fn new() -> GameState {
        GameState {
            players: HashMap::new(),
            bullets: HashMap::new(),
            clients: HashMap::new(),
            next_bullet_id: 0,
        }
    }

    /// Tries to process every available websocket event without blocking.
    pub fn process_websocket_events(&mut self, game_messages: &mpsc::Receiver<WebSocketEvent>) {
        loop {
            match game_messages.try_recv() {
                Ok(message) => self.process_websocket_event(message),
                Err(mpsc::TryRecvError::Empty) => return,
                Err(mpsc::TryRecvError::Disconnected) => panic!("Now I am disconnected?"),
            }
        }
    }

    /// Updates the game state in one tick.
    pub fn process_game_update(&mut self) {
        // Do a normal position update
        for (_, player) in &mut self.players {
            player.x += player.move_x.unwrap_or(0.0);
            player.y += player.move_y.unwrap_or(0.0);
        }

        let mut destroyed_bullets = Vec::new();
        let mut destroyed_players = Vec::new();

        for (_, bullet) in &mut self.bullets {
            bullet.x += bullet.move_x.unwrap_or(0.0);
            bullet.y += bullet.move_y.unwrap_or(0.0);

            if bullet.x < 0.0 || bullet.x > MAP_WIDTH || bullet.y < 0.0 || bullet.y > MAP_HEIGHT {
                destroyed_bullets.push(bullet.id);
            }
        }

        // Check for collisions
        for (_, bullet) in &mut self.bullets {
            for (_, player) in &mut self.players {
                if distance_between(bullet.x, bullet.y, player.x, player.y) <
                   BULLET_RADIUS + PLAYER_RADIUS {
                    destroyed_bullets.push(bullet.id);
                    destroyed_players.push(player.id);
                }
            }
        }

        // Process destroy requests
        for bullet_id in destroyed_bullets {
            let _ = self.bullets.remove(&bullet_id);
        }

        let mut rng = thread_rng();
        for player_id in destroyed_players {
            let (new_x, new_y) = self.random_free_spot(&mut rng);
            let dead_player = self.players.get_mut(&player_id).unwrap();
            dead_player.x = new_x;
            dead_player.y = new_y;
        }
    }

    /// Send the current state to each client.
    pub fn send_state_updates(&self) {
        let value = self.serialize();

        for (_, client) in &self.clients {
            // Always ignore if the send fails.
            // We will eventually get a disconnect WebSocketMessage where we will cleanly do the disconnect.
            let _ = client.send(value.clone());
        }
    }

    /// Process a web socket event.
    fn process_websocket_event(&mut self, message: WebSocketEvent) {
        match message {
            WebSocketEvent::ClientCreated { client } => {
                let welcome_message = message::Message::Welcome {
                    id: client.id,
                    speed: 0.0,
                    size: PLAYER_RADIUS,
                    bullet_speed: 0.0,
                    bullet_size: BULLET_RADIUS,
                };

                let _ = client.send(welcome_message.to_string());
                let _ = client.send(self.serialize());

                let (x, y) = self.random_free_spot(&mut thread_rng());
                let _ = self.players
                            .insert(client.id, message::Player::not_moving(client.id, x, y));

                let _ = self.clients.insert(client.id, client);
            }
            WebSocketEvent::ClientClosed { client_id } => {
                let _ = self.players.remove(&client_id);
                let _ = self.clients.remove(&client_id);
            }
            WebSocketEvent::ClientMessage { client_id, message } => {
                self.process_client_message(client_id, message);
            }
        }
    }

    /// Serialize the entire game state into one json string.
    fn serialize(&self) -> String {
        let players: Vec<_> = self.players
                                  .values()
                                  .cloned()
                                  .collect();
        let bullets: Vec<_> = self.bullets
                                  .values()
                                  .cloned()
                                  .collect();
        let state = message::Message::WorldState {
            player_count: players.len() as u32,
            alive_players: players,
            alive_bullets: bullets,
        };
        state.to_string()
    }

    /// Process a simple string message from the client.
    fn process_client_message(&mut self, client_id: u32, message: message::Message) {
        match message {
            message::Message::StartMoving { move_x, move_y } => {
                let player = self.players.get_mut(&client_id).unwrap();
                player.move_x = Some(move_x);
                player.move_y = Some(move_y);
            }
            message::Message::StopMoving => {
                let player = self.players.get_mut(&client_id).unwrap();
                player.move_x = None;
                player.move_y = None;
            }
            message::Message::Fire { move_x, move_y } => {
                let player = self.players.get(&client_id).unwrap();

                // Have to move the bullet out of the way of the player to avoid an instant collision.
                let start_x = player.x + move_x * (BULLET_RADIUS + PLAYER_RADIUS + 1.0);
                let start_y = player.y + move_y * (BULLET_RADIUS + PLAYER_RADIUS + 1.0);

                let _ = self.bullets.insert(self.next_bullet_id,
                                            message::Bullet::moving(self.next_bullet_id,
                                                                    start_x,
                                                                    start_y,
                                                                    move_x,
                                                                    move_y));

                self.next_bullet_id += 1;
            }
            _ => panic!("Unprocessed message! {}", message.to_string()),
        }
    }

    fn random_free_spot<R: Rng>(&self, rng: &mut R) -> (f32, f32) {
        static MAX_ITERATIONS: u32 = 100;

        for _ in 1..MAX_ITERATIONS {
            let x: f32 = rng.gen_range(0.0, MAP_WIDTH);
            let y: f32 = rng.gen_range(0.0, MAP_HEIGHT);

            let mut collides = false;

            for (_, player) in &self.players {
                if distance_between(x, y, player.x, player.y) < 2.0 * PLAYER_RADIUS {
                    collides = true;
                    break;
                }
            }

            for (_, bullet) in &self.bullets {
                if distance_between(x, y, bullet.x, bullet.y) < PLAYER_RADIUS + BULLET_RADIUS {
                    collides = true;
                    break;
                }
            }

            if !collides {
                return (x, y);
            }
        }
        println!("Failed to find a random empty spot for player after {} iterations", MAX_ITERATIONS);

        (rng.gen_range(0.0, MAP_WIDTH), rng.gen_range(0.0, MAP_HEIGHT))
    }
}
<commit_msg>Implement collisions<commit_after>//! The state of the game itself.

use message;

use std::collections::HashMap;
use std::sync::mpsc;

use math::distance_between;
use rand::{thread_rng, Rng};

use self::super::Client;
use self::super::WebSocketEvent;

static BULLET_RADIUS: f32 = 5.0;
static PLAYER_RADIUS: f32 = 10.0;
static MAP_WIDTH: f32 = 500.0;
static MAP_HEIGHT: f32 = 500.0;

/// The `GameState` contains the whole state of the game.
///
/// It consists of both players, and all the clients which are currently connected.
#[derive(Debug)]
pub struct GameState {
    players: HashMap<u32, message::Player>,
    bullets: HashMap<u32, message::Bullet>,
    clients: HashMap<u32, Client>,
    next_bullet_id: u32,
}

impl GameState {
    /// Create a new game state.
    pub fn new() -> GameState {
        GameState {
            players: HashMap::new(),
            bullets: HashMap::new(),
            clients: HashMap::new(),
            next_bullet_id: 0,
        }
    }

    /// Tries to process every available websocket event without blocking.
    pub fn process_websocket_events(&mut self, game_messages: &mpsc::Receiver<WebSocketEvent>) {
        loop {
            match game_messages.try_recv() {
                Ok(message) => self.process_websocket_event(message),
                Err(mpsc::TryRecvError::Empty) => return,
                Err(mpsc::TryRecvError::Disconnected) => panic!("Now I am disconnected?"),
            }
        }
    }

    /// Updates the game state in one tick.
    pub fn process_game_update(&mut self) {
        // Do a normal position update
        let player_ids: Vec<_> = self.players.keys().map(|i| *i).collect();
        for cur_player_id in &player_ids {
            {
                let cur_player = self.players.get(cur_player_id).unwrap();
                match (cur_player.move_x, cur_player.move_y) {
                    (None, None) => continue,
                    (Some(move_x), Some(move_y)) => {
                        let mut collides = false;
                        for cmp_player_id in &player_ids {
                            if cmp_player_id != cur_player_id {
                                let cmp_player = self.players.get(cmp_player_id).unwrap();
                                if distance_between(cur_player.x + move_x,
                                                    cur_player.y + move_y,
                                                    cmp_player.x,
                                                    cmp_player.y) <
                                   2.0 * PLAYER_RADIUS {
                                    collides = true;
                                    break;
                                }
                            }
                        }
                        if collides {
                            continue;
                        }
                    }
                    _ => panic!("Invariant not met: player moves only in one direction"),
                }
            }

            let mut player = self.players.get_mut(cur_player_id).unwrap();
            player.x = (player.x + player.move_x.unwrap_or(0.0))
                           .max(PLAYER_RADIUS)
                           .min(MAP_WIDTH - PLAYER_RADIUS);
            player.y = (player.y + player.move_y.unwrap_or(0.0))
                           .max(PLAYER_RADIUS)
                           .min(MAP_HEIGHT - PLAYER_RADIUS);
        }

        let mut destroyed_bullets = Vec::new();
        let mut destroyed_players = Vec::new();

        for (_, bullet) in &mut self.bullets {
            bullet.x += bullet.move_x.unwrap_or(0.0);
            bullet.y += bullet.move_y.unwrap_or(0.0);

            if bullet.x < 0.0 || bullet.x > MAP_WIDTH || bullet.y < 0.0 || bullet.y > MAP_HEIGHT {
                destroyed_bullets.push(bullet.id);
            }
        }

        // Check for collisions
        for (_, bullet) in &mut self.bullets {
            for (_, player) in &mut self.players {
                if distance_between(bullet.x, bullet.y, player.x, player.y) <
                   BULLET_RADIUS + PLAYER_RADIUS {
                    destroyed_bullets.push(bullet.id);
                    destroyed_players.push(player.id);
                }
            }
        }

        // Process destroy requests
        for bullet_id in destroyed_bullets {
            let _ = self.bullets.remove(&bullet_id);
        }

        let mut rng = thread_rng();
        for player_id in destroyed_players {
            let (new_x, new_y) = self.random_free_spot(&mut rng);
            let dead_player = self.players.get_mut(&player_id).unwrap();
            dead_player.x = new_x;
            dead_player.y = new_y;
        }
    }

    /// Send the current state to each client.
    pub fn send_state_updates(&self) {
        let value = self.serialize();

        for (_, client) in &self.clients {
            // Always ignore if the send fails.
            // We will eventually get a disconnect WebSocketMessage where we will cleanly do the disconnect.
            let _ = client.send(value.clone());
        }
    }

    /// Process a web socket event.
    fn process_websocket_event(&mut self, message: WebSocketEvent) {
        match message {
            WebSocketEvent::ClientCreated { client } => {
                let welcome_message = message::Message::Welcome {
                    id: client.id,
                    speed: 0.0,
                    size: PLAYER_RADIUS,
                    bullet_speed: 0.0,
                    bullet_size: BULLET_RADIUS,
                };

                let _ = client.send(welcome_message.to_string());
                let _ = client.send(self.serialize());

                let (x, y) = self.random_free_spot(&mut thread_rng());
                let _ = self.players
                            .insert(client.id, message::Player::not_moving(client.id, x, y));

                let _ = self.clients.insert(client.id, client);
            }
            WebSocketEvent::ClientClosed { client_id } => {
                let _ = self.players.remove(&client_id);
                let _ = self.clients.remove(&client_id);
            }
            WebSocketEvent::ClientMessage { client_id, message } => {
                self.process_client_message(client_id, message);
            }
        }
    }

    /// Serialize the entire game state into one json string.
    fn serialize(&self) -> String {
        let players: Vec<_> = self.players
                                  .values()
                                  .cloned()
                                  .collect();
        let bullets: Vec<_> = self.bullets
                                  .values()
                                  .cloned()
                                  .collect();
        let state = message::Message::WorldState {
            player_count: players.len() as u32,
            alive_players: players,
            alive_bullets: bullets,
        };
        state.to_string()
    }

    /// Process a simple string message from the client.
    fn process_client_message(&mut self, client_id: u32, message: message::Message) {
        match message {
            message::Message::StartMoving { move_x, move_y } => {
                let player = self.players.get_mut(&client_id).unwrap();
                player.move_x = Some(move_x);
                player.move_y = Some(move_y);
            }
            message::Message::StopMoving => {
                let player = self.players.get_mut(&client_id).unwrap();
                player.move_x = None;
                player.move_y = None;
            }
            message::Message::Fire { move_x, move_y } => {
                let player = self.players.get(&client_id).unwrap();

                // Have to move the bullet out of the way of the player to avoid an instant collision.
                let start_x = player.x + move_x * (BULLET_RADIUS + PLAYER_RADIUS + 1.0);
                let start_y = player.y + move_y * (BULLET_RADIUS + PLAYER_RADIUS + 1.0);

                let _ = self.bullets.insert(self.next_bullet_id,
                                            message::Bullet::moving(self.next_bullet_id,
                                                                    start_x,
                                                                    start_y,
                                                                    move_x,
                                                                    move_y));

                self.next_bullet_id += 1;
            }
            _ => panic!("Unprocessed message! {}", message.to_string()),
        }
    }

    fn random_free_spot<R: Rng>(&self, rng: &mut R) -> (f32, f32) {
        static MAX_ITERATIONS: u32 = 100;

        let min_vial_x = PLAYER_RADIUS;
        let min_vial_y = PLAYER_RADIUS;
        let max_vial_x = MAP_WIDTH - PLAYER_RADIUS;
        let max_vial_y = MAP_HEIGHT - PLAYER_RADIUS;

        for _ in 1..MAX_ITERATIONS {
            let x: f32 = rng.gen_range(min_vial_x, max_vial_x);
            let y: f32 = rng.gen_range(min_vial_y, max_vial_y);

            let mut collides = false;

            for (_, player) in &self.players {
                if distance_between(x, y, player.x, player.y) < 2.0 * PLAYER_RADIUS {
                    collides = true;
                    break;
                }
            }

            for (_, bullet) in &self.bullets {
                if distance_between(x, y, bullet.x, bullet.y) < PLAYER_RADIUS + BULLET_RADIUS {
                    collides = true;
                    break;
                }
            }

            if !collides {
                return (x, y);
            }
        }
        println!("Failed to find a random empty spot for player after {} iterations",
                 MAX_ITERATIONS);

        (rng.gen_range(0.0, MAP_WIDTH), rng.gen_range(0.0, MAP_HEIGHT))
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::rc::{Rc, Weak};
use mio::{Event, PollOpt, Ready, Token};
use mio::net::TcpStream;

use super::client::Client;
use super::connection::{self, Connection, ConnectionId};
use super::packetizer::Packetizer;
use super::stream_buffer::StreamBuffer;

const TAG: &'static str = "TCPConnection";

enum TCPState {
    SynSent,
    SynReceived,
    Established,
    CloseWait,
    LastAck,
}

struct TCPConnection {
    id: ConnectionId,
    client: Weak<RefCell<Client>>,
    stream: TcpStream,
    token: Token,
    client_to_network: StreamBuffer,
    network_to_client: Packetizer,
    closed: bool,
    state: TCPState,
    syn_sequence_number: u32,
    sequence_number: u32,
    acknowledgement_number: u32,
    their_acknowledgement_numbe: u32,
    client_window: u16,
    remote_closed: bool,
}
<commit_msg>Introduce TCPConnection<commit_after>use std::cell::RefCell;
use std::io;
use std::net::{Ipv4Addr, SocketAddr};
use std::rc::{Rc, Weak};
use mio::{Event, PollOpt, Ready, Token};
use mio::net::TcpStream;

use super::client::Client;
use super::connection::{self, Connection, ConnectionId};
use super::ipv4_packet::{IPv4Packet, MAX_PACKET_LENGTH};
use super::packetizer::Packetizer;
use super::selector::Selector;
use super::stream_buffer::StreamBuffer;
use super::transport_header::TransportHeader;

const TAG: &'static str = "TCPConnection";

enum TCPState {
    SynSent,
    SynReceived,
    Established,
    CloseWait,
    LastAck,
}

struct TCPConnection {
    id: ConnectionId,
    client: Weak<RefCell<Client>>,
    stream: TcpStream,
    token: Token,
    client_to_network: StreamBuffer,
    network_to_client: Packetizer,
    closed: bool,
    state: TCPState,
    syn_sequence_number: u32,
    sequence_number: u32,
    acknowledgement_number: u32,
    their_acknowledgement_numbe: u32,
    client_window: u16,
    remote_closed: bool,
}

impl TCPConnection {
/*    pub fn new(selector: &mut Selector, id: ConnectionId, client: Weak<RefCell<Client>>, reference_packet: &IPv4Packet) -> io::Result<Rc<RefCell<Self>>> {
        let stream = TCPConnection::create_stream(&id)?;
        let raw = reference_packet.raw();
        let ipv4_header = reference_packet.ipv4_header().clone();
        let transport_header = reference_packet.transport_header().as_ref().unwrap().clone();
        if let TransportHeader::TCP(ref mut tcp_header) = transport_header {
            tcp_header.shrink_options(raw);
        }
        Err()
    }

    fn create_stream(id: &ConnectionId) -> io::Result<TcpStream> {
        let rewritten_destination = connection::rewritten_destination(id.destination_ip(), id.destination_port()).into();
        TcpStream::connect(&rewritten_destination)
    }*/
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate pod_typeinfo;

use std::mem;

use pod_typeinfo::Type::*;
use pod_typeinfo::{Type, TypeInfo, Field};

#[test]
fn test_scalar_types() {
    fn check_scalar_type<T: TypeInfo>(ty: Type) {
        assert_eq!(<T as TypeInfo>::type_info(), ty);
        assert_eq!(ty.size(), mem::size_of::<T>());
        assert!(ty.is_scalar() && !ty.is_array() && !ty.is_compound());
    }

    check_scalar_type::<i8>(Int8);
    check_scalar_type::<i16>(Int16);
    check_scalar_type::<i32>(Int32);
    check_scalar_type::<i64>(Int64);
    check_scalar_type::<u8>(UInt8);
    check_scalar_type::<u16>(UInt16);
    check_scalar_type::<u32>(UInt32);
    check_scalar_type::<u64>(UInt64);
    check_scalar_type::<isize>(ISize);
    check_scalar_type::<usize>(USize);
    check_scalar_type::<f32>(Float32);
    check_scalar_type::<f64>(Float64);
    check_scalar_type::<bool>(Bool);
    check_scalar_type::<char>(Char);
}

#[test]
fn test_array_types() {
    let ty = <[u16; 42] as TypeInfo>::type_info();
    assert_eq!(ty, Array(Box::new(UInt16), 42));
    assert_eq!(ty.size(), 2 * 42);
    assert!(ty.is_array() && !ty.is_scalar() && !ty.is_compound());

    let ty = <[[i8; 2]; 3] as TypeInfo>::type_info();
    assert_eq!(ty, Array(Box::new(Array(Box::new(Int8), 2)), 3));
    assert_eq!(ty.size(), 1 * 2 * 3);
    assert!(ty.is_array() && !ty.is_scalar() && !ty.is_compound());
}

#[test]
fn test_compound_types() {
    def![struct X { a: i32, }];
    let ty = X::type_info();
    assert_eq!(ty, Compound(vec![
        Field::new(&Int32, "a", 0)
    ], mem::size_of::<X>()));
    assert_eq!(ty.size(), mem::size_of::<X>());

    def![struct Y { a: u64, x: [X; 2] }];
    let ty = Y::type_info();
    assert_eq!(ty, Compound(vec![
        Field::new(&UInt64, "a", 0),
        Field::new(&Array(Box::new(X::type_info()), 2), "x", 8),
    ], mem::size_of::<Y>()));
    assert_eq!(ty.size(), mem::size_of::<Y>());
}

#[test]
fn test_compound_copy_clone() {
    def![struct X { a: char }];
    let x = X { a: '0' };
    let y = x;
    assert_eq!(x.a, y.a);
    assert_eq!(x.clone().a, y.clone().a);
}

#[test]
fn test_struct_attributes() {
    def![struct X { a: i8, b: u64 }];
    def![#[repr(packed)] struct Y { a: i8, b: u64 }];
    assert!(X::type_info().size() > Y::type_info().size());
}

#[cfg(test)]
mod module {
    def! {
        pub struct A {
            x: i32,
            y: i32
        }
    }

    def! {
        pub struct B {
            pub x: i32,
            pub y: i32
        }
    }
}

#[test]
#[allow(unused_variables, unused_imports)]
fn test_pub_structs_fields() {
    use module::{A, B};
    let b = B { x: 1, y: 2 };
}
<commit_msg>Add tests for multiple compound type definitions, plus tests for is_*<commit_after>#[macro_use]
extern crate pod_typeinfo;

use std::mem;

use pod_typeinfo::Type::*;
use pod_typeinfo::{Type, TypeInfo, Field};

#[test]
fn test_scalar_types() {
    fn check_scalar_type<T: TypeInfo>(ty: Type) {
        assert_eq!(<T as TypeInfo>::type_info(), ty);
        assert_eq!(ty.size(), mem::size_of::<T>());
        assert!(ty.is_scalar() && !ty.is_array() && !ty.is_compound());
    }

    check_scalar_type::<i8>(Int8);
    check_scalar_type::<i16>(Int16);
    check_scalar_type::<i32>(Int32);
    check_scalar_type::<i64>(Int64);
    check_scalar_type::<u8>(UInt8);
    check_scalar_type::<u16>(UInt16);
    check_scalar_type::<u32>(UInt32);
    check_scalar_type::<u64>(UInt64);
    check_scalar_type::<isize>(ISize);
    check_scalar_type::<usize>(USize);
    check_scalar_type::<f32>(Float32);
    check_scalar_type::<f64>(Float64);
    check_scalar_type::<bool>(Bool);
    check_scalar_type::<char>(Char);
}

#[test]
fn test_array_types() {
    let ty = <[u16; 42] as TypeInfo>::type_info();
    assert_eq!(ty, Array(Box::new(UInt16), 42));
    assert_eq!(ty.size(), 2 * 42);
    assert!(ty.is_array() && !ty.is_scalar() && !ty.is_compound());

    let ty = <[[i8; 2]; 3] as TypeInfo>::type_info();
    assert_eq!(ty, Array(Box::new(Array(Box::new(Int8), 2)), 3));
    assert_eq!(ty.size(), 1 * 2 * 3);
    assert!(ty.is_array() && !ty.is_scalar() && !ty.is_compound());
}

#[test]
fn test_compound_types() {
    def![struct X { a: i32, }];
    let ty = X::type_info();
    assert_eq!(ty, Compound(vec![
        Field::new(&Int32, "a", 0)
    ], mem::size_of::<X>()));
    assert_eq!(ty.size(), mem::size_of::<X>());
    assert!(ty.is_compound() && !ty.is_scalar() && !ty.is_array());

    def![struct Y { a: u64, x: [X; 2] }];
    let ty = Y::type_info();
    assert_eq!(ty, Compound(vec![
        Field::new(&UInt64, "a", 0),
        Field::new(&Array(Box::new(X::type_info()), 2), "x", 8),
    ], mem::size_of::<Y>()));
    assert_eq!(ty.size(), mem::size_of::<Y>());
    assert!(ty.is_compound() && !ty.is_scalar() && !ty.is_array());
}

#[test]
fn test_compound_copy_clone() {
    def![struct X { a: char }];
    let x = X { a: '0' };
    let y = x;
    assert_eq!(x.a, y.a);
    assert_eq!(x.clone().a, y.clone().a);
}

#[test]
fn test_struct_attributes() {
    def![struct X { a: i8, b: u64 }];
    def![#[repr(packed)] struct Y { a: i8, b: u64 }];
    assert!(X::type_info().size() > Y::type_info().size());
}

#[cfg(test)]
mod module {
    def! {
        pub struct A {
            x: i32,
            y: i32
        }
    }
    def! {
        pub struct B {
            pub x: i32,
            pub y: i32
        }
    }

    pub mod multiple {
        def! {
            struct C { x: i32 }
            struct D { x: i32 }
        }
        def! {
            pub struct E { x: i32 }
            pub struct F { x: i32 }
        }
        def! {
            pub struct G { pub x: i32 }
            pub struct H { pub x: i32 }
        }
    }
}

#[test]
#[allow(unused_variables, unused_imports)]
fn test_pub_structs_fields() {
    use module::{A, B};
    let b = B { x: 1, y: 2 };
    use module::multiple::{E, F, G, H};
}
<|endoftext|>


<commit_before>#![crate_type = "lib"]
#![feature(globs)]
#![allow(non_camel_case_types)]

#![desc = "protobuf implementation for rust"]
#![license = "BSD"]

extern crate collections;

pub use unknown::UnknownFields;
pub use unknown::UnknownValues;
pub use unknown::UnknownValue;
pub use unknown::UnknownValueRef;
pub use unknown::UnknownValuesIter;
pub use unknown::UnknownFieldIter;
pub use repeated::RepeatedField;
pub use singular::SingularField;
pub use singular::SingularPtrField;
pub use clear::Clear;
pub use core::Message;
pub use core::ProtobufEnum;
pub use core::parse_from_bytes;
pub use core::parse_from_reader;
pub use core::parse_length_delimited_from;
pub use core::parse_length_delimited_from_bytes;
pub use stream::CodedInputStream;
pub use stream::CodedOutputStream;
pub use stream::wire_format;
pub use error::ProtobufResult;
pub use error::ProtobufError;

pub mod core;
pub mod rt;
pub mod lazy;
pub mod descriptor;
pub mod codegen;
pub mod repeated;
pub mod singular;
pub mod clear;
pub mod reflect;
pub mod text_format;
pub mod stream;
pub mod error;

// used by test
pub mod hex;

mod misc;
mod zigzag;
mod maybe_owned_slice;
mod paginate;
mod unknown;
mod strx;
mod descriptorx;

// so `use protobuf::*` could work in descriptor mod
mod protobuf {
    pub use descriptor;
    pub use codegen;
    pub use reflect;
    pub use core::*;
    pub use error::*;
    pub use stream::*;
    pub use rt;
    pub use lazy;
    pub use unknown::UnknownFields;
    pub use unknown::UnknownValues;
    pub use unknown::UnknownValue;
    pub use unknown::UnknownValueRef;
    pub use unknown::UnknownValuesIter;
    pub use unknown::UnknownFieldIter;
    pub use repeated::RepeatedField;
    pub use singular::SingularField;
    pub use singular::SingularPtrField;
    pub use clear::Clear;
}
<commit_msg>Fix warnings<commit_after>#![crate_type = "lib"]
#![feature(globs)]
#![allow(non_camel_case_types)]

extern crate collections;

pub use unknown::UnknownFields;
pub use unknown::UnknownValues;
pub use unknown::UnknownValue;
pub use unknown::UnknownValueRef;
pub use unknown::UnknownValuesIter;
pub use unknown::UnknownFieldIter;
pub use repeated::RepeatedField;
pub use singular::SingularField;
pub use singular::SingularPtrField;
pub use clear::Clear;
pub use core::Message;
pub use core::ProtobufEnum;
pub use core::parse_from_bytes;
pub use core::parse_from_reader;
pub use core::parse_length_delimited_from;
pub use core::parse_length_delimited_from_bytes;
pub use stream::CodedInputStream;
pub use stream::CodedOutputStream;
pub use stream::wire_format;
pub use error::ProtobufResult;
pub use error::ProtobufError;

pub mod core;
pub mod rt;
pub mod lazy;
pub mod descriptor;
pub mod codegen;
pub mod repeated;
pub mod singular;
pub mod clear;
pub mod reflect;
pub mod text_format;
pub mod stream;
pub mod error;

// used by test
pub mod hex;

mod misc;
mod zigzag;
mod maybe_owned_slice;
mod paginate;
mod unknown;
mod strx;
mod descriptorx;

// so `use protobuf::*` could work in descriptor mod
mod protobuf {
    pub use descriptor;
    pub use codegen;
    pub use reflect;
    pub use core::*;
    pub use error::*;
    pub use stream::*;
    pub use rt;
    pub use lazy;
    pub use unknown::UnknownFields;
    pub use unknown::UnknownValues;
    pub use unknown::UnknownValue;
    pub use unknown::UnknownValueRef;
    pub use unknown::UnknownValuesIter;
    pub use unknown::UnknownFieldIter;
    pub use repeated::RepeatedField;
    pub use singular::SingularField;
    pub use singular::SingularPtrField;
    pub use clear::Clear;
}
<|endoftext|>


<commit_before>use spin::Mutex;
use super::{Address, Allocator, AllocErr, Layout, AllocResult};

extern crate params;

use self::params::InitParams;

use core::ops::{Deref, DerefMut};
use core::ptr::Unique;
#[cfg(feature = "bump_ptr")]
use bump_ptr::BumpPtr;

#[cfg(feature = "buddy")]
use buddy::Heap as BuddyHeap;

pub enum Tier<'a> {
    Uninitialized
    , #[cfg(feature = "bump_ptr")]
      Bump(BumpPtr)
    , #[cfg(feature = "buddy")]
      Buddy(BuddyHeap<'a>)
}
#[cfg(all(feature = "bump_ptr", feature="buddy"))]
impl Deref for Tier<'static> {
    type Target = Allocator + 'static ;
    fn deref(&self) -> &Self::Target{
        match self {
            &Tier::Bump(ref alloc) => alloc
          , &Tier::Buddy(ref alloc) => alloc
          , _ => panic!("no allocator!")
        }
    }
}

#[cfg(all(feature = "bump_ptr", feature = "buddy"))]
unsafe impl<'a> Allocator for Tier<'a> {
    #[inline(always)]
    unsafe fn alloc(&mut self, layout: Layout) -> AllocResult<Address> {
        match *self {
            Tier::Bump(ref mut alloc) => alloc.alloc(layout)
          , Tier::Buddy(ref mut alloc) => alloc.alloc(layout)
          , _ => Err(AllocErr::Unsupported {
                    details: "System allocator uninitialized!"
                })
        }
    }

    #[inline(always)]
    unsafe fn dealloc(&mut self, ptr: Address, layout: Layout) {
        match *self {
            Tier::Bump(ref mut alloc) => alloc.dealloc(ptr, layout)
          , Tier::Buddy(ref mut alloc) => alloc.dealloc(ptr, layout)
          , _ =>  {
              // just leak it? not sure if we should panic here...
          }
        }
    }

}

pub struct SystemAllocator(Mutex<Tier<'static>>);

impl SystemAllocator {

    /// Borrow a raw allocation from the system allocator
    ///
    /// The borrowed allocation handle will automagically deallocate the
    /// allocation at the end of its lifetime
    pub fn borrow_ptr<'alloc>(&'alloc self, layout: Layout)
                      -> AllocResult<BorrowedPtr<'alloc, Tier<'static>>> {
        let ptr = unsafe { self.0.lock().alloc(layout.clone())? };
        Ok(BorrowedPtr { ptr: unsafe { Unique::new(ptr) }
                       , layout: layout
                       , allocator: &self.0 })
    }

    /// Borrow an object allocation from the system allocator.
    ///
    /// The borrowed allocation handle will automagically deallocate the
    /// allocated object at the end of its lifetime
    pub fn borrow<'alloc, T>(&'alloc self)
                        -> AllocResult<Borrowed<'alloc, Tier<'static>, T>> {
        let value = unsafe { self.0.lock().alloc_one::<T>()? };
        Ok(Borrowed { value: value
                    , allocator: &self.0 })
    }
}

/// A borrowed handle on a heap allocation with a specified lifetime.
///
/// This automatically deallocates the allocated object when the borrow's
/// lifetime ends. It also ensures that the borrow only lives as long as the
/// allocator that provided it, and that the borrow is dropped if the allocator
/// is dropped.
pub struct BorrowedPtr<'a, A>
where A: Allocator
    , A: 'a {
    ptr: Unique<u8>
  , layout: Layout
  , allocator: &'a Mutex
}

impl<'a, A> Deref for BorrowedPtr<'a, A>
where A: Allocator
    , A: 'a {
    type Target = *mut u8;
    fn deref(&self) ->  &Self::Target { &(*self.ptr) }
}
//
// impl<'a, A> ops::DerefMut for BorrowedPtr<'a, A>
// where A: Allocator
//     , A: 'a {
//     fn deref_mut(&mut self) ->  &mut Self::Target { &mut self.frame }
// }

impl<'a, A> Drop for BorrowedPtr<'a, A>
where A: Allocator
    , A: 'a {
    fn drop(&mut self) {
        unsafe {
            self.allocator.lock().dealloc(*self.ptr, self.layout.clone())
        }
    }
}

/// A borrowed handle on a heap allocation with a specified lifetime.
///
/// This automatically deallocates the allocated object when the borrow's
/// lifetime ends. It also ensures that the borrow only lives as long as the
/// allocator that provided it, and that the borrow is dropped if the allocator
/// is dropped.
pub struct Borrowed<'a, A, T>
where A: Allocator
    , A: 'a {
    value: Unique<T>
  , allocator: &'a Mutex
}

impl<'a, A, T> Deref for Borrowed<'a, A, T>
where A: Allocator
    , A: 'a {
    type Target = T;
    fn deref(&self) ->  &Self::Target { unsafe { self.value.get() } }
}

impl<'a, A, T> DerefMut for Borrowed<'a, A, T>
where A: Allocator
    , A: 'a {
    fn deref_mut(&mut self) ->  &mut Self::Target {
        unsafe { self.value.get_mut() }
    }
}

impl<'a, A, T> Drop for Borrowed<'a, A, T>
where A: Allocator
    , A: 'a {
    fn drop(&mut self) {
        unsafe {
            self.allocator.lock()
                .dealloc( *self.value as *mut u8
                        , Layout::for_value(self.value.get()))
        }
    }
}
<commit_msg>[alloc] slightly more readable lifetime parameters<commit_after>use spin::Mutex;
use super::{Address, Allocator, AllocErr, Layout, AllocResult};

extern crate params;

use self::params::InitParams;

use core::ops::{Deref, DerefMut};
use core::ptr::Unique;
#[cfg(feature = "bump_ptr")]
use bump_ptr::BumpPtr;

#[cfg(feature = "buddy")]
use buddy::Heap as BuddyHeap;

pub enum Tier<'a> {
    Uninitialized
    , #[cfg(feature = "bump_ptr")]
      Bump(BumpPtr)
    , #[cfg(feature = "buddy")]
      Buddy(BuddyHeap<'a>)
}
#[cfg(all(feature = "bump_ptr", feature="buddy"))]
impl Deref for Tier<'static> {
    type Target = Allocator + 'static ;
    fn deref(&self) -> &Self::Target{
        match self {
            &Tier::Bump(ref alloc) => alloc
          , &Tier::Buddy(ref alloc) => alloc
          , _ => panic!("no allocator!")
        }
    }
}

#[cfg(all(feature = "bump_ptr", feature = "buddy"))]
unsafe impl<'a> Allocator for Tier<'a> {
    #[inline(always)]
    unsafe fn alloc(&mut self, layout: Layout) -> AllocResult<Address> {
        match *self {
            Tier::Bump(ref mut alloc) => alloc.alloc(layout)
          , Tier::Buddy(ref mut alloc) => alloc.alloc(layout)
          , _ => Err(AllocErr::Unsupported {
                    details: "System allocator uninitialized!"
                })
        }
    }

    #[inline(always)]
    unsafe fn dealloc(&mut self, ptr: Address, layout: Layout) {
        match *self {
            Tier::Bump(ref mut alloc) => alloc.dealloc(ptr, layout)
          , Tier::Buddy(ref mut alloc) => alloc.dealloc(ptr, layout)
          , _ =>  {
              // just leak it? not sure if we should panic here...
          }
        }
    }

}

pub struct SystemAllocator(Mutex<Tier<'static>>);

impl SystemAllocator {

    /// Borrow a raw allocation from the system allocator
    ///
    /// The borrowed allocation handle will automagically deallocate the
    /// allocation at the end of its lifetime
    pub fn borrow_ptr<'alloc>(&'alloc self, layout: Layout)
                      -> AllocResult<BorrowedPtr<'alloc, Tier<'static>>> {
        let ptr = unsafe { self.0.lock().alloc(layout.clone())? };
        Ok(BorrowedPtr { ptr: unsafe { Unique::new(ptr) }
                       , layout: layout
                       , allocator: &self.0 })
    }

    /// Borrow an object allocation from the system allocator.
    ///
    /// The borrowed allocation handle will automagically deallocate the
    /// allocated object at the end of its lifetime
    pub fn borrow<'alloc, T>(&'alloc self)
                        -> AllocResult<Borrowed<'alloc, Tier<'static>, T>> {
        let value = unsafe { self.0.lock().alloc_one::<T>()? };
        Ok(Borrowed { value: value
                    , allocator: &self.0 })
    }
}

/// A borrowed handle on a heap allocation with a specified lifetime.
///
/// This automatically deallocates the allocated object when the borrow's
/// lifetime ends. It also ensures that the borrow only lives as long as the
/// allocator that provided it, and that the borrow is dropped if the allocator
/// is dropped.
pub struct BorrowedPtr<'alloc, A>
where A: Allocator
    , A: 'alloc {
    ptr: Unique<u8>
  , layout: Layout
  , allocator: &'alloc Mutex
}

impl<'alloc, A> Deref for BorrowedPtr<'alloc, A>
where A: Allocator
    , A: 'alloc {
    type Target = *mut u8;
    fn deref(&self) ->  &Self::Target { &(*self.ptr) }
}
//
// impl<'alloc, A> ops::DerefMut for BorrowedPtr<'alloc, A>
// where A: Allocator
//     , A: 'alloc {
//     fn deref_mut(&mut self) ->  &mut Self::Target { &mut self.frame }
// }

impl<'alloc, A> Drop for BorrowedPtr<'alloc, A>
where A: Allocator
    , A: 'alloc {
    fn drop(&mut self) {
        unsafe {
            self.allocator.lock().dealloc(*self.ptr, self.layout.clone())
        }
    }
}

/// A borrowed handle on a heap allocation with a specified lifetime.
///
/// This automatically deallocates the allocated object when the borrow's
/// lifetime ends. It also ensures that the borrow only lives as long as the
/// allocator that provided it, and that the borrow is dropped if the allocator
/// is dropped.
pub struct Borrowed<'alloc, A, T>
where A: Allocator
    , A: 'alloc {
    value: Unique<T>
  , allocator: &'alloc Mutex
}

impl<'alloc, A, T> Deref for Borrowed<'alloc, A, T>
where A: Allocator
    , A: 'alloc {
    type Target = T;
    fn deref(&self) ->  &Self::Target { unsafe { self.value.get() } }
}

impl<'alloc, A, T> DerefMut for Borrowed<'alloc, A, T>
where A: Allocator
    , A: 'alloc {
    fn deref_mut(&mut self) ->  &mut Self::Target {
        unsafe { self.value.get_mut() }
    }
}

impl<'alloc, A, T> Drop for Borrowed<'alloc, A, T>
where A: Allocator
    , A: 'alloc {
    fn drop(&mut self) {
        unsafe {
            self.allocator.lock()
                .dealloc( *self.value as *mut u8
                        , Layout::for_value(self.value.get()))
        }
    }
}
<|endoftext|>