<commit_before>#[macro_use(s)] extern crate ndarray;
extern crate num as libnum;

use ndarray::RcArray;
use ndarray::{arr0, rcarr1, rcarr2};
use ndarray::{
    OwnedArray,
    Ix,
};

use std::fmt;
use libnum::Float;

fn test_oper(op: &str, a: &[f32], b: &[f32], c: &[f32])
{
    let aa = rcarr1(a);
    let bb = rcarr1(b);
    let cc = rcarr1(c);
    test_oper_arr(op, aa.clone(), bb.clone(), cc.clone());
    let dim = (2, 2);
    let aa = aa.reshape(dim);
    let bb = bb.reshape(dim);
    let cc = cc.reshape(dim);
    test_oper_arr(op, aa.clone(), bb.clone(), cc.clone());
    let dim = (1, 2, 1, 2);
    let aa = aa.reshape(dim);
    let bb = bb.reshape(dim);
    let cc = cc.reshape(dim);
    test_oper_arr(op, aa.clone(), bb.clone(), cc.clone());
}

fn test_oper_arr<A: Float + fmt::Debug, D: ndarray::Dimension>
    (op: &str, mut aa: RcArray<A,D>, bb: RcArray<A, D>, cc: RcArray<A, D>)
{
    match op {
        "+" => {
            assert_eq!(&aa + &bb, cc);
            aa.iadd(&bb);
            assert_eq!(aa, cc);
        },
        "-" => {
            assert_eq!(&aa - &bb, cc);
            aa.isub(&bb);
            assert_eq!(aa, cc);
        },
        "*" => {
            assert_eq!(&aa * &bb, cc);
            aa.imul(&bb);
            assert_eq!(aa, cc);
        },
        "/" => {
            assert_eq!(&aa / &bb, cc);
            aa.idiv(&bb);
            assert_eq!(aa, cc);
        },
        "%" => {
            assert_eq!(&aa % &bb, cc);
            aa.irem(&bb);
            assert_eq!(aa, cc);
        },
        "neg" => {
            assert_eq!(-aa.clone(), cc);
            aa.ineg();
            assert_eq!(aa, cc);
        },
        _ => panic!()
    }
}

#[test]
fn operations()
{
    test_oper("+", &[1.0,2.0,3.0,4.0], &[0.0, 1.0, 2.0, 3.0], &[1.0,3.0,5.0,7.0]);
    test_oper("-", &[1.0,2.0,3.0,4.0], &[0.0, 1.0, 2.0, 3.0], &[1.0,1.0,1.0,1.0]);
    test_oper("*", &[1.0,2.0,3.0,4.0], &[0.0, 1.0, 2.0, 3.0], &[0.0,2.0,6.0,12.0]);
    test_oper("/", &[1.0,2.0,3.0,4.0], &[1.0, 1.0, 2.0, 3.0], &[1.0,2.0,3.0/2.0,4.0/3.0]);
    test_oper("%", &[1.0,2.0,3.0,4.0], &[1.0, 1.0, 2.0, 3.0], &[0.0,0.0,1.0,1.0]);
    test_oper("neg", &[1.0,2.0,3.0,4.0], &[1.0, 1.0, 2.0, 3.0], &[-1.0,-2.0,-3.0,-4.0]);
}

#[test]
fn scalar_operations()
{
    let a = arr0::<f32>(1.);
    let b = rcarr1::<f32>(&[1., 1.]);
    let c = rcarr2(&[[1., 1.], [1., 1.]]);

    {
        let mut x = a.clone();
        let mut y = arr0(0.);
        x.iadd_scalar(&1.);
        y.assign_scalar(&2.);
        assert_eq!(x, a + arr0(1.));
        assert_eq!(x, y);
    }

    {
        let mut x = b.clone();
        let mut y = rcarr1(&[0., 0.]);
        x.iadd_scalar(&1.);
        y.assign_scalar(&2.);
        assert_eq!(x, b + arr0(1.));
        assert_eq!(x, y);
    }

    {
        let mut x = c.clone();
        let mut y = RcArray::zeros((2, 2));
        x.iadd_scalar(&1.);
        y.assign_scalar(&2.);
        assert_eq!(x, c + arr0(1.));
        assert_eq!(x, y);
    }
}

fn assert_approx_eq<F: fmt::Debug + Float>(f: F, g: F, tol: F) -> bool {
    assert!((f - g).abs() <= tol, "{:?} approx== {:?} (tol={:?})",
            f, g, tol);
    true
}

#[test]
fn dot_product() {
    let a = OwnedArray::range(0., 69., 1.);
    let b = &a * 2. - 7.;
    let dot = 197846.;
    assert_approx_eq(a.dot(&b), dot, 1e-5);
    let a = a.map(|f| *f as f32);
    let b = b.map(|f| *f as f32);
    assert_approx_eq(a.dot(&b), dot as f32, 1e-5);
    let a = a.map(|f| *f as i32);
    let b = b.map(|f| *f as i32);
    assert_eq!(a.dot(&b), dot as i32);
}

fn range_mat(m: Ix, n: Ix) -> OwnedArray<f32, (Ix, Ix)> {
    OwnedArray::linspace(0., (m * n - 1) as f32, m * n).into_shape((m, n)).unwrap()
}

#[cfg(has_assign)]
#[test]
fn mat_mul() {
    let (m, n, k) = (8, 8, 8);
    let a = range_mat(m, n);
    let b = range_mat(n, k);
    let mut b = b / 4.;
    {
        let mut c = b.column_mut(0);
        c += 1.0;
    }
    let ab = a.mat_mul(&b);

    let mut af = OwnedArray::zeros_f(a.dim());
    let mut bf = OwnedArray::zeros_f(b.dim());
    af.assign(&a);
    bf.assign(&b);

    assert_eq!(ab, a.mat_mul(&bf));
    assert_eq!(ab, af.mat_mul(&b));
    assert_eq!(ab, af.mat_mul(&bf));

    let (m, n, k) = (10, 5, 11);
    let a = range_mat(m, n);
    let b = range_mat(n, k);
    let mut b = b / 4.;
    {
        let mut c = b.column_mut(0);
        c += 1.0;
    }
    let ab = a.mat_mul(&b);

    let mut af = OwnedArray::zeros_f(a.dim());
    let mut bf = OwnedArray::zeros_f(b.dim());
    af.assign(&a);
    bf.assign(&b);

    assert_eq!(ab, a.mat_mul(&bf));
    assert_eq!(ab, af.mat_mul(&b));
    assert_eq!(ab, af.mat_mul(&bf));

    let (m, n, k) = (10, 8, 1);
    let a = range_mat(m, n);
    let b = range_mat(n, k);
    let mut b = b / 4.;
    {
        let mut c = b.column_mut(0);
        c += 1.0;
    }
    let ab = a.mat_mul(&b);

    let mut af = OwnedArray::zeros_f(a.dim());
    let mut bf = OwnedArray::zeros_f(b.dim());
    af.assign(&a);
    bf.assign(&b);

    assert_eq!(ab, a.mat_mul(&bf));
    assert_eq!(ab, af.mat_mul(&b));
    assert_eq!(ab, af.mat_mul(&bf));
}

// Check that matrix multiplication of contiguous matrices returns a
// matrix with the same order
#[test]
fn mat_mul_order() {
    let (m, n, k) = (8, 8, 8);
    let a = range_mat(m, n);
    let b = range_mat(n, k);
    let mut af = OwnedArray::zeros_f(a.dim());
    let mut bf = OwnedArray::zeros_f(b.dim());
    af.assign(&a);
    bf.assign(&b);

    let cc = a.mat_mul(&b);
    let ff = af.mat_mul(&bf);

    assert_eq!(cc.strides()[1], 1);
    assert_eq!(ff.strides()[0], 1);
}

// Check that matrix multiplication
// supports broadcast arrays.
#[test]
fn mat_mul_broadcast() {
    let (m, n, k) = (16, 16, 16);
    let a = range_mat(m, n);
    let x1 = 1.;
    let x = OwnedArray::from_vec(vec![x1]);
    let b0 = x.broadcast((n, k)).unwrap();
    let b1 = OwnedArray::from_elem(n, x1);
    let b1 = b1.broadcast((n, k)).unwrap();
    let b2 = OwnedArray::from_elem((n, k), x1);

    let c2 = a.mat_mul(&b2);
    let c1 = a.mat_mul(&b1);
    let c0 = a.mat_mul(&b0);
    assert_eq!(c2, c1);
    assert_eq!(c2, c0);
}

// Check that matrix multiplication supports reversed axes
#[test]
fn mat_mul_rev() {
    let (m, n, k) = (16, 16, 16);
    let a = range_mat(m, n);
    let b = range_mat(n, k);
    let mut rev = OwnedArray::zeros(b.dim());
    let mut rev = rev.slice_mut(s![..;-1, ..]);
    rev.assign(&b);
    println!("{:.?}", rev);

    let c1 = a.mat_mul(&b);
    let c2 = a.mat_mul(&rev);
    assert_eq!(c1, c2);
}

#[test]
fn scaled_add() {
    let a = range_mat(16, 15);
    let mut b = range_mat(16, 15);
    b.mapv_inplace(f32::exp);

    let alpha = 0.2_f32;
    let mut c = a.clone();
    c.scaled_add(alpha, &b);

    let d = alpha * &b + &a;
    assert_eq!(c, d);

}
<commit_msg>Add dot tests of different alignments<commit_after>#[macro_use(s)] extern crate ndarray;
extern crate num as libnum;

use ndarray::RcArray;
use ndarray::{arr0, rcarr1, rcarr2};
use ndarray::{
    OwnedArray,
    Ix, Ixs,
    AsArray,
    NdFloat,
};

use std::fmt;
use libnum::Float;

fn test_oper(op: &str, a: &[f32], b: &[f32], c: &[f32])
{
    let aa = rcarr1(a);
    let bb = rcarr1(b);
    let cc = rcarr1(c);
    test_oper_arr(op, aa.clone(), bb.clone(), cc.clone());
    let dim = (2, 2);
    let aa = aa.reshape(dim);
    let bb = bb.reshape(dim);
    let cc = cc.reshape(dim);
    test_oper_arr(op, aa.clone(), bb.clone(), cc.clone());
    let dim = (1, 2, 1, 2);
    let aa = aa.reshape(dim);
    let bb = bb.reshape(dim);
    let cc = cc.reshape(dim);
    test_oper_arr(op, aa.clone(), bb.clone(), cc.clone());
}

fn test_oper_arr<A: Float + fmt::Debug, D: ndarray::Dimension>
    (op: &str, mut aa: RcArray<A,D>, bb: RcArray<A, D>, cc: RcArray<A, D>)
{
    match op {
        "+" => {
            assert_eq!(&aa + &bb, cc);
            aa.iadd(&bb);
            assert_eq!(aa, cc);
        },
        "-" => {
            assert_eq!(&aa - &bb, cc);
            aa.isub(&bb);
            assert_eq!(aa, cc);
        },
        "*" => {
            assert_eq!(&aa * &bb, cc);
            aa.imul(&bb);
            assert_eq!(aa, cc);
        },
        "/" => {
            assert_eq!(&aa / &bb, cc);
            aa.idiv(&bb);
            assert_eq!(aa, cc);
        },
        "%" => {
            assert_eq!(&aa % &bb, cc);
            aa.irem(&bb);
            assert_eq!(aa, cc);
        },
        "neg" => {
            assert_eq!(-aa.clone(), cc);
            aa.ineg();
            assert_eq!(aa, cc);
        },
        _ => panic!()
    }
}

