<commit_before>use crate::iter::LoopState;
use crate::ops::Try;

/// An iterator able to yield elements from both ends.
///
/// Something that implements `DoubleEndedIterator` has one extra capability
/// over something that implements [`Iterator`]: the ability to also take
/// `Item`s from the back, as well as the front.
///
/// It is important to note that both back and forth work on the same range,
/// and do not cross: iteration is over when they meet in the middle.
///
/// In a similar fashion to the [`Iterator`] protocol, once a
/// `DoubleEndedIterator` returns `None` from a `next_back()`, calling it again
/// may or may not ever return `Some` again. `next()` and `next_back()` are
/// interchangeable for this purpose.
///
/// [`Iterator`]: trait.Iterator.html
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// let numbers = vec![1, 2, 3, 4, 5, 6];
///
/// let mut iter = numbers.iter();
///
/// assert_eq!(Some(&1), iter.next());
/// assert_eq!(Some(&6), iter.next_back());
/// assert_eq!(Some(&5), iter.next_back());
/// assert_eq!(Some(&2), iter.next());
/// assert_eq!(Some(&3), iter.next());
/// assert_eq!(Some(&4), iter.next());
/// assert_eq!(None, iter.next());
/// assert_eq!(None, iter.next_back());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait DoubleEndedIterator: Iterator {
    /// Removes and returns an element from the end of the iterator.
    ///
    /// Returns `None` when there are no more elements.
    ///
    /// The [trait-level] docs contain more details.
    ///
    /// [trait-level]: trait.DoubleEndedIterator.html
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let numbers = vec![1, 2, 3, 4, 5, 6];
    ///
    /// let mut iter = numbers.iter();
    ///
    /// assert_eq!(Some(&1), iter.next());
    /// assert_eq!(Some(&6), iter.next_back());
    /// assert_eq!(Some(&5), iter.next_back());
    /// assert_eq!(Some(&2), iter.next());
    /// assert_eq!(Some(&3), iter.next());
    /// assert_eq!(Some(&4), iter.next());
    /// assert_eq!(None, iter.next());
    /// assert_eq!(None, iter.next_back());
    /// ```
    ///
    /// # Remarks
    ///
    /// The elements yielded by `DoubleEndedIterator`'s methods may differ from
    /// the ones yielded by `Iterator`'s methods:
    ///
    /// ```
    /// let vec = vec![(1, 'a'), (1, 'b'), (1, 'c'), (2, 'a'), (2, 'b')];
    /// let uniq_by_fst_comp = || {
    ///     let mut seen = std::collections::HashSet::new();
    ///     vec.iter().copied().filter(move |x| seen.insert(x.0))
    /// };
    ///
    /// assert_eq!(uniq_by_fst_comp().last(), Some((2, 'a')));
    /// assert_eq!(uniq_by_fst_comp().next_back(), Some((2, 'b')));
    ///
    /// assert_eq!(
    ///     uniq_by_fst_comp().fold(vec![], |mut v, x| {v.push(x); v}),
    ///     vec![(1, 'a'), (2, 'a')]
    /// );
    /// assert_eq!(
    ///     uniq_by_fst_comp().rfold(vec![], |mut v, x| {v.push(x); v}),
    ///     vec![(2, 'b'), (1, 'c')]
    /// );
    /// ```
    ///
    #[stable(feature = "rust1", since = "1.0.0")]
    fn next_back(&mut self) -> Option<Self::Item>;

    /// Returns the `n`th element from the end of the iterator.
    ///
    /// This is essentially the reversed version of [`nth`]. Although like most indexing
    /// operations, the count starts from zero, so `nth_back(0)` returns the first value from
    /// the end, `nth_back(1)` the second, and so on.
    ///
    /// Note that all elements between the end and the returned element will be
    /// consumed, including the returned element. This also means that calling
    /// `nth_back(0)` multiple times on the same iterator will return different
    /// elements.
    ///
    /// `nth_back()` will return [`None`] if `n` is greater than or equal to the length of the
    /// iterator.
    ///
    /// [`None`]: ../../std/option/enum.Option.html#variant.None
    /// [`nth`]: ../../std/iter/trait.Iterator.html#method.nth
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let a = [1, 2, 3];
    /// assert_eq!(a.iter().nth_back(2), Some(&1));
    /// ```
    ///
    /// Calling `nth_back()` multiple times doesn't rewind the iterator:
    ///
    /// ```
    /// let a = [1, 2, 3];
    ///
    /// let mut iter = a.iter();
    ///
    /// assert_eq!(iter.nth_back(1), Some(&2));
    /// assert_eq!(iter.nth_back(1), None);
    /// ```
    ///
    /// Returning `None` if there are less than `n + 1` elements:
    ///
    /// ```
    /// let a = [1, 2, 3];
    /// assert_eq!(a.iter().nth_back(10), None);
    /// ```
    #[inline]
    #[stable(feature = "iter_nth_back", since = "1.37.0")]
    fn nth_back(&mut self, mut n: usize) -> Option<Self::Item> {
        for x in self.rev() {
            if n == 0 {
                return Some(x);
            }
            n -= 1;
        }
        None
    }

    /// This is the reverse version of [`try_fold()`]: it takes elements
    /// starting from the back of the iterator.
    ///
    /// [`try_fold()`]: trait.Iterator.html#method.try_fold
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let a = ["1", "2", "3"];
    /// let sum = a.iter()
    ///     .map(|&s| s.parse::<i32>())
    ///     .try_rfold(0, |acc, x| x.and_then(|y| Ok(acc + y)));
    /// assert_eq!(sum, Ok(6));
    /// ```
    ///
    /// Short-circuiting:
    ///
    /// ```
    /// let a = ["1", "rust", "3"];
    /// let mut it = a.iter();
    /// let sum = it
    ///     .by_ref()
    ///     .map(|&s| s.parse::<i32>())
    ///     .try_rfold(0, |acc, x| x.and_then(|y| Ok(acc + y)));
    /// assert!(sum.is_err());
    ///
    /// // Because it short-circuited, the remaining elements are still
    /// // available through the iterator.
    /// assert_eq!(it.next_back(), Some(&"1"));
    /// ```
    #[inline]
    #[stable(feature = "iterator_try_fold", since = "1.27.0")]
    fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
    where
        Self: Sized,
        F: FnMut(B, Self::Item) -> R,
        R: Try<Ok = B>,
    {
        let mut accum = init;
        while let Some(x) = self.next_back() {
            accum = f(accum, x)?;
        }
        Try::from_ok(accum)
    }

    /// An iterator method that reduces the iterator's elements to a single,
    /// final value, starting from the back.
    ///
    /// This is the reverse version of [`fold()`]: it takes elements starting from
    /// the back of the iterator.
    ///
    /// `rfold()` takes two arguments: an initial value, and a closure with two
    /// arguments: an 'accumulator', and an element. The closure returns the value that
    /// the accumulator should have for the next iteration.
    ///
    /// The initial value is the value the accumulator will have on the first
    /// call.
    ///
    /// After applying this closure to every element of the iterator, `rfold()`
    /// returns the accumulator.
    ///
    /// This operation is sometimes called 'reduce' or 'inject'.
    ///
    /// Folding is useful whenever you have a collection of something, and want
    /// to produce a single value from it.
    ///
    /// [`fold()`]: trait.Iterator.html#method.fold
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let a = [1, 2, 3];
    ///
    /// // the sum of all of the elements of a
    /// let sum = a.iter()
    ///            .rfold(0, |acc, &x| acc + x);
    ///
    /// assert_eq!(sum, 6);
    /// ```
    ///
    /// This example builds a string, starting with an initial value
    /// and continuing with each element from the back until the front:
    ///
    /// ```
    /// let numbers = [1, 2, 3, 4, 5];
    ///
    /// let zero = "0".to_string();
    ///
    /// let result = numbers.iter().rfold(zero, |acc, &x| {
    ///     format!("({} + {})", x, acc)
    /// });
    ///
    /// assert_eq!(result, "(1 + (2 + (3 + (4 + (5 + 0)))))");
    /// ```
    #[inline]
    #[stable(feature = "iter_rfold", since = "1.27.0")]
    fn rfold<B, F>(mut self, init: B, mut f: F) -> B
    where
        Self: Sized,
        F: FnMut(B, Self::Item) -> B,
    {
        let mut accum = init;
        while let Some(x) = self.next_back() {
            accum = f(accum, x);
        }
        accum
    }

    /// Searches for an element of an iterator from the back that satisfies a predicate.
    ///
    /// `rfind()` takes a closure that returns `true` or `false`. It applies
    /// this closure to each element of the iterator, starting at the end, and if any
    /// of them return `true`, then `rfind()` returns [`Some(element)`]. If they all return
    /// `false`, it returns [`None`].
    ///
    /// `rfind()` is short-circuiting; in other words, it will stop processing
    /// as soon as the closure returns `true`.
    ///
    /// Because `rfind()` takes a reference, and many iterators iterate over
    /// references, this leads to a possibly confusing situation where the
    /// argument is a double reference. You can see this effect in the
    /// examples below, with `&&x`.
    ///
    /// [`Some(element)`]: ../../std/option/enum.Option.html#variant.Some
    /// [`None`]: ../../std/option/enum.Option.html#variant.None
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let a = [1, 2, 3];
    ///
    /// assert_eq!(a.iter().rfind(|&&x| x == 2), Some(&2));
    ///
    /// assert_eq!(a.iter().rfind(|&&x| x == 5), None);
    /// ```
    ///
    /// Stopping at the first `true`:
    ///
    /// ```
    /// let a = [1, 2, 3];
    ///
    /// let mut iter = a.iter();
    ///
    /// assert_eq!(iter.rfind(|&&x| x == 2), Some(&2));
    ///
    /// // we can still use `iter`, as there are more elements.
    /// assert_eq!(iter.next_back(), Some(&1));
    /// ```
    #[inline]
    #[stable(feature = "iter_rfind", since = "1.27.0")]
    fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
    where
        Self: Sized,
        P: FnMut(&Self::Item) -> bool,
    {
        #[inline]
        fn check<T>(
            mut predicate: impl FnMut(&T) -> bool,
        ) -> impl FnMut((), T) -> LoopState<(), T> {
            move |(), x| {
                if predicate(&x) { LoopState::Break(x) } else { LoopState::Continue(()) }
            }
        }

        self.try_rfold((), check(predicate)).break_value()
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I {
    fn next_back(&mut self) -> Option<I::Item> {
        (**self).next_back()
    }
    fn nth_back(&mut self, n: usize) -> Option<I::Item> {
        (**self).nth_back(n)
    }
}
<commit_msg>Intra-doc for DoubleEndIterator<commit_after>use crate::iter::LoopState;
use crate::ops::Try;

/// An iterator able to yield elements from both ends.
///
/// Something that implements `DoubleEndedIterator` has one extra capability
/// over something that implements [`Iterator`]: the ability to also take
/// `Item`s from the back, as well as the front.
///
/// It is important to note that both back and forth work on the same range,
/// and do not cross: iteration is over when they meet in the middle.
///
/// In a similar fashion to the [`Iterator`] protocol, once a
/// `DoubleEndedIterator` returns `None` from a `next_back()`, calling it again
/// may or may not ever return `Some` again. `next()` and `next_back()` are
/// interchangeable for this purpose.
///
/// [`Iterator`]: trait.Iterator.html
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// let numbers = vec![1, 2, 3, 4, 5, 6];
///
/// let mut iter = numbers.iter();
///
/// assert_eq!(Some(&1), iter.next());
/// assert_eq!(Some(&6), iter.next_back());
/// assert_eq!(Some(&5), iter.next_back());
/// assert_eq!(Some(&2), iter.next());
/// assert_eq!(Some(&3), iter.next());
/// assert_eq!(Some(&4), iter.next());
/// assert_eq!(None, iter.next());
/// assert_eq!(None, iter.next_back());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait DoubleEndedIterator: Iterator {
    /// Removes and returns an element from the end of the iterator.
    ///
    /// Returns `None` when there are no more elements.
    ///
    /// The [trait-level] docs contain more details.
    ///
    /// [trait-level]: trait.DoubleEndedIterator.html
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let numbers = vec![1, 2, 3, 4, 5, 6];
    ///
    /// let mut iter = numbers.iter();
    ///
    /// assert_eq!(Some(&1), iter.next());
    /// assert_eq!(Some(&6), iter.next_back());
    /// assert_eq!(Some(&5), iter.next_back());
    /// assert_eq!(Some(&2), iter.next());
    /// assert_eq!(Some(&3), iter.next());
    /// assert_eq!(Some(&4), iter.next());
    /// assert_eq!(None, iter.next());
    /// assert_eq!(None, iter.next_back());
    /// ```
    ///
    /// # Remarks
    ///
    /// The elements yielded by `DoubleEndedIterator`'s methods may differ from
    /// the ones yielded by `Iterator`'s methods:
    ///
    /// ```
    /// let vec = vec![(1, 'a'), (1, 'b'), (1, 'c'), (2, 'a'), (2, 'b')];
    /// let uniq_by_fst_comp = || {
    ///     let mut seen = std::collections::HashSet::new();
    ///     vec.iter().copied().filter(move |x| seen.insert(x.0))
    /// };
    ///
    /// assert_eq!(uniq_by_fst_comp().last(), Some((2, 'a')));
    /// assert_eq!(uniq_by_fst_comp().next_back(), Some((2, 'b')));
    ///
    /// assert_eq!(
    ///     uniq_by_fst_comp().fold(vec![], |mut v, x| {v.push(x); v}),
    ///     vec![(1, 'a'), (2, 'a')]
    /// );
    /// assert_eq!(
    ///     uniq_by_fst_comp().rfold(vec![], |mut v, x| {v.push(x); v}),
    ///     vec![(2, 'b'), (1, 'c')]
    /// );
    /// ```
    ///
    #[stable(feature = "rust1", since = "1.0.0")]
    fn next_back(&mut self) -> Option<Self::Item>;

    /// Returns the `n`th element from the end of the iterator.
    ///
    /// This is essentially the reversed version of [`nth`]. Although like most indexing
    /// operations, the count starts from zero, so `nth_back(0)` returns the first value from
    /// the end, `nth_back(1)` the second, and so on.
    ///
    /// Note that all elements between the end and the returned element will be
    /// consumed, including the returned element. This also means that calling
    /// `nth_back(0)` multiple times on the same iterator will return different
    /// elements.
    ///
    /// `nth_back()` will return [`None`] if `n` is greater than or equal to the length of the
    /// iterator.
    ///
    /// [`nth`]: crate::iter::Iterator::nth
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let a = [1, 2, 3];
    /// assert_eq!(a.iter().nth_back(2), Some(&1));
    /// ```
    ///
    /// Calling `nth_back()` multiple times doesn't rewind the iterator:
    ///
    /// ```
    /// let a = [1, 2, 3];
    ///
    /// let mut iter = a.iter();
    ///
    /// assert_eq!(iter.nth_back(1), Some(&2));
    /// assert_eq!(iter.nth_back(1), None);
    /// ```
    ///
    /// Returning `None` if there are less than `n + 1` elements:
    ///
    /// ```
    /// let a = [1, 2, 3];
    /// assert_eq!(a.iter().nth_back(10), None);
    /// ```
    #[inline]
    #[stable(feature = "iter_nth_back", since = "1.37.0")]
    fn nth_back(&mut self, mut n: usize) -> Option<Self::Item> {
        for x in self.rev() {
            if n == 0 {
                return Some(x);
            }
            n -= 1;
        }
        None
    }

    /// This is the reverse version of [`try_fold()`]: it takes elements
    /// starting from the back of the iterator.
    ///
    /// [`try_fold()`]: trait.Iterator.html#method.try_fold
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let a = ["1", "2", "3"];
    /// let sum = a.iter()
    ///     .map(|&s| s.parse::<i32>())
    ///     .try_rfold(0, |acc, x| x.and_then(|y| Ok(acc + y)));
    /// assert_eq!(sum, Ok(6));
    /// ```
    ///
    /// Short-circuiting:
    ///
    /// ```
    /// let a = ["1", "rust", "3"];
    /// let mut it = a.iter();
    /// let sum = it
    ///     .by_ref()
    ///     .map(|&s| s.parse::<i32>())
    ///     .try_rfold(0, |acc, x| x.and_then(|y| Ok(acc + y)));
    /// assert!(sum.is_err());
    ///
    /// // Because it short-circuited, the remaining elements are still
    /// // available through the iterator.
    /// assert_eq!(it.next_back(), Some(&"1"));
    /// ```
    #[inline]
    #[stable(feature = "iterator_try_fold", since = "1.27.0")]
    fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
    where
        Self: Sized,
        F: FnMut(B, Self::Item) -> R,
        R: Try<Ok = B>,
    {
        let mut accum = init;
        while let Some(x) = self.next_back() {
            accum = f(accum, x)?;
        }
        Try::from_ok(accum)
    }

    /// An iterator method that reduces the iterator's elements to a single,
    /// final value, starting from the back.
    ///
    /// This is the reverse version of [`fold()`]: it takes elements starting from
    /// the back of the iterator.
    ///
    /// `rfold()` takes two arguments: an initial value, and a closure with two
    /// arguments: an 'accumulator', and an element. The closure returns the value that
    /// the accumulator should have for the next iteration.
    ///
    /// The initial value is the value the accumulator will have on the first
    /// call.
    ///
    /// After applying this closure to every element of the iterator, `rfold()`
    /// returns the accumulator.
    ///
    /// This operation is sometimes called 'reduce' or 'inject'.
    ///
    /// Folding is useful whenever you have a collection of something, and want
    /// to produce a single value from it.
    ///
    /// [`fold()`]: trait.Iterator.html#method.fold
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let a = [1, 2, 3];
    ///
    /// // the sum of all of the elements of a
    /// let sum = a.iter()
    ///            .rfold(0, |acc, &x| acc + x);
    ///
    /// assert_eq!(sum, 6);
    /// ```
    ///
    /// This example builds a string, starting with an initial value
    /// and continuing with each element from the back until the front:
    ///
    /// ```
    /// let numbers = [1, 2, 3, 4, 5];
    ///
    /// let zero = "0".to_string();
    ///
    /// let result = numbers.iter().rfold(zero, |acc, &x| {
    ///     format!("({} + {})", x, acc)
    /// });
    ///
    /// assert_eq!(result, "(1 + (2 + (3 + (4 + (5 + 0)))))");
    /// ```
    #[inline]
    #[stable(feature = "iter_rfold", since = "1.27.0")]
    fn rfold<B, F>(mut self, init: B, mut f: F) -> B
    where
        Self: Sized,
        F: FnMut(B, Self::Item) -> B,
    {
        let mut accum = init;
        while let Some(x) = self.next_back() {
            accum = f(accum, x);
        }
        accum
    }

    /// Searches for an element of an iterator from the back that satisfies a predicate.
    ///
    /// `rfind()` takes a closure that returns `true` or `false`. It applies
    /// this closure to each element of the iterator, starting at the end, and if any
    /// of them return `true`, then `rfind()` returns [`Some(element)`]. If they all return
    /// `false`, it returns [`None`].
    ///
    /// `rfind()` is short-circuiting; in other words, it will stop processing
    /// as soon as the closure returns `true`.
    ///
    /// Because `rfind()` takes a reference, and many iterators iterate over
    /// references, this leads to a possibly confusing situation where the
    /// argument is a double reference. You can see this effect in the
    /// examples below, with `&&x`.
    ///
    /// [`Some(element)`]: Some
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let a = [1, 2, 3];
    ///
    /// assert_eq!(a.iter().rfind(|&&x| x == 2), Some(&2));
    ///
    /// assert_eq!(a.iter().rfind(|&&x| x == 5), None);
    /// ```
    ///
    /// Stopping at the first `true`:
    ///
    /// ```
    /// let a = [1, 2, 3];
    ///
    /// let mut iter = a.iter();
    ///
    /// assert_eq!(iter.rfind(|&&x| x == 2), Some(&2));
    ///
    /// // we can still use `iter`, as there are more elements.
    /// assert_eq!(iter.next_back(), Some(&1));
    /// ```
    #[inline]
    #[stable(feature = "iter_rfind", since = "1.27.0")]
    fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
    where
        Self: Sized,
        P: FnMut(&Self::Item) -> bool,
    {
        #[inline]
        fn check<T>(
            mut predicate: impl FnMut(&T) -> bool,
        ) -> impl FnMut((), T) -> LoopState<(), T> {
            move |(), x| {
                if predicate(&x) { LoopState::Break(x) } else { LoopState::Continue(()) }
            }
        }

        self.try_rfold((), check(predicate)).break_value()
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I {
    fn next_back(&mut self) -> Option<I::Item> {
        (**self).next_back()
    }
    fn nth_back(&mut self, n: usize) -> Option<I::Item> {
        (**self).nth_back(n)
    }
}
<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

use std::convert::TryFrom;
use std::error::Error;
use std::fmt;

/// Parse a size string into a number of bytes.
///
/// A size string comprises an integer and an optional unit. The unit
/// may be K, M, G, T, P, E, Z or Y (powers of 1024), or KB, MB,
/// etc. (powers of 1000), or b which is 512.
/// Binary prefixes can be used, too: KiB=K, MiB=M, and so on.
///
/// # Errors
///
/// Will return `ParseSizeError` if it’s not possible to parse this
/// string into a number, e.g. if the string does not begin with a
/// numeral, or if the unit is not one of the supported units described
/// in the preceding section.
///
/// # Examples
///
/// ```rust
/// use uucore::parse_size::parse_size;
/// assert_eq!(Ok(123), parse_size("123"));
/// assert_eq!(Ok(9 * 1000), parse_size("9kB")); // kB is 1000
/// assert_eq!(Ok(2 * 1024), parse_size("2K")); // K is 1024
/// ```
pub fn parse_size(size: &str) -> Result<usize, ParseSizeError> {
    if size.is_empty() {
        return Err(ParseSizeError::parse_failure(size));
    }
    // Get the numeric part of the size argument. For example, if the
    // argument is "123K", then the numeric part is "123".
    let numeric_string: String = size.chars().take_while(|c| c.is_digit(10)).collect();
    let number: usize = if !numeric_string.is_empty() {
        match numeric_string.parse() {
            Ok(n) => n,
            Err(_) => return Err(ParseSizeError::parse_failure(size)),
        }
    } else {
        1
    };

    // Get the alphabetic units part of the size argument and compute
    // the factor it represents. For example, if the argument is "123K",
    // then the unit part is "K" and the factor is 1024. This may be the
    // empty string, in which case, the factor is 1.
    let unit = &size[numeric_string.len()..];
    let (base, exponent): (u128, u32) = match unit {
        "" => (1, 0),
        "b" => (512, 1), // (`head` and `tail` use "b")
        "KiB" | "K" | "k" => (1024, 1),
        "MiB" | "M" | "m" => (1024, 2),
        "GiB" | "G" | "g" => (1024, 3),
        "TiB" | "T" | "t" => (1024, 4),
        "PiB" | "P" | "p" => (1024, 5),
        "EiB" | "E" | "e" => (1024, 6),
        "ZiB" | "Z" | "z" => (1024, 7),
        "YiB" | "Y" | "y" => (1024, 8),
        "KB" | "kB" => (1000, 1),
        "MB" | "mB" => (1000, 2),
        "GB" | "gB" => (1000, 3),
        "TB" | "tB" => (1000, 4),
        "PB" | "pB" => (1000, 5),
        "EB" | "eB" => (1000, 6),
        "ZB" | "zB" => (1000, 7),
        "YB" | "yB" => (1000, 8),
        _ => return Err(ParseSizeError::parse_failure(size)),
    };
    let factor = match usize::try_from(base.pow(exponent)) {
        Ok(n) => n,
        Err(_) => return Err(ParseSizeError::size_too_big(size)),
    };
    match number.checked_mul(factor) {
        Some(n) => Ok(n),
        None => Err(ParseSizeError::size_too_big(size)),
    }
}

#[derive(Debug, PartialEq, Eq)]
pub enum ParseSizeError {
    ParseFailure(String), // Syntax
    SizeTooBig(String),   // Overflow
}

impl Error for ParseSizeError {
    fn description(&self) -> &str {
        match *self {
            ParseSizeError::ParseFailure(ref s) => &*s,
            ParseSizeError::SizeTooBig(ref s) => &*s,
        }
    }
}

impl fmt::Display for ParseSizeError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let s = match self {
            ParseSizeError::ParseFailure(s) => s,
            ParseSizeError::SizeTooBig(s) => s,
        };
        write!(f, "{}", s)
    }
}

