<commit_before>// Copyright 2012 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.

//! A structure for holding a set of enum variants.
//!
//! This module defines a container which uses an efficient bit mask
//! representation to hold C-like enum variants.

use core::prelude::*;
use core::fmt;

// FIXME(conventions): implement BitXor
// FIXME(contentions): implement union family of methods? (general design may be wrong here)

#[deriving(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
/// A specialized `Set` implementation to use enum types.
pub struct EnumSet<E> {
    // We must maintain the invariant that no bits are set
    // for which no variant exists
    bits: uint
}

impl<E:CLike+fmt::Show> fmt::Show for EnumSet<E> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(fmt, "{{"));
        let mut first = true;
        for e in self.iter() {
            if !first {
                try!(write!(fmt, ", "));
            }
            try!(write!(fmt, "{}", e));
            first = false;
        }
        write!(fmt, "}}")
    }
}

/**
An interface for casting C-like enum to uint and back.
A typically implementation is as below.

```{rust,ignore}
#[repr(uint)]
enum Foo {
    A, B, C
}

impl CLike for Foo {
    fn to_uint(&self) -> uint {
        *self as uint
    }

    fn from_uint(v: uint) -> Foo {
        unsafe { mem::transmute(v) }
    }
}
```
*/
pub trait CLike {
    /// Converts a C-like enum to a `uint`.
    fn to_uint(&self) -> uint;
    /// Converts a `uint` to a C-like enum.
    fn from_uint(uint) -> Self;
}

fn bit<E:CLike>(e: &E) -> uint {
    use core::uint;
    let value = e.to_uint();
    assert!(value < uint::BITS,
            "EnumSet only supports up to {} variants.", uint::BITS - 1);
    1 << value
}

impl<E:CLike> EnumSet<E> {
    /// Deprecated: Renamed to `new`.
    #[deprecated = "Renamed to `new`"]
    pub fn empty() -> EnumSet<E> {
        EnumSet::new()
    }

    /// Returns an empty `EnumSet`.
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn new() -> EnumSet<E> {
        EnumSet {bits: 0}
    }

    /// Returns the number of elements in the given `EnumSet`.
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn len(&self) -> uint {
        self.bits.count_ones()
    }

    /// Returns true if the `EnumSet` is empty.
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn is_empty(&self) -> bool {
        self.bits == 0
    }

    pub fn clear(&mut self) {
        self.bits = 0;
    }

    /// Returns `true` if the `EnumSet` contains any enum of the given `EnumSet`.
    /// Deprecated: Use `is_disjoint`.
    #[deprecated = "Use `is_disjoint`"]
    pub fn intersects(&self, e: EnumSet<E>) -> bool {
        !self.is_disjoint(&e)
    }

    /// Returns `false` if the `EnumSet` contains any enum of the given `EnumSet`.
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn is_disjoint(&self, other: &EnumSet<E>) -> bool {
        (self.bits & other.bits) == 0
    }

    /// Returns `true` if a given `EnumSet` is included in this `EnumSet`.
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn is_superset(&self, other: &EnumSet<E>) -> bool {
        (self.bits & other.bits) == other.bits
    }

    /// Returns `true` if this `EnumSet` is included in the given `EnumSet`.
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn is_subset(&self, other: &EnumSet<E>) -> bool {
        other.is_superset(self)
    }

    /// Returns the union of both `EnumSets`.
    pub fn union(&self, e: EnumSet<E>) -> EnumSet<E> {
        EnumSet {bits: self.bits | e.bits}
    }

    /// Returns the intersection of both `EnumSets`.
    pub fn intersection(&self, e: EnumSet<E>) -> EnumSet<E> {
        EnumSet {bits: self.bits & e.bits}
    }

    /// Deprecated: Use `insert`.
    #[deprecated = "Use `insert`"]
    pub fn add(&mut self, e: E) {
        self.insert(e);
    }

    /// Adds an enum to the `EnumSet`, and returns `true` if it wasn't there before
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn insert(&mut self, e: E) -> bool {
        let result = !self.contains(&e);
        self.bits |= bit(&e);
        result
    }

    /// Removes an enum from the EnumSet
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn remove(&mut self, e: &E) -> bool {
        let result = self.contains(e);
        self.bits &= !bit(e);
        result
    }

    /// Deprecated: use `contains`.
    #[deprecated = "use `contains"]
    pub fn contains_elem(&self, e: E) -> bool {
        self.contains(&e)
    }

    /// Returns `true` if an `EnumSet` contains a given enum.
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn contains(&self, e: &E) -> bool {
        (self.bits & bit(e)) != 0
    }

    /// Returns an iterator over an `EnumSet`.
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn iter(&self) -> Items<E> {
        Items::new(self.bits)
    }
}

impl<E:CLike> Sub<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
    fn sub(&self, e: &EnumSet<E>) -> EnumSet<E> {
        EnumSet {bits: self.bits & !e.bits}
    }
}

impl<E:CLike> BitOr<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
    fn bitor(&self, e: &EnumSet<E>) -> EnumSet<E> {
        EnumSet {bits: self.bits | e.bits}
    }
}

impl<E:CLike> BitAnd<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
    fn bitand(&self, e: &EnumSet<E>) -> EnumSet<E> {
        EnumSet {bits: self.bits & e.bits}
    }
}

/// An iterator over an EnumSet
pub struct Items<E> {
    index: uint,
    bits: uint,
}

impl<E:CLike> Items<E> {
    fn new(bits: uint) -> Items<E> {
        Items { index: 0, bits: bits }
    }
}

impl<E:CLike> Iterator<E> for Items<E> {
    fn next(&mut self) -> Option<E> {
        if self.bits == 0 {
            return None;
        }

        while (self.bits & 1) == 0 {
            self.index += 1;
            self.bits >>= 1;
        }
        let elem = CLike::from_uint(self.index);
        self.index += 1;
        self.bits >>= 1;
        Some(elem)
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        let exact = self.bits.count_ones();
        (exact, Some(exact))
    }
}

impl<E:CLike> FromIterator<E> for EnumSet<E> {
    fn from_iter<I:Iterator<E>>(iterator: I) -> EnumSet<E> {
        let mut ret = EnumSet::new();
        ret.extend(iterator);
        ret
    }
}

impl<E:CLike> Extend<E> for EnumSet<E> {
    fn extend<I: Iterator<E>>(&mut self, mut iterator: I) {
        for element in iterator {
            self.insert(element);
        }
    }
}

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

    use super::{EnumSet, CLike};

    #[deriving(PartialEq, Show)]
    #[repr(uint)]
    enum Foo {
        A, B, C
    }

    impl CLike for Foo {
        fn to_uint(&self) -> uint {
            *self as uint
        }

        fn from_uint(v: uint) -> Foo {
            unsafe { mem::transmute(v) }
        }
    }

    #[test]
    fn test_new() {
        let e: EnumSet<Foo> = EnumSet::new();
        assert!(e.is_empty());
    }

    #[test]
    fn test_show() {
        let mut e = EnumSet::new();
        assert_eq!("{}", e.to_string().as_slice());
        e.insert(A);
        assert_eq!("{A}", e.to_string().as_slice());
        e.insert(C);
        assert_eq!("{A, C}", e.to_string().as_slice());
    }

    #[test]
    fn test_len() {
        let mut e = EnumSet::new();
        assert_eq!(e.len(), 0);
        e.insert(A);
        e.insert(B);
        e.insert(C);
        assert_eq!(e.len(), 3);
        e.remove(&A);
        assert_eq!(e.len(), 2);
        e.clear();
        assert_eq!(e.len(), 0);
    }

    ///////////////////////////////////////////////////////////////////////////
    // intersect

    #[test]
    fn test_two_empties_do_not_intersect() {
        let e1: EnumSet<Foo> = EnumSet::new();
        let e2: EnumSet<Foo> = EnumSet::new();
        assert!(e1.is_disjoint(&e2));
    }

    #[test]
    fn test_empty_does_not_intersect_with_full() {
        let e1: EnumSet<Foo> = EnumSet::new();

        let mut e2: EnumSet<Foo> = EnumSet::new();
        e2.insert(A);
        e2.insert(B);
        e2.insert(C);

        assert!(e1.is_disjoint(&e2));
    }

    #[test]
    fn test_disjoint_intersects() {
        let mut e1: EnumSet<Foo> = EnumSet::new();
        e1.insert(A);

        let mut e2: EnumSet<Foo> = EnumSet::new();
        e2.insert(B);

        assert!(e1.is_disjoint(&e2));
    }

    #[test]
    fn test_overlapping_intersects() {
        let mut e1: EnumSet<Foo> = EnumSet::new();
        e1.insert(A);

        let mut e2: EnumSet<Foo> = EnumSet::new();
        e2.insert(A);
        e2.insert(B);

        assert!(!e1.is_disjoint(&e2));
    }

    ///////////////////////////////////////////////////////////////////////////
    // contains and contains_elem

    #[test]
    fn test_superset() {
        let mut e1: EnumSet<Foo> = EnumSet::new();
        e1.insert(A);

        let mut e2: EnumSet<Foo> = EnumSet::new();
        e2.insert(A);
        e2.insert(B);

        let mut e3: EnumSet<Foo> = EnumSet::new();
        e3.insert(C);

        assert!(e1.is_subset(&e2));
        assert!(e2.is_superset(&e1));
        assert!(!e3.is_superset(&e2))
        assert!(!e2.is_superset(&e3))
    }

    #[test]
    fn test_contains() {
        let mut e1: EnumSet<Foo> = EnumSet::new();
        e1.insert(A);
        assert!(e1.contains(&A));
        assert!(!e1.contains(&B));
        assert!(!e1.contains(&C));

        e1.insert(A);
        e1.insert(B);
        assert!(e1.contains(&A));
        assert!(e1.contains(&B));
        assert!(!e1.contains(&C));
    }

    ///////////////////////////////////////////////////////////////////////////
    // iter

    #[test]
    fn test_iterator() {
        let mut e1: EnumSet<Foo> = EnumSet::new();

        let elems: Vec<Foo> = e1.iter().collect();
        assert!(elems.is_empty())

        e1.insert(A);
        let elems = e1.iter().collect();
        assert_eq!(vec![A], elems)

        e1.insert(C);
        let elems = e1.iter().collect();
        assert_eq!(vec![A,C], elems)

        e1.insert(C);
        let elems = e1.iter().collect();
        assert_eq!(vec![A,C], elems)

        e1.insert(B);
        let elems = e1.iter().collect();
        assert_eq!(vec![A,B,C], elems)
    }

    ///////////////////////////////////////////////////////////////////////////
    // operators

    #[test]
    fn test_operators() {
        let mut e1: EnumSet<Foo> = EnumSet::new();
        e1.insert(A);
        e1.insert(C);

        let mut e2: EnumSet<Foo> = EnumSet::new();
        e2.insert(B);
        e2.insert(C);

        let e_union = e1 | e2;
        let elems = e_union.iter().collect();
        assert_eq!(vec![A,B,C], elems)

        let e_intersection = e1 & e2;
        let elems = e_intersection.iter().collect();
        assert_eq!(vec![C], elems)

        let e_subtract = e1 - e2;
        let elems = e_subtract.iter().collect();
        assert_eq!(vec![A], elems)
    }

    #[test]
    #[should_fail]
    fn test_overflow() {
        #[allow(dead_code)]
        #[repr(uint)]
        enum Bar {
            V00, V01, V02, V03, V04, V05, V06, V07, V08, V09,
            V10, V11, V12, V13, V14, V15, V16, V17, V18, V19,
            V20, V21, V22, V23, V24, V25, V26, V27, V28, V29,
            V30, V31, V32, V33, V34, V35, V36, V37, V38, V39,
            V40, V41, V42, V43, V44, V45, V46, V47, V48, V49,
            V50, V51, V52, V53, V54, V55, V56, V57, V58, V59,
            V60, V61, V62, V63, V64, V65, V66, V67, V68, V69,
        }
        impl CLike for Bar {
            fn to_uint(&self) -> uint {
                *self as uint
            }

            fn from_uint(v: uint) -> Bar {
                unsafe { mem::transmute(v) }
            }
        }
        let mut set = EnumSet::empty();
        set.add(V64);
    }
}
<commit_msg>auto merge of #18756 : jbcrail/rust/add-enum-set-bitxor, r=alexcrichton<commit_after>// Copyright 2012 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.