#[test]
fn operations()
{
    test_oper("+", &[1.0,2.0,3.0,4.0], &[0.0, 1.0, 2.0, 3.0], &[1.0,3.0,5.0,7.0]);
    test_oper("-", &[1.0,2.0,3.0,4.0], &[0.0, 1.0, 2.0, 3.0], &[1.0,1.0,1.0,1.0]);
    test_oper("*", &[1.0,2.0,3.0,4.0], &[0.0, 1.0, 2.0, 3.0], &[0.0,2.0,6.0,12.0]);
    test_oper("/", &[1.0,2.0,3.0,4.0], &[1.0, 1.0, 2.0, 3.0], &[1.0,2.0,3.0/2.0,4.0/3.0]);
    test_oper("%", &[1.0,2.0,3.0,4.0], &[1.0, 1.0, 2.0, 3.0], &[0.0,0.0,1.0,1.0]);
    test_oper("neg", &[1.0,2.0,3.0,4.0], &[1.0, 1.0, 2.0, 3.0], &[-1.0,-2.0,-3.0,-4.0]);
}

#[test]
fn scalar_operations()
{
    let a = arr0::<f32>(1.);
    let b = rcarr1::<f32>(&[1., 1.]);
    let c = rcarr2(&[[1., 1.], [1., 1.]]);

    {
        let mut x = a.clone();
        let mut y = arr0(0.);
        x.iadd_scalar(&1.);
        y.assign_scalar(&2.);
        assert_eq!(x, a + arr0(1.));
        assert_eq!(x, y);
    }

    {
        let mut x = b.clone();
        let mut y = rcarr1(&[0., 0.]);
        x.iadd_scalar(&1.);
        y.assign_scalar(&2.);
        assert_eq!(x, b + arr0(1.));
        assert_eq!(x, y);
    }

    {
        let mut x = c.clone();
        let mut y = RcArray::zeros((2, 2));
        x.iadd_scalar(&1.);
        y.assign_scalar(&2.);
        assert_eq!(x, c + arr0(1.));
        assert_eq!(x, y);
    }
}

fn assert_approx_eq<F: fmt::Debug + Float>(f: F, g: F, tol: F) -> bool {
    assert!((f - g).abs() <= tol, "{:?} approx== {:?} (tol={:?})",
            f, g, tol);
    true
}

fn reference_dot<'a,A, V1, V2>(a: V1, b: V2) -> A
    where A: NdFloat,
          V1: AsArray<'a, A>,
          V2: AsArray<'a, A>,
{
    let a = a.into();
    let b = b.into();
    a.iter().zip(b.iter()).fold(A::zero(), |acc, (&x, &y)| {
        acc + x * y
    })
}

#[test]
fn dot_product() {
    let a = OwnedArray::range(0., 69., 1.);
    let b = &a * 2. - 7.;
    let dot = 197846.;
    assert_approx_eq(a.dot(&b), reference_dot(&a, &b), 1e-5);

    // test different alignments
    let max = 8 as Ixs;
    for i in 1..max {
        let a1 = a.slice(s![i..]);
        let b1 = b.slice(s![i..]);
        assert_approx_eq(a1.dot(&b1), reference_dot(&a1, &b1), 1e-5);
        let a2 = a.slice(s![..-i]);
        let b2 = b.slice(s![i..]);
        assert_approx_eq(a2.dot(&b2), reference_dot(&a2, &b2), 1e-5);
    }

    let a = a.map(|f| *f as f32);
    let b = b.map(|f| *f as f32);
    assert_approx_eq(a.dot(&b), dot as f32, 1e-5);

    let max = 8 as Ixs;
    for i in 1..max {
        let a1 = a.slice(s![i..]);
        let b1 = b.slice(s![i..]);
        assert_approx_eq(a1.dot(&b1), reference_dot(&a1, &b1), 1e-5);
        let a2 = a.slice(s![..-i]);
        let b2 = b.slice(s![i..]);
        assert_approx_eq(a2.dot(&b2), reference_dot(&a2, &b2), 1e-5);
    }

    let a = a.map(|f| *f as i32);
    let b = b.map(|f| *f as i32);
    assert_eq!(a.dot(&b), dot as i32);
}

fn range_mat(m: Ix, n: Ix) -> OwnedArray<f32, (Ix, Ix)> {
    OwnedArray::linspace(0., (m * n - 1) as f32, m * n).into_shape((m, n)).unwrap()
}

#[cfg(has_assign)]
#[test]
fn mat_mul() {
    let (m, n, k) = (8, 8, 8);
    let a = range_mat(m, n);
    let b = range_mat(n, k);
    let mut b = b / 4.;
    {
        let mut c = b.column_mut(0);
        c += 1.0;
    }
    let ab = a.mat_mul(&b);

    let mut af = OwnedArray::zeros_f(a.dim());
    let mut bf = OwnedArray::zeros_f(b.dim());
    af.assign(&a);
    bf.assign(&b);

    assert_eq!(ab, a.mat_mul(&bf));
    assert_eq!(ab, af.mat_mul(&b));
    assert_eq!(ab, af.mat_mul(&bf));

    let (m, n, k) = (10, 5, 11);
    let a = range_mat(m, n);
    let b = range_mat(n, k);
    let mut b = b / 4.;
    {
        let mut c = b.column_mut(0);
        c += 1.0;
    }
    let ab = a.mat_mul(&b);

    let mut af = OwnedArray::zeros_f(a.dim());
    let mut bf = OwnedArray::zeros_f(b.dim());
    af.assign(&a);
    bf.assign(&b);

    assert_eq!(ab, a.mat_mul(&bf));
    assert_eq!(ab, af.mat_mul(&b));
    assert_eq!(ab, af.mat_mul(&bf));

    let (m, n, k) = (10, 8, 1);
    let a = range_mat(m, n);
    let b = range_mat(n, k);
    let mut b = b / 4.;
    {
        let mut c = b.column_mut(0);
        c += 1.0;
    }
    let ab = a.mat_mul(&b);

    let mut af = OwnedArray::zeros_f(a.dim());
    let mut bf = OwnedArray::zeros_f(b.dim());
    af.assign(&a);
    bf.assign(&b);

    assert_eq!(ab, a.mat_mul(&bf));
    assert_eq!(ab, af.mat_mul(&b));
    assert_eq!(ab, af.mat_mul(&bf));
}

// Check that matrix multiplication of contiguous matrices returns a
// matrix with the same order
#[test]
fn mat_mul_order() {
    let (m, n, k) = (8, 8, 8);
    let a = range_mat(m, n);
    let b = range_mat(n, k);
    let mut af = OwnedArray::zeros_f(a.dim());
    let mut bf = OwnedArray::zeros_f(b.dim());
    af.assign(&a);
    bf.assign(&b);

    let cc = a.mat_mul(&b);
    let ff = af.mat_mul(&bf);

    assert_eq!(cc.strides()[1], 1);
    assert_eq!(ff.strides()[0], 1);
}

// Check that matrix multiplication
// supports broadcast arrays.
#[test]
fn mat_mul_broadcast() {
    let (m, n, k) = (16, 16, 16);
    let a = range_mat(m, n);
    let x1 = 1.;
    let x = OwnedArray::from_vec(vec![x1]);
    let b0 = x.broadcast((n, k)).unwrap();
    let b1 = OwnedArray::from_elem(n, x1);
    let b1 = b1.broadcast((n, k)).unwrap();
    let b2 = OwnedArray::from_elem((n, k), x1);

    let c2 = a.mat_mul(&b2);
    let c1 = a.mat_mul(&b1);
    let c0 = a.mat_mul(&b0);
    assert_eq!(c2, c1);
    assert_eq!(c2, c0);
}

// Check that matrix multiplication supports reversed axes
#[test]
fn mat_mul_rev() {
    let (m, n, k) = (16, 16, 16);
    let a = range_mat(m, n);
    let b = range_mat(n, k);
    let mut rev = OwnedArray::zeros(b.dim());
    let mut rev = rev.slice_mut(s![..;-1, ..]);
    rev.assign(&b);
    println!("{:.?}", rev);

    let c1 = a.mat_mul(&b);
    let c2 = a.mat_mul(&rev);
    assert_eq!(c1, c2);
}

#[test]
fn scaled_add() {
    let a = range_mat(16, 15);
    let mut b = range_mat(16, 15);
    b.mapv_inplace(f32::exp);

    let alpha = 0.2_f32;
    let mut c = a.clone();
    c.scaled_add(alpha, &b);

    let d = alpha * &b + &a;
    assert_eq!(c, d);

}
<|endoftext|>


<commit_before>extern crate tempfile;
use tempfile::TempFile;
use std::io::{Write, Read, Seek, SeekFrom};

#[test]
fn test_basic() {
    let mut tmpfile = TempFile::new_in("/tmp").unwrap();
    write!(tmpfile, "abcde").unwrap();
    tmpfile.seek(SeekFrom::Start(0)).unwrap();
    let mut buf = String::new();
    tmpfile.read_to_string(&mut buf).unwrap();
    assert_eq!("abcde", buf);
}

#[test]
fn test_share() {
    let mut tmpfile = TempFile::new_in("/tmp").unwrap();
    write!(tmpfile, "abcde").unwrap();
    let mut shared = tmpfile.share().unwrap();
    let mut buf = String::new();
    shared.read_to_string(&mut buf).unwrap();
    assert_eq!("abcde", buf);
}
<commit_msg>Don't assume unix in tests.<commit_after>extern crate tempfile;
use tempfile::TempFile;
use std::io::{Write, Read, Seek, SeekFrom};

#[test]
fn test_basic() {
    let mut tmpfile = TempFile::new().unwrap();
    write!(tmpfile, "abcde").unwrap();
    tmpfile.seek(SeekFrom::Start(0)).unwrap();
    let mut buf = String::new();
    tmpfile.read_to_string(&mut buf).unwrap();
    assert_eq!("abcde", buf);
}

#[test]
fn test_share() {
    let mut tmpfile = TempFile::new().unwrap();
    write!(tmpfile, "abcde").unwrap();
    let mut shared = tmpfile.share().unwrap();
    let mut buf = String::new();
    shared.read_to_string(&mut buf).unwrap();
    assert_eq!("abcde", buf);
}
<|endoftext|>


<commit_before>use std::{f32, f64};

#[macro_use]
extern crate quote;

struct X;

impl quote::ToTokens for X {
    fn to_tokens(&self, tokens: &mut quote::Tokens) {
        tokens.append("X");
    }
}

#[test]
fn test_quote_impl() {
    let tokens = quote!(
        impl<'a, T: ToTokens> ToTokens for &'a T {
            fn to_tokens(&self, tokens: &mut Tokens) {
                (**self).to_tokens(tokens)
            }
        }
    );

    let expected = concat!(
        "impl < 'a , T : ToTokens > ToTokens for & 'a T { ",
            "fn to_tokens ( & self , tokens : & mut Tokens ) { ",
                "( * * self ) . to_tokens ( tokens ) ",
            "} ",
        "}"
    );

    assert_eq!(expected, tokens.to_string());
}

