<commit_before>use super::Spec;

use std::cmp::PartialEq;
use std::fmt::Debug;

pub trait ContainingIntoIterSpec<'s, T: 's>
    where T: Debug + PartialEq
{
    fn contains(&mut self, expected_value: &'s T) -> &mut Self;
    fn equals_iterator<E: 's>(&mut self, expected_iter: &'s E) -> &mut Self
        where E: Iterator<Item = &'s T> + Clone;
}

pub trait ContainingIteratorSpec<'s, T: 's>
    where T: Debug + PartialEq
{
    fn contains(&mut self, expected_value: &'s T) -> &mut Self;
    fn equals_iterator<E: 's>(&mut self, expected_iter: &'s E) -> &mut Self
        where E: Iterator<Item = &'s T> + Clone;
}

pub trait MappingIterSpec<'s, T: 's>
    where T: Debug
{
    fn matching_contains<F>(&mut self, matcher: F) -> &mut Self where F: Fn(&'s T) -> bool;
    fn mapped_contains<F, M: 's>(&mut self, mapping_function: F, expected_value: &M) -> &mut Self
        where M: Debug + PartialEq,
              F: Fn(&'s T) -> M;
}

impl<'s, T: 's, I> ContainingIntoIterSpec<'s, T> for Spec<'s, I>
    where T: Debug + PartialEq,
          &'s I: IntoIterator<Item = &'s T>
{
    /// Asserts that the subject contains the provided value. The subject must implement
    /// `IntoIterator`, and the contained type must implement `PartialEq` and `Debug`.
    ///
    /// ```rust,ignore
    /// let test_vec = vec![1,2,3];
    /// assert_that(&test_vec).contains(&2);
    /// ```
    fn contains(&mut self, expected_value: &'s T) -> &mut Self {
        let subject_iter = self.subject.into_iter();
        check_iterator_contains(self, subject_iter, &expected_value);

        self
    }

    /// Asserts that the subject is equal to provided iterator. The subject must implement
    /// `IntoIterator`, the contained type must implement `PartialEq` and `Debug` and the expected
    /// value must implement Iterator and Clone.
    ///
    /// ```rust,ignore
    /// let expected_vec = vec![1,2,3];
    /// let test_vec = vec![1,2,3];
    /// assert_that(&test_vec).equals_iterator(&expected_vec.iter());
    /// ```
    fn equals_iterator<E: 's>(&mut self, expected_iter: &'s E) -> &mut Self
        where E: Iterator<Item = &'s T> + Clone
    {
        compare_iterators(self, self.subject.into_iter(), expected_iter.clone());

        self
    }
}

impl<'s, T: 's, I> ContainingIteratorSpec<'s, T> for Spec<'s, I>
    where T: Debug + PartialEq,
          I: Iterator<Item = &'s T> + Clone
{
    /// Asserts that the iterable subject contains the provided value. The subject must implement
    /// `Iterator`, and the contained type must implement `PartialEq` and `Debug`.
    ///
    /// ```rust,ignore
    /// let test_vec = vec![1,2,3];
    /// assert_that(&test_vec.iter()).contains(&2);
    /// ```
    fn contains(&mut self, expected_value: &'s T) -> &mut Self {
        let subject_iter = self.subject.clone();
        check_iterator_contains(self, subject_iter, &expected_value);

        self
    }

    /// Asserts that the iterable subject is equal to provided iterator. The subject must implement
    /// `Iterator`, the contained type must implement `PartialEq` and `Debug` and the expected
    /// value must implement Iterator and Clone.
    ///
    /// ```rust,ignore
    /// let expected_vec = vec![1,2,3];
    /// let test_vec = vec![1,2,3];
    /// assert_that(&test_vec.iter()).equals_iterator(&expected_vec.iter());
    /// ```
    fn equals_iterator<E: 's>(&mut self, expected_iter: &'s E) -> &mut Self
        where E: Iterator<Item = &'s T> + Clone
    {
        compare_iterators(self, self.subject.clone(), expected_iter.clone());

        self
    }
}