//! A structure for holding a set of enum variants.
//!
//! This module defines a container which uses an efficient bit mask
//! representation to hold C-like enum variants.

use core::prelude::*;
use core::fmt;

// FIXME(contentions): implement union family of methods? (general design may be wrong here)

#[deriving(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
/// A specialized `Set` implementation to use enum types.
pub struct EnumSet<E> {
    // We must maintain the invariant that no bits are set
    // for which no variant exists
    bits: uint
}

impl<E:CLike+fmt::Show> fmt::Show for EnumSet<E> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(fmt, "{{"));
        let mut first = true;
        for e in self.iter() {
            if !first {
                try!(write!(fmt, ", "));
            }
            try!(write!(fmt, "{}", e));
            first = false;
        }
        write!(fmt, "}}")
    }
}

/**
An interface for casting C-like enum to uint and back.
A typically implementation is as below.

```{rust,ignore}
#[repr(uint)]
enum Foo {
    A, B, C
}

impl CLike for Foo {
    fn to_uint(&self) -> uint {
        *self as uint
    }

    fn from_uint(v: uint) -> Foo {
        unsafe { mem::transmute(v) }
    }
}
```
*/
pub trait CLike {
    /// Converts a C-like enum to a `uint`.
    fn to_uint(&self) -> uint;
    /// Converts a `uint` to a C-like enum.
    fn from_uint(uint) -> Self;
}

fn bit<E:CLike>(e: &E) -> uint {
    use core::uint;
    let value = e.to_uint();
    assert!(value < uint::BITS,
            "EnumSet only supports up to {} variants.", uint::BITS - 1);
    1 << value
}

impl<E:CLike> EnumSet<E> {
    /// Deprecated: Renamed to `new`.
    #[deprecated = "Renamed to `new`"]
    pub fn empty() -> EnumSet<E> {
        EnumSet::new()
    }

    /// Returns an empty `EnumSet`.
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn new() -> EnumSet<E> {
        EnumSet {bits: 0}
    }

    /// Returns the number of elements in the given `EnumSet`.
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn len(&self) -> uint {
        self.bits.count_ones()
    }

    /// Returns true if the `EnumSet` is empty.
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn is_empty(&self) -> bool {
        self.bits == 0
    }

    pub fn clear(&mut self) {
        self.bits = 0;
    }

    /// Returns `true` if the `EnumSet` contains any enum of the given `EnumSet`.
    /// Deprecated: Use `is_disjoint`.
    #[deprecated = "Use `is_disjoint`"]
    pub fn intersects(&self, e: EnumSet<E>) -> bool {
        !self.is_disjoint(&e)
    }

    /// Returns `false` if the `EnumSet` contains any enum of the given `EnumSet`.
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn is_disjoint(&self, other: &EnumSet<E>) -> bool {
        (self.bits & other.bits) == 0
    }

    /// Returns `true` if a given `EnumSet` is included in this `EnumSet`.
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn is_superset(&self, other: &EnumSet<E>) -> bool {
        (self.bits & other.bits) == other.bits
    }

    /// Returns `true` if this `EnumSet` is included in the given `EnumSet`.
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn is_subset(&self, other: &EnumSet<E>) -> bool {
        other.is_superset(self)
    }

    /// Returns the union of both `EnumSets`.
    pub fn union(&self, e: EnumSet<E>) -> EnumSet<E> {
        EnumSet {bits: self.bits | e.bits}
    }

    /// Returns the intersection of both `EnumSets`.
    pub fn intersection(&self, e: EnumSet<E>) -> EnumSet<E> {
        EnumSet {bits: self.bits & e.bits}
    }

    /// Deprecated: Use `insert`.
    #[deprecated = "Use `insert`"]
    pub fn add(&mut self, e: E) {
        self.insert(e);
    }

    /// Adds an enum to the `EnumSet`, and returns `true` if it wasn't there before
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn insert(&mut self, e: E) -> bool {
        let result = !self.contains(&e);
        self.bits |= bit(&e);
        result
    }

    /// Removes an enum from the EnumSet
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn remove(&mut self, e: &E) -> bool {
        let result = self.contains(e);
        self.bits &= !bit(e);
        result
    }

    /// Deprecated: use `contains`.
    #[deprecated = "use `contains"]
    pub fn contains_elem(&self, e: E) -> bool {
        self.contains(&e)
    }

    /// Returns `true` if an `EnumSet` contains a given enum.
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn contains(&self, e: &E) -> bool {
        (self.bits & bit(e)) != 0
    }

    /// Returns an iterator over an `EnumSet`.
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn iter(&self) -> Items<E> {
        Items::new(self.bits)
    }
}

impl<E:CLike> Sub<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
    fn sub(&self, e: &EnumSet<E>) -> EnumSet<E> {
        EnumSet {bits: self.bits & !e.bits}
    }
}

impl<E:CLike> BitOr<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
    fn bitor(&self, e: &EnumSet<E>) -> EnumSet<E> {
        EnumSet {bits: self.bits | e.bits}
    }
}

impl<E:CLike> BitAnd<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
    fn bitand(&self, e: &EnumSet<E>) -> EnumSet<E> {
        EnumSet {bits: self.bits & e.bits}
    }
}

impl<E:CLike> BitXor<EnumSet<E>, EnumSet<E>> for EnumSet<E> {
    fn bitxor(&self, e: &EnumSet<E>) -> EnumSet<E> {
        EnumSet {bits: self.bits ^ e.bits}
    }
}

/// An iterator over an EnumSet
pub struct Items<E> {
    index: uint,
    bits: uint,
}

impl<E:CLike> Items<E> {
    fn new(bits: uint) -> Items<E> {
        Items { index: 0, bits: bits }
    }
}

impl<E:CLike> Iterator<E> for Items<E> {
    fn next(&mut self) -> Option<E> {
        if self.bits == 0 {
            return None;
        }

        while (self.bits & 1) == 0 {
            self.index += 1;
            self.bits >>= 1;
        }
        let elem = CLike::from_uint(self.index);
        self.index += 1;
        self.bits >>= 1;
        Some(elem)
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        let exact = self.bits.count_ones();
        (exact, Some(exact))
    }
}

impl<E:CLike> FromIterator<E> for EnumSet<E> {
    fn from_iter<I:Iterator<E>>(iterator: I) -> EnumSet<E> {
        let mut ret = EnumSet::new();
        ret.extend(iterator);
        ret
    }
}

impl<E:CLike> Extend<E> for EnumSet<E> {
    fn extend<I: Iterator<E>>(&mut self, mut iterator: I) {
        for element in iterator {
            self.insert(element);
        }
    }
}

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

    use super::{EnumSet, CLike};

    #[deriving(PartialEq, Show)]
    #[repr(uint)]
    enum Foo {
        A, B, C
    }

    impl CLike for Foo {
        fn to_uint(&self) -> uint {
            *self as uint
        }

        fn from_uint(v: uint) -> Foo {
            unsafe { mem::transmute(v) }
        }
    }

    #[test]
    fn test_new() {
        let e: EnumSet<Foo> = EnumSet::new();
        assert!(e.is_empty());
    }

    #[test]
    fn test_show() {
        let mut e = EnumSet::new();
        assert_eq!("{}", e.to_string().as_slice());
        e.insert(A);
        assert_eq!("{A}", e.to_string().as_slice());
        e.insert(C);
        assert_eq!("{A, C}", e.to_string().as_slice());
    }

    #[test]
    fn test_len() {
        let mut e = EnumSet::new();
        assert_eq!(e.len(), 0);
        e.insert(A);
        e.insert(B);
        e.insert(C);
        assert_eq!(e.len(), 3);
        e.remove(&A);
        assert_eq!(e.len(), 2);
        e.clear();
        assert_eq!(e.len(), 0);
    }

    ///////////////////////////////////////////////////////////////////////////
    // intersect

    #[test]
    fn test_two_empties_do_not_intersect() {
        let e1: EnumSet<Foo> = EnumSet::new();
        let e2: EnumSet<Foo> = EnumSet::new();
        assert!(e1.is_disjoint(&e2));
    }

    #[test]
    fn test_empty_does_not_intersect_with_full() {
        let e1: EnumSet<Foo> = EnumSet::new();

        let mut e2: EnumSet<Foo> = EnumSet::new();
        e2.insert(A);
        e2.insert(B);
        e2.insert(C);

        assert!(e1.is_disjoint(&e2));
    }

    #[test]
    fn test_disjoint_intersects() {
        let mut e1: EnumSet<Foo> = EnumSet::new();
        e1.insert(A);

        let mut e2: EnumSet<Foo> = EnumSet::new();
        e2.insert(B);

        assert!(e1.is_disjoint(&e2));
    }

    #[test]
    fn test_overlapping_intersects() {
        let mut e1: EnumSet<Foo> = EnumSet::new();
        e1.insert(A);

        let mut e2: EnumSet<Foo> = EnumSet::new();
        e2.insert(A);
        e2.insert(B);

        assert!(!e1.is_disjoint(&e2));
    }

    ///////////////////////////////////////////////////////////////////////////
    // contains and contains_elem

    #[test]
    fn test_superset() {
        let mut e1: EnumSet<Foo> = EnumSet::new();
        e1.insert(A);

        let mut e2: EnumSet<Foo> = EnumSet::new();
        e2.insert(A);
        e2.insert(B);

        let mut e3: EnumSet<Foo> = EnumSet::new();
        e3.insert(C);

        assert!(e1.is_subset(&e2));
        assert!(e2.is_superset(&e1));
        assert!(!e3.is_superset(&e2))
        assert!(!e2.is_superset(&e3))
    }

    #[test]
    fn test_contains() {
        let mut e1: EnumSet<Foo> = EnumSet::new();
        e1.insert(A);
        assert!(e1.contains(&A));
        assert!(!e1.contains(&B));
        assert!(!e1.contains(&C));

        e1.insert(A);
        e1.insert(B);
        assert!(e1.contains(&A));
        assert!(e1.contains(&B));
        assert!(!e1.contains(&C));
    }

    ///////////////////////////////////////////////////////////////////////////
    // iter

    #[test]
    fn test_iterator() {
        let mut e1: EnumSet<Foo> = EnumSet::new();

        let elems: Vec<Foo> = e1.iter().collect();
        assert!(elems.is_empty())

        e1.insert(A);
        let elems = e1.iter().collect();
        assert_eq!(vec![A], elems)

        e1.insert(C);
        let elems = e1.iter().collect();
        assert_eq!(vec![A,C], elems)

        e1.insert(C);
        let elems = e1.iter().collect();
        assert_eq!(vec![A,C], elems)

        e1.insert(B);
        let elems = e1.iter().collect();
        assert_eq!(vec![A,B,C], elems)
    }

    ///////////////////////////////////////////////////////////////////////////
    // operators

    #[test]
    fn test_operators() {
        let mut e1: EnumSet<Foo> = EnumSet::new();
        e1.insert(A);
        e1.insert(C);

        let mut e2: EnumSet<Foo> = EnumSet::new();
        e2.insert(B);
        e2.insert(C);

        let e_union = e1 | e2;
        let elems = e_union.iter().collect();
        assert_eq!(vec![A,B,C], elems)

        let e_intersection = e1 & e2;
        let elems = e_intersection.iter().collect();
        assert_eq!(vec![C], elems)

        // Another way to express intersection
        let e_intersection = e1 - (e1 - e2);
        let elems = e_intersection.iter().collect();
        assert_eq!(vec![C], elems)

        let e_subtract = e1 - e2;
        let elems = e_subtract.iter().collect();
        assert_eq!(vec![A], elems)

        // Bitwise XOR of two sets, aka symmetric difference
        let e_symmetric_diff = e1 ^ e2;
        let elems = e_symmetric_diff.iter().collect();
        assert_eq!(vec![A,B], elems)

        // Another way to express symmetric difference
        let e_symmetric_diff = (e1 - e2) | (e2 - e1);
        let elems = e_symmetric_diff.iter().collect();
        assert_eq!(vec![A,B], elems)

        // Yet another way to express symmetric difference
        let e_symmetric_diff = (e1 | e2) - (e1 & e2);
        let elems = e_symmetric_diff.iter().collect();
        assert_eq!(vec![A,B], elems)
    }

    #[test]
    #[should_fail]
    fn test_overflow() {
        #[allow(dead_code)]
        #[repr(uint)]
        enum Bar {
            V00, V01, V02, V03, V04, V05, V06, V07, V08, V09,
            V10, V11, V12, V13, V14, V15, V16, V17, V18, V19,
            V20, V21, V22, V23, V24, V25, V26, V27, V28, V29,
            V30, V31, V32, V33, V34, V35, V36, V37, V38, V39,
            V40, V41, V42, V43, V44, V45, V46, V47, V48, V49,
            V50, V51, V52, V53, V54, V55, V56, V57, V58, V59,
            V60, V61, V62, V63, V64, V65, V66, V67, V68, V69,
        }
        impl CLike for Bar {
            fn to_uint(&self) -> uint {
                *self as uint
            }

            fn from_uint(v: uint) -> Bar {
                unsafe { mem::transmute(v) }
            }
        }
        let mut set = EnumSet::empty();
        set.add(V64);
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;
//extern crate serialize;

use nom::{IResult,FlatMapper,Mapper,Producer,ProducerState,FileProducer};
use nom::IResult::*;

use std::str;
use std::collections::HashMap;
//use serialize::hex::ToHex;

pub trait HexDisplay {
      /// Converts the value of `self` to a hex value, returning the owned
      ///     /// string.
  fn to_hex(&self, chunk_size: usize) -> String;
}

static CHARS: &'static[u8] = b"0123456789abcdef";

impl HexDisplay for [u8] {
    fn to_hex(&self, chunk_size: usize) -> String {
      let mut v = Vec::with_capacity(self.len() * 3);
      let mut i = 0;
      for chunk in self.chunks(chunk_size) {
        let s = format!("{:08x}", i);
        let s2: &str = &s;
        for &ch in s.as_bytes().iter() {
          v.push(ch);
        }
        v.push('\t' as u8);

        i = i + chunk_size;

        for &byte in chunk {
          v.push(CHARS[(byte >> 4) as usize]);
          v.push(CHARS[(byte & 0xf) as usize]);
          v.push(' ' as u8);
        }
        if chunk_size > chunk.len() {
          for i in 0..(chunk_size - chunk.len()) {
            v.push(' ' as u8);
            v.push(' ' as u8);
            v.push(' ' as u8);
          }
        }
        v.push('\t' as u8);

        for &byte in chunk {
          if (byte >=32 && byte <= 126) || byte >= 128 {
            v.push(byte);
          } else {
            v.push('.' as u8);
          }
        }
        v.push('\n' as u8);
      }

      unsafe {
        String::from_utf8_unchecked(v)
      }
    }
}

fn mp4_box(input:&[u8]) -> IResult<&[u8], &[u8]> {

  take!(offset_parser 4);
  match offset_parser(input) {
    Done(i, offset_bytes) => {
      let offset:u32 = (offset_bytes[3] as u32) + (offset_bytes[2] as u32) * 0x100 + (offset_bytes[1] as u32) * 0x10000 + (offset_bytes[0] as u32) * 0x1000000;
      let sz: usize = offset as usize;
      if i.len() >= sz {
        return Done(&i[(sz-4)..], &i[0..(sz-4)])
      } else {
        return Incomplete(0)
      }
    },
    e => e
  }
}

#[derive(PartialEq,Eq,Debug)]
struct FileType<'a> {
  major_brand:         &'a str,
  major_brand_version: &'a [u8],
  compatible_brands:   Vec<&'a str>
}