#[test]
fn test_substitution() {
    let x = X;
    let tokens = quote!(#x <#x> (#x) [#x] {#x});

    let expected = "X < X > ( X ) [ X ] { X }";

    assert_eq!(expected, tokens.to_string());
}

#[test]
fn test_iter() {
    let primes = &[X, X, X, X];

    assert_eq!("X X X X", quote!(#(#primes)*).to_string());

    assert_eq!("X , X , X , X ,", quote!(#(#primes,)*).to_string());

    assert_eq!("X , X , X , X", quote!(#(#primes),*).to_string());
}

#[test]
fn test_advanced() {
    let generics = quote!( <'a, T> );

    let where_clause = quote!( where T: Serialize );

    let field_ty = quote!( String );

    let item_ty = quote!( Cow<'a, str> );

    let path = quote!( SomeTrait::serialize_with );

    let value = quote!( self.x );

    let tokens = quote! {
        struct SerializeWith #generics #where_clause {
            value: &'a #field_ty,
            phantom: ::std::marker::PhantomData<#item_ty>,
        }

        impl #generics ::serde::Serialize for SerializeWith #generics #where_clause {
            fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error>
                where S: ::serde::Serializer
            {
                #path(self.value, s)
            }
        }

        SerializeWith {
            value: #value,
            phantom: ::std::marker::PhantomData::<#item_ty>,
        }
    };

    let expected = concat!(
        "struct SerializeWith < 'a , T > where T : Serialize { ",
            "value : & 'a String , ",
            "phantom : :: std :: marker :: PhantomData < Cow < 'a , str > > , ",
        "} ",
        "impl < 'a , T > :: serde :: Serialize for SerializeWith < 'a , T > where T : Serialize { ",
            "fn serialize < S > ( & self , s : & mut S ) -> Result < ( ) , S :: Error > ",
                "where S : :: serde :: Serializer ",
            "{ ",
                "SomeTrait :: serialize_with ( self . value , s ) ",
            "} ",
        "} ",
        "SerializeWith { ",
            "value : self . x , ",
            "phantom : :: std :: marker :: PhantomData :: < Cow < 'a , str > > , ",
        "}"
    );

    assert_eq!(expected, tokens.to_string());
}

#[test]
fn test_tuple() {
    let x = ("foo", 4_u32);
    let tokens = quote!(#x);
    let expected = "( \"foo\" , 4u32 , )";
    assert_eq!(expected, tokens.to_string());
}

#[test]
fn test_array() {
    let x: [u32; 3] = [1, 2, 3];
    let tokens = quote!(#x);
    let expected = "[ 1u32 , 2u32 , 3u32 , ]";
    assert_eq!(expected, tokens.to_string());
}

#[test]
fn test_slice() {
    let x: &[u32] = &[1, 2, 3];
    let tokens = quote!(&#x);  // Note: explicit `&`
    let expected = "& [ 1u32 , 2u32 , 3u32 , ]";
    assert_eq!(expected, tokens.to_string());
}

#[test]
fn test_vec() {
    let x: Vec<u32> = vec![1, 2, 3];
    let tokens = quote!(vec!#x);  // Note: explicit `vec!`
    let expected = "vec ! [ 1u32 , 2u32 , 3u32 , ]";
    assert_eq!(expected, tokens.to_string());
}

#[test]
fn test_integer() {
    let ii8 = -1i8;
    let ii16 = -1i16;
    let ii32 = -1i32;
    let ii64 = -1i64;
    let iisize = -1isize;
    let uu8 = 1u8;
    let uu16 = 1u16;
    let uu32 = 1u32;
    let uu64 = 1u64;
    let uusize = 1usize;

    let tokens = quote! {
        #ii8 #ii16 #ii32 #ii64 #iisize
        #uu8 #uu16 #uu32 #uu64 #uusize
    };
    let expected = "-1i8 -1i16 -1i32 -1i64 -1isize 1u8 1u16 1u32 1u64 1usize";
    assert_eq!(expected, tokens.to_string());
}

#[test]
fn test_hex() {
    let hex = quote::Hex(0xFFFF_0000_u32);
    let tokens = quote!(#hex);
    let expected = "0xFFFF0000u32";
    assert_eq!(expected, tokens.to_string());
}

#[test]
fn test_floating() {
    let e32 = 2.71828f32;
    let nan32 = f32::NAN;
    let inf32 = f32::INFINITY;
    let neginf32 = f32::NEG_INFINITY;

    let e64 = 2.71828f64;
    let nan64 = f64::NAN;
    let inf64 = f64::INFINITY;
    let neginf64 = f64::NEG_INFINITY;

    let tokens = quote! {
        #e32 @ #nan32 @ #inf32 @ #neginf32
        #e64 @ #nan64 @ #inf64 @ #neginf64
    };
    let expected = concat!(
        "2.71828f32 @ :: std :: f32 :: NAN @ :: std :: f32 :: INFINITY @ :: std :: f32 :: NEG_INFINITY ",
        "2.71828f64 @ :: std :: f64 :: NAN @ :: std :: f64 :: INFINITY @ :: std :: f64 :: NEG_INFINITY",
    );
    assert_eq!(expected, tokens.to_string());
}

#[test]
fn test_char() {
    let zero = '\0';
    let pound = '#';
    let quote = '"';
    let apost = '\'';
    let newline = '\n';
    let heart = '\u{2764}';

    let tokens = quote! {
        #zero #pound #quote #apost #newline #heart
    };
    let expected = "'\\0' '#' '\"' '\\'' '\\n' '\u{2764}'";
    assert_eq!(expected, tokens.to_string());
}

#[test]
fn test_str() {
    let s = "\0 a 'b \" c";
    let tokens = quote!(#s);
    let expected = "\"\\0 a 'b \\\" c\"";
    assert_eq!(expected, tokens.to_string());
}

#[test]
fn test_string() {
    let s = "\0 a 'b \" c".to_string();
    let tokens = quote!(#s);
    let expected = "\"\\0 a 'b \\\" c\"";
    assert_eq!(expected, tokens.to_string());
}

#[test]
fn test_byte_str() {
    let s = quote::ByteStr("\0 a 'b \" c");
    let tokens = quote!(#s);
    let expected = "b\"\\0 a 'b \\\" c\"";
    assert_eq!(expected, tokens.to_string());
}

#[test]
fn test_ident() {
    let foo = quote::Ident::from("Foo");
    let bar = quote::Ident::from(format!("Bar{}", 7));
    let tokens = quote!(struct #foo; enum #bar {});
    let expected = "struct Foo ; enum Bar7 { }";
    assert_eq!(expected, tokens.to_string());
}

#[test]
fn test_duplicate() {
    let ch = 'x';

    let tokens = quote!(#ch #ch);

    let expected = "'x' 'x'";
    assert_eq!(expected, tokens.to_string());
}

#[test]
fn test_fancy_repetition() {
    let foo = vec!["a", "b"];
    let bar = vec![true, false];

    let tokens = quote! {
        #(#foo: #bar),*
    };

    let expected = r#""a" : true , "b" : false"#;
    assert_eq!(expected, tokens.to_string());
}

#[test]
fn test_nested_fancy_repetition() {
    let nested = vec![vec!['a', 'b', 'c'], vec!['x', 'y', 'z']];

    let tokens = quote! {
        #(
            #(#nested)*
        ),*
    };

    let expected = "'a' 'b' 'c' , 'x' 'y' 'z'";
    assert_eq!(expected, tokens.to_string());
}

#[test]
fn test_empty_repetition() {
    let tokens = quote!(#(a b)* #(c d),*);
    assert_eq!("", tokens.to_string());
}

#[test]
fn test_variable_name_conflict() {
    // The implementation of `#(...),*` uses the variable `_i` but it should be
    // fine, if a little confusing when debugging.
    let _i = vec!['a', 'b'];
    let tokens = quote! { #(#_i),* };
    let expected = "'a' , 'b'";
    assert_eq!(expected, tokens.to_string());
}

#[test]
fn test_empty_quote() {
    let tokens = quote!();
    assert_eq!("", tokens.to_string());
}
<commit_msg>Use as_str in tests<commit_after>use std::{f32, f64};

#[macro_use]
extern crate quote;

struct X;

impl quote::ToTokens for X {
    fn to_tokens(&self, tokens: &mut quote::Tokens) {
        tokens.append("X");
    }
}

#[test]
fn test_quote_impl() {
    let tokens = quote!(
        impl<'a, T: ToTokens> ToTokens for &'a T {
            fn to_tokens(&self, tokens: &mut Tokens) {
                (**self).to_tokens(tokens)
            }
        }
    );

    let expected = concat!(
        "impl < 'a , T : ToTokens > ToTokens for & 'a T { ",
            "fn to_tokens ( & self , tokens : & mut Tokens ) { ",
                "( * * self ) . to_tokens ( tokens ) ",
            "} ",
        "}"
    );

    assert_eq!(expected, tokens.as_str());
}

#[test]
fn test_substitution() {
    let x = X;
    let tokens = quote!(#x <#x> (#x) [#x] {#x});

    let expected = "X < X > ( X ) [ X ] { X }";

    assert_eq!(expected, tokens.as_str());
}

#[test]
fn test_iter() {
    let primes = &[X, X, X, X];

    assert_eq!("X X X X", quote!(#(#primes)*).as_str());

    assert_eq!("X , X , X , X ,", quote!(#(#primes,)*).as_str());

    assert_eq!("X , X , X , X", quote!(#(#primes),*).as_str());
}

#[test]
fn test_advanced() {
    let generics = quote!( <'a, T> );

    let where_clause = quote!( where T: Serialize );

    let field_ty = quote!( String );

    let item_ty = quote!( Cow<'a, str> );

    let path = quote!( SomeTrait::serialize_with );

    let value = quote!( self.x );

    let tokens = quote! {
        struct SerializeWith #generics #where_clause {
            value: &'a #field_ty,
            phantom: ::std::marker::PhantomData<#item_ty>,
        }

        impl #generics ::serde::Serialize for SerializeWith #generics #where_clause {
            fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error>
                where S: ::serde::Serializer
            {
                #path(self.value, s)
            }
        }

        SerializeWith {
            value: #value,
            phantom: ::std::marker::PhantomData::<#item_ty>,
        }
    };

    let expected = concat!(
        "struct SerializeWith < 'a , T > where T : Serialize { ",
            "value : & 'a String , ",
            "phantom : :: std :: marker :: PhantomData < Cow < 'a , str > > , ",
        "} ",
        "impl < 'a , T > :: serde :: Serialize for SerializeWith < 'a , T > where T : Serialize { ",
            "fn serialize < S > ( & self , s : & mut S ) -> Result < ( ) , S :: Error > ",
                "where S : :: serde :: Serializer ",
            "{ ",
                "SomeTrait :: serialize_with ( self . value , s ) ",
            "} ",
        "} ",
        "SerializeWith { ",
            "value : self . x , ",
            "phantom : :: std :: marker :: PhantomData :: < Cow < 'a , str > > , ",
        "}"
    );

    assert_eq!(expected, tokens.as_str());
}

#[test]
fn test_tuple() {
    let x = ("foo", 4_u32);
    let tokens = quote!(#x);
    let expected = "( \"foo\" , 4u32 , )";
    assert_eq!(expected, tokens.as_str());
}

#[test]
fn test_array() {
    let x: [u32; 3] = [1, 2, 3];
    let tokens = quote!(#x);
    let expected = "[ 1u32 , 2u32 , 3u32 , ]";
    assert_eq!(expected, tokens.as_str());
}

#[test]
fn test_slice() {
    let x: &[u32] = &[1, 2, 3];
    let tokens = quote!(&#x);  // Note: explicit `&`
    let expected = "& [ 1u32 , 2u32 , 3u32 , ]";
    assert_eq!(expected, tokens.as_str());
}

#[test]
fn test_vec() {
    let x: Vec<u32> = vec![1, 2, 3];
    let tokens = quote!(vec!#x);  // Note: explicit `vec!`
    let expected = "vec ! [ 1u32 , 2u32 , 3u32 , ]";
    assert_eq!(expected, tokens.as_str());
}

#[test]
fn test_integer() {
    let ii8 = -1i8;
    let ii16 = -1i16;
    let ii32 = -1i32;
    let ii64 = -1i64;
    let iisize = -1isize;
    let uu8 = 1u8;
    let uu16 = 1u16;
    let uu32 = 1u32;
    let uu64 = 1u64;
    let uusize = 1usize;

    let tokens = quote! {
        #ii8 #ii16 #ii32 #ii64 #iisize
        #uu8 #uu16 #uu32 #uu64 #uusize
    };
    let expected = "-1i8 -1i16 -1i32 -1i64 -1isize 1u8 1u16 1u32 1u64 1usize";
    assert_eq!(expected, tokens.as_str());
}

#[test]
fn test_hex() {
    let hex = quote::Hex(0xFFFF_0000_u32);
    let tokens = quote!(#hex);
    let expected = "0xFFFF0000u32";
    assert_eq!(expected, tokens.as_str());
}

#[test]
fn test_floating() {
    let e32 = 2.71828f32;
    let nan32 = f32::NAN;
    let inf32 = f32::INFINITY;
    let neginf32 = f32::NEG_INFINITY;

    let e64 = 2.71828f64;
    let nan64 = f64::NAN;
    let inf64 = f64::INFINITY;
    let neginf64 = f64::NEG_INFINITY;

    let tokens = quote! {
        #e32 @ #nan32 @ #inf32 @ #neginf32
        #e64 @ #nan64 @ #inf64 @ #neginf64
    };
    let expected = concat!(
        "2.71828f32 @ :: std :: f32 :: NAN @ :: std :: f32 :: INFINITY @ :: std :: f32 :: NEG_INFINITY ",
        "2.71828f64 @ :: std :: f64 :: NAN @ :: std :: f64 :: INFINITY @ :: std :: f64 :: NEG_INFINITY",
    );
    assert_eq!(expected, tokens.as_str());
}

#[test]
fn test_char() {
    let zero = '\0';
    let pound = '#';
    let quote = '"';
    let apost = '\'';
    let newline = '\n';
    let heart = '\u{2764}';

    let tokens = quote! {
        #zero #pound #quote #apost #newline #heart
    };
    let expected = "'\\0' '#' '\"' '\\'' '\\n' '\u{2764}'";
    assert_eq!(expected, tokens.as_str());
}

#[test]
fn test_str() {
    let s = "\0 a 'b \" c";
    let tokens = quote!(#s);
    let expected = "\"\\0 a 'b \\\" c\"";
    assert_eq!(expected, tokens.as_str());
}

#[test]
fn test_string() {
    let s = "\0 a 'b \" c".to_string();
    let tokens = quote!(#s);
    let expected = "\"\\0 a 'b \\\" c\"";
    assert_eq!(expected, tokens.as_str());
}

#[test]
fn test_byte_str() {
    let s = quote::ByteStr("\0 a 'b \" c");
    let tokens = quote!(#s);
    let expected = "b\"\\0 a 'b \\\" c\"";
    assert_eq!(expected, tokens.as_str());
}

#[test]
fn test_ident() {
    let foo = quote::Ident::from("Foo");
    let bar = quote::Ident::from(format!("Bar{}", 7));
    let tokens = quote!(struct #foo; enum #bar {});
    let expected = "struct Foo ; enum Bar7 { }";
    assert_eq!(expected, tokens.as_str());
}

#[test]
fn test_duplicate() {
    let ch = 'x';

    let tokens = quote!(#ch #ch);

    let expected = "'x' 'x'";
    assert_eq!(expected, tokens.as_str());
}

#[test]
fn test_fancy_repetition() {
    let foo = vec!["a", "b"];
    let bar = vec![true, false];

    let tokens = quote! {
        #(#foo: #bar),*
    };

    let expected = r#""a" : true , "b" : false"#;
    assert_eq!(expected, tokens.as_str());
}

#[test]
fn test_nested_fancy_repetition() {
    let nested = vec![vec!['a', 'b', 'c'], vec!['x', 'y', 'z']];

    let tokens = quote! {
        #(
            #(#nested)*
        ),*
    };

    let expected = "'a' 'b' 'c' , 'x' 'y' 'z'";
    assert_eq!(expected, tokens.as_str());
}

#[test]
fn test_empty_repetition() {
    let tokens = quote!(#(a b)* #(c d),*);
    assert_eq!("", tokens.as_str());
}

#[test]
fn test_variable_name_conflict() {
    // The implementation of `#(...),*` uses the variable `_i` but it should be
    // fine, if a little confusing when debugging.
    let _i = vec!['a', 'b'];
    let tokens = quote! { #(#_i),* };
    let expected = "'a' , 'b'";
    assert_eq!(expected, tokens.as_str());
}

#[test]
fn test_empty_quote() {
    let tokens = quote!();
    assert_eq!("", tokens.as_str());
}
<|endoftext|>


<commit_before>
use std::clone::Clone;

use linked_hash_map::LinkedHashMap;

use parser::ast::*;
use parser::store::*;
use parser::api::*;
use parser::util::allocate_element_key;
use processing::structs::*;
use processing::scope::*;
use processing::process_util::*;

#[derive(Debug)]
pub struct ProcessContent {
    // root_node: &'input ContentNodeType,
    root_block: BlockProcessingState,
    base_scope: ElementOpScope,
    scopes: LinkedHashMap<String, ElementOpScope>
}

impl ProcessContent {

    pub fn new(base_scope: ElementOpScope) -> Self {
        ProcessContent {
            root_block: Default::default(),
            base_scope: base_scope,
            scopes: Default::default()
        }
    }

    fn scope(&mut self) -> ElementOpScope {
        self.scopes.back().map_or(self.base_scope.clone(), |s| s.1.clone())
    }

    fn push_scope(&mut self, scope: ElementOpScope) {
        let scope_id = scope.0.complete_element_key();
        self.scopes.insert(scope_id, scope);
    }

    fn pop_scope(&mut self) { self.scopes.pop_back(); }

    #[inline]
    pub fn process_content_node(&mut self,
                            node: &ContentNodeType,
                            processing: &DocumentProcessingState,
                            block: &mut BlockProcessingState,
                            resolution_mode: &BareSymbolResolutionMode)
                            -> DocumentProcessingResult<()> {
        let mut scope = self.scope();

        match node {
            &ContentNodeType::ElementNode(ref element_data) => {
                let is_void = element_data.children.as_ref().map_or(false, |c| c.len() > 0);

                let element_tag = element_data.element_ty.to_lowercase();
                let element_key =
                    element_data.element_key.as_ref().map_or(String::from(""), Clone::clone);

                let attrs = element_data.attrs.as_ref().map(Clone::clone);
                let lens = element_data.lens.as_ref().map(Clone::clone);
                let bindings = element_data.bindings.as_ref().map(|s| s.clone());

                // Try to locate a matching component
                if let Some(..) = processing.comp_map.get(element_data.element_ty.as_str()) {

                    // Attempt to map lens values
                    // FIXME
                    let lens = map_lens_using_scope(lens.as_ref(), processing, &mut block.scope);

                    let attrs = match lens {
                        Some(LensExprType::GetLens(ref sym)) => {
                            let mut attrs = attrs.as_ref().map_or_else(|| Default::default(), |s| s.clone());

                            if let &SymbolReferenceType::UnresolvedReference(ref key) = sym.sym_ref() {
                                if let Some(ref sym) = resolve_reducer_key(processing, &mut block.scope, key) {
                                    let value = Some(ExprValue::SymbolReference(sym.clone()));
                                    attrs.push((key.clone(), value));
                                };
                            };

                            Some(attrs)
                        }

                        Some(LensExprType::ForLens(ref ele_key, ref coll_sym)) => {
                            let mut attrs = attrs.as_ref().map_or_else(|| Default::default(), |s| s.clone());

                            // let resolved = resolve_sym(coll_sym, processing, &mut scope);
                            // let coll_expr = ExprValue::SymbolReference(coll_sym.clone());
                            // let coll_expr = map_expr_using_scope(&coll_expr, processing, &mut block.scope, resolution_mode);
                            // let ele_sym = Symbol::unresolved(ele_key.to_owned());

                            // if let &SymbolReferenceType::UnresolvedReference(ref key) = coll_sym.sym_ref() {
                            //     if let Some(ref sym) = resolve_reducer_key(processing, &mut scope, key) {
                            //         let value = Some(ExprValue::SymbolReference(sym.clone()));
                            //         attrs.push((key.clone(), value));
                            //     };
                            // };

                            if let &Some(ref ele_key) = ele_key {
                                let sym = Symbol::prop(ele_key);
                                let value = Some(ExprValue::SymbolReference(sym.clone()));
                                attrs.push((ele_key.clone(), value));
                            };

                            Some(attrs)
                        }

                        _ => attrs
                    };

                    // Render a component during render
                    block.ops_vec.push(ElementOp::InstanceComponent(element_tag,
                                                                Some(element_key),
                                                                attrs,
                                                                lens));

                } else {
                    let mut scope = scope.clone();
                    scope.0.append_key(&element_key);
                    let complete_key = scope.0.complete_element_key();

                    // Treat this as an HTML element
                    // TODO: Support imported elements

                    let mut events: Option<Vec<ElementEventBinding>> = Default::default();
                    let mut value_binding: ElementValueBinding = Default::default();

                    // Process bindings
                    if let Some(ref bindings) = element_data.bindings {
                        // Loop through value bindings first
                        for binding in bindings {
                            if let &ElementBindingNodeType::ElementValueBindingNode(ref key) = binding {
                                value_binding = Some(key.to_owned());
                                block.scope.1.add_element_value_binding(key, &complete_key);
                            };
                        }

                    //                     param.1 = param.1.as_ref().map(|expr| map_expr_using_scope(expr, processing, &mut block.scope, resolution_mode));

                        // Loop through the event bindings
                        for binding in bindings {
                            if let &ElementBindingNodeType::ElementEventBindingNode(ref event) = binding {
                                let mut event = event.clone();

                                event.2 = event.2.as_ref().map(|action_ops| {
                                    action_ops.iter().map(|action_op| {
                                        match action_op {
                                            &ActionOpNode::DispatchAction(ref action_key, ref action_params) => {
                                                let action_ty = scope.0.make_action_type(&action_key);

                                                let action_params = action_params.as_ref().map(|action_params| {
                                                    let mut action_params = action_params.clone();
                                                    for mut param in &mut action_params {
                                                        param.1 = param.1.as_ref().map(|expr| {
                                                            if let &ExprValue::SymbolReference(ref sym) = expr {
                                                                if let &SymbolReferenceType::UnresolvedReference(ref key) = sym.sym_ref() {
                                                                    if let Some(sym) = block.scope.1.element_value_bindings.get(key) {
                                                                        return ExprValue::SymbolReference(sym.to_owned());
                                                                    };
                                                                };
                                                            };

                                                            map_expr_using_scope(expr, processing, &mut block.scope, resolution_mode)
                                                        });
                                                    }
                                                    action_params
                                                });

                                                ActionOpNode::DispatchAction(action_ty, action_params)
                                            },
                                            _ => action_op.to_owned()
                                        }

                                        // let mut action_op = action_op.to_owned();
                                        // if let &ActionOpNode::DispatchAction(..) = action_op {

                                        //     action_op.0 = scope.0.make_action_type(&action_op.0);
                                        //     let mut action_op = ActionOpNode
                                    // for mut action_op = action_ops {
                                        // action_op.0 = scope.0.make_action_type(&action_op.0);
                                        // if let ActionOpNode::DispatchAction(mut action_key, _) = action_op {
                                        //     action_key = scope.0.make_action_type(&action_key);
                                        // };

                                        // if let ActionOpNode::DispatchAction(_, Some(ref mut action_params)) = action_op {
                                        //     for param in action_params {
                                        //         param.1 = param.1.as_ref().map(|expr| {
                                        //             if let &ExprValue::SymbolReference(ref sym) = expr {
                                        //                 if let &SymbolReferenceType::UnresolvedReference(ref key) = sym.sym_ref() {
                                        //                     if let Some(sym) = block.scope.1.element_value_bindings.get(key) {
                                        //                         return ExprValue::SymbolReference(sym.to_owned());
                                        //                     };
                                        //                 };
                                        //             };

                                        //             map_expr_using_scope(expr, processing, &mut block.scope, resolution_mode)
                                        //         });
                                        //     }
                                        // };
                                        // action_op
                                    }).collect()
                                });

                                block.events_vec.push((scope.0.complete_element_key(),
                                                    event.0.as_ref().map(|s| s.to_owned()),
                                                    event.1.as_ref().map(|s| s.to_owned()),
                                                    event.2.as_ref().map(|s| s.to_owned()),
                                                    None,
                                                    Some(block.block_id.to_owned())));
                                if !events.is_some() { events = Some(Default::default()); }
                                if let Some(ref mut events) = events { events.push(event.clone()); }
                            };
                        }
                    }

                    // Process events
                    // let expr = map_expr_using_scope(expr, processing, &mut block.scope, resolution_mode);

                    // for ref mut event in events {
                    //     if let Some(ref mut action_ops) = event.action_ops {
                    //         for ref mut action_op in action_ops {
                    //             if let &ActionOpNode::DispatchAction(_, ref mut action_params) = action_op {
                    //                 for ref mut param in action_params {
                    //                     param.1 = param.1.as_ref().map(|expr| map_expr_using_scope(expr, processing, &mut block.scope, resolution_mode));
                    //                 }
                    //             }
                    //         }
                    //     };
                    // }

                    // let events = events.as_ref().map(|event| {
                    //     event.action_ops = event.action_ops.as_ref().map(|action_op| {
                    //         if let &ActionOpNode::DispatchAction(_, ref action_params) = action_op {
                    //             if let Some(ref mut action_params) = action_params {
                    //                 let action_params: PropVec = action_params.iter().map(|param| {
                    //                     if let Some(ExprValue::SymbolReference(ref sym)) = param.1 {
                    //                         if let &SymbolReferenceType::UnresolvedReference(ref key) = sym.sym_ref() {
                    //                             if let Some(sym) = scope.1.element_value_bindings.get(key) {
                    //                                 return (param.0.to_owned(), Some(ExprValue::SymbolReference(sym.to_owned())));
                    //                             };
                    //                         };

                    //                         if let Some(ref sym) = resolve_document_symbol(sym, self.doc, &mut scope) {
                    //                             return (param.0.to_owned(), Some(ExprValue::SymbolReference(sym.to_owned())));
                    //                         };
                    //                     };

                    //                     param.to_owned()
                    //                 }).collect();
                    //         }

                    //     })

                    // });

                    // This should only be Some if there are actually children
                    if let Some(ref children) = element_data.children {
                        // Push element open
                        block.ops_vec.push(ElementOp::ElementOpen(element_tag.clone(),
                                                            Some(element_key),
                                                            attrs,
                                                            events,
                                                            value_binding));

                        // Push scope
                        self.push_scope(scope.clone());

                        // Iterate over children
                        for ref child in children {
                            self.process_content_node(child, processing, block, resolution_mode)?;
                        }

                        // Pop scope
                        self.pop_scope();

                        // Push element close
                        block.ops_vec.push(ElementOp::ElementClose(element_tag.clone()));
                    } else {
                        block.ops_vec.push(ElementOp::ElementVoid(element_tag.clone(),
                                                            Some(element_key),
                                                            attrs,
                                                            events,
                                                            value_binding));
                    }
                }
            }
            &ContentNodeType::ExpressionValueNode(ref expr) => {
                let expr = map_expr_using_scope(expr, processing, &mut block.scope, resolution_mode);

                block.ops_vec.push(ElementOp::WriteValue(expr, Some(allocate_element_key())));
            }
            &ContentNodeType::ForNode(ref ele, ref coll_expr, ref nodes) => {
                let mut scope = scope.clone();

                let block_id = allocate_element_key().replace("-", "_");
                block.ops_vec.push(ElementOp::StartBlock(block_id.clone()));

                let coll_expr = map_expr_using_scope(coll_expr, processing, &mut block.scope, resolution_mode);

                // Add forvar as a parameter in the symbol map
                if let &Some(ref ele_key) = ele {
                    scope.1.add_loop_var(ele_key);
                }

                if let &Some(ref nodes) = nodes {
                    for ref node in nodes {
                        // FIXME: forvar resolve
                        self.process_content_node(node, processing, block, resolution_mode)?;
                    }
                };

                block.ops_vec.push(ElementOp::EndBlock(block_id.clone()));
                block.ops_vec.push(ElementOp::MapCollection(block_id.clone(),
                                                        ele.as_ref().map(Clone::clone),
                                                        coll_expr.clone()));
            }
        }
        (Ok(()))
    }
}<commit_msg>Remove some commented code in process_content<commit_after>
use std::clone::Clone;

use linked_hash_map::LinkedHashMap;

use parser::ast::*;
use parser::store::*;
use parser::api::*;
use parser::util::allocate_element_key;
use processing::structs::*;
use processing::scope::*;
use processing::process_util::*;

#[derive(Debug)]
pub struct ProcessContent {
    // root_node: &'input ContentNodeType,
    root_block: BlockProcessingState,
    base_scope: ElementOpScope,
    scopes: LinkedHashMap<String, ElementOpScope>
}

impl ProcessContent {

    pub fn new(base_scope: ElementOpScope) -> Self {
        ProcessContent {
            root_block: Default::default(),
            base_scope: base_scope,
            scopes: Default::default()
        }
    }

    fn scope(&mut self) -> ElementOpScope {
        self.scopes.back().map_or(self.base_scope.clone(), |s| s.1.clone())
    }

    fn push_scope(&mut self, scope: ElementOpScope) {
        let scope_id = scope.0.complete_element_key();
        self.scopes.insert(scope_id, scope);
    }

    fn pop_scope(&mut self) { self.scopes.pop_back(); }

    #[inline]
    pub fn process_content_node(&mut self,
                            node: &ContentNodeType,
                            processing: &DocumentProcessingState,
                            block: &mut BlockProcessingState,
                            resolution_mode: &BareSymbolResolutionMode)
                            -> DocumentProcessingResult<()> {
        let mut scope = self.scope();

        match node {
            &ContentNodeType::ElementNode(ref element_data) => {
                let is_void = element_data.children.as_ref().map_or(false, |c| c.len() > 0);

                let element_tag = element_data.element_ty.to_lowercase();
                let element_key =
                    element_data.element_key.as_ref().map_or(String::from(""), Clone::clone);

                let attrs = element_data.attrs.as_ref().map(Clone::clone);
                let lens = element_data.lens.as_ref().map(Clone::clone);
                let bindings = element_data.bindings.as_ref().map(|s| s.clone());

                // Try to locate a matching component
                if let Some(..) = processing.comp_map.get(element_data.element_ty.as_str()) {

                    // Attempt to map lens values
                    // FIXME
                    let lens = map_lens_using_scope(lens.as_ref(), processing, &mut block.scope);

                    let attrs = match lens {
                        Some(LensExprType::GetLens(ref sym)) => {
                            let mut attrs = attrs.as_ref().map_or_else(|| Default::default(), |s| s.clone());

                            if let &SymbolReferenceType::UnresolvedReference(ref key) = sym.sym_ref() {
                                if let Some(ref sym) = resolve_reducer_key(processing, &mut block.scope, key) {
                                    let value = Some(ExprValue::SymbolReference(sym.clone()));
                                    attrs.push((key.clone(), value));
                                };
                            };

                            Some(attrs)
                        }

                        Some(LensExprType::ForLens(ref ele_key, ref coll_sym)) => {
                            let mut attrs = attrs.as_ref().map_or_else(|| Default::default(), |s| s.clone());

                            // let resolved = resolve_sym(coll_sym, processing, &mut scope);
                            // let coll_expr = ExprValue::SymbolReference(coll_sym.clone());
                            // let coll_expr = map_expr_using_scope(&coll_expr, processing, &mut block.scope, resolution_mode);
                            // let ele_sym = Symbol::unresolved(ele_key.to_owned());

                            // if let &SymbolReferenceType::UnresolvedReference(ref key) = coll_sym.sym_ref() {
                            //     if let Some(ref sym) = resolve_reducer_key(processing, &mut scope, key) {
                            //         let value = Some(ExprValue::SymbolReference(sym.clone()));
                            //         attrs.push((key.clone(), value));
                            //     };
                            // };

                            if let &Some(ref ele_key) = ele_key {
                                let sym = Symbol::prop(ele_key);
                                let value = Some(ExprValue::SymbolReference(sym.clone()));
                                attrs.push((ele_key.clone(), value));
                            };

                            Some(attrs)
                        }

                        _ => attrs
                    };

                    // Render a component during render
                    block.ops_vec.push(ElementOp::InstanceComponent(element_tag,
                                                                Some(element_key),
                                                                attrs,
                                                                lens));

                } else {
                    let mut scope = scope.clone();
                    scope.0.append_key(&element_key);
                    let complete_key = scope.0.complete_element_key();

                    // Treat this as an HTML element
                    // TODO: Support imported elements

                    let mut events: Option<Vec<ElementEventBinding>> = Default::default();
                    let mut value_binding: ElementValueBinding = Default::default();

                    // Process bindings
                    if let Some(ref bindings) = element_data.bindings {
                        // Loop through value bindings first
                        for binding in bindings {
                            if let &ElementBindingNodeType::ElementValueBindingNode(ref key) = binding {
                                value_binding = Some(key.to_owned());
                                block.scope.1.add_element_value_binding(key, &complete_key);
                            };
                        }

                    //                     param.1 = param.1.as_ref().map(|expr| map_expr_using_scope(expr, processing, &mut block.scope, resolution_mode));

                        // Loop through the event bindings
                        for binding in bindings {
                            if let &ElementBindingNodeType::ElementEventBindingNode(ref event) = binding {
                                let mut event = event.clone();

                                event.2 = event.2.as_ref().map(|action_ops| {
                                    action_ops.iter().map(|action_op| {
                                        match action_op {
                                            &ActionOpNode::DispatchAction(ref action_key, ref action_params) => {
                                                let action_ty = scope.0.make_action_type(&action_key);

                                                let action_params = action_params.as_ref().map(|action_params| {
                                                    let mut action_params = action_params.clone();
                                                    for mut param in &mut action_params {
                                                        param.1 = param.1.as_ref().map(|expr| {
                                                            if let &ExprValue::SymbolReference(ref sym) = expr {
                                                                if let &SymbolReferenceType::UnresolvedReference(ref key) = sym.sym_ref() {
                                                                    if let Some(sym) = block.scope.1.element_value_bindings.get(key) {
                                                                        return ExprValue::SymbolReference(sym.to_owned());
                                                                    };
                                                                };
                                                            };

                                                            map_expr_using_scope(expr, processing, &mut block.scope, resolution_mode)
                                                        });
                                                    }
                                                    action_params
                                                });

                                                ActionOpNode::DispatchAction(action_ty, action_params)
                                            },
                                            _ => action_op.to_owned()
                                        }
                                    }).collect()
                                });

                                block.events_vec.push((scope.0.complete_element_key(),
                                                    event.0.as_ref().map(|s| s.to_owned()),
                                                    event.1.as_ref().map(|s| s.to_owned()),
                                                    event.2.as_ref().map(|s| s.to_owned()),
                                                    None,
                                                    Some(block.block_id.to_owned())));
                                if !events.is_some() { events = Some(Default::default()); }
                                if let Some(ref mut events) = events { events.push(event.clone()); }
                            };
                        }
                    }

                    // This should only be Some if there are actually children
                    if let Some(ref children) = element_data.children {
                        // Push element open
                        block.ops_vec.push(ElementOp::ElementOpen(element_tag.clone(),
                                                            Some(element_key),
                                                            attrs,
                                                            events,
                                                            value_binding));

                        // Push scope
                        self.push_scope(scope.clone());

                        // Iterate over children
                        for ref child in children {
                            self.process_content_node(child, processing, block, resolution_mode)?;
                        }

                        // Pop scope
                        self.pop_scope();

                        // Push element close
                        block.ops_vec.push(ElementOp::ElementClose(element_tag.clone()));
                    } else {
                        block.ops_vec.push(ElementOp::ElementVoid(element_tag.clone(),
                                                            Some(element_key),
                                                            attrs,
                                                            events,
                                                            value_binding));
                    }
                }
            }
            &ContentNodeType::ExpressionValueNode(ref expr) => {
                let expr = map_expr_using_scope(expr, processing, &mut block.scope, resolution_mode);

                block.ops_vec.push(ElementOp::WriteValue(expr, Some(allocate_element_key())));
            }
            &ContentNodeType::ForNode(ref ele, ref coll_expr, ref nodes) => {
                let mut scope = scope.clone();

                let block_id = allocate_element_key().replace("-", "_");
                block.ops_vec.push(ElementOp::StartBlock(block_id.clone()));

                let coll_expr = map_expr_using_scope(coll_expr, processing, &mut block.scope, resolution_mode);

                // Add forvar as a parameter in the symbol map
                if let &Some(ref ele_key) = ele {
                    scope.1.add_loop_var(ele_key);
                }

                if let &Some(ref nodes) = nodes {
                    for ref node in nodes {
                        // FIXME: forvar resolve
                        self.process_content_node(node, processing, block, resolution_mode)?;
                    }
                };

                block.ops_vec.push(ElementOp::EndBlock(block_id.clone()));
                block.ops_vec.push(ElementOp::MapCollection(block_id.clone(),
                                                        ele.as_ref().map(Clone::clone),
                                                        coll_expr.clone()));
            }
        }
        (Ok(()))
    }
}<|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/. */

use dom::bindings::js::JS;
use dom::bindings::utils::{Reflectable, Reflector};

use js::jsapi::{JSObject, JSTracer, JS_CallTracer, JSTRACE_OBJECT};
use js::jsval::JSVal;

use libc;
use std::cast;
use std::cell::{Cell, RefCell};
use serialize::{Encodable, Encoder};

// IMPORTANT: We rely on the fact that we never attempt to encode DOM objects using
//            any encoder but JSTracer. Since we derive trace hooks automatically,
//            we are unfortunately required to use generic types everywhere and
//            unsafely cast to the concrete JSTracer we actually require.

fn get_jstracer<'a, S: Encoder<E>, E>(s: &'a mut S) -> &'a mut JSTracer {
    unsafe {
        cast::transmute(s)
    }
}

impl<T: Reflectable+Encodable<S, E>, S: Encoder<E>, E> Encodable<S, E> for JS<T> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        trace_reflector(get_jstracer(s), "", self.reflector());
        Ok(())
    }
}

impl<S: Encoder<E>, E> Encodable<S, E> for Reflector {
    fn encode(&self, _s: &mut S) -> Result<(), E> {
        Ok(())
    }
}

pub trait JSTraceable {
    fn trace(&self, trc: *mut JSTracer);
}

pub fn trace_jsval(tracer: *mut JSTracer, description: &str, val: JSVal) {
    if !val.is_gcthing() {
        return;
    }

    unsafe {
        description.to_c_str().with_ref(|name| {
            (*tracer).debugPrinter = None;
            (*tracer).debugPrintIndex = -1;
            (*tracer).debugPrintArg = name as *libc::c_void;
            debug!("tracing value {:s}", description);
            JS_CallTracer(tracer, val.to_gcthing(), val.trace_kind());
        });
    }
}

pub fn trace_reflector(tracer: *mut JSTracer, description: &str, reflector: &Reflector) {
    trace_object(tracer, description, reflector.get_jsobject())
}

pub fn trace_object(tracer: *mut JSTracer, description: &str, obj: *mut JSObject) {
    unsafe {
        description.to_c_str().with_ref(|name| {
            (*tracer).debugPrinter = None;
            (*tracer).debugPrintIndex = -1;
            (*tracer).debugPrintArg = name as *libc::c_void;
            debug!("tracing {:s}", description);
            JS_CallTracer(tracer, obj as *mut libc::c_void, JSTRACE_OBJECT);
        });
    }
}

/// Encapsulates a type that cannot easily have Encodable derived automagically,
/// but also does not need to be made known to the SpiderMonkey garbage collector.
/// Use only with types that are not associated with a JS reflector and do not contain
/// fields of types associated with JS reflectors.
pub struct Untraceable<T> {
    inner: T,
}

impl<T> Untraceable<T> {
    pub fn new(val: T) -> Untraceable<T> {
        Untraceable {
            inner: val
        }
    }
}

impl<S: Encoder<E>, E, T> Encodable<S, E> for Untraceable<T> {
    fn encode(&self, _s: &mut S) -> Result<(), E> {
        Ok(())
    }
}

impl<T> Deref<T> for Untraceable<T> {
    fn deref<'a>(&'a self) -> &'a T {
        &self.inner
    }
}

impl<T> DerefMut<T> for Untraceable<T> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        &mut self.inner
    }
}

/// Encapsulates a type that can be traced but is boxed in a type we don't control
/// (such as RefCell). Wrap a field in Traceable and implement the Encodable trait
/// for that new concrete type to achieve magic compiler-derived trace hooks.
#[deriving(Eq, Clone)]
pub struct Traceable<T> {
    inner: T
}

impl<T> Traceable<T> {
    pub fn new(val: T) -> Traceable<T> {
        Traceable {
            inner: val
        }
    }
}

impl<T> Deref<T> for Traceable<T> {
    fn deref<'a>(&'a self) -> &'a T {
        &self.inner
    }
}

impl<T> DerefMut<T> for Traceable<T> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        &mut self.inner
    }
}

impl<S: Encoder<E>, E, T: Encodable<S, E>> Encodable<S, E> for Traceable<RefCell<T>> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        self.borrow().encode(s)
    }
}

impl<S: Encoder<E>, E, T: Encodable<S, E>+Copy> Encodable<S, E> for Traceable<Cell<T>> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        self.deref().get().encode(s)
    }
}

impl<S: Encoder<E>, E> Encodable<S, E> for Traceable<*mut JSObject> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        trace_object(get_jstracer(s), "object", **self);
        Ok(())
    }
}

impl<S: Encoder<E>, E> Encodable<S, E> for Traceable<JSVal> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        trace_jsval(get_jstracer(s), "val", **self);
        Ok(())
    }
}
<commit_msg>Make 'Cell<JS<T>>' traceable.<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/. */

use dom::bindings::js::JS;
use dom::bindings::utils::{Reflectable, Reflector};

use js::jsapi::{JSObject, JSTracer, JS_CallTracer, JSTRACE_OBJECT};
use js::jsval::JSVal;

use libc;
use std::cast;
use std::cell::{Cell, RefCell};
use serialize::{Encodable, Encoder};

// IMPORTANT: We rely on the fact that we never attempt to encode DOM objects using
//            any encoder but JSTracer. Since we derive trace hooks automatically,
//            we are unfortunately required to use generic types everywhere and
//            unsafely cast to the concrete JSTracer we actually require.

fn get_jstracer<'a, S: Encoder<E>, E>(s: &'a mut S) -> &'a mut JSTracer {
    unsafe {
        cast::transmute(s)
    }
}

impl<T: Reflectable+Encodable<S, E>, S: Encoder<E>, E> Encodable<S, E> for JS<T> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        trace_reflector(get_jstracer(s), "", self.reflector());
        Ok(())
    }
}

impl<S: Encoder<E>, E> Encodable<S, E> for Reflector {
    fn encode(&self, _s: &mut S) -> Result<(), E> {
        Ok(())
    }
}

pub trait JSTraceable {
    fn trace(&self, trc: *mut JSTracer);
}

pub fn trace_jsval(tracer: *mut JSTracer, description: &str, val: JSVal) {
    if !val.is_gcthing() {
        return;
    }

    unsafe {
        description.to_c_str().with_ref(|name| {
            (*tracer).debugPrinter = None;
            (*tracer).debugPrintIndex = -1;
            (*tracer).debugPrintArg = name as *libc::c_void;
            debug!("tracing value {:s}", description);
            JS_CallTracer(tracer, val.to_gcthing(), val.trace_kind());
        });
    }
}

pub fn trace_reflector(tracer: *mut JSTracer, description: &str, reflector: &Reflector) {
    trace_object(tracer, description, reflector.get_jsobject())
}

pub fn trace_object(tracer: *mut JSTracer, description: &str, obj: *mut JSObject) {
    unsafe {
        description.to_c_str().with_ref(|name| {
            (*tracer).debugPrinter = None;
            (*tracer).debugPrintIndex = -1;
            (*tracer).debugPrintArg = name as *libc::c_void;
            debug!("tracing {:s}", description);
            JS_CallTracer(tracer, obj as *mut libc::c_void, JSTRACE_OBJECT);
        });
    }
}

/// Encapsulates a type that cannot easily have Encodable derived automagically,
/// but also does not need to be made known to the SpiderMonkey garbage collector.
/// Use only with types that are not associated with a JS reflector and do not contain
/// fields of types associated with JS reflectors.
pub struct Untraceable<T> {
    inner: T,
}

impl<T> Untraceable<T> {
    pub fn new(val: T) -> Untraceable<T> {
        Untraceable {
            inner: val
        }
    }
}

impl<S: Encoder<E>, E, T> Encodable<S, E> for Untraceable<T> {
    fn encode(&self, _s: &mut S) -> Result<(), E> {
        Ok(())
    }
}

impl<T> Deref<T> for Untraceable<T> {
    fn deref<'a>(&'a self) -> &'a T {
        &self.inner
    }
}

impl<T> DerefMut<T> for Untraceable<T> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        &mut self.inner
    }
}

/// Encapsulates a type that can be traced but is boxed in a type we don't control
/// (such as RefCell). Wrap a field in Traceable and implement the Encodable trait
/// for that new concrete type to achieve magic compiler-derived trace hooks.
#[deriving(Eq, Clone)]
pub struct Traceable<T> {
    inner: T
}

impl<T> Traceable<T> {
    pub fn new(val: T) -> Traceable<T> {
        Traceable {
            inner: val
        }
    }
}

impl<T> Deref<T> for Traceable<T> {
    fn deref<'a>(&'a self) -> &'a T {
        &self.inner
    }
}

impl<T> DerefMut<T> for Traceable<T> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        &mut self.inner
    }
}

impl<S: Encoder<E>, E, T: Encodable<S, E>> Encodable<S, E> for Traceable<RefCell<T>> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        self.borrow().encode(s)
    }
}

impl<S: Encoder<E>, E, T: Encodable<S, E>+Copy> Encodable<S, E> for Traceable<Cell<T>> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        self.deref().get().encode(s)
    }
}

