<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 standard, garbage-collected linked list.

#[deriving(Clone, Eq)]
#[allow(missing_doc)]
pub enum List<T> {
    Cons(T, @List<T>),
    Nil,
}

pub struct Items<'a, T> {
    priv head: &'a List<T>,
    priv next: Option<&'a @List<T>>
}

impl<'a, T> Iterator<&'a T> for Items<'a, T> {
    fn next(&mut self) -> Option<&'a T> {
        match self.next {
            None => match *self.head {
                Nil => None,
                Cons(ref value, ref tail) => {
                    self.next = Some(tail);
                    Some(value)
                }
            },
            Some(next) => match **next {
                Nil => None,
                Cons(ref value, ref tail) => {
                    self.next = Some(tail);
                    Some(value)
                }
            }
        }
    }
}

impl<T> List<T> {
    /// Returns a forward iterator
    pub fn iter<'a>(&'a self) -> Items<'a, T> {
        Items {
            head: self,
            next: None
        }
    }
}

/**
 * Left fold
 *
 * Applies `f` to `u` and the first element in the list, then applies `f` to
 * the result of the previous call and the second element, and so on,
 * returning the accumulated result.
 *
 * # Arguments
 *
 * * list - The list to fold
 * * z - The initial value
 * * f - The function to apply
 */
pub fn foldl<T:Clone,U>(z: T, list: @List<U>, f: |&T, &U| -> T) -> T {
    let mut accum: T = z;
    iter(list, |element| accum = f(&accum, element));
    accum
}

/**
 * Search for an element that matches a given predicate
 *
 * Apply function `f` to each element of `list`, starting from the first.
 * When function `f` returns true then an option containing the element
 * is returned. If `f` matches no elements then none is returned.
 */
pub fn find<T:Clone>(list: @List<T>, f: |&T| -> bool) -> Option<T> {
    let mut list = list;
    loop {
        list = match *list {
          Cons(ref head, tail) => {
            if f(head) { return Some((*head).clone()); }
            tail
          }
          Nil => return None
        }
    };
}

/**
 * Returns true if a list contains an element that matches a given predicate
 *
 * Apply function `f` to each element of `list`, starting from the first.
 * When function `f` returns true then it also returns true. If `f` matches no
 * elements then false is returned.
 */
pub fn any<T>(list: @List<T>, f: |&T| -> bool) -> bool {
    let mut list = list;
    loop {
        list = match *list {
            Cons(ref head, tail) => {
                if f(head) { return true; }
                tail
            }
            Nil => return false
        }
    };
}

/// Returns true if a list contains an element with the given value
pub fn has<T:Eq>(list: @List<T>, element: T) -> bool {
    let mut found = false;
    each(list, |e| {
        if *e == element { found = true; false } else { true }
    });
    return found;
}

/// Returns true if the list is empty
pub fn is_empty<T>(list: @List<T>) -> bool {
    match *list {
        Nil => true,
        _ => false
    }
}

/// Returns the length of a list
pub fn len<T>(list: @List<T>) -> uint {
    let mut count = 0u;
    iter(list, |_e| count += 1u);
    count
}

/// Returns all but the first element of a list
pub fn tail<T>(list: @List<T>) -> @List<T> {
    match *list {
        Cons(_, tail) => return tail,
        Nil => fail!("list empty")
    }
}

/// Returns the first element of a list
pub fn head<T:Clone>(list: @List<T>) -> T {
    match *list {
      Cons(ref head, _) => (*head).clone(),
      // makes me sad
      _ => fail!("head invoked on empty list")
    }
}

/// Appends one list to another
pub fn append<T:Clone + 'static>(list: @List<T>, other: @List<T>) -> @List<T> {
    match *list {
      Nil => return other,
      Cons(ref head, tail) => {
        let rest = append(tail, other);
        return @Cons((*head).clone(), rest);
      }
    }
}

impl<T:'static + Clone> List<T> {
    /// Create a list from a vector
    pub fn from_vec(v: &[T]) -> List<T> {
        match v.len() {
            0 => Nil,
            _ => v.rev_iter().fold(Nil, |tail, value: &T| Cons(value.clone(), @tail))
        }
    }
}

/*
/// Push one element into the front of a list, returning a new list
/// THIS VERSION DOESN'T ACTUALLY WORK
fn push<T:Clone>(ll: &mut @list<T>, vv: T) {
    ll = &mut @cons(vv, *ll)
}
*/

/// Iterate over a list
pub fn iter<T>(list: @List<T>, f: |&T|) {
    let mut cur = list;
    loop {
        cur = match *cur {
          Cons(ref head, tail) => {
            f(head);
            tail
          }
          Nil => break
        }
    }
}

/// Iterate over a list
pub fn each<T>(list: @List<T>, f: |&T| -> bool) -> bool {
    let mut cur = list;
    loop {
        cur = match *cur {
          Cons(ref head, tail) => {
            if !f(head) { return false; }
            tail
          }
          Nil => { return true; }
        }
    }
}

#[cfg(test)]
mod tests {
    use list::{List, Nil, head, is_empty, tail};
    use list;

    use std::option;

    #[test]
    fn test_iter() {
        let list = List::from_vec([0, 1, 2]);
        let mut iter = list.iter();
        assert_eq!(&0, iter.next().unwrap());
        assert_eq!(&1, iter.next().unwrap());
        assert_eq!(&2, iter.next().unwrap());
        assert_eq!(None, iter.next());
    }

    #[test]
    fn test_is_empty() {
        let empty : @list::List<int> = @List::from_vec([]);
        let full1 = @List::from_vec([1]);
        let full2 = @List::from_vec(['r', 'u']);

        assert!(is_empty(empty));
        assert!(!is_empty(full1));
        assert!(!is_empty(full2));
    }

    #[test]
    fn test_from_vec() {
        let list = @List::from_vec([0, 1, 2]);

        assert_eq!(head(list), 0);

        let tail_l = tail(list);
        assert_eq!(head(tail_l), 1);

        let tail_tail_l = tail(tail_l);
        assert_eq!(head(tail_tail_l), 2);
    }

    #[test]
    fn test_from_vec_empty() {
        let empty : list::List<int> = List::from_vec([]);
        assert_eq!(empty, Nil::<int>);
    }

    #[test]
    fn test_foldl() {
        fn add(a: &uint, b: &int) -> uint { return *a + (*b as uint); }
        let list = @List::from_vec([0, 1, 2, 3, 4]);
        let empty = @list::Nil::<int>;
        assert_eq!(list::foldl(0u, list, add), 10u);
        assert_eq!(list::foldl(0u, empty, add), 0u);
    }

    #[test]
    fn test_foldl2() {
        fn sub(a: &int, b: &int) -> int {
            *a - *b
        }
        let list = @List::from_vec([1, 2, 3, 4]);
        assert_eq!(list::foldl(0, list, sub), -10);
    }

    #[test]
    fn test_find_success() {
        fn match_(i: &int) -> bool { return *i == 2; }
        let list = @List::from_vec([0, 1, 2]);
        assert_eq!(list::find(list, match_), option::Some(2));
    }

    #[test]
    fn test_find_fail() {
        fn match_(_i: &int) -> bool { return false; }
        let list = @List::from_vec([0, 1, 2]);
        let empty = @list::Nil::<int>;
        assert_eq!(list::find(list, match_), option::None::<int>);
        assert_eq!(list::find(empty, match_), option::None::<int>);
    }

    #[test]
    fn test_any() {
        fn match_(i: &int) -> bool { return *i == 2; }
        let list = @List::from_vec([0, 1, 2]);
        let empty = @list::Nil::<int>;
        assert_eq!(list::any(list, match_), true);
        assert_eq!(list::any(empty, match_), false);
    }

    #[test]
    fn test_has() {
        let list = @List::from_vec([5, 8, 6]);
        let empty = @list::Nil::<int>;
        assert!((list::has(list, 5)));
        assert!((!list::has(list, 7)));
        assert!((list::has(list, 8)));
        assert!((!list::has(empty, 5)));
    }

    #[test]
    fn test_len() {
        let list = @List::from_vec([0, 1, 2]);
        let empty = @list::Nil::<int>;
        assert_eq!(list::len(list), 3u);
        assert_eq!(list::len(empty), 0u);
    }

    #[test]
    fn test_append() {
        assert!(@List::from_vec([1,2,3,4])
            == list::append(@List::from_vec([1,2]), @List::from_vec([3,4])));
    }
}
<commit_msg>Removed list::foldl() in favor of iter().fold()<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 standard, garbage-collected linked list.

#[deriving(Clone, Eq)]
#[allow(missing_doc)]
pub enum List<T> {
    Cons(T, @List<T>),
    Nil,
}

pub struct Items<'a, T> {
    priv head: &'a List<T>,
    priv next: Option<&'a @List<T>>
}

impl<'a, T> Iterator<&'a T> for Items<'a, T> {
    fn next(&mut self) -> Option<&'a T> {
        match self.next {
            None => match *self.head {
                Nil => None,
                Cons(ref value, ref tail) => {
                    self.next = Some(tail);
                    Some(value)
                }
            },
            Some(next) => match **next {
                Nil => None,
                Cons(ref value, ref tail) => {
                    self.next = Some(tail);
                    Some(value)
                }
            }
        }
    }
}

impl<T> List<T> {
    /// Returns a forward iterator
    pub fn iter<'a>(&'a self) -> Items<'a, T> {
        Items {
            head: self,
            next: None
        }
    }
}

/**
 * Search for an element that matches a given predicate
 *
 * Apply function `f` to each element of `list`, starting from the first.
 * When function `f` returns true then an option containing the element
 * is returned. If `f` matches no elements then none is returned.
 */
pub fn find<T:Clone>(list: @List<T>, f: |&T| -> bool) -> Option<T> {
    let mut list = list;
    loop {
        list = match *list {
          Cons(ref head, tail) => {
            if f(head) { return Some((*head).clone()); }
            tail
          }
          Nil => return None
        }
    };
}

/**
 * Returns true if a list contains an element that matches a given predicate
 *
 * Apply function `f` to each element of `list`, starting from the first.
 * When function `f` returns true then it also returns true. If `f` matches no
 * elements then false is returned.
 */
pub fn any<T>(list: @List<T>, f: |&T| -> bool) -> bool {
    let mut list = list;
    loop {
        list = match *list {
            Cons(ref head, tail) => {
                if f(head) { return true; }
                tail
            }
            Nil => return false
        }
    };
}

/// Returns true if a list contains an element with the given value
pub fn has<T:Eq>(list: @List<T>, element: T) -> bool {
    let mut found = false;
    each(list, |e| {
        if *e == element { found = true; false } else { true }
    });
    return found;
}

/// Returns true if the list is empty
pub fn is_empty<T>(list: @List<T>) -> bool {
    match *list {
        Nil => true,
        _ => false
    }
}

/// Returns the length of a list
pub fn len<T>(list: @List<T>) -> uint {
    let mut count = 0u;
    iter(list, |_e| count += 1u);
    count
}

/// Returns all but the first element of a list
pub fn tail<T>(list: @List<T>) -> @List<T> {
    match *list {
        Cons(_, tail) => return tail,
        Nil => fail!("list empty")
    }
}

/// Returns the first element of a list
pub fn head<T:Clone>(list: @List<T>) -> T {
    match *list {
      Cons(ref head, _) => (*head).clone(),
      // makes me sad
      _ => fail!("head invoked on empty list")
    }
}

/// Appends one list to another
pub fn append<T:Clone + 'static>(list: @List<T>, other: @List<T>) -> @List<T> {
    match *list {
      Nil => return other,
      Cons(ref head, tail) => {
        let rest = append(tail, other);
        return @Cons((*head).clone(), rest);
      }
    }
}