#[derive(PartialEq,Eq,Debug)]
enum MP4Box<'a> {
  Ftyp(FileType<'a>),
  Moov,
  Free
}

take!(offset 4);
tag!(ftyp    "ftyp".as_bytes());

fn brand_name(input:&[u8]) -> IResult<&[u8],&str> {
  take!(major_brand_bytes 4);
  major_brand_bytes(input).map_res(str::from_utf8)
}
take!(major_brand_version 4);
many0!(compatible_brands<&[u8],&str> brand_name);

fn filetype_parser<'a>(input: &'a[u8]) -> IResult<&'a [u8], FileType<'a> > {
  chaining_parser!(input, ||{FileType{major_brand: m, major_brand_version:v, compatible_brands: c}},
    m: brand_name,
    v: major_brand_version,
    c: compatible_brands,)
}

o!(filetype <&[u8], FileType>  ftyp ~ [ filetype_parser ]);

fn filetype_box(input:&[u8]) -> IResult<&[u8], MP4Box> {
  //FIXME: flat_map should work here
  //mp4_box(input).flat_map(filetype)
  match mp4_box(input) {
    Done(i, o) => {
      match filetype(o) {
        Done(i2, o2) => {
          Done(i, MP4Box::Ftyp(o2))
        },
        a => Error(0)
      }
    },
    a => Error(0)
  }
}

tag!(free    "ftyp".as_bytes());
fn free_box(input:&[u8]) -> IResult<&[u8], MP4Box> {
  match mp4_box(input) {
    Done(i, o) => {
      match free(o) {
        Done(i2, o2) => {
          Done(i, MP4Box::Free)
        },
        a => Error(0)
      }
    },
    a => Error(0)
  }
}

alt!(box_parser<&[u8], MP4Box>, filetype_box | free_box);

fn parse_mp4_file(filename: &str) {
  FileProducer::new(filename, 150).map(|producer: FileProducer| {
    let mut p = producer;
    match p.produce() {
      ProducerState::Data(bytes) => {
        println!("bytes:\n{}", bytes.to_hex(8));
        match box_parser(bytes) {
          Done(i, o) => {
            match o {
              MP4Box::Ftyp(f) => println!("parsed ftyp: {:?}", f),
              MP4Box::Moov    => println!("found moov box"),
              MP4Box::Free    => println!("found free box")
            }
            println!("remaining:\n{}", i.to_hex(8))
          },
          a => println!("error: {:?}", a)
        }
      },
      _ => println!("got error")
    }
    /*//p.push(|par| {println!("parsed file: {}", par); par});
    //p.push(|par| par.flat_map(print));
    fn pr<'a,'b,'c>(data: &[u8]) -> IResult<'b,&[u8], &[u8]> {
      println!("bytes: {:?}", &data[0..20]);
      //Done("".as_bytes(), data).map_res(str::from_utf8);
      Done("".as_bytes(),"".as_bytes())
    }
    pusher!(ps, pr);
    ps(&mut p);
    */
    assert!(false);
  });

}
#[test]
fn file_test() {
  parse_mp4_file("small.mp4");
}
#[test]
fn bunny_test() {
  parse_mp4_file("bigbuckbunny.mp4");
}
<commit_msg>retransmit errors and incomplete<commit_after>#[macro_use]
extern crate nom;
//extern crate serialize;

use nom::{IResult,FlatMapper,Mapper,Producer,ProducerState,FileProducer};
use nom::IResult::*;

use std::str;
use std::collections::HashMap;
//use serialize::hex::ToHex;

pub trait HexDisplay {
      /// Converts the value of `self` to a hex value, returning the owned
      ///     /// string.
  fn to_hex(&self, chunk_size: usize) -> String;
}

static CHARS: &'static[u8] = b"0123456789abcdef";

impl HexDisplay for [u8] {
    fn to_hex(&self, chunk_size: usize) -> String {
      let mut v = Vec::with_capacity(self.len() * 3);
      let mut i = 0;
      for chunk in self.chunks(chunk_size) {
        let s = format!("{:08x}", i);
        let s2: &str = &s;
        for &ch in s.as_bytes().iter() {
          v.push(ch);
        }
        v.push('\t' as u8);

        i = i + chunk_size;

        for &byte in chunk {
          v.push(CHARS[(byte >> 4) as usize]);
          v.push(CHARS[(byte & 0xf) as usize]);
          v.push(' ' as u8);
        }
        if chunk_size > chunk.len() {
          for i in 0..(chunk_size - chunk.len()) {
            v.push(' ' as u8);
            v.push(' ' as u8);
            v.push(' ' as u8);
          }
        }
        v.push('\t' as u8);

        for &byte in chunk {
          if (byte >=32 && byte <= 126) || byte >= 128 {
            v.push(byte);
          } else {
            v.push('.' as u8);
          }
        }
        v.push('\n' as u8);
      }

      unsafe {
        String::from_utf8_unchecked(v)
      }
    }
}

fn mp4_box(input:&[u8]) -> IResult<&[u8], &[u8]> {

  take!(offset_parser 4);
  match offset_parser(input) {
    Done(i, offset_bytes) => {
      let offset:u32 = (offset_bytes[3] as u32) + (offset_bytes[2] as u32) * 0x100 + (offset_bytes[1] as u32) * 0x10000 + (offset_bytes[0] as u32) * 0x1000000;
      let sz: usize = offset as usize;
      if i.len() >= sz {
        return Done(&i[(sz-4)..], &i[0..(sz-4)])
      } else {
        return Incomplete(0)
      }
    },
    e => e
  }
}

#[derive(PartialEq,Eq,Debug)]
struct FileType<'a> {
  major_brand:         &'a str,
  major_brand_version: &'a [u8],
  compatible_brands:   Vec<&'a str>
}

#[derive(PartialEq,Eq,Debug)]
enum MP4Box<'a> {
  Ftyp(FileType<'a>),
  Moov,
  Free
}

take!(offset 4);
tag!(ftyp    "ftyp".as_bytes());

fn brand_name(input:&[u8]) -> IResult<&[u8],&str> {
  take!(major_brand_bytes 4);
  major_brand_bytes(input).map_res(str::from_utf8)
}
take!(major_brand_version 4);
many0!(compatible_brands<&[u8],&str> brand_name);

fn filetype_parser<'a>(input: &'a[u8]) -> IResult<&'a [u8], FileType<'a> > {
  chaining_parser!(input, ||{FileType{major_brand: m, major_brand_version:v, compatible_brands: c}},
    m: brand_name,
    v: major_brand_version,
    c: compatible_brands,)
}

o!(filetype <&[u8], FileType>  ftyp ~ [ filetype_parser ]);

fn filetype_box(input:&[u8]) -> IResult<&[u8], MP4Box> {
  //FIXME: flat_map should work here
  //mp4_box(input).flat_map(filetype)
  match mp4_box(input) {
    Done(i, o) => {
      match filetype(o) {
        Done(i2, o2) => {
          Done(i, MP4Box::Ftyp(o2))
        },
        Error(a) => Error(a),
        Incomplete(a) => Incomplete(a)
      }
    },
    Error(a) => Error(a),
    Incomplete(a) => Incomplete(a)
  }
}

tag!(free    "ftyp".as_bytes());
fn free_box(input:&[u8]) -> IResult<&[u8], MP4Box> {
  match mp4_box(input) {
    Done(i, o) => {
      match free(o) {
        Done(i2, o2) => {
          Done(i, MP4Box::Free)
        },
        a => Error(0)
      }
    },
    a => Error(0)
  }
}

