<commit_before>use ga::{self, Tensor};
use ga::tensor::TensorMode;

use super::graph::Node;
use super::var_store::{VarIndex, VarStore};

pub trait Operation : 'static {
    fn forward(&mut self, &ga::Context, &VarStore, &Node);
    fn backward(&mut self, &ga::Context, &VarStore, &Node);
}

pub trait OpBuilder {
    type Op: Operation;

    fn build(&self, ctx: &ga::Context, v: &VarStore)
             -> Result<OpDescriptor<Self::Op>, String>;
}

pub struct OpDescriptor<T: Operation> {
    pub op: T,
    pub inputs: Vec<VarIndex>,
    pub out_shapes: Vec<Vec<usize>>,
}

////////////////////////////////////////////////////////////////////////////////////////////////////

pub struct MatMul(pub VarIndex, pub VarIndex);

impl OpBuilder for MatMul {
    type Op = MatMulImpl;

    fn build(&self, ctx: &ga::Context, v: &VarStore)
             -> Result<OpDescriptor<MatMulImpl>, String> {
        let a = &v.get(self.0);
        let b = &v.get(self.1);
        Ok(OpDescriptor {
            op: MatMulImpl::new(ctx, a.shape().to_vec(), b.shape().to_vec()),
            inputs: vec![self.0, self.1],
            out_shapes: vec![vec![a.shape()[0], b.shape()[1]]],
        })
    }
}

pub struct MatMulImpl {
    a_t: Tensor<f32>,
    b_t: Tensor<f32>,
}

impl MatMulImpl {
    pub fn new(ctx: &ga::Context, a_shape: Vec<usize>, b_shape: Vec<usize>) -> Self {
        MatMulImpl {
            a_t: Tensor::new(ctx, vec![a_shape[1], a_shape[0]], TensorMode::Mut),
            b_t: Tensor::new(ctx, vec![b_shape[1], b_shape[0]], TensorMode::Mut),
        }
    }
}

impl Operation for MatMulImpl {
    fn forward(&mut self, ctx: &ga::Context, v: &VarStore, n: &Node) {
        let a = &v.get(n.inputs[0]);
        let b = &v.get(n.inputs[1]);
        let c = &v.get(n.outputs[0]);
        ga::matmul(ctx, a, b, c); // c = a*b
    }