impl ParseSizeError {
    fn parse_failure(s: &str) -> ParseSizeError {
        // has to be handled in the respective uutils because strings differ, e.g.
        // truncate: Invalid number: ‘fb’
        // tail: invalid number of bytes: ‘fb’
        ParseSizeError::ParseFailure(format!("‘{}’", s))
    }

    fn size_too_big(s: &str) -> ParseSizeError {
        // has to be handled in the respective uutils because strings differ, e.g.
        // truncate: Invalid number: ‘1Y’: Value too large to be stored in data type
        // tail: invalid number of bytes: ‘1Y’: Value too large to be stored in data type
        ParseSizeError::SizeTooBig(format!(
            "‘{}’: Value too large to be stored in data type",
            s
        ))
    }
}

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

    fn variant_eq(a: &ParseSizeError, b: &ParseSizeError) -> bool {
        std::mem::discriminant(a) == std::mem::discriminant(b)
    }

    #[test]
    fn all_suffixes() {
        // Units  are  K,M,G,T,P,E,Z,Y  (powers  of 1024) or KB,MB,... (powers of 1000).
        // Binary prefixes can be used, too: KiB=K, MiB=M, and so on.
        let suffixes = [
            ('K', 1u32),
            ('M', 2u32),
            ('G', 3u32),
            ('T', 4u32),
            ('P', 5u32),
            ('E', 6u32),
            #[cfg(target_pointer_width = "128")]
            ('Z', 7u32), // ParseSizeError::SizeTooBig on x64
            #[cfg(target_pointer_width = "128")]
            ('Y', 8u32), // ParseSizeError::SizeTooBig on x64
        ];

        for &(c, exp) in &suffixes {
            let s = format!("2{}B", c); // KB
            assert_eq!(Ok((2 * (1000 as u128).pow(exp)) as usize), parse_size(&s));
            let s = format!("2{}", c); // K
            assert_eq!(Ok((2 * (1024 as u128).pow(exp)) as usize), parse_size(&s));
            let s = format!("2{}iB", c); // KiB
            assert_eq!(Ok((2 * (1024 as u128).pow(exp)) as usize), parse_size(&s));

            // suffix only
            let s = format!("{}B", c); // KB
            assert_eq!(Ok(((1000 as u128).pow(exp)) as usize), parse_size(&s));
            let s = format!("{}", c); // K
            assert_eq!(Ok(((1024 as u128).pow(exp)) as usize), parse_size(&s));
            let s = format!("{}iB", c); // KiB
            assert_eq!(Ok(((1024 as u128).pow(exp)) as usize), parse_size(&s));
        }
    }

    #[test]
    #[cfg(not(target_pointer_width = "128"))]
    fn overflow_x64() {
        assert!(parse_size("10000000000000000000000").is_err());
        assert!(parse_size("1000000000T").is_err());
        assert!(parse_size("100000P").is_err());
        assert!(parse_size("100E").is_err());
        assert!(parse_size("1Z").is_err());
        assert!(parse_size("1Y").is_err());

        assert!(variant_eq(
            &parse_size("1Z").unwrap_err(),
            &ParseSizeError::SizeTooBig(String::new())
        ));

        assert_eq!(
            ParseSizeError::SizeTooBig(
                "‘1Y’: Value too large to be stored in data type".to_string()
            ),
            parse_size("1Y").unwrap_err()
        );
    }

    #[test]
    #[cfg(target_pointer_width = "32")]
    fn overflow_x32() {
        assert!(variant_eq(
            &parse_size("1T").unwrap_err(),
            &ParseSizeError::SizeTooBig(String::new())
        ));
        assert!(variant_eq(
            &parse_size("1000G").unwrap_err(),
            &ParseSizeError::SizeTooBig(String::new())
        ));
    }

    #[test]
    fn invalid_syntax() {
        let test_strings = ["328hdsf3290", "5MiB nonsense", "5mib", "biB", "-", ""];
        for &test_string in &test_strings {
            assert_eq!(
                parse_size(test_string).unwrap_err(),
                ParseSizeError::ParseFailure(format!("‘{}’", test_string))
            );
        }
    }

    #[test]
    fn b_suffix() {
        assert_eq!(Ok(3 * 512), parse_size("3b")); // b is 512
    }

    #[test]
    fn no_suffix() {
        assert_eq!(Ok(1234), parse_size("1234"));
        assert_eq!(Ok(0), parse_size("0"));
    }

    #[test]
    fn kilobytes_suffix() {
        assert_eq!(Ok(123 * 1000), parse_size("123KB")); // KB is 1000
        assert_eq!(Ok(9 * 1000), parse_size("9kB")); // kB is 1000
        assert_eq!(Ok(2 * 1024), parse_size("2K")); // K is 1024
        assert_eq!(Ok(0), parse_size("0K"));
        assert_eq!(Ok(0), parse_size("0KB"));
        assert_eq!(Ok(1000), parse_size("KB"));
        assert_eq!(Ok(1024), parse_size("K"));
    }

    #[test]
    fn megabytes_suffix() {
        assert_eq!(Ok(123 * 1024 * 1024), parse_size("123M"));
        assert_eq!(Ok(123 * 1000 * 1000), parse_size("123MB"));
        assert_eq!(Ok(1024 * 1024), parse_size("M"));
        assert_eq!(Ok(1000 * 1000), parse_size("MB"));
    }
}
<commit_msg>uucore: add more tests to parse_size<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