alt!(box_parser<&[u8], MP4Box>, filetype_box | free_box);

fn parse_mp4_file(filename: &str) {
  FileProducer::new(filename, 150).map(|producer: FileProducer| {
    let mut p = producer;
    match p.produce() {
      ProducerState::Data(bytes) => {
        println!("bytes:\n{}", bytes.to_hex(8));
        match box_parser(bytes) {
          Done(i, o) => {
            match o {
              MP4Box::Ftyp(f) => println!("parsed ftyp: {:?}", f),
              MP4Box::Moov    => println!("found moov box"),
              MP4Box::Free    => println!("found free box")
            }
            println!("remaining:\n{}", i.to_hex(8))
          },
          a => println!("error: {:?}", a)
        }
      },
      _ => println!("got error")
    }
    /*//p.push(|par| {println!("parsed file: {}", par); par});
    //p.push(|par| par.flat_map(print));
    fn pr<'a,'b,'c>(data: &[u8]) -> IResult<'b,&[u8], &[u8]> {
      println!("bytes: {:?}", &data[0..20]);
      //Done("".as_bytes(), data).map_res(str::from_utf8);
      Done("".as_bytes(),"".as_bytes())
    }
    pusher!(ps, pr);
    ps(&mut p);
    */
    assert!(false);
  });

}
#[test]
fn file_test() {
  parse_mp4_file("small.mp4");
}
#[test]
fn bunny_test() {
  parse_mp4_file("bigbuckbunny.mp4");
}
<|endoftext|>


<commit_before><commit_msg>add tests for the pihex library<commit_after>extern crate pihex;
use pihex::*;

#[test]
fn pihex_test() {
    assert_eq!(pihex(0), "243f");
    assert_eq!(pihex(1), "43f6");
    assert_eq!(pihex(2), "3f6a");
    assert_eq!(pihex(3), "f6a8");
    assert_eq!(pihex(4), "6a88");
    assert_eq!(pihex(8), "85a3");
    assert_eq!(pihex(12), "08d3");
    assert_eq!(pihex(96), "c0ac");
    assert_eq!(pihex(128), "9216");
    assert_eq!(pihex(1024), "25d4");
    assert_eq!(pihex(4096), "5a04");
    assert_eq!(pihex(8192), "77af");
}
<|endoftext|>


<commit_before><commit_msg>Assignments are now checked.<commit_after><|endoftext|>


<commit_before><commit_msg>Simplified name conversion<commit_after><|endoftext|>


<commit_before>// Copyright 2013 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.

/*! Task-local garbage-collected boxes

The `Gc` type provides shared ownership of an immutable value. Destruction is not deterministic, and
will occur some time between every `Gc` handle being gone and the end of the task. The garbage
collector is task-local so `Gc<T>` is not sendable.

*/

use kinds::Send;
use clone::{Clone, DeepClone};
use managed;

/// Immutable garbage-collected pointer type
#[lang="gc"]
#[cfg(not(test))]
#[no_send]
pub struct Gc<T> {
    priv ptr: @T
}

#[cfg(test)]
#[no_send]
pub struct Gc<T> {
    priv ptr: @T
}

impl<T: 'static> Gc<T> {
    /// Construct a new garbage-collected box
    #[inline]
    pub fn new(value: T) -> Gc<T> {
        Gc { ptr: @value }
    }

    /// Borrow the value contained in the garbage-collected box
    #[inline]
    pub fn borrow<'r>(&'r self) -> &'r T {
        &*self.ptr
    }

    /// Determine if two garbage-collected boxes point to the same object
    #[inline]
    pub fn ptr_eq(&self, other: &Gc<T>) -> bool {
        managed::ptr_eq(self.ptr, other.ptr)
    }
}

impl<T> Clone for Gc<T> {
    /// Clone the pointer only
    #[inline]
    fn clone(&self) -> Gc<T> {
        Gc{ ptr: self.ptr }
    }
}

/// An value that represents the task-local managed heap.
///
/// Use this like `let foo = box(GC) Bar::new(...);`
#[lang="managed_heap"]
#[cfg(not(test))]
pub static GC: () = ();

#[cfg(test)]
pub static GC: () = ();

/// The `Send` bound restricts this to acyclic graphs where it is well-defined.
///
/// A `Freeze` bound would also work, but `Send` *or* `Freeze` cannot be expressed.
impl<T: DeepClone + Send + 'static> DeepClone for Gc<T> {
    #[inline]
    fn deep_clone(&self) -> Gc<T> {
        Gc::new(self.borrow().deep_clone())
    }
}

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

    #[test]
    fn test_clone() {
        let x = Gc::new(RefCell::new(5));
        let y = x.clone();
        x.borrow().with_mut(|inner| {
            *inner = 20;
        });
        assert_eq!(y.borrow().with(|x| *x), 20);
    }

    #[test]
    fn test_deep_clone() {
        let x = Gc::new(RefCell::new(5));
        let y = x.deep_clone();
        x.borrow().with_mut(|inner| {
            *inner = 20;
        });
        assert_eq!(y.borrow().with(|x| *x), 5);
    }

    #[test]
    fn test_simple() {
        let x = Gc::new(5);
        assert_eq!(*x.borrow(), 5);
    }

    #[test]
    fn test_simple_clone() {
        let x = Gc::new(5);
        let y = x.clone();
        assert_eq!(*x.borrow(), 5);
        assert_eq!(*y.borrow(), 5);
    }

    #[test]
    fn test_ptr_eq() {
        let x = Gc::new(5);
        let y = x.clone();
        let z = Gc::new(7);
        assert!(x.ptr_eq(&x));
        assert!(x.ptr_eq(&y));
        assert!(!x.ptr_eq(&z));
    }

    #[test]
    fn test_destructor() {
        let x = Gc::new(~5);
        assert_eq!(**x.borrow(), 5);
    }
}
<commit_msg>auto merge of #11543 : thestinger/rust/gc, r=cmr<commit_after>// Copyright 2013 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.

/*! Task-local garbage-collected boxes

The `Gc` type provides shared ownership of an immutable value. Destruction is not deterministic, and
will occur some time between every `Gc` handle being gone and the end of the task. The garbage
collector is task-local so `Gc<T>` is not sendable.

*/

#[allow(experimental)];

use kinds::Send;
use clone::{Clone, DeepClone};
use managed;

/// Immutable garbage-collected pointer type
#[lang="gc"]
#[cfg(not(test))]
#[no_send]
#[experimental = "Gc is currently based on reference-counting and will not collect cycles until \
                  task annihilation. For now, cycles need to be broken manually by using `Rc<T>` \
                  with a non-owning `Weak<T>` pointer. A tracing garbage collector is planned."]
pub struct Gc<T> {
    priv ptr: @T
}

#[cfg(test)]
#[no_send]
pub struct Gc<T> {
    priv ptr: @T
}

impl<T: 'static> Gc<T> {
    /// Construct a new garbage-collected box
    #[inline]
    pub fn new(value: T) -> Gc<T> {
        Gc { ptr: @value }
    }

    /// Borrow the value contained in the garbage-collected box
    #[inline]
    pub fn borrow<'r>(&'r self) -> &'r T {
        &*self.ptr
    }

    /// Determine if two garbage-collected boxes point to the same object
    #[inline]
    pub fn ptr_eq(&self, other: &Gc<T>) -> bool {
        managed::ptr_eq(self.ptr, other.ptr)
    }
}

impl<T> Clone for Gc<T> {
    /// Clone the pointer only
    #[inline]
    fn clone(&self) -> Gc<T> {
        Gc{ ptr: self.ptr }
    }
}

/// An value that represents the task-local managed heap.
///
/// Use this like `let foo = box(GC) Bar::new(...);`
#[lang="managed_heap"]
#[cfg(not(test))]
pub static GC: () = ();

#[cfg(test)]
pub static GC: () = ();

/// The `Send` bound restricts this to acyclic graphs where it is well-defined.
///
/// A `Freeze` bound would also work, but `Send` *or* `Freeze` cannot be expressed.
impl<T: DeepClone + Send + 'static> DeepClone for Gc<T> {
    #[inline]
    fn deep_clone(&self) -> Gc<T> {
        Gc::new(self.borrow().deep_clone())
    }
}

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

    #[test]
    fn test_clone() {
        let x = Gc::new(RefCell::new(5));
        let y = x.clone();
        x.borrow().with_mut(|inner| {
            *inner = 20;
        });
        assert_eq!(y.borrow().with(|x| *x), 20);
    }

    #[test]
    fn test_deep_clone() {
        let x = Gc::new(RefCell::new(5));
        let y = x.deep_clone();
        x.borrow().with_mut(|inner| {
            *inner = 20;
        });
        assert_eq!(y.borrow().with(|x| *x), 5);
    }

    #[test]
    fn test_simple() {
        let x = Gc::new(5);
        assert_eq!(*x.borrow(), 5);
    }

    #[test]
    fn test_simple_clone() {
        let x = Gc::new(5);
        let y = x.clone();
        assert_eq!(*x.borrow(), 5);
        assert_eq!(*y.borrow(), 5);
    }

    #[test]
    fn test_ptr_eq() {
        let x = Gc::new(5);
        let y = x.clone();
        let z = Gc::new(7);
        assert!(x.ptr_eq(&x));
        assert!(x.ptr_eq(&y));
        assert!(!x.ptr_eq(&z));
    }

    #[test]
    fn test_destructor() {
        let x = Gc::new(~5);
        assert_eq!(**x.borrow(), 5);
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::io::{stdout, Write};

use super::peg::{Pipeline, Job};
use super::input_editor::readln;
use super::status::{SUCCESS, FAILURE};

pub struct Variables {
    variables: BTreeMap<String, String>,
}

impl Variables {
    pub fn new() -> Variables {
        Variables { variables: BTreeMap::new() }
    }

    pub fn read<I: IntoIterator>(&mut self, args: I) -> i32
        where I::Item: AsRef<str>
    {
        let mut out = stdout();
        for arg in args.into_iter().skip(1) {
            print!("{}=", arg.as_ref().trim());
            if let Err(message) = out.flush() {
                println!("{}: Failed to flush stdout", message);
                return FAILURE;
            }
            if let Some(value) = readln() {
                self.set_var(arg.as_ref(), value.trim());
            }
        }
        SUCCESS
    }

    pub fn let_<I: IntoIterator>(&mut self, args: I) -> i32
        where I::Item: AsRef<str>
    {
        let args = args.into_iter();
        let string: String = args.skip(1).fold(String::new(), |string, x| string + x.as_ref());
        let mut split = string.split('=');
        match (split.next().and_then(|x| if x == "" { None } else { Some(x) }), split.next()) {
            (Some(key), Some(value)) => {
                self.variables.insert(key.to_string(), value.to_string());
            },
            (Some(key), None) => {
                self.variables.remove(key);
            },
            _ => {
                for (key, value) in self.variables.iter() {
                    println!("{}={}", key, value);
                }
            }
        }
        SUCCESS
    }

    pub fn set_var(&mut self, name: &str, value: &str) {
        if !name.is_empty() {
            if value.is_empty() {
                self.variables.remove(&name.to_string());
            } else {
                self.variables.insert(name.to_string(), value.to_string());
            }
        }
    }

    pub fn expand_pipeline(&self, pipeline: &Pipeline) -> Pipeline {
        // TODO don't copy everything
        Pipeline::new(pipeline.jobs.iter().map(|job| {self.expand_job(job)}).collect())
    }

    pub fn expand_job(&self, job: &Job) -> Job {
        // TODO don't copy everything
        Job::from_vec_string(job.args
                                .iter()
                                .map(|original: &String| self.expand_string(&original).to_string())
                                .collect(),
                             job.background)
    }

    fn replace_substring(string: &mut String, start: usize, end: usize, replacement: &str) {
        let string_start = string.chars().take(start).collect::<String>();
        let string_end = string.chars().skip(end+1).collect::<String>();
        *string = string_start + replacement + &string_end;
    }

    #[inline]
    pub fn expand_string<'a>(&'a self, original: &'a str) -> String {
        let mut new = original.to_owned();
        let mut replacements: Vec<(usize, usize, String)> = vec![];
        for (n, _) in original.match_indices("$") {
            if n > 0 {
                if let Some(c) = original.chars().nth(n-1) {
                    if c == '\\' {
                        continue;
                    }
                }
            }
            let mut var_name = "".to_owned();
            for (i, c) in original.char_indices().skip(n+1) { // skip the dollar sign
                if !c.is_whitespace() {
                    var_name.push(c);
                    if i == original.len() - 1 {
                        replacements.push((n, i, var_name.clone()));
                        break;
                    }
                } else {
                    replacements.push((n, i-1, var_name.clone()));
                    break;
                }
            }
        }

        for &(start, end, ref var_name) in replacements.iter().rev() {
            let value: &str = match self.variables.get(var_name) {
                Some(v) => &v,
                None => ""
            };
            Variables::replace_substring(&mut new, start, end, value);
        }
        new.clone()
    }
}

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

    #[test]
    fn undefined_variable_expands_to_empty_string() {
        let variables = Variables::new();
        let expanded = variables.expand_string("$FOO");
        assert_eq!("", &expanded);
    }

    #[test]
    fn let_and_expand_a_variable() {
        let mut variables = Variables::new();
        variables.let_(vec!["let", "FOO", "=", "BAR"]);
        let expanded = variables.expand_string("$FOO");
        assert_eq!("BAR", &expanded);
    }

    #[test]
    fn set_var_and_expand_a_variable() {
        let mut variables = Variables::new();
        variables.set_var("FOO", "BAR");
        let expanded = variables.expand_string("$FOO");
        assert_eq!("BAR", &expanded);
    }

    #[test]
    fn remove_a_variable_with_let() {
        let mut variables = Variables::new();
        variables.let_(vec!["let", "FOO", "=", "BAR"]);
        variables.let_(vec!["let", "FOO"]);
        let expanded = variables.expand_string("$FOO");
        assert_eq!("", &expanded);
    }

    #[test]
    fn expand_several_variables() {
        let mut variables = Variables::new();
        variables.let_(vec!["let", "FOO", "=", "BAR"]);
        variables.let_(vec!["let", "X", "=", "Y"]);
        let expanded = variables.expand_string("variables: $FOO $X");
        assert_eq!("variables: BAR Y", &expanded);
    }

    #[test]
    fn replace_substring() {
        let mut string = "variable: $FOO".to_owned();
        Variables::replace_substring(&mut string, 10, 13, "BAR");
        assert_eq!("variable: BAR", string);
    }

    #[test]
    fn escape_with_backslash() {
        let mut variables = Variables::new();
        let expanded = variables.expand_string("\\$FOO");
        assert_eq!("\\$FOO", &expanded);
    }
}
<commit_msg>Add a function to check if a character is a valid variable name character<commit_after>use std::collections::BTreeMap;
use std::io::{stdout, Write};