impl<S: Encoder<E>, E> Encodable<S, E> for Traceable<*mut JSObject> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        trace_object(get_jstracer(s), "object", **self);
        Ok(())
    }
}

impl<S: Encoder<E>, E> Encodable<S, E> for Traceable<JSVal> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        trace_jsval(get_jstracer(s), "val", **self);
        Ok(())
    }
}

/// for a field which contains DOMType
impl<T: Reflectable+Encodable<S, E>, S: Encoder<E>, E> Encodable<S, E> for Cell<JS<T>> {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        self.get().encode(s)
    }
}
<|endoftext|>


<commit_before>extern crate bindgen;

use std::env;
use std::path::PathBuf;

#[cfg(any(windows, feature = "headless"))]
use std::fs::File;
#[cfg(any(windows, feature = "headless"))]
use std::io::prelude::*;
#[cfg(any(windows, feature = "headless"))]
use std::io::BufReader;

#[cfg(all(target_os = "macos", feature = "headless"))]
static LASTRUN_PATH: (&str, &str) = ("HOME", "Library/Application Support/Binary Ninja/lastrun");

#[cfg(all(target_os = "linux", feature = "headless"))]
static LASTRUN_PATH: (&str, &str) = ("HOME", ".binaryninja/lastrun");

#[cfg(windows)]
static LASTRUN_PATH: (&str, &str) = ("APPDATA", "Binary Ninja\\lastrun");