use std::convert::TryFrom;
use std::error::Error;
use std::fmt;

/// Parse a size string into a number of bytes.
///
/// A size string comprises an integer and an optional unit. The unit
/// may be K, M, G, T, P, E, Z or Y (powers of 1024), or KB, MB,
/// etc. (powers of 1000), or b which is 512.
/// Binary prefixes can be used, too: KiB=K, MiB=M, and so on.
///
/// # Errors
///
/// Will return `ParseSizeError` if it’s not possible to parse this
/// string into a number, e.g. if the string does not begin with a
/// numeral, or if the unit is not one of the supported units described
/// in the preceding section.
///
/// # Examples
///
/// ```rust
/// use uucore::parse_size::parse_size;
/// assert_eq!(Ok(123), parse_size("123"));
/// assert_eq!(Ok(9 * 1000), parse_size("9kB")); // kB is 1000
/// assert_eq!(Ok(2 * 1024), parse_size("2K")); // K is 1024
/// ```
pub fn parse_size(size: &str) -> Result<usize, ParseSizeError> {
    if size.is_empty() {
        return Err(ParseSizeError::parse_failure(size));
    }
    // Get the numeric part of the size argument. For example, if the
    // argument is "123K", then the numeric part is "123".
    let numeric_string: String = size.chars().take_while(|c| c.is_digit(10)).collect();
    let number: usize = if !numeric_string.is_empty() {
        match numeric_string.parse() {
            Ok(n) => n,
            Err(_) => return Err(ParseSizeError::parse_failure(size)),
        }
    } else {
        1
    };

    // Get the alphabetic units part of the size argument and compute
    // the factor it represents. For example, if the argument is "123K",
    // then the unit part is "K" and the factor is 1024. This may be the
    // empty string, in which case, the factor is 1.
    let unit = &size[numeric_string.len()..];
    let (base, exponent): (u128, u32) = match unit {
        "" => (1, 0),
        "b" => (512, 1), // (`head` and `tail` use "b")
        "KiB" | "kiB" | "K" | "k" => (1024, 1),
        "MiB" | "miB" | "M" | "m" => (1024, 2),
        "GiB" | "giB" | "G" | "g" => (1024, 3),
        "TiB" | "tiB" | "T" | "t" => (1024, 4),
        "PiB" | "piB" | "P" | "p" => (1024, 5),
        "EiB" | "eiB" | "E" | "e" => (1024, 6),
        "ZiB" | "ziB" | "Z" | "z" => (1024, 7),
        "YiB" | "yiB" | "Y" | "y" => (1024, 8),
        "KB" | "kB" => (1000, 1),
        "MB" | "mB" => (1000, 2),
        "GB" | "gB" => (1000, 3),
        "TB" | "tB" => (1000, 4),
        "PB" | "pB" => (1000, 5),
        "EB" | "eB" => (1000, 6),
        "ZB" | "zB" => (1000, 7),
        "YB" | "yB" => (1000, 8),
        _ => return Err(ParseSizeError::parse_failure(size)),
    };
    let factor = match usize::try_from(base.pow(exponent)) {
        Ok(n) => n,
        Err(_) => return Err(ParseSizeError::size_too_big(size)),
    };
    match number.checked_mul(factor) {
        Some(n) => Ok(n),
        None => Err(ParseSizeError::size_too_big(size)),
    }
}

#[derive(Debug, PartialEq, Eq)]
pub enum ParseSizeError {
    ParseFailure(String), // Syntax
    SizeTooBig(String),   // Overflow
}

impl Error for ParseSizeError {
    fn description(&self) -> &str {
        match *self {
            ParseSizeError::ParseFailure(ref s) => &*s,
            ParseSizeError::SizeTooBig(ref s) => &*s,
        }
    }
}

impl fmt::Display for ParseSizeError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let s = match self {
            ParseSizeError::ParseFailure(s) => s,
            ParseSizeError::SizeTooBig(s) => s,
        };
        write!(f, "{}", s)
    }
}

impl ParseSizeError {
    fn parse_failure(s: &str) -> ParseSizeError {
        // has to be handled in the respective uutils because strings differ, e.g.
        // truncate: Invalid number: ‘fb’
        // tail: invalid number of bytes: ‘fb’
        ParseSizeError::ParseFailure(format!("‘{}’", s))
    }