impl<'s, T: 's, I> MappingIterSpec<'s, T> for Spec<'s, I>
    where T: Debug,
          &'s I: IntoIterator<Item = &'s T>
{
    /// Maps the values of the subject before asserting that the mapped subject contains the
    /// provided value. The subject must implement IntoIterator, and the type of the mapped
    /// value must implement `PartialEq`.
    ///
    /// NOTE: The panic message will refer to the mapped values rather than the values present in
    /// the original subject.
    ///
    /// ```rust,ignore
    /// #[derive(PartialEq, Debug)]
    /// struct Simple {
    ///     pub val: usize,
    /// }
    ///
    /// ...
    ///
    /// assert_that(&vec![Simple { val: 1 }, Simple { val: 2 } ]).mapped_contains(|x| &x.val, &2);
    /// ```
    fn mapped_contains<F, M: 's>(&mut self, mapping_function: F, expected_value: &M) -> &mut Self
        where M: Debug + PartialEq,
              F: Fn(&'s T) -> M
    {
        let subject = self.subject;

        let mapped_vec: Vec<M> = subject.into_iter().map(mapping_function).collect();
        if mapped_vec.contains(&expected_value) {
            return self;
        }

        panic_unmatched(self, expected_value, mapped_vec);
        unreachable!();
    }

    /// Asserts that the subject contains a matching item by using the provided function.
    /// The subject must implement `IntoIterator`, and the contained type must implement `Debug`.
    ///
    /// ```rust,ignore
    /// let mut test_into_iter = LinkedList::new();
    /// test_into_iter.push_back(TestEnum::Bad);
    /// test_into_iter.push_back(TestEnum::Good);
    /// test_into_iter.push_back(TestEnum::Bad);
    ///
    /// assert_that(&test_into_iter).matching_contains(|val| {
    ///     match val {
    ///         &TestEnum::Good => true,
    ///         _ => false
    ///     }
    /// });
    /// ```
    fn matching_contains<F>(&mut self, matcher: F) -> &mut Self
        where F: Fn(&'s T) -> bool
    {
        let mut actual = Vec::new();
        for x in self.subject {
            if matcher(x) {
                return self;
            } else {
                actual.push(x);
            }
        }
        self.fail_with_message(format!("expectation failed for iterator with values <{:?}>",
                                       actual));

        unreachable!();
    }
}

fn check_iterator_contains<T, V, I>(spec: &mut Spec<T>, actual_iter: I, expected_value: &V)
    where V: PartialEq + Debug,
          I: Iterator<Item = V>
{
    let mut actual = Vec::new();

    for x in actual_iter {
        if expected_value.eq(&x) {
            return;
        } else {
            actual.push(x);
        }
    }

    panic_unmatched(spec, expected_value, actual);
}

fn compare_iterators<T, V, I, E>(spec: &mut Spec<T>, actual_iter: I, expected_iter: E)
    where V: PartialEq + Debug,
          I: Iterator<Item = V>,
          E: Iterator<Item = V>
{
    let mut actual_iter = actual_iter;
    let mut expected_iter = expected_iter;

    let mut read_subject = vec![];
    let mut read_expected = vec![];

    loop {
        match (actual_iter.next(), expected_iter.next()) {
            (Some(actual), Some(expected)) => {
                if !&actual.eq(&expected) {
                    spec.with_expected(format!("Iterator item of <{:?}> (read <{:?}>)",
                                               expected,
                                               read_expected))
                        .with_actual(format!("Iterator item of <{:?}> (read <{:?}>)",
                                             actual,
                                             read_subject))
                        .fail();

                    unreachable!();
                }

                read_subject.push(actual);
                read_expected.push(expected);
            }
            (Some(actual), None) => {
                spec.with_expected(format!("Completed iterator (read <{:?}>)", read_expected))
                    .with_actual(format!("Iterator item of <{:?}> (read <{:?}>",
                                         actual,
                                         read_subject))
                    .fail();

                unreachable!();
            }
            (None, Some(expected)) => {
                spec.with_expected(format!("Iterator item of <{:?}> (read <{:?}>",
                                           expected,
                                           read_expected))
                    .with_actual(format!("Completed iterator (read <{:?}>", read_subject))
                    .fail();

                unreachable!();
            }
            (None, None) => {
                break;
            }
        }
    }
}

fn panic_unmatched<T, E: Debug, A: Debug>(spec: &mut Spec<T>, expected: E, actual: A) {
    spec.with_expected(format!("iterator to contain <{:?}>", expected))
        .with_actual(format!("<{:?}>", actual))
        .fail();
}

#[cfg(test)]
mod tests {

    use super::super::prelude::*;
    use std::collections::LinkedList;

    #[test]
    fn should_not_panic_if_vec_contains_value() {
        let test_vec = vec![1, 2, 3];
        assert_that(&test_vec).contains(&2);
    }

    #[test]
    #[should_panic(expected = "\n\texpected: iterator to contain <5>\n\t but was: <[1, 2, 3]>")]
    fn should_panic_if_vec_does_not_contain_value() {
        let test_vec = vec![1, 2, 3];
        assert_that(&test_vec).contains(&5);
    }

    #[test]
    fn should_not_panic_if_iterable_contains_value() {
        let mut test_into_iter = LinkedList::new();
        test_into_iter.push_back(1);
        test_into_iter.push_back(2);
        test_into_iter.push_back(3);

        assert_that(&test_into_iter).contains(&2);
    }

    #[test]
    #[should_panic(expected = "\n\texpected: iterator to contain <5>\n\t but was: <[1, 2, 3]>")]
    fn should_panic_if_iterable_does_not_contain_value() {
        let mut test_into_iter = LinkedList::new();
        test_into_iter.push_back(1);
        test_into_iter.push_back(2);
        test_into_iter.push_back(3);

        assert_that(&test_into_iter).contains(&5);
    }

    #[test]
    fn should_not_panic_if_iteratable_equals_expected_iterator() {
        let expected_vec = vec![1, 2, 3];
        let test_vec = vec![1, 2, 3];

        assert_that(&test_vec).equals_iterator(&expected_vec.iter());
    }

    #[test]
    #[should_panic(expected = "\n\texpected: Iterator item of <4> (read <[1, 2]>)\
                   \n\t but was: Iterator item of <3> (read <[1, 2]>)")]
    fn should_panic_if_iteratable_does_not_equal_expected_iterator() {
        let expected_vec = vec![1, 2, 4];
        let test_vec = vec![1, 2, 3];

        assert_that(&test_vec).equals_iterator(&expected_vec.iter());
    }

    #[test]
    fn should_not_panic_if_iterator_contains_value() {
        let test_vec = vec![1, 2, 3];
        assert_that(&test_vec.iter()).contains(&2);
    }

    #[test]
    #[should_panic(expected = "\n\texpected: iterator to contain <5>\n\t but was: <[1, 2, 3]>")]
    fn should_panic_if_iterator_does_not_contain_value() {
        let test_vec = vec![1, 2, 3];
        assert_that(&test_vec.iter()).contains(&5);
    }

    #[test]
    fn should_not_panic_if_iterator_equals_expected_iterator() {
        let expected_vec = vec![1, 2, 3];
        let test_vec = vec![1, 2, 3];

        assert_that(&test_vec.iter()).equals_iterator(&expected_vec.iter());
    }

    #[test]
    #[should_panic(expected = "\n\texpected: Iterator item of <4> (read <[1, 2]>)\
                   \n\t but was: Iterator item of <3> (read <[1, 2]>)")]
    fn should_panic_if_iterator_does_not_equal_expected_iterator() {
        let expected_vec = vec![1, 2, 4];
        let test_vec = vec![1, 2, 3];

        assert_that(&test_vec.iter()).equals_iterator(&expected_vec.iter());
    }

    #[test]
    fn should_not_panic_if_iterator_matches_on_value() {
        let mut test_into_iter = LinkedList::new();
        test_into_iter.push_back(TestEnum::Bad);
        test_into_iter.push_back(TestEnum::Good);
        test_into_iter.push_back(TestEnum::Bad);

        assert_that(&test_into_iter).matching_contains(|val| {
            match val {
                &TestEnum::Good => true,
                _ => false,
            }
        });
    }

    #[test]
    #[should_panic(expected = "\n\texpectation failed for iterator with values <[Bad, Bad, Bad]>")]
    fn should_panic_if_iterator_does_not_match_on_value() {
        let mut test_into_iter = LinkedList::new();
        test_into_iter.push_back(TestEnum::Bad);
        test_into_iter.push_back(TestEnum::Bad);
        test_into_iter.push_back(TestEnum::Bad);

        assert_that(&test_into_iter).matching_contains(|val| {
            match val {
                &TestEnum::Good => true,
                _ => false,
            }
        });
    }

    #[test]
    fn should_not_panic_if_vec_contains_mapped_value() {
        let test_vec = vec![TestStruct { value: 5 }, TestStruct { value: 6 }];
        assert_that(&test_vec).mapped_contains(|val| val.value, &5);
    }

    #[test]
    #[should_panic(expected = "\n\texpected: iterator to contain <1>\n\t but was: <[5, 6]>")]
    fn should_panic_if_vec_does_not_contain_mapped_value() {
        let test_vec = vec![TestStruct { value: 5 }, TestStruct { value: 6 }];
        assert_that(&test_vec).mapped_contains(|val| val.value, &1);
    }

    #[derive(Debug, PartialEq)]
    struct TestStruct {
        pub value: u8,
    }

    #[derive(Debug)]
    enum TestEnum {
        Good,
        Bad,
    }

}
<commit_msg>Use a macro to generate the iter containing specs<commit_after>use super::Spec;

use std::cmp::PartialEq;
use std::fmt::Debug;

macro_rules! generate_iter_spec_trait {
    ($trait_name:ident) => {
        pub trait $trait_name<'s, T: 's>
            where T: Debug + PartialEq
            {
                fn contains(&mut self, expected_value: &'s T) -> &mut Self;
                fn equals_iterator<E: 's>(&mut self, expected_iter: &'s E) -> &mut Self
                    where E: Iterator<Item = &'s T> + Clone;
            }
    }
}

generate_iter_spec_trait!(ContainingIntoIterSpec);
generate_iter_spec_trait!(ContainingIteratorSpec);

pub trait MappingIterSpec<'s, T: 's>
    where T: Debug
{
    fn matching_contains<F>(&mut self, matcher: F) -> &mut Self where F: Fn(&'s T) -> bool;
    fn mapped_contains<F, M: 's>(&mut self, mapping_function: F, expected_value: &M) -> &mut Self
        where M: Debug + PartialEq,
              F: Fn(&'s T) -> M;
}

impl<'s, T: 's, I> ContainingIntoIterSpec<'s, T> for Spec<'s, I>
    where T: Debug + PartialEq,
          &'s I: IntoIterator<Item = &'s T>
{
    /// Asserts that the subject contains the provided value. The subject must implement
    /// `IntoIterator`, and the contained type must implement `PartialEq` and `Debug`.
    ///
    /// ```rust,ignore
    /// let test_vec = vec![1,2,3];
    /// assert_that(&test_vec).contains(&2);
    /// ```
    fn contains(&mut self, expected_value: &'s T) -> &mut Self {
        let subject_iter = self.subject.into_iter();
        check_iterator_contains(self, subject_iter, &expected_value);

        self
    }

    /// Asserts that the subject is equal to provided iterator. The subject must implement
    /// `IntoIterator`, the contained type must implement `PartialEq` and `Debug` and the expected
    /// value must implement Iterator and Clone.
    ///
    /// ```rust,ignore
    /// let expected_vec = vec![1,2,3];
    /// let test_vec = vec![1,2,3];
    /// assert_that(&test_vec).equals_iterator(&expected_vec.iter());
    /// ```
    fn equals_iterator<E: 's>(&mut self, expected_iter: &'s E) -> &mut Self
        where E: Iterator<Item = &'s T> + Clone
    {
        compare_iterators(self, self.subject.into_iter(), expected_iter.clone());

        self
    }
}

impl<'s, T: 's, I> ContainingIteratorSpec<'s, T> for Spec<'s, I>
    where T: Debug + PartialEq,
          I: Iterator<Item = &'s T> + Clone
{
    /// Asserts that the iterable subject contains the provided value. The subject must implement
    /// `Iterator`, and the contained type must implement `PartialEq` and `Debug`.
    ///
    /// ```rust,ignore
    /// let test_vec = vec![1,2,3];
    /// assert_that(&test_vec.iter()).contains(&2);
    /// ```
    fn contains(&mut self, expected_value: &'s T) -> &mut Self {
        let subject_iter = self.subject.clone();
        check_iterator_contains(self, subject_iter, &expected_value);

        self
    }

    /// Asserts that the iterable subject is equal to provided iterator. The subject must implement
    /// `Iterator`, the contained type must implement `PartialEq` and `Debug` and the expected
    /// value must implement Iterator and Clone.
    ///
    /// ```rust,ignore
    /// let expected_vec = vec![1,2,3];
    /// let test_vec = vec![1,2,3];
    /// assert_that(&test_vec.iter()).equals_iterator(&expected_vec.iter());
    /// ```
    fn equals_iterator<E: 's>(&mut self, expected_iter: &'s E) -> &mut Self
        where E: Iterator<Item = &'s T> + Clone
    {
        compare_iterators(self, self.subject.clone(), expected_iter.clone());

        self
    }
}

impl<'s, T: 's, I> MappingIterSpec<'s, T> for Spec<'s, I>
    where T: Debug,
          &'s I: IntoIterator<Item = &'s T>
{
    /// Maps the values of the subject before asserting that the mapped subject contains the
    /// provided value. The subject must implement IntoIterator, and the type of the mapped
    /// value must implement `PartialEq`.
    ///
    /// NOTE: The panic message will refer to the mapped values rather than the values present in
    /// the original subject.
    ///
    /// ```rust,ignore
    /// #[derive(PartialEq, Debug)]
    /// struct Simple {
    ///     pub val: usize,
    /// }
    ///
    /// ...
    ///
    /// assert_that(&vec![Simple { val: 1 }, Simple { val: 2 } ]).mapped_contains(|x| &x.val, &2);
    /// ```
    fn mapped_contains<F, M: 's>(&mut self, mapping_function: F, expected_value: &M) -> &mut Self
        where M: Debug + PartialEq,
              F: Fn(&'s T) -> M
    {
        let subject = self.subject;

        let mapped_vec: Vec<M> = subject.into_iter().map(mapping_function).collect();
        if mapped_vec.contains(&expected_value) {
            return self;
        }

        panic_unmatched(self, expected_value, mapped_vec);
        unreachable!();
    }

    /// Asserts that the subject contains a matching item by using the provided function.
    /// The subject must implement `IntoIterator`, and the contained type must implement `Debug`.
    ///
    /// ```rust,ignore
    /// let mut test_into_iter = LinkedList::new();
    /// test_into_iter.push_back(TestEnum::Bad);
    /// test_into_iter.push_back(TestEnum::Good);
    /// test_into_iter.push_back(TestEnum::Bad);
    ///
    /// assert_that(&test_into_iter).matching_contains(|val| {
    ///     match val {
    ///         &TestEnum::Good => true,
    ///         _ => false
    ///     }
    /// });
    /// ```
    fn matching_contains<F>(&mut self, matcher: F) -> &mut Self
        where F: Fn(&'s T) -> bool
    {
        let mut actual = Vec::new();
        for x in self.subject {
            if matcher(x) {
                return self;
            } else {
                actual.push(x);
            }
        }
        self.fail_with_message(format!("expectation failed for iterator with values <{:?}>",
                                       actual));

        unreachable!();
    }
}

fn check_iterator_contains<T, V, I>(spec: &mut Spec<T>, actual_iter: I, expected_value: &V)
    where V: PartialEq + Debug,
          I: Iterator<Item = V>
{
    let mut actual = Vec::new();

    for x in actual_iter {
        if expected_value.eq(&x) {
            return;
        } else {
            actual.push(x);
        }
    }

    panic_unmatched(spec, expected_value, actual);
}

fn compare_iterators<T, V, I, E>(spec: &mut Spec<T>, actual_iter: I, expected_iter: E)
    where V: PartialEq + Debug,
          I: Iterator<Item = V>,
          E: Iterator<Item = V>
{
    let mut actual_iter = actual_iter;
    let mut expected_iter = expected_iter;

    let mut read_subject = vec![];
    let mut read_expected = vec![];

    loop {
        match (actual_iter.next(), expected_iter.next()) {
            (Some(actual), Some(expected)) => {
                if !&actual.eq(&expected) {
                    spec.with_expected(format!("Iterator item of <{:?}> (read <{:?}>)",
                                               expected,
                                               read_expected))
                        .with_actual(format!("Iterator item of <{:?}> (read <{:?}>)",
                                             actual,
                                             read_subject))
                        .fail();

                    unreachable!();
                }

                read_subject.push(actual);
                read_expected.push(expected);
            }
            (Some(actual), None) => {
                spec.with_expected(format!("Completed iterator (read <{:?}>)", read_expected))
                    .with_actual(format!("Iterator item of <{:?}> (read <{:?}>",
                                         actual,
                                         read_subject))
                    .fail();

                unreachable!();
            }
            (None, Some(expected)) => {
                spec.with_expected(format!("Iterator item of <{:?}> (read <{:?}>",
                                           expected,
                                           read_expected))
                    .with_actual(format!("Completed iterator (read <{:?}>", read_subject))
                    .fail();

                unreachable!();
            }
            (None, None) => {
                break;
            }
        }
    }
}

fn panic_unmatched<T, E: Debug, A: Debug>(spec: &mut Spec<T>, expected: E, actual: A) {
    spec.with_expected(format!("iterator to contain <{:?}>", expected))
        .with_actual(format!("<{:?}>", actual))
        .fail();
}

#[cfg(test)]
mod tests {

    use super::super::prelude::*;
    use std::collections::LinkedList;

    #[test]
    fn should_not_panic_if_vec_contains_value() {
        let test_vec = vec![1, 2, 3];
        assert_that(&test_vec).contains(&2);
    }

    #[test]
    #[should_panic(expected = "\n\texpected: iterator to contain <5>\n\t but was: <[1, 2, 3]>")]
    fn should_panic_if_vec_does_not_contain_value() {
        let test_vec = vec![1, 2, 3];
        assert_that(&test_vec).contains(&5);
    }

    #[test]
    fn should_not_panic_if_iterable_contains_value() {
        let mut test_into_iter = LinkedList::new();
        test_into_iter.push_back(1);
        test_into_iter.push_back(2);
        test_into_iter.push_back(3);

        assert_that(&test_into_iter).contains(&2);
    }

    #[test]
    #[should_panic(expected = "\n\texpected: iterator to contain <5>\n\t but was: <[1, 2, 3]>")]
    fn should_panic_if_iterable_does_not_contain_value() {
        let mut test_into_iter = LinkedList::new();
        test_into_iter.push_back(1);
        test_into_iter.push_back(2);
        test_into_iter.push_back(3);

        assert_that(&test_into_iter).contains(&5);
    }

    #[test]
    fn should_not_panic_if_iteratable_equals_expected_iterator() {
        let expected_vec = vec![1, 2, 3];
        let test_vec = vec![1, 2, 3];

        assert_that(&test_vec).equals_iterator(&expected_vec.iter());
    }

    #[test]
    #[should_panic(expected = "\n\texpected: Iterator item of <4> (read <[1, 2]>)\
                   \n\t but was: Iterator item of <3> (read <[1, 2]>)")]
    fn should_panic_if_iteratable_does_not_equal_expected_iterator() {
        let expected_vec = vec![1, 2, 4];
        let test_vec = vec![1, 2, 3];

        assert_that(&test_vec).equals_iterator(&expected_vec.iter());
    }

    #[test]
    fn should_not_panic_if_iterator_contains_value() {
        let test_vec = vec![1, 2, 3];
        assert_that(&test_vec.iter()).contains(&2);
    }

    #[test]
    #[should_panic(expected = "\n\texpected: iterator to contain <5>\n\t but was: <[1, 2, 3]>")]
    fn should_panic_if_iterator_does_not_contain_value() {
        let test_vec = vec![1, 2, 3];
        assert_that(&test_vec.iter()).contains(&5);
    }

    #[test]
    fn should_not_panic_if_iterator_equals_expected_iterator() {
        let expected_vec = vec![1, 2, 3];
        let test_vec = vec![1, 2, 3];

        assert_that(&test_vec.iter()).equals_iterator(&expected_vec.iter());
    }

    #[test]
    #[should_panic(expected = "\n\texpected: Iterator item of <4> (read <[1, 2]>)\
                   \n\t but was: Iterator item of <3> (read <[1, 2]>)")]
    fn should_panic_if_iterator_does_not_equal_expected_iterator() {
        let expected_vec = vec![1, 2, 4];
        let test_vec = vec![1, 2, 3];

        assert_that(&test_vec.iter()).equals_iterator(&expected_vec.iter());
    }

    #[test]
    fn should_not_panic_if_iterator_matches_on_value() {
        let mut test_into_iter = LinkedList::new();
        test_into_iter.push_back(TestEnum::Bad);
        test_into_iter.push_back(TestEnum::Good);
        test_into_iter.push_back(TestEnum::Bad);

        assert_that(&test_into_iter).matching_contains(|val| {
            match val {
                &TestEnum::Good => true,
                _ => false,
            }
        });
    }

    #[test]
    #[should_panic(expected = "\n\texpectation failed for iterator with values <[Bad, Bad, Bad]>")]
    fn should_panic_if_iterator_does_not_match_on_value() {
        let mut test_into_iter = LinkedList::new();
        test_into_iter.push_back(TestEnum::Bad);
        test_into_iter.push_back(TestEnum::Bad);
        test_into_iter.push_back(TestEnum::Bad);

        assert_that(&test_into_iter).matching_contains(|val| {
            match val {
                &TestEnum::Good => true,
                _ => false,
            }
        });
    }

    #[test]
    fn should_not_panic_if_vec_contains_mapped_value() {
        let test_vec = vec![TestStruct { value: 5 }, TestStruct { value: 6 }];
        assert_that(&test_vec).mapped_contains(|val| val.value, &5);
    }

    #[test]
    #[should_panic(expected = "\n\texpected: iterator to contain <1>\n\t but was: <[5, 6]>")]
    fn should_panic_if_vec_does_not_contain_mapped_value() {
        let test_vec = vec![TestStruct { value: 5 }, TestStruct { value: 6 }];
        assert_that(&test_vec).mapped_contains(|val| val.value, &1);
    }

    #[derive(Debug, PartialEq)]
    struct TestStruct {
        pub value: u8,
    }

    #[derive(Debug)]
    enum TestEnum {
        Good,
        Bad,
    }

}
<|endoftext|>


<commit_before>pub trait IteratorCloneEach<'a, E, It> where E: Clone, It: Iterator<&'a E> {
    /**
Creates an iterator which will clone each element of the input iterator.
    */
    fn clone_each(self) -> CloneItems<It>;
}

impl<'a, E, It> IteratorCloneEach<'a, E, It> for It where E: Clone, It: Iterator<&'a E> {
    fn clone_each(self) -> CloneItems<It> {
        CloneItems {
            iter: self,
        }
    }
}

pub struct CloneItems<It> {
    iter: It,
}

impl<'a, E, It> Iterator<E> for CloneItems<It> where E: 'a+Clone, It: Iterator<&'a E> {
    fn next(&mut self) -> Option<E> {
        match self.iter.next() {
            None => None,
            Some(e) => Some(e.clone())
        }
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        self.iter.size_hint()
    }
}

#[test]
fn test_clone_each() {
    let it: Vec<int> = vec![1, 2, 3];
    let mut it = it.iter().clone_each();
    assert_eq!(it.next(), Some(1));
    assert_eq!(it.next(), Some(2));
    assert_eq!(it.next(), Some(3));
    assert_eq!(it.next(), None);
}

pub trait IteratorFoldl<E> {
    /**
Folds the elements of the iterator together, from left to right, using `f`.

Returns `None` if the iterator is empty.
    */
    fn foldl(self, f: |E, E| -> E) -> Option<E>;
}

impl<It, E> IteratorFoldl<E> for It where It: Iterator<E> {
    fn foldl(mut self, f: |E, E| -> E) -> Option<E> {
        let first = match self.next() {
            None => return None,
            Some(e) => e
        };

        Some(self.fold(first, f))
    }
}

#[test]
fn test_foldl() {
    let vs = vec!["a", "b", "c"];
    let vs = vs.into_iter().map(|e| e.into_string());
    assert_eq!(Some("((a, b), c)".into_string()), vs.foldl(|a,b| format!("({}, {})", a, b)));
}

pub trait IteratorFoldr<E> {
    /**
Folds the elements of the iterator together, from right to left, using `f`.

Returns `None` if the iterator is empty.
    */
    fn foldr(self, f: |E, E| -> E) -> Option<E>;
}

impl<It, E> IteratorFoldr<E> for It where It: DoubleEndedIterator<E> {
    fn foldr(mut self, f: |E, E| -> E) -> Option<E> {
        let mut last = match self.next_back() {
            None => return None,
            Some(e) => e
        };

        loop {
            match self.next_back() {
                None => break,
                Some(e) => last = f(e, last)
            }
        }

        Some(last)
    }
}

#[test]
fn test_foldr() {
    let vs = vec!["a", "b", "c"];
    let vs = vs.into_iter().map(|e| e.into_string());
    assert_eq!(Some("(a, (b, c))".into_string()), vs.foldr(|a,b| format!("({}, {})", a, b)));
}

pub trait IteratorStride<E, It> where It: Iterator<E> {
    /**
Creates an iterator which yields every `n`th element of the input iterator, including the first.
    */
    fn stride(self, n: uint) -> StrideItems<It>;
}

impl<E, It> IteratorStride<E, It> for It where It: Iterator<E> {
    fn stride(self, n: uint) -> StrideItems<It> {
        StrideItems {
            iter: self,
            stride: n
        }
    }
}

pub struct StrideItems<It> {
    iter: It,
    stride: uint,
}

impl<E, It> Iterator<E> for StrideItems<It> where It: Iterator<E> {
    fn next(&mut self) -> Option<E> {
        let v = match self.iter.next() {
            Some(v) => v,
            None => return None
        };

        for _ in range(0, self.stride - 1) {
            match self.iter.next() {
                None => break,
                _ => ()
            }
        }

        Some(v)
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        match self.iter.size_hint() {
            (lb, Some(ub)) => ((lb + self.stride - 1) / self.stride,
                                Some((ub + self.stride - 1) / self.stride)),
            (lb, None) => (lb, None)
        }
    }
}

#[test]
fn test_stride() {
    let v = vec![0i, 1, 2, 3, 4, 5, 6, 7, 8, 9];
    let mut it = v.iter().clone_each().stride(2);
    assert_eq!(it.size_hint(), (5, Some(5)));
    assert_eq!(it.next(), Some(0));
    assert_eq!(it.next(), Some(2));
    assert_eq!(it.next(), Some(4));
    assert_eq!(it.next(), Some(6));
    assert_eq!(it.next(), Some(8));
    assert_eq!(it.next(), None);

    let v = vec![0i, 1, 2, 3, 4, 5];
    let it = v.iter().clone_each().stride(3);
    assert_eq!(it.size_hint(), (2, Some(2)));

    let v = vec![0i, 1, 2, 3, 4, 5, 6];
    let it = v.iter().clone_each().stride(3);
    assert_eq!(it.size_hint(), (3, Some(3)));

    let v = vec![0i, 1, 2, 3, 4, 5, 6, 7];
    let it = v.iter().clone_each().stride(3);
    assert_eq!(it.size_hint(), (3, Some(3)));

    let v = vec![0i, 1, 2, 3, 4, 5, 6, 7, 8];
    let it = v.iter().clone_each().stride(3);
    assert_eq!(it.size_hint(), (3, Some(3)));

    let v = vec![0i, 1, 2, 3, 4, 5, 6, 7, 8, 9];
    let it = v.iter().clone_each().stride(3);
    assert_eq!(it.size_hint(), (4, Some(4)));
}
<commit_msg>Added round_robin and round_robin_longest.<commit_after>use std::cmp::min;

pub trait IteratorCloneEach<'a, E, It> where E: Clone, It: Iterator<&'a E> {
    /**
Creates an iterator which will clone each element of the input iterator.
    */
    fn clone_each(self) -> CloneItems<It>;
}

impl<'a, E, It> IteratorCloneEach<'a, E, It> for It where E: Clone, It: Iterator<&'a E> {
    fn clone_each(self) -> CloneItems<It> {
        CloneItems {
            iter: self,
        }
    }
}

pub struct CloneItems<It> {
    iter: It,
}

impl<'a, E, It> Iterator<E> for CloneItems<It> where E: 'a+Clone, It: Iterator<&'a E> {
    fn next(&mut self) -> Option<E> {
        match self.iter.next() {
            None => None,
            Some(e) => Some(e.clone())
        }
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        self.iter.size_hint()
    }
}