    fn backward(&mut self, ctx: &ga::Context, v: &VarStore, n: &Node) {
        let a = &v.get(n.inputs[0]);
        let b = &v.get(n.inputs[1]);
        let a_d = &v.get(n.in_grad[0]);
        let b_d = &v.get(n.in_grad[1]);
        let g = &v.get(n.out_grad[0].get());

        // Derivative with respect to first input
        // a_d = g*b_t
        ga::transpose(ctx, b, &self.b_t);
        ga::matmul(ctx, g, &self.b_t, a_d);

        // Derivative with respect to second input
        // b_d = a_t*g
        ga::transpose(ctx, a, &self.a_t);
        ga::matmul(ctx, &self.a_t, g, b_d);
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

pub struct Add(pub VarIndex, pub VarIndex, pub i32);

impl OpBuilder for Add {
    type Op = AddImpl;

    fn build(&self, _: &ga::Context, v: &VarStore)
             -> Result<OpDescriptor<AddImpl>, String> {
        let a = &v.get(self.0);
        let b = &v.get(self.1);
        let add_axis = self.2;
        match add_axis {
            -1 => {
                if a.shape() != b.shape() {
                    return Err("DIM ERROR: Shapes must be equal for Add".to_string());
                }
            },
            0 => {
                if b.shape()[0] != 1 || a.shape()[1] != b.shape()[1] {
                    return Err(format!("DIM ERROR: Shapes must be [M, N] and [1, N]
                                       (got {:?} and {:?}) for Add with broadcast axis of 0",
                                       a.shape(), b.shape()));
                }
            },
            1 => {
                if b.shape()[1] != 1 || a.shape()[0] != b.shape()[0] {
                    return Err(format!("DIM ERROR: Shapes must be [M, N] and [M, 1]
                                       (got {:?} and {:?}) for Add with broadcast axis of 1",
                                       a.shape(), b.shape()));
                }
            },
            _ => {
                return Err(format!("BROADCAST AXIS ERROR: Invalid broadcast axis {}", add_axis));
            }
        }
        Ok(OpDescriptor {
            op: AddImpl::new(add_axis),
            inputs: vec![self.0, self.1],
            out_shapes: vec![a.shape().to_vec()]
        })
    }
}

pub struct AddImpl {
    axis: i32,
}

impl AddImpl {
    pub fn new(axis: i32) -> Self {
        AddImpl {
            axis: axis,
        }
    }
}

impl Operation for AddImpl {
    fn forward(&mut self, ctx: &ga::Context, v: &VarStore, n: &Node) {
        let a = &v.get(n.inputs[0]);
        let b = &v.get(n.inputs[1]);
        let c = &v.get(n.outputs[0]);
        ga::add(ctx, a, self.axis, b, c); // c = a+b
    }

    fn backward(&mut self, ctx: &ga::Context, v: &VarStore, n: &Node) {
        let a_d = &v.get(n.in_grad[0]);
        let b_d = &v.get(n.in_grad[1]);
        let g = &v.get(n.out_grad[0].get());
        ga::copy_to(ctx, g, a_d);
        ga::sum(ctx, g, self.axis as usize, b_d);
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

pub struct Relu(pub VarIndex);

impl OpBuilder for Relu {
    type Op = ReluImpl;

    fn build(&self, _: &ga::Context, v: &VarStore)
             -> Result<OpDescriptor<ReluImpl>, String> {
        let a = &v.get(self.0);
        Ok(OpDescriptor {
            op: ReluImpl,
            inputs: vec![self.0],
            out_shapes: vec![a.shape().to_vec()],
        })
    }
}

pub struct ReluImpl;

impl Operation for ReluImpl {
    fn forward(&mut self, ctx: &ga::Context, v: &VarStore, n: &Node) {
        let a = &v.get(n.inputs[0]);
        let b = &v.get(n.outputs[0]);
        ga::max(ctx, a, 0.0, b); // b = max(0, a)
    }

    fn backward(&mut self, ctx: &ga::Context, v: &VarStore, n: &Node) {
        let a = &v.get(n.inputs[0]);
        let a_d = &v.get(n.in_grad[0]);
        let g = &v.get(n.out_grad[0].get());
        ga::dmax(ctx, a, 0.0, a_d);
        ga::multiply(ctx, g, -1, a_d, a_d);
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

pub struct Mse(pub VarIndex, pub VarIndex);

impl OpBuilder for Mse {
    type Op = MseImpl;

    fn build(&self, _: &ga::Context, v: &VarStore)
             -> Result<OpDescriptor<MseImpl>, String> {
        let a = &v.get(self.0);
        let b = &v.get(self.1);
        if a.shape() != b.shape() {
            return Err("DIM ERROR: Shapes must be equal for MSE".to_string());
        }
        Ok(OpDescriptor {
            op: MseImpl,
            inputs: vec![self.0, self.1],
            out_shapes: vec![a.shape().to_vec()],
        })
    }
}

pub struct MseImpl;

impl Operation for MseImpl {
    fn forward(&mut self, ctx: &ga::Context, v: &VarStore, n: &Node) {
        let h = &v.get(n.inputs[0]); // predictions
        let y = &v.get(n.inputs[1]); // training output
        let out = &v.get(n.outputs[0]);
        ga::mse(ctx, h, y, out); // out = mse(h, y)
    }

    fn backward(&mut self, ctx: &ga::Context, v: &VarStore, n: &Node) {
        let h = &v.get(n.inputs[0]); // predictions
        let h_d = &v.get(n.in_grad[0]);
        let y = &v.get(n.inputs[1]); // training output
        let g = &v.get(n.out_grad[0].get());
        ga::dmse(ctx, h, y, h_d); // h_d = dmse(h, y)
        ga::multiply(ctx, h_d, 0, g, h_d); // h_d = g*h_d
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

// Lstm(input, state)
/*pub struct Lstm(pub VarIndex, pub VarIndex, usize);

impl OpBuilder for Lstm {
    type Op = LstmImpl;

    fn build(&self, ctx: &ga::Context, v: &VarStore)
             -> Result<OpDescriptor<LstmImpl>, String> {
        let x = &v.get(self.0);
        let s = &v.get(self.1);
        let seq_len = x.shape()[0];
        let batch_size = x.shape()[1];
        let input_size = x.shape()[2];
        let hidden_size = self.2;
        if x.shape() != s.shape() {
            return Err("DIM ERROR: Shapes must be equal for LSTM".to_string());
        }
        Ok(OpDescriptor {
            op: LstmImpl::new(ctx, seq_len, batch_size, input_size, hidden_size),
            inputs: vec![self.0, self.1],
            out_shapes: vec![x.shape().to_vec()],
        })
    }
}

pub struct LstmImpl {
    ifog: ga::Tensor<f32>, // input, forget, output, gate (IFOG): input sums
    ifog_f: ga::Tensor<f32>, // input, forget, output, gate: activations
    c: ga::Tensor<f32>,

    // Recurrent connections from last sequence
    c0: ga::Tensor<f32>,
    h0: ga::Tensor<f32>,

    seq_len: usize,
    batch_size: usize,
    input_size: usize,
    hidden_size: usize,
}

impl LstmImpl {
    fn new(ctx: &ga::Context,
           seq_len: usize,
           batch_size: usize,
           input_size: usize,
           hidden_size: usize) -> Self {
        let n = seq_len;
        let b = batch_size;
        let d = hidden_size;
        LstmImpl {
            ifog: Tensor::new(ctx, vec![n, b, d*4], TensorMode::Mut),
            ifog_f: Tensor::new(ctx, vec![n, b, d*4], TensorMode::Mut),
            c: Tensor::new(ctx, vec![n, b, d], TensorMode::Mut),

            c0: Tensor::new(ctx, vec![b, d], TensorMode::Mut),
            h0: Tensor::new(ctx, vec![b, d], TensorMode::Mut),

            seq_len: seq_len,
            batch_size: batch_size,
            input_size: input_size,
            hidden_size: hidden_size,
        }
    }
}

impl Operation for LstmImpl {
    fn forward(&mut self, ctx: &ga::Context, v: &VarStore, node: &Node) {
        let n = self.seq_len;
        let b = self.batch_size;
        let d = self.hidden_size;
        let i = self.input_size;

        let x = &v.get(node.inputs[0]); // input
        let wlstm = &v.get(node.inputs[1]); // all of the weights for all the cells

        // recurrent connections
        let ref c0 = self.c0;
        let ref h0 = self.h0;

        let ref ifog = self.ifog;
        let ref ifog_f = self.ifog_f;
        let ref c = self.c;

        let c_f = &v.get(node.outputs[0]); // cell
        let h = &v.get(node.outputs[1]); // output

        for t in 0..self.seq_len {
            // Output from last time step
            let ref prevh = if t > 0 { h.slice(s![t-1]) } else { h0 };
            // Input
            ga::fill(h_in.slice(s![t, .., 0]), 1.0); // bias
            ga::copy_slice(ctx, x.slice(s![t]), h_in.slice(s![t, .., 1..i+1]));
            ga::copy_slice(ctx, prevh, h_in.slice(s![t, .., i+1..]));
            // Multiply inputs and weights, and add biases; all in one dot product!
            ga::matmul(ctx, h_in, wlstm, ifog.slice(s![t]));
            // Compute internal activations
            ga::sigmoid(ctx, ifog.slice(s![t, .., ..3*d]), ifog_f.slice(s![t, .., ..3*d])); // sigmoids; these are the gates
            ga::tanh(ctx, ifog.slice(s![t, .., 3*d..]), ifog_f.slice(s![t, .., 3*d..])); // tanh
            // compute the LSTM cell activation
            let ref prevc = if t > 0 { c.slice(s![t-1]) } else { c0 };
            c.slice(s![t]) = ifog_f.slice(s![t, .., ..d]) * ifog_f.slice(s![t, .., 3*d..]) + ifog_f.slice(s![t, .., d..2*d]) * prevc
            ga::tanh(ctx, c.slice(s![t]), c_f.slice(s![t]));
            ga::multiply(ctx, ifog_f.slice(s![t, .., 2*d..3*d]), c_f.slice(s![t]), h.slice(s![t]));
        }
    }

    fn backward(&mut self, ctx: &ga::Context, v: &VarStore, n: &Node) {
    }
}*/
<commit_msg>Shape check for MatMul<commit_after>use ga::{self, Tensor};
use ga::tensor::TensorMode;

use super::graph::Node;
use super::var_store::{VarIndex, VarStore};

pub trait Operation : 'static {
    fn forward(&mut self, &ga::Context, &VarStore, &Node);
    fn backward(&mut self, &ga::Context, &VarStore, &Node);
}

pub trait OpBuilder {
    type Op: Operation;

    fn build(&self, ctx: &ga::Context, v: &VarStore)
             -> Result<OpDescriptor<Self::Op>, String>;
}

pub struct OpDescriptor<T: Operation> {
    pub op: T,
    pub inputs: Vec<VarIndex>,
    pub out_shapes: Vec<Vec<usize>>,
}

////////////////////////////////////////////////////////////////////////////////////////////////////

pub struct MatMul(pub VarIndex, pub VarIndex);

impl OpBuilder for MatMul {
    type Op = MatMulImpl;

    fn build(&self, ctx: &ga::Context, v: &VarStore)
             -> Result<OpDescriptor<MatMulImpl>, String> {
        let a = &v.get(self.0);
        let b = &v.get(self.1);
        if a.shape()[1] != b.shape()[0] {
            return Err(format!("DIM ERROR: Shapes must be of form [I, J] and [J, K]
                                (got {:?} and {:?}) for MatMul",
                               a.shape(), b.shape()));
        }
        Ok(OpDescriptor {
            op: MatMulImpl::new(ctx, a.shape().to_vec(), b.shape().to_vec()),
            inputs: vec![self.0, self.1],
            out_shapes: vec![vec![a.shape()[0], b.shape()[1]]],
        })
    }
}

pub struct MatMulImpl {
    a_t: Tensor<f32>,
    b_t: Tensor<f32>,
}

impl MatMulImpl {
    pub fn new(ctx: &ga::Context, a_shape: Vec<usize>, b_shape: Vec<usize>) -> Self {
        MatMulImpl {
            a_t: Tensor::new(ctx, vec![a_shape[1], a_shape[0]], TensorMode::Mut),
            b_t: Tensor::new(ctx, vec![b_shape[1], b_shape[0]], TensorMode::Mut),
        }
    }
}

impl Operation for MatMulImpl {
    fn forward(&mut self, ctx: &ga::Context, v: &VarStore, n: &Node) {
        let a = &v.get(n.inputs[0]);
        let b = &v.get(n.inputs[1]);
        let c = &v.get(n.outputs[0]);
        ga::matmul(ctx, a, b, c); // c = a*b
    }

    fn backward(&mut self, ctx: &ga::Context, v: &VarStore, n: &Node) {
        let a = &v.get(n.inputs[0]);
        let b = &v.get(n.inputs[1]);
        let a_d = &v.get(n.in_grad[0]);
        let b_d = &v.get(n.in_grad[1]);
        let g = &v.get(n.out_grad[0].get());

        // Derivative with respect to first input
        // a_d = g*b_t
        ga::transpose(ctx, b, &self.b_t);
        ga::matmul(ctx, g, &self.b_t, a_d);

        // Derivative with respect to second input
        // b_d = a_t*g
        ga::transpose(ctx, a, &self.a_t);
        ga::matmul(ctx, &self.a_t, g, b_d);
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

pub struct Add(pub VarIndex, pub VarIndex, pub i32);

impl OpBuilder for Add {
    type Op = AddImpl;

    fn build(&self, _: &ga::Context, v: &VarStore)
             -> Result<OpDescriptor<AddImpl>, String> {
        let a = &v.get(self.0);
        let b = &v.get(self.1);
        let add_axis = self.2;
        match add_axis {
            -1 => {
                if a.shape() != b.shape() {
                    return Err("DIM ERROR: Shapes must be equal for Add".to_string());
                }
            },
            0 => {
                if b.shape()[0] != 1 || a.shape()[1] != b.shape()[1] {
                    return Err(format!("DIM ERROR: Shapes must be [M, N] and [1, N]
                                        (got {:?} and {:?}) for Add with broadcast axis of 0",
                                       a.shape(), b.shape()));
                }
            },
            1 => {
                if b.shape()[1] != 1 || a.shape()[0] != b.shape()[0] {
                    return Err(format!("DIM ERROR: Shapes must be [M, N] and [M, 1]
                                        (got {:?} and {:?}) for Add with broadcast axis of 1",
                                       a.shape(), b.shape()));
                }
            },
            _ => {
                return Err(format!("BROADCAST AXIS ERROR: Invalid broadcast axis {}", add_axis));
            }
        }
        Ok(OpDescriptor {
            op: AddImpl::new(add_axis),
            inputs: vec![self.0, self.1],
            out_shapes: vec![a.shape().to_vec()]
        })
    }
}

pub struct AddImpl {
    axis: i32,
}

impl AddImpl {
    pub fn new(axis: i32) -> Self {
        AddImpl {
            axis: axis,
        }
    }
}

impl Operation for AddImpl {
    fn forward(&mut self, ctx: &ga::Context, v: &VarStore, n: &Node) {
        let a = &v.get(n.inputs[0]);
        let b = &v.get(n.inputs[1]);
        let c = &v.get(n.outputs[0]);
        ga::add(ctx, a, self.axis, b, c); // c = a+b
    }

    fn backward(&mut self, ctx: &ga::Context, v: &VarStore, n: &Node) {
        let a_d = &v.get(n.in_grad[0]);
        let b_d = &v.get(n.in_grad[1]);
        let g = &v.get(n.out_grad[0].get());
        ga::copy_to(ctx, g, a_d);
        ga::sum(ctx, g, self.axis as usize, b_d);
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

pub struct Relu(pub VarIndex);

impl OpBuilder for Relu {
    type Op = ReluImpl;

    fn build(&self, _: &ga::Context, v: &VarStore)
             -> Result<OpDescriptor<ReluImpl>, String> {
        let a = &v.get(self.0);
        Ok(OpDescriptor {
            op: ReluImpl,
            inputs: vec![self.0],
            out_shapes: vec![a.shape().to_vec()],
        })
    }
}

pub struct ReluImpl;

impl Operation for ReluImpl {
    fn forward(&mut self, ctx: &ga::Context, v: &VarStore, n: &Node) {
        let a = &v.get(n.inputs[0]);
        let b = &v.get(n.outputs[0]);
        ga::max(ctx, a, 0.0, b); // b = max(0, a)
    }

    fn backward(&mut self, ctx: &ga::Context, v: &VarStore, n: &Node) {
        let a = &v.get(n.inputs[0]);
        let a_d = &v.get(n.in_grad[0]);
        let g = &v.get(n.out_grad[0].get());
        ga::dmax(ctx, a, 0.0, a_d);
        ga::multiply(ctx, g, -1, a_d, a_d);
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

pub struct Mse(pub VarIndex, pub VarIndex);

impl OpBuilder for Mse {
    type Op = MseImpl;

    fn build(&self, _: &ga::Context, v: &VarStore)
             -> Result<OpDescriptor<MseImpl>, String> {
        let a = &v.get(self.0);
        let b = &v.get(self.1);
        if a.shape() != b.shape() {
            return Err("DIM ERROR: Shapes must be equal for MSE".to_string());
        }
        Ok(OpDescriptor {
            op: MseImpl,
            inputs: vec![self.0, self.1],
            out_shapes: vec![a.shape().to_vec()],
        })
    }
}

pub struct MseImpl;

impl Operation for MseImpl {
    fn forward(&mut self, ctx: &ga::Context, v: &VarStore, n: &Node) {
        let h = &v.get(n.inputs[0]); // predictions
        let y = &v.get(n.inputs[1]); // training output
        let out = &v.get(n.outputs[0]);
        ga::mse(ctx, h, y, out); // out = mse(h, y)
    }

    fn backward(&mut self, ctx: &ga::Context, v: &VarStore, n: &Node) {
        let h = &v.get(n.inputs[0]); // predictions
        let h_d = &v.get(n.in_grad[0]);
        let y = &v.get(n.inputs[1]); // training output
        let g = &v.get(n.out_grad[0].get());
        ga::dmse(ctx, h, y, h_d); // h_d = dmse(h, y)
        ga::multiply(ctx, h_d, 0, g, h_d); // h_d = g*h_d
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////

// Lstm(input, state)
/*pub struct Lstm(pub VarIndex, pub VarIndex, usize);

impl OpBuilder for Lstm {
    type Op = LstmImpl;

    fn build(&self, ctx: &ga::Context, v: &VarStore)
             -> Result<OpDescriptor<LstmImpl>, String> {
        let x = &v.get(self.0);
        let s = &v.get(self.1);
        let seq_len = x.shape()[0];
        let batch_size = x.shape()[1];
        let input_size = x.shape()[2];
        let hidden_size = self.2;
        if x.shape() != s.shape() {
            return Err("DIM ERROR: Shapes must be equal for LSTM".to_string());
        }
        Ok(OpDescriptor {
            op: LstmImpl::new(ctx, seq_len, batch_size, input_size, hidden_size),
            inputs: vec![self.0, self.1],
            out_shapes: vec![x.shape().to_vec()],
        })
    }
}

pub struct LstmImpl {
    ifog: ga::Tensor<f32>, // input, forget, output, gate (IFOG): input sums
    ifog_f: ga::Tensor<f32>, // input, forget, output, gate: activations
    c: ga::Tensor<f32>,

    // Recurrent connections from last sequence
    c0: ga::Tensor<f32>,
    h0: ga::Tensor<f32>,

    seq_len: usize,
    batch_size: usize,
    input_size: usize,
    hidden_size: usize,
}

impl LstmImpl {
    fn new(ctx: &ga::Context,
           seq_len: usize,
           batch_size: usize,
           input_size: usize,
           hidden_size: usize) -> Self {
        let n = seq_len;
        let b = batch_size;
        let d = hidden_size;
        LstmImpl {
            ifog: Tensor::new(ctx, vec![n, b, d*4], TensorMode::Mut),
            ifog_f: Tensor::new(ctx, vec![n, b, d*4], TensorMode::Mut),
            c: Tensor::new(ctx, vec![n, b, d], TensorMode::Mut),

            c0: Tensor::new(ctx, vec![b, d], TensorMode::Mut),
            h0: Tensor::new(ctx, vec![b, d], TensorMode::Mut),

            seq_len: seq_len,
            batch_size: batch_size,
            input_size: input_size,
            hidden_size: hidden_size,
        }
    }
}

impl Operation for LstmImpl {
    fn forward(&mut self, ctx: &ga::Context, v: &VarStore, node: &Node) {
        let n = self.seq_len;
        let b = self.batch_size;
        let d = self.hidden_size;
        let i = self.input_size;

        let x = &v.get(node.inputs[0]); // input
        let wlstm = &v.get(node.inputs[1]); // all of the weights for all the cells

        // recurrent connections
        let ref c0 = self.c0;
        let ref h0 = self.h0;

        let ref ifog = self.ifog;
        let ref ifog_f = self.ifog_f;
        let ref c = self.c;

        let c_f = &v.get(node.outputs[0]); // cell
        let h = &v.get(node.outputs[1]); // output

        for t in 0..self.seq_len {
            // Output from last time step
            let ref prevh = if t > 0 { h.slice(s![t-1]) } else { h0 };
            // Input
            ga::fill(h_in.slice(s![t, .., 0]), 1.0); // bias
            ga::copy_slice(ctx, x.slice(s![t]), h_in.slice(s![t, .., 1..i+1]));
            ga::copy_slice(ctx, prevh, h_in.slice(s![t, .., i+1..]));
            // Multiply inputs and weights, and add biases; all in one dot product!
            ga::matmul(ctx, h_in, wlstm, ifog.slice(s![t]));
            // Compute internal activations
            ga::sigmoid(ctx, ifog.slice(s![t, .., ..3*d]), ifog_f.slice(s![t, .., ..3*d])); // sigmoids; these are the gates
            ga::tanh(ctx, ifog.slice(s![t, .., 3*d..]), ifog_f.slice(s![t, .., 3*d..])); // tanh
            // compute the LSTM cell activation
            let ref prevc = if t > 0 { c.slice(s![t-1]) } else { c0 };
            c.slice(s![t]) = ifog_f.slice(s![t, .., ..d]) * ifog_f.slice(s![t, .., 3*d..]) + ifog_f.slice(s![t, .., d..2*d]) * prevc
            ga::tanh(ctx, c.slice(s![t]), c_f.slice(s![t]));
            ga::multiply(ctx, ifog_f.slice(s![t, .., 2*d..3*d]), c_f.slice(s![t]), h.slice(s![t]));
        }
    }

    fn backward(&mut self, ctx: &ga::Context, v: &VarStore, n: &Node) {
    }
}*/
<|endoftext|>


<commit_before>//!# Find the last box of a list.
//!# example
///```
///use p99::p1::my_last;
///assert_eq!(my_last(&['a','b','c','d']),Some(['d']))
///```

pub fn my_last(list: &[char]) -> Option<[char; 1]> {
    if list.len() > 0{
        Some([list[list.len()-1]])
    }
    else{
        None
    }
}

<commit_msg>add more tests<commit_after>//!# Find the last box of a list.
//!# example
///```
///use p99::p1::my_last;
///assert_eq!(my_last(&['a','b','c','d']),Some(['d']));
///assert_eq!(my_last(&['d']),Some(['d']));
///assert_eq!(my_last(&[]),None);
///```

pub fn my_last(list: &[char]) -> Option<[char; 1]> {
    if list.len() > 0{
        Some([list[list.len()-1]])
    }
    else{
        None
    }
}

<|endoftext|>


<commit_before>//! Volume Groups

use std::io::Result;
use std::io::Error;
use std::io::ErrorKind::Other;
use std::collections::btree_map::BTreeMap;

use uuid::Uuid;
use time::now;
use nix;

use lv::{LV, Segment};
use pv::PV;
use parser::{LvmTextMap, Entry};
use pvlabel::MDA;
use lvmetad::vg_update_lvmetad;
use dm::DM;

/// A Volume Group.
#[derive(Debug, PartialEq, Clone)]
pub struct VG {
    /// Name.
    pub name: String,
    /// Uuid.
    pub id: String,
    /// The generation of metadata this VG represents.
    pub seqno: u64,
    /// Always "LVM2".
    pub format: String,
    /// Status.
    pub status: Vec<String>,
    /// Flags.
    pub flags: Vec<String>,
    /// Size of each extent, in 512-byte sectors.
    pub extent_size: u64,
    /// Maximum number of LVs, 0 means no limit.
    pub max_lv: u64,
    /// Maximum number of PVs, 0 means no limit.
    pub max_pv: u64,
    /// How many metadata copies (?)
    pub metadata_copies: u64,
    /// Physical Volumes within this volume group.
    pub pvs: BTreeMap<String, PV>,
    /// Logical Volumes within this volume group.
    pub lvs: BTreeMap<String, LV>,
}

impl VG {
    /// The total number of extents in use in the volume group.
    pub fn extents_in_use(&self) -> u64 {
        self.lvs
            .values()
            .map(|x| x.used_extents())
            .sum()
    }

    /// The total number of free extents in the volume group.
    pub fn extents_free(&self) -> u64 {
        self.extents() - self.extents_in_use()
    }

    /// The total number of extents in the volume group.
    pub fn extents(&self) -> u64 {
        self.pvs
            .values()
            .map(|x| x.pe_count)
            .sum()
    }

    /// Create a new linear logival volume in the volume group.
    pub fn new_linear_lv(&mut self, name: &str, extent_size: u64) -> Result<()> {
        if self.lvs.contains_key(name) {
            return Err(Error::new(Other, "LV already exists"));
        }

        let mut contig_area = None;
        for (pvname, areas) in self.free_areas() {
            for (start, len) in areas {
                if len >= extent_size {
                    contig_area = Some((pvname, start));
                    break;
                }
            }
        }

        // we don't support multiple segments yet
        let (pv_with_area, area_start) = match contig_area {
            None => return Err(Error::new(Other, "no contiguous area for new LV")),
            Some(x) => x,
        };

        let segment = Segment {
            name: "segment1".to_string(),
            start_extent: 0,
            extent_count: extent_size,
            ty: "striped".to_string(),
            stripes: vec![(pv_with_area, area_start)],
        };

        let mut lv = LV {
            name: name.to_string(),
            id: Uuid::new_v4().to_hyphenated_string(),
            status: vec!["READ".to_string(),
                         "WRITE".to_string(),
                         "VISIBLE".to_string()],
            flags: Vec::new(),
            creation_host: nix::sys::utsname::uname().nodename().to_string(),
            creation_time: now().to_timespec().sec,
            segments: vec![segment],
            device: None,
        };

        // poke dm and tell it about a new device
        {
            let dm = try!(DM::new(self));
            try!(dm.activate_device(&mut lv));
        }

        self.lvs.insert(name.to_string(), lv);

        let map = self.clone().into();

        // TODO: atomicity of updating pvs, metad, dm
        for pv in self.pvs.values() {
            if let Some(path) = pv.device.path() {
                let mut mda = MDA::new(&path).expect("could not open MDA");

                try!(mda.write_metadata(&map));
            }
        }

        // tell lvmetad
        try!(vg_update_lvmetad(&map));

        // open champagne ?

        Ok(())
    }

    fn used_areas(&self) -> BTreeMap<String, BTreeMap<u64, u64>> {
        let mut used_map = BTreeMap::new();

        // pretty sure this is only correct for my system...
        for lv in self.lvs.values() {
            for seg in &lv.segments {
                for &(ref pvname, start) in &seg.stripes {
                    used_map.entry(pvname.to_string())
                        .or_insert(BTreeMap::new())
                        .insert(start as u64, seg.extent_count);
                }
            }
        }

        used_map
    }

    fn free_areas(&self) -> BTreeMap<String, BTreeMap<u64, u64>> {
        let mut free_map = BTreeMap::new();

        for (pvname, area_map) in &mut self.used_areas() {

            // Insert an entry to mark the end of the PV so the fold works
            // correctly
            let pv = self.pvs.get(pvname)
                .expect("area map name refers to nonexistent PV");
            area_map.insert(pv.pe_count, 0);

            area_map.iter()
                .fold(0, |prev_end, (start, len)| {
                    if prev_end < *start {
                        free_map.entry(pvname.clone())
                            .or_insert(BTreeMap::new())
                            .insert(prev_end, start-prev_end);
                    }
                    start + len
                });
        }

        // Also return completely-unused PVs
        for (pvname, pv) in &self.pvs {
            if !free_map.contains_key(pvname) {
                let mut map = BTreeMap::new();
                map.insert(0, pv.pe_count);
                free_map.insert(pvname.clone(), map);
            }
        }

        free_map
    }
}

impl From<VG> for LvmTextMap {
    fn from(vg: VG) -> Self {
        let mut map = LvmTextMap::new();

        map.insert("id".to_string(), Entry::String(vg.id));
        map.insert("seqno".to_string(),
                   Entry::Number(vg.seqno as i64 + 1));
        map.insert("format".to_string(), Entry::String(vg.format));

        map.insert("max_pv".to_string(), Entry::Number(0));
        map.insert("max_lv".to_string(), Entry::Number(0));

        map.insert("status".to_string(),
                   Entry::List(
                       Box::new(
                           vg.status
                               .into_iter()
                               .map(|x| Entry::String(x))
                               .collect())));

        map.insert("flags".to_string(),
                   Entry::List(
                       Box::new(
                           vg.flags
                               .into_iter()
                               .map(|x| Entry::String(x))
                               .collect())));

        map.insert("extent_size".to_string(),
                   Entry::Number(vg.extent_size as i64));
        map.insert("metadata_copies".to_string(),
                   Entry::Number(vg.metadata_copies as i64));
        map.insert("physical_volumes".to_string(),
                   Entry::TextMap(
                       Box::new(
                           vg.pvs
                               .into_iter()
                               .map(|(k, v)|
                                    (k, Entry::TextMap(Box::new(v.into()))))
                               .collect())));

        map.insert("logical_volumes".to_string(),
                   Entry::TextMap(
                       Box::new(
                           vg.lvs
                               .into_iter()
                               .map(|(k, v)|
                                    (k, Entry::TextMap(Box::new(v.into()))))
                               .collect())));

        let mut outer_map = LvmTextMap::new();

        outer_map.insert(vg.name, Entry::TextMap(Box::new(map)));

        outer_map
    }
}
<commit_msg>rustdoc fixes<commit_after>//! Volume Groups

use std::io::Result;
use std::io::Error;
use std::io::ErrorKind::Other;
use std::collections::btree_map::BTreeMap;

use uuid::Uuid;
use time::now;
use nix;

use lv::{LV, Segment};
use pv::PV;
use parser::{LvmTextMap, Entry};
use pvlabel::MDA;
use lvmetad::vg_update_lvmetad;
use dm::DM;

/// A Volume Group.
#[derive(Debug, PartialEq, Clone)]
pub struct VG {
    /// Name.
    pub name: String,
    /// Uuid.
    pub id: String,
    /// The generation of metadata this VG represents.
    pub seqno: u64,
    /// Always "LVM2".
    pub format: String,
    /// Status.
    pub status: Vec<String>,
    /// Flags.
    pub flags: Vec<String>,
    /// Size of each extent, in 512-byte sectors.
    pub extent_size: u64,
    /// Maximum number of LVs, 0 means no limit.
    pub max_lv: u64,
    /// Maximum number of PVs, 0 means no limit.
    pub max_pv: u64,
    /// How many metadata copies (?)
    pub metadata_copies: u64,
    /// Physical Volumes within this volume group.
    pub pvs: BTreeMap<String, PV>,
    /// Logical Volumes within this volume group.
    pub lvs: BTreeMap<String, LV>,
}

impl VG {
    /// The total number of extents in use in the volume group.
    pub fn extents_in_use(&self) -> u64 {
        self.lvs
            .values()
            .map(|x| x.used_extents())
            .sum()
    }

    /// The total number of free extents in the volume group.
    pub fn extents_free(&self) -> u64 {
        self.extents() - self.extents_in_use()
    }

    /// The total number of extents in the volume group.
    pub fn extents(&self) -> u64 {
        self.pvs
            .values()
            .map(|x| x.pe_count)
            .sum()
    }

    /// Create a new linear logical volume in the volume group.
    pub fn new_linear_lv(&mut self, name: &str, extent_size: u64) -> Result<()> {
        if self.lvs.contains_key(name) {
            return Err(Error::new(Other, "LV already exists"));
        }

        let mut contig_area = None;
        for (pvname, areas) in self.free_areas() {
            for (start, len) in areas {
                if len >= extent_size {
                    contig_area = Some((pvname, start));
                    break;
                }
            }
        }

        // we don't support multiple segments yet
        let (pv_with_area, area_start) = match contig_area {
            None => return Err(Error::new(Other, "no contiguous area for new LV")),
            Some(x) => x,
        };

        let segment = Segment {
            name: "segment1".to_string(),
            start_extent: 0,
            extent_count: extent_size,
            ty: "striped".to_string(),
            stripes: vec![(pv_with_area, area_start)],
        };

        let mut lv = LV {
            name: name.to_string(),
            id: Uuid::new_v4().to_hyphenated_string(),
            status: vec!["READ".to_string(),
                         "WRITE".to_string(),
                         "VISIBLE".to_string()],
            flags: Vec::new(),
            creation_host: nix::sys::utsname::uname().nodename().to_string(),
            creation_time: now().to_timespec().sec,
            segments: vec![segment],
            device: None,
        };

        // poke dm and tell it about a new device
        {
            let dm = try!(DM::new(self));
            try!(dm.activate_device(&mut lv));
        }

        self.lvs.insert(name.to_string(), lv);

        let map = self.clone().into();

        // TODO: atomicity of updating pvs, metad, dm
        for pv in self.pvs.values() {
            if let Some(path) = pv.device.path() {
                let mut mda = MDA::new(&path).expect("could not open MDA");

                try!(mda.write_metadata(&map));
            }
        }

        // tell lvmetad
        try!(vg_update_lvmetad(&map));

        // open champagne ?

        Ok(())
    }

    // Returns e.g. {"pv0": {0: 45, 47: 100} }
    // PVs with no used areas are not in the outer map at all.
    //
    fn used_areas(&self) -> BTreeMap<String, BTreeMap<u64, u64>> {
        let mut used_map = BTreeMap::new();

        // pretty sure this is only correct for my system...
        for lv in self.lvs.values() {
            for seg in &lv.segments {
                for &(ref pvname, start) in &seg.stripes {
                    used_map.entry(pvname.to_string())
                        .or_insert(BTreeMap::new())
                        .insert(start as u64, seg.extent_count);
                }
            }
        }

        used_map
    }

    fn free_areas(&self) -> BTreeMap<String, BTreeMap<u64, u64>> {
        let mut free_map = BTreeMap::new();

        for (pvname, area_map) in &mut self.used_areas() {

            // Insert an entry to mark the end of the PV so the fold works
            // correctly
            let pv = self.pvs.get(pvname)
                .expect("area map name refers to nonexistent PV");
            area_map.insert(pv.pe_count, 0);

            area_map.iter()
                .fold(0, |prev_end, (start, len)| {
                    if prev_end < *start {
                        free_map.entry(pvname.clone())
                            .or_insert(BTreeMap::new())
                            .insert(prev_end, start-prev_end);
                    }
                    start + len
                });
        }

        // Also return completely-unused PVs
        for (pvname, pv) in &self.pvs {
            if !free_map.contains_key(pvname) {
                let mut map = BTreeMap::new();
                map.insert(0, pv.pe_count);
                free_map.insert(pvname.clone(), map);
            }
        }

        free_map
    }
}

impl From<VG> for LvmTextMap {
    fn from(vg: VG) -> Self {
        let mut map = LvmTextMap::new();

        map.insert("id".to_string(), Entry::String(vg.id));
        map.insert("seqno".to_string(),
                   Entry::Number(vg.seqno as i64 + 1));
        map.insert("format".to_string(), Entry::String(vg.format));

        map.insert("max_pv".to_string(), Entry::Number(0));
        map.insert("max_lv".to_string(), Entry::Number(0));

        map.insert("status".to_string(),
                   Entry::List(
                       Box::new(
                           vg.status
                               .into_iter()
                               .map(|x| Entry::String(x))
                               .collect())));

        map.insert("flags".to_string(),
                   Entry::List(
                       Box::new(
                           vg.flags
                               .into_iter()
                               .map(|x| Entry::String(x))
                               .collect())));

        map.insert("extent_size".to_string(),
                   Entry::Number(vg.extent_size as i64));
        map.insert("metadata_copies".to_string(),
                   Entry::Number(vg.metadata_copies as i64));
        map.insert("physical_volumes".to_string(),
                   Entry::TextMap(
                       Box::new(
                           vg.pvs
                               .into_iter()
                               .map(|(k, v)|
                                    (k, Entry::TextMap(Box::new(v.into()))))
                               .collect())));

        map.insert("logical_volumes".to_string(),
                   Entry::TextMap(
                       Box::new(
                           vg.lvs
                               .into_iter()
                               .map(|(k, v)|
                                    (k, Entry::TextMap(Box::new(v.into()))))
                               .collect())));

        let mut outer_map = LvmTextMap::new();

        outer_map.insert(vg.name, Entry::TextMap(Box::new(map)));

        outer_map
    }
}
<|endoftext|>


<commit_before>use atom::*;
use env::Env;
use errors::*;
use symbol::*;
use funcs::*;
use eval::*;
use self::Instruction::*;

#[derive (Debug, Clone)]
struct Frame {
    program: CompiledFunction,
    pc: usize
}

impl Frame {
    fn new(f: CompiledFunction) -> Frame {
        Frame {
            program: f,
            pc: 0
        }
    }

    fn current_instruction(&self) -> Option<&Instruction> {
        self.program.body.get(self.pc)
    }
}

#[derive (Debug)]
pub struct VirtualMachine {
    stack: Vec<Atom>,
    frames: Vec<Frame>,
    fp: usize,
    sp: usize,
}

#[derive (Debug, Clone, PartialEq)]
#[allow(non_camel_case_types)]
pub enum Instruction {
    CONST(Atom), // pushes the atom on the stack
    LOAD(InternedStr), // loads then pushes the value
    DEFINE(InternedStr), // sets the symbol to value on the top of the stack
    POP, // pops one off the stack
    // FUNCTION,
    JUMP_IF(usize),
    JUMP(usize),
    RETURN, // pops the frame
    CALL(Function, usize), // calls a noncompiled or native function
    DCALL(usize) // calls the function at the top of the stack
}

fn compile_node(node: Atom, out: &mut Vec<Instruction>, env: &Env) -> Result<(), Error> {
    match node {
        Atom::Symbol(sym) => {
            out.push(Instruction::LOAD(sym))
        },
        Atom::List(ref list) => {
            for n in list.iter() {
                try!(compile(n.clone(), out, env));
            }
        },
        // handle constants
        _ => {
            out.push(Instruction::CONST(node.clone()));
        }
    }
    Ok(())
}

pub fn compile(node: Atom, out: &mut Vec<Instruction>, env: &Env) -> Result<(), Error> {
    match node {
        Atom::List(ref list) => {
            if list.is_empty() {
                out.push(Instruction::CONST(node.clone()));
                return Ok(())
            }
            ()
        },
        _ => return compile_node(node, out, env)
    }

    let list = try!(node.as_list());

    if let Atom::List(_) = list[0] {
        for i in list.iter().skip(1) {
            try!(compile(i.clone(), out, env));
        }
        try!(compile(list[0].clone(), out, env));
        out.push(DCALL(list.len() - 1));
        return Ok(())
    }

    match list[0] {
        Atom::Form(f) => {
            match f {
                Form::If => {
                    if list.len() < 2 {
                        return Err(Error::NotEnoughArguments)
                    }
                    try!(compile(list[1].clone(), out, env));
                    // predicate on stack
                    out.push(JUMP_IF(0));
                    let else_jump_pos = out.len() -1;

                    try!(compile(list[2].clone(), out, env));
                    out.push(JUMP(0));
                    let out_jump = out.len() - 1;
                    out[else_jump_pos] = JUMP_IF(out.len());

                    try!(compile(list[3].clone(), out , env));

                    out[out_jump] = JUMP(out.len()-1);
                    return Ok(())
                },
                Form::Let => {
                    let mut new_env = Env::new(Some(env.clone()));
                    let bind_list = try!(list[1].as_list());
                    let mut bindings = Vec::new();

                    for binding in bind_list.iter() {
                        let bind_exp = try!(binding.as_list());
                        try!(expect_arg_length(bind_exp, 2));
                        bindings.push(bind_exp[0].clone());
                        try!(compile(bind_exp[1].clone(), out, env));
                    }
                    let mut body = Vec::new();
                    try!(compile(list[2].clone(), &mut body, &mut new_env));
                    body.push(RETURN);

                    let arity = bindings.len();

                    let func = CompiledFunction {
                        body: body,
                        params: to_list(bindings),
                        env: new_env
                    };

                    out.push(CONST(Atom::Function(Function::Compiled(func))));
                    out.push(DCALL(arity));
                    return Ok(())
                },
                Form::Set => {
                },
                Form::Def => {
                    let sym = try!(list[1].as_symbol());
                    try!(compile(list[2].clone(), out, env));
                    out.push(DEFINE(*sym));
                    return Ok(())
                },
                Form::Do => {
                    if list.len() > 2 {
                        for i in 1..list.len()-1 {
                            try!(compile(list[i].clone(), out, env));
                            out.push(POP);
                        }
                    }
                    return compile(list[list.len()-1].clone(), out, env)
                },
                Form::Fn => {
                    let mut body = Vec::new();
                    let mut env = Env::new(Some(env.clone()));
                    try!(compile(list[2].clone(), &mut body, &mut env));
                    body.push(RETURN);
                    let func = CompiledFunction {
                        body: body,
                        params: try!(list[1].as_list()).clone(),
                        env: env
                    };
                    out.push(CONST(Atom::Function(Function::Compiled(func))));
                    return Ok(())
                }
                _ => {
                    return Err(Error::NotImplemented)
                }
            }
        },
        Atom::Symbol(_) => {
            for n in list.iter().skip(1) {
                try!(compile(n.clone(), out, env));
            }
            try!(compile_node(list[0].clone(), out, env));
            out.push( DCALL(list.len() -1 ));
            return Ok(())
        }
        Atom::Function(ref func) => {
            for n in list.iter().skip(1) {
                try!(compile(n.clone(), out, env));
            }
            match *func {
                Function::Native(_) => {
                    out.push(Instruction::CALL(func.clone(), list.len() -1));
                    return Ok(())
                },
                Function::Compiled(_) => {
                    out.push(CALL(func.clone(), list.len() -1));
                    return Ok(())
                },
                _ => {
                    return Err(Error::NotImplemented)
                }
            }
        },
        _ => {
            return Err(Error::NotAFunction)
        }
    }

    Err(Error::InvalidArguments)
}

fn eval_native_borrow(v: &mut VirtualMachine, n: Native, len: usize) -> AtomResult {
    let &mut VirtualMachine { ref mut stack, ref mut frames, fp, .. } = v;
    eval_native(n, &stack[len..], &mut frames[fp].program.env)
}

impl VirtualMachine {
    pub fn new() -> VirtualMachine {
        VirtualMachine {
            stack: vec![],
            frames: vec![],
            sp: 0,
            fp: 0
        }
    }

    fn next_instruction(&self) -> Option<Instruction> {
        self.frames[self.fp].current_instruction().map(|n| n.clone())
    }

    fn current_frame(&mut self) -> &mut Frame {
        &mut self.frames[self.fp]
    }

    fn current_env(&mut self) -> &mut Env {
        &mut self.current_frame().program.env
    }

    pub fn run(&mut self) -> AtomResult {
        while let Some(instruction) = self.next_instruction() {
            match instruction {
                JUMP_IF(addr) => {
                    let pred = match self.pop() {
                        Atom::Boolean(b) => b,
                        Atom::Nil => false,
                        Atom::List(ref l) if l.is_empty() => false,
                        _ => true
                    };
                    if pred {
                        self.current_frame().pc = addr;
                        continue;
                    }
                },
                JUMP(addr) => {
                    self.current_frame().pc = addr;
                    continue;
                }
                POP => {
                    self.pop();
                }
                RETURN => {
                    if self.fp > 0 {
                        self.fp -= 1;
                        self.frames.pop();
                    } else {
                        return Ok(self.pop())
                    }
                },
                LOAD(sym) => {
                    let value = self.current_frame().program.env.get(sym.as_ref()).unwrap_or(Atom::Nil);
                    self.push(value);
                },
                CONST(ref atom) => {
                    self.push(atom.clone())
                },
                DEFINE(sym) => {
                    let v = self.pop();
                    let a = try!(self.current_env().define(sym, v));
                    self.push(a);
                },
                DCALL(arity) => {
                    let func = self.pop();

                    match func {
                        Atom::Function(Function::Compiled(mut f)) => {
                            f.env.bind_mut(&f.params, &self.stack[self.sp-arity..]);
                            for _ in 0..arity {
                                self.pop();
                            }
                            self.frames.push(Frame::new(f.clone()));
                            self.fp += 1;
                            continue; // don't advance PC of the new frame
                        },
                        _ => {
                            println!("not a function: {:?}", func);
                            return Err(Error::NotAFunction)
                        }
                    }
                },
                CALL(func, arity) => {
                    match func {
                        Function::Native(n) => {
                            let len = self.stack.len();
                            let r = try!(eval_native_borrow(self, n, len - arity));
                            for _ in 1..arity {
                                self.pop();
                            }
                            self.push(r);
                        },
                        _ => {
                            return Err(Error::NotImplemented)
                        }
                    }
                },
            }
            self.current_frame().pc += 1;
        }
        Ok(self.pop())
    }

    fn push(&mut self, a: Atom)  {
        self.stack.push(a);
        self.sp += 1
    }

    fn pop(&mut self) -> Atom {
        self.sp -= 1;
        self.stack.pop().unwrap()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use parser::*;
    use atom::*;
    use env::*;
    use super::Frame;

    fn empty_frame() -> Frame {
        Frame::new(CompiledFunction{
            body: Vec::new(),
            params: empty_list(),
            env: Env::new(None)
        })
    }

    fn run_expr(s: &str) -> Atom {
        let p = tokenize(s).unwrap();
        let mut out = Vec::new();
        let env = Env::new(None);
        compile(p, &mut out, &env).unwrap();
        println!("output: {:?}", out);
        let mut vm = VirtualMachine::new();
        let mut f = empty_frame();
        f.program.env = env;
        f.program.body = out;
        vm.frames.push(f);
        vm.run().unwrap()
    }

    #[test]
    fn test() {
        assert_eq!(Atom::from(6), run_expr("(+ (+ 2 2) 2)"));
        assert_eq!(Atom::symbol("a"), run_expr("(def a 1)"));
        assert_eq!(Atom::from(3), run_expr("(do (def foo (fn (x) (+ x 2))) (foo 1))"));
    }

    #[test]
    fn test_invoke_fn_inline() {
        assert_eq!(Atom::from(1), run_expr("((fn (x) 1) 0)"));
    }

    #[test]
    fn test_closure() {
        assert_eq!(Atom::from(2), run_expr("(do (def foo (fn (x) (fn () (* 2 x)))) (def foo2 (foo 1)) (foo2))"))
    }

    #[test]
    fn let_binding() {
        assert_eq!(Atom::from(-1), run_expr("(let* ((x 2) (y 3)) (- x y))"));
    }

    #[test]
    fn let_doesnt_leak() {
        assert_eq!(Atom::from(0), run_expr("(do (let* ((x 1)) (let* ((x 0)) x)))"))
    }
}
<commit_msg>it's a ifnot, add result to pop<commit_after>use atom::*;
use env::Env;
use errors::*;
use symbol::*;
use funcs::*;
use eval::*;
use self::Instruction::*;

#[derive (Debug, Clone)]
struct Frame {
    program: CompiledFunction,
    pc: usize
}

impl Frame {
    fn new(f: CompiledFunction) -> Frame {
        Frame {
            program: f,
            pc: 0
        }
    }

    fn current_instruction(&self) -> Option<&Instruction> {
        self.program.body.get(self.pc)
    }
}

#[derive (Debug)]
pub struct VirtualMachine {
    stack: Vec<Atom>,
    frames: Vec<Frame>,
    fp: usize,
    sp: usize,
}

#[derive (Debug, Clone, PartialEq)]
#[allow(non_camel_case_types)]
pub enum Instruction {
    CONST(Atom), // pushes the atom on the stack
    LOAD(InternedStr), // loads then pushes the value
    DEFINE(InternedStr), // sets the symbol to value on the top of the stack
    POP, // pops one off the stack
    // FUNCTION,
    JUMP_IFNOT(usize),
    JUMP(usize),
    RETURN, // pops the frame
    CALL(Function, usize), // calls a noncompiled or native function
    DCALL(usize) // calls the function at the top of the stack
}

fn compile_node(node: Atom, out: &mut Vec<Instruction>, env: &Env) -> Result<(), Error> {
    match node {
        Atom::Symbol(sym) => {
            out.push(Instruction::LOAD(sym))
        },
        Atom::List(ref list) => {
            for n in list.iter() {
                try!(compile(n.clone(), out, env));
            }
        },
        // handle constants
        _ => {
            out.push(Instruction::CONST(node.clone()));
        }
    }
    Ok(())
}

pub fn compile(node: Atom, out: &mut Vec<Instruction>, env: &Env) -> Result<(), Error> {
    match node {
        Atom::List(ref list) => {
            if list.is_empty() {
                out.push(Instruction::CONST(node.clone()));
                return Ok(())
            }
            ()
        },
        _ => return compile_node(node, out, env)
    }

    let list = try!(node.as_list());

    if let Atom::List(_) = list[0] {
        for i in list.iter().skip(1) {
            try!(compile(i.clone(), out, env));
        }
        try!(compile(list[0].clone(), out, env));
        out.push(DCALL(list.len() - 1));
        return Ok(())
    }

    match list[0] {
        Atom::Form(f) => {
            match f {
                Form::If => {
                    if list.len() < 2 {
                        return Err(Error::NotEnoughArguments)
                    }
                    try!(compile(list[1].clone(), out, env));
                    // predicate on stack
                    out.push(JUMP_IFNOT(0));
                    let else_jump_pos = out.len() -1;
                    try!(compile(list[2].clone(), out, env));

                    out.push(JUMP(0));
                    let out_jump = out.len() - 1;

                    out[else_jump_pos] = JUMP_IFNOT(out.len());

                    try!(compile(list[3].clone(), out , env));

                    out[out_jump] = JUMP(out.len());
                    return Ok(())
                },
                Form::Let => {
                    let mut new_env = Env::new(Some(env.clone()));
                    let bind_list = try!(list[1].as_list());
                    let mut bindings = Vec::new();

                    for binding in bind_list.iter() {
                        let bind_exp = try!(binding.as_list());
                        try!(expect_arg_length(bind_exp, 2));
                        bindings.push(bind_exp[0].clone());
                        try!(compile(bind_exp[1].clone(), out, env));
                    }
                    let mut body = Vec::new();
                    try!(compile(list[2].clone(), &mut body, &mut new_env));
                    body.push(RETURN);

                    let arity = bindings.len();

                    let func = CompiledFunction {
                        body: body,
                        params: to_list(bindings),
                        env: new_env
                    };

                    out.push(CONST(Atom::Function(Function::Compiled(func))));
                    out.push(DCALL(arity));
                    return Ok(())
                },
                Form::Set => {
                },
                Form::Def => {
                    let sym = try!(list[1].as_symbol());
                    try!(compile(list[2].clone(), out, env));
                    out.push(DEFINE(*sym));
                    return Ok(())
                },
                Form::Do => {
                    if list.len() > 2 {
                        for i in 1..list.len()-1 {
                            try!(compile(list[i].clone(), out, env));
                            out.push(POP);
                        }
                    }
                    return compile(list[list.len()-1].clone(), out, env)
                },
                Form::Fn => {
                    let mut body = Vec::new();
                    let mut env = Env::new(Some(env.clone()));
                    try!(compile(list[2].clone(), &mut body, &mut env));
                    body.push(RETURN);
                    let func = CompiledFunction {
                        body: body,
                        params: try!(list[1].as_list()).clone(),
                        env: env
                    };
                    out.push(CONST(Atom::Function(Function::Compiled(func))));
                    return Ok(())
                }
                _ => {
                    return Err(Error::NotImplemented)
                }
            }
        },
        Atom::Symbol(_) => {
            for n in list.iter().skip(1) {
                try!(compile(n.clone(), out, env));
            }
            try!(compile_node(list[0].clone(), out, env));
            out.push( DCALL(list.len() -1 ));
            return Ok(())
        }
        Atom::Function(ref func) => {
            for n in list.iter().skip(1) {
                try!(compile(n.clone(), out, env));
            }
            match *func {
                Function::Native(_) => {
                    out.push(Instruction::CALL(func.clone(), list.len() -1));
                    return Ok(())
                },
                Function::Compiled(_) => {
                    out.push(CALL(func.clone(), list.len() -1));
                    return Ok(())
                },
                _ => {
                    return Err(Error::NotImplemented)
                }
            }
        },
        _ => {
            return Err(Error::NotAFunction)
        }
    }

    Err(Error::InvalidArguments)
}

fn eval_native_borrow(v: &mut VirtualMachine, n: Native, len: usize) -> AtomResult {
    let &mut VirtualMachine { ref mut stack, ref mut frames, fp, .. } = v;
    eval_native(n, &stack[len..], &mut frames[fp].program.env)
}

impl VirtualMachine {
    pub fn new() -> VirtualMachine {
        VirtualMachine {
            stack: vec![],
            frames: vec![],
            sp: 0,
            fp: 0
        }
    }

    fn next_instruction(&self) -> Option<Instruction> {
        self.frames[self.fp].current_instruction().map(|n| n.clone())
    }

    fn current_frame(&mut self) -> &mut Frame {
        &mut self.frames[self.fp]
    }

    fn current_env(&mut self) -> &mut Env {
        &mut self.current_frame().program.env
    }

    pub fn run(&mut self) -> AtomResult {
        while let Some(instruction) = self.next_instruction() {
            match instruction {
                JUMP_IFNOT(addr) => {
                    if !try!(self.pop()).as_bool() {
                        self.current_frame().pc = addr;
                        continue;
                    }
                },
                JUMP(addr) => {
                    self.current_frame().pc = addr;
                    continue;
                }
                POP => {
                    try!(self.pop());
                }
                RETURN => {
                    if self.fp > 0 {
                        self.fp -= 1;
                        self.frames.pop();
                    } else {
                        return self.pop()
                    }
                },
                LOAD(sym) => {
                    let value = self.current_frame().program.env.get(sym.as_ref()).unwrap_or(Atom::Nil);
                    self.push(value);
                },
                CONST(ref atom) => {
                    self.push(atom.clone())
                },
                DEFINE(sym) => {
                    let v = try!(self.pop());
                    let a = try!(self.current_env().define(sym, v));
                    self.push(a);
                },
                DCALL(arity) => {
                    let func = try!(self.pop());

                    match func {
                        Atom::Function(Function::Compiled(mut f)) => {
                            f.env.bind_mut(&f.params, &self.stack[self.sp-arity..]);
                            for _ in 0..arity {
                                try!(self.pop());
                            }
                            self.frames.push(Frame::new(f.clone()));
                            self.fp += 1;
                            continue; // don't advance PC of the new frame
                        },
                        _ => {
                            println!("not a function: {:?}", func);
                            return Err(Error::NotAFunction)
                        }
                    }
                },
                CALL(func, arity) => {
                    match func {
                        Function::Native(n) => {
                            let len = self.stack.len();
                            let r = try!(eval_native_borrow(self, n, len - arity));
                            for _ in 1..arity {
                                try!(self.pop());
                            }
                            self.push(r);
                        },
                        _ => {
                            return Err(Error::NotImplemented)
                        }
                    }
                },
            }
            self.current_frame().pc += 1;
        }
        self.pop()
    }

    fn push(&mut self, a: Atom)  {
        self.stack.push(a);
        self.sp += 1
    }

    fn pop(&mut self) -> AtomResult {
        self.sp -= 1;
        self.stack.pop().ok_or(Error::RuntimeAssertion)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use parser::*;
    use atom::*;
    use env::*;
    use super::Frame;

    fn empty_frame() -> Frame {
        Frame::new(CompiledFunction{
            body: Vec::new(),
            params: empty_list(),
            env: Env::new(None)
        })
    }

    fn run_expr(s: &str) -> Atom {
        let p = tokenize(s).unwrap();
        let mut out = Vec::new();
        let env = Env::new(None);
        compile(p, &mut out, &env).unwrap();
        let mut vm = VirtualMachine::new();
        let mut f = empty_frame();
        f.program.env = env;
        f.program.body = out;
        vm.frames.push(f);
        vm.run().unwrap()
    }

    #[test]
    fn test() {
        assert_eq!(Atom::from(6), run_expr("(+ (+ 2 2) 2)"));
        assert_eq!(Atom::symbol("a"), run_expr("(def a 1)"));
        assert_eq!(Atom::from(3), run_expr("(do (def foo (fn (x) (+ x 2))) (foo 1))"));
    }

    #[test]
    fn test_invoke_fn_inline() {
        assert_eq!(Atom::from(1), run_expr("((fn (x) 1) 0)"));
    }

    #[test]
    fn test_closure() {
        assert_eq!(Atom::from(2), run_expr("(do (def foo (fn (x) (fn () (* 2 x)))) (def foo2 (foo 1)) (foo2))"))
    }

    #[test]
    fn let_binding() {
        assert_eq!(Atom::from(-1), run_expr("(let* ((x 2) (y 3)) (- x y))"));
    }

    #[test]
    fn nested_let() {
        assert_eq!(Atom::from(0), run_expr("(do (let* ((x 1)) (let* ((x 0)) x)))"))
    }

    #[test]
    fn if_test() {
        assert_eq!(Atom::from(0), run_expr("(if false 1 0)"));
        assert_eq!(Atom::from(1), run_expr("(if true 1 0)"));
    }

}
<|endoftext|>


<commit_before>pub const TILE_WIDTH: f32 = 46.0;

pub const TILES_PCS_W: usize = 64;
pub const TILES_PCS_H: usize = 64;

#[cfg_attr(feature = "cargo-clippy", allow(decimal_literal_representation))]
pub const TILE_MAP_BUF_LENGTH: usize = 4096;
pub const CHARACTER_BUF_LENGTH: usize = 224;

pub const RESOLUTION_X: u32 = 1920;
pub const RESOLUTION_Y: u32 = 1080;

pub const ASPECT_RATIO: f32 = (RESOLUTION_X / RESOLUTION_Y) as f32;

pub const VIEW_DISTANCE: f32 = 300.0;

pub const CHARACTER_SHEET_TOTAL_WIDTH: f32 = 16_128f32;
pub const SPRITE_OFFSET: f32 = 2.0;

pub const ZOMBIE_SHEET_TOTAL_WIDTH: f32 = 9_184f32;

pub const BULLET_SPEED: f32 = 1.0;

pub const X_MOVEMENT: f32 = 1.0;
pub const Y_MOVEMENT: f32 = 1.0;

//Assets
pub const ZOMBIE_JSON_PATH: &str = "assets/zombie.json";
pub const CHARACTER_JSON_PATH: &str = "assets/character.json";
pub const PISTOL_AUDIO_PATH: &str = "assets/audio/pistol.ogg";
pub const MAP_FILE_PATH: &str = "assets/maps/tilemap.tmx";

pub const RUN_SPRITE_OFFSET: usize = 64;
pub const ZOMBIE_STILL_SPRITE_OFFSET: usize = 32;
pub const NORMAL_DEATH_SPRITE_OFFSET: usize = 64;

pub const HOUSE_POSITIONS: [[f32; 2]; 2] = [[-36.0, 644.0], [450.0, 230.0]];
pub const TREE_POSITIONS: [[f32; 2]; 5] = [[-506.0, -230.0], [368.0, -368.0], [-690.0, -506.0], [-874.0, -92.0], [-690.0, 138.0]];

pub const TERRAIN_OBJECTS: [[usize; 2]; 34] = [
  [16, 18], [16, 19], [16, 20],
  [17, 18], [17, 19], [17, 20],
  [18, 18], [18, 19], [18, 20],
  [19, 18], [19, 19], [19, 20],
  [37, 15], [37, 16], [37, 17],
  [38, 15], [38, 16], [38, 17],
  [39, 15], [39, 16], [39, 17],
  [40, 15], [40, 16], [40, 17],
  [29, 49], [28, 50],
  [49, 33], [50, 34],
  [29, 59], [30, 60],
  [16, 54], [17, 55],
  [15, 45], [16, 46]];
<commit_msg>Fix second house position<commit_after>pub const TILE_WIDTH: f32 = 46.0;

pub const TILES_PCS_W: usize = 64;
pub const TILES_PCS_H: usize = 64;

#[cfg_attr(feature = "cargo-clippy", allow(decimal_literal_representation))]
pub const TILE_MAP_BUF_LENGTH: usize = 4096;
pub const CHARACTER_BUF_LENGTH: usize = 224;

pub const RESOLUTION_X: u32 = 1920;
pub const RESOLUTION_Y: u32 = 1080;

pub const ASPECT_RATIO: f32 = (RESOLUTION_X / RESOLUTION_Y) as f32;

pub const VIEW_DISTANCE: f32 = 300.0;

pub const CHARACTER_SHEET_TOTAL_WIDTH: f32 = 16_128f32;
pub const SPRITE_OFFSET: f32 = 2.0;

pub const ZOMBIE_SHEET_TOTAL_WIDTH: f32 = 9_184f32;

pub const BULLET_SPEED: f32 = 1.0;

pub const X_MOVEMENT: f32 = 1.0;
pub const Y_MOVEMENT: f32 = 1.0;

//Assets
pub const ZOMBIE_JSON_PATH: &str = "assets/zombie.json";
pub const CHARACTER_JSON_PATH: &str = "assets/character.json";
pub const PISTOL_AUDIO_PATH: &str = "assets/audio/pistol.ogg";
pub const MAP_FILE_PATH: &str = "assets/maps/tilemap.tmx";

pub const RUN_SPRITE_OFFSET: usize = 64;
pub const ZOMBIE_STILL_SPRITE_OFFSET: usize = 32;
pub const NORMAL_DEATH_SPRITE_OFFSET: usize = 64;

pub const HOUSE_POSITIONS: [[f32; 2]; 2] = [[-36.0, 644.0], [506.0, 230.0]];
pub const TREE_POSITIONS: [[f32; 2]; 5] = [[-506.0, -230.0], [368.0, -368.0], [-690.0, -506.0], [-874.0, -92.0], [-690.0, 138.0]];

pub const TERRAIN_OBJECTS: [[usize; 2]; 34] = [
  [16, 18], [16, 19], [16, 20],
  [17, 18], [17, 19], [17, 20],
  [18, 18], [18, 19], [18, 20],
  [19, 18], [19, 19], [19, 20],
  [37, 15], [37, 16], [37, 17],
  [38, 15], [38, 16], [38, 17],
  [39, 15], [39, 16], [39, 17],
  [40, 15], [40, 16], [40, 17],
  [29, 49], [28, 50],
  [49, 33], [50, 34],
  [29, 59], [30, 60],
  [16, 54], [17, 55],
  [15, 45], [16, 46]];
<|endoftext|>


<commit_before>#![cfg(feature = "dnssec")]

extern crate futures;
extern crate log;
extern crate tokio_core;
extern crate trust_dns;
extern crate trust_dns_proto;

mod server_harness;

use std::env;
use std::fs::File;
use std::path::Path;
use std::io::*;
use std::net::*;

use tokio_core::reactor::Core;

use trust_dns::client::*;
use trust_dns::tcp::TcpClientStream;
use trust_dns::rr::dnssec::*;

use server_harness::*;

#[cfg(all(not(feature = "dnssec-ring"), feature = "dnssec-openssl"))]
fn confg_toml() -> &'static str {
    "openssl_dnssec.toml"
}

#[cfg(all(feature = "dnssec-ring", not(feature = "dnssec-openssl")))]
fn confg_toml() -> &'static str {
    "ring_dnssec.toml"
}

#[cfg(all(feature = "dnssec-ring", feature = "dnssec-openssl"))]
fn confg_toml() -> &'static str {
    "all_supported_dnssec.toml"
}

fn trust_anchor(public_key_path: &Path, format: KeyFormat, algorithm: Algorithm) -> TrustAnchor {
    let mut file = File::open(public_key_path).expect("key not found");
    let mut buf = Vec::<u8>::new();

    file.read_to_end(&mut buf).expect("could not read key");
    let key_pair = format.decode_key(&buf, Some("123456"), algorithm).expect(
        "could not decode key",
    );

    let public_key = key_pair.to_public_key().unwrap();
    let mut trust_anchor = TrustAnchor::new();

    trust_anchor.insert_trust_anchor(public_key);
    trust_anchor
}

fn standard_conn(port: u16, io_loop: &Core) -> BasicClientHandle {
    let addr: SocketAddr = ("127.0.0.1", port)
        .to_socket_addrs()
        .unwrap()
        .next()
        .unwrap();
    let (stream, sender) = TcpClientStream::new(addr, &io_loop.handle());
    ClientFuture::new(stream, sender, &io_loop.handle(), None)
}

fn generic_test(config_toml: &str, key_path: &str, key_format: KeyFormat, algorithm: Algorithm) {
    // use trust_dns::logger;
    // use log::LogLevel;
    // logger::TrustDnsLogger::enable_logging(LogLevel::Debug);

    let server_path = env::var("TDNS_SERVER_SRC_ROOT").unwrap_or(".".to_owned());
    let server_path = Path::new(&server_path);

    named_test_harness(config_toml, |port, _| {
        let mut io_loop = Core::new().unwrap();

        // verify all records are present
        let client = standard_conn(port, &io_loop);
        query_all_dnssec_with_rfc6975(&mut io_loop, client, algorithm);
        let client = standard_conn(port, &io_loop);
        query_all_dnssec_wo_rfc6975(&mut io_loop, client, algorithm);

        // test that request with Secure client is successful, i.e. validates chain
        let trust_anchor = trust_anchor(&server_path.join(key_path), key_format, algorithm);
        let client = standard_conn(port, &io_loop);
        let mut client = SecureClientHandle::with_trust_anchor(client, trust_anchor);

        query_a(&mut io_loop, &mut client);
    });
}

#[test]
#[cfg(feature = "dnssec-openssl")]
fn test_rsa_sha256() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA256,
    );
}

#[test]
#[cfg(feature = "dnssec-openssl")]
fn test_rsa_sha512() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA512,
    );
}

#[test]
#[cfg(feature = "dnssec-openssl")]
fn test_ecdsa_p256() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/ecdsa_p256.pem",
        KeyFormat::Pem,
        Algorithm::ECDSAP256SHA256,
    );
}

#[test]
#[cfg(feature = "dnssec-openssl")]
fn test_ecdsa_p384() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/ecdsa_p384.pem",
        KeyFormat::Pem,
        Algorithm::ECDSAP384SHA384,
    );
}

#[test]
#[cfg(feature = "dnssec-ring")]
fn test_ed25519() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/ed25519.pk8",
        KeyFormat::Pkcs8,
        Algorithm::ED25519,
    );
}

#[test]
#[should_panic]
fn test_rsa_sha1_fails() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA1,
    );
}

#[cfg(feature = "dnssec-openssl")]
#[test]
fn test_dnssec_restart_with_update_journal() {
    // TODO: make journal path configurable, it should be in target/tests/...
    let server_path = env::var("TDNS_SERVER_SRC_ROOT").unwrap_or(".".to_owned());
    let server_path = Path::new(&server_path);
    let journal = server_path.join("tests/named_test_configs/example.com.jrnl");
    std::fs::remove_file(&journal).ok();

    generic_test(
        "dnssec_with_update.toml",
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA256,
    );

    // after running the above test, the journal file should exist
    assert!(journal.exists());

    // and all dnssec tests should still pass
    generic_test(
        "dnssec_with_update.toml",
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA256,
    );

    // and journal should still exist
    assert!(journal.exists());

    // cleanup...
    // TODO: fix journal path so that it doesn't leave the dir dirty...
    std::fs::remove_file(&journal).expect("failed to cleanup after test");
}
<commit_msg>disable test_dnssec_restart_with_update_journal on windows, requires cleanup<commit_after>#![cfg(feature = "dnssec")]

extern crate futures;
extern crate log;
extern crate tokio_core;
extern crate trust_dns;
extern crate trust_dns_proto;

mod server_harness;

use std::env;
use std::fs::File;
use std::path::Path;
use std::io::*;
use std::net::*;

use tokio_core::reactor::Core;

use trust_dns::client::*;
use trust_dns::tcp::TcpClientStream;
use trust_dns::rr::dnssec::*;

use server_harness::*;

#[cfg(all(not(feature = "dnssec-ring"), feature = "dnssec-openssl"))]
fn confg_toml() -> &'static str {
    "openssl_dnssec.toml"
}

#[cfg(all(feature = "dnssec-ring", not(feature = "dnssec-openssl")))]
fn confg_toml() -> &'static str {
    "ring_dnssec.toml"
}