    fn size_too_big(s: &str) -> ParseSizeError {
        // has to be handled in the respective uutils because strings differ, e.g.
        // truncate: Invalid number: ‘1Y’: Value too large to be stored in data type
        // tail: invalid number of bytes: ‘1Y’: Value too large to be stored in data type
        ParseSizeError::SizeTooBig(format!(
            "‘{}’: Value too large to be stored in data type",
            s
        ))
    }
}

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

    fn variant_eq(a: &ParseSizeError, b: &ParseSizeError) -> bool {
        std::mem::discriminant(a) == std::mem::discriminant(b)
    }

    #[test]
    fn all_suffixes() {
        // Units  are  K,M,G,T,P,E,Z,Y  (powers  of 1024) or KB,MB,... (powers of 1000).
        // Binary prefixes can be used, too: KiB=K, MiB=M, and so on.
        let suffixes = [
            ('K', 1u32),
            ('M', 2u32),
            ('G', 3u32),
            ('T', 4u32),
            ('P', 5u32),
            ('E', 6u32),
            #[cfg(target_pointer_width = "128")]
            ('Z', 7u32), // ParseSizeError::SizeTooBig on x64
            #[cfg(target_pointer_width = "128")]
            ('Y', 8u32), // ParseSizeError::SizeTooBig on x64
        ];

        for &(c, exp) in &suffixes {
            let s = format!("2{}B", c); // KB
            assert_eq!(Ok((2 * (1000_u128).pow(exp)) as usize), parse_size(&s));
            let s = format!("2{}", c); // K
            assert_eq!(Ok((2 * (1024_u128).pow(exp)) as usize), parse_size(&s));
            let s = format!("2{}iB", c); // KiB
            assert_eq!(Ok((2 * (1024_u128).pow(exp)) as usize), parse_size(&s));
            let s = format!("2{}iB", c.to_lowercase()); // kiB
            assert_eq!(Ok((2 * (1024_u128).pow(exp)) as usize), parse_size(&s));

            // suffix only
            let s = format!("{}B", c); // KB
            assert_eq!(Ok(((1000_u128).pow(exp)) as usize), parse_size(&s));
            let s = format!("{}", c); // K
            assert_eq!(Ok(((1024_u128).pow(exp)) as usize), parse_size(&s));
            let s = format!("{}iB", c); // KiB
            assert_eq!(Ok(((1024_u128).pow(exp)) as usize), parse_size(&s));
            let s = format!("{}iB", c.to_lowercase()); // kiB
            assert_eq!(Ok(((1024_u128).pow(exp)) as usize), parse_size(&s));
        }
    }

    #[test]
    #[cfg(not(target_pointer_width = "128"))]
    fn overflow_x64() {
        assert!(parse_size("10000000000000000000000").is_err());
        assert!(parse_size("1000000000T").is_err());
        assert!(parse_size("100000P").is_err());
        assert!(parse_size("100E").is_err());
        assert!(parse_size("1Z").is_err());
        assert!(parse_size("1Y").is_err());

        assert!(variant_eq(
            &parse_size("1Z").unwrap_err(),
            &ParseSizeError::SizeTooBig(String::new())
        ));

        assert_eq!(
            ParseSizeError::SizeTooBig(
                "‘1Y’: Value too large to be stored in data type".to_string()
            ),
            parse_size("1Y").unwrap_err()
        );
    }

    #[test]
    #[cfg(target_pointer_width = "32")]
    fn overflow_x32() {
        assert!(variant_eq(
            &parse_size("1T").unwrap_err(),
            &ParseSizeError::SizeTooBig(String::new())
        ));
        assert!(variant_eq(
            &parse_size("1000G").unwrap_err(),
            &ParseSizeError::SizeTooBig(String::new())
        ));
    }

    #[test]
    fn invalid_syntax() {
        let test_strings = ["328hdsf3290", "5MiB nonsense", "5mib", "biB", "-", ""];
        for &test_string in &test_strings {
            assert_eq!(
                parse_size(test_string).unwrap_err(),
                ParseSizeError::ParseFailure(format!("‘{}’", test_string))
            );
        }
    }

    #[test]
    fn b_suffix() {
        assert_eq!(Ok(3 * 512), parse_size("3b")); // b is 512
    }

    #[test]
    fn no_suffix() {
        assert_eq!(Ok(1234), parse_size("1234"));
        assert_eq!(Ok(0), parse_size("0"));
    }

    #[test]
    fn kilobytes_suffix() {
        assert_eq!(Ok(123 * 1000), parse_size("123KB")); // KB is 1000
        assert_eq!(Ok(9 * 1000), parse_size("9kB")); // kB is 1000
        assert_eq!(Ok(2 * 1024), parse_size("2K")); // K is 1024
        assert_eq!(Ok(0), parse_size("0K"));
        assert_eq!(Ok(0), parse_size("0KB"));
        assert_eq!(Ok(1000), parse_size("KB"));
        assert_eq!(Ok(1024), parse_size("K"));
    }

    #[test]
    fn megabytes_suffix() {
        assert_eq!(Ok(123 * 1024 * 1024), parse_size("123M"));
        assert_eq!(Ok(123 * 1000 * 1000), parse_size("123MB"));
        assert_eq!(Ok(1024 * 1024), parse_size("M"));
        assert_eq!(Ok(1000 * 1000), parse_size("MB"));
    }
}
<|endoftext|>


<commit_before>//! This pass enforces various "well-formedness constraints" on impls.
//! Logically, it is part of wfcheck -- but we do it early so that we
//! can stop compilation afterwards, since part of the trait matching
//! infrastructure gets very grumpy if these conditions don't hold. In
//! particular, if there are type parameters that are not part of the
//! impl, then coherence will report strange inference ambiguity
//! errors; if impls have duplicate items, we get misleading
//! specialization errors. These things can (and probably should) be
//! fixed, but for the moment it's easier to do these checks early.

use crate::constrained_generic_params as cgp;
use rustc::hir;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir::def_id::DefId;
use rustc::ty::{self, TyCtxt, TypeFoldable};
use rustc::ty::query::Providers;
use rustc::util::nodemap::{FxHashMap, FxHashSet};
use std::collections::hash_map::Entry::{Occupied, Vacant};

use syntax_pos::Span;

/// Checks that all the type/lifetime parameters on an impl also
/// appear in the trait ref or self type (or are constrained by a
/// where-clause). These rules are needed to ensure that, given a
/// trait ref like `<T as Trait<U>>`, we can derive the values of all
/// parameters on the impl (which is needed to make specialization
/// possible).
///
/// However, in the case of lifetimes, we only enforce these rules if
/// the lifetime parameter is used in an associated type. This is a
/// concession to backwards compatibility; see comment at the end of
/// the fn for details.
///
/// Example:
///
/// ```rust,ignore (pseudo-Rust)
/// impl<T> Trait<Foo> for Bar { ... }
/// //   ^ T does not appear in `Foo` or `Bar`, error!
///
/// impl<T> Trait<Foo<T>> for Bar { ... }
/// //   ^ T appears in `Foo<T>`, ok.
///
/// impl<T> Trait<Foo> for Bar where Bar: Iterator<Item = T> { ... }
/// //   ^ T is bound to `<Bar as Iterator>::Item`, ok.
///
/// impl<'a> Trait<Foo> for Bar { }
/// //   ^ 'a is unused, but for back-compat we allow it
///
/// impl<'a> Trait<Foo> for Bar { type X = &'a i32; }
/// //   ^ 'a is unused and appears in assoc type, error
/// ```
pub fn impl_wf_check(tcx: TyCtxt<'_>) {
    // We will tag this as part of the WF check -- logically, it is,
    // but it's one that we must perform earlier than the rest of
    // WfCheck.
    for &module in tcx.hir().krate().modules.keys() {
        tcx.ensure().check_mod_impl_wf(tcx.hir().local_def_id_from_node_id(module));
    }
}

fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: DefId) {
    tcx.hir().visit_item_likes_in_module(
        module_def_id,
        &mut ImplWfCheck { tcx }
    );
}

pub fn provide(providers: &mut Providers<'_>) {
    *providers = Providers {
        check_mod_impl_wf,
        ..*providers
    };
}

struct ImplWfCheck<'tcx> {
    tcx: TyCtxt<'tcx>,
}

impl ItemLikeVisitor<'tcx> for ImplWfCheck<'tcx> {
    fn visit_item(&mut self, item: &'tcx hir::Item) {
        if let hir::ItemKind::Impl(.., ref impl_item_refs) = item.node {
            let impl_def_id = self.tcx.hir().local_def_id(item.hir_id);
            enforce_impl_params_are_constrained(self.tcx,
                                                impl_def_id,
                                                impl_item_refs);
            enforce_impl_items_are_distinct(self.tcx, impl_item_refs);
        }
    }

    fn visit_trait_item(&mut self, _trait_item: &'tcx hir::TraitItem) { }

    fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem) { }
}

fn enforce_impl_params_are_constrained(
    tcx: TyCtxt<'_>,
    impl_def_id: DefId,
    impl_item_refs: &[hir::ImplItemRef],
) {
    // Every lifetime used in an associated type must be constrained.
    let impl_self_ty = tcx.type_of(impl_def_id);
    if impl_self_ty.references_error() {
        // Don't complain about unconstrained type params when self ty isn't known due to errors.
        // (#36836)
        tcx.sess.delay_span_bug(tcx.def_span(impl_def_id), &format(
            "potentially unconstrained type parameters weren't evaluated on `{:?}`",
            impl_self_ty,
        ));
        return;
    }
    let impl_generics = tcx.generics_of(impl_def_id);
    let impl_predicates = tcx.predicates_of(impl_def_id);
    let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);

    let mut input_parameters = cgp::parameters_for_impl(impl_self_ty, impl_trait_ref);
    cgp::identify_constrained_generic_params(
        tcx, &impl_predicates, impl_trait_ref, &mut input_parameters);

    // Disallow unconstrained lifetimes, but only if they appear in assoc types.
    let lifetimes_in_associated_types: FxHashSet<_> = impl_item_refs.iter()
        .map(|item_ref| tcx.hir().local_def_id(item_ref.id.hir_id))
        .filter(|&def_id| {
            let item = tcx.associated_item(def_id);
            item.kind == ty::AssocKind::Type && item.defaultness.has_value()
        })
        .flat_map(|def_id| {
            cgp::parameters_for(&tcx.type_of(def_id), true)
        }).collect();

    for param in &impl_generics.params {
        match param.kind {
            // Disallow ANY unconstrained type parameters.
            ty::GenericParamDefKind::Type { .. } => {
                let param_ty = ty::ParamTy::for_def(param);
                if !input_parameters.contains(&cgp::Parameter::from(param_ty)) {
                    report_unused_parameter(tcx,
                                            tcx.def_span(param.def_id),
                                            "type",
                                            &param_ty.to_string());
                }
            }
            ty::GenericParamDefKind::Lifetime => {
                let param_lt = cgp::Parameter::from(param.to_early_bound_region_data());
                if lifetimes_in_associated_types.contains(&param_lt) && // (*)
                    !input_parameters.contains(&param_lt) {
                    report_unused_parameter(tcx,
                                            tcx.def_span(param.def_id),
                                            "lifetime",
                                            &param.name.to_string());
                }
            }
            ty::GenericParamDefKind::Const => {
                let param_ct = ty::ParamConst::for_def(param);
                if !input_parameters.contains(&cgp::Parameter::from(param_ct)) {
                    report_unused_parameter(tcx,
                                           tcx.def_span(param.def_id),
                                           "const",
                                           &param_ct.to_string());
                }
            }
        }
    }

    // (*) This is a horrible concession to reality. I think it'd be
    // better to just ban unconstrianed lifetimes outright, but in
    // practice people do non-hygenic macros like:
    //
    // ```
    // macro_rules! __impl_slice_eq1 {
    //     ($Lhs: ty, $Rhs: ty, $Bound: ident) => {
    //         impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
    //            ....
    //         }
    //     }
    // }
    // ```
    //
    // In a concession to backwards compatibility, we continue to
    // permit those, so long as the lifetimes aren't used in
    // associated types. I believe this is sound, because lifetimes
    // used elsewhere are not projected back out.
}

fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: &str) {
    struct_span_err!(
        tcx.sess, span, E0207,
        "the {} parameter `{}` is not constrained by the \
        impl trait, self type, or predicates",
        kind, name)
        .span_label(span, format!("unconstrained {} parameter", kind))
        .emit();
}

/// Enforce that we do not have two items in an impl with the same name.
fn enforce_impl_items_are_distinct(tcx: TyCtxt<'_>, impl_item_refs: &[hir::ImplItemRef]) {
    let mut seen_type_items = FxHashMap::default();
    let mut seen_value_items = FxHashMap::default();
    for impl_item_ref in impl_item_refs {
        let impl_item = tcx.hir().impl_item(impl_item_ref.id);
        let seen_items = match impl_item.node {
            hir::ImplItemKind::TyAlias(_) => &mut seen_type_items,
            _                          => &mut seen_value_items,
        };
        match seen_items.entry(impl_item.ident.modern()) {
            Occupied(entry) => {
                let mut err = struct_span_err!(tcx.sess, impl_item.span, E0201,
                                               "duplicate definitions with name `{}`:",
                                               impl_item.ident);
                err.span_label(*entry.get(),
                               format!("previous definition of `{}` here",
                                       impl_item.ident));
                err.span_label(impl_item.span, "duplicate definition");
                err.emit();
            }
            Vacant(entry) => {
                entry.insert(impl_item.span);
            }
        }
    }
}
<commit_msg>review comment<commit_after>//! This pass enforces various "well-formedness constraints" on impls.
//! Logically, it is part of wfcheck -- but we do it early so that we
//! can stop compilation afterwards, since part of the trait matching
//! infrastructure gets very grumpy if these conditions don't hold. In
//! particular, if there are type parameters that are not part of the
//! impl, then coherence will report strange inference ambiguity
//! errors; if impls have duplicate items, we get misleading
//! specialization errors. These things can (and probably should) be
//! fixed, but for the moment it's easier to do these checks early.

use crate::constrained_generic_params as cgp;
use rustc::hir;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir::def_id::DefId;
use rustc::ty::{self, TyCtxt, TypeFoldable};
use rustc::ty::query::Providers;
use rustc::util::nodemap::{FxHashMap, FxHashSet};
use std::collections::hash_map::Entry::{Occupied, Vacant};

use syntax_pos::Span;