#[cfg(any(windows, feature = "headless"))]
fn link_path() -> PathBuf {
    let home = PathBuf::from(env::var(LASTRUN_PATH.0).unwrap());
    let lastrun = PathBuf::from(&home).join(LASTRUN_PATH.1);

    File::open(lastrun)
        .and_then(|f| {
            let mut binja_path = String::new();
            let mut reader = BufReader::new(f);

            reader.read_line(&mut binja_path)?;
            Ok(PathBuf::from(binja_path.trim()))
        })
        .unwrap_or_else(|_| {
            #[cfg(target_os = "macos")]
            return PathBuf::from("/Applications/Binary Ninja.app/Contents/MacOS");

            #[cfg(target_os = "linux")]
            return home.join("binaryninja");

            #[cfg(windows)]
            return PathBuf::from(env::var("PROGRAMFILES").unwrap())
                .join("Vector35\\BinaryNinja\\");
        })
}

fn main() {
    println!("cargo:rerun-if-changed=../../binaryninjacore.h");

    // Allow the library search path to be overridden for internal dev builds, but
    // otherwise search the usual install paths
    let out_dir = env::var("OUT_DIR").unwrap();
    let llvm_dir = env::var("LIBCLANG_PATH");
    let llvm_version = env::var("LLVM_VERSION");
    let llvm_install_dir = env::var("LLVM_INSTALL_DIR");

    #[cfg(any(windows, feature = "headless"))]
    let link_path = env::var("BINARYNINJADIR")
        .map(PathBuf::from)
        .unwrap_or_else(|_| link_path());

    #[cfg(all(unix, feature = "headless"))]
    {
        use std::process::Command;

        // Spectacularly evil linking hack due to Cargo shortcomings. In a nutshell,
        // due to the inability for our .rlib crate to contribute linker arguments
        // (or even just an rpath!) to our consumers, any resulting binaries will
        // fail to run unless loaded into a process that already has the core loaded.
        //
        // For plugins this restriction is fine as they'll only be loaded by the core;
        // headless binaries on the other hand (consider `cargo test`, too!) will fail
        // because libbinaryninjacore is not in the library path on pretty much any
        // system anywhere. If only we could trick the linker into linking with an
        // absolute path...
        //
        // LOOK ON MY WORKS, YE MIGHTY, AND DESPAIR
        //
        // We build a simple do-nothing library called liblinkhack and add it as a
        // native dependency. Crucially, we ensure that LC_ID_DYLIB (macos) or DT_SONAME
        // (linux) is set to the absolute path of libbinaryninjacore. This has the effect
        // that any binary attempting to link with liblinkhack will have its dependency
        // on liblinkhack recorded as the path to the binaryninja core. Later on, the
        // actual core will get linked and that dependency will be recorded in the normal
        // way.
        //
        // tl;dr we're linking against a fake, shim library that actually results in
        // the binaryninja core getting linked twice, once with an absolute path and once
        // correctly. yes, this is as horrifying as you think it is. no, there is no other
        // way to make `cargo test` work.
        //
        // I'm not happy about it either.

        #[cfg(target_os = "macos")]
        Command::new("clang")
            .args(&["-Wl,-dylib", "-o"])
            .arg(&format!("{}/liblinkhack.dylib", out_dir))
            .arg(&format!(
                "-Wl,-install_name,{}/libbinaryninjacore.dylib",
                &link_path.to_str().unwrap()
            ))
            .arg(&format!(
                "{}/linkhack/linkhack.c",
                env::var("CARGO_MANIFEST_DIR").unwrap()
            ))
            .status()
            .unwrap();

        #[cfg(target_os = "linux")]
        {
            Command::new("gcc")
                .args(&["-shared", "-o"])
                .arg(&format!("{}/liblinkhack.so", out_dir))
                .arg(&format!(
                    "-Wl,-soname,{}libbinaryninjacore.so.1",
                    &link_path.to_str().unwrap()
                )) // TODO : Check mac to see if I need to remove the extra slash as well
                .arg(&format!(
                    "{}/linkhack/linkhack.c",
                    env::var("CARGO_MANIFEST_DIR").unwrap()
                ))
                .status()
                .unwrap();

            // Linux builds of binaryninja ship with libbinaryninjacore.so.1 in the
            // application folder and no symlink. The linker will attempt to link with
            // libbinaryninjacore.so. Since this is likely going to fail, we detect this
            // ahead of time and create an appropriately named symlink inside of OUT_DIR
            // and add it to the library search path.
            let symlink_target = PathBuf::from(&out_dir).join("libbinaryninjacore.so");
            if !link_path.join("libbinaryninjacore.so").exists() && !symlink_target.exists() {
                use std::os::unix::fs;
                fs::symlink(
                    link_path.join("libbinaryninjacore.so.1"),
                    PathBuf::from(&out_dir).join("libbinaryninjacore.so"),
                )
                .expect("failed to create required symlink");
            }
        }

        println!("cargo:rustc-link-lib=linkhack");
        println!("cargo:rustc-link-search={}", out_dir);
    }

    #[cfg(any(windows, feature = "headless"))]
    {
        println!("cargo:rustc-link-lib=binaryninjacore");
        println!("cargo:rustc-link-search={}", link_path.to_str().unwrap());
    }

    #[warn(unused_assignments)]
    let mut is_mac = false;
    #[cfg(target_os = "macos")]
    {
        is_mac = true;
    }

    // Difference between global LLVM/Clang install and custom LLVM/Clang install...
    //  First option is for the build server, second option is being nice to our dev who have `LLVM_INSTALL_DIR` set, third is for people with "normal" setups (and Macs)
    let bindings;
    if let (false, Ok(llvm_dir), Ok(llvm_version)) = (is_mac, llvm_dir, llvm_version) {
        let llvm_include_path = format!("-I{}/clang/{}/include", llvm_dir, llvm_version);
        bindings = bindgen::builder()
            .header("../../binaryninjacore.h")
            .clang_arg("-std=c++17")
            .clang_arg("-x")
            .clang_arg("c++")
            .clang_arg(llvm_include_path)
            .size_t_is_usize(true)
            .generate_comments(false)
            .whitelist_function("BN.*")
            .whitelist_var("BN_CURRENT_CORE_ABI_VERSION")
            .whitelist_var("BN_MINIMUM_CORE_ABI_VERSION")
            .rustified_enum("BN.*")
            .generate()
            .expect("Unable to generate bindings");
    } else if let (false, Ok(llvm_install_dir)) = (is_mac, llvm_install_dir) {
        let llvm_include_path = format!("-I{}/11.0.0/lib/clang/11.0.0/include", llvm_install_dir);
        env::set_var("LIBCLANG_PATH", format!("{}/11.0.0/lib", llvm_install_dir));
        bindings = bindgen::builder()
            .header("../../binaryninjacore.h")
            .clang_arg("-std=c++17")
            .clang_arg("-x")
            .clang_arg("c++")
            .clang_arg(llvm_include_path)
            .size_t_is_usize(true)
            .generate_comments(false)
            .whitelist_function("BN.*")
            .whitelist_var("BN_CURRENT_CORE_ABI_VERSION")
            .whitelist_var("BN_MINIMUM_CORE_ABI_VERSION")
            .rustified_enum("BN.*")
            .generate()
            .expect("Unable to generate bindings");
    } else {
        bindings = bindgen::builder()
            .header("../../binaryninjacore.h")
            .clang_arg("-std=c++17")
            .clang_arg("-x")
            .clang_arg("c++")
            .size_t_is_usize(true)
            .generate_comments(false)
            .whitelist_function("BN.*")
            .whitelist_var("BN_CURRENT_CORE_ABI_VERSION")
            .whitelist_var("BN_MINIMUM_CORE_ABI_VERSION")
            .rustified_enum("BN.*")
            .generate()
            .expect("Unable to generate bindings");
    }

    bindings
        .write_to_file(PathBuf::from(out_dir).join("bindings.rs"))
        .expect("Couldn't write bindings!");
}
<commit_msg>Fix Rust API linker error on macos<commit_after>extern crate bindgen;