#[cfg(all(feature = "dnssec-ring", feature = "dnssec-openssl"))]
fn confg_toml() -> &'static str {
    "all_supported_dnssec.toml"
}

fn trust_anchor(public_key_path: &Path, format: KeyFormat, algorithm: Algorithm) -> TrustAnchor {
    let mut file = File::open(public_key_path).expect("key not found");
    let mut buf = Vec::<u8>::new();

    file.read_to_end(&mut buf).expect("could not read key");
    let key_pair = format.decode_key(&buf, Some("123456"), algorithm).expect(
        "could not decode key",
    );

    let public_key = key_pair.to_public_key().unwrap();
    let mut trust_anchor = TrustAnchor::new();

    trust_anchor.insert_trust_anchor(public_key);
    trust_anchor
}

fn standard_conn(port: u16, io_loop: &Core) -> BasicClientHandle {
    let addr: SocketAddr = ("127.0.0.1", port)
        .to_socket_addrs()
        .unwrap()
        .next()
        .unwrap();
    let (stream, sender) = TcpClientStream::new(addr, &io_loop.handle());
    ClientFuture::new(stream, sender, &io_loop.handle(), None)
}

fn generic_test(config_toml: &str, key_path: &str, key_format: KeyFormat, algorithm: Algorithm) {
    // use trust_dns::logger;
    // use log::LogLevel;
    // logger::TrustDnsLogger::enable_logging(LogLevel::Debug);

    let server_path = env::var("TDNS_SERVER_SRC_ROOT").unwrap_or(".".to_owned());
    let server_path = Path::new(&server_path);

    named_test_harness(config_toml, |port, _| {
        let mut io_loop = Core::new().unwrap();

        // verify all records are present
        let client = standard_conn(port, &io_loop);
        query_all_dnssec_with_rfc6975(&mut io_loop, client, algorithm);
        let client = standard_conn(port, &io_loop);
        query_all_dnssec_wo_rfc6975(&mut io_loop, client, algorithm);

        // test that request with Secure client is successful, i.e. validates chain
        let trust_anchor = trust_anchor(&server_path.join(key_path), key_format, algorithm);
        let client = standard_conn(port, &io_loop);
        let mut client = SecureClientHandle::with_trust_anchor(client, trust_anchor);

        query_a(&mut io_loop, &mut client);
    });
}