/// Checks that all the type/lifetime parameters on an impl also
/// appear in the trait ref or self type (or are constrained by a
/// where-clause). These rules are needed to ensure that, given a
/// trait ref like `<T as Trait<U>>`, we can derive the values of all
/// parameters on the impl (which is needed to make specialization
/// possible).
///
/// However, in the case of lifetimes, we only enforce these rules if
/// the lifetime parameter is used in an associated type. This is a
/// concession to backwards compatibility; see comment at the end of
/// the fn for details.
///
/// Example:
///
/// ```rust,ignore (pseudo-Rust)
/// impl<T> Trait<Foo> for Bar { ... }
/// //   ^ T does not appear in `Foo` or `Bar`, error!
///
/// impl<T> Trait<Foo<T>> for Bar { ... }
/// //   ^ T appears in `Foo<T>`, ok.
///
/// impl<T> Trait<Foo> for Bar where Bar: Iterator<Item = T> { ... }
/// //   ^ T is bound to `<Bar as Iterator>::Item`, ok.
///
/// impl<'a> Trait<Foo> for Bar { }
/// //   ^ 'a is unused, but for back-compat we allow it
///
/// impl<'a> Trait<Foo> for Bar { type X = &'a i32; }
/// //   ^ 'a is unused and appears in assoc type, error
/// ```
pub fn impl_wf_check(tcx: TyCtxt<'_>) {
    // We will tag this as part of the WF check -- logically, it is,
    // but it's one that we must perform earlier than the rest of
    // WfCheck.
    for &module in tcx.hir().krate().modules.keys() {
        tcx.ensure().check_mod_impl_wf(tcx.hir().local_def_id_from_node_id(module));
    }
}

fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: DefId) {
    tcx.hir().visit_item_likes_in_module(
        module_def_id,
        &mut ImplWfCheck { tcx }
    );
}

pub fn provide(providers: &mut Providers<'_>) {
    *providers = Providers {
        check_mod_impl_wf,
        ..*providers
    };
}

struct ImplWfCheck<'tcx> {
    tcx: TyCtxt<'tcx>,
}

impl ItemLikeVisitor<'tcx> for ImplWfCheck<'tcx> {
    fn visit_item(&mut self, item: &'tcx hir::Item) {
        if let hir::ItemKind::Impl(.., ref impl_item_refs) = item.node {
            let impl_def_id = self.tcx.hir().local_def_id(item.hir_id);
            enforce_impl_params_are_constrained(self.tcx,
                                                impl_def_id,
                                                impl_item_refs);
            enforce_impl_items_are_distinct(self.tcx, impl_item_refs);
        }
    }

    fn visit_trait_item(&mut self, _trait_item: &'tcx hir::TraitItem) { }

    fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem) { }
}

fn enforce_impl_params_are_constrained(
    tcx: TyCtxt<'_>,
    impl_def_id: DefId,
    impl_item_refs: &[hir::ImplItemRef],
) {
    // Every lifetime used in an associated type must be constrained.
    let impl_self_ty = tcx.type_of(impl_def_id);
    if impl_self_ty.references_error() {
        // Don't complain about unconstrained type params when self ty isn't known due to errors.
        // (#36836)
        tcx.sess.delay_span_bug(
            tcx.def_span(impl_def_id),
            "potentially unconstrained type parameters weren't evaluated",
        );
        return;
    }
    let impl_generics = tcx.generics_of(impl_def_id);
    let impl_predicates = tcx.predicates_of(impl_def_id);
    let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);

    let mut input_parameters = cgp::parameters_for_impl(impl_self_ty, impl_trait_ref);
    cgp::identify_constrained_generic_params(
        tcx, &impl_predicates, impl_trait_ref, &mut input_parameters);

    // Disallow unconstrained lifetimes, but only if they appear in assoc types.
    let lifetimes_in_associated_types: FxHashSet<_> = impl_item_refs.iter()
        .map(|item_ref| tcx.hir().local_def_id(item_ref.id.hir_id))
        .filter(|&def_id| {
            let item = tcx.associated_item(def_id);
            item.kind == ty::AssocKind::Type && item.defaultness.has_value()
        })
        .flat_map(|def_id| {
            cgp::parameters_for(&tcx.type_of(def_id), true)
        }).collect();

    for param in &impl_generics.params {
        match param.kind {
            // Disallow ANY unconstrained type parameters.
            ty::GenericParamDefKind::Type { .. } => {
                let param_ty = ty::ParamTy::for_def(param);
                if !input_parameters.contains(&cgp::Parameter::from(param_ty)) {
                    report_unused_parameter(tcx,
                                            tcx.def_span(param.def_id),
                                            "type",
                                            &param_ty.to_string());
                }
            }
            ty::GenericParamDefKind::Lifetime => {
                let param_lt = cgp::Parameter::from(param.to_early_bound_region_data());
                if lifetimes_in_associated_types.contains(&param_lt) && // (*)
                    !input_parameters.contains(&param_lt) {
                    report_unused_parameter(tcx,
                                            tcx.def_span(param.def_id),
                                            "lifetime",
                                            &param.name.to_string());
                }
            }
            ty::GenericParamDefKind::Const => {
                let param_ct = ty::ParamConst::for_def(param);
                if !input_parameters.contains(&cgp::Parameter::from(param_ct)) {
                    report_unused_parameter(tcx,
                                           tcx.def_span(param.def_id),
                                           "const",
                                           &param_ct.to_string());
                }
            }
        }
    }

    // (*) This is a horrible concession to reality. I think it'd be
    // better to just ban unconstrianed lifetimes outright, but in
    // practice people do non-hygenic macros like:
    //
    // ```
    // macro_rules! __impl_slice_eq1 {
    //     ($Lhs: ty, $Rhs: ty, $Bound: ident) => {
    //         impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
    //            ....
    //         }
    //     }
    // }
    // ```
    //
    // In a concession to backwards compatibility, we continue to
    // permit those, so long as the lifetimes aren't used in
    // associated types. I believe this is sound, because lifetimes
    // used elsewhere are not projected back out.
}

fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: &str) {
    struct_span_err!(
        tcx.sess, span, E0207,
        "the {} parameter `{}` is not constrained by the \
        impl trait, self type, or predicates",
        kind, name)
        .span_label(span, format!("unconstrained {} parameter", kind))
        .emit();
}

/// Enforce that we do not have two items in an impl with the same name.
fn enforce_impl_items_are_distinct(tcx: TyCtxt<'_>, impl_item_refs: &[hir::ImplItemRef]) {
    let mut seen_type_items = FxHashMap::default();
    let mut seen_value_items = FxHashMap::default();
    for impl_item_ref in impl_item_refs {
        let impl_item = tcx.hir().impl_item(impl_item_ref.id);
        let seen_items = match impl_item.node {
            hir::ImplItemKind::TyAlias(_) => &mut seen_type_items,
            _                          => &mut seen_value_items,
        };
        match seen_items.entry(impl_item.ident.modern()) {
            Occupied(entry) => {
                let mut err = struct_span_err!(tcx.sess, impl_item.span, E0201,
                                               "duplicate definitions with name `{}`:",
                                               impl_item.ident);
                err.span_label(*entry.get(),
                               format!("previous definition of `{}` here",
                                       impl_item.ident));
                err.span_label(impl_item.span, "duplicate definition");
                err.emit();
            }
            Vacant(entry) => {
                entry.insert(impl_item.span);
            }
        }
    }
}
<|endoftext|>


<commit_before>#[doc = "Prunes branches of the tree that are not exported"];

import rustc::syntax::ast;
import rustc::syntax::ast_util;
import rustc::middle::ast_map;

export mk_pass;

fn mk_pass() -> pass {
    run
}

fn run(srv: astsrv::srv, doc: doc::cratedoc) -> doc::cratedoc {
    let fold = fold::fold({
        fold_mod: fold_mod
        with *fold::default_seq_fold(srv)
    });
    fold.fold_crate(fold, doc)
}

fn fold_mod(fold: fold::fold<astsrv::srv>, doc: doc::moddoc) -> doc::moddoc {
    let doc = fold::default_seq_fold_mod(fold, doc);
    {
        items: ~exported_items(fold.ctxt, doc)
        with doc
    }
}

fn exported_items(srv: astsrv::srv, doc: doc::moddoc) -> [doc::itemtag] {
    exported_things(
        srv, doc,
        exported_items_from_crate,
        exported_items_from_mod
    )
}

fn exported_things<T>(
    srv: astsrv::srv,
    doc: doc::moddoc,
    from_crate: fn(astsrv::srv, doc::moddoc) -> [T],
    from_mod: fn(astsrv::srv, doc::moddoc) -> [T]
) -> [T] {
    if doc.id == ast::crate_node_id {
        from_crate(srv, doc)
    } else {
        from_mod(srv, doc)
    }
}

fn exported_items_from_crate(
    srv: astsrv::srv,
    doc: doc::moddoc
) -> [doc::itemtag] {
    exported_items_from(srv, doc, is_exported_from_crate)
}

fn exported_items_from_mod(
    srv: astsrv::srv,
    doc: doc::moddoc
) -> [doc::itemtag] {
    exported_items_from(srv, doc, bind is_exported_from_mod(_, doc.id, _))
}

fn exported_items_from(
    srv: astsrv::srv,
    doc: doc::moddoc,
    is_exported: fn(astsrv::srv, str) -> bool
) -> [doc::itemtag] {
    vec::filter_map(*doc.items) { |itemtag|
        let itemtag = alt itemtag {
          doc::enumtag(enumdoc) {
            // Also need to check variant exportedness
            doc::enumtag({
                variants: exported_variants_from(srv, enumdoc, is_exported)
                with enumdoc
            })
          }
          _ { itemtag }
        };
        if is_exported(srv, itemtag.name()) {
            some(itemtag)
        } else {
            none
        }
    }
}

fn exported_variants_from(
    srv: astsrv::srv,
    doc: doc::enumdoc,
    is_exported: fn(astsrv::srv, str) -> bool
) -> [doc::variantdoc] {
    vec::filter_map(doc.variants) { |doc|
        if is_exported(srv, doc.name) {
            some(doc)
        } else {
            none
        }
    }
}

fn is_exported_from_mod(
    srv: astsrv::srv,
    mod_id: doc::ast_id,
    item_name: str
) -> bool {
    astsrv::exec(srv) {|ctxt|
        alt ctxt.ast_map.get(mod_id) {
          ast_map::node_item(item) {
            alt item.node {
              ast::item_mod(m) {
                ast_util::is_exported(item_name, m)
              }
            }
          }
        }
    }
}

fn is_exported_from_crate(
    srv: astsrv::srv,
    item_name: str
) -> bool {
    astsrv::exec(srv) {|ctxt|
        ast_util::is_exported(item_name, ctxt.ast.node.module)
    }
}

#[test]
fn should_prune_unexported_fns() {
    let source = "mod b { export a; fn a() { } fn b() { } }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = run(srv, doc);
    assert vec::len(doc.topmod.mods()[0].fns()) == 1u;
}

#[test]
fn should_prune_unexported_fns_from_top_mod() {
    let source = "export a; fn a() { } fn b() { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = run(srv, doc);
    assert vec::len(doc.topmod.fns()) == 1u;
}

#[test]
fn should_prune_unexported_modules() {
    let source = "mod a { export a; mod a { } mod b { } }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = run(srv, doc);
    assert vec::len(doc.topmod.mods()[0].mods()) == 1u;
}

#[test]
fn should_prune_unexported_modules_from_top_mod() {
    let source = "export a; mod a { } mod b { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = run(srv, doc);
    assert vec::len(doc.topmod.mods()) == 1u;
}

#[test]
fn should_prune_unexported_consts() {
    let source = "mod a { export a; \
                  const a: bool = true; \
                  const b: bool = true; }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = run(srv, doc);
    assert vec::len(doc.topmod.mods()[0].consts()) == 1u;
}

#[test]
fn should_prune_unexported_consts_from_top_mod() {
    let source = "export a; const a: bool = true; const b: bool = true;";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = run(srv, doc);
    assert vec::len(doc.topmod.consts()) == 1u;
}

#[test]
fn should_prune_unexported_enums_from_top_mod() {
    let source = "export a; mod a { } enum b { c }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = run(srv, doc);
    assert vec::len(doc.topmod.enums()) == 0u;
}