use super::peg::{Pipeline, Job};
use super::input_editor::readln;
use super::status::{SUCCESS, FAILURE};

pub struct Variables {
    variables: BTreeMap<String, String>,
}

impl Variables {
    pub fn new() -> Variables {
        Variables { variables: BTreeMap::new() }
    }

    pub fn read<I: IntoIterator>(&mut self, args: I) -> i32
        where I::Item: AsRef<str>
    {
        let mut out = stdout();
        for arg in args.into_iter().skip(1) {
            print!("{}=", arg.as_ref().trim());
            if let Err(message) = out.flush() {
                println!("{}: Failed to flush stdout", message);
                return FAILURE;
            }
            if let Some(value) = readln() {
                self.set_var(arg.as_ref(), value.trim());
            }
        }
        SUCCESS
    }

    pub fn let_<I: IntoIterator>(&mut self, args: I) -> i32
        where I::Item: AsRef<str>
    {
        let args = args.into_iter();
        let string: String = args.skip(1).fold(String::new(), |string, x| string + x.as_ref());
        let mut split = string.split('=');
        match (split.next().and_then(|x| if x == "" { None } else { Some(x) }), split.next()) {
            (Some(key), Some(value)) => {
                self.variables.insert(key.to_string(), value.to_string());
            },
            (Some(key), None) => {
                self.variables.remove(key);
            },
            _ => {
                for (key, value) in self.variables.iter() {
                    println!("{}={}", key, value);
                }
            }
        }
        SUCCESS
    }

    pub fn set_var(&mut self, name: &str, value: &str) {
        if !name.is_empty() {
            if value.is_empty() {
                self.variables.remove(&name.to_string());
            } else {
                self.variables.insert(name.to_string(), value.to_string());
            }
        }
    }

    pub fn expand_pipeline(&self, pipeline: &Pipeline) -> Pipeline {
        // TODO don't copy everything
        Pipeline::new(pipeline.jobs.iter().map(|job| {self.expand_job(job)}).collect())
    }

    pub fn expand_job(&self, job: &Job) -> Job {
        // TODO don't copy everything
        Job::from_vec_string(job.args
                                .iter()
                                .map(|original: &String| self.expand_string(&original).to_string())
                                .collect(),
                             job.background)
    }

    fn replace_substring(string: &mut String, start: usize, end: usize, replacement: &str) {
        let string_start = string.chars().take(start).collect::<String>();
        let string_end = string.chars().skip(end+1).collect::<String>();
        *string = string_start + replacement + &string_end;
    }

    pub fn is_valid_variable_character(c: char) -> bool {
        c.is_alphanumeric() || c == '_' || c == '?'
    }

    #[inline]
    pub fn expand_string<'a>(&'a self, original: &'a str) -> String {
        let mut new = original.to_owned();
        let mut replacements: Vec<(usize, usize, String)> = vec![];
        for (n, _) in original.match_indices("$") {
            if n > 0 {
                if let Some(c) = original.chars().nth(n-1) {
                    if c == '\\' {
                        continue;
                    }
                }
            }
            let mut var_name = "".to_owned();
            for (i, c) in original.char_indices().skip(n+1) { // skip the dollar sign
                if Variables::is_valid_variable_character(c) {
                    var_name.push(c);
                    if i == original.len() - 1 {
                        replacements.push((n, i, var_name.clone()));
                        break;
                    }
                } else {
                    replacements.push((n, i-1, var_name.clone()));
                    break;
                }
            }
        }

        for &(start, end, ref var_name) in replacements.iter().rev() {
            let value: &str = match self.variables.get(var_name) {
                Some(v) => &v,
                None => ""
            };
            Variables::replace_substring(&mut new, start, end, value);
        }
        new.clone()
    }
}

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

    #[test]
    fn undefined_variable_expands_to_empty_string() {
        let variables = Variables::new();
        let expanded = variables.expand_string("$FOO");
        assert_eq!("", &expanded);
    }

    #[test]
    fn let_and_expand_a_variable() {
        let mut variables = Variables::new();
        variables.let_(vec!["let", "FOO", "=", "BAR"]);
        let expanded = variables.expand_string("$FOO");
        assert_eq!("BAR", &expanded);
    }

    #[test]
    fn set_var_and_expand_a_variable() {
        let mut variables = Variables::new();
        variables.set_var("FOO", "BAR");
        let expanded = variables.expand_string("$FOO");
        assert_eq!("BAR", &expanded);
    }

    #[test]
    fn remove_a_variable_with_let() {
        let mut variables = Variables::new();
        variables.let_(vec!["let", "FOO", "=", "BAR"]);
        variables.let_(vec!["let", "FOO"]);
        let expanded = variables.expand_string("$FOO");
        assert_eq!("", &expanded);
    }

    #[test]
    fn expand_several_variables() {
        let mut variables = Variables::new();
        variables.let_(vec!["let", "FOO", "=", "BAR"]);
        variables.let_(vec!["let", "X", "=", "Y"]);
        let expanded = variables.expand_string("variables: $FOO $X");
        assert_eq!("variables: BAR Y", &expanded);
    }

    #[test]
    fn replace_substring() {
        let mut string = "variable: $FOO".to_owned();
        Variables::replace_substring(&mut string, 10, 13, "BAR");
        assert_eq!("variable: BAR", string);
    }

    #[test]
    fn escape_with_backslash() {
        let mut variables = Variables::new();
        let expanded = variables.expand_string("\\$FOO");
        assert_eq!("\\$FOO", &expanded);
    }
}
<|endoftext|>


<commit_before><commit_msg>Address string hex encoding prefix can be cut silently<commit_after><|endoftext|>


<commit_before><commit_msg>Replace camelCase with snake_case<commit_after><|endoftext|>


<commit_before><commit_msg>Lay down some notes<commit_after><|endoftext|>


<commit_before><commit_msg>Problem 21<commit_after>fn insert<T: Clone>(elem: T, list: &[T], k: uint) -> ~[T] {
    let mut res = ~[];
    res.push_all(list.slice_to(k-1));
    res.push(elem);
    res.push_all(list.slice_from(k));
    res
}

fn main() {
    let list = ~['a', 'b', 'c', 'd'];
    println!("{:?}", insert('X', list, 2));
}

<|endoftext|>


<commit_before>use Renderable;
use context::Context;
use filters::{size, upcase, downcase, capitalize, minus, plus, times, divided_by, ceil, floor,
              round, prepend, append, first, last, pluralize, replace, date, sort, slice};
use filters::split;
use filters::join;
use error::Result;

pub struct Template {
    pub elements: Vec<Box<Renderable>>,
}

impl Renderable for Template {
    fn render(&self, context: &mut Context) -> Result<Option<String>> {

        context.maybe_add_filter("size", Box::new(size));
        context.maybe_add_filter("upcase", Box::new(upcase));
        context.maybe_add_filter("downcase", Box::new(downcase));
        context.maybe_add_filter("capitalize", Box::new(capitalize));
        context.maybe_add_filter("minus", Box::new(minus));
        context.maybe_add_filter("plus", Box::new(plus));
        context.maybe_add_filter("times", Box::new(times));
        context.maybe_add_filter("divided_by", Box::new(divided_by));
        context.maybe_add_filter("ceil", Box::new(ceil));
        context.maybe_add_filter("floor", Box::new(floor));
        context.maybe_add_filter("round", Box::new(round));
        context.maybe_add_filter("first", Box::new(first));
        context.maybe_add_filter("last", Box::new(last));
        context.maybe_add_filter("prepend", Box::new(prepend));
        context.maybe_add_filter("append", Box::new(append));
        context.maybe_add_filter("replace", Box::new(replace));
        context.maybe_add_filter("pluralize", Box::new(pluralize));
        context.maybe_add_filter("split", Box::new(split));
        context.maybe_add_filter("join", Box::new(join));
        context.maybe_add_filter("slice", Box::new(slice));
        context.maybe_add_filter("sort", Box::new(sort));
        context.maybe_add_filter("date", Box::new(date));

        let mut buf = String::new();
        for el in &self.elements {
            if let Some(ref x) = try!(el.render(context)) {
                buf = buf + x;
            }

            // Did the last element we processed set an interrupt? If so, we
            // need to abandon the rest of our child elements and just
            // return what we've got. This is usually in response to a
            // `break` or `continue` tag being rendered.
            if context.interrupted() {
                break;
            }
        }
        Ok(Some(buf))
    }
}