#[test]
#[cfg(feature = "dnssec-openssl")]
fn test_rsa_sha256() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA256,
    );
}

#[test]
#[cfg(feature = "dnssec-openssl")]
fn test_rsa_sha512() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA512,
    );
}

#[test]
#[cfg(feature = "dnssec-openssl")]
fn test_ecdsa_p256() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/ecdsa_p256.pem",
        KeyFormat::Pem,
        Algorithm::ECDSAP256SHA256,
    );
}

#[test]
#[cfg(feature = "dnssec-openssl")]
fn test_ecdsa_p384() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/ecdsa_p384.pem",
        KeyFormat::Pem,
        Algorithm::ECDSAP384SHA384,
    );
}

#[test]
#[cfg(feature = "dnssec-ring")]
fn test_ed25519() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/ed25519.pk8",
        KeyFormat::Pkcs8,
        Algorithm::ED25519,
    );
}

#[test]
#[should_panic]
fn test_rsa_sha1_fails() {
    generic_test(
        confg_toml(),
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA1,
    );
}

#[cfg(feature = "dnssec-openssl")]
#[cfg(not(windows))]
#[test]
fn test_dnssec_restart_with_update_journal() {
    // TODO: make journal path configurable, it should be in target/tests/...
    let server_path = env::var("TDNS_SERVER_SRC_ROOT").unwrap_or(".".to_owned());
    let server_path = Path::new(&server_path);
    let journal = server_path.join("tests/named_test_configs/example.com.jrnl");
    std::fs::remove_file(&journal).ok();

    generic_test(
        "dnssec_with_update.toml",
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA256,
    );

    // after running the above test, the journal file should exist
    assert!(journal.exists());

    // and all dnssec tests should still pass
    generic_test(
        "dnssec_with_update.toml",
        "tests/named_test_configs/dnssec/rsa_2048.pem",
        KeyFormat::Pem,
        Algorithm::RSASHA256,
    );

    // and journal should still exist
    assert!(journal.exists());

    // cleanup...
    // TODO: fix journal path so that it doesn't leave the dir dirty... this might make windows an option after that
    std::fs::remove_file(&journal).expect("failed to cleanup after test");
}
<|endoftext|>