impl<T:'static + Clone> List<T> {
    /// Create a list from a vector
    pub fn from_vec(v: &[T]) -> List<T> {
        match v.len() {
            0 => Nil,
            _ => v.rev_iter().fold(Nil, |tail, value: &T| Cons(value.clone(), @tail))
        }
    }
}

/*
/// Push one element into the front of a list, returning a new list
/// THIS VERSION DOESN'T ACTUALLY WORK
fn push<T:Clone>(ll: &mut @list<T>, vv: T) {
    ll = &mut @cons(vv, *ll)
}
*/

/// Iterate over a list
pub fn iter<T>(list: @List<T>, f: |&T|) {
    let mut cur = list;
    loop {
        cur = match *cur {
          Cons(ref head, tail) => {
            f(head);
            tail
          }
          Nil => break
        }
    }
}

/// Iterate over a list
pub fn each<T>(list: @List<T>, f: |&T| -> bool) -> bool {
    let mut cur = list;
    loop {
        cur = match *cur {
          Cons(ref head, tail) => {
            if !f(head) { return false; }
            tail
          }
          Nil => { return true; }
        }
    }
}

#[cfg(test)]
mod tests {
    use list::{List, Nil, head, is_empty, tail};
    use list;

    use std::option;

    #[test]
    fn test_iter() {
        let list = List::from_vec([0, 1, 2]);
        let mut iter = list.iter();
        assert_eq!(&0, iter.next().unwrap());
        assert_eq!(&1, iter.next().unwrap());
        assert_eq!(&2, iter.next().unwrap());
        assert_eq!(None, iter.next());
    }

    #[test]
    fn test_is_empty() {
        let empty : @list::List<int> = @List::from_vec([]);
        let full1 = @List::from_vec([1]);
        let full2 = @List::from_vec(['r', 'u']);

        assert!(is_empty(empty));
        assert!(!is_empty(full1));
        assert!(!is_empty(full2));
    }

    #[test]
    fn test_from_vec() {
        let list = @List::from_vec([0, 1, 2]);

        assert_eq!(head(list), 0);

        let tail_l = tail(list);
        assert_eq!(head(tail_l), 1);

        let tail_tail_l = tail(tail_l);
        assert_eq!(head(tail_tail_l), 2);
    }

    #[test]
    fn test_from_vec_empty() {
        let empty : list::List<int> = List::from_vec([]);
        assert_eq!(empty, Nil::<int>);
    }

    #[test]
    fn test_fold() {
        fn add_(a: uint, b: &uint) -> uint { a + *b }
        fn subtract_(a: uint, b: &uint) -> uint { a - *b }

        let empty = Nil::<uint>;
        assert_eq!(empty.iter().fold(0u, add_), 0u);
        assert_eq!(empty.iter().fold(10u, subtract_), 10u);

        let list = List::from_vec([0u, 1u, 2u, 3u, 4u]);
        assert_eq!(list.iter().fold(0u, add_), 10u);
        assert_eq!(list.iter().fold(10u, subtract_), 0u);
    }

    #[test]
    fn test_find_success() {
        fn match_(i: &int) -> bool { return *i == 2; }
        let list = @List::from_vec([0, 1, 2]);
        assert_eq!(list::find(list, match_), option::Some(2));
    }

    #[test]
    fn test_find_fail() {
        fn match_(_i: &int) -> bool { return false; }
        let list = @List::from_vec([0, 1, 2]);
        let empty = @list::Nil::<int>;
        assert_eq!(list::find(list, match_), option::None::<int>);
        assert_eq!(list::find(empty, match_), option::None::<int>);
    }

    #[test]
    fn test_any() {
        fn match_(i: &int) -> bool { return *i == 2; }
        let list = @List::from_vec([0, 1, 2]);
        let empty = @list::Nil::<int>;
        assert_eq!(list::any(list, match_), true);
        assert_eq!(list::any(empty, match_), false);
    }

    #[test]
    fn test_has() {
        let list = @List::from_vec([5, 8, 6]);
        let empty = @list::Nil::<int>;
        assert!((list::has(list, 5)));
        assert!((!list::has(list, 7)));
        assert!((list::has(list, 8)));
        assert!((!list::has(empty, 5)));
    }

    #[test]
    fn test_len() {
        let list = @List::from_vec([0, 1, 2]);
        let empty = @list::Nil::<int>;
        assert_eq!(list::len(list), 3u);
        assert_eq!(list::len(empty), 0u);
    }

    #[test]
    fn test_append() {
        assert!(@List::from_vec([1,2,3,4])
            == list::append(@List::from_vec([1,2]), @List::from_vec([3,4])));
    }
}
<|endoftext|>


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

#[test]
fn fixed_size_array() {
    let mut array = [0; 64];
    let mut zero_sized = [(); 64];
    let mut empty_array = [0; 0];
    let mut empty_zero_sized = [(); 0];

    assert_eq!(FixedSizeArray::as_slice(&array).len(), 64);
    assert_eq!(FixedSizeArray::as_slice(&zero_sized).len(), 64);
    assert_eq!(FixedSizeArray::as_slice(&empty_array).len(), 0);
    assert_eq!(FixedSizeArray::as_slice(&empty_zero_sized).len(), 0);

    assert_eq!(FixedSizeArray::as_mut_slice(&mut array).len(), 64);
    assert_eq!(FixedSizeArray::as_mut_slice(&mut zero_sized).len(), 64);
    assert_eq!(FixedSizeArray::as_mut_slice(&mut empty_array).len(), 0);
    assert_eq!(FixedSizeArray::as_mut_slice(&mut empty_zero_sized).len(), 0);
}

#[test]
fn array_try_from() {
    macro_rules! test {
        ($($N:expr)+) => {
            $({
                type Array = [u8; $N];
                let array: Array = [0; $N];
                let slice: &[u8] = &array[..];

                let result = <&Array>::try_from(slice);
                assert_eq!(Ok(&array), result);
            })+
        }
    }
    test! {
         0  1  2  3  4  5  6  7  8  9
        10 11 12 13 14 15 16 17 18 19
        20 21 22 23 24 25 26 27 28 29
        30 31 32
    }
}
<commit_msg>Try to fix array TryFrom tests<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.
use core::array::FixedSizeArray;
use core::convert::TryFrom;

#[test]
fn fixed_size_array() {
    let mut array = [0; 64];
    let mut zero_sized = [(); 64];
    let mut empty_array = [0; 0];
    let mut empty_zero_sized = [(); 0];

    assert_eq!(FixedSizeArray::as_slice(&array).len(), 64);
    assert_eq!(FixedSizeArray::as_slice(&zero_sized).len(), 64);
    assert_eq!(FixedSizeArray::as_slice(&empty_array).len(), 0);
    assert_eq!(FixedSizeArray::as_slice(&empty_zero_sized).len(), 0);

    assert_eq!(FixedSizeArray::as_mut_slice(&mut array).len(), 64);
    assert_eq!(FixedSizeArray::as_mut_slice(&mut zero_sized).len(), 64);
    assert_eq!(FixedSizeArray::as_mut_slice(&mut empty_array).len(), 0);
    assert_eq!(FixedSizeArray::as_mut_slice(&mut empty_zero_sized).len(), 0);
}

#[test]
fn array_try_from() {
    macro_rules! test {
        ($($N:expr)+) => {
            $({
                type Array = [u8; $N];
                let array: Array = [0; $N];
                let slice: &[u8] = &array[..];

                let result = <&Array>::try_from(slice);
                assert_eq!(&array, result.unwrap());
            })+
        }
    }
    test! {
         0  1  2  3  4  5  6  7  8  9
        10 11 12 13 14 15 16 17 18 19
        20 21 22 23 24 25 26 27 28 29
        30 31 32
    }
}
<|endoftext|>


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

extern crate gcc;
extern crate build_helper;

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

use build_helper::output;

fn detect_llvm_link(major: u32, minor: u32, llvm_config: &Path)
    -> (&'static str, Option<&'static str>) {
    if major > 3 || (major == 3 && minor >= 9) {
        // Force the link mode we want, preferring static by default, but
        // possibly overridden by `configure --enable-llvm-link-shared`.
        if env::var_os("LLVM_LINK_SHARED").is_some() {
            return ("dylib", Some("--link-shared"));
        } else {
            return ("static", Some("--link-static"));
        }
    } else if major == 3 && minor == 8 {
        // Find out LLVM's default linking mode.
        let mut mode_cmd = Command::new(llvm_config);
        mode_cmd.arg("--shared-mode");
        if output(&mut mode_cmd).trim() == "shared" {
            return ("dylib", None);
        } else {
            return ("static", None);
        }
    }
    ("static", None)
}