#[test]
fn test_clone_each() {
    let it: Vec<int> = vec![1, 2, 3];
    let mut it = it.iter().clone_each();
    assert_eq!(it.next(), Some(1));
    assert_eq!(it.next(), Some(2));
    assert_eq!(it.next(), Some(3));
    assert_eq!(it.next(), None);
}

pub trait IteratorFoldl<E> {
    /**
Folds the elements of the iterator together, from left to right, using `f`.

Returns `None` if the iterator is empty.
    */
    fn foldl(self, f: |E, E| -> E) -> Option<E>;
}

impl<It, E> IteratorFoldl<E> for It where It: Iterator<E> {
    fn foldl(mut self, f: |E, E| -> E) -> Option<E> {
        let first = match self.next() {
            None => return None,
            Some(e) => e
        };

        Some(self.fold(first, f))
    }
}

#[test]
fn test_foldl() {
    let vs = vec!["a", "b", "c"];
    let vs = vs.into_iter().map(|e| e.into_string());
    assert_eq!(Some("((a, b), c)".into_string()), vs.foldl(|a,b| format!("({}, {})", a, b)));
}

pub trait IteratorFoldr<E> {
    /**
Folds the elements of the iterator together, from right to left, using `f`.

Returns `None` if the iterator is empty.
    */
    fn foldr(self, f: |E, E| -> E) -> Option<E>;
}

impl<It, E> IteratorFoldr<E> for It where It: DoubleEndedIterator<E> {
    fn foldr(mut self, f: |E, E| -> E) -> Option<E> {
        let mut last = match self.next_back() {
            None => return None,
            Some(e) => e
        };

        loop {
            match self.next_back() {
                None => break,
                Some(e) => last = f(e, last)
            }
        }

        Some(last)
    }
}

#[test]
fn test_foldr() {
    let vs = vec!["a", "b", "c"];
    let vs = vs.into_iter().map(|e| e.into_string());
    assert_eq!(Some("(a, (b, c))".into_string()), vs.foldr(|a,b| format!("({}, {})", a, b)));
}

pub trait IteratorRoundRobin<E, It1> where It1: Iterator<E> {
    /**
Creates an iterator that alternates between yielding elements of the two input iterators.  It stops as soon as either iterator is exhausted.
    */
    fn round_robin(self, it1: It1) -> RoundRobinItems<E, Self, It1>;

    /**
Creates an iterator that alternates between yielding elements of the two input iterators.  If one iterator stops before the other, it is simply skipped.
    */
    fn round_robin_longest(self, it1: It1) -> RoundRobinLongestItems<E, Self, It1>;
}

impl<E, It0, It1> IteratorRoundRobin<E, It1> for It0 where It0: Iterator<E>, It1: Iterator<E> {
    fn round_robin(self, it1: It1) -> RoundRobinItems<E, It0, It1> {
        RoundRobinItems {
            it0: self,
            it1: it1,
            phase: 0,
        }
    }

    fn round_robin_longest(self, it1: It1) -> RoundRobinLongestItems<E, It0, It1> {
        RoundRobinLongestItems {
            it0: self,
            it1: it1,
            phase: 0,
            fused: false,
        }
    }
}

pub struct RoundRobinItems<E, It0, It1> where It0: Iterator<E>, It1: Iterator<E> {
    it0: It0,
    it1: It1,
    phase: u8,
}

impl<E, It0, It1> Iterator<E> for RoundRobinItems<E, It0, It1> where It0: Iterator<E>, It1: Iterator<E> {
    fn next(&mut self) -> Option<E> {
        match self.phase {
            0 => match self.it0.next() {
                None => None,
                e @ _ => {
                    self.phase = 1;
                    e
                }
            },
            _ => match self.it1.next() {
                None => None,
                e @ _ => {
                    self.phase = 0;
                    e
                }
            },
        }
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        match (self.it0.size_hint(), self.it1.size_hint()) {
            ((l0, None), (l1, _)) | ((l0, _), (l1, None)) => (l0+l1, None),
            ((l0, Some(u0)), (l1, Some(u1))) => (l0+l1, Some(2*min(u0, u1)))
        }
    }
}

pub struct RoundRobinLongestItems<E, It0, It1> where It0: Iterator<E>, It1: Iterator<E> {
    it0: It0,
    it1: It1,
    phase: u8,
    fused: bool,
}

impl<E, It0, It1> Iterator<E> for RoundRobinLongestItems<E, It0, It1> where It0: Iterator<E>, It1: Iterator<E> {
    fn next(&mut self) -> Option<E> {
        match (self.phase, self.fused) {
            (0, true) => match self.it0.next() {
                None => None,
                e @ _ => e,
            },
            (_, true) => match self.it1.next() {
                None => None,
                e @ _ => e,
            },
            (0, false) => match self.it0.next() {
                None => {
                    self.phase = 1;
                    self.fused = true;
                    self.next()
                },
                e @ _ => {
                    self.phase = 1;
                    e
                },
            },
            (_, false) => match self.it1.next() {
                None => {
                    self.phase = 0;
                    self.fused = true;
                    self.next()
                },
                e @ _ => {
                    self.phase = 0;
                    e
                },
            },
        }
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        match (self.it0.size_hint(), self.it1.size_hint()) {
            ((l0, None), (l1, _)) | ((l0, _), (l1, None)) => (l0+l1, None),
            ((l0, Some(u0)), (l1, Some(u1))) => (l0+l1, Some(u0+u1))
        }
    }
}