use std::env;
use std::path::PathBuf;

#[cfg(any(not(target_os = "linux"), feature = "headless"))]
use std::fs::File;
#[cfg(any(not(target_os = "linux"), feature = "headless"))]
use std::io::prelude::*;
#[cfg(any(not(target_os = "linux"), feature = "headless"))]
use std::io::BufReader;

#[cfg(target_os = "macos")]
static LASTRUN_PATH: (&str, &str) = ("HOME", "Library/Application Support/Binary Ninja/lastrun");

#[cfg(all(target_os = "linux", feature = "headless"))]
static LASTRUN_PATH: (&str, &str) = ("HOME", ".binaryninja/lastrun");

#[cfg(windows)]
static LASTRUN_PATH: (&str, &str) = ("APPDATA", "Binary Ninja\\lastrun");

#[cfg(any(not(target_os = "linux"), feature = "headless"))]
fn link_path() -> PathBuf {
    let home = PathBuf::from(env::var(LASTRUN_PATH.0).unwrap());
    let lastrun = PathBuf::from(&home).join(LASTRUN_PATH.1);

    File::open(lastrun)
        .and_then(|f| {
            let mut binja_path = String::new();
            let mut reader = BufReader::new(f);

            reader.read_line(&mut binja_path)?;
            Ok(PathBuf::from(binja_path.trim()))
        })
        .unwrap_or_else(|_| {
            #[cfg(target_os = "macos")]
            return PathBuf::from("/Applications/Binary Ninja.app/Contents/MacOS");

            #[cfg(target_os = "linux")]
            return home.join("binaryninja");

            #[cfg(windows)]
            return PathBuf::from(env::var("PROGRAMFILES").unwrap())
                .join("Vector35\\BinaryNinja\\");
        })
}