fn main() {
    let target = env::var("TARGET").expect("TARGET was not set");
    let llvm_config = env::var_os("LLVM_CONFIG")
        .map(PathBuf::from)
        .unwrap_or_else(|| {
            if let Some(dir) = env::var_os("CARGO_TARGET_DIR").map(PathBuf::from) {
                let to_test = dir.parent()
                    .unwrap()
                    .parent()
                    .unwrap()
                    .join(&target)
                    .join("llvm/bin/llvm-config");
                if Command::new(&to_test).output().is_ok() {
                    return to_test;
                }
            }
            PathBuf::from("llvm-config")
        });

    println!("cargo:rerun-if-changed={}", llvm_config.display());

    // Test whether we're cross-compiling LLVM. This is a pretty rare case
    // currently where we're producing an LLVM for a different platform than
    // what this build script is currently running on.
    //
    // In that case, there's no guarantee that we can actually run the target,
    // so the build system works around this by giving us the LLVM_CONFIG for
    // the host platform. This only really works if the host LLVM and target
    // LLVM are compiled the same way, but for us that's typically the case.
    //
    // We *want* detect this cross compiling situation by asking llvm-config
    // what it's host-target is. If that's not the TARGET, then we're cross
    // compiling. Unfortunately `llvm-config` seems either be buggy, or we're
    // misconfiguring it, because the `i686-pc-windows-gnu` build of LLVM will
    // report itself with a `--host-target` of `x86_64-pc-windows-gnu`. This
    // tricks us into thinking we're doing a cross build when we aren't, so
    // havoc ensues.
    //
    // In any case, if we're cross compiling, this generally just means that we
    // can't trust all the output of llvm-config becaues it might be targeted
    // for the host rather than the target. As a result a bunch of blocks below
    // are gated on `if !is_crossed`
    let target = env::var("TARGET").expect("TARGET was not set");
    let host = env::var("HOST").expect("HOST was not set");
    let is_crossed = target != host;

    let mut optional_components =
        vec!["x86", "arm", "aarch64", "mips", "powerpc", "pnacl",
             "systemz", "jsbackend", "msp430", "sparc", "nvptx"];

    let mut version_cmd = Command::new(&llvm_config);
    version_cmd.arg("--version");
    let version_output = output(&mut version_cmd);
    let mut parts = version_output.split('.').take(2)
        .filter_map(|s| s.parse::<u32>().ok());
    let (major, minor) =
        if let (Some(major), Some(minor)) = (parts.next(), parts.next()) {
            (major, minor)
        } else {
            (3, 7)
        };

    if major > 3 {
        optional_components.push("hexagon");
    }

    // FIXME: surely we don't need all these components, right? Stuff like mcjit
    //        or interpreter the compiler itself never uses.
    let required_components = &["ipo",
                                "bitreader",
                                "bitwriter",
                                "linker",
                                "asmparser",
                                "mcjit",
                                "interpreter",
                                "instrumentation"];

    let components = output(Command::new(&llvm_config).arg("--components"));
    let mut components = components.split_whitespace().collect::<Vec<_>>();
    components.retain(|c| optional_components.contains(c) || required_components.contains(c));

    for component in required_components {
        if !components.contains(component) {
            panic!("require llvm component {} but wasn't found", component);
        }
    }

    for component in components.iter() {
        println!("cargo:rustc-cfg=llvm_component=\"{}\"", component);
    }

    // Link in our own LLVM shims, compiled with the same flags as LLVM
    let mut cmd = Command::new(&llvm_config);
    cmd.arg("--cxxflags");
    let cxxflags = output(&mut cmd);
    let mut cfg = gcc::Config::new();
    for flag in cxxflags.split_whitespace() {
        // Ignore flags like `-m64` when we're doing a cross build
        if is_crossed && flag.starts_with("-m") {
            continue;
        }

        // -Wdate-time is not supported by the netbsd cross compiler
        if is_crossed && target.contains("netbsd") && flag.contains("date-time") {
            continue;
        }

        cfg.flag(flag);
    }

    for component in &components {
        let mut flag = String::from("-DLLVM_COMPONENT_");
        flag.push_str(&component.to_uppercase());
        cfg.flag(&flag);
    }

    if env::var_os("LLVM_RUSTLLVM").is_some() {
        cfg.flag("-DLLVM_RUSTLLVM");
    }

    build_helper::rerun_if_changed_anything_in_dir(Path::new("../rustllvm"));
    cfg.file("../rustllvm/PassWrapper.cpp")
       .file("../rustllvm/RustWrapper.cpp")
       .file("../rustllvm/ArchiveWrapper.cpp")
       .cpp(true)
       .cpp_link_stdlib(None) // we handle this below
       .compile("librustllvm.a");

    let (llvm_kind, llvm_link_arg) = detect_llvm_link(major, minor, &llvm_config);

    // Link in all LLVM libraries, if we're uwring the "wrong" llvm-config then
    // we don't pick up system libs because unfortunately they're for the host
    // of llvm-config, not the target that we're attempting to link.
    let mut cmd = Command::new(&llvm_config);
    cmd.arg("--libs");

    if let Some(link_arg) = llvm_link_arg {
        cmd.arg(link_arg);
    }

    if !is_crossed {
        cmd.arg("--system-libs");
    }
    cmd.args(&components);

    for lib in output(&mut cmd).split_whitespace() {
        let name = if lib.starts_with("-l") {
            &lib[2..]
        } else if lib.starts_with("-") {
            &lib[1..]
        } else if Path::new(lib).exists() {
            // On MSVC llvm-config will print the full name to libraries, but
            // we're only interested in the name part
            let name = Path::new(lib).file_name().unwrap().to_str().unwrap();
            name.trim_right_matches(".lib")
        } else if lib.ends_with(".lib") {
            // Some MSVC libraries just come up with `.lib` tacked on, so chop
            // that off
            lib.trim_right_matches(".lib")
        } else {
            continue;
        };

        // Don't need or want this library, but LLVM's CMake build system
        // doesn't provide a way to disable it, so filter it here even though we
        // may or may not have built it. We don't reference anything from this
        // library and it otherwise may just pull in extra dependencies on
        // libedit which we don't want
        if name == "LLVMLineEditor" {
            continue;
        }

        let kind = if name.starts_with("LLVM") {
            llvm_kind
        } else {
            "dylib"
        };
        println!("cargo:rustc-link-lib={}={}", kind, name);
    }

    // LLVM ldflags
    //
    // If we're a cross-compile of LLVM then unfortunately we can't trust these
    // ldflags (largely where all the LLVM libs are located). Currently just
    // hack around this by replacing the host triple with the target and pray
    // that those -L directories are the same!
    let mut cmd = Command::new(&llvm_config);
    if let Some(link_arg) = llvm_link_arg {
        cmd.arg(link_arg);
    }
    cmd.arg("--ldflags");
    for lib in output(&mut cmd).split_whitespace() {
        if lib.starts_with("-LIBPATH:") {
            println!("cargo:rustc-link-search=native={}", &lib[9..]);
        } else if is_crossed {
            if lib.starts_with("-L") {
                println!("cargo:rustc-link-search=native={}",
                         lib[2..].replace(&host, &target));
            }
        } else if lib.starts_with("-l") {
            println!("cargo:rustc-link-lib={}", &lib[2..]);
        } else if lib.starts_with("-L") {
            println!("cargo:rustc-link-search=native={}", &lib[2..]);
        }
    }

    let llvm_static_stdcpp = env::var_os("LLVM_STATIC_STDCPP");

    let stdcppname = if target.contains("openbsd") {
        // OpenBSD has a particular C++ runtime library name
        "estdc++"
    } else if target.contains("netbsd") && llvm_static_stdcpp.is_some() {
        // NetBSD uses a separate library when relocation is required
        "stdc++_pic"
    } else {
        "stdc++"
    };

    // C++ runtime library
    if !target.contains("msvc") {
        if let Some(s) = llvm_static_stdcpp {
            assert!(!cxxflags.contains("stdlib=libc++"));
            let path = PathBuf::from(s);
            println!("cargo:rustc-link-search=native={}",
                     path.parent().unwrap().display());
            println!("cargo:rustc-link-lib=static={}", stdcppname);
        } else if cxxflags.contains("stdlib=libc++") {
            println!("cargo:rustc-link-lib=c++");
        } else {
            println!("cargo:rustc-link-lib={}", stdcppname);
        }
    }

    // LLVM requires symbols from this library, but apparently they're not printeds
    // during llvm-config?
    if target.contains("windows") {
        println!("cargo:rustc-link-lib=ole32");
    }
    if target.contains("windows-gnu") {
        println!("cargo:rustc-link-lib=static-nobundle=gcc_s");
        println!("cargo:rustc-link-lib=static-nobundle=pthread");
    }
}
<commit_msg>Auto merge of #42113 - segevfiner:fix-ole32-warning, r=petrochenkov<commit_after>// Copyright 2015 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.

extern crate gcc;
extern crate build_helper;

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

use build_helper::output;

fn detect_llvm_link(major: u32, minor: u32, llvm_config: &Path)
    -> (&'static str, Option<&'static str>) {
    if major > 3 || (major == 3 && minor >= 9) {
        // Force the link mode we want, preferring static by default, but
        // possibly overridden by `configure --enable-llvm-link-shared`.
        if env::var_os("LLVM_LINK_SHARED").is_some() {
            return ("dylib", Some("--link-shared"));
        } else {
            return ("static", Some("--link-static"));
        }
    } else if major == 3 && minor == 8 {
        // Find out LLVM's default linking mode.
        let mut mode_cmd = Command::new(llvm_config);
        mode_cmd.arg("--shared-mode");
        if output(&mut mode_cmd).trim() == "shared" {
            return ("dylib", None);
        } else {
            return ("static", None);
        }
    }
    ("static", None)
}

fn main() {
    let target = env::var("TARGET").expect("TARGET was not set");
    let llvm_config = env::var_os("LLVM_CONFIG")
        .map(PathBuf::from)
        .unwrap_or_else(|| {
            if let Some(dir) = env::var_os("CARGO_TARGET_DIR").map(PathBuf::from) {
                let to_test = dir.parent()
                    .unwrap()
                    .parent()
                    .unwrap()
                    .join(&target)
                    .join("llvm/bin/llvm-config");
                if Command::new(&to_test).output().is_ok() {
                    return to_test;
                }
            }
            PathBuf::from("llvm-config")
        });

    println!("cargo:rerun-if-changed={}", llvm_config.display());

    // Test whether we're cross-compiling LLVM. This is a pretty rare case
    // currently where we're producing an LLVM for a different platform than
    // what this build script is currently running on.
    //
    // In that case, there's no guarantee that we can actually run the target,
    // so the build system works around this by giving us the LLVM_CONFIG for
    // the host platform. This only really works if the host LLVM and target
    // LLVM are compiled the same way, but for us that's typically the case.
    //
    // We *want* detect this cross compiling situation by asking llvm-config
    // what it's host-target is. If that's not the TARGET, then we're cross
    // compiling. Unfortunately `llvm-config` seems either be buggy, or we're
    // misconfiguring it, because the `i686-pc-windows-gnu` build of LLVM will
    // report itself with a `--host-target` of `x86_64-pc-windows-gnu`. This
    // tricks us into thinking we're doing a cross build when we aren't, so
    // havoc ensues.
    //
    // In any case, if we're cross compiling, this generally just means that we
    // can't trust all the output of llvm-config becaues it might be targeted
    // for the host rather than the target. As a result a bunch of blocks below
    // are gated on `if !is_crossed`
    let target = env::var("TARGET").expect("TARGET was not set");
    let host = env::var("HOST").expect("HOST was not set");
    let is_crossed = target != host;

    let mut optional_components =
        vec!["x86", "arm", "aarch64", "mips", "powerpc", "pnacl",
             "systemz", "jsbackend", "msp430", "sparc", "nvptx"];

    let mut version_cmd = Command::new(&llvm_config);
    version_cmd.arg("--version");
    let version_output = output(&mut version_cmd);
    let mut parts = version_output.split('.').take(2)
        .filter_map(|s| s.parse::<u32>().ok());
    let (major, minor) =
        if let (Some(major), Some(minor)) = (parts.next(), parts.next()) {
            (major, minor)
        } else {
            (3, 7)
        };

    if major > 3 {
        optional_components.push("hexagon");
    }

    // FIXME: surely we don't need all these components, right? Stuff like mcjit
    //        or interpreter the compiler itself never uses.
    let required_components = &["ipo",
                                "bitreader",
                                "bitwriter",
                                "linker",
                                "asmparser",
                                "mcjit",
                                "interpreter",
                                "instrumentation"];

    let components = output(Command::new(&llvm_config).arg("--components"));
    let mut components = components.split_whitespace().collect::<Vec<_>>();
    components.retain(|c| optional_components.contains(c) || required_components.contains(c));

    for component in required_components {
        if !components.contains(component) {
            panic!("require llvm component {} but wasn't found", component);
        }
    }

    for component in components.iter() {
        println!("cargo:rustc-cfg=llvm_component=\"{}\"", component);
    }

    // Link in our own LLVM shims, compiled with the same flags as LLVM
    let mut cmd = Command::new(&llvm_config);
    cmd.arg("--cxxflags");
    let cxxflags = output(&mut cmd);
    let mut cfg = gcc::Config::new();
    for flag in cxxflags.split_whitespace() {
        // Ignore flags like `-m64` when we're doing a cross build
        if is_crossed && flag.starts_with("-m") {
            continue;
        }

        // -Wdate-time is not supported by the netbsd cross compiler
        if is_crossed && target.contains("netbsd") && flag.contains("date-time") {
            continue;
        }

        cfg.flag(flag);
    }

    for component in &components {
        let mut flag = String::from("-DLLVM_COMPONENT_");
        flag.push_str(&component.to_uppercase());
        cfg.flag(&flag);
    }

    if env::var_os("LLVM_RUSTLLVM").is_some() {
        cfg.flag("-DLLVM_RUSTLLVM");
    }

    build_helper::rerun_if_changed_anything_in_dir(Path::new("../rustllvm"));
    cfg.file("../rustllvm/PassWrapper.cpp")
       .file("../rustllvm/RustWrapper.cpp")
       .file("../rustllvm/ArchiveWrapper.cpp")
       .cpp(true)
       .cpp_link_stdlib(None) // we handle this below
       .compile("librustllvm.a");

    let (llvm_kind, llvm_link_arg) = detect_llvm_link(major, minor, &llvm_config);

    // Link in all LLVM libraries, if we're uwring the "wrong" llvm-config then
    // we don't pick up system libs because unfortunately they're for the host
    // of llvm-config, not the target that we're attempting to link.
    let mut cmd = Command::new(&llvm_config);
    cmd.arg("--libs");

    if let Some(link_arg) = llvm_link_arg {
        cmd.arg(link_arg);
    }

    if !is_crossed {
        cmd.arg("--system-libs");
    }
    cmd.args(&components);

    for lib in output(&mut cmd).split_whitespace() {
        let name = if lib.starts_with("-l") {
            &lib[2..]
        } else if lib.starts_with("-") {
            &lib[1..]
        } else if Path::new(lib).exists() {
            // On MSVC llvm-config will print the full name to libraries, but
            // we're only interested in the name part
            let name = Path::new(lib).file_name().unwrap().to_str().unwrap();
            name.trim_right_matches(".lib")
        } else if lib.ends_with(".lib") {
            // Some MSVC libraries just come up with `.lib` tacked on, so chop
            // that off
            lib.trim_right_matches(".lib")
        } else {
            continue;
        };

        // Don't need or want this library, but LLVM's CMake build system
        // doesn't provide a way to disable it, so filter it here even though we
        // may or may not have built it. We don't reference anything from this
        // library and it otherwise may just pull in extra dependencies on
        // libedit which we don't want
        if name == "LLVMLineEditor" {
            continue;
        }

        let kind = if name.starts_with("LLVM") {
            llvm_kind
        } else {
            "dylib"
        };
        println!("cargo:rustc-link-lib={}={}", kind, name);
    }

    // LLVM ldflags
    //
    // If we're a cross-compile of LLVM then unfortunately we can't trust these
    // ldflags (largely where all the LLVM libs are located). Currently just
    // hack around this by replacing the host triple with the target and pray
    // that those -L directories are the same!
    let mut cmd = Command::new(&llvm_config);
    if let Some(link_arg) = llvm_link_arg {
        cmd.arg(link_arg);
    }
    cmd.arg("--ldflags");
    for lib in output(&mut cmd).split_whitespace() {
        if lib.starts_with("-LIBPATH:") {
            println!("cargo:rustc-link-search=native={}", &lib[9..]);
        } else if is_crossed {
            if lib.starts_with("-L") {
                println!("cargo:rustc-link-search=native={}",
                         lib[2..].replace(&host, &target));
            }
        } else if lib.starts_with("-l") {
            println!("cargo:rustc-link-lib={}", &lib[2..]);
        } else if lib.starts_with("-L") {
            println!("cargo:rustc-link-search=native={}", &lib[2..]);
        }
    }

    let llvm_static_stdcpp = env::var_os("LLVM_STATIC_STDCPP");

    let stdcppname = if target.contains("openbsd") {
        // OpenBSD has a particular C++ runtime library name
        "estdc++"
    } else if target.contains("netbsd") && llvm_static_stdcpp.is_some() {
        // NetBSD uses a separate library when relocation is required
        "stdc++_pic"
    } else {
        "stdc++"
    };

    // C++ runtime library
    if !target.contains("msvc") {
        if let Some(s) = llvm_static_stdcpp {
            assert!(!cxxflags.contains("stdlib=libc++"));
            let path = PathBuf::from(s);
            println!("cargo:rustc-link-search=native={}",
                     path.parent().unwrap().display());
            println!("cargo:rustc-link-lib=static={}", stdcppname);
        } else if cxxflags.contains("stdlib=libc++") {
            println!("cargo:rustc-link-lib=c++");
        } else {
            println!("cargo:rustc-link-lib={}", stdcppname);
        }
    }

    // LLVM requires symbols from this library, but apparently they're not printed
    // during llvm-config?
    if target.contains("windows-gnu") {
        println!("cargo:rustc-link-lib=static-nobundle=gcc_s");
        println!("cargo:rustc-link-lib=static-nobundle=pthread");
    }
}
<|endoftext|>