#[test]
fn test_round_robin() {
    let v0 = vec![0u, 2, 4];
    let v1 = vec![1u, 3, 5, 7];
    let mut it = v0.into_iter().round_robin(v1.into_iter());
    assert_eq!(it.next(), Some(0));
    assert_eq!(it.next(), Some(1));
    assert_eq!(it.next(), Some(2));
    assert_eq!(it.next(), Some(3));
    assert_eq!(it.next(), Some(4));
    assert_eq!(it.next(), Some(5));
    assert_eq!(it.next(), None);
}

#[test]
fn test_round_robin_longest() {
    let v0 = vec![0u, 2, 4];
    let v1 = vec![1u, 3, 5, 7];
    let mut it = v0.into_iter().round_robin_longest(v1.into_iter());
    assert_eq!(it.next(), Some(0));
    assert_eq!(it.next(), Some(1));
    assert_eq!(it.next(), Some(2));
    assert_eq!(it.next(), Some(3));
    assert_eq!(it.next(), Some(4));
    assert_eq!(it.next(), Some(5));
    assert_eq!(it.next(), Some(7));
    assert_eq!(it.next(), None);
}

pub trait IteratorStride<E, It> where It: Iterator<E> {
    /**
Creates an iterator which yields every `n`th element of the input iterator, including the first.
    */
    fn stride(self, n: uint) -> StrideItems<It>;
}

impl<E, It> IteratorStride<E, It> for It where It: Iterator<E> {
    fn stride(self, n: uint) -> StrideItems<It> {
        StrideItems {
            iter: self,
            stride: n
        }
    }
}

pub struct StrideItems<It> {
    iter: It,
    stride: uint,
}

impl<E, It> Iterator<E> for StrideItems<It> where It: Iterator<E> {
    fn next(&mut self) -> Option<E> {
        let v = match self.iter.next() {
            Some(v) => v,
            None => return None
        };

        for _ in range(0, self.stride - 1) {
            match self.iter.next() {
                None => break,
                _ => ()
            }
        }

        Some(v)
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        match self.iter.size_hint() {
            (lb, Some(ub)) => ((lb + self.stride - 1) / self.stride,
                                Some((ub + self.stride - 1) / self.stride)),
            (lb, None) => (lb, None)
        }
    }
}

#[test]
fn test_stride() {
    let v = vec![0i, 1, 2, 3, 4, 5, 6, 7, 8, 9];
    let mut it = v.iter().clone_each().stride(2);
    assert_eq!(it.size_hint(), (5, Some(5)));
    assert_eq!(it.next(), Some(0));
    assert_eq!(it.next(), Some(2));
    assert_eq!(it.next(), Some(4));
    assert_eq!(it.next(), Some(6));
    assert_eq!(it.next(), Some(8));
    assert_eq!(it.next(), None);

    let v = vec![0i, 1, 2, 3, 4, 5];
    let it = v.iter().clone_each().stride(3);
    assert_eq!(it.size_hint(), (2, Some(2)));

    let v = vec![0i, 1, 2, 3, 4, 5, 6];
    let it = v.iter().clone_each().stride(3);
    assert_eq!(it.size_hint(), (3, Some(3)));

    let v = vec![0i, 1, 2, 3, 4, 5, 6, 7];
    let it = v.iter().clone_each().stride(3);
    assert_eq!(it.size_hint(), (3, Some(3)));

    let v = vec![0i, 1, 2, 3, 4, 5, 6, 7, 8];
    let it = v.iter().clone_each().stride(3);
    assert_eq!(it.size_hint(), (3, Some(3)));

    let v = vec![0i, 1, 2, 3, 4, 5, 6, 7, 8, 9];
    let it = v.iter().clone_each().stride(3);
    assert_eq!(it.size_hint(), (4, Some(4)));
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! An owned, growable string that enforces that its contents are valid UTF-8.

use core::prelude::*;

use core::default::Default;
use core::fmt;
use core::mem;
use core::ptr;
use core::raw::Slice;

use {Collection, Mutable};
use hash;
use str;
use str::{CharRange, StrAllocating};
use vec::Vec;

/// A growable string stored as a UTF-8 encoded buffer.
#[deriving(Clone, PartialEq, PartialOrd, Eq, Ord)]
pub struct String {
    vec: Vec<u8>,
}

impl String {
    /// Creates a new string buffer initialized with the empty string.
    #[inline]
    pub fn new() -> String {
        String {
            vec: Vec::new(),
        }
    }

    /// Creates a new string buffer with the given capacity.
    #[inline]
    pub fn with_capacity(capacity: uint) -> String {
        String {
            vec: Vec::with_capacity(capacity),
        }
    }

    /// Creates a new string buffer from length, capacity, and a pointer.
    #[inline]
    pub unsafe fn from_raw_parts(length: uint, capacity: uint, ptr: *mut u8) -> String {
        String {
            vec: Vec::from_raw_parts(length, capacity, ptr),
        }
    }

    /// Creates a new string buffer from the given string.
    #[inline]
    pub fn from_str(string: &str) -> String {
        String {
            vec: Vec::from_slice(string.as_bytes())
        }
    }

    #[allow(missing_doc)]
    #[deprecated = "obsoleted by the removal of ~str"]
    #[inline]
    pub fn from_owned_str(string: String) -> String {
        string
    }

    /// Returns the vector as a string buffer, if possible, taking care not to
    /// copy it.
    ///
    /// Returns `Err` with the original vector if the vector contains invalid
    /// UTF-8.
    #[inline]
    pub fn from_utf8(vec: Vec<u8>) -> Result<String, Vec<u8>> {
        if str::is_utf8(vec.as_slice()) {
            Ok(String { vec: vec })
        } else {
            Err(vec)
        }
    }

    /// Return the underlying byte buffer, encoded as UTF-8.
    #[inline]
    pub fn into_bytes(self) -> Vec<u8> {
        self.vec
    }

    /// Pushes the given string onto this buffer; then, returns `self` so that it can be used
    /// again.
    #[inline]
    pub fn append(mut self, second: &str) -> String {
        self.push_str(second);
        self
    }

    /// Creates a string buffer by repeating a character `length` times.
    #[inline]
    pub fn from_char(length: uint, ch: char) -> String {
        if length == 0 {
            return String::new()
        }

        let mut buf = String::new();
        buf.push_char(ch);
        let size = buf.len() * length;
        buf.reserve(size);
        for _ in range(1, length) {
            buf.push_char(ch)
        }
        buf
    }

    /// Pushes the given string onto this string buffer.
    #[inline]
    pub fn push_str(&mut self, string: &str) {
        self.vec.push_all(string.as_bytes())
    }

    /// Push `ch` onto the given string `count` times.
    #[inline]
    pub fn grow(&mut self, count: uint, ch: char) {
        for _ in range(0, count) {
            self.push_char(ch)
        }
    }

    /// Returns the number of bytes that this string buffer can hold without reallocating.
    #[inline]
    pub fn byte_capacity(&self) -> uint {
        self.vec.capacity()
    }

    /// Reserves capacity for at least `extra` additional bytes in this string buffer.
    #[inline]
    pub fn reserve_additional(&mut self, extra: uint) {
        self.vec.reserve_additional(extra)
    }

    /// Reserves capacity for at least `capacity` bytes in this string buffer.
    #[inline]
    pub fn reserve(&mut self, capacity: uint) {
        self.vec.reserve(capacity)
    }

    /// Reserves capacity for exactly `capacity` bytes in this string buffer.
    #[inline]
    pub fn reserve_exact(&mut self, capacity: uint) {
        self.vec.reserve_exact(capacity)
    }

    /// Shrinks the capacity of this string buffer to match its length.
    #[inline]
    pub fn shrink_to_fit(&mut self) {
        self.vec.shrink_to_fit()
    }

    /// Adds the given character to the end of the string.
    #[inline]
    pub fn push_char(&mut self, ch: char) {
        let cur_len = self.len();
        // This may use up to 4 bytes.
        self.vec.reserve_additional(4);

        unsafe {
            // Attempt to not use an intermediate buffer by just pushing bytes
            // directly onto this string.
            let slice = Slice {
                data: self.vec.as_ptr().offset(cur_len as int),
                len: 4,
            };
            let used = ch.encode_utf8(mem::transmute(slice));
            self.vec.set_len(cur_len + used);
        }
    }

    /// Pushes the given bytes onto this string buffer. This is unsafe because it does not check
    /// to ensure that the resulting string will be valid UTF-8.
    #[inline]
    pub unsafe fn push_bytes(&mut self, bytes: &[u8]) {
        self.vec.push_all(bytes)
    }

    /// Works with the underlying buffer as a byte slice.
    #[inline]
    pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
        self.vec.as_slice()
    }

    /// Works with the underlying buffer as a mutable byte slice. Unsafe
    /// because this can be used to violate the UTF-8 property.
    #[inline]
    pub unsafe fn as_mut_bytes<'a>(&'a mut self) -> &'a mut [u8] {
        self.vec.as_mut_slice()
    }

    /// Shorten a string to the specified length (which must be <= the current length)
    #[inline]
    pub fn truncate(&mut self, len: uint) {
        assert!(self.as_slice().is_char_boundary(len));
        self.vec.truncate(len)
    }

    /// Appends a byte to this string buffer. The caller must preserve the valid UTF-8 property.
    #[inline]
    pub unsafe fn push_byte(&mut self, byte: u8) {
        self.push_bytes([byte])
    }

    /// Removes the last byte from the string buffer and returns it. Returns `None` if this string
    /// buffer is empty.
    ///
    /// The caller must preserve the valid UTF-8 property.
    #[inline]
    pub unsafe fn pop_byte(&mut self) -> Option<u8> {
        let len = self.len();
        if len == 0 {
            return None
        }

        let byte = self.as_bytes()[len - 1];
        self.vec.set_len(len - 1);
        Some(byte)
    }

    /// Removes the last character from the string buffer and returns it. Returns `None` if this
    /// string buffer is empty.
    #[inline]
    pub fn pop_char(&mut self) -> Option<char> {
        let len = self.len();
        if len == 0 {
            return None
        }

        let CharRange {ch, next} = self.as_slice().char_range_at_reverse(len);
        unsafe {
            self.vec.set_len(next);
        }
        Some(ch)
    }

    /// Removes the first byte from the string buffer and returns it. Returns `None` if this string
    /// buffer is empty.
    ///
    /// The caller must preserve the valid UTF-8 property.
    pub unsafe fn shift_byte(&mut self) -> Option<u8> {
        self.vec.shift()
    }

    /// Removes the first character from the string buffer and returns it. Returns `None` if this
    /// string buffer is empty.
    ///
    /// # Warning
    ///
    /// This is a O(n) operation as it requires copying every element in the buffer.
    pub fn shift_char (&mut self) -> Option<char> {
        let len = self.len();
        if len == 0 {
            return None
        }

        let CharRange {ch, next} = self.as_slice().char_range_at(0);
        let new_len = len - next;
        unsafe {
            ptr::copy_memory(self.vec.as_mut_ptr(), self.vec.as_ptr().offset(next as int), new_len);
            self.vec.set_len(new_len);
        }
        Some(ch)
    }

    /// Views the string buffer as a mutable sequence of bytes.
    ///
    /// Callers must preserve the valid UTF-8 property.
    pub unsafe fn as_mut_vec<'a>(&'a mut self) -> &'a mut Vec<u8> {
        &mut self.vec
    }
}

impl Collection for String {
    #[inline]
    fn len(&self) -> uint {
        self.vec.len()
    }
}

impl Mutable for String {
    #[inline]
    fn clear(&mut self) {
        self.vec.clear()
    }
}

impl FromIterator<char> for String {
    fn from_iter<I:Iterator<char>>(iterator: I) -> String {
        let mut buf = String::new();
        buf.extend(iterator);
        buf
    }
}

impl Extendable<char> for String {
    fn extend<I:Iterator<char>>(&mut self, mut iterator: I) {
        for ch in iterator {
            self.push_char(ch)
        }
    }
}

impl Str for String {
    #[inline]
    fn as_slice<'a>(&'a self) -> &'a str {
        unsafe {
            mem::transmute(self.vec.as_slice())
        }
    }
}

impl StrAllocating for String {
    #[inline]
    fn into_string(self) -> String {
        self
    }
}

impl Default for String {
    fn default() -> String {
        String::new()
    }
}

impl fmt::Show for String {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.as_slice().fmt(f)
    }
}

impl<H: hash::Writer> hash::Hash<H> for String {
    #[inline]
    fn hash(&self, hasher: &mut H) {
        self.as_slice().hash(hasher)
    }
}