<commit_before>// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use generated::p_format;

macro_rules! fourcc {
    ($a:expr, $b:expr, $c:expr, $d:expr) => {
        Some($a as u32 | ($b as u32) << 8 | ($c as u32) << 16 | ($d as u32) << 24)
    };
}

/// Gets the fourcc that corresponds to the given pipe format, or `None` if the format is
/// unrecognized.
pub fn pipe_format_fourcc(f: p_format::pipe_format) -> Option<u32> {
    match f {
        p_format::PIPE_FORMAT_B8G8R8A8_UNORM => fourcc!('A', 'R', '2', '4'),
        p_format::PIPE_FORMAT_B8G8R8X8_UNORM => fourcc!('X', 'R', '2', '4'),
        p_format::PIPE_FORMAT_R8G8B8A8_UNORM => fourcc!('A', 'B', '2', '4'),
        p_format::PIPE_FORMAT_R8G8B8X8_UNORM => fourcc!('X', 'B', '2', '4'),
        // p_format::PIPE_FORMAT_B5G6R5_UNORM => fourcc!('R', 'G', '1', '6'),
        // p_format::PIPE_FORMAT_R8_UNORM => fourcc!('R', '8', ' ', ' '),
        // p_format::PIPE_FORMAT_G8R8_UNORM => fourcc!('R', 'G', '8', '8'),
        _ => None,
    }
}
<commit_msg>gpu_renderer: Enable DRM_FORMAT_RGB565 format.<commit_after>// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use generated::p_format;