<commit_before>use super::*;
use super::super::lexer;
use codemap::CodeMap;
use codemap::Spanned;
use std::fmt::Debug;
use std::cmp::PartialEq;

fn get_tokens(source: &str) -> Vec<Spanned<Token>> {
  let mut map = CodeMap::new();
  let file = map.add_file(String::from("_test"), String::from(source));
  lexer::lex(&file)
}

fn test_parse<T: Debug + PartialEq>(
  source: &str,
  func: &Fn(&mut ParseIter) -> Result<T, ParseErrorKind>,
  expect: Result<T, ParseErrorKind>,
) {
  let tokens = get_tokens(source);
  let mut it = tokens.iter().peekable();

  assert_eq!(func(&mut it), expect);

  assert_eq!(func(&mut it), Err(UnexpectedToken(lexer::Token::End)));
  it.next();

  assert_eq!(func(&mut it), Err(UnexpectedToken(lexer::Token::EOF)));
  it.next();

  assert_eq!(func(&mut it), Err(UnexpectedEOF));
}

#[test]
fn test_quark() {
  test_parse("null", &parse_quark, Ok(Node::Null));
  test_parse("true", &parse_quark, Ok(Node::Bool(true)));
  test_parse("false", &parse_quark, Ok(Node::Bool(false)));
  test_parse("1.3", &parse_quark, Ok(Node::Float(1.3)));
  test_parse("0.3", &parse_quark, Ok(Node::Float(0.3)));
  test_parse("2", &parse_quark, Ok(Node::Int(2)));
  test_parse("3", &parse_quark, Ok(Node::Int(3)));
  test_parse("name", &parse_quark, Ok(Node::Name(String::from("name"))));
  test_parse("table", &parse_quark, Ok(Node::Table));
}

#[test]
fn test_atom() {
  test_parse("null", &parse_atom, Ok(Node::Null));

  test_parse("(null)", &parse_atom, Ok(Node::Null));
}

#[test]
fn test_simple() {
  test_parse("foo", &parse_simple, Ok(Node::Name(String::from("foo"))));
  test_parse(
    "foo.bar",
    &parse_simple,
    Ok(Node::Index {
      lhs: Box::new(Node::Name(String::from("foo"))),
      rhs: Box::new(Node::Str(String::from("bar"))),
    }),
  );
  test_parse(
    "foo[bar]",
    &parse_simple,
    Ok(Node::Index {
      lhs: Box::new(Node::Name(String::from("foo"))),
      rhs: Box::new(Node::Name(String::from("bar"))),
    }),
  );
  test_parse(
    "foo()",
    &parse_simple,
    Ok(Node::Call {
      func: Box::new(Node::Name(String::from("foo"))),
      args: Vec::new(),
    }),
  );
  test_parse(
    "foo:bar()",
    &parse_simple,
    Ok(Node::Method {
      owner: Box::new(Node::Name(String::from("foo"))),
      method: Box::new(Node::Str(String::from("bar"))),
      args: Vec::new(),
    }),
  );
  test_parse(
    "foo.bar()",
    &parse_simple,
    Ok(Node::Call {
      func: Box::new(Node::Index {
        lhs: Box::new(Node::Name(String::from("foo"))),
        rhs: Box::new(Node::Str(String::from("bar"))),
      }),
      args: Vec::new(),
    }),
  );
  test_parse(
    "foo.bar[baz]:qux()",
    &parse_simple,
    Ok(Node::Method {
      owner: Box::new(Node::Index {
        lhs: Box::new(Node::Index {
          lhs: Box::new(Node::Name(String::from("foo"))),
          rhs: Box::new(Node::Str(String::from("bar"))),
        }),
        rhs: Box::new(Node::Name(String::from("baz"))),
      }),
      method: Box::new(Node::Str(String::from("qux"))),
      args: Vec::new(),
    }),
  );
}

#[test]
fn test_fn_args() {
  test_parse("()", &parse_fn_args, Ok(Vec::new()));
}

#[test]
fn test_un_expr() {
  test_parse("5", &parse_un_expr, Ok(Node::Int(5)));

  test_parse(
    "foo()",
    &parse_un_expr,
    Ok(Node::Call {
      func: Box::new(Node::Name(String::from("foo"))),
      args: Vec::new(),
    }),
  );

  test_parse(
    "-5",
    &parse_un_expr,
    Ok(Node::UnExpr {
      op: lexer::Token::Sub,
      val: Box::new(Node::Int(5)),
    }),
  );

  test_parse(
    "-foo.bar",
    &parse_un_expr,
    Ok(Node::UnExpr {
      op: lexer::Token::Sub,
      val: Box::new(Node::Index {
        lhs: Box::new(Node::Name(String::from("foo"))),
        rhs: Box::new(Node::Str(String::from("bar"))),
      }),
    }),
  );

  test_parse(
    "!-5",
    &parse_un_expr,
    Ok(Node::UnExpr {
      op: lexer::Token::Not,
      val: Box::new(Node::UnExpr {
        op: lexer::Token::Sub,
        val: Box::new(Node::Int(5)),
      }),
    }),
  );
}

#[test]
fn test_bin_expr() {
  test_parse(
    "1 + 2",
    &parse_bin_expr,
    Ok(Node::BinExpr {
      lhs: Box::new(Node::Int(1)),
      op: lexer::Token::Add,
      rhs: Box::new(Node::Int(2)),
    }),
  );

  test_parse(
    "(1 + 2)",
    &parse_bin_expr,
    Ok(Node::BinExpr {
      lhs: Box::new(Node::Int(1)),
      op: lexer::Token::Add,
      rhs: Box::new(Node::Int(2)),
    }),
  );

  test_parse(
    "1 + 2 * 3",
    &parse_bin_expr,
    Ok(Node::BinExpr {
      lhs: Box::new(Node::Int(1)),
      op: lexer::Token::Add,
      rhs: Box::new(Node::BinExpr {
        lhs: Box::new(Node::Int(2)),
        op: lexer::Token::Mul,
        rhs: Box::new(Node::Int(3)),
      }),
    }),
  );
}

#[test]
fn test_fn_expr() {
  test_parse(
    "|| 5",
    &parse_il_expr,
    Ok(Node::Lambda {
      params: Vec::new(),
      expr: Box::new(Node::Int(5)),
    }),
  );

  test_parse(
    "|x| 5",
    &parse_il_expr,
    Ok(Node::Lambda {
      params: vec![String::from("x")],
      expr: Box::new(Node::Int(5)),
    }),
  );

  test_parse(
    "|x,| 5",
    &parse_il_expr,
    Ok(Node::Lambda {
      params: vec![String::from("x")],
      expr: Box::new(Node::Int(5)),
    }),
  );

  test_parse(
    "|x,y| 5",
    &parse_il_expr,
    Ok(Node::Lambda {
      params: vec![String::from("x"), String::from("y")],
      expr: Box::new(Node::Int(5)),
    }),
  );
}

#[test]
fn test_decl() {
  test_parse("x", &parse_decl, Ok(Var::Single(String::from("x"))));

  test_parse(
    "[x]",
    &parse_decl,
    Ok(Var::Multi(vec![Var::Single(String::from("x"))])),
  );

  test_parse(
    "[x, y]",
    &parse_decl,
    Ok(Var::Multi(vec![
      Var::Single(String::from("x")),
      Var::Single(String::from("y")),
    ])),
  );

  test_parse(
    "[[x, y], z]",
    &parse_decl,
    Ok(Var::Multi(vec![
      Var::Multi(vec![
        Var::Single(String::from("x")),
        Var::Single(String::from("y")),
      ]),
      Var::Single(String::from("z")),
    ])),
  );

  test_parse(
    "[x, [y, z]]",
    &parse_decl,
    Ok(Var::Multi(vec![
      Var::Single(String::from("x")),
      Var::Multi(vec![
        Var::Single(String::from("y")),
        Var::Single(String::from("z")),
      ]),
    ])),
  );

  test_parse(
    "[[x], [y]]",
    &parse_decl,
    Ok(Var::Multi(vec![
      Var::Multi(vec![Var::Single(String::from("x"))]),
      Var::Multi(vec![Var::Single(String::from("y"))]),
    ])),
  );

  test_parse(
    "[x, [y, z], q]",
    &parse_decl,
    Ok(Var::Multi(vec![
      Var::Single(String::from("x")),
      Var::Multi(vec![
        Var::Single(String::from("y")),
        Var::Single(String::from("z")),
      ]),
      Var::Single(String::from("q")),
    ])),
  );
}