impl Template {
    pub fn new(elements: Vec<Box<Renderable>>) -> Template {
        Template { elements: elements }
    }
}
<commit_msg>Template::render(): Sort filters alphabetically<commit_after>use Renderable;
use context::Context;
use filters::{size, upcase, downcase, capitalize, minus, plus, times, divided_by, ceil, floor,
              round, prepend, append, first, last, pluralize, replace, date, sort, slice};
use filters::split;
use filters::join;
use error::Result;

pub struct Template {
    pub elements: Vec<Box<Renderable>>,
}

impl Renderable for Template {
    fn render(&self, context: &mut Context) -> Result<Option<String>> {

        context.maybe_add_filter("append", Box::new(append));
        context.maybe_add_filter("capitalize", Box::new(capitalize));
        context.maybe_add_filter("ceil", Box::new(ceil));
        context.maybe_add_filter("date", Box::new(date));
        context.maybe_add_filter("divided_by", Box::new(divided_by));
        context.maybe_add_filter("downcase", Box::new(downcase));
        context.maybe_add_filter("first", Box::new(first));
        context.maybe_add_filter("floor", Box::new(floor));
        context.maybe_add_filter("join", Box::new(join));
        context.maybe_add_filter("last", Box::new(last));
        context.maybe_add_filter("minus", Box::new(minus));
        context.maybe_add_filter("pluralize", Box::new(pluralize));
        context.maybe_add_filter("plus", Box::new(plus));
        context.maybe_add_filter("prepend", Box::new(prepend));
        context.maybe_add_filter("replace", Box::new(replace));
        context.maybe_add_filter("round", Box::new(round));
        context.maybe_add_filter("size", Box::new(size));
        context.maybe_add_filter("slice", Box::new(slice));
        context.maybe_add_filter("sort", Box::new(sort));
        context.maybe_add_filter("split", Box::new(split));
        context.maybe_add_filter("times", Box::new(times));
        context.maybe_add_filter("upcase", Box::new(upcase));

        let mut buf = String::new();
        for el in &self.elements {
            if let Some(ref x) = try!(el.render(context)) {
                buf = buf + x;
            }

            // Did the last element we processed set an interrupt? If so, we
            // need to abandon the rest of our child elements and just
            // return what we've got. This is usually in response to a
            // `break` or `continue` tag being rendered.
            if context.interrupted() {
                break;
            }
        }
        Ok(Some(buf))
    }
}

impl Template {
    pub fn new(elements: Vec<Box<Renderable>>) -> Template {
        Template { elements: elements }
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 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.

// This test case tests the incremental compilation hash (ICH) implementation
// for if expressions.

// The general pattern followed here is: Change one thing between rev1 and rev2
// and make sure that the hash has changed, then change nothing between rev2 and
// rev3 and make sure that the hash has not changed.

// must-compile-successfully
// revisions: cfail1 cfail2 cfail3
// compile-flags: -Z query-dep-graph

#![allow(warnings)]
#![feature(rustc_attrs)]
#![crate_type="rlib"]

// Change condition (if) -------------------------------------------------------
#[cfg(cfail1)]
pub fn change_condition(x: bool) -> u32 {
    if x {
        return 1
    }

    return 0
}

#[cfg(not(cfail1))]
#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_dirty(label="HirBody", cfg="cfail2")]
#[rustc_clean(label="HirBody", cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_condition(x: bool) -> u32 {
    if !x {
        return 1
    }

    return 0
}

// Change then branch (if) -----------------------------------------------------
#[cfg(cfail1)]
pub fn change_then_branch(x: bool) -> u32 {
    if x {
        return 1
    }

    return 0
}

#[cfg(not(cfail1))]
#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_dirty(label="HirBody", cfg="cfail2")]
#[rustc_clean(label="HirBody", cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_then_branch(x: bool) -> u32 {
    if x {
        return 2
    }

    return 0
}

// Change else branch (if) -----------------------------------------------------
#[cfg(cfail1)]
pub fn change_else_branch(x: bool) -> u32 {
    if x {
        1
    } else {
        2
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_dirty(label="HirBody", cfg="cfail2")]
#[rustc_clean(label="HirBody", cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_else_branch(x: bool) -> u32 {
    if x {
        1
    } else {
        3
    }
}

// Add else branch (if) --------------------------------------------------------
#[cfg(cfail1)]
pub fn add_else_branch(x: bool) -> u32 {
    let mut ret = 1;

    if x {
        ret += 1;
    }

    ret
}

#[cfg(not(cfail1))]
#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_dirty(label="HirBody", cfg="cfail2")]
#[rustc_clean(label="HirBody", cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn add_else_branch(x: bool) -> u32 {
    let mut ret = 1;

    if x {
        ret += 1;
    } else {
    }

    ret
}

// Change condition (if let) ---------------------------------------------------
#[cfg(cfail1)]
pub fn change_condition_if_let(x: Option<u32>) -> u32 {
    if let Some(_x) = x {
        return 1
    }

    0
}

#[cfg(not(cfail1))]
#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_dirty(label="HirBody", cfg="cfail2")]
#[rustc_clean(label="HirBody", cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_condition_if_let(x: Option<u32>) -> u32 {
    if let Some(_) = x {
        return 1
    }

    0
}

// Change then branch (if let) -------------------------------------------------
#[cfg(cfail1)]
pub fn change_then_branch_if_let(x: Option<u32>) -> u32 {
    if let Some(x) = x {
        return x
    }

    0
}

#[cfg(not(cfail1))]
#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_dirty(label="HirBody", cfg="cfail2")]
#[rustc_clean(label="HirBody", cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_then_branch_if_let(x: Option<u32>) -> u32 {
    if let Some(x) = x {
        return x + 1
    }

    0
}

// Change else branch (if let) -------------------------------------------------
#[cfg(cfail1)]
pub fn change_else_branch_if_let(x: Option<u32>) -> u32 {
    if let Some(x) = x {
        x
    } else {
        1
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_dirty(label="HirBody", cfg="cfail2")]
#[rustc_clean(label="HirBody", cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_else_branch_if_let(x: Option<u32>) -> u32 {
    if let Some(x) = x {
        x
    } else {
        2
    }
}

// Add else branch (if let) ----------------------------------------------------
#[cfg(cfail1)]
pub fn add_else_branch_if_let(x: Option<u32>) -> u32 {
    let mut ret = 1;

    if let Some(x) = x {
        ret += x;
    }

    ret
}

#[cfg(not(cfail1))]
#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_dirty(label="HirBody", cfg="cfail2")]
#[rustc_clean(label="HirBody", cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn add_else_branch_if_let(x: Option<u32>) -> u32 {
    let mut ret = 1;

    if let Some(x) = x {
        ret += x;
    } else {
    }

    ret
}
<commit_msg>Update if-expressions incremental hash tests<commit_after>// Copyright 2016 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.

// This test case tests the incremental compilation hash (ICH) implementation
// for if expressions.

// The general pattern followed here is: Change one thing between rev1 and rev2
// and make sure that the hash has changed, then change nothing between rev2 and
// rev3 and make sure that the hash has not changed.

// must-compile-successfully
// revisions: cfail1 cfail2 cfail3
// compile-flags: -Z query-dep-graph

#![allow(warnings)]
#![feature(rustc_attrs)]
#![crate_type="rlib"]

// Change condition (if) -------------------------------------------------------
#[cfg(cfail1)]
pub fn change_condition(x: bool) -> u32 {
    if x {
        return 1
    }

    return 0
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody,MirValidated,MirOptimized,TypeckTables")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_condition(x: bool) -> u32 {
    if !x {
        return 1
    }

    return 0
}

// Change then branch (if) -----------------------------------------------------
#[cfg(cfail1)]
pub fn change_then_branch(x: bool) -> u32 {
    if x {
        return 1
    }

    return 0
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody,MirValidated,MirOptimized")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_then_branch(x: bool) -> u32 {
    if x {
        return 2
    }

    return 0
}