fn main() {
    println!("cargo:rerun-if-changed=../../binaryninjacore.h");

    // Allow the library search path to be overridden for internal dev builds, but
    // otherwise search the usual install paths
    let out_dir = env::var("OUT_DIR").unwrap();
    let llvm_dir = env::var("LIBCLANG_PATH");
    let llvm_version = env::var("LLVM_VERSION");
    let llvm_install_dir = env::var("LLVM_INSTALL_DIR");

    #[cfg(any(not(target_os = "linux"), feature = "headless"))]
    let link_path = env::var("BINARYNINJADIR")
        .map(PathBuf::from)
        .unwrap_or_else(|_| link_path());

    #[cfg(all(unix, feature = "headless"))]
    {
        use std::process::Command;

        // Spectacularly evil linking hack due to Cargo shortcomings. In a nutshell,
        // due to the inability for our .rlib crate to contribute linker arguments
        // (or even just an rpath!) to our consumers, any resulting binaries will
        // fail to run unless loaded into a process that already has the core loaded.
        //
        // For plugins this restriction is fine as they'll only be loaded by the core;
        // headless binaries on the other hand (consider `cargo test`, too!) will fail
        // because libbinaryninjacore is not in the library path on pretty much any
        // system anywhere. If only we could trick the linker into linking with an
        // absolute path...
        //
        // LOOK ON MY WORKS, YE MIGHTY, AND DESPAIR
        //
        // We build a simple do-nothing library called liblinkhack and add it as a
        // native dependency. Crucially, we ensure that LC_ID_DYLIB (macos) or DT_SONAME
        // (linux) is set to the absolute path of libbinaryninjacore. This has the effect
        // that any binary attempting to link with liblinkhack will have its dependency
        // on liblinkhack recorded as the path to the binaryninja core. Later on, the
        // actual core will get linked and that dependency will be recorded in the normal
        // way.
        //
        // tl;dr we're linking against a fake, shim library that actually results in
        // the binaryninja core getting linked twice, once with an absolute path and once
        // correctly. yes, this is as horrifying as you think it is. no, there is no other
        // way to make `cargo test` work.
        //
        // I'm not happy about it either.

        #[cfg(target_os = "macos")]
        Command::new("clang")
            .args(&["-Wl,-dylib", "-o"])
            .arg(&format!("{}/liblinkhack.dylib", out_dir))
            .arg(&format!(
                "-Wl,-install_name,{}/libbinaryninjacore.dylib",
                &link_path.to_str().unwrap()
            ))
            .arg(&format!(
                "{}/linkhack/linkhack.c",
                env::var("CARGO_MANIFEST_DIR").unwrap()
            ))
            .status()
            .unwrap();

        #[cfg(target_os = "linux")]
        {
            Command::new("gcc")
                .args(&["-shared", "-o"])
                .arg(&format!("{}/liblinkhack.so", out_dir))
                .arg(&format!(
                    "-Wl,-soname,{}libbinaryninjacore.so.1",
                    &link_path.to_str().unwrap()
                )) // TODO : Check mac to see if I need to remove the extra slash as well
                .arg(&format!(
                    "{}/linkhack/linkhack.c",
                    env::var("CARGO_MANIFEST_DIR").unwrap()
                ))
                .status()
                .unwrap();

            // Linux builds of binaryninja ship with libbinaryninjacore.so.1 in the
            // application folder and no symlink. The linker will attempt to link with
            // libbinaryninjacore.so. Since this is likely going to fail, we detect this
            // ahead of time and create an appropriately named symlink inside of OUT_DIR
            // and add it to the library search path.
            let symlink_target = PathBuf::from(&out_dir).join("libbinaryninjacore.so");
            if !link_path.join("libbinaryninjacore.so").exists() && !symlink_target.exists() {
                use std::os::unix::fs;
                fs::symlink(
                    link_path.join("libbinaryninjacore.so.1"),
                    PathBuf::from(&out_dir).join("libbinaryninjacore.so"),
                )
                .expect("failed to create required symlink");
            }
        }

        println!("cargo:rustc-link-lib=linkhack");
        println!("cargo:rustc-link-search={}", out_dir);
    }

    #[cfg(any(not(target_os = "linux"), feature = "headless"))]
    {
        println!("cargo:rustc-link-lib=binaryninjacore");
        println!("cargo:rustc-link-search={}", link_path.to_str().unwrap());
    }

    #[warn(unused_assignments)]
    let mut is_mac = false;
    #[cfg(target_os = "macos")]
    {
        is_mac = true;
    }

    // Difference between global LLVM/Clang install and custom LLVM/Clang install...
    //  First option is for the build server, second option is being nice to our dev who have `LLVM_INSTALL_DIR` set, third is for people with "normal" setups (and Macs)
    let bindings;
    if let (false, Ok(llvm_dir), Ok(llvm_version)) = (is_mac, llvm_dir, llvm_version) {
        let llvm_include_path = format!("-I{}/clang/{}/include", llvm_dir, llvm_version);
        bindings = bindgen::builder()
            .header("../../binaryninjacore.h")
            .clang_arg("-std=c++17")
            .clang_arg("-x")
            .clang_arg("c++")
            .clang_arg(llvm_include_path)
            .size_t_is_usize(true)
            .generate_comments(false)
            .whitelist_function("BN.*")
            .whitelist_var("BN_CURRENT_CORE_ABI_VERSION")
            .whitelist_var("BN_MINIMUM_CORE_ABI_VERSION")
            .rustified_enum("BN.*")
            .generate()
            .expect("Unable to generate bindings");
    } else if let (false, Ok(llvm_install_dir)) = (is_mac, llvm_install_dir) {
        let llvm_include_path = format!("-I{}/11.0.0/lib/clang/11.0.0/include", llvm_install_dir);
        env::set_var("LIBCLANG_PATH", format!("{}/11.0.0/lib", llvm_install_dir));
        bindings = bindgen::builder()
            .header("../../binaryninjacore.h")
            .clang_arg("-std=c++17")
            .clang_arg("-x")
            .clang_arg("c++")
            .clang_arg(llvm_include_path)
            .size_t_is_usize(true)
            .generate_comments(false)
            .whitelist_function("BN.*")
            .whitelist_var("BN_CURRENT_CORE_ABI_VERSION")
            .whitelist_var("BN_MINIMUM_CORE_ABI_VERSION")
            .rustified_enum("BN.*")
            .generate()
            .expect("Unable to generate bindings");
    } else {
        bindings = bindgen::builder()
            .header("../../binaryninjacore.h")
            .clang_arg("-std=c++17")
            .clang_arg("-x")
            .clang_arg("c++")
            .size_t_is_usize(true)
            .generate_comments(false)
            .whitelist_function("BN.*")
            .whitelist_var("BN_CURRENT_CORE_ABI_VERSION")
            .whitelist_var("BN_MINIMUM_CORE_ABI_VERSION")
            .rustified_enum("BN.*")
            .generate()
            .expect("Unable to generate bindings");
    }

    bindings
        .write_to_file(PathBuf::from(out_dir).join("bindings.rs"))
        .expect("Couldn't write bindings!");
}
<|endoftext|>