impl<'a, S: Str> Equiv<S> for String {
    #[inline]
    fn equiv(&self, other: &S) -> bool {
        self.as_slice() == other.as_slice()
    }
}

impl<S: Str> Add<S, String> for String {
    fn add(&self, other: &S) -> String {
        let mut s = self.to_string();
        s.push_str(other.as_slice());
        return s;
    }
}

#[cfg(test)]
mod tests {
    use std::prelude::*;
    use test::Bencher;

    use Mutable;
    use str::{Str, StrSlice};
    use super::String;

    #[bench]
    fn bench_with_capacity(b: &mut Bencher) {
        b.iter(|| {
            String::with_capacity(100)
        });
    }

    #[bench]
    fn bench_push_str(b: &mut Bencher) {
        let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
        b.iter(|| {
            let mut r = String::new();
            r.push_str(s);
        });
    }

    #[test]
    fn test_push_bytes() {
        let mut s = String::from_str("ABC");
        unsafe {
            s.push_bytes([ 'D' as u8 ]);
        }
        assert_eq!(s.as_slice(), "ABCD");
    }

    #[test]
    fn test_push_str() {
        let mut s = String::new();
        s.push_str("");
        assert_eq!(s.as_slice().slice_from(0), "");
        s.push_str("abc");
        assert_eq!(s.as_slice().slice_from(0), "abc");
        s.push_str("ประเทศไทย中华Việt Nam");
        assert_eq!(s.as_slice().slice_from(0), "abcประเทศไทย中华Việt Nam");
    }

    #[test]
    fn test_push_char() {
        let mut data = String::from_str("ประเทศไทย中");
        data.push_char('华');
        data.push_char('b'); // 1 byte
        data.push_char('¢'); // 2 byte
        data.push_char('€'); // 3 byte
        data.push_char('𤭢'); // 4 byte
        assert_eq!(data.as_slice(), "ประเทศไทย中华b¢€𤭢");
    }

    #[test]
    fn test_pop_char() {
        let mut data = String::from_str("ประเทศไทย中华b¢€𤭢");
        assert_eq!(data.pop_char().unwrap(), '𤭢'); // 4 bytes
        assert_eq!(data.pop_char().unwrap(), '€'); // 3 bytes
        assert_eq!(data.pop_char().unwrap(), '¢'); // 2 bytes
        assert_eq!(data.pop_char().unwrap(), 'b'); // 1 bytes
        assert_eq!(data.pop_char().unwrap(), '华');
        assert_eq!(data.as_slice(), "ประเทศไทย中");
    }

    #[test]
    fn test_shift_char() {
        let mut data = String::from_str("𤭢€¢b华ประเทศไทย中");
        assert_eq!(data.shift_char().unwrap(), '𤭢'); // 4 bytes
        assert_eq!(data.shift_char().unwrap(), '€'); // 3 bytes
        assert_eq!(data.shift_char().unwrap(), '¢'); // 2 bytes
        assert_eq!(data.shift_char().unwrap(), 'b'); // 1 bytes
        assert_eq!(data.shift_char().unwrap(), '华');
        assert_eq!(data.as_slice(), "ประเทศไทย中");
    }

    #[test]
    fn test_str_truncate() {
        let mut s = String::from_str("12345");
        s.truncate(5);
        assert_eq!(s.as_slice(), "12345");
        s.truncate(3);
        assert_eq!(s.as_slice(), "123");
        s.truncate(0);
        assert_eq!(s.as_slice(), "");

        let mut s = String::from_str("12345");
        let p = s.as_slice().as_ptr();
        s.truncate(3);
        s.push_str("6");
        let p_ = s.as_slice().as_ptr();
        assert_eq!(p_, p);
    }

    #[test]
    #[should_fail]
    fn test_str_truncate_invalid_len() {
        let mut s = String::from_str("12345");
        s.truncate(6);
    }

    #[test]
    #[should_fail]
    fn test_str_truncate_split_codepoint() {
        let mut s = String::from_str("\u00FC"); // ü
        s.truncate(1);
    }

    #[test]
    fn test_str_clear() {
        let mut s = String::from_str("12345");
        s.clear();
        assert_eq!(s.len(), 0);
        assert_eq!(s.as_slice(), "");
    }

    #[test]
    fn test_str_add() {
        let a = String::from_str("12345");
        let b = a + "2";
        let b = b + String::from_str("2");
        assert_eq!(b.len(), 7);
        assert_eq!(b.as_slice(), "1234522");
    }
}
<commit_msg>auto merge of #15465 : SimonSapin/rust/patch-4, r=alexcrichton<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! An owned, growable string that enforces that its contents are valid UTF-8.

use core::prelude::*;

use core::default::Default;
use core::fmt;
use core::mem;
use core::ptr;
use core::raw::Slice;

use {Collection, Mutable};
use hash;
use str;
use str::{CharRange, StrAllocating};
use vec::Vec;

/// A growable string stored as a UTF-8 encoded buffer.
#[deriving(Clone, PartialEq, PartialOrd, Eq, Ord)]
pub struct String {
    vec: Vec<u8>,
}

impl String {
    /// Creates a new string buffer initialized with the empty string.
    #[inline]
    pub fn new() -> String {
        String {
            vec: Vec::new(),
        }
    }

    /// Creates a new string buffer with the given capacity.
    #[inline]
    pub fn with_capacity(capacity: uint) -> String {
        String {
            vec: Vec::with_capacity(capacity),
        }
    }

    /// Creates a new string buffer from length, capacity, and a pointer.
    #[inline]
    pub unsafe fn from_raw_parts(length: uint, capacity: uint, ptr: *mut u8) -> String {
        String {
            vec: Vec::from_raw_parts(length, capacity, ptr),
        }
    }

    /// Creates a new string buffer from the given string.
    #[inline]
    pub fn from_str(string: &str) -> String {
        String {
            vec: Vec::from_slice(string.as_bytes())
        }
    }

    #[allow(missing_doc)]
    #[deprecated = "obsoleted by the removal of ~str"]
    #[inline]
    pub fn from_owned_str(string: String) -> String {
        string
    }

    /// Returns the vector as a string buffer, if possible, taking care not to
    /// copy it.
    ///
    /// Returns `Err` with the original vector if the vector contains invalid
    /// UTF-8.
    #[inline]
    pub fn from_utf8(vec: Vec<u8>) -> Result<String, Vec<u8>> {
        if str::is_utf8(vec.as_slice()) {
            Ok(String { vec: vec })
        } else {
            Err(vec)
        }
    }

    /// Return the underlying byte buffer, encoded as UTF-8.
    #[inline]
    pub fn into_bytes(self) -> Vec<u8> {
        self.vec
    }

    /// Pushes the given string onto this buffer; then, returns `self` so that it can be used
    /// again.
    #[inline]
    pub fn append(mut self, second: &str) -> String {
        self.push_str(second);
        self
    }

    /// Creates a string buffer by repeating a character `length` times.
    #[inline]
    pub fn from_char(length: uint, ch: char) -> String {
        if length == 0 {
            return String::new()
        }

        let mut buf = String::new();
        buf.push_char(ch);
        let size = buf.len() * length;
        buf.reserve(size);
        for _ in range(1, length) {
            buf.push_char(ch)
        }
        buf
    }

    /// Pushes the given string onto this string buffer.
    #[inline]
    pub fn push_str(&mut self, string: &str) {
        self.vec.push_all(string.as_bytes())
    }

    /// Push `ch` onto the given string `count` times.
    #[inline]
    pub fn grow(&mut self, count: uint, ch: char) {
        for _ in range(0, count) {
            self.push_char(ch)
        }
    }

    /// Returns the number of bytes that this string buffer can hold without reallocating.
    #[inline]
    pub fn byte_capacity(&self) -> uint {
        self.vec.capacity()
    }

    /// Reserves capacity for at least `extra` additional bytes in this string buffer.
    #[inline]
    pub fn reserve_additional(&mut self, extra: uint) {
        self.vec.reserve_additional(extra)
    }

    /// Reserves capacity for at least `capacity` bytes in this string buffer.
    #[inline]
    pub fn reserve(&mut self, capacity: uint) {
        self.vec.reserve(capacity)
    }

    /// Reserves capacity for exactly `capacity` bytes in this string buffer.
    #[inline]
    pub fn reserve_exact(&mut self, capacity: uint) {
        self.vec.reserve_exact(capacity)
    }

    /// Shrinks the capacity of this string buffer to match its length.
    #[inline]
    pub fn shrink_to_fit(&mut self) {
        self.vec.shrink_to_fit()
    }

    /// Adds the given character to the end of the string.
    #[inline]
    pub fn push_char(&mut self, ch: char) {
        let cur_len = self.len();
        // This may use up to 4 bytes.
        self.vec.reserve_additional(4);

        unsafe {
            // Attempt to not use an intermediate buffer by just pushing bytes
            // directly onto this string.
            let slice = Slice {
                data: self.vec.as_ptr().offset(cur_len as int),
                len: 4,
            };
            let used = ch.encode_utf8(mem::transmute(slice));
            self.vec.set_len(cur_len + used);
        }
    }

    /// Pushes the given bytes onto this string buffer. This is unsafe because it does not check
    /// to ensure that the resulting string will be valid UTF-8.
    #[inline]
    pub unsafe fn push_bytes(&mut self, bytes: &[u8]) {
        self.vec.push_all(bytes)
    }

    /// Works with the underlying buffer as a byte slice.
    #[inline]
    pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
        self.vec.as_slice()
    }

    /// Works with the underlying buffer as a mutable byte slice. Unsafe
    /// because this can be used to violate the UTF-8 property.
    #[inline]
    pub unsafe fn as_mut_bytes<'a>(&'a mut self) -> &'a mut [u8] {
        self.vec.as_mut_slice()
    }

    /// Shorten a string to the specified length (which must be <= the current length)
    #[inline]
    pub fn truncate(&mut self, len: uint) {
        assert!(self.as_slice().is_char_boundary(len));
        self.vec.truncate(len)
    }

    /// Appends a byte to this string buffer. The caller must preserve the valid UTF-8 property.
    #[inline]
    pub unsafe fn push_byte(&mut self, byte: u8) {
        self.vec.push(byte)
    }

    /// Removes the last byte from the string buffer and returns it. Returns `None` if this string
    /// buffer is empty.
    ///
    /// The caller must preserve the valid UTF-8 property.
    #[inline]
    pub unsafe fn pop_byte(&mut self) -> Option<u8> {
        let len = self.len();
        if len == 0 {
            return None
        }

        let byte = self.as_bytes()[len - 1];
        self.vec.set_len(len - 1);
        Some(byte)
    }

    /// Removes the last character from the string buffer and returns it. Returns `None` if this
    /// string buffer is empty.
    #[inline]
    pub fn pop_char(&mut self) -> Option<char> {
        let len = self.len();
        if len == 0 {
            return None
        }

        let CharRange {ch, next} = self.as_slice().char_range_at_reverse(len);
        unsafe {
            self.vec.set_len(next);
        }
        Some(ch)
    }

    /// Removes the first byte from the string buffer and returns it. Returns `None` if this string
    /// buffer is empty.
    ///
    /// The caller must preserve the valid UTF-8 property.
    pub unsafe fn shift_byte(&mut self) -> Option<u8> {
        self.vec.shift()
    }

    /// Removes the first character from the string buffer and returns it. Returns `None` if this
    /// string buffer is empty.
    ///
    /// # Warning
    ///
    /// This is a O(n) operation as it requires copying every element in the buffer.
    pub fn shift_char (&mut self) -> Option<char> {
        let len = self.len();
        if len == 0 {
            return None
        }

        let CharRange {ch, next} = self.as_slice().char_range_at(0);
        let new_len = len - next;
        unsafe {
            ptr::copy_memory(self.vec.as_mut_ptr(), self.vec.as_ptr().offset(next as int), new_len);
            self.vec.set_len(new_len);
        }
        Some(ch)
    }

    /// Views the string buffer as a mutable sequence of bytes.
    ///
    /// Callers must preserve the valid UTF-8 property.
    pub unsafe fn as_mut_vec<'a>(&'a mut self) -> &'a mut Vec<u8> {
        &mut self.vec
    }
}

impl Collection for String {
    #[inline]
    fn len(&self) -> uint {
        self.vec.len()
    }
}

impl Mutable for String {
    #[inline]
    fn clear(&mut self) {
        self.vec.clear()
    }
}

impl FromIterator<char> for String {
    fn from_iter<I:Iterator<char>>(iterator: I) -> String {
        let mut buf = String::new();
        buf.extend(iterator);
        buf
    }
}

impl Extendable<char> for String {
    fn extend<I:Iterator<char>>(&mut self, mut iterator: I) {
        for ch in iterator {
            self.push_char(ch)
        }
    }
}