// Change else branch (if) -----------------------------------------------------
#[cfg(cfail1)]
pub fn change_else_branch(x: bool) -> u32 {
    if x {
        1
    } else {
        2
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody,MirValidated,MirOptimized")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_else_branch(x: bool) -> u32 {
    if x {
        1
    } else {
        3
    }
}

// Add else branch (if) --------------------------------------------------------
#[cfg(cfail1)]
pub fn add_else_branch(x: bool) -> u32 {
    let mut ret = 1;

    if x {
        ret += 1;
    }

    ret
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody,TypeckTables")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn add_else_branch(x: bool) -> u32 {
    let mut ret = 1;

    if x {
        ret += 1;
    } else {
    }

    ret
}

// Change condition (if let) ---------------------------------------------------
#[cfg(cfail1)]
pub fn change_condition_if_let(x: Option<u32>) -> u32 {
    if let Some(_x) = x {
        return 1
    }

    0
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody,MirValidated,MirOptimized,TypeckTables")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_condition_if_let(x: Option<u32>) -> u32 {
    if let Some(_) = x {
        return 1
    }

    0
}

// Change then branch (if let) -------------------------------------------------
#[cfg(cfail1)]
pub fn change_then_branch_if_let(x: Option<u32>) -> u32 {
    if let Some(x) = x {
        return x
    }

    0
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody,MirValidated,MirOptimized,TypeckTables")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_then_branch_if_let(x: Option<u32>) -> u32 {
    if let Some(x) = x {
        return x + 1
    }

    0
}

// Change else branch (if let) -------------------------------------------------
#[cfg(cfail1)]
pub fn change_else_branch_if_let(x: Option<u32>) -> u32 {
    if let Some(x) = x {
        x
    } else {
        1
    }
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody,MirValidated,MirOptimized")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn change_else_branch_if_let(x: Option<u32>) -> u32 {
    if let Some(x) = x {
        x
    } else {
        2
    }
}

// Add else branch (if let) ----------------------------------------------------
#[cfg(cfail1)]
pub fn add_else_branch_if_let(x: Option<u32>) -> u32 {
    let mut ret = 1;

    if let Some(x) = x {
        ret += x;
    }

    ret
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody,TypeckTables")]
#[rustc_clean(cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
pub fn add_else_branch_if_let(x: Option<u32>) -> u32 {
    let mut ret = 1;

    if let Some(x) = x {
        ret += x;
    } else {
    }

    ret
}
<|endoftext|>


<commit_before><commit_msg>Add integration test setup<commit_after>use std::process::Command;

fn is_command_available(command: String) -> bool {
    // TODO NiCo: remove output on terminal for this check
    let mut result = Command::new(command)
                         .arg("-v")
                         .status();
    match result {
        Ok(status) => true,
        Err(_) => false,
    }
}

// Attention: if this test fails all other test will/should do so too
#[test]
fn original_xxd_is_available() {
    assert!(is_command_available("xxd".to_string()));
}

#[test]
fn xxd_rs_is_available() {
    assert!(is_command_available("xxd-rs".to_string()));
}
<|endoftext|>


<commit_before><commit_msg>Test for issue 2286<commit_after>/* Test that exporting a class also exports its
   public fields and methods */

import kitty::*;

mod kitty {
  export cat;
  class cat {
    let meows: uint;
    let name: str;

    fn get_name() -> str {  self.name }
    new(in_name: str) { self.name = in_name; self.meows = 0u; }
  }
}

fn main() {
  assert(cat("Spreckles").get_name() == "Spreckles");
}<|endoftext|>


<commit_before><commit_msg>boxes<commit_after>fn main() {
    let n = Box::new(42);
    let q = &*n;
    let p = &*n;
    println!("{:?}", q);
    println!("{:?}", p);
    println!("{:?}", n);

    let n1 = Box::new(33);
    let mut m = n1;
    *m = 67;
    println!("{:?}", m);
}<|endoftext|>


<commit_before><commit_msg>Example &str parser<commit_after>
#[macro_use]
extern crate nom;

use nom::IResult;

use std::collections::HashMap;

fn is_alphabetic(chr:char) -> bool {
  (chr as u8 >= 0x41 && chr as u8 <= 0x5A) || (chr as u8 >= 0x61 && chr as u8 <= 0x7A)
}

fn is_digit(chr: char) -> bool {
  chr as u8 >= 0x30 && chr as u8 <= 0x39
}

fn is_alphanumeric(chr: char) -> bool {
  is_alphabetic(chr) || is_digit(chr)
}

fn is_space(chr:char) -> bool {
  chr == ' ' || chr == '\t'
}

fn is_line_ending_or_comment(chr:char) -> bool {
  chr == ';' || chr == '\n'
}

named!(alphanumeric<&str,&str>,         take_while_s!(is_alphanumeric));
named!(not_line_ending<&str,&str>,      is_not_s!("\r\n"));
named!(space<&str,&str>,                take_while_s!(is_space));
named!(space_or_line_ending<&str,&str>, is_a_s!(" \r\n"));

fn right_bracket(c:char) -> bool {
  c == ']'
}

named!(category     <&str, &str>,
  chain!(
          tag_s!("[")                 ~
    name: take_till_s!(right_bracket) ~
          tag_s!("]")                 ~
          space_or_line_ending?       ,
    ||{ name }
  )
);

named!(key_value    <&str,(&str,&str)>,
  chain!(
    key: alphanumeric                            ~
         space?                                  ~
         tag_s!("=")                             ~
         space?                                  ~
    val: take_till_s!(is_line_ending_or_comment) ~
         space?                                  ~
         pair!(tag_s!(";"), not_line_ending)?    ~
         space_or_line_ending?                   ,
    ||{(key, val)}
  )
);

named!(keys_and_values_aggregator<&str, Vec<(&str,&str)> >, many0!(key_value));

fn keys_and_values(input:&str) -> IResult<&str, HashMap<&str, &str> > {
  let mut h: HashMap<&str, &str> = HashMap::new();

  match keys_and_values_aggregator(input) {
    IResult::Done(i,tuple_vec) => {
      for &(k,v) in &tuple_vec {
        h.insert(k, v);
      }
      IResult::Done(i, h)
    },
    IResult::Incomplete(a)     => IResult::Incomplete(a),
    IResult::Error(a)          => IResult::Error(a)
  }
}

named!(category_and_keys<&str,(&str,HashMap<&str,&str>)>,
  pair!(category, keys_and_values)
);

named!(categories_aggregator<&str, Vec<(&str, HashMap<&str,&str>)> >, many0!(category_and_keys));

fn categories(input: &str) -> IResult<&str, HashMap<&str, HashMap<&str, &str> > > {
  let mut h: HashMap<&str, HashMap<&str, &str>> = HashMap::new();

  match categories_aggregator(input) {
    IResult::Done(i,tuple_vec) => {
      for &(k,ref v) in &tuple_vec {
        h.insert(k, v.clone());
      }
      IResult::Done(i, h)
    },
    IResult::Incomplete(a)     => IResult::Incomplete(a),
    IResult::Error(a)          => IResult::Error(a)
  }
}

#[test]
fn parse_category_test() {
  let ini_file = "[category]

parameter=value
key = value2";

  let ini_without_category = "parameter=value
key = value2";

  let res = category(ini_file);
  println!("{:?}", res);
  match res {
    IResult::Done(i, o) => println!("i: {} | o: {:?}", i, o),
    _ => println!("error")
  }

  assert_eq!(res, IResult::Done(ini_without_category, "category"));
}

#[test]
fn parse_key_value_test() {
  let ini_file = "parameter=value
key = value2";

  let ini_without_key_value = "key = value2";

  let res = key_value(ini_file);
  println!("{:?}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {} | o: ({:?},{:?})", i, o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, IResult::Done(ini_without_key_value, ("parameter", "value")));
}

#[test]
fn parse_key_value_with_space_test() {
  let ini_file = "parameter = value
key = value2";

  let ini_without_key_value = "key = value2";

  let res = key_value(ini_file);
  println!("{:?}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {} | o: ({:?},{:?})", i, o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, IResult::Done(ini_without_key_value, ("parameter", "value")));
}

#[test]
fn parse_key_value_with_comment_test() {
  let ini_file = "parameter=value;abc
key = value2";

  let ini_without_key_value = "key = value2";

  let res = key_value(ini_file);
  println!("{:?}", res);
  match res {
    IResult::Done(i, (o1, o2)) => println!("i: {} | o: ({:?},{:?})", i, o1, o2),
    _ => println!("error")
  }

  assert_eq!(res, IResult::Done(ini_without_key_value, ("parameter", "value")));
}

#[test]
fn parse_multiple_keys_and_values_test() {
  let ini_file = "parameter=value;abc

key = value2

[category]";

  let ini_without_key_value = "[category]";

  let res = keys_and_values(ini_file);
  println!("{:?}", res);
  match res {
    IResult::Done(i, ref o) => println!("i: {} | o: {:?}", i, o),
    _ => println!("error")
  }

  let mut expected: HashMap<&str, &str> = HashMap::new();
  expected.insert("parameter", "value");
  expected.insert("key", "value2");
  assert_eq!(res, IResult::Done(ini_without_key_value, expected));
}

#[test]
fn parse_category_then_multiple_keys_and_values_test() {
  //FIXME: there can be an empty line or a comment line after a category
  let ini_file = "[abcd]
parameter=value;abc

key = value2

[category]";

  let ini_after_parser = "[category]";

  let res = category_and_keys(ini_file);
  println!("{:?}", res);
  match res {
    IResult::Done(i, ref o) => println!("i: {} | o: {:?}", i, o),
    _ => println!("error")
  }

  let mut expected_h: HashMap<&str, &str> = HashMap::new();
  expected_h.insert("parameter", "value");
  expected_h.insert("key", "value2");
  assert_eq!(res, IResult::Done(ini_after_parser, ("abcd", expected_h)));
}

#[test]
fn parse_multiple_categories_test() {
  let ini_file = "[abcd]

parameter=value;abc

key = value2

[category]
parameter3=value3
key4 = value4
";

  let res = categories(ini_file);
  //println!("{:?}", res);
  match res {
    IResult::Done(i, ref o) => println!("i: {} | o: {:?}", i, o),
    _ => println!("error")
  }

  let mut expected_1: HashMap<&str, &str> = HashMap::new();
  expected_1.insert("parameter", "value");
  expected_1.insert("key", "value2");
  let mut expected_2: HashMap<&str, &str> = HashMap::new();
  expected_2.insert("parameter3", "value3");
  expected_2.insert("key4", "value4");
  let mut expected_h: HashMap<&str, HashMap<&str, &str>> = HashMap::new();
  expected_h.insert("abcd",     expected_1);
  expected_h.insert("category", expected_2);
  assert_eq!(res, IResult::Done("", expected_h));
}
<|endoftext|>


<commit_before><commit_msg>tiny traffic light example<commit_after>extern crate anybar;
use anybar::{Anybar,Color};
use std::{thread, time};

fn main() {
    // create a new AnyBar instance connected to the default port
    let mut bar = Anybar::default();

    // set the color
    bar.set_color(Color::Red).unwrap();
    thread::sleep(time::Duration::from_millis(700));
    bar.set_color(Color::Orange).unwrap();
    thread::sleep(time::Duration::from_millis(700));
    bar.set_color(Color::Green).unwrap();
    thread::sleep(time::Duration::from_millis(700));
    bar.quit().unwrap();
}
<|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.

// ignore-fast Feature gating doesn't work
// ignore-stage1
// ignore-pretty
// ignore-android

#[feature(phase)];

#[phase(syntax)]
extern mod fourcc;

static static_val: u32 = fourcc!("foo ");
static static_val_be: u32 = fourcc!("foo ", big);
static static_val_le: u32 = fourcc!("foo ", little);
static static_val_target: u32 = fourcc!("foo ", target);

fn main() {
    let val = fourcc!("foo ", big);
    assert_eq!(val, 0x666f6f20u32);
    assert_eq!(val, fourcc!("foo "));

    let val = fourcc!("foo ", little);
    assert_eq!(val, 0x206f6f66u32);

    let val = fourcc!("foo ", target);
    let exp = if cfg!(target_endian = "big") { 0x666f6f20u32 } else { 0x206f6f66u32 };
    assert_eq!(val, exp);

    assert_eq!(static_val_be, 0x666f6f20u32);
    assert_eq!(static_val, static_val_be);
    assert_eq!(static_val_le, 0x206f6f66u32);
    let exp = if cfg!(target_endian = "big") { 0x666f6f20u32 } else { 0x206f6f66u32 };
    assert_eq!(static_val_target, exp);

    assert_eq!(fourcc!("\xC0\xFF\xEE!"), 0xC0FFEE21);
}
<commit_msg>auto merge of #12216 : alexcrichton/rust/another-snap-fix, r=brson<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.

// ignore-fast Feature gating doesn't work
// ignore-stage1
// ignore-pretty
// ignore-cross-compile

#[feature(phase)];

#[phase(syntax)]
extern mod fourcc;

static static_val: u32 = fourcc!("foo ");
static static_val_be: u32 = fourcc!("foo ", big);
static static_val_le: u32 = fourcc!("foo ", little);
static static_val_target: u32 = fourcc!("foo ", target);

fn main() {
    let val = fourcc!("foo ", big);
    assert_eq!(val, 0x666f6f20u32);
    assert_eq!(val, fourcc!("foo "));

    let val = fourcc!("foo ", little);
    assert_eq!(val, 0x206f6f66u32);

    let val = fourcc!("foo ", target);
    let exp = if cfg!(target_endian = "big") { 0x666f6f20u32 } else { 0x206f6f66u32 };
    assert_eq!(val, exp);

    assert_eq!(static_val_be, 0x666f6f20u32);
    assert_eq!(static_val, static_val_be);
    assert_eq!(static_val_le, 0x206f6f66u32);
    let exp = if cfg!(target_endian = "big") { 0x666f6f20u32 } else { 0x206f6f66u32 };
    assert_eq!(static_val_target, exp);

    assert_eq!(fourcc!("\xC0\xFF\xEE!"), 0xC0FFEE21);
}
<|endoftext|>


<commit_before><commit_msg>Bubble sort in Rust<commit_after><|endoftext|>


<commit_before><commit_msg>12 - modules<commit_after>fn function() {
    println!("called `function()`");
}

// A module named `my`
mod my {
    // A module can contain items like functions
    #[allow(dead_code)]
    fn function() {
        println!("called `my::function()`");
    }

    // Modules can be nested
    mod nested {
        #[allow(dead_code)]
        fn function() {
            println!("called `my::nested::function()`");
        }
    }
}

fn main() {
    function();

    // Items inside a module can be called using their full path
    // The `println` function lives in the `stdio` module
    // The `stdio` module lives in the `io` module
    // And the `io` module lives in the `std` crate
    std::io::stdio::println("Hello World!");

    // Error! `my::function` is private
    // my::function();
}
<|endoftext|>


<commit_before><commit_msg>Add codegen test<commit_after>// compile-flags: -g
//
// CHECK-LABEL: @main
// CHECK: {{.*}}DIDerivedType(tag: DW_TAG_pointer_type, name: "fn() -> <recursive_type>",{{.*}}
//
// CHECK: {{.*}}DISubroutineType{{.*}}
// CHECK: {{.*}}DIBasicType(name: "<recur_type>", encoding: DW_ATE_unsigned)

pub fn foo() -> impl Copy {
    foo
}

fn main() {
    let my_res = foo();
}
<|endoftext|>


<commit_before><commit_msg>comments<commit_after><|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// Handles invoking external binaries.
// This module assumes that, for a given machine, there is only one place
// where the desired executable might be installed. It expects the engine
// to identify that place at its initialization by invoking verify_binaries(),
// and to exit immediately if verify_binaries() return an error. If this
// protocol is followed then when any command is executed the unique absolute
// path of the binary for this machine will already have been identified.
// However stratisd may run for a while and it is possible for the binary
// to be caused to be uninstalled while stratisd is being run. Therefore,
// the existence of the file is checked before the command is invoked, and
// an explicit error is returned if the executable can not be found.

use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::process::Command;

use uuid::Uuid;

use stratis::{StratisError, StratisResult};

/// Find the binary with the given name by looking in likely locations.
/// Return None if no binary was found.
/// Search an explicit list of directories rather than the user's PATH
/// environment variable. stratisd may be running when there is no PATH
/// variable set.
fn find_binary(name: &str) -> Option<PathBuf> {
    ["/usr/sbin", "/sbin", "/usr/bin", "/bin"]
        .iter()
        .map(|pre| [pre, name].iter().collect::<PathBuf>())
        .find(|path| path.exists())
}

// These are the external binaries that stratisd relies on.
// Any change in this list requires a corresponding change to BINARIES,
// and vice-versa.
const MKFS_XFS: &str = "mkfs.xfs";
const THIN_CHECK: &str = "thin_check";
const THIN_REPAIR: &str = "thin_repair";
const XFS_ADMIN: &str = "xfs_admin";
const XFS_GROWFS: &str = "xfs_growfs";

lazy_static! {
    static ref BINARIES: HashMap<String, Option<PathBuf>> = [
        (MKFS_XFS.to_string(), find_binary(MKFS_XFS)),
        (THIN_CHECK.to_string(), find_binary(THIN_CHECK)),
        (THIN_REPAIR.to_string(), find_binary(THIN_REPAIR)),
        (XFS_ADMIN.to_string(), find_binary(XFS_ADMIN)),
        (XFS_GROWFS.to_string(), find_binary(XFS_GROWFS)),
    ].iter()
        .cloned()
        .collect();
}

/// Verify that all binaries that the engine might invoke are available at some
/// path. Return an error if any are missing. Required to be called on engine
/// initialization.
pub fn verify_binaries() -> StratisResult<()> {
    match BINARIES.iter().find(|(_, ref path)| path.is_none()) {
        None => Ok(()),
        Some((ref name, _)) => Err(StratisError::Error(format!(
            "Unable to find absolute path for \"{}\"",
            name
        ))),
    }
}

/// Invoke the specified command. Return an error if invoking the command
/// fails or if the command itself fails.
fn execute_cmd(cmd: &mut Command) -> StratisResult<()> {
    match cmd.output() {
        Err(err) => Err(StratisError::Error(format!(
            "Failed to execute command {:?}, err: {:?}",
            cmd, err
        ))),
        Ok(result) => {
            if result.status.success() {
                Ok(())
            } else {
                let std_out_txt = String::from_utf8_lossy(&result.stdout);
                let std_err_txt = String::from_utf8_lossy(&result.stderr);
                let err_msg = format!(
                    "Command failed: cmd: {:?}, stdout: {} stderr: {}",
                    cmd, std_out_txt, std_err_txt
                );
                Err(StratisError::Error(err_msg))
            }
        }
    }
}

/// Get an absolute path for the executable with the given name.
/// Precondition: verify_binaries() has already been invoked.
fn get_executable(name: &str) -> StratisResult<PathBuf> {
    Ok(BINARIES
        .get(name)
        .expect("name arguments are all constants defined with BINARIES, lookup can not fail")
        .as_ref()
        .expect("verify_binaries() was previously called and returned no error")
        .to_path_buf())
}

/// Create a filesystem on devnode.
pub fn create_fs(devnode: &Path, uuid: Uuid) -> StratisResult<()> {
    execute_cmd(
        Command::new(get_executable(MKFS_XFS)?.as_os_str())
            .arg("-f")
            .arg("-q")
            .arg(&devnode)
            .arg("-m")
            .arg(format!("uuid={}", uuid)),
    )
}

/// Use the xfs_growfs command to expand a filesystem mounted at the given
/// mount point.
pub fn xfs_growfs(mount_point: &Path) -> StratisResult<()> {
    execute_cmd(
        Command::new(get_executable(XFS_GROWFS)?.as_os_str())
            .arg(mount_point)
            .arg("-d"),
    )
}

/// Set a new UUID for filesystem on the devnode.
pub fn set_uuid(devnode: &Path, uuid: Uuid) -> StratisResult<()> {
    execute_cmd(
        Command::new(get_executable(XFS_ADMIN)?.as_os_str())
            .arg("-U")
            .arg(format!("{}", uuid))
            .arg(&devnode),
    )
}

/// Call thin_check on a thinpool
pub fn thin_check(devnode: &Path) -> StratisResult<()> {
    execute_cmd(
        Command::new(get_executable(THIN_CHECK)?.as_os_str())
            .arg("-q")
            .arg(devnode),
    )
}

/// Call thin_repair on a thinpool
pub fn thin_repair(meta_dev: &Path, new_meta_dev: &Path) -> StratisResult<()> {
    execute_cmd(
        Command::new(get_executable(THIN_REPAIR)?.as_os_str())
            .arg("-i")
            .arg(meta_dev)
            .arg("-o")
            .arg(new_meta_dev),
    )
}

/// Call udevadm settle
#[cfg(test)]
pub fn udev_settle() -> StratisResult<()> {
    execute_cmd(Command::new("udevadm").arg("settle"))
}

#[cfg(test)]
pub fn create_ext3_fs(devnode: &Path) -> StratisResult<()> {
    execute_cmd(Command::new("mkfs.ext3").arg(&devnode))
}
<commit_msg>Have get_executable no longer return a Result<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// Handles invoking external binaries.
// This module assumes that, for a given machine, there is only one place
// where the desired executable might be installed. It expects the engine
// to identify that place at its initialization by invoking verify_binaries(),
// and to exit immediately if verify_binaries() return an error. If this
// protocol is followed then when any command is executed the unique absolute
// path of the binary for this machine will already have been identified.
// However stratisd may run for a while and it is possible for the binary
// to be caused to be uninstalled while stratisd is being run. Therefore,
// the existence of the file is checked before the command is invoked, and
// an explicit error is returned if the executable can not be found.

use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::process::Command;

use uuid::Uuid;

use stratis::{StratisError, StratisResult};

/// Find the binary with the given name by looking in likely locations.
/// Return None if no binary was found.
/// Search an explicit list of directories rather than the user's PATH
/// environment variable. stratisd may be running when there is no PATH
/// variable set.
fn find_binary(name: &str) -> Option<PathBuf> {
    ["/usr/sbin", "/sbin", "/usr/bin", "/bin"]
        .iter()
        .map(|pre| [pre, name].iter().collect::<PathBuf>())
        .find(|path| path.exists())
}

// These are the external binaries that stratisd relies on.
// Any change in this list requires a corresponding change to BINARIES,
// and vice-versa.
const MKFS_XFS: &str = "mkfs.xfs";
const THIN_CHECK: &str = "thin_check";
const THIN_REPAIR: &str = "thin_repair";
const XFS_ADMIN: &str = "xfs_admin";
const XFS_GROWFS: &str = "xfs_growfs";

lazy_static! {
    static ref BINARIES: HashMap<String, Option<PathBuf>> = [
        (MKFS_XFS.to_string(), find_binary(MKFS_XFS)),
        (THIN_CHECK.to_string(), find_binary(THIN_CHECK)),
        (THIN_REPAIR.to_string(), find_binary(THIN_REPAIR)),
        (XFS_ADMIN.to_string(), find_binary(XFS_ADMIN)),
        (XFS_GROWFS.to_string(), find_binary(XFS_GROWFS)),
    ].iter()
        .cloned()
        .collect();
}

/// Verify that all binaries that the engine might invoke are available at some
/// path. Return an error if any are missing. Required to be called on engine
/// initialization.
pub fn verify_binaries() -> StratisResult<()> {
    match BINARIES.iter().find(|(_, ref path)| path.is_none()) {
        None => Ok(()),
        Some((ref name, _)) => Err(StratisError::Error(format!(
            "Unable to find absolute path for \"{}\"",
            name
        ))),
    }
}

/// Invoke the specified command. Return an error if invoking the command
/// fails or if the command itself fails.
fn execute_cmd(cmd: &mut Command) -> StratisResult<()> {
    match cmd.output() {
        Err(err) => Err(StratisError::Error(format!(
            "Failed to execute command {:?}, err: {:?}",
            cmd, err
        ))),
        Ok(result) => {
            if result.status.success() {
                Ok(())
            } else {
                let std_out_txt = String::from_utf8_lossy(&result.stdout);
                let std_err_txt = String::from_utf8_lossy(&result.stderr);
                let err_msg = format!(
                    "Command failed: cmd: {:?}, stdout: {} stderr: {}",
                    cmd, std_out_txt, std_err_txt
                );
                Err(StratisError::Error(err_msg))
            }
        }
    }
}

/// Get an absolute path for the executable with the given name.
/// Precondition: verify_binaries() has already been invoked.
fn get_executable(name: &str) -> &Path {
    BINARIES
        .get(name)
        .expect("name arguments are all constants defined with BINARIES, lookup can not fail")
        .as_ref()
        .expect("verify_binaries() was previously called and returned no error")
}

/// Create a filesystem on devnode.
pub fn create_fs(devnode: &Path, uuid: Uuid) -> StratisResult<()> {
    execute_cmd(
        Command::new(get_executable(MKFS_XFS).as_os_str())
            .arg("-f")
            .arg("-q")
            .arg(&devnode)
            .arg("-m")
            .arg(format!("uuid={}", uuid)),
    )
}

/// Use the xfs_growfs command to expand a filesystem mounted at the given
/// mount point.
pub fn xfs_growfs(mount_point: &Path) -> StratisResult<()> {
    execute_cmd(
        Command::new(get_executable(XFS_GROWFS).as_os_str())
            .arg(mount_point)
            .arg("-d"),
    )
}

/// Set a new UUID for filesystem on the devnode.
pub fn set_uuid(devnode: &Path, uuid: Uuid) -> StratisResult<()> {
    execute_cmd(
        Command::new(get_executable(XFS_ADMIN).as_os_str())
            .arg("-U")
            .arg(format!("{}", uuid))
            .arg(&devnode),
    )
}

/// Call thin_check on a thinpool
pub fn thin_check(devnode: &Path) -> StratisResult<()> {
    execute_cmd(
        Command::new(get_executable(THIN_CHECK).as_os_str())
            .arg("-q")
            .arg(devnode),
    )
}

/// Call thin_repair on a thinpool
pub fn thin_repair(meta_dev: &Path, new_meta_dev: &Path) -> StratisResult<()> {
    execute_cmd(
        Command::new(get_executable(THIN_REPAIR).as_os_str())
            .arg("-i")
            .arg(meta_dev)
            .arg("-o")
            .arg(new_meta_dev),
    )
}

/// Call udevadm settle
#[cfg(test)]
pub fn udev_settle() -> StratisResult<()> {
    execute_cmd(Command::new("udevadm").arg("settle"))
}

#[cfg(test)]
pub fn create_ext3_fs(devnode: &Path) -> StratisResult<()> {
    execute_cmd(Command::new("mkfs.ext3").arg(&devnode))
}
<|endoftext|>


<commit_before><commit_msg>Little fix<commit_after><|endoftext|>


<commit_before><commit_msg>file read<commit_after><|endoftext|>


<commit_before><commit_msg>unwrap<commit_after><|endoftext|>


<commit_before><commit_msg>match<commit_after>fn main() {
    let x = 4;
    match x {
        0 => { println!("unmatch"); },
        4 => { println!("match"); },
        _ => { println!("default");}
    }
}
<|endoftext|>