macro_rules! fourcc {
    ($a:expr, $b:expr, $c:expr, $d:expr) => {
        Some($a as u32 | ($b as u32) << 8 | ($c as u32) << 16 | ($d as u32) << 24)
    };
}

/// Gets the fourcc that corresponds to the given pipe format, or `None` if the format is
/// unrecognized.
pub fn pipe_format_fourcc(f: p_format::pipe_format) -> Option<u32> {
    match f {
        p_format::PIPE_FORMAT_B8G8R8A8_UNORM => fourcc!('A', 'R', '2', '4'),
        p_format::PIPE_FORMAT_B8G8R8X8_UNORM => fourcc!('X', 'R', '2', '4'),
        p_format::PIPE_FORMAT_R8G8B8A8_UNORM => fourcc!('A', 'B', '2', '4'),
        p_format::PIPE_FORMAT_R8G8B8X8_UNORM => fourcc!('X', 'B', '2', '4'),
        p_format::PIPE_FORMAT_B5G6R5_UNORM => fourcc!('R', 'G', '1', '6'),
        // p_format::PIPE_FORMAT_R8_UNORM => fourcc!('R', '8', ' ', ' '),
        // p_format::PIPE_FORMAT_G8R8_UNORM => fourcc!('R', 'G', '8', '8'),
        _ => None,
    }
}
<|endoftext|>