impl Str for String {
    #[inline]
    fn as_slice<'a>(&'a self) -> &'a str {
        unsafe {
            mem::transmute(self.vec.as_slice())
        }
    }
}

impl StrAllocating for String {
    #[inline]
    fn into_string(self) -> String {
        self
    }
}

impl Default for String {
    fn default() -> String {
        String::new()
    }
}

impl fmt::Show for String {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.as_slice().fmt(f)
    }
}

impl<H: hash::Writer> hash::Hash<H> for String {
    #[inline]
    fn hash(&self, hasher: &mut H) {
        self.as_slice().hash(hasher)
    }
}

impl<'a, S: Str> Equiv<S> for String {
    #[inline]
    fn equiv(&self, other: &S) -> bool {
        self.as_slice() == other.as_slice()
    }
}

impl<S: Str> Add<S, String> for String {
    fn add(&self, other: &S) -> String {
        let mut s = self.to_string();
        s.push_str(other.as_slice());
        return s;
    }
}

#[cfg(test)]
mod tests {
    use std::prelude::*;
    use test::Bencher;

    use Mutable;
    use str::{Str, StrSlice};
    use super::String;

    #[bench]
    fn bench_with_capacity(b: &mut Bencher) {
        b.iter(|| {
            String::with_capacity(100)
        });
    }

    #[bench]
    fn bench_push_str(b: &mut Bencher) {
        let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
        b.iter(|| {
            let mut r = String::new();
            r.push_str(s);
        });
    }

    #[test]
    fn test_push_bytes() {
        let mut s = String::from_str("ABC");
        unsafe {
            s.push_bytes([ 'D' as u8 ]);
        }
        assert_eq!(s.as_slice(), "ABCD");
    }

    #[test]
    fn test_push_str() {
        let mut s = String::new();
        s.push_str("");
        assert_eq!(s.as_slice().slice_from(0), "");
        s.push_str("abc");
        assert_eq!(s.as_slice().slice_from(0), "abc");
        s.push_str("ประเทศไทย中华Việt Nam");
        assert_eq!(s.as_slice().slice_from(0), "abcประเทศไทย中华Việt Nam");
    }

    #[test]
    fn test_push_char() {
        let mut data = String::from_str("ประเทศไทย中");
        data.push_char('华');
        data.push_char('b'); // 1 byte
        data.push_char('¢'); // 2 byte
        data.push_char('€'); // 3 byte
        data.push_char('𤭢'); // 4 byte
        assert_eq!(data.as_slice(), "ประเทศไทย中华b¢€𤭢");
    }

    #[test]
    fn test_pop_char() {
        let mut data = String::from_str("ประเทศไทย中华b¢€𤭢");
        assert_eq!(data.pop_char().unwrap(), '𤭢'); // 4 bytes
        assert_eq!(data.pop_char().unwrap(), '€'); // 3 bytes
        assert_eq!(data.pop_char().unwrap(), '¢'); // 2 bytes
        assert_eq!(data.pop_char().unwrap(), 'b'); // 1 bytes
        assert_eq!(data.pop_char().unwrap(), '华');
        assert_eq!(data.as_slice(), "ประเทศไทย中");
    }

    #[test]
    fn test_shift_char() {
        let mut data = String::from_str("𤭢€¢b华ประเทศไทย中");
        assert_eq!(data.shift_char().unwrap(), '𤭢'); // 4 bytes
        assert_eq!(data.shift_char().unwrap(), '€'); // 3 bytes
        assert_eq!(data.shift_char().unwrap(), '¢'); // 2 bytes
        assert_eq!(data.shift_char().unwrap(), 'b'); // 1 bytes
        assert_eq!(data.shift_char().unwrap(), '华');
        assert_eq!(data.as_slice(), "ประเทศไทย中");
    }

    #[test]
    fn test_str_truncate() {
        let mut s = String::from_str("12345");
        s.truncate(5);
        assert_eq!(s.as_slice(), "12345");
        s.truncate(3);
        assert_eq!(s.as_slice(), "123");
        s.truncate(0);
        assert_eq!(s.as_slice(), "");

        let mut s = String::from_str("12345");
        let p = s.as_slice().as_ptr();
        s.truncate(3);
        s.push_str("6");
        let p_ = s.as_slice().as_ptr();
        assert_eq!(p_, p);
    }

    #[test]
    #[should_fail]
    fn test_str_truncate_invalid_len() {
        let mut s = String::from_str("12345");
        s.truncate(6);
    }

    #[test]
    #[should_fail]
    fn test_str_truncate_split_codepoint() {
        let mut s = String::from_str("\u00FC"); // ü
        s.truncate(1);
    }

    #[test]
    fn test_str_clear() {
        let mut s = String::from_str("12345");
        s.clear();
        assert_eq!(s.len(), 0);
        assert_eq!(s.as_slice(), "");
    }

    #[test]
    fn test_str_add() {
        let a = String::from_str("12345");
        let b = a + "2";
        let b = b + String::from_str("2");
        assert_eq!(b.len(), 7);
        assert_eq!(b.as_slice(), "1234522");
    }
}
<|endoftext|>


<commit_before>use detail::{align_down, mut_offset};
use reg_context::InitFn;
use stack::Stack;

#[cfg(not(nightly))]
#[link(name = "asm", kind = "static")]
extern "C" {
    pub fn bootstrap_green_task();
    pub fn prefetch(data: *const usize);
    pub fn swap_registers(out_regs: *mut Registers, in_regs: *const Registers);
}

#[cfg(nightly)]
mod asm_impl {
    use super::Registers;
    /// prefetch data
    #[inline]
    pub unsafe extern "C" fn prefetch(data: *const usize) {
        asm!(
            "prefetcht1 $0"
            : // no output
            : "m"(*data)
            :
            : "volatile"
        );
    }

    #[naked]
    #[inline(never)]
    pub unsafe extern "C" fn bootstrap_green_task() {
        asm!(
            "
                mov %r12, %rdi     // setup the function arg
                mov %r13, %rsi     // setup the function arg
                and $$-16, %rsp    // align the stack pointer
                mov %r14, (%rsp)   // this is the new return adrress
            "
            : // no output
            : // no input
            : "memory"
            : "volatile"
        );
    }

    #[naked]
    #[inline(never)]
    pub unsafe extern "C" fn swap_registers(out_regs: *mut Registers, in_regs: *const Registers) {
        // The first argument is in %rdi, and the second one is in %rsi
        asm!(
            ""
            :
            : "{rdi}"(out_regs), "{rsi}"(in_regs)
            :
            :
        );

        // introduce this function to workaround rustc bug! (#6)
        #[naked]
        unsafe extern "C" fn _swap_reg() {
            // Save registers
            asm!(
                "
                    mov %rbx, (0*8)(%rdi)
                    mov %rsp, (1*8)(%rdi)
                    mov %rbp, (2*8)(%rdi)
                    mov %r12, (4*8)(%rdi)
                    mov %r13, (5*8)(%rdi)
                    mov %r14, (6*8)(%rdi)
                    mov %r15, (7*8)(%rdi)

                    mov %rdi, (3*8)(%rdi)

                    mov (0*8)(%rsi), %rbx
                    mov (1*8)(%rsi), %rsp
                    mov (2*8)(%rsi), %rbp
                    mov (4*8)(%rsi), %r12
                    mov (5*8)(%rsi), %r13
                    mov (6*8)(%rsi), %r14
                    mov (7*8)(%rsi), %r15

                    mov (3*8)(%rsi), %rdi
                "
                :
                : //"{rdi}"(out_regs), "{rsi}"(in_regs)
                : "memory"
                : "volatile"
            );
        }

        _swap_reg()
    }
}
#[cfg(nightly)]
pub use self::asm_impl::*;

#[repr(C)]
#[derive(Debug)]
pub struct Registers {
    gpr: [usize; 8],
}

impl Registers {
    pub fn new() -> Registers {
        Registers { gpr: [0; 8] }
    }

    #[inline]
    pub fn prefetch(&self) {
        unsafe {
            prefetch(self as *const _ as *const usize);
            prefetch(self.gpr[1] as *const usize);
        }
    }
}

pub fn initialize_call_frame(
    regs: &mut Registers,
    fptr: InitFn,
    arg: usize,
    arg2: *mut usize,
    stack: &Stack,
) {
    // Redefinitions from rt/arch/x86_64/regs.h
    const RUSTRT_RSP: usize = 1;
    const RUSTRT_RBP: usize = 2;
    const RUSTRT_R12: usize = 4;
    const RUSTRT_R13: usize = 5;
    const RUSTRT_R14: usize = 6;

    let sp = align_down(stack.end());

    // These registers are frobbed by bootstrap_green_task into the right
    // location so we can invoke the "real init function", `fptr`.
    regs.gpr[RUSTRT_R12] = arg;
    regs.gpr[RUSTRT_R13] = arg2 as usize;
    regs.gpr[RUSTRT_R14] = fptr as usize;

    // Last base pointer on the stack should be 0
    regs.gpr[RUSTRT_RBP] = 0;

    // setup the init stack
    // this is prepared for the swap context
    regs.gpr[RUSTRT_RSP] = mut_offset(sp, -2) as usize;

    unsafe {
        // leave enough space for RET
        *mut_offset(sp, -2) = bootstrap_green_task as usize;
        *mut_offset(sp, -1) = 0;
    }
}
<commit_msg>:pencil: update to 2018 edition for unix<commit_after>use crate::detail::{align_down, mut_offset};
use crate::reg_context::InitFn;
use crate::stack::Stack;

#[cfg(not(nightly))]
#[link(name = "asm", kind = "static")]
extern "C" {
    pub fn bootstrap_green_task();
    pub fn prefetch(data: *const usize);
    pub fn swap_registers(out_regs: *mut Registers, in_regs: *const Registers);
}

#[cfg(nightly)]
mod asm_impl {
    use super::Registers;
    /// prefetch data
    #[inline]
    pub unsafe extern "C" fn prefetch(data: *const usize) {
        asm!(
            "prefetcht1 $0"
            : // no output
            : "m"(*data)
            :
            : "volatile"
        );
    }

    #[naked]
    #[inline(never)]
    pub unsafe extern "C" fn bootstrap_green_task() {
        asm!(
            "
                mov %r12, %rdi     // setup the function arg
                mov %r13, %rsi     // setup the function arg
                and $$-16, %rsp    // align the stack pointer
                mov %r14, (%rsp)   // this is the new return adrress
            "
            : // no output
            : // no input
            : "memory"
            : "volatile"
        );
    }

    #[naked]
    #[inline(never)]
    pub unsafe extern "C" fn swap_registers(out_regs: *mut Registers, in_regs: *const Registers) {
        // The first argument is in %rdi, and the second one is in %rsi
        asm!(
            ""
            :
            : "{rdi}"(out_regs), "{rsi}"(in_regs)
            :
            :
        );

        // introduce this function to workaround rustc bug! (#6)
        #[naked]
        unsafe extern "C" fn _swap_reg() {
            // Save registers
            asm!(
                "
                    mov %rbx, (0*8)(%rdi)
                    mov %rsp, (1*8)(%rdi)
                    mov %rbp, (2*8)(%rdi)
                    mov %r12, (4*8)(%rdi)
                    mov %r13, (5*8)(%rdi)
                    mov %r14, (6*8)(%rdi)
                    mov %r15, (7*8)(%rdi)

                    mov %rdi, (3*8)(%rdi)

                    mov (0*8)(%rsi), %rbx
                    mov (1*8)(%rsi), %rsp
                    mov (2*8)(%rsi), %rbp
                    mov (4*8)(%rsi), %r12
                    mov (5*8)(%rsi), %r13
                    mov (6*8)(%rsi), %r14
                    mov (7*8)(%rsi), %r15

                    mov (3*8)(%rsi), %rdi
                "
                :
                : //"{rdi}"(out_regs), "{rsi}"(in_regs)
                : "memory"
                : "volatile"
            );
        }

        _swap_reg()
    }
}
#[cfg(nightly)]
pub use self::asm_impl::*;

#[repr(C)]
#[derive(Debug)]
pub struct Registers {
    gpr: [usize; 8],
}

impl Registers {
    pub fn new() -> Registers {
        Registers { gpr: [0; 8] }
    }

    #[inline]
    pub fn prefetch(&self) {
        unsafe {
            prefetch(self as *const _ as *const usize);
            prefetch(self.gpr[1] as *const usize);
        }
    }
}