#[test]
fn should_prune_unexported_enums() {
    let source = "mod a { export a; mod a { } enum b { c } }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = run(srv, doc);
    assert vec::len(doc.topmod.mods()[0].enums()) == 0u;
}

#[test]
fn should_prune_unexported_variants_from_top_mod() {
    let source = "export b::{}; enum b { c }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = run(srv, doc);
    assert vec::len(doc.topmod.enums()[0].variants) == 0u;
}

#[test]
fn should_prune_unexported_variants() {
    let source = "mod a { export b::{}; enum b { c } }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = run(srv, doc);
    assert vec::len(doc.topmod.mods()[0].enums()[0].variants) == 0u;
}

#[test]
fn should_prune_unexported_resources_from_top_mod() {
    let source = "export a; mod a { } resource r(a: bool) { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = run(srv, doc);
    assert vec::is_empty(doc.topmod.resources());
}

#[test]
fn should_prune_unexported_resources() {
    let source = "mod a { export a; mod a { } resource r(a: bool) { } }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = run(srv, doc);
    assert vec::is_empty(doc.topmod.mods()[0].resources());
}
<commit_msg>rustdoc: Add a test that unexported ifaces are pruned<commit_after>#[doc = "Prunes branches of the tree that are not exported"];

import rustc::syntax::ast;
import rustc::syntax::ast_util;
import rustc::middle::ast_map;

export mk_pass;

fn mk_pass() -> pass {
    run
}

fn run(srv: astsrv::srv, doc: doc::cratedoc) -> doc::cratedoc {
    let fold = fold::fold({
        fold_mod: fold_mod
        with *fold::default_seq_fold(srv)
    });
    fold.fold_crate(fold, doc)
}

fn fold_mod(fold: fold::fold<astsrv::srv>, doc: doc::moddoc) -> doc::moddoc {
    let doc = fold::default_seq_fold_mod(fold, doc);
    {
        items: ~exported_items(fold.ctxt, doc)
        with doc
    }
}

fn exported_items(srv: astsrv::srv, doc: doc::moddoc) -> [doc::itemtag] {
    exported_things(
        srv, doc,
        exported_items_from_crate,
        exported_items_from_mod
    )
}

fn exported_things<T>(
    srv: astsrv::srv,
    doc: doc::moddoc,
    from_crate: fn(astsrv::srv, doc::moddoc) -> [T],
    from_mod: fn(astsrv::srv, doc::moddoc) -> [T]
) -> [T] {
    if doc.id == ast::crate_node_id {
        from_crate(srv, doc)
    } else {
        from_mod(srv, doc)
    }
}

fn exported_items_from_crate(
    srv: astsrv::srv,
    doc: doc::moddoc
) -> [doc::itemtag] {
    exported_items_from(srv, doc, is_exported_from_crate)
}

fn exported_items_from_mod(
    srv: astsrv::srv,
    doc: doc::moddoc
) -> [doc::itemtag] {
    exported_items_from(srv, doc, bind is_exported_from_mod(_, doc.id, _))
}

fn exported_items_from(
    srv: astsrv::srv,
    doc: doc::moddoc,
    is_exported: fn(astsrv::srv, str) -> bool
) -> [doc::itemtag] {
    vec::filter_map(*doc.items) { |itemtag|
        let itemtag = alt itemtag {
          doc::enumtag(enumdoc) {
            // Also need to check variant exportedness
            doc::enumtag({
                variants: exported_variants_from(srv, enumdoc, is_exported)
                with enumdoc
            })
          }
          _ { itemtag }
        };
        if is_exported(srv, itemtag.name()) {
            some(itemtag)
        } else {
            none
        }
    }
}

fn exported_variants_from(
    srv: astsrv::srv,
    doc: doc::enumdoc,
    is_exported: fn(astsrv::srv, str) -> bool
) -> [doc::variantdoc] {
    vec::filter_map(doc.variants) { |doc|
        if is_exported(srv, doc.name) {
            some(doc)
        } else {
            none
        }
    }
}

fn is_exported_from_mod(
    srv: astsrv::srv,
    mod_id: doc::ast_id,
    item_name: str
) -> bool {
    astsrv::exec(srv) {|ctxt|
        alt ctxt.ast_map.get(mod_id) {
          ast_map::node_item(item) {
            alt item.node {
              ast::item_mod(m) {
                ast_util::is_exported(item_name, m)
              }
            }
          }
        }
    }
}

fn is_exported_from_crate(
    srv: astsrv::srv,
    item_name: str
) -> bool {
    astsrv::exec(srv) {|ctxt|
        ast_util::is_exported(item_name, ctxt.ast.node.module)
    }
}

#[test]
fn should_prune_unexported_fns() {
    let source = "mod b { export a; fn a() { } fn b() { } }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = run(srv, doc);
    assert vec::len(doc.topmod.mods()[0].fns()) == 1u;
}

#[test]
fn should_prune_unexported_fns_from_top_mod() {
    let source = "export a; fn a() { } fn b() { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = run(srv, doc);
    assert vec::len(doc.topmod.fns()) == 1u;
}

#[test]
fn should_prune_unexported_modules() {
    let source = "mod a { export a; mod a { } mod b { } }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = run(srv, doc);
    assert vec::len(doc.topmod.mods()[0].mods()) == 1u;
}

#[test]
fn should_prune_unexported_modules_from_top_mod() {
    let source = "export a; mod a { } mod b { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = run(srv, doc);
    assert vec::len(doc.topmod.mods()) == 1u;
}

#[test]
fn should_prune_unexported_consts() {
    let source = "mod a { export a; \
                  const a: bool = true; \
                  const b: bool = true; }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = run(srv, doc);
    assert vec::len(doc.topmod.mods()[0].consts()) == 1u;
}

#[test]
fn should_prune_unexported_consts_from_top_mod() {
    let source = "export a; const a: bool = true; const b: bool = true;";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = run(srv, doc);
    assert vec::len(doc.topmod.consts()) == 1u;
}

#[test]
fn should_prune_unexported_enums_from_top_mod() {
    let source = "export a; mod a { } enum b { c }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = run(srv, doc);
    assert vec::len(doc.topmod.enums()) == 0u;
}

#[test]
fn should_prune_unexported_enums() {
    let source = "mod a { export a; mod a { } enum b { c } }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = run(srv, doc);
    assert vec::len(doc.topmod.mods()[0].enums()) == 0u;
}

#[test]
fn should_prune_unexported_variants_from_top_mod() {
    let source = "export b::{}; enum b { c }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = run(srv, doc);
    assert vec::len(doc.topmod.enums()[0].variants) == 0u;
}

#[test]
fn should_prune_unexported_variants() {
    let source = "mod a { export b::{}; enum b { c } }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = run(srv, doc);
    assert vec::len(doc.topmod.mods()[0].enums()[0].variants) == 0u;
}

#[test]
fn should_prune_unexported_resources_from_top_mod() {
    let source = "export a; mod a { } resource r(a: bool) { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = run(srv, doc);
    assert vec::is_empty(doc.topmod.resources());
}

#[test]
fn should_prune_unexported_resources() {
    let source = "mod a { export a; mod a { } resource r(a: bool) { } }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = run(srv, doc);
    assert vec::is_empty(doc.topmod.mods()[0].resources());
}

#[test]
fn should_prune_unexported_ifaces_from_top_mod() {
    let source = "export a; mod a { } iface b { fn c(); }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = run(srv, doc);
    assert vec::is_empty(doc.topmod.ifaces());
}<|endoftext|>


<commit_before>use serde_json::json;
use std::io::prelude::*;
use std::io::BufReader;
use std::process::{Child, Command, Stdio};
use std::time::{Duration, Instant};
use unused_port::unused_tcp_port;
use web3::{transports::Http, Transport, Web3};

/// How long we will wait for ganache to indicate that it is ready.
const GANACHE_STARTUP_TIMEOUT_MILLIS: u64 = 10_000;

/// Provides a dedicated `ganachi-cli` instance with a connected `Web3` instance.
///
/// Requires that `ganachi-cli` is installed and available on `PATH`.
pub struct GanacheInstance {
    pub port: u16,
    child: Child,
    pub web3: Web3<Http>,
    chain_id: u64,
}

impl GanacheInstance {
    fn new_from_child(mut child: Child, port: u16, chain_id: u64) -> Result<Self, String> {
        let stdout = child
            .stdout
            .ok_or("Unable to get stdout for ganache child process")?;

        let start = Instant::now();
        let mut reader = BufReader::new(stdout);
        loop {
            if start + Duration::from_millis(GANACHE_STARTUP_TIMEOUT_MILLIS) <= Instant::now() {
                break Err(
                    "Timed out waiting for ganache to start. Is ganache installed?".to_string(),
                );
            }

            let mut line = String::new();
            if let Err(e) = reader.read_line(&mut line) {
                break Err(format!("Failed to read line from ganache process: {:?}", e));
            } else if line.starts_with("RPC Listening on") {
                break Ok(());
            } else {
                continue;
            }
        }?;

        let transport = Http::new(&endpoint(port)).map_err(|e| {
            format!(
                "Failed to start HTTP transport connected to ganache: {:?}",
                e
            )
        })?;
        let web3 = Web3::new(transport);

        child.stdout = Some(reader.into_inner());

        Ok(Self {
            port,
            child,
            web3,
            chain_id,
        })
    }

    /// Start a new `ganache` process, waiting until it indicates that it is ready to accept
    /// RPC connections.
    pub fn new(chain_id: u64) -> Result<Self, String> {
        let port = unused_tcp_port()?;
        let binary = match cfg!(windows) {
            true => "ganache.cmd",
            false => "ganache",
        };
        let child = Command::new(binary)
            .stdout(Stdio::piped())
            .arg("--defaultBalanceEther")
            .arg("1000000000")
            .arg("--gasLimit")
            .arg("1000000000")
            .arg("--accounts")
            .arg("10")
            .arg("--port")
            .arg(format!("{}", port))
            .arg("--mnemonic")
            .arg("\"vast thought differ pull jewel broom cook wrist tribe word before omit\"")
            .arg("--chain.chainId")
            .arg(format!("{}", chain_id))
            .spawn()
            .map_err(|e| {
                format!(
                    "Failed to start {}. \
                    Is it installed and available on $PATH? Error: {:?}",
                    binary, e
                )
            })?;

        Self::new_from_child(child, port, chain_id)
    }

    pub fn fork(&self) -> Result<Self, String> {
        let port = unused_tcp_port()?;
        let binary = match cfg!(windows) {
            true => "ganache.cmd",
            false => "ganache",
        };
        let child = Command::new(binary)
            .stdout(Stdio::piped())
            .arg("--fork")
            .arg(self.endpoint())
            .arg("--port")
            .arg(format!("{}", port))
            .arg("--chain.chainId")
            .arg(format!("{}", self.chain_id))
            .spawn()
            .map_err(|e| {
                format!(
                    "Failed to start {}. \
                    Is it installed and available on $PATH? Error: {:?}",
                    binary, e
                )
            })?;

        Self::new_from_child(child, port, self.chain_id)
    }

    /// Returns the endpoint that this instance is listening on.
    pub fn endpoint(&self) -> String {
        endpoint(self.port)
    }

    /// Returns the chain id of the ganache instance
    pub fn chain_id(&self) -> u64 {
        self.chain_id
    }

    /// Increase the timestamp on future blocks by `increase_by` seconds.
    pub async fn increase_time(&self, increase_by: u64) -> Result<(), String> {
        self.web3
            .transport()
            .execute("evm_increaseTime", vec![json!(increase_by)])
            .await
            .map(|_json_value| ())
            .map_err(|e| format!("Failed to increase time on EVM (is this ganache?): {:?}", e))
    }

    /// Returns the current block number, as u64
    pub async fn block_number(&self) -> Result<u64, String> {
        self.web3
            .eth()
            .block_number()
            .await
            .map(|v| v.as_u64())
            .map_err(|e| format!("Failed to get block number: {:?}", e))
    }

    /// Mines a single block.
    pub async fn evm_mine(&self) -> Result<(), String> {
        self.web3
            .transport()
            .execute("evm_mine", vec![])
            .await
            .map(|_| ())
            .map_err(|_| {
                "utils should mine new block with evm_mine (only works with ganache!)".to_string()
            })
    }
}