<commit_before>//! The filter implementation
//!

pub use ops::and::And;
pub use ops::not::Not;
pub use ops::xor::XOr;
pub use ops::or::Or;

/// Trait for converting something into a Filter
pub trait IntoFilter<N> {
    type IntoFilt: Filter<N>;

    fn into_filter(self) -> Self::IntoFilt;
}

/// All Filters can be turned into Filters
impl<N, I: Filter<N>> IntoFilter<N> for I {
    type IntoFilt = I;

    fn into_filter(self) -> I {
        self
    }
}

/// All closures that take a ref to something and return bool are filters
impl<I, T: Fn(&I) -> bool> Filter<I> for T {
    fn filter(&self, other: &I) -> bool {
        self(other)
    }
}

/// The filter trai
pub trait Filter<N> {

    /// The function which is used to filter something
    fn filter(&self, &N) -> bool;

    /// Helper to invert a filter.
    ///
    /// ```ignore
    /// (|&a: &usize| { a == 1 }).not() == (|&a: &usize| { a != 1 })
    /// ```
    fn not(self) -> Not<Self>
        where Self: Sized
    {
        Not::new(self)
    }

    /// Helper to connect two filters via logical OR
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    ///
    /// a.or(b) == (|&a: &usize| { a == 1 || a == 2 })
    /// ```
    fn or<F>(self, other: F) -> Or<Self, F::IntoFilt>
        where Self: Sized,
              F: IntoFilter<N> + Sized
    {
        Or::new(self, other.into_filter())
    }

    /// Helper to connect two filters via logical OR and NOT
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    ///
    /// a.or_not(b) == (|&a: &usize| { a == 1 || !(a == 2) })
    /// ```
    fn or_not<F>(self, other: F) -> Or<Self, Not<F::IntoFilt>>
        where Self: Sized,
              F: IntoFilter<N> + Sized,
    {
        self.or(Not::new(other.into_filter()))
    }

    /// Helper to connect three filters via logical OR
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    /// let c = (|&a: &usize| { a == 3 });
    ///
    /// a.or3(b, c) == (|&a: &usize| { a == 1 || a == 2 || a == 3 })
    /// ```
    fn or3<F, F2>(self, other: F, other2: F2) -> Or<Self, Or<F::IntoFilt, F2::IntoFilt>>
        where Self: Sized,
              F: IntoFilter<N> + Sized,
              F2: IntoFilter<N> + Sized
    {
        Or::new(self, Or::new(other.into_filter(), other2.into_filter()))
    }

    /// Helper to connect two filters via logical NOR
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    ///
    /// a.nor(b) == (|&a: &usize| { !(a == 1 || a == 2) })
    /// ```
    fn nor<F>(self, other: F) -> Not<Or<Self, F>>
        where Self: Sized,
    {
        Not::new(Or::new(self, other))
    }

    /// Helper to connect two filters via logical XOR
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    ///
    /// a.xor(b) == (|&a: &usize| { !(a == 1 || a == 2) })
    /// ```
    fn xor<F>(self, other: F) -> XOr<Self, F>
        where Self: Sized,
    {
        XOr::new(self, other)
    }

    /// Helper to connect two filters via logical AND
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    ///
    /// a.and(b) == (|&a: &usize| { a == 1 && a == 2 })
    /// ```
    fn and<F>(self, other: F) -> And<Self, F::IntoFilt>
        where Self: Sized,
              F: IntoFilter<N> + Sized
    {
        And::new(self, other.into_filter())
    }

    /// Helper to connect three filters via logical AND
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    /// let c = (|&a: &usize| { a == 3 });
    ///
    /// a.and3(b, c) == (|&a: &usize| { a == 1 && a == 2 && a == 3 })
    /// ```
    fn and3<F, F2>(self, other: F, other2: F2) -> And<Self, And<F::IntoFilt, F2::IntoFilt>>
        where Self: Sized,
              F: IntoFilter<N> + Sized,
              F2: IntoFilter<N> + Sized
    {
        And::new(self, And::new(other.into_filter(), other2.into_filter()))
    }

    /// Helper to connect two filters via logical AND and NOT
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    ///
    /// a.and_not(b) == (|&a: &usize| { a == 1 && !(a == 2) })
    /// ```
    fn and_not<F>(self, other: F) -> And<Self, Not<F::IntoFilt>>
        where Self: Sized,
              F: IntoFilter<N> + Sized
    {
        self.and(Not::new(other.into_filter()))
    }