pub fn initialize_call_frame(
    regs: &mut Registers,
    fptr: InitFn,
    arg: usize,
    arg2: *mut usize,
    stack: &Stack,
) {
    // Redefinitions from rt/arch/x86_64/regs.h
    const RUSTRT_RSP: usize = 1;
    const RUSTRT_RBP: usize = 2;
    const RUSTRT_R12: usize = 4;
    const RUSTRT_R13: usize = 5;
    const RUSTRT_R14: usize = 6;

    let sp = align_down(stack.end());

    // These registers are frobbed by bootstrap_green_task into the right
    // location so we can invoke the "real init function", `fptr`.
    regs.gpr[RUSTRT_R12] = arg;
    regs.gpr[RUSTRT_R13] = arg2 as usize;
    regs.gpr[RUSTRT_R14] = fptr as usize;

    // Last base pointer on the stack should be 0
    regs.gpr[RUSTRT_RBP] = 0;

    // setup the init stack
    // this is prepared for the swap context
    regs.gpr[RUSTRT_RSP] = mut_offset(sp, -2) as usize;

    unsafe {
        // leave enough space for RET
        *mut_offset(sp, -2) = bootstrap_green_task as usize;
        *mut_offset(sp, -1) = 0;
    }
}
<|endoftext|>


<commit_before>//! Defines the render target for tray, where our image will be written too
//! during rendering
//! TODO: Reconstruction filters

use std::vec::Vec;
use std::iter;
use std::cmp;
use std::num::Float;

use linalg;
use film::Colorf;

/// RenderTarget is a RGBF render target to write our image too while rendering
#[derive(Clone)]
pub struct RenderTarget {
    width: usize,
    height: usize,
    pixels: Vec<Colorf>,
}

impl RenderTarget {
    /// Create a render target with `width * height` pixels
    pub fn new(width: usize, height: usize) -> RenderTarget {
        RenderTarget { width: width, height: height,
            pixels: iter::repeat(Colorf::broadcast(0.0)).take(width * height).collect(),
        }
    }
    /// Write a color value to the image at `(x, y)`
    pub fn write(&mut self, x: f32, y: f32, c: &Colorf) {
        // Compute the discrete pixel coordinates which the sample hits, no filtering for now
        let img_x = x - 0.5;
        let img_y = y - 0.5;
        // TODO: We're just pretending to be a single pixel box filter for now
        let x_range = (Float::max(Float::ceil(img_x - 0.5), 0.0) as usize,
                       Float::min(Float::floor(img_x + 0.5), self.width as f32 - 1.0) as usize);
        let y_range = (Float::max(Float::ceil(img_y - 0.5), 0.0) as usize,
                       Float::min(Float::floor(img_y + 0.5), self.height as f32 - 1.0) as usize);
        let ix = x_range.0;
        let iy = y_range.0;
        self.pixels[iy * self.width + ix] = self.pixels[iy * self.width + ix] + *c;
        // Set the filter weight, currently just a box filter with single pixel extent
        self.pixels[iy * self.width + ix].a += 1.0;
    }
    /// Get the dimensions of the render target
    pub fn dimensions(&self) -> (usize, usize) {
        (self.width, self.height)
    }
    /// Convert the floating point color buffer to 24bpp sRGB for output to an image
    pub fn get_render(&self) -> Vec<u8> {
        let mut render: Vec<u8> = iter::repeat(0u8).take(self.width * self.height * 3).collect();
        for y in 0..self.height {
            for x in 0..self.width {
                let c = &self.pixels[y * self.width + x];
                if c.a != 0.0 {
                    let cn = (*c / c.a).clamp().to_srgb();
                    for i in 0..3us {
                        render[y * self.width * 3 + x * 3 + i] = (cn[i] * 255.0) as u8;
                    }
                }
            }
        }
        render
    }
}

<commit_msg>Add note on Rust support for += operator<commit_after>//! Defines the render target for tray, where our image will be written too
//! during rendering
//! TODO: Reconstruction filters

use std::vec::Vec;
use std::iter;
use std::cmp;
use std::num::Float;

use linalg;
use film::Colorf;

/// RenderTarget is a RGBF render target to write our image too while rendering
#[derive(Clone)]
pub struct RenderTarget {
    width: usize,
    height: usize,
    pixels: Vec<Colorf>,
}

impl RenderTarget {
    /// Create a render target with `width * height` pixels
    pub fn new(width: usize, height: usize) -> RenderTarget {
        RenderTarget { width: width, height: height,
            pixels: iter::repeat(Colorf::broadcast(0.0)).take(width * height).collect(),
        }
    }
    /// Write a color value to the image at `(x, y)`
    pub fn write(&mut self, x: f32, y: f32, c: &Colorf) {
        // Compute the discrete pixel coordinates which the sample hits, no filtering for now
        let img_x = x - 0.5;
        let img_y = y - 0.5;
        // TODO: We're just pretending to be a single pixel box filter for now
        let x_range = (Float::max(Float::ceil(img_x - 0.5), 0.0) as usize,
                       Float::min(Float::floor(img_x + 0.5), self.width as f32 - 1.0) as usize);
        let y_range = (Float::max(Float::ceil(img_y - 0.5), 0.0) as usize,
                       Float::min(Float::floor(img_y + 0.5), self.height as f32 - 1.0) as usize);
        let ix = x_range.0;
        let iy = y_range.0;
        // TODO: Can't currently overload the += operator
        self.pixels[iy * self.width + ix] = self.pixels[iy * self.width + ix] + *c;
        // Set the filter weight, currently just a box filter with single pixel extent
        self.pixels[iy * self.width + ix].a += 1.0;
    }
    /// Get the dimensions of the render target
    pub fn dimensions(&self) -> (usize, usize) {
        (self.width, self.height)
    }
    /// Convert the floating point color buffer to 24bpp sRGB for output to an image
    pub fn get_render(&self) -> Vec<u8> {
        let mut render: Vec<u8> = iter::repeat(0u8).take(self.width * self.height * 3).collect();
        for y in 0..self.height {
            for x in 0..self.width {
                let c = &self.pixels[y * self.width + x];
                if c.a != 0.0 {
                    let cn = (*c / c.a).clamp().to_srgb();
                    for i in 0..3us {
                        render[y * self.width * 3 + x * 3 + i] = (cn[i] * 255.0) as u8;
                    }
                }
            }
        }
        render
    }
}

<|endoftext|>


<commit_before>extern crate curl;

use std::process;
use curl::http;

fn main() {
    println!("Hello!");
    let url = "https://github.com/clux/muslrust/blob/master/README.md";
    let resp = http::handle().get(url).exec().unwrap();
    process::exit(if resp.get_code() == 200 { 0 } else { 1 });
}
<commit_msg>check that output works<commit_after>extern crate curl;

use std::process;
use curl::http;

fn main() {
    let url = "https://raw.githubusercontent.com/clux/muslrust/master/test/curlcrate/src/main.rs";

    let resp = http::handle().get(url).exec().unwrap();
    let body = String::from_utf8_lossy(resp.get_body());
    println!("{}", body);
    process::exit(if resp.get_code() == 200 { 0 } else { 1 });
    // NB: This is a quine
}
<|endoftext|>


<commit_before>

use fred;
use super::utils;

use tokio_core::reactor::{
  Core,
  Handle
};

use tokio_timer::*;

use futures::future;
use futures::{
  IntoFuture,
  Future,
  Stream
};
use futures::sync::oneshot::{
  Sender as OneshotSender,
  Receiver as OneshotReceiver,
  channel as oneshot_channel
};
use futures::sync::mpsc::{
  Sender,
  Receiver,
  channel
};

use std::time::Duration;

use fred::error::{
  RedisErrorKind,
  RedisError
};

use fred::types::*;
use fred::RedisClient;

use std::thread;
use std::sync::Arc;

use pretty_env_logger;

use super::keys as keys_tests;
use super::hashes as hashes_tests;
use super::lists as lists_tests;

#[test]
fn it_should_connect_and_disconnect() {
  let mut config = RedisConfig::default_clustered();
  let mut core = Core::new().unwrap();
  let handle = core.handle();

  let client = RedisClient::new(config);
  let connection_ft = client.connect(&handle);

  let select_ft = client.on_connect().and_then(|client| {
    client.info(None)
  })
  .and_then(|(client, _)| {
    client.quit()
  });

  let (err, client) = core.run(connection_ft.join(select_ft)).unwrap();
  assert!(err.is_none());
}

#[test]
fn it_should_connect_and_disconnect_with_policy() {
  let mut config = RedisConfig::default_clustered();
  let policy = ReconnectPolicy::Constant {
    delay: 2000,
    attempts: 0,
    max_attempts: 10
  };

  let mut core = Core::new().unwrap();
  let handle = core.handle();

  let client = RedisClient::new(config);
  let connection_ft = client.connect_with_policy(&handle, policy);

  let select_ft = client.on_connect().and_then(|client| {
    client.info(None)
  })
  .and_then(|(client, _)| {
    client.quit()
  });

  let (_, client) = core.run(connection_ft.join(select_ft)).unwrap();
}

pub mod keys {
  use super::*;

  #[test]
  fn it_should_set_and_get_simple_key() {
    let config = RedisConfig::default_clustered();
    utils::setup_test_client(config, |client| {
      keys_tests::should_set_and_get_simple_key(client)
    });
  }

  #[test]
  fn it_should_set_and_get_large_key() {
    let config = RedisConfig::default_clustered();
    utils::setup_test_client(config, |client| {
      keys_tests::should_set_and_get_large_key(client)
    })
  }

  #[test]
  fn it_should_set_and_get_random_keys() {
    let config = RedisConfig::default_clustered();
    utils::setup_test_client(config, |client| {
      keys_tests::should_set_and_get_random_keys(client)
    })
  }

  #[test]
  fn it_should_set_random_keys_with_fqdn_addresses() {
    let hosts: Vec<(String, u16)> = vec![
      ("localhost".to_owned(), 30001),
      ("localhost".to_owned(), 30002),
      ("localhost".to_owned(), 30003),
    ];
    let config = RedisConfig::new_clustered(hosts, None);

    utils::setup_test_client(config, |client| {
      keys_tests::should_set_and_get_random_keys(client)
    })
  }

  #[cfg(all(feature="metrics", not(feature="mock")))]
  #[test]
  fn it_should_track_latency_and_size_metrics() {
    let config = RedisConfig::default_clustered();
    utils::setup_test_client(config, |client| {
      keys_tests::should_track_latency_and_size(client)
    })
  }

}

pub mod hashes {
  use super::*;

  #[test]
  fn it_should_set_and_get_simple_key() {
    let config = RedisConfig::default_clustered();
    utils::setup_test_client(config, |client| {
      hashes_tests::should_set_and_get_simple_key(client)
    });
  }

  #[test]
  fn it_should_set_and_get_all_simple_key() {
    let config = RedisConfig::default_clustered();
    utils::setup_test_client(config, |client| {
      hashes_tests::should_set_and_get_all_simple_key(client)
    });
  }

  #[test]
  fn it_should_check_hexists() {
    let config = RedisConfig::default_clustered();
    utils::setup_test_client(config, |client| {
      hashes_tests::should_check_hexists(client)
    });
  }

  #[test]
  fn it_should_read_large_hash() {
    let config = RedisConfig::default_centralized();
    utils::setup_test_client(config, |client| {
      hashes_tests::should_read_large_hash(client)
    });
  }

}

pub mod lists {
  use super::*;

  #[test]
  fn it_should_llen_on_empty_list() {
    let config = RedisConfig::default();
    utils::setup_test_client(config, |client| {
      lists_tests::should_llen_on_empty_list(client)
    });
  }

  #[test]
  fn it_should_llen_on_list_with_elements() {
    let config = RedisConfig::default();
    utils::setup_test_client(config, |client| {
      lists_tests::should_llen_on_list_with_elements(client)
    });
  }

  #[test]
  fn it_should_lpush_and_lpop_to_list() {
    let config = RedisConfig::default();
    utils::setup_test_client(config, |client| {
      lists_tests::should_lpush_and_lpop_to_list(client)
    });
  }
}
<commit_msg>Use RedisConfig::default_clustered() in cluster intergration tests<commit_after>

use fred;
use super::utils;

use tokio_core::reactor::{
  Core,
  Handle
};

use tokio_timer::*;

use futures::future;
use futures::{
  IntoFuture,
  Future,
  Stream
};
use futures::sync::oneshot::{
  Sender as OneshotSender,
  Receiver as OneshotReceiver,
  channel as oneshot_channel
};
use futures::sync::mpsc::{
  Sender,
  Receiver,
  channel
};

use std::time::Duration;

use fred::error::{
  RedisErrorKind,
  RedisError
};

use fred::types::*;
use fred::RedisClient;

use std::thread;
use std::sync::Arc;

use pretty_env_logger;

use super::keys as keys_tests;
use super::hashes as hashes_tests;
use super::lists as lists_tests;

#[test]
fn it_should_connect_and_disconnect() {
  let mut config = RedisConfig::default_clustered();
  let mut core = Core::new().unwrap();
  let handle = core.handle();

  let client = RedisClient::new(config);
  let connection_ft = client.connect(&handle);

  let select_ft = client.on_connect().and_then(|client| {
    client.info(None)
  })
  .and_then(|(client, _)| {
    client.quit()
  });

  let (err, client) = core.run(connection_ft.join(select_ft)).unwrap();
  assert!(err.is_none());
}