fn endpoint(port: u16) -> String {
    format!("http://localhost:{}", port)
}

impl Drop for GanacheInstance {
    fn drop(&mut self) {
        if cfg!(windows) {
            // Calling child.kill() in Windows will only kill the process
            // that spawned ganache, leaving the actual ganache process
            // intact. You have to kill the whole process tree. What's more,
            // if you don't spawn ganache with --keepAliveTimeout=0, Windows
            // will STILL keep the server running even after you've ended
            // the process tree and it's disappeared from the task manager.
            // Unbelievable...
            Command::new("taskkill")
                .arg("/pid")
                .arg(self.child.id().to_string())
                .arg("/T")
                .arg("/F")
                .output()
                .expect("failed to execute taskkill");
        } else {
            let _ = self.child.kill();
        }
    }
}
<commit_msg>Fix ganache test endpoint for ipv6 machines (#3563)<commit_after>use serde_json::json;
use std::io::prelude::*;
use std::io::BufReader;
use std::process::{Child, Command, Stdio};
use std::time::{Duration, Instant};
use unused_port::unused_tcp_port;
use web3::{transports::Http, Transport, Web3};

/// How long we will wait for ganache to indicate that it is ready.
const GANACHE_STARTUP_TIMEOUT_MILLIS: u64 = 10_000;

/// Provides a dedicated `ganachi-cli` instance with a connected `Web3` instance.
///
/// Requires that `ganachi-cli` is installed and available on `PATH`.
pub struct GanacheInstance {
    pub port: u16,
    child: Child,
    pub web3: Web3<Http>,
    chain_id: u64,
}

impl GanacheInstance {
    fn new_from_child(mut child: Child, port: u16, chain_id: u64) -> Result<Self, String> {
        let stdout = child
            .stdout
            .ok_or("Unable to get stdout for ganache child process")?;

        let start = Instant::now();
        let mut reader = BufReader::new(stdout);
        loop {
            if start + Duration::from_millis(GANACHE_STARTUP_TIMEOUT_MILLIS) <= Instant::now() {
                break Err(
                    "Timed out waiting for ganache to start. Is ganache installed?".to_string(),
                );
            }

            let mut line = String::new();
            if let Err(e) = reader.read_line(&mut line) {
                break Err(format!("Failed to read line from ganache process: {:?}", e));
            } else if line.starts_with("RPC Listening on") {
                break Ok(());
            } else {
                continue;
            }
        }?;

        let transport = Http::new(&endpoint(port)).map_err(|e| {
            format!(
                "Failed to start HTTP transport connected to ganache: {:?}",
                e
            )
        })?;
        let web3 = Web3::new(transport);

        child.stdout = Some(reader.into_inner());

        Ok(Self {
            port,
            child,
            web3,
            chain_id,
        })
    }

    /// Start a new `ganache` process, waiting until it indicates that it is ready to accept
    /// RPC connections.
    pub fn new(chain_id: u64) -> Result<Self, String> {
        let port = unused_tcp_port()?;
        let binary = match cfg!(windows) {
            true => "ganache.cmd",
            false => "ganache",
        };
        let child = Command::new(binary)
            .stdout(Stdio::piped())
            .arg("--defaultBalanceEther")
            .arg("1000000000")
            .arg("--gasLimit")
            .arg("1000000000")
            .arg("--accounts")
            .arg("10")
            .arg("--port")
            .arg(format!("{}", port))
            .arg("--mnemonic")
            .arg("\"vast thought differ pull jewel broom cook wrist tribe word before omit\"")
            .arg("--chain.chainId")
            .arg(format!("{}", chain_id))
            .spawn()
            .map_err(|e| {
                format!(
                    "Failed to start {}. \
                    Is it installed and available on $PATH? Error: {:?}",
                    binary, e
                )
            })?;

        Self::new_from_child(child, port, chain_id)
    }

    pub fn fork(&self) -> Result<Self, String> {
        let port = unused_tcp_port()?;
        let binary = match cfg!(windows) {
            true => "ganache.cmd",
            false => "ganache",
        };
        let child = Command::new(binary)
            .stdout(Stdio::piped())
            .arg("--fork")
            .arg(self.endpoint())
            .arg("--port")
            .arg(format!("{}", port))
            .arg("--chain.chainId")
            .arg(format!("{}", self.chain_id))
            .spawn()
            .map_err(|e| {
                format!(
                    "Failed to start {}. \
                    Is it installed and available on $PATH? Error: {:?}",
                    binary, e
                )
            })?;

        Self::new_from_child(child, port, self.chain_id)
    }

    /// Returns the endpoint that this instance is listening on.
    pub fn endpoint(&self) -> String {
        endpoint(self.port)
    }

    /// Returns the chain id of the ganache instance
    pub fn chain_id(&self) -> u64 {
        self.chain_id
    }

    /// Increase the timestamp on future blocks by `increase_by` seconds.
    pub async fn increase_time(&self, increase_by: u64) -> Result<(), String> {
        self.web3
            .transport()
            .execute("evm_increaseTime", vec![json!(increase_by)])
            .await
            .map(|_json_value| ())
            .map_err(|e| format!("Failed to increase time on EVM (is this ganache?): {:?}", e))
    }

    /// Returns the current block number, as u64
    pub async fn block_number(&self) -> Result<u64, String> {
        self.web3
            .eth()
            .block_number()
            .await
            .map(|v| v.as_u64())
            .map_err(|e| format!("Failed to get block number: {:?}", e))
    }

    /// Mines a single block.
    pub async fn evm_mine(&self) -> Result<(), String> {
        self.web3
            .transport()
            .execute("evm_mine", vec![])
            .await
            .map(|_| ())
            .map_err(|_| {
                "utils should mine new block with evm_mine (only works with ganache!)".to_string()
            })
    }
}

fn endpoint(port: u16) -> String {
    format!("http://127.0.0.1:{}", port)
}

impl Drop for GanacheInstance {
    fn drop(&mut self) {
        if cfg!(windows) {
            // Calling child.kill() in Windows will only kill the process
            // that spawned ganache, leaving the actual ganache process
            // intact. You have to kill the whole process tree. What's more,
            // if you don't spawn ganache with --keepAliveTimeout=0, Windows
            // will STILL keep the server running even after you've ended
            // the process tree and it's disappeared from the task manager.
            // Unbelievable...
            Command::new("taskkill")
                .arg("/pid")
                .arg(self.child.id().to_string())
                .arg("/T")
                .arg("/F")
                .output()
                .expect("failed to execute taskkill");
        } else {
            let _ = self.child.kill();
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt::{self, Display};
use std::str::FromStr;

use self::Charset::*;

/// A Mime charset.
///
/// The string representation is normalized to upper case.
///
/// See <http://www.iana.org/assignments/character-sets/character-sets.xhtml>.
#[derive(Clone, Debug, PartialEq)]
#[allow(non_camel_case_types)]
pub enum Charset {
    /// US ASCII
    Us_Ascii,
    /// ISO-8859-1
    Iso_8859_1,
    /// ISO-8859-2
    Iso_8859_2,
    /// ISO-8859-3
    Iso_8859_3,
    /// ISO-8859-4
    Iso_8859_4,
    /// ISO-8859-5
    Iso_8859_5,
    /// ISO-8859-6
    Iso_8859_6,
    /// ISO-8859-7
    Iso_8859_7,
    /// ISO-8859-8
    Iso_8859_8,
    /// ISO-8859-9
    Iso_8859_9,
    /// ISO-8859-10
    Iso_8859_10,
    /// Shift_JIS
    Shift_Jis,
    /// EUC-JP
    Euc_Jp,
    /// ISO-2022-KR
    Iso_2022_Kr,
    /// EUC-KR
    Euc_Kr,
    /// ISO-2022-JP
    Iso_2022_Jp,
    /// ISO-2022-JP-2
    Iso_2022_Jp_2,
    /// ISO-8859-6-E
    Iso_8859_6_E,
    /// ISO-8859-6-I
    Iso_8859_6_I,
    /// ISO-8859-8-E
    Iso_8859_8_E,
    /// ISO-8859-8-I
    Iso_8859_8_I,
    /// GB2312
    Gb2312,
    /// Big5
    Big5,
    /// KOI8-R
    Koi8_R,
    /// An arbitrary charset specified as a string
    Ext(String),
}

impl Charset {
    fn label(&self) -> &str {
        match *self {
            Us_Ascii => "US-ASCII",
            Iso_8859_1 => "ISO-8859-1",
            Iso_8859_2 => "ISO-8859-2",
            Iso_8859_3 => "ISO-8859-3",
            Iso_8859_4 => "ISO-8859-4",
            Iso_8859_5 => "ISO-8859-5",
            Iso_8859_6 => "ISO-8859-6",
            Iso_8859_7 => "ISO-8859-7",
            Iso_8859_8 => "ISO-8859-8",
            Iso_8859_9 => "ISO-8859-9",
            Iso_8859_10 => "ISO-8859-10",
            Shift_Jis => "Shift-JIS",
            Euc_Jp => "EUC-JP",
            Iso_2022_Kr => "ISO-2022-KR",
            Euc_Kr => "EUC-KR",
            Iso_2022_Jp => "ISO-2022-JP",
            Iso_2022_Jp_2 => "ISO-2022-JP-2",
            Iso_8859_6_E => "ISO-8859-6-E",
            Iso_8859_6_I => "ISO-8859-6-I",
            Iso_8859_8_E => "ISO-8859-8-E",
            Iso_8859_8_I => "ISO-8859-8-I",
            Gb2312 => "GB2312",
            Big5 => "big5",
            Koi8_R => "KOI8-R",
            Ext(ref s) => s,
        }
    }
}

impl Display for Charset {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(self.label())
    }
}

impl FromStr for Charset {
    type Err = crate::Error;

    fn from_str(s: &str) -> Result<Charset, crate::Error> {
        Ok(match s.to_ascii_uppercase().as_ref() {
            "US-ASCII" => Us_Ascii,
            "ISO-8859-1" => Iso_8859_1,
            "ISO-8859-2" => Iso_8859_2,
            "ISO-8859-3" => Iso_8859_3,
            "ISO-8859-4" => Iso_8859_4,
            "ISO-8859-5" => Iso_8859_5,
            "ISO-8859-6" => Iso_8859_6,
            "ISO-8859-7" => Iso_8859_7,
            "ISO-8859-8" => Iso_8859_8,
            "ISO-8859-9" => Iso_8859_9,
            "ISO-8859-10" => Iso_8859_10,
            "SHIFT-JIS" => Shift_Jis,
            "EUC-JP" => Euc_Jp,
            "ISO-2022-KR" => Iso_2022_Kr,
            "EUC-KR" => Euc_Kr,
            "ISO-2022-JP" => Iso_2022_Jp,
            "ISO-2022-JP-2" => Iso_2022_Jp_2,
            "ISO-8859-6-E" => Iso_8859_6_E,
            "ISO-8859-6-I" => Iso_8859_6_I,
            "ISO-8859-8-E" => Iso_8859_8_E,
            "ISO-8859-8-I" => Iso_8859_8_I,
            "GB2312" => Gb2312,
            "big5" => Big5,
            "KOI8-R" => Koi8_R,
            s => Ext(s.to_owned()),
        })
    }
}

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

    #[test]
    fn test_parse() {
        assert_eq!(Us_Ascii, "us-ascii".parse().unwrap());
        assert_eq!(Us_Ascii, "US-Ascii".parse().unwrap());
        assert_eq!(Us_Ascii, "US-ASCII".parse().unwrap());
        assert_eq!(Shift_Jis, "Shift-JIS".parse().unwrap());
        assert_eq!(Ext("ABCD".to_owned()), "abcd".parse().unwrap());
    }

    #[test]
    fn test_display() {
        assert_eq!("US-ASCII", format!("{}", Us_Ascii));
        assert_eq!("ABCD", format!("{}", Ext("ABCD".to_owned())));
    }
}
<commit_msg>fix big5 charset parsing<commit_after>use std::fmt::{self, Display};
use std::str::FromStr;

use self::Charset::*;

/// A Mime charset.
///
/// The string representation is normalized to upper case.
///
/// See <http://www.iana.org/assignments/character-sets/character-sets.xhtml>.
#[derive(Clone, Debug, PartialEq)]
#[allow(non_camel_case_types)]
pub enum Charset {
    /// US ASCII
    Us_Ascii,
    /// ISO-8859-1
    Iso_8859_1,
    /// ISO-8859-2
    Iso_8859_2,
    /// ISO-8859-3
    Iso_8859_3,
    /// ISO-8859-4
    Iso_8859_4,
    /// ISO-8859-5
    Iso_8859_5,
    /// ISO-8859-6
    Iso_8859_6,
    /// ISO-8859-7
    Iso_8859_7,
    /// ISO-8859-8
    Iso_8859_8,
    /// ISO-8859-9
    Iso_8859_9,
    /// ISO-8859-10
    Iso_8859_10,
    /// Shift_JIS
    Shift_Jis,
    /// EUC-JP
    Euc_Jp,
    /// ISO-2022-KR
    Iso_2022_Kr,
    /// EUC-KR
    Euc_Kr,
    /// ISO-2022-JP
    Iso_2022_Jp,
    /// ISO-2022-JP-2
    Iso_2022_Jp_2,
    /// ISO-8859-6-E
    Iso_8859_6_E,
    /// ISO-8859-6-I
    Iso_8859_6_I,
    /// ISO-8859-8-E
    Iso_8859_8_E,
    /// ISO-8859-8-I
    Iso_8859_8_I,
    /// GB2312
    Gb2312,
    /// Big5
    Big5,
    /// KOI8-R
    Koi8_R,
    /// An arbitrary charset specified as a string
    Ext(String),
}

impl Charset {
    fn label(&self) -> &str {
        match *self {
            Us_Ascii => "US-ASCII",
            Iso_8859_1 => "ISO-8859-1",
            Iso_8859_2 => "ISO-8859-2",
            Iso_8859_3 => "ISO-8859-3",
            Iso_8859_4 => "ISO-8859-4",
            Iso_8859_5 => "ISO-8859-5",
            Iso_8859_6 => "ISO-8859-6",
            Iso_8859_7 => "ISO-8859-7",
            Iso_8859_8 => "ISO-8859-8",
            Iso_8859_9 => "ISO-8859-9",
            Iso_8859_10 => "ISO-8859-10",
            Shift_Jis => "Shift-JIS",
            Euc_Jp => "EUC-JP",
            Iso_2022_Kr => "ISO-2022-KR",
            Euc_Kr => "EUC-KR",
            Iso_2022_Jp => "ISO-2022-JP",
            Iso_2022_Jp_2 => "ISO-2022-JP-2",
            Iso_8859_6_E => "ISO-8859-6-E",
            Iso_8859_6_I => "ISO-8859-6-I",
            Iso_8859_8_E => "ISO-8859-8-E",
            Iso_8859_8_I => "ISO-8859-8-I",
            Gb2312 => "GB2312",
            Big5 => "Big5",
            Koi8_R => "KOI8-R",
            Ext(ref s) => s,
        }
    }
}

impl Display for Charset {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(self.label())
    }
}

impl FromStr for Charset {
    type Err = crate::Error;

    fn from_str(s: &str) -> Result<Charset, crate::Error> {
        Ok(match s.to_ascii_uppercase().as_ref() {
            "US-ASCII" => Us_Ascii,
            "ISO-8859-1" => Iso_8859_1,
            "ISO-8859-2" => Iso_8859_2,
            "ISO-8859-3" => Iso_8859_3,
            "ISO-8859-4" => Iso_8859_4,
            "ISO-8859-5" => Iso_8859_5,
            "ISO-8859-6" => Iso_8859_6,
            "ISO-8859-7" => Iso_8859_7,
            "ISO-8859-8" => Iso_8859_8,
            "ISO-8859-9" => Iso_8859_9,
            "ISO-8859-10" => Iso_8859_10,
            "SHIFT-JIS" => Shift_Jis,
            "EUC-JP" => Euc_Jp,
            "ISO-2022-KR" => Iso_2022_Kr,
            "EUC-KR" => Euc_Kr,
            "ISO-2022-JP" => Iso_2022_Jp,
            "ISO-2022-JP-2" => Iso_2022_Jp_2,
            "ISO-8859-6-E" => Iso_8859_6_E,
            "ISO-8859-6-I" => Iso_8859_6_I,
            "ISO-8859-8-E" => Iso_8859_8_E,
            "ISO-8859-8-I" => Iso_8859_8_I,
            "GB2312" => Gb2312,
            "BIG5" => Big5,
            "KOI8-R" => Koi8_R,
            s => Ext(s.to_owned()),
        })
    }
}

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

    #[test]
    fn test_parse() {
        assert_eq!(Us_Ascii, "us-ascii".parse().unwrap());
        assert_eq!(Us_Ascii, "US-Ascii".parse().unwrap());
        assert_eq!(Us_Ascii, "US-ASCII".parse().unwrap());
        assert_eq!(Shift_Jis, "Shift-JIS".parse().unwrap());
        assert_eq!(Ext("ABCD".to_owned()), "abcd".parse().unwrap());
    }

    #[test]
    fn test_display() {
        assert_eq!("US-ASCII", format!("{}", Us_Ascii));
        assert_eq!("ABCD", format!("{}", Ext("ABCD".to_owned())));
    }
}
<|endoftext|>