#[test]
fn test_return_stmt() {
  test_parse("return", &parse_stmt, Ok(Node::Return(None)));

  test_parse(
    "return 5",
    &parse_stmt,
    Ok(Node::Return(Some(Box::new(Node::Int(5))))),
  );

  test_parse(
    "return fn()
       return 5",
    &parse_stmt,
    Ok(Node::Return(Some(Box::new(Node::Func {
      params: Vec::new(),
      body: vec![Node::Return(Some(Box::new(Node::Int(5))))],
    })))),
  );
}

#[test]
fn test_if_stmt() {
  test_parse(
    "if true
       pass",
    &parse_stmt,
    Ok(Node::If {
      cond: Box::new(Node::Bool(true)),
      body: vec![Node::Pass],
    }),
  );

  test_parse(
    "else if true
       pass",
    &parse_stmt,
    Ok(Node::ElseIf {
      cond: Box::new(Node::Bool(true)),
      body: vec![Node::Pass],
    }),
  );

  test_parse(
    "else
       pass",
    &parse_stmt,
    Ok(Node::Else {
      body: vec![Node::Pass],
    }),
  );
}

#[test]
fn test_for_stmt() {
  test_parse(
    "for x in true
       pass",
    &parse_stmt,
    Ok(Node::For {
      decl: Var::Single(String::from("x")),
      expr: Box::new(Node::Bool(true)),
      body: vec![Node::Pass],
    }),
  );
}

#[test]
fn test_while_stmt() {
  test_parse(
    "while true
       pass",
    &parse_stmt,
    Ok(Node::While {
      expr: Box::new(Node::Bool(true)),
      body: vec![Node::Pass],
    }),
  );
}

#[test]
fn test_loop_stmt() {
  test_parse(
    "loop
       pass",
    &parse_stmt,
    Ok(Node::Loop {
      body: vec![Node::Pass],
    }),
  );
}
<commit_msg>tests.parser: Add dummy parse_place tests<commit_after>use super::*;
use super::super::lexer;
use codemap::CodeMap;
use codemap::Spanned;
use std::fmt::Debug;
use std::cmp::PartialEq;

fn get_tokens(source: &str) -> Vec<Spanned<Token>> {
  let mut map = CodeMap::new();
  let file = map.add_file(String::from("_test"), String::from(source));
  lexer::lex(&file)
}

fn test_parse<T: Debug + PartialEq>(
  source: &str,
  func: &Fn(&mut ParseIter) -> Result<T, ParseErrorKind>,
  expect: Result<T, ParseErrorKind>,
) {
  let tokens = get_tokens(source);
  let mut it = tokens.iter().peekable();

  assert_eq!(func(&mut it), expect);

  assert_eq!(func(&mut it), Err(UnexpectedToken(lexer::Token::End)));
  it.next();

  assert_eq!(func(&mut it), Err(UnexpectedToken(lexer::Token::EOF)));
  it.next();

  assert_eq!(func(&mut it), Err(UnexpectedEOF));
}

#[test]
fn test_quark() {
  test_parse("null", &parse_quark, Ok(Node::Null));
  test_parse("true", &parse_quark, Ok(Node::Bool(true)));
  test_parse("false", &parse_quark, Ok(Node::Bool(false)));
  test_parse("1.3", &parse_quark, Ok(Node::Float(1.3)));
  test_parse("0.3", &parse_quark, Ok(Node::Float(0.3)));
  test_parse("2", &parse_quark, Ok(Node::Int(2)));
  test_parse("3", &parse_quark, Ok(Node::Int(3)));
  test_parse("name", &parse_quark, Ok(Node::Name(String::from("name"))));
  test_parse("table", &parse_quark, Ok(Node::Table));
}

#[test]
fn test_atom() {
  test_parse("null", &parse_atom, Ok(Node::Null));

  test_parse("(null)", &parse_atom, Ok(Node::Null));
}

#[test]
fn test_simple() {
  test_parse("foo", &parse_simple, Ok(Node::Name(String::from("foo"))));
  test_parse(
    "foo.bar",
    &parse_simple,
    Ok(Node::Index {
      lhs: Box::new(Node::Name(String::from("foo"))),
      rhs: Box::new(Node::Str(String::from("bar"))),
    }),
  );
  test_parse(
    "foo[bar]",
    &parse_simple,
    Ok(Node::Index {
      lhs: Box::new(Node::Name(String::from("foo"))),
      rhs: Box::new(Node::Name(String::from("bar"))),
    }),
  );
  test_parse(
    "foo()",
    &parse_simple,
    Ok(Node::Call {
      func: Box::new(Node::Name(String::from("foo"))),
      args: Vec::new(),
    }),
  );
  test_parse(
    "foo:bar()",
    &parse_simple,
    Ok(Node::Method {
      owner: Box::new(Node::Name(String::from("foo"))),
      method: Box::new(Node::Str(String::from("bar"))),
      args: Vec::new(),
    }),
  );
  test_parse(
    "foo.bar()",
    &parse_simple,
    Ok(Node::Call {
      func: Box::new(Node::Index {
        lhs: Box::new(Node::Name(String::from("foo"))),
        rhs: Box::new(Node::Str(String::from("bar"))),
      }),
      args: Vec::new(),
    }),
  );
  test_parse(
    "foo.bar[baz]:qux()",
    &parse_simple,
    Ok(Node::Method {
      owner: Box::new(Node::Index {
        lhs: Box::new(Node::Index {
          lhs: Box::new(Node::Name(String::from("foo"))),
          rhs: Box::new(Node::Str(String::from("bar"))),
        }),
        rhs: Box::new(Node::Name(String::from("baz"))),
      }),
      method: Box::new(Node::Str(String::from("qux"))),
      args: Vec::new(),
    }),
  );
}

#[test]
fn test_fn_args() {
  test_parse("()", &parse_fn_args, Ok(Vec::new()));
}

#[test]
fn test_un_expr() {
  test_parse("5", &parse_un_expr, Ok(Node::Int(5)));

  test_parse(
    "foo()",
    &parse_un_expr,
    Ok(Node::Call {
      func: Box::new(Node::Name(String::from("foo"))),
      args: Vec::new(),
    }),
  );

  test_parse(
    "-5",
    &parse_un_expr,
    Ok(Node::UnExpr {
      op: lexer::Token::Sub,
      val: Box::new(Node::Int(5)),
    }),
  );

  test_parse(
    "-foo.bar",
    &parse_un_expr,
    Ok(Node::UnExpr {
      op: lexer::Token::Sub,
      val: Box::new(Node::Index {
        lhs: Box::new(Node::Name(String::from("foo"))),
        rhs: Box::new(Node::Str(String::from("bar"))),
      }),
    }),
  );

  test_parse(
    "!-5",
    &parse_un_expr,
    Ok(Node::UnExpr {
      op: lexer::Token::Not,
      val: Box::new(Node::UnExpr {
        op: lexer::Token::Sub,
        val: Box::new(Node::Int(5)),
      }),
    }),
  );
}

#[test]
fn test_bin_expr() {
  test_parse(
    "1 + 2",
    &parse_bin_expr,
    Ok(Node::BinExpr {
      lhs: Box::new(Node::Int(1)),
      op: lexer::Token::Add,
      rhs: Box::new(Node::Int(2)),
    }),
  );

  test_parse(
    "(1 + 2)",
    &parse_bin_expr,
    Ok(Node::BinExpr {
      lhs: Box::new(Node::Int(1)),
      op: lexer::Token::Add,
      rhs: Box::new(Node::Int(2)),
    }),
  );

  test_parse(
    "1 + 2 * 3",
    &parse_bin_expr,
    Ok(Node::BinExpr {
      lhs: Box::new(Node::Int(1)),
      op: lexer::Token::Add,
      rhs: Box::new(Node::BinExpr {
        lhs: Box::new(Node::Int(2)),
        op: lexer::Token::Mul,
        rhs: Box::new(Node::Int(3)),
      }),
    }),
  );
}

#[test]
fn test_fn_expr() {
  test_parse(
    "|| 5",
    &parse_il_expr,
    Ok(Node::Lambda {
      params: Vec::new(),
      expr: Box::new(Node::Int(5)),
    }),
  );

  test_parse(
    "|x| 5",
    &parse_il_expr,
    Ok(Node::Lambda {
      params: vec![String::from("x")],
      expr: Box::new(Node::Int(5)),
    }),
  );

  test_parse(
    "|x,| 5",
    &parse_il_expr,
    Ok(Node::Lambda {
      params: vec![String::from("x")],
      expr: Box::new(Node::Int(5)),
    }),
  );

  test_parse(
    "|x,y| 5",
    &parse_il_expr,
    Ok(Node::Lambda {
      params: vec![String::from("x"), String::from("y")],
      expr: Box::new(Node::Int(5)),
    }),
  );
}

#[test]
fn test_decl() {
  test_parse("x", &parse_decl, Ok(Var::Single(String::from("x"))));

  test_parse(
    "[x]",
    &parse_decl,
    Ok(Var::Multi(vec![Var::Single(String::from("x"))])),
  );

  test_parse(
    "[x, y]",
    &parse_decl,
    Ok(Var::Multi(vec![
      Var::Single(String::from("x")),
      Var::Single(String::from("y")),
    ])),
  );

  test_parse(
    "[[x, y], z]",
    &parse_decl,
    Ok(Var::Multi(vec![
      Var::Multi(vec![
        Var::Single(String::from("x")),
        Var::Single(String::from("y")),
      ]),
      Var::Single(String::from("z")),
    ])),
  );

  test_parse(
    "[x, [y, z]]",
    &parse_decl,
    Ok(Var::Multi(vec![
      Var::Single(String::from("x")),
      Var::Multi(vec![
        Var::Single(String::from("y")),
        Var::Single(String::from("z")),
      ]),
    ])),
  );

  test_parse(
    "[[x], [y]]",
    &parse_decl,
    Ok(Var::Multi(vec![
      Var::Multi(vec![Var::Single(String::from("x"))]),
      Var::Multi(vec![Var::Single(String::from("y"))]),
    ])),
  );

  test_parse(
    "[x, [y, z], q]",
    &parse_decl,
    Ok(Var::Multi(vec![
      Var::Single(String::from("x")),
      Var::Multi(vec![
        Var::Single(String::from("y")),
        Var::Single(String::from("z")),
      ]),
      Var::Single(String::from("q")),
    ])),
  );
}

#[test]
fn test_return_stmt() {
  test_parse("return", &parse_stmt, Ok(Node::Return(None)));

  test_parse(
    "return 5",
    &parse_stmt,
    Ok(Node::Return(Some(Box::new(Node::Int(5))))),
  );

  test_parse(
    "return fn()
       return 5",
    &parse_stmt,
    Ok(Node::Return(Some(Box::new(Node::Func {
      params: Vec::new(),
      body: vec![Node::Return(Some(Box::new(Node::Int(5))))],
    })))),
  );
}

#[test]
fn test_if_stmt() {
  test_parse(
    "if true
       pass",
    &parse_stmt,
    Ok(Node::If {
      cond: Box::new(Node::Bool(true)),
      body: vec![Node::Pass],
      els: None,
    }),
  );

  test_parse(
    "else if true
       pass",
    &parse_stmt,
    Ok(Node::ElseIf {
      cond: Box::new(Node::Bool(true)),
      body: vec![Node::Pass],
    }),
  );

  test_parse(
    "else
       pass",
    &parse_stmt,
    Ok(Node::Else {
      body: vec![Node::Pass],
    }),
  );
}