#[test]
fn it_should_connect_and_disconnect_with_policy() {
  let mut config = RedisConfig::default_clustered();
  let policy = ReconnectPolicy::Constant {
    delay: 2000,
    attempts: 0,
    max_attempts: 10
  };

  let mut core = Core::new().unwrap();
  let handle = core.handle();

  let client = RedisClient::new(config);
  let connection_ft = client.connect_with_policy(&handle, policy);

  let select_ft = client.on_connect().and_then(|client| {
    client.info(None)
  })
  .and_then(|(client, _)| {
    client.quit()
  });

  let (_, client) = core.run(connection_ft.join(select_ft)).unwrap();
}

pub mod keys {
  use super::*;

  #[test]
  fn it_should_set_and_get_simple_key() {
    let config = RedisConfig::default_clustered();
    utils::setup_test_client(config, |client| {
      keys_tests::should_set_and_get_simple_key(client)
    });
  }

  #[test]
  fn it_should_set_and_get_large_key() {
    let config = RedisConfig::default_clustered();
    utils::setup_test_client(config, |client| {
      keys_tests::should_set_and_get_large_key(client)
    })
  }

  #[test]
  fn it_should_set_and_get_random_keys() {
    let config = RedisConfig::default_clustered();
    utils::setup_test_client(config, |client| {
      keys_tests::should_set_and_get_random_keys(client)
    })
  }

  #[test]
  fn it_should_set_random_keys_with_fqdn_addresses() {
    let hosts: Vec<(String, u16)> = vec![
      ("localhost".to_owned(), 30001),
      ("localhost".to_owned(), 30002),
      ("localhost".to_owned(), 30003),
    ];
    let config = RedisConfig::new_clustered(hosts, None);

    utils::setup_test_client(config, |client| {
      keys_tests::should_set_and_get_random_keys(client)
    })
  }

  #[cfg(all(feature="metrics", not(feature="mock")))]
  #[test]
  fn it_should_track_latency_and_size_metrics() {
    let config = RedisConfig::default_clustered();
    utils::setup_test_client(config, |client| {
      keys_tests::should_track_latency_and_size(client)
    })
  }

}

pub mod hashes {
  use super::*;

  #[test]
  fn it_should_set_and_get_simple_key() {
    let config = RedisConfig::default_clustered();
    utils::setup_test_client(config, |client| {
      hashes_tests::should_set_and_get_simple_key(client)
    });
  }

  #[test]
  fn it_should_set_and_get_all_simple_key() {
    let config = RedisConfig::default_clustered();
    utils::setup_test_client(config, |client| {
      hashes_tests::should_set_and_get_all_simple_key(client)
    });
  }

  #[test]
  fn it_should_check_hexists() {
    let config = RedisConfig::default_clustered();
    utils::setup_test_client(config, |client| {
      hashes_tests::should_check_hexists(client)
    });
  }

  #[test]
  fn it_should_read_large_hash() {
    let config = RedisConfig::default_centralized();
    utils::setup_test_client(config, |client| {
      hashes_tests::should_read_large_hash(client)
    });
  }

}

pub mod lists {
  use super::*;

  #[test]
  fn it_should_llen_on_empty_list() {
    let config = RedisConfig::default_clustered();
    utils::setup_test_client(config, |client| {
      lists_tests::should_llen_on_empty_list(client)
    });
  }

  #[test]
  fn it_should_llen_on_list_with_elements() {
    let config = RedisConfig::default_clustered();
    utils::setup_test_client(config, |client| {
      lists_tests::should_llen_on_list_with_elements(client)
    });
  }

  #[test]
  fn it_should_lpush_and_lpop_to_list() {
    let config = RedisConfig::default_clustered();
    utils::setup_test_client(config, |client| {
      lists_tests::should_lpush_and_lpop_to_list(client)
    });
  }
}
<|endoftext|>


<commit_before>// Generic x86-64 target for bare-metal code - Floating point disabled
//
// Can be used in conjunction with the `target-feature` and
// `target-cpu` compiler flags to opt-in more hardware-specific
// features.

use super::{CodeModel, LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions};

pub fn target() -> Target {
    let opts = TargetOptions {
        abi: "softfloat".to_string(),
        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
        linker: Some("rust-lld".to_owned()),
        features: "-mmx,-sse,+soft-float".to_string(),
        executables: true,
        disable_redzone: true,
        panic_strategy: PanicStrategy::Abort,
        code_model: Some(CodeModel::Kernel),
        ..Default::default()
    };
    Target {
        llvm_target: "x86_64-unknown-none-elf".to_string(),
        pointer_width: 64,
        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
            .to_string(),
        arch: "x86_64".to_string(),
        options: opts,
    }
}
<commit_msg>x86_64-unknown-none: Drop the `abi` field<commit_after>// Generic x86-64 target for bare-metal code - Floating point disabled
//
// Can be used in conjunction with the `target-feature` and
// `target-cpu` compiler flags to opt-in more hardware-specific
// features.

use super::{CodeModel, LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions};

pub fn target() -> Target {
    let opts = TargetOptions {
        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
        linker: Some("rust-lld".to_owned()),
        features: "-mmx,-sse,+soft-float".to_string(),
        executables: true,
        disable_redzone: true,
        panic_strategy: PanicStrategy::Abort,
        code_model: Some(CodeModel::Kernel),
        ..Default::default()
    };
    Target {
        llvm_target: "x86_64-unknown-none-elf".to_string(),
        pointer_width: 64,
        data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
            .to_string(),
        arch: "x86_64".to_string(),
        options: opts,
    }
}
<|endoftext|>


<commit_before>#![cfg(test)]

use std::collections::HashMap;
use rustc_serialize::json;
use rustc_serialize::json::{decode, Json, Object};
use rustc_serialize::{Decoder, Decodable};
use std::io::prelude::*;
use std::fs::File;
use token::{Token, ReservedWord};

pub struct ExpectPass {
    source: String,
    expected: Json,
    options: Option<Json>
}

pub struct ExpectFail {
    source: String,
    error: String,
    options: Option<Json>
}

pub enum TestCase {
    Pass(ExpectPass),
    Fail(ExpectFail)
}

trait JsonExt {
    fn into_array(self) -> json::Array;
    fn into_string(self) -> String;
    fn into_string_opt(self) -> Option<String>;
}

impl JsonExt for Json {
    fn into_array(self) -> json::Array {
        match self {
            Json::Array(array) => array,
            _ => panic!("expected array")
        }
    }
    fn into_string(self) -> String {
        match self {
            Json::String(string) => string,
            _ => panic!("expected string")
        }
    }
    fn into_string_opt(self) -> Option<String> {
        match self {
            Json::Null => None,
            Json::String(string) => Some(string),
            _ => panic!("expected string or null")
        }
    }
}

fn parse_expect_fail(test: &mut Object) -> ExpectFail {
    ExpectFail {
        source: test.remove("source").unwrap().into_string(),
        error: test.remove("error").unwrap().into_string(),
        options: None
    }
}

fn parse_expect_pass(test: &mut Object) -> ExpectPass {
    ExpectPass {
        source: test.remove("source").unwrap().into_string(),
        expected: test.remove("expected").unwrap(),
        options: None
    }
}

fn nullary(token: Token) -> Box<FnOnce(&mut Object) -> Option<Token>> {
    Box::new(|_| { Some(token) })
}

fn deserialize_token(mut data: Json) -> Token {
    let mut obj = data.as_object_mut().unwrap();
    let ty = obj.remove("type").unwrap().into_string();

    let mut matchers: HashMap<&str, Box<FnOnce(&mut Object) -> Option<Token>>> = HashMap::new();
    matchers.insert("LBrace", Box::new(|_| -> Option<Token> { Some(Token::LBrace) }));
    matchers.insert("DecimalInt", Box::new(|data| -> Option<Token> {
        match data.remove("value") {
            None => None,
            Some(str) => Some(Token::DecimalInt(str.into_string()))
        }
    }));
    let f = matchers.get("DecimalInt").unwrap();
    let mut data = Json::from_str("{\"type\":\"DecimalInt\",\"value\":\"11.3\"}").unwrap();
    let obj = data.as_object_mut().unwrap();
    f(obj).unwrap()
}

fn parse_test(mut test: Json) -> TestCase {
    let obj = test.as_object_mut().unwrap();
    if obj.contains_key("error") {
        TestCase::Fail(parse_expect_fail(obj))
    } else {
        TestCase::Pass(parse_expect_pass(obj))
    }
}

pub fn read_tests(path: &str) -> Vec<TestCase> {
    let mut f: File = File::open(path).unwrap();
    let mut s = String::new();
    f.read_to_string(&mut s);
    parse_tests(&s)
}

pub fn parse_tests(src: &str) -> Vec<TestCase> {
    let data: Json = src.parse().unwrap();
    data.into_array()
        .into_iter()
        .map(parse_test)
        .collect()
}
<commit_msg>Niko said this was a limitation of DST and gave me boilerplate for a workaround by wrapping the FnOnce in a new trait abstraction<commit_after>#![cfg(test)]

use std::collections::HashMap;
use rustc_serialize::json;
use rustc_serialize::json::{decode, Json, Object};
use rustc_serialize::{Decoder, Decodable};
use std::io::prelude::*;
use std::fs::File;
use token::{Token, ReservedWord};

pub struct ExpectPass {
    source: String,
    expected: Json,
    options: Option<Json>
}

pub struct ExpectFail {
    source: String,
    error: String,
    options: Option<Json>
}

pub enum TestCase {
    Pass(ExpectPass),
    Fail(ExpectFail)
}

trait JsonExt {
    fn into_array(self) -> json::Array;
    fn into_string(self) -> String;
    fn into_string_opt(self) -> Option<String>;
}

impl JsonExt for Json {
    fn into_array(self) -> json::Array {
        match self {
            Json::Array(array) => array,
            _ => panic!("expected array")
        }
    }
    fn into_string(self) -> String {
        match self {
            Json::String(string) => string,
            _ => panic!("expected string")
        }
    }
    fn into_string_opt(self) -> Option<String> {
        match self {
            Json::Null => None,
            Json::String(string) => Some(string),
            _ => panic!("expected string or null")
        }
    }
}

fn parse_expect_fail(test: &mut Object) -> ExpectFail {
    ExpectFail {
        source: test.remove("source").unwrap().into_string(),
        error: test.remove("error").unwrap().into_string(),
        options: None
    }
}

fn parse_expect_pass(test: &mut Object) -> ExpectPass {
    ExpectPass {
        source: test.remove("source").unwrap().into_string(),
        expected: test.remove("expected").unwrap(),
        options: None
    }
}

trait Matcher {
    fn test(self: Box<Self>, arg: &mut Object) -> Option<Token>;
}

impl<F> Matcher for F
    where F: FnOnce(&mut Object) -> Option<Token>
{
    fn test(self: Box<F>, arg: &mut Object) -> Option<Token> {
        self(arg)
    }
}

fn matcher<F:FnOnce(&mut Object) -> Option<Token> + 'static>(f: F) -> Box<Matcher> {
    Box::new(f)
}

fn nullary(token: Token) -> Box<Matcher> {
    matcher(|_| { Some(token) })
}

fn deserialize_token(mut data: Json) -> Token {
    let mut obj = data.as_object_mut().unwrap();
    let ty = obj.remove("type").unwrap().into_string();

    let mut matchers: HashMap<&str, Box<Matcher>> = HashMap::new();
    matchers.insert("LBrace", nullary(Token::LBrace));
    matchers.insert("DecimalInt", matcher(|data| -> Option<Token> {
        match data.remove("value") {
            None => None,
            Some(str) => Some(Token::DecimalInt(str.into_string()))
        }
    }));
    let f = matchers.remove("DecimalInt").unwrap();
    let mut data = Json::from_str("{\"type\":\"DecimalInt\",\"value\":\"11.3\"}").unwrap();
    let obj = data.as_object_mut().unwrap();
    f.test(obj).unwrap()
}

fn parse_test(mut test: Json) -> TestCase {
    let obj = test.as_object_mut().unwrap();
    if obj.contains_key("error") {
        TestCase::Fail(parse_expect_fail(obj))
    } else {
        TestCase::Pass(parse_expect_pass(obj))
    }
}

pub fn read_tests(path: &str) -> Vec<TestCase> {
    let mut f: File = File::open(path).unwrap();
    let mut s = String::new();
    f.read_to_string(&mut s);
    parse_tests(&s)
}

pub fn parse_tests(src: &str) -> Vec<TestCase> {
    let data: Json = src.parse().unwrap();
    data.into_array()
        .into_iter()
        .map(parse_test)
        .collect()
}
<|endoftext|>