<commit_before>//! Debug tracing macros.
//!
//! This module defines the `dbg!` macro which works like `println!` except it writes to the
//! Cretonne tracing output file if enabled.
//!
//! Tracing can be enabled by setting the `CRETONNE_DBG` environment variable to something
/// other than `0`.
///
/// The output will appear in files named `cretonne.dbg.*`, where the suffix is named after the
/// thread doing the logging.

use std::ascii::AsciiExt;
use std::cell::RefCell;
use std::env;
use std::ffi::OsStr;
use std::fmt;
use std::fs::File;
use std::io::{self, Write};
use std::sync::atomic;
use std::thread;

static STATE: atomic::AtomicIsize = atomic::ATOMIC_ISIZE_INIT;

/// Is debug tracing enabled?
///
/// Debug tracing can be enabled by setting the `CRETONNE_DBG` environment variable to something
/// other than `0`.
///
/// This inline function turns into a constant `false` when debug assertions are disabled.
#[inline]
pub fn enabled() -> bool {
    if cfg!(debug_assertions) {
        match STATE.load(atomic::Ordering::Relaxed) {
            0 => initialize(),
            s => s > 0,
        }
    } else {
        false
    }
}

/// Initialize `STATE` from the environment variable.
fn initialize() -> bool {
    let enable = match env::var_os("CRETONNE_DBG") {
        Some(s) => s != OsStr::new("0"),
        None => false,
    };

    if enable {
        STATE.store(1, atomic::Ordering::Relaxed);
    } else {
        STATE.store(-1, atomic::Ordering::Relaxed);
    }

    enable
}

thread_local! {
    static WRITER : RefCell<io::BufWriter<File>> = RefCell::new(open_file());
}

/// Write a line with the given format arguments.
///
/// This is for use by the `dbg!` macro.
pub fn writeln_with_format_args(args: fmt::Arguments) -> io::Result<()> {
    WRITER.with(|rc| {
        let mut w = rc.borrow_mut();
        writeln!(*w, "{}", args)?;
        w.flush()
    })
}

/// Open the tracing file for the current thread.
fn open_file() -> io::BufWriter<File> {
    let file = match thread::current().name() {
        None => File::create("cretonne.dbg"),
        Some(name) => {
            let mut path = "cretonne.dbg.".to_owned();
            for ch in name.chars() {
                if ch.is_ascii() && ch.is_alphanumeric() {
                    path.push(ch);
                }
            }
            File::create(path)
        }
    }.expect("Can't open tracing file");
    io::BufWriter::new(file)
}

/// Write a line to the debug trace file if tracing is enabled.
///
/// Arguments are the same as for `printf!`.
#[macro_export]
macro_rules! dbg {
    ($($arg:tt)+) => {
        if $crate::dbg::enabled() {
            // Drop the error result so we don't get compiler errors for ignoring it.
            // What are you going to do, log the error?
            $crate::dbg::writeln_with_format_args(format_args!($($arg)+)).ok();
        }
    }
}

/// Helper for printing lists.
pub struct DisplayList<'a, T>(pub &'a [T])
where
    T: 'a + fmt::Display;

impl<'a, T> fmt::Display for DisplayList<'a, T>
where
    T: 'a + fmt::Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.0.split_first() {
            None => write!(f, "[]"),
            Some((first, rest)) => {
                write!(f, "[{}", first)?;
                for x in rest {
                    write!(f, ", {}", x)?;
                }
                write!(f, "]")
            }
        }
    }
}
<commit_msg>Use the ThreadId to name cretonne.dbg in unnamed threads.<commit_after>//! Debug tracing macros.
//!
//! This module defines the `dbg!` macro which works like `println!` except it writes to the
//! Cretonne tracing output file if enabled.
//!
//! Tracing can be enabled by setting the `CRETONNE_DBG` environment variable to something
/// other than `0`.
///
/// The output will appear in files named `cretonne.dbg.*`, where the suffix is named after the
/// thread doing the logging.

use std::cell::RefCell;
use std::env;
use std::ffi::OsStr;
use std::fmt;
use std::fs::File;
use std::io::{self, Write};
use std::sync::atomic;
use std::thread;

static STATE: atomic::AtomicIsize = atomic::ATOMIC_ISIZE_INIT;

/// Is debug tracing enabled?
///
/// Debug tracing can be enabled by setting the `CRETONNE_DBG` environment variable to something
/// other than `0`.
///
/// This inline function turns into a constant `false` when debug assertions are disabled.
#[inline]
pub fn enabled() -> bool {
    if cfg!(debug_assertions) {
        match STATE.load(atomic::Ordering::Relaxed) {
            0 => initialize(),
            s => s > 0,
        }
    } else {
        false
    }
}

/// Initialize `STATE` from the environment variable.
fn initialize() -> bool {
    let enable = match env::var_os("CRETONNE_DBG") {
        Some(s) => s != OsStr::new("0"),
        None => false,
    };

    if enable {
        STATE.store(1, atomic::Ordering::Relaxed);
    } else {
        STATE.store(-1, atomic::Ordering::Relaxed);
    }

    enable
}

thread_local! {
    static WRITER : RefCell<io::BufWriter<File>> = RefCell::new(open_file());
}

/// Write a line with the given format arguments.
///
/// This is for use by the `dbg!` macro.
pub fn writeln_with_format_args(args: fmt::Arguments) -> io::Result<()> {
    WRITER.with(|rc| {
        let mut w = rc.borrow_mut();
        writeln!(*w, "{}", args)?;
        w.flush()
    })
}

/// Open the tracing file for the current thread.
fn open_file() -> io::BufWriter<File> {
    let curthread = thread::current();
    let tmpstr;
    let mut path = "cretonne.dbg.".to_owned();
    path.extend(
        match curthread.name() {
            Some(name) => name.chars(),
            // The thread is unnamed, so use the thread ID instead.
            None => {
                tmpstr = format!("{:?}", curthread.id());
                tmpstr.chars()
            }
        }.filter(|ch| ch.is_alphanumeric() || *ch == '-' || *ch == '_'),
    );
    let file = File::create(path).expect("Can't open tracing file");
    io::BufWriter::new(file)
}

/// Write a line to the debug trace file if tracing is enabled.
///
/// Arguments are the same as for `printf!`.
#[macro_export]
macro_rules! dbg {
    ($($arg:tt)+) => {
        if $crate::dbg::enabled() {
            // Drop the error result so we don't get compiler errors for ignoring it.
            // What are you going to do, log the error?
            $crate::dbg::writeln_with_format_args(format_args!($($arg)+)).ok();
        }
    }
}

/// Helper for printing lists.
pub struct DisplayList<'a, T>(pub &'a [T])
where
    T: 'a + fmt::Display;

impl<'a, T> fmt::Display for DisplayList<'a, T>
where
    T: 'a + fmt::Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.0.split_first() {
            None => write!(f, "[]"),
            Some((first, rest)) => {
                write!(f, "[{}", first)?;
                for x in rest {
                    write!(f, ", {}", x)?;
                }
                write!(f, "]")
            }
        }
    }
}
<|endoftext|>