#[test]
fn test_for_stmt() {
  test_parse(
    "for x in true
       pass",
    &parse_stmt,
    Ok(Node::For {
      decl: Var::Single(String::from("x")),
      expr: Box::new(Node::Bool(true)),
      body: vec![Node::Pass],
    }),
  );
}

#[test]
fn test_while_stmt() {
  test_parse(
    "while true
       pass",
    &parse_stmt,
    Ok(Node::While {
      expr: Box::new(Node::Bool(true)),
      body: vec![Node::Pass],
    }),
  );
}

#[test]
fn test_loop_stmt() {
  test_parse(
    "loop
       pass",
    &parse_stmt,
    Ok(Node::Loop {
      body: vec![Node::Pass],
    }),
  );
}

#[test]
fn test_place() {
  test_parse(
    "x",
    &parse_place,
    Ok(Place::Single(Box::new(Node::Name(String::from("x"))))),
  );

  test_parse(
    "[x]",
    &parse_place,
    Ok(Place::Multi(vec![
      Place::Single(Box::new(Node::Name(String::from("x")))),
    ])),
  );

  test_parse(
    "[x.y]",
    &parse_place,
    Ok(Place::Multi(vec![
      Place::Single(Box::new(Node::Index {
        lhs: Box::new(Node::Name(String::from("x"))),
        rhs: Box::new(Node::Str(String::from("y"))),
      })),
    ])),
  );

  test_parse(
    "[x, y]",
    &parse_place,
    Ok(Place::Multi(vec![
      Place::Single(Box::new(Node::Name(String::from("x")))),
      Place::Single(Box::new(Node::Name(String::from("y")))),
    ])),
  );

  test_parse(
    "[[x, y], z]",
    &parse_place,
    Ok(Place::Multi(vec![
      Place::Multi(vec![
        Place::Single(Box::new(Node::Name(String::from("x")))),
        Place::Single(Box::new(Node::Name(String::from("y")))),
      ]),
      Place::Single(Box::new(Node::Name(String::from("z")))),
    ])),
  );

  test_parse(
    "[x, [y, z]]",
    &parse_place,
    Ok(Place::Multi(vec![
      Place::Single(Box::new(Node::Name(String::from("x")))),
      Place::Multi(vec![
        Place::Single(Box::new(Node::Name(String::from("y")))),
        Place::Single(Box::new(Node::Name(String::from("z")))),
      ]),
    ])),
  );

  test_parse(
    "[[x], [y]]",
    &parse_place,
    Ok(Place::Multi(vec![
      Place::Multi(vec![Place::Single(Box::new(Node::Name(String::from("x"))))]),
      Place::Multi(vec![Place::Single(Box::new(Node::Name(String::from("y"))))]),
    ])),
  );

  test_parse(
    "[x, [y, z], q]",
    &parse_place,
    Ok(Place::Multi(vec![
      Place::Single(Box::new(Node::Name(String::from("x")))),
      Place::Multi(vec![
        Place::Single(Box::new(Node::Name(String::from("y")))),
        Place::Single(Box::new(Node::Name(String::from("z")))),
      ]),
      Place::Single(Box::new(Node::Name(String::from("q")))),
    ])),
  );
}
<|endoftext|>


<commit_before>use tensor::{Tensor, NumLimits, THVec, THVecGeneric, THDims};
use num::NumCast;

impl<T: NumLimits> THVec<T> {
    pub fn new(dims: Vec<usize>, data: Vec<T>) -> Self {
        THVec {
            dims: dims,
            data: data,
        }
    }
}
impl THVecGeneric {
    pub fn new(dims: Vec<usize>, data: Vec<i64>) -> Self {
        THVecGeneric {
            dims: dims,
            data: data,
        }
    }
}
impl THDims {
    fn new(dims: Vec<usize>) -> Self {
        THDims { dims: dims }
    }
}
impl<T: NumLimits> From<Vec<Vec<Vec<T>>>> for THVec<T> {
    fn from(input: Vec<Vec<Vec<T>>>) -> Self {
        let dims = vec![input.len(), input[0].len(), input[0][0].len()];
        let v = input
            .iter()
            .flat_map(|d| d.iter())
            .flat_map(|d| d.iter())
            .map(|d| *d)
            .collect();
        THVec::new(dims, v)
    }
}
impl<T: NumLimits> From<Vec<Vec<T>>> for THVec<T> {
    fn from(input: Vec<Vec<T>>) -> Self {
        let dims = vec![input.len(), input[0].len()];
        let v = input.iter().flat_map(|d| d.iter()).map(|d| *d).collect();
        THVec::new(dims, v)
    }
}
impl<T: NumLimits> From<Vec<T>> for THVec<T> {
    fn from(input: Vec<T>) -> Self {
        let dims = vec![input.len()];
        THVec::new(dims, input)
    }
}
impl<T: NumLimits> From<T> for THVec<T> {
    fn from(input: T) -> Self {
        let v = vec![input];
        THVec::new(vec![], v)
    }
}
impl<T: NumLimits> From<T> for THVecGeneric {
    fn from(input: T) -> Self {
        let v: Vec<i64> = vec![<i64 as NumCast>::from(input).unwrap()];
        THVecGeneric::new(vec![], v)
    }
}

#[allow(unused_variables)]
impl<T: NumLimits> From<()> for THVec<T> {
    fn from(input: ()) -> Self {
        THVec::new(vec![], vec![])
    }
}
#[allow(unused_variables)]
impl From<()> for THVecGeneric {
    fn from(input: ()) -> Self {
        THVecGeneric::new(vec![], vec![])
    }
}
#[allow(unused_variables)]
impl From<()> for THDims {
    fn from(input: ()) -> Self {
        THDims::new(vec![])
    }
}
impl<T: NumLimits> From<(usize, usize)> for THVec<T> {
    fn from(input: (usize, usize)) -> Self {
        THVec::new(vec![input.0, input.1], vec![])
    }
}
impl From<(usize, usize)> for THVecGeneric {
    fn from(input: (usize, usize)) -> Self {

        THVecGeneric::new(vec![input.0, input.1], vec![])
    }
}
impl From<(usize)> for THVecGeneric {
    fn from(input: (usize)) -> Self {

        THVecGeneric::new(vec![input], vec![])
    }
}
impl<T: NumLimits> From<(usize)> for THVec<T> {
    fn from(input: (usize)) -> Self {
        THVec::new(vec![input], vec![])
    }
}
impl<T: NumLimits> From<Vec<usize>> for THVec<T> {
    fn from(input: Vec<usize>) -> Self {
        THVec::new(input, vec![])
    }
}
impl From<Vec<usize>> for THVecGeneric {
    fn from(input: Vec<usize>) -> Self {
        THVecGeneric::new(input, vec![])
    }
}
impl From<Vec<usize>> for THDims {
    fn from(input: Vec<usize>) -> Self {
        THDims::new(input)
    }
}
impl<S: NumLimits, D: NumLimits> From<Tensor<S>> for THVec<D> {
    fn from(input: Tensor<S>) -> Self {
        unimplemented!()
    }
}
impl<T: NumLimits> From<Vec<THVec<T>>> for THVec<T> {
    fn from(input: Vec<THVec<T>>) -> Self {
        unimplemented!()
    }
}
impl<S: NumLimits, D: NumLimits> From<Vec<Tensor<S>>> for THVec<D> {
    fn from(input: Vec<Tensor<S>>) -> Self {
        let mut d: Vec<D> = Vec::with_capacity(input.len() * input[0].len());
        let len = input[0].len();
        let mut tmp: Vec<S> = Vec::with_capacity(len);
        for t in &input {
            t.get_storage(&mut tmp);
            for j in 0..len {
                d.push(<D as ::num::NumCast>::from(tmp[j]).unwrap());
            }
        }
        let mut sizes = input[0].size();
        let mut dims = vec![input.len()];
        dims.append(&mut sizes);
        THVec::new(dims, d)
    }
}
impl From<THVecGeneric> for THVec<u8> {
    fn from(input: THVecGeneric) -> Self {
        let data: Vec<u8> = input
            .data
            .iter()
            .map(|t| <u8 as NumCast>::from(*t).unwrap())
            .collect();
        THVec::new(input.dims.clone(), data)
    }
}
impl From<THVecGeneric> for THVec<f32> {
    fn from(input: THVecGeneric) -> Self {
        let data: Vec<f32> = input
            .data
            .iter()
            .map(|t| <f32 as NumCast>::from(*t).unwrap())
            .collect();
        THVec::new(input.dims.clone(), data)
    }
}
impl From<THVecGeneric> for THVec<i64> {
    fn from(input: THVecGeneric) -> Self {
        let data: Vec<i64> = input
            .data
            .iter()
            .map(|t| <i64 as NumCast>::from(*t).unwrap())
            .collect();
        THVec::new(input.dims.clone(), data)
    }
}

impl<T: NumLimits> From<THVec<T>> for THDims {
    fn from(input: THVec<T>) -> Self {
        THDims::new(input.dims.clone())
    }
}
impl From<THVecGeneric> for THDims {
    fn from(input: THVecGeneric) -> Self {
        THDims::new(input.dims.clone())
    }
}

trait TensorNew<T: NumLimits> {
    fn tensor_new(arg: THDims) -> Tensor<T>;
}

impl<T: NumLimits> TensorNew<T> for Tensor<T> {
    #[allow(unused_variables)]
    default fn tensor_new(arg: THDims) -> Tensor<T> {
        unreachable!()
    }
}

impl TensorNew<u8> for Tensor<u8> {
    fn tensor_new(arg: THDims) -> Tensor<u8> {
        let t = ::RcMutNew(::tensor::ByteTensor::with_capacity(arg.dims.as_slice()));
        ::tensor::Tensor { value: t }
    }
}
impl TensorNew<i64> for Tensor<i64> {
    fn tensor_new(arg: THDims) -> Tensor<i64> {
        let t = ::RcMutNew(::tensor::LongTensor::with_capacity(arg.dims.as_slice()));
        ::tensor::Tensor { value: t }
    }
}
impl TensorNew<f32> for Tensor<f32> {
    fn tensor_new(arg: THDims) -> Tensor<f32> {
        let t = ::RcMutNew(::tensor::FloatTensor::with_capacity(arg.dims.as_slice()));
        ::tensor::Tensor { value: t }
    }
}
impl TensorNew<f64> for Tensor<f64> {
    fn tensor_new(arg: THDims) -> Tensor<f64> {
        let t = ::RcMutNew(::tensor::DoubleTensor::with_capacity(arg.dims.as_slice()));
        ::tensor::Tensor { value: t }
    }
}

pub fn byte_tensor<T>(arg: T) -> Tensor<u8>
    where T: Into<THVec<u8>>
{
    tensor(arg)
}
pub fn long_tensor<T>(arg: T) -> Tensor<i64>
    where T: Into<THVec<i64>>
{
    tensor(arg)
}
pub fn float_tensor<T>(arg: T) -> Tensor<f32>
    where T: Into<THVec<f32>>
{
    tensor(arg)
}
pub fn double_tensor<T>(arg: T) -> Tensor<f64>
    where T: Into<THVec<f64>>
{
    tensor(arg)
}
pub fn tensor<S, T>(arg: S) -> Tensor<T>
    where T: NumLimits,
          S: Into<THVec<T>>
{
    let t: THVec<T> = arg.into();
    Tensor::tensor_new(t.into())
}
<commit_msg>add support for [usize; 4]<commit_after>use tensor::{Tensor, NumLimits, THVec, THVecGeneric, THDims};
use num::NumCast;