<commit_before>extern crate dynamic_reload;

fn main() {

}
<commit_msg>Implemented working example<commit_after>extern crate dynamic_reload;

use dynamic_reload::{DynamicReload, Lib, Symbol, Search, PlatformName, UpdateState};
use std::rc::Rc;
use std::time::Duration;
use std::thread;

struct Plugins {
    plugins: Vec<Rc<Lib>>,
}

impl Plugins {
    fn add_plugin(&mut self, plugin: &Rc<Lib>) {
        self.plugins.push(plugin.clone());
    }

    fn unload_plugins(&mut self, lib: &Rc<Lib>) {
        for i in (0..self.plugins.len()).rev() {
            if self.plugins[i].original_path == lib.original_path {
                self.plugins.swap_remove(i);
            }
        }
    }

    fn reload_plugin(&mut self, lib: &Rc<Lib>) {
        Self::add_plugin(self, lib);
    }

    // called when a lib needs to be reloaded.
    fn reload_callback(&mut self, state: UpdateState, lib: Option<&Rc<Lib>>) {
        match state {
            UpdateState::Before => Self::unload_plugins(self, lib.unwrap()),
            UpdateState::After => Self::reload_plugin(self, lib.unwrap()),
            UpdateState::ReloadFalied => println!("Failed to reload"),
        }
    }
}

fn main() {
    let mut plugin_handler = Plugins { plugins: Vec::new() };

    // Setup the reload handler. A temporary directory will be created inside the target/debug
    // where plugins will be loaded from. That is because on some OS:es loading a shared lib
    // will lock the file so we can't overwrite it so this works around that issue.
    let mut reload_handler = DynamicReload::new(Some(vec!["target/debug"]),
                                                Some("target/debug"),
                                                Search::Default);

    // test_shared is generated in build.rs
    match reload_handler.add_library("test_shared", PlatformName::Yes) {
        Ok(lib) => plugin_handler.add_plugin(&lib),
        Err(e) => {
            println!("Unable to load dynamic lib, err {:?}", e);
            return;
        }
    }

    // While this is running (printing a constant number) change return value in file src/test_shared.rs
    // build the project with cargo build and notice that this code will now return the new value
    loop {
        reload_handler.update(Plugins::reload_callback, &mut plugin_handler);

        if plugin_handler.plugins.len() > 0 {
            // In a real program you want to cache the symbol and not do it every time if your
            // application is performance critical
            let fun: Symbol<extern "C" fn() -> i32> = unsafe {
                plugin_handler.plugins[0].lib.get(b"shared_fun\0").unwrap()
            };

            println!("Value {}", fun());
        }

        // Wait for 0.5 sec
        thread::sleep(Duration::from_millis(500));
    }
}
<|endoftext|>


<commit_before>#[macro_use] // for the hlist macro
extern crate frunk;
extern crate frunk_core;

#[derive(Generic, Debug, PartialEq)]
struct Person<'a> {
    first_name: &'a str,
    last_name: &'a str,
    age: usize,
}

fn main() {
    let h = hlist!("Joe", "Blow", 30);
    let p: Person = frunk::from_generic(h);
    assert_eq!(
        p,
        Person {
            first_name: "Joe",
            last_name: "Blow",
            age: 30,
        }
    );
    println!("{}", p.first_name);
}
<commit_msg>add usage example for map_repr.<commit_after>#[macro_use] // for the hlist macro
extern crate frunk;
extern crate frunk_core;

#[derive(Generic, Debug, PartialEq)]
struct Person<'a> {
    first_name: &'a str,
    last_name: &'a str,
    age: usize,
}

fn main() {
    let repr = hlist!("Joe", "Blow", 30);
    let person: Person = frunk::from_generic(repr);
    assert_eq!(
        person,
        Person {
            first_name: "Joe",
            last_name: "Blow",
            age: 30,
        }
    );
    println!("{}", person.first_name);

    let older_person = frunk::map_repr(person, |repr| {
        let hlist_pat![first, last, age] = repr;
        hlist![first, last, age * 3]
    });
    assert_eq!(older_person.age, 90);
}
<|endoftext|>


<commit_before>struct Person<'a> {
    name: &'static str,
    parent: Option<&'a Person<'a>>,
}

impl<'a> Person<'a> {
    fn new(name: &'static str, parent: Option<&'a Person<'a>>) -> Person<'a> {
        Person{name: name, parent: parent}
    }

    fn parents_name(&self) -> Option<&'static str> {
        match self.parent {
            Some(p) => Some(p.name),
            None => None,
        }
    }
}

#[test]
fn it_works() {
    let jane = Person::new("Jane", None);
    let tom = Person::new("Tom", Some(&jane));

    assert_eq!(tom.name, "Tom");
    assert_eq!(jane.name, "Jane");
    assert_eq!(tom.parent.unwrap().name, "Jane");
    assert_eq!(tom.parents_name(), Some("Jane"));
    assert_eq!(jane.parents_name(), None);
}

// - We are making a promise to the compiler that all of these things live for atleast the same scope.
// - We are not asking the compiler to "create a lifetime". We are just telling it to complain if we
//   don't do what we say we are doing.
// - Why? Because this allows Rust to ensure we cannot cause common memory allocation bugs. It does
//   this at compile time. It's a zero-cost abstraction because there is no runtime penalty.
// - It makes code look "uglier". But this is the wrong mindset for writing systems-level programs.
//   The emphasis here is on safety, not expressiveness.
// - Question: Why can't Rust ensure/infer/elide this scenario? Surely any reference to a Parent
//   must *always* live for the same or a bigger scope???
//   - There is an open RFC for this
//   - It may be complex to implement and/or slow down compilation
//   - Eliding in more cases may prevent newcomer Rust programmers from ever encountering
//     lifetimes, which could have a negative impact in the long run. Pedagogy!
<commit_msg>Added function that takes reference and returns reference<commit_after>struct Person<'a> {
    name: &'static str,
    parent: Option<&'a Person<'a>>,
}

impl<'a> Person<'a> {
    fn new(name: &'static str, parent: Option<&'a Person<'a>>) -> Person<'a> {
        Person{name: name, parent: parent}
    }

    fn parents_name(&self) -> Option<&'static str> {
        match self.parent {
            Some(p) => Some(p.name),
            None => None,
        }
    }
}

fn first_five<'a>(value: &'a String) -> &'a str {
    &value[..5]
}

#[test]
fn it_works() {
    let jane = Person::new("Jane", None);
    let tom = Person::new("Tom", Some(&jane));
    let name = "Andrew".to_owned();

    assert_eq!(first_five(&name), "Andre");

    assert_eq!(tom.name, "Tom");
    assert_eq!(jane.name, "Jane");
    assert_eq!(tom.parent.unwrap().name, "Jane");
    assert_eq!(tom.parents_name(), Some("Jane"));
    assert_eq!(jane.parents_name(), None);
}

// - We are making a promise to the compiler that all of these things live for atleast the same scope.
// - We are not asking the compiler to "create a lifetime". We are just telling it to complain if we
//   don't do what we say we are doing.
// - Why? Because this allows Rust to ensure we cannot cause common memory allocation bugs. It does
//   this at compile time. It's a zero-cost abstraction because there is no runtime penalty.
// - It makes code look "uglier". But this is the wrong mindset for writing systems-level programs.
//   The emphasis here is on safety, not expressiveness.
// - Question: Why can't Rust ensure/infer/elide this scenario? Surely any reference to a Parent
//   must *always* live for the same or a bigger scope???
//   - There is an open RFC for this
//   - It may be complex to implement and/or slow down compilation
//   - Eliding in more cases may prevent newcomer Rust programmers from ever encountering
//     lifetimes, which could have a negative impact in the long run. Pedagogy!
<|endoftext|>