    /// Helper to connect two filters via logical NAND
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    ///
    /// a.nand(b) == (|&a: &usize| { !(a == 1 && a == 2) })
    /// ```
    fn nand<F>(self, other: F) -> Not<And<Self, F>>
        where Self: Sized,
    {
        Not::new(And::new(self, other))
    }

}

#[cfg(test)]
mod test {
    use filter::Filter;
    use ops::and::And;

    #[test]
    fn closures() {
        let a = (|&a: &usize|{ a < 3 }).and(|&a: &usize| a > 1);

        assert_eq!(a.filter(&2), true);
    }

    #[test]
    fn and_filter() {
        let a = And::new(|&a: &usize| a > 0, |&a: &usize| a == 3);

        assert_eq!(a.filter(&3),  true);
        assert_eq!(a.filter(&5),  false);
        assert_eq!(a.filter(&0), false);
    }

    #[test]
    fn complex_filter() {
        let a = (|&a: &usize|{ a > 5 }).and_not(|&a: &usize| a < 20).or(|&a: &usize| a == 10);
        // We now have ((a > 5) && !(a < 20) ) || a == 10

        assert_eq!(a.filter(&21), true);
        assert_eq!(a.filter(&10), true);
        assert_eq!(a.filter(&11), false);
        assert_eq!(a.filter(&5), false);
    }

    #[test]
    fn complex_filter_closured() {
        let a = (|&a: &usize| (|&a: &usize|{ a > 5 }).and_not(|&a: &usize| a < 20).filter(&a)).or(|&a: &usize| a == 10);
        // We now have ((a > 5) && !(a < 20)) || a == 10

        assert_eq!(a.filter(&21), true);
        assert_eq!(a.filter(&10), true);
        assert_eq!(a.filter(&11), false);
        assert_eq!(a.filter(&5), false);
    }

    #[test]
    fn complex_filter_named_closures() {
        let not_eq_to_one   = |&a: &usize| { a != 1 };
        let not_eq_to_two   = |&a: &usize| { a != 2 };
        let not_eq_to_three = |&a: &usize| { a != 3 };

        let a = not_eq_to_one.and(not_eq_to_two).and(not_eq_to_three);
        // We now have ((a > 5) && !(a < 20)) || a == 10

        assert_eq!(a.filter(&21), true);
        assert_eq!(a.filter(&10), true);
        assert_eq!(a.filter(&1), false);
        assert_eq!(a.filter(&3), false);
    }

    struct EqTo {
        pub i: usize,
    }

    impl Filter<usize> for EqTo {
        fn filter(&self, n: &usize) -> bool {
            self.i == *n
        }
    }

    #[test]
    fn filter_with_eqto() {
        let eq = EqTo { i: 0 };
        assert_eq!(eq.filter(&0),  true);
        assert_eq!(eq.filter(&1),  false);
        assert_eq!(eq.filter(&17), false);
        assert_eq!(eq.filter(&42), false);
    }

    #[test]
    fn filter_with_combined_eqto() {
        let aeq = EqTo { i: 1 }.not().and_not(EqTo { i: 17 });

        assert_eq!(aeq.filter(&0),  true);
        assert_eq!(aeq.filter(&1),  false);
        assert_eq!(aeq.filter(&2),  true);
        assert_eq!(aeq.filter(&17), false);
    }

    #[test]
    fn filter_iterator() {
        let v = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];

        let inrange        = (|&a: &usize| { a > 5 }).and(|&a: &usize| { a < 15 });

        let r : Vec<usize> = v.into_iter().filter(|x| inrange.filter(x)).collect();

        assert_eq!(r, vec![6, 7, 8, 9, 10, 11, 12, 13, 14]);
    }
}
<commit_msg>Add test for Filter::xor()<commit_after>//! The filter implementation
//!

pub use ops::and::And;
pub use ops::not::Not;
pub use ops::xor::XOr;
pub use ops::or::Or;

/// Trait for converting something into a Filter
pub trait IntoFilter<N> {
    type IntoFilt: Filter<N>;

    fn into_filter(self) -> Self::IntoFilt;
}

/// All Filters can be turned into Filters
impl<N, I: Filter<N>> IntoFilter<N> for I {
    type IntoFilt = I;

    fn into_filter(self) -> I {
        self
    }
}

/// All closures that take a ref to something and return bool are filters
impl<I, T: Fn(&I) -> bool> Filter<I> for T {
    fn filter(&self, other: &I) -> bool {
        self(other)
    }
}

/// The filter trai
pub trait Filter<N> {

    /// The function which is used to filter something
    fn filter(&self, &N) -> bool;

    /// Helper to invert a filter.
    ///
    /// ```ignore
    /// (|&a: &usize| { a == 1 }).not() == (|&a: &usize| { a != 1 })
    /// ```
    fn not(self) -> Not<Self>
        where Self: Sized
    {
        Not::new(self)
    }

    /// Helper to connect two filters via logical OR
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    ///
    /// a.or(b) == (|&a: &usize| { a == 1 || a == 2 })
    /// ```
    fn or<F>(self, other: F) -> Or<Self, F::IntoFilt>
        where Self: Sized,
              F: IntoFilter<N> + Sized
    {
        Or::new(self, other.into_filter())
    }

    /// Helper to connect two filters via logical OR and NOT
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    ///
    /// a.or_not(b) == (|&a: &usize| { a == 1 || !(a == 2) })
    /// ```
    fn or_not<F>(self, other: F) -> Or<Self, Not<F::IntoFilt>>
        where Self: Sized,
              F: IntoFilter<N> + Sized,
    {
        self.or(Not::new(other.into_filter()))
    }

    /// Helper to connect three filters via logical OR
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    /// let c = (|&a: &usize| { a == 3 });
    ///
    /// a.or3(b, c) == (|&a: &usize| { a == 1 || a == 2 || a == 3 })
    /// ```
    fn or3<F, F2>(self, other: F, other2: F2) -> Or<Self, Or<F::IntoFilt, F2::IntoFilt>>
        where Self: Sized,
              F: IntoFilter<N> + Sized,
              F2: IntoFilter<N> + Sized
    {
        Or::new(self, Or::new(other.into_filter(), other2.into_filter()))
    }

    /// Helper to connect two filters via logical NOR
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    ///
    /// a.nor(b) == (|&a: &usize| { !(a == 1 || a == 2) })
    /// ```
    fn nor<F>(self, other: F) -> Not<Or<Self, F>>
        where Self: Sized,
    {
        Not::new(Or::new(self, other))
    }

    /// Helper to connect two filters via logical XOR
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    ///
    /// a.xor(b) == (|&a: &usize| { !(a == 1 || a == 2) })
    /// ```
    fn xor<F>(self, other: F) -> XOr<Self, F>
        where Self: Sized,
    {
        XOr::new(self, other)
    }

    /// Helper to connect two filters via logical AND
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    ///
    /// a.and(b) == (|&a: &usize| { a == 1 && a == 2 })
    /// ```
    fn and<F>(self, other: F) -> And<Self, F::IntoFilt>
        where Self: Sized,
              F: IntoFilter<N> + Sized
    {
        And::new(self, other.into_filter())
    }

    /// Helper to connect three filters via logical AND
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    /// let c = (|&a: &usize| { a == 3 });
    ///
    /// a.and3(b, c) == (|&a: &usize| { a == 1 && a == 2 && a == 3 })
    /// ```
    fn and3<F, F2>(self, other: F, other2: F2) -> And<Self, And<F::IntoFilt, F2::IntoFilt>>
        where Self: Sized,
              F: IntoFilter<N> + Sized,
              F2: IntoFilter<N> + Sized
    {
        And::new(self, And::new(other.into_filter(), other2.into_filter()))
    }

    /// Helper to connect two filters via logical AND and NOT
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    ///
    /// a.and_not(b) == (|&a: &usize| { a == 1 && !(a == 2) })
    /// ```
    fn and_not<F>(self, other: F) -> And<Self, Not<F::IntoFilt>>
        where Self: Sized,
              F: IntoFilter<N> + Sized
    {
        self.and(Not::new(other.into_filter()))
    }

    /// Helper to connect two filters via logical NAND
    ///
    /// ```ignore
    /// let a = (|&a: &usize| { a == 1 });
    /// let b = (|&a: &usize| { a == 2 });
    ///
    /// a.nand(b) == (|&a: &usize| { !(a == 1 && a == 2) })
    /// ```
    fn nand<F>(self, other: F) -> Not<And<Self, F>>
        where Self: Sized,
    {
        Not::new(And::new(self, other))
    }

}

#[cfg(test)]
mod test {
    use filter::Filter;
    use ops::and::And;

    #[test]
    fn closures() {
        let a = (|&a: &usize|{ a < 3 }).and(|&a: &usize| a > 1);

        assert_eq!(a.filter(&2), true);
    }

    #[test]
    fn and_filter() {
        let a = And::new(|&a: &usize| a > 0, |&a: &usize| a == 3);

        assert_eq!(a.filter(&3),  true);
        assert_eq!(a.filter(&5),  false);
        assert_eq!(a.filter(&0), false);
    }

    #[test]
    fn xor_filter() {
        let a = (|&a: &usize| a == 0).xor(|&a: &usize| a == 3);

        assert_eq!(a.filter(&3), true);
        assert_eq!(a.filter(&5), false);
        assert_eq!(a.filter(&0), true);
    }

    #[test]
    fn complex_filter() {
        let a = (|&a: &usize|{ a > 5 }).and_not(|&a: &usize| a < 20).or(|&a: &usize| a == 10);
        // We now have ((a > 5) && !(a < 20) ) || a == 10

        assert_eq!(a.filter(&21), true);
        assert_eq!(a.filter(&10), true);
        assert_eq!(a.filter(&11), false);
        assert_eq!(a.filter(&5), false);
    }

    #[test]
    fn complex_filter_closured() {
        let a = (|&a: &usize| (|&a: &usize|{ a > 5 }).and_not(|&a: &usize| a < 20).filter(&a)).or(|&a: &usize| a == 10);
        // We now have ((a > 5) && !(a < 20)) || a == 10

        assert_eq!(a.filter(&21), true);
        assert_eq!(a.filter(&10), true);
        assert_eq!(a.filter(&11), false);
        assert_eq!(a.filter(&5), false);
    }

    #[test]
    fn complex_filter_named_closures() {
        let not_eq_to_one   = |&a: &usize| { a != 1 };
        let not_eq_to_two   = |&a: &usize| { a != 2 };
        let not_eq_to_three = |&a: &usize| { a != 3 };

        let a = not_eq_to_one.and(not_eq_to_two).and(not_eq_to_three);
        // We now have ((a > 5) && !(a < 20)) || a == 10

        assert_eq!(a.filter(&21), true);
        assert_eq!(a.filter(&10), true);
        assert_eq!(a.filter(&1), false);
        assert_eq!(a.filter(&3), false);
    }

    struct EqTo {
        pub i: usize,
    }

    impl Filter<usize> for EqTo {
        fn filter(&self, n: &usize) -> bool {
            self.i == *n
        }
    }

    #[test]
    fn filter_with_eqto() {
        let eq = EqTo { i: 0 };
        assert_eq!(eq.filter(&0),  true);
        assert_eq!(eq.filter(&1),  false);
        assert_eq!(eq.filter(&17), false);
        assert_eq!(eq.filter(&42), false);
    }

    #[test]
    fn filter_with_combined_eqto() {
        let aeq = EqTo { i: 1 }.not().and_not(EqTo { i: 17 });

        assert_eq!(aeq.filter(&0),  true);
        assert_eq!(aeq.filter(&1),  false);
        assert_eq!(aeq.filter(&2),  true);
        assert_eq!(aeq.filter(&17), false);
    }

    #[test]
    fn filter_iterator() {
        let v = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];

        let inrange        = (|&a: &usize| { a > 5 }).and(|&a: &usize| { a < 15 });

        let r : Vec<usize> = v.into_iter().filter(|x| inrange.filter(x)).collect();

        assert_eq!(r, vec![6, 7, 8, 9, 10, 11, 12, 13, 14]);
    }
}
<|endoftext|>