impl<T: NumLimits> THVec<T> {
    pub fn new(dims: Vec<usize>, data: Vec<T>) -> Self {
        THVec {
            dims: dims,
            data: data,
        }
    }
}
impl THVecGeneric {
    pub fn new(dims: Vec<usize>, data: Vec<i64>) -> Self {
        THVecGeneric {
            dims: dims,
            data: data,
        }
    }
}
impl THDims {
    fn new(dims: Vec<usize>) -> Self {
        THDims { dims: dims }
    }
}
impl<T: NumLimits> From<Vec<Vec<Vec<T>>>> for THVec<T> {
    fn from(input: Vec<Vec<Vec<T>>>) -> Self {
        let dims = vec![input.len(), input[0].len(), input[0][0].len()];
        let v = input
            .iter()
            .flat_map(|d| d.iter())
            .flat_map(|d| d.iter())
            .map(|d| *d)
            .collect();
        THVec::new(dims, v)
    }
}
impl<T: NumLimits> From<Vec<Vec<T>>> for THVec<T> {
    fn from(input: Vec<Vec<T>>) -> Self {
        let dims = vec![input.len(), input[0].len()];
        let v = input.iter().flat_map(|d| d.iter()).map(|d| *d).collect();
        THVec::new(dims, v)
    }
}
impl<T: NumLimits> From<Vec<T>> for THVec<T> {
    fn from(input: Vec<T>) -> Self {
        let dims = vec![input.len()];
        THVec::new(dims, input)
    }
}
impl<T: NumLimits> From<T> for THVec<T> {
    fn from(input: T) -> Self {
        let v = vec![input];
        THVec::new(vec![], v)
    }
}
impl<T: NumLimits> From<T> for THVecGeneric {
    fn from(input: T) -> Self {
        let v: Vec<i64> = vec![<i64 as NumCast>::from(input).unwrap()];
        THVecGeneric::new(vec![], v)
    }
}

#[allow(unused_variables)]
impl<T: NumLimits> From<()> for THVec<T> {
    fn from(input: ()) -> Self {
        THVec::new(vec![], vec![])
    }
}
#[allow(unused_variables)]
impl From<()> for THVecGeneric {
    fn from(input: ()) -> Self {
        THVecGeneric::new(vec![], vec![])
    }
}
#[allow(unused_variables)]
impl From<()> for THDims {
    fn from(input: ()) -> Self {
        THDims::new(vec![])
    }
}
impl<T: NumLimits> From<[usize; 4]> for THVec<T> {
    fn from(input: [usize; 4]) -> Self {
        THVec::new(input.to_vec(), vec![])
    }
}
impl<T: NumLimits> From<(usize, usize)> for THVec<T> {
    fn from(input: (usize, usize)) -> Self {
        THVec::new(vec![input.0, input.1], vec![])
    }
}
impl From<(usize, usize)> for THVecGeneric {
    fn from(input: (usize, usize)) -> Self {

        THVecGeneric::new(vec![input.0, input.1], vec![])
    }
}
impl From<(usize)> for THVecGeneric {
    fn from(input: (usize)) -> Self {

        THVecGeneric::new(vec![input], vec![])
    }
}
impl<T: NumLimits> From<(usize)> for THVec<T> {
    fn from(input: (usize)) -> Self {
        THVec::new(vec![input], vec![])
    }
}
impl<T: NumLimits> From<Vec<usize>> for THVec<T> {
    fn from(input: Vec<usize>) -> Self {
        THVec::new(input, vec![])
    }
}
impl From<Vec<usize>> for THVecGeneric {
    fn from(input: Vec<usize>) -> Self {
        THVecGeneric::new(input, vec![])
    }
}
impl From<Vec<usize>> for THDims {
    fn from(input: Vec<usize>) -> Self {
        THDims::new(input)
    }
}
impl<S: NumLimits, D: NumLimits> From<Tensor<S>> for THVec<D> {
    fn from(input: Tensor<S>) -> Self {
        unimplemented!()
    }
}
impl<T: NumLimits> From<Vec<THVec<T>>> for THVec<T> {
    fn from(input: Vec<THVec<T>>) -> Self {
        unimplemented!()
    }
}
impl<S: NumLimits, D: NumLimits> From<Vec<Tensor<S>>> for THVec<D> {
    fn from(input: Vec<Tensor<S>>) -> Self {
        let mut d: Vec<D> = Vec::with_capacity(input.len() * input[0].len());
        let len = input[0].len();
        let mut tmp: Vec<S> = Vec::with_capacity(len);
        for t in &input {
            t.get_storage(&mut tmp);
            for j in 0..len {
                d.push(<D as ::num::NumCast>::from(tmp[j]).unwrap());
            }
        }
        let mut sizes = input[0].size();
        let mut dims = vec![input.len()];
        dims.append(&mut sizes);
        THVec::new(dims, d)
    }
}
impl From<THVecGeneric> for THVec<u8> {
    fn from(input: THVecGeneric) -> Self {
        let data: Vec<u8> = input
            .data
            .iter()
            .map(|t| <u8 as NumCast>::from(*t).unwrap())
            .collect();
        THVec::new(input.dims.clone(), data)
    }
}
impl From<THVecGeneric> for THVec<f32> {
    fn from(input: THVecGeneric) -> Self {
        let data: Vec<f32> = input
            .data
            .iter()
            .map(|t| <f32 as NumCast>::from(*t).unwrap())
            .collect();
        THVec::new(input.dims.clone(), data)
    }
}
impl From<THVecGeneric> for THVec<i64> {
    fn from(input: THVecGeneric) -> Self {
        let data: Vec<i64> = input
            .data
            .iter()
            .map(|t| <i64 as NumCast>::from(*t).unwrap())
            .collect();
        THVec::new(input.dims.clone(), data)
    }
}

impl<T: NumLimits> From<THVec<T>> for THDims {
    fn from(input: THVec<T>) -> Self {
        THDims::new(input.dims.clone())
    }
}
impl From<THVecGeneric> for THDims {
    fn from(input: THVecGeneric) -> Self {
        THDims::new(input.dims.clone())
    }
}

trait TensorNew<T: NumLimits> {
    fn tensor_new(arg: THDims) -> Tensor<T>;
}

impl<T: NumLimits> TensorNew<T> for Tensor<T> {
    #[allow(unused_variables)]
    default fn tensor_new(arg: THDims) -> Tensor<T> {
        unreachable!()
    }
}

impl TensorNew<u8> for Tensor<u8> {
    fn tensor_new(arg: THDims) -> Tensor<u8> {
        let t = ::RcMutNew(::tensor::ByteTensor::with_capacity(arg.dims.as_slice()));
        ::tensor::Tensor { value: t }
    }
}
impl TensorNew<i64> for Tensor<i64> {
    fn tensor_new(arg: THDims) -> Tensor<i64> {
        let t = ::RcMutNew(::tensor::LongTensor::with_capacity(arg.dims.as_slice()));
        ::tensor::Tensor { value: t }
    }
}
impl TensorNew<f32> for Tensor<f32> {
    fn tensor_new(arg: THDims) -> Tensor<f32> {
        let t = ::RcMutNew(::tensor::FloatTensor::with_capacity(arg.dims.as_slice()));
        ::tensor::Tensor { value: t }
    }
}
impl TensorNew<f64> for Tensor<f64> {
    fn tensor_new(arg: THDims) -> Tensor<f64> {
        let t = ::RcMutNew(::tensor::DoubleTensor::with_capacity(arg.dims.as_slice()));
        ::tensor::Tensor { value: t }
    }
}

pub fn byte_tensor<T>(arg: T) -> Tensor<u8>
    where T: Into<THVec<u8>>
{
    tensor(arg)
}
pub fn long_tensor<T>(arg: T) -> Tensor<i64>
    where T: Into<THVec<i64>>
{
    tensor(arg)
}
pub fn float_tensor<T>(arg: T) -> Tensor<f32>
    where T: Into<THVec<f32>>
{
    tensor(arg)
}
pub fn double_tensor<T>(arg: T) -> Tensor<f64>
    where T: Into<THVec<f64>>
{
    tensor(arg)
}
pub fn tensor<S, T>(arg: S) -> Tensor<T>
    where T: NumLimits,
          S: Into<THVec<T>>
{
    let t: THVec<T> = arg.into();
    Tensor::tensor_new(t.into())
}
<|endoftext|>


<commit_before>use bencode::BEncode;
use std::path::PathBuf;
use std::collections::BTreeMap;
use std::{io, fs, fmt, cmp};
use sha1::Sha1;
use util::torrent_name;
use disk;

#[derive(Serialize, Deserialize, Clone)]
pub struct Info {
    pub name: String,
    pub announce: String,
    pub piece_len: u32,
    pub total_len: u64,
    pub hashes: Vec<Vec<u8>>,
    pub hash: [u8; 20],
    pub files: Vec<File>,
}

impl fmt::Debug for Info {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Torrent Info {{ name: {:?}, announce: {:?}, piece_len: {:?}, total_len: {:?}, hash: {:?}, files: {:?} }}",
               self.name, self.announce, self.piece_len, self.total_len, torrent_name(&self.hash), self.files)
    }
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct File {
    pub path: PathBuf,
    pub length: usize,
}

impl File {
    fn from_bencode(data: BEncode) -> Result<File, &'static str> {
        let mut d = data.to_dict().ok_or("File must be a dictionary type!")?;
        match (d.remove("name"), d.remove("path"), d.remove("length")) {
            (Some(v), None, Some(l)) => {
                let f = File {
                    path: PathBuf::from(v.to_string().ok_or("Path must be a valid string.")?),
                    length: l.to_int().ok_or("File length must be a valid int")? as usize,
                };
                Ok(f)
            }
            (None, Some(path), Some(l)) => {
                let mut p = PathBuf::new();
                for dir in path.to_list().ok_or("File path should be a list")? {
                    p.push(dir.to_string().ok_or("File path parts should be strings")?);
                }
                let f = File {
                    path: p,
                    length: l.to_int().ok_or("File length must be a valid int")? as usize,
                };
                Ok(f)
            }
            _ => Err("File dict must contain length and name or path"),
        }
    }

    fn create(&self) -> Result<(), io::Error> {
        if let Some(parent) = self.path.parent() {
            fs::create_dir_all(parent)?;
        }
        let f = fs::OpenOptions::new().write(true).create(true).open(&self.path)?;
        f.set_len(self.length as u64)?;
        Ok(())
    }
}

impl Info {
    pub fn from_bencode(data: BEncode) -> Result<Info, &'static str> {
        data.to_dict()
            .and_then(|mut d| d.remove("info").and_then(|i| i.to_dict()).map(|i| (d, i)))
            .ok_or("")
            .and_then(|(mut d, mut i)| {
                let mut m = Sha1::new();
                let mut info_bytes = Vec::new();
                // TODO: Deal with this error/maybe convert everything to io::Error
                BEncode::Dict(i.clone()).encode(&mut info_bytes).unwrap();
                m.update(&info_bytes);
                let hash = m.digest().bytes();

                let a = d.remove("announce")
                    .and_then(|a| a.to_string())
                    .ok_or("Info must have announce url")?;
                let pl = i.remove("piece length")
                    .and_then(|i| i.to_int())
                    .ok_or("Info must specify piece length")?;
                let hashes = i.remove("pieces")
                    .and_then(|p| p.to_bytes())
                    .map(|mut p| {
                        let mut v = Vec::new();
                        while !p.is_empty() {
                            let remaining = p.split_off(20);
                            v.push(p);
                            p = remaining;
                        }
                        v
                    })
                    .ok_or("Info must provide valid hashes")?;
                let files = parse_bencode_files(i)?;
                let name = if files.is_empty() {
                    files[0].path.clone().into_os_string().into_string().unwrap()
                } else if !files[0].path.has_root() {
                    let mut piter = files[0].path.components();
                    piter.next().unwrap().as_os_str().to_os_string().into_string().unwrap()
                } else {
                    unreachable!();
                };
                let total_len = files.iter().map(|f| f.length as u64).sum();
                Ok(Info {
                    name,
                    announce: a,
                    piece_len: pl as u32,
                    hashes,
                    hash,
                    files,
                    total_len,
                })
            })
    }

    pub fn create_files(&self) -> Result<(), io::Error> {
        for file in self.files.iter() {
            file.create()?;
        }
        Ok(())
    }

    pub fn block_len(&self, idx: u32, offset: u32) -> u32 {
        if idx != self.pieces() - 1 {
            16384
        } else {
            let last_piece_len = (self.total_len - self.piece_len as u64 * (self.pieces() as u64 - 1)) as u32;
            // Note this is not the real last block len, just what it will be IF the offset really
            // is for the last block
            let last_block_len = last_piece_len - offset;
            if offset < last_piece_len && last_block_len <= 16384 {
                last_block_len
            } else {
                16384
            }
        }
    }

    pub fn piece_len(&self, idx: u32) -> u32 {
        if idx != self.pieces() - 1 {
            self.piece_len
        } else {
            (self.total_len - self.piece_len as u64 * (self.pieces() as u64 - 1)) as u32
        }
    }

    pub fn pieces(&self) -> u32 {
        self.hashes.len() as u32
    }

    /// Calculates the file offsets for a given block at index/begin
    pub fn block_disk_locs(&self, index: u32, begin: u32) -> Vec<disk::Location> {
        let len = self.block_len(index, begin);
        self.calc_disk_locs(index, begin, len)
    }

    /// Calculates the file offsets for a given piece at index
    pub fn piece_disk_locs(&self, index: u32) -> Vec<disk::Location> {
        let len = self.piece_len(index);
        self.calc_disk_locs(index, 0, len)
    }

    /// Calculates the file offsets for a given index, begin, and block length.
    fn calc_disk_locs(&self, index: u32, begin: u32, mut len: u32) -> Vec<disk::Location> {
        // The absolute byte offset where we start processing data.
        let mut cur_start = index * self.piece_len as u32 + begin;
        // Current index of the data block we're writing
        let mut data_start = 0;
        // The current file end length.
        let mut fidx = 0;
        // Iterate over all file lengths, if we find any which end a bigger
        // idx than cur_start, write from cur_start..cur_start + file_write_len for that file
        // and continue if we're now at the end of the file.
        let mut locs = Vec::new();
        for f in self.files.iter() {
            fidx += f.length;
            if (cur_start as usize) < fidx {
                let file_write_len = cmp::min(fidx - cur_start as usize, len as usize);
                let offset = (cur_start - (fidx - f.length) as u32) as u64;
                if file_write_len == len as usize {
                    // The file is longer than our len, just write to it,
                    // exit loop
                    locs.push(disk::Location::new(f.path.clone(), offset, data_start, data_start + file_write_len));
                    break;
                } else {
                    // Write to the end of file, continue
                    locs.push(disk::Location::new(f.path.clone(), offset, data_start, data_start + file_write_len as usize));
                    len -= file_write_len as u32;
                    cur_start += file_write_len as u32;
                    data_start += file_write_len;
                }
            }
        }
        locs
    }
}

fn parse_bencode_files(mut data: BTreeMap<String, BEncode>) -> Result<Vec<File>, &'static str> {
    match data.remove("files").and_then(|l| l.to_list()) {
        Some(fs) => {
            let mut path = PathBuf::new();
            path.push(data.remove("name")
                .and_then(|v| v.to_string())
                .ok_or("Multifile mode must have a name field")?);
            let mut files = Vec::new();
            for f in fs {
                let mut file = File::from_bencode(f)?;
                file.path = path.join(file.path);
                files.push(file);
            }
            Ok(files)
        }
        None => File::from_bencode(BEncode::Dict(data)).map(|f| vec![f]),
    }
}
<commit_msg>Add private field to torrent info<commit_after>use bencode::BEncode;
use std::path::PathBuf;
use std::collections::BTreeMap;
use std::{io, fs, fmt, cmp};
use sha1::Sha1;
use util::torrent_name;
use disk;

#[derive(Serialize, Deserialize, Clone)]
pub struct Info {
    pub name: String,
    pub announce: String,
    pub piece_len: u32,
    pub total_len: u64,
    pub hashes: Vec<Vec<u8>>,
    pub hash: [u8; 20],
    pub files: Vec<File>,
    pub private: bool,
}

impl fmt::Debug for Info {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Torrent Info {{ name: {:?}, announce: {:?}, piece_len: {:?}, total_len: {:?}, hash: {:?}, files: {:?} }}",
               self.name, self.announce, self.piece_len, self.total_len, torrent_name(&self.hash), self.files)
    }
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct File {
    pub path: PathBuf,
    pub length: usize,
}

impl File {
    fn from_bencode(data: BEncode) -> Result<File, &'static str> {
        let mut d = data.to_dict().ok_or("File must be a dictionary type!")?;
        match (d.remove("name"), d.remove("path"), d.remove("length")) {
            (Some(v), None, Some(l)) => {
                let f = File {
                    path: PathBuf::from(v.to_string().ok_or("Path must be a valid string.")?),
                    length: l.to_int().ok_or("File length must be a valid int")? as usize,
                };
                Ok(f)
            }
            (None, Some(path), Some(l)) => {
                let mut p = PathBuf::new();
                for dir in path.to_list().ok_or("File path should be a list")? {
                    p.push(dir.to_string().ok_or("File path parts should be strings")?);
                }
                let f = File {
                    path: p,
                    length: l.to_int().ok_or("File length must be a valid int")? as usize,
                };
                Ok(f)
            }
            _ => Err("File dict must contain length and name or path"),
        }
    }

    fn create(&self) -> Result<(), io::Error> {
        if let Some(parent) = self.path.parent() {
            fs::create_dir_all(parent)?;
        }
        let f = fs::OpenOptions::new().write(true).create(true).open(&self.path)?;
        f.set_len(self.length as u64)?;
        Ok(())
    }
}

impl Info {
    pub fn from_bencode(data: BEncode) -> Result<Info, &'static str> {
        data.to_dict()
            .and_then(|mut d| d.remove("info").and_then(|i| i.to_dict()).map(|i| (d, i)))
            .ok_or("")
            .and_then(|(mut d, mut i)| {
                let mut m = Sha1::new();
                let mut info_bytes = Vec::new();
                // TODO: Deal with this error/maybe convert everything to io::Error
                BEncode::Dict(i.clone()).encode(&mut info_bytes).unwrap();
                m.update(&info_bytes);
                let hash = m.digest().bytes();

                let a = d.remove("announce")
                    .and_then(|a| a.to_string())
                    .ok_or("Info must have announce url")?;
                let pl = i.remove("piece length")
                    .and_then(|i| i.to_int())
                    .ok_or("Info must specify piece length")?;
                let hashes = i.remove("pieces")
                    .and_then(|p| p.to_bytes())
                    .map(|mut p| {
                        let mut v = Vec::new();
                        while !p.is_empty() {
                            let remaining = p.split_off(20);
                            v.push(p);
                            p = remaining;
                        }
                        v
                    })
                    .ok_or("Info must provide valid hashes")?;

                let private = i.remove("private")
                    .and_then(|v| v.to_int())
                    .map(|p| p == 1)
                    .unwrap_or(false);

                let files = parse_bencode_files(i)?;
                let name = if files.is_empty() {
                    files[0].path.clone().into_os_string().into_string().unwrap()
                } else if !files[0].path.has_root() {
                    let mut piter = files[0].path.components();
                    piter.next().unwrap().as_os_str().to_os_string().into_string().unwrap()
                } else {
                    unreachable!();
                };

                let total_len = files.iter().map(|f| f.length as u64).sum();
                Ok(Info {
                    name,
                    announce: a,
                    piece_len: pl as u32,
                    hashes,
                    hash,
                    files,
                    total_len,
                    private,
                })
            })
    }

    pub fn create_files(&self) -> Result<(), io::Error> {
        for file in self.files.iter() {
            file.create()?;
        }
        Ok(())
    }

    pub fn block_len(&self, idx: u32, offset: u32) -> u32 {
        if idx != self.pieces() - 1 {
            16384
        } else {
            let last_piece_len = (self.total_len - self.piece_len as u64 * (self.pieces() as u64 - 1)) as u32;
            // Note this is not the real last block len, just what it will be IF the offset really
            // is for the last block
            let last_block_len = last_piece_len - offset;
            if offset < last_piece_len && last_block_len <= 16384 {
                last_block_len
            } else {
                16384
            }
        }
    }

    pub fn piece_len(&self, idx: u32) -> u32 {
        if idx != self.pieces() - 1 {
            self.piece_len
        } else {
            (self.total_len - self.piece_len as u64 * (self.pieces() as u64 - 1)) as u32
        }
    }

    pub fn pieces(&self) -> u32 {
        self.hashes.len() as u32
    }

    /// Calculates the file offsets for a given block at index/begin
    pub fn block_disk_locs(&self, index: u32, begin: u32) -> Vec<disk::Location> {
        let len = self.block_len(index, begin);
        self.calc_disk_locs(index, begin, len)
    }

    /// Calculates the file offsets for a given piece at index
    pub fn piece_disk_locs(&self, index: u32) -> Vec<disk::Location> {
        let len = self.piece_len(index);
        self.calc_disk_locs(index, 0, len)
    }

    /// Calculates the file offsets for a given index, begin, and block length.
    fn calc_disk_locs(&self, index: u32, begin: u32, mut len: u32) -> Vec<disk::Location> {
        // The absolute byte offset where we start processing data.
        let mut cur_start = index * self.piece_len as u32 + begin;
        // Current index of the data block we're writing
        let mut data_start = 0;
        // The current file end length.
        let mut fidx = 0;
        // Iterate over all file lengths, if we find any which end a bigger
        // idx than cur_start, write from cur_start..cur_start + file_write_len for that file
        // and continue if we're now at the end of the file.
        let mut locs = Vec::new();
        for f in self.files.iter() {
            fidx += f.length;
            if (cur_start as usize) < fidx {
                let file_write_len = cmp::min(fidx - cur_start as usize, len as usize);
                let offset = (cur_start - (fidx - f.length) as u32) as u64;
                if file_write_len == len as usize {
                    // The file is longer than our len, just write to it,
                    // exit loop
                    locs.push(disk::Location::new(f.path.clone(), offset, data_start, data_start + file_write_len));
                    break;
                } else {
                    // Write to the end of file, continue
                    locs.push(disk::Location::new(f.path.clone(), offset, data_start, data_start + file_write_len as usize));
                    len -= file_write_len as u32;
                    cur_start += file_write_len as u32;
                    data_start += file_write_len;
                }
            }
        }
        locs
    }
}

fn parse_bencode_files(mut data: BTreeMap<String, BEncode>) -> Result<Vec<File>, &'static str> {
    match data.remove("files").and_then(|l| l.to_list()) {
        Some(fs) => {
            let mut path = PathBuf::new();
            path.push(data.remove("name")
                .and_then(|v| v.to_string())
                .ok_or("Multifile mode must have a name field")?);
            let mut files = Vec::new();
            for f in fs {
                let mut file = File::from_bencode(f)?;
                file.path = path.join(file.path);
                files.push(file);
            }
            Ok(files)
        }
        None => File::from_bencode(BEncode::Dict(data)).map(|f| vec![f]),
    }
}
<|endoftext|>