<commit_before>//! Processor
//!
//! ## Terminololgy
//! * Evaluator - a code fragment to evaluate an expression
//! * Processor - A list of evaluators
//!
//! ## Phases for Generation
//!

use std::convert::From;
use std::rc::Rc;

use common::err::{Error, Result, Void, void_ok};
use common::func::{
	NoArgFn,
	UnaryFn,
	BinaryFn,
	TrinityFn
};
use common::plugin::{
	FuncRegistry,
	TypeRegistry
};
use common::rows::{
	MiniPage,
  FMiniPage,
	Page,
	OwnedPageBuilder,
	PageId
};
use common::session::Session;
use common::types::{Ty, name};

use jit::{JitCompiler};
use jit::builder::{Builder, CastOp};
use jit::types::{self, LLVMTy};
use jit::value::{Function, Predicate, Value, ValueRef, ToValue};
use plan::expr::*;
use plan::expr::visitor::{accept_by_default, Visitor};

use driver::DriverContext;
use super::NamedSchema;

#[repr(C)]
pub struct MiniPage2 {
  ptr: *const u8,
  size: usize
}

pub type MapFunc = extern "C" fn(&mut MiniPage2) -> i32;

macro_rules! unary_codegen (
  ($name:ident, $func:ident) => (
    pub fn $name(&mut self, expr: &Expr)
    {
      let val = self.visit(expr);
      let builder = &self.builder;

      self.stack.push(builder.$func(&val));
    }
  );
);

macro_rules! bin_codegen (
  ($name:ident, $func:ident) => (
    pub fn $name(&mut self, lhs: &Expr, rhs: &Expr)
    {
      println!("before lhs");
      let lhs_val = self.visit(lhs);
      println!("before rhs");
      let rhs_val = self.visit(rhs);
      let builder = &self.builder;

      self.stack.push(builder.$func(&lhs_val, &rhs_val));
    }
  );
);

fn to_llvm_ty<'a>(jit: &'a JitCompiler, ty: &Ty) -> &'a types::Ty
{
  match *ty {
    Ty::Bool => jit.get_bool_ty(),
    Ty::I8   => jit.get_i8_ty(),
    Ty::I16  => jit.get_i16_ty(),
    Ty::I32  => jit.get_i32_ty(),
    Ty::I64  => jit.get_i64_ty(),
    Ty::F32  => jit.get_f32_ty(),
    Ty::F64  => jit.get_f64_ty(),
    _        => panic!("not supported type: {}", ty.base())
  }
}

pub struct MapCompiler;

impl MapCompiler {
  pub fn compile(jit: &JitCompiler, fn_reg: &FuncRegistry, sess: &Session, schema: &NamedSchema, expr: &Expr) -> Result<Rc<MapFunc>> {
    let builder = jit.new_builder();
    let func = MapCompiler::create_fn_prototype(jit, &builder);

    let mut exprc = ExprCompiler::new(jit, fn_reg, sess, schema, &builder);
    let codegen = try!(exprc.compile(expr));
    builder.create_ret(&codegen);
    // dump code
    jit.dump();
    try!(MapCompiler::verify(jit));
    Ok(MapCompiler::ret_func(jit, &func))
  }

  fn create_fn_prototype(jit: &JitCompiler, bld: &Builder) -> Function {
    let minipage_ty = jit.get_ty("struct.MiniPage").unwrap();
    let minipage_ptr_ty = jit.get_pointer_ty(&minipage_ty);
    jit.create_func_prototype(
      "processor",
      &i32::llvm_ty(jit.context()),
      &[&minipage_ptr_ty],
      Some(bld))
  }

  fn verify(jit: &JitCompiler) -> Result<()> {
    match jit.verify() {
      Ok(_) => Ok(()),
      Err(msg) => {
        error!("{}", msg);
        Err(Error::CorruptedFunction(msg.to_owned()))
      }
    }
  }

 fn ret_func(jit: &JitCompiler, func: &Function) -> Rc<MapFunc> {
    let func_ptr = unsafe { jit.get_func_ptr(func).unwrap() };
    let func = unsafe {::std::mem::transmute(func_ptr)};
    Rc::new(func)
  }
}

pub struct ExprCompiler<'a>
{
  jit  : &'a JitCompiler,
  types: &'a Vec<Ty>,
	names: &'a Vec<&'a str>,
	stack: Vec<Value>,
  error: Option<Error>,
  builder: &'a Builder
}

impl<'a> ExprCompiler<'a> {
  fn new(jit: &'a JitCompiler,
         fn_registry: &FuncRegistry,
		     session: &Session,
		     schema : &'a NamedSchema, builder: &'a Builder) -> ExprCompiler<'a> {
		ExprCompiler {
      jit   : jit,
			types : &schema.types,
			names : &schema.names,
			stack : Vec::new(),
			error : None,
      builder: builder
		}
	}

  pub fn compile(&mut self, expr: &Expr) -> Result<Value>
  {
    self.accept(expr);
    match self.stack.pop() {
      Some(v) => Ok(v),
      None    => Err(Error::CorruptedFunction("empty value stack".to_string()))
    }
  }

  /*
  fn generate_scalar_func(map: &mut ExprCompiler, jit: &JitCompiler) {
    let func = &map.func;
    let builder = &map.builder;

    let codegen = map.stack.pop().unwrap();
    let minipage: Value = func.arg(0).into();

    let call = match jit.get_func("test") {
      Some(f) => {
        builder.create_call(&f, &[&minipage, &codegen])
      },
      _       => panic!("No such a function")
    };
    builder.create_ret(&call);
  }*/

  #[inline(always)]
  fn visit(&mut self, expr: &Expr) -> Value
  {
    self.accept(expr);
    // Stack must contain at least one Value item.
    // Otherwise, it is definitely a bug.
    self.stack.pop().unwrap()
  }

  #[inline(always)]
  fn push_value<T: ToValue>(&mut self, val: &T)
  {
    let v = val.to_value(self.jit.context());
    self.stack.push(v);
  }

  unary_codegen!(Not, create_not);

	pub fn IsNull(&self, c: &Expr)
	{
	}

	pub fn IsNotNull(&self, e: &Expr)
	{
	}

	pub fn PlusSign(&mut self, e: &Expr)
	{
    self.accept(e);
	}

  unary_codegen!(MinusSign, create_neg);

	pub fn Cast(&mut self, e: &Expr, from: &Ty, to: &Ty)
	{
    // if the both types are equivalent, just return.
    if from == to { return; }

    let cast_op = if from.is_sint() && to.is_sint() {
      if from.size_of() < to.size_of() {
        CastOp::SExt
      } else {
        CastOp::Trunc
      }
    } else if from.is_sint() && to.is_float() {
      CastOp::SIToFP
    } else if from.is_uint() && to.is_float() {
      CastOp::UIToFP
    } else if from.is_float() && to.is_sint() {
      CastOp::FPToSI
    } else if from.is_float() && to.is_uint() {
      CastOp::FPToUI
    } else if from.is_float() && to.is_float() {
      if from.size_of() < to.size_of() {
        CastOp::FPExt
      } else {
        CastOp::FPTrunc
      }
    } else {
      panic!("not supported cast from {} to {}", from.base(), to.base());
    };

    let val = self.visit(e);
    let builder = &self.builder;

    self.stack.push(builder.create_cast(cast_op, &val, to_llvm_ty(self.jit, to)));
	}

  bin_codegen!(And, create_and);
  bin_codegen!(Or,  create_or);
  bin_codegen!(Xor, create_xor);

	pub fn Cmp(&mut self, op: &CmpOp, lhs: &Expr, rhs: &Expr)
	{
    let lhs_val = self.visit(lhs);
    let rhs_val = self.visit(rhs);

    let builder = &self.builder;

    let pred = match *op {
      CmpOp::Eq => Predicate::Eq,
      CmpOp::Ne => Predicate::Ne,
      CmpOp::Lt => Predicate::Lt,
      CmpOp::Le => Predicate::Le,
      CmpOp::Gt => Predicate::Gt,
      CmpOp::Ge => Predicate::Ge
    };

    self.stack.push(builder.create_cmp(&lhs_val, &rhs_val, pred));
	}

	pub fn Arithm(&mut self, ty: &Ty, op: &ArithmOp, lhs: &Expr, rhs: &Expr)
	{
    let lhs_val = self.visit(lhs);
    let rhs_val = self.visit(rhs);

    let builder = &self.builder;

    self.stack.push(match *op {
      ArithmOp::Plus => {builder.create_add(&lhs_val, &rhs_val)}
      ArithmOp::Sub  => {builder.create_sub(&lhs_val, &rhs_val)}
      ArithmOp::Mul  => {builder.create_mul(&lhs_val, &rhs_val)}
      ArithmOp::Div  => {builder.create_div(&lhs_val, &rhs_val)}
      ArithmOp::Rem  => {builder.create_rem(&lhs_val, &rhs_val)}
    });
	}

	pub fn Func(&self, f: &FnDecl, args: &Vec<Box<Expr>>)
	{
	}

  pub fn Const(&mut self, l: &Literal)
  {
    match *l {
      Literal::U8(ref v)  => self.push_value(v),
      Literal::I8(ref v)  => self.push_value(v),
      Literal::I16(ref v) => self.push_value(v),
      Literal::I32(ref v) => self.push_value(v),
      Literal::I64(ref v) => self.push_value(v),
      Literal::F32(ref v) => self.push_value(v),
      Literal::F64(ref v) => self.push_value(v),
      _                    => unimplemented!()
    }
  }

	pub fn Field(&mut self, ty: &Ty, name: &str)
	{
		/*
    let found: Option<(usize, &Ty, &&str)>;

		found = izip!(0 .. self.types.len(), self.types, self.names)
						.find(|&(i, t, n)| *n == name);

    let eval = match found {
    	Some(f) => FieldEvaluator {idx: f.0, ty: f.1.clone()},
    	None    => panic!("no such field for {}", name)
    };*/
	}
}

impl<'a> visitor::Visitor for ExprCompiler<'a>
{
	fn accept(&mut self, e: &Expr)
	{
	  match *e.kind() {
	    ExprKind::Not      (ref c)               => self.Not(c),
	    ExprKind::IsNull   (ref c)               => self.IsNull(c),
	    ExprKind::IsNotNull(ref c)               => self.IsNotNull(c),
	    ExprKind::PlusSign (ref c)               => self.PlusSign(c),
	    ExprKind::MinusSign(ref c)               => self.MinusSign(c),
	    ExprKind::Cast     (ref c, ref f, ref t) => self.Cast(c, f, t),

	    ExprKind::And      (ref l, ref r)        => self.And(l, r),
	    ExprKind::Or       (ref l, ref r)        => self.Or(l, r),
	    ExprKind::Cmp      (ref o, ref l, ref r) => self.Cmp(o, l, r),
	    ExprKind::Arithm   (ref o, ref l, ref r) => self.Arithm(e.ty(), o, l, r),

	    ExprKind::Fn     (ref f, ref args)  => self.Func(f, args),
			ExprKind::Field  (ref name)         => self.Field(e.ty(), name),
	    ExprKind::Const  (ref lit)          => self.Const(lit),
	    /*
	    ExprKind::Switch(ref cases, ref default) => {
	    	for c in cases.iter() {
	    		v.accept(c);
	   	  }

	    	v.accept(default);
	    },

	    ExprKind::Case   (ref l, ref r) => { v.accept(l); v.accept(r) },*/
	    _ => panic!("")
	  }
	}
}

pub trait Processor
{
  fn process(
    &self,
    input: &Page,
    builder: &mut OwnedPageBuilder) -> Void;
}

#[cfg(test)]
mod tests {
	use common::rows::{
		Page,
		OwnedPageBuilder,
		PageId
	};
	use common::plugin::*;
	use common::session::Session;
	use common::storage::{RandomTable, MemTable};
	use common::types::*;

  use jit::JitCompiler;

	use plan::expr::*;
	use driver::DriverContext;

	use super::super::NamedSchema;

	use super::*;

  #[test]
  pub fn codegen() {
    let plugin_mgr = PluginManager::new();
    let jit = JitCompiler::new_from_bc("../common/target/ir/common.bc").ok().unwrap();
    assert!(jit.get_ty("struct.MiniPage").is_some());
    assert!(jit.get_ty("struct.Page").is_some());

    let types: Vec<Ty> = schema!(
	    I64, // l_orderkey      bigint
	    I64, // l_partkey       bigint
	    I64, // l_suppkey       bigint
	    I32, // l_linenumber    int
	    F64, // l_quantity      double,
	    F64, // l_extendedprice double,
	    F64, // l_discount      double,
	    F64  // l_tax           double,
	    // string types are not implmeneted yet.
    );

	  let names: Vec<&str> = vec![
	  	"l_orderkey",
	  	"l_partkey",
	  	"l_suppkey",
	  	"l_linenumber",
	  	"l_quantity",
	  	"l_extendedprice",
	  	"l_discount",
	  	"l_tax"
	  ];

    let expr = Plus(I32, Const(19800401i32), Const(1i32));
    //let expr = Or(Const(4i32), Const(2i32));
    //let expr = Not(Const(0i32));
    //let expr = MinusSign(Const(7i32));
    let schema  = NamedSchema::new(&names, &types);
  	let session = Session;

    // let map = ExprCompiler::compile(&jit,
    //                                plugin_mgr.fn_registry(),
		// 															 &session,
		// 															 &schema,
		// 															 &expr).ok().unwrap();
    let map = MapCompiler::compile(&jit,
                          plugin_mgr.fn_registry(),
                          &session,
                          &schema,
                          &expr).ok().unwrap();

    let mut minipage = MiniPage2 {
      ptr: ::std::ptr::null(),
      size: 0
    };
    assert_eq!(map(&mut minipage), 19800401i32);
  }
}<commit_msg>Reindent MapCompiler::compile.<commit_after>//! Processor
//!
//! ## Terminololgy
//! * Evaluator - a code fragment to evaluate an expression
//! * Processor - A list of evaluators
//!
//! ## Phases for Generation
//!

use std::convert::From;
use std::rc::Rc;

use common::err::{Error, Result, Void, void_ok};
use common::func::{
	NoArgFn,
	UnaryFn,
	BinaryFn,
	TrinityFn
};
use common::plugin::{
	FuncRegistry,
	TypeRegistry
};
use common::rows::{
	MiniPage,
  FMiniPage,
	Page,
	OwnedPageBuilder,
	PageId
};
use common::session::Session;
use common::types::{Ty, name};

use jit::{JitCompiler};
use jit::builder::{Builder, CastOp};
use jit::types::{self, LLVMTy};
use jit::value::{Function, Predicate, Value, ValueRef, ToValue};
use plan::expr::*;
use plan::expr::visitor::{accept_by_default, Visitor};

use driver::DriverContext;
use super::NamedSchema;

#[repr(C)]
pub struct MiniPage2 {
  ptr: *const u8,
  size: usize
}

pub type MapFunc = extern "C" fn(&mut MiniPage2) -> i32;

macro_rules! unary_codegen (
  ($name:ident, $func:ident) => (
    pub fn $name(&mut self, expr: &Expr)
    {
      let val = self.visit(expr);
      let builder = &self.builder;

      self.stack.push(builder.$func(&val));
    }
  );
);

macro_rules! bin_codegen (
  ($name:ident, $func:ident) => (
    pub fn $name(&mut self, lhs: &Expr, rhs: &Expr)
    {
      println!("before lhs");
      let lhs_val = self.visit(lhs);
      println!("before rhs");
      let rhs_val = self.visit(rhs);
      let builder = &self.builder;

      self.stack.push(builder.$func(&lhs_val, &rhs_val));
    }
  );
);

fn to_llvm_ty<'a>(jit: &'a JitCompiler, ty: &Ty) -> &'a types::Ty
{
  match *ty {
    Ty::Bool => jit.get_bool_ty(),
    Ty::I8   => jit.get_i8_ty(),
    Ty::I16  => jit.get_i16_ty(),
    Ty::I32  => jit.get_i32_ty(),
    Ty::I64  => jit.get_i64_ty(),
    Ty::F32  => jit.get_f32_ty(),
    Ty::F64  => jit.get_f64_ty(),
    _        => panic!("not supported type: {}", ty.base())
  }
}

pub struct MapCompiler;

impl MapCompiler {
  pub fn compile(jit: &JitCompiler,
                 fn_reg: &FuncRegistry,
                 sess: &Session,
                 schema: &NamedSchema,
                 expr: &Expr) -> Result<Rc<MapFunc>> {
    let builder = jit.new_builder();
    let func = MapCompiler::create_fn_prototype(jit, &builder);

    let mut exprc = ExprCompiler::new(jit, fn_reg, sess, schema, &builder);
    let codegen = try!(exprc.compile(expr));
    builder.create_ret(&codegen);
    // dump code
    jit.dump();
    try!(MapCompiler::verify(jit));
    Ok(MapCompiler::ret_func(jit, &func))
  }

  fn create_fn_prototype(jit: &JitCompiler, bld: &Builder) -> Function {
    let minipage_ty = jit.get_ty("struct.MiniPage").unwrap();
    let minipage_ptr_ty = jit.get_pointer_ty(&minipage_ty);
    jit.create_func_prototype(
      "processor",
      &i32::llvm_ty(jit.context()),
      &[&minipage_ptr_ty],
      Some(bld))
  }

  fn verify(jit: &JitCompiler) -> Result<()> {
    match jit.verify() {
      Ok(_) => Ok(()),
      Err(msg) => {
        error!("{}", msg);
        Err(Error::CorruptedFunction(msg.to_owned()))
      }
    }
  }

 fn ret_func(jit: &JitCompiler, func: &Function) -> Rc<MapFunc> {
    let func_ptr = unsafe { jit.get_func_ptr(func).unwrap() };
    let func = unsafe {::std::mem::transmute(func_ptr)};
    Rc::new(func)
  }
}

pub struct ExprCompiler<'a>
{
  jit  : &'a JitCompiler,
  types: &'a Vec<Ty>,
	names: &'a Vec<&'a str>,
	stack: Vec<Value>,
  error: Option<Error>,
  builder: &'a Builder
}

impl<'a> ExprCompiler<'a> {
  fn new(jit: &'a JitCompiler,
         fn_registry: &FuncRegistry,
		     session: &Session,
		     schema : &'a NamedSchema, builder: &'a Builder) -> ExprCompiler<'a> {
		ExprCompiler {
      jit   : jit,
			types : &schema.types,
			names : &schema.names,
			stack : Vec::new(),
			error : None,
      builder: builder
		}
	}

  pub fn compile(&mut self, expr: &Expr) -> Result<Value>
  {
    self.accept(expr);
    match self.stack.pop() {
      Some(v) => Ok(v),
      None    => Err(Error::CorruptedFunction("empty value stack".to_string()))
    }
  }

  /*
  fn generate_scalar_func(map: &mut ExprCompiler, jit: &JitCompiler) {
    let func = &map.func;
    let builder = &map.builder;

    let codegen = map.stack.pop().unwrap();
    let minipage: Value = func.arg(0).into();

    let call = match jit.get_func("test") {
      Some(f) => {
        builder.create_call(&f, &[&minipage, &codegen])
      },
      _       => panic!("No such a function")
    };
    builder.create_ret(&call);
  }*/

  #[inline(always)]
  fn visit(&mut self, expr: &Expr) -> Value
  {
    self.accept(expr);
    // Stack must contain at least one Value item.
    // Otherwise, it is definitely a bug.
    self.stack.pop().unwrap()
  }

  #[inline(always)]
  fn push_value<T: ToValue>(&mut self, val: &T)
  {
    let v = val.to_value(self.jit.context());
    self.stack.push(v);
  }

  unary_codegen!(Not, create_not);

	pub fn IsNull(&self, c: &Expr)
	{
	}

	pub fn IsNotNull(&self, e: &Expr)
	{
	}

	pub fn PlusSign(&mut self, e: &Expr)
	{
    self.accept(e);
	}

  unary_codegen!(MinusSign, create_neg);

	pub fn Cast(&mut self, e: &Expr, from: &Ty, to: &Ty)
	{
    // if the both types are equivalent, just return.
    if from == to { return; }

    let cast_op = if from.is_sint() && to.is_sint() {
      if from.size_of() < to.size_of() {
        CastOp::SExt
      } else {
        CastOp::Trunc
      }
    } else if from.is_sint() && to.is_float() {
      CastOp::SIToFP
    } else if from.is_uint() && to.is_float() {
      CastOp::UIToFP
    } else if from.is_float() && to.is_sint() {
      CastOp::FPToSI
    } else if from.is_float() && to.is_uint() {
      CastOp::FPToUI
    } else if from.is_float() && to.is_float() {
      if from.size_of() < to.size_of() {
        CastOp::FPExt
      } else {
        CastOp::FPTrunc
      }
    } else {
      panic!("not supported cast from {} to {}", from.base(), to.base());
    };

    let val = self.visit(e);
    let builder = &self.builder;

    self.stack.push(builder.create_cast(cast_op, &val, to_llvm_ty(self.jit, to)));
	}

  bin_codegen!(And, create_and);
  bin_codegen!(Or,  create_or);
  bin_codegen!(Xor, create_xor);

	pub fn Cmp(&mut self, op: &CmpOp, lhs: &Expr, rhs: &Expr)
	{
    let lhs_val = self.visit(lhs);
    let rhs_val = self.visit(rhs);

    let builder = &self.builder;

    let pred = match *op {
      CmpOp::Eq => Predicate::Eq,
      CmpOp::Ne => Predicate::Ne,
      CmpOp::Lt => Predicate::Lt,
      CmpOp::Le => Predicate::Le,
      CmpOp::Gt => Predicate::Gt,
      CmpOp::Ge => Predicate::Ge
    };

    self.stack.push(builder.create_cmp(&lhs_val, &rhs_val, pred));
	}

	pub fn Arithm(&mut self, ty: &Ty, op: &ArithmOp, lhs: &Expr, rhs: &Expr)
	{
    let lhs_val = self.visit(lhs);
    let rhs_val = self.visit(rhs);

    let builder = &self.builder;

    self.stack.push(match *op {
      ArithmOp::Plus => {builder.create_add(&lhs_val, &rhs_val)}
      ArithmOp::Sub  => {builder.create_sub(&lhs_val, &rhs_val)}
      ArithmOp::Mul  => {builder.create_mul(&lhs_val, &rhs_val)}
      ArithmOp::Div  => {builder.create_div(&lhs_val, &rhs_val)}
      ArithmOp::Rem  => {builder.create_rem(&lhs_val, &rhs_val)}
    });
	}

	pub fn Func(&self, f: &FnDecl, args: &Vec<Box<Expr>>)
	{
	}

  pub fn Const(&mut self, l: &Literal)
  {
    match *l {
      Literal::U8(ref v)  => self.push_value(v),
      Literal::I8(ref v)  => self.push_value(v),
      Literal::I16(ref v) => self.push_value(v),
      Literal::I32(ref v) => self.push_value(v),
      Literal::I64(ref v) => self.push_value(v),
      Literal::F32(ref v) => self.push_value(v),
      Literal::F64(ref v) => self.push_value(v),
      _                    => unimplemented!()
    }
  }

	pub fn Field(&mut self, ty: &Ty, name: &str)
	{
		/*
    let found: Option<(usize, &Ty, &&str)>;

		found = izip!(0 .. self.types.len(), self.types, self.names)
						.find(|&(i, t, n)| *n == name);

    let eval = match found {
    	Some(f) => FieldEvaluator {idx: f.0, ty: f.1.clone()},
    	None    => panic!("no such field for {}", name)
    };*/
	}
}

impl<'a> visitor::Visitor for ExprCompiler<'a>
{
	fn accept(&mut self, e: &Expr)
	{
	  match *e.kind() {
	    ExprKind::Not      (ref c)               => self.Not(c),
	    ExprKind::IsNull   (ref c)               => self.IsNull(c),
	    ExprKind::IsNotNull(ref c)               => self.IsNotNull(c),
	    ExprKind::PlusSign (ref c)               => self.PlusSign(c),
	    ExprKind::MinusSign(ref c)               => self.MinusSign(c),
	    ExprKind::Cast     (ref c, ref f, ref t) => self.Cast(c, f, t),

	    ExprKind::And      (ref l, ref r)        => self.And(l, r),
	    ExprKind::Or       (ref l, ref r)        => self.Or(l, r),
	    ExprKind::Cmp      (ref o, ref l, ref r) => self.Cmp(o, l, r),
	    ExprKind::Arithm   (ref o, ref l, ref r) => self.Arithm(e.ty(), o, l, r),

	    ExprKind::Fn     (ref f, ref args)  => self.Func(f, args),
			ExprKind::Field  (ref name)         => self.Field(e.ty(), name),
	    ExprKind::Const  (ref lit)          => self.Const(lit),
	    /*
	    ExprKind::Switch(ref cases, ref default) => {
	    	for c in cases.iter() {
	    		v.accept(c);
	   	  }

	    	v.accept(default);
	    },

	    ExprKind::Case   (ref l, ref r) => { v.accept(l); v.accept(r) },*/
	    _ => panic!("")
	  }
	}
}

pub trait Processor
{
  fn process(
    &self,
    input: &Page,
    builder: &mut OwnedPageBuilder) -> Void;
}

#[cfg(test)]
mod tests {
	use common::rows::{
		Page,
		OwnedPageBuilder,
		PageId
	};
	use common::plugin::*;
	use common::session::Session;
	use common::storage::{RandomTable, MemTable};
	use common::types::*;

  use jit::JitCompiler;

	use plan::expr::*;
	use driver::DriverContext;

	use super::super::NamedSchema;

	use super::*;

  #[test]
  pub fn codegen() {
    let plugin_mgr = PluginManager::new();
    let jit = JitCompiler::new_from_bc("../common/target/ir/common.bc").ok().unwrap();
    assert!(jit.get_ty("struct.MiniPage").is_some());
    assert!(jit.get_ty("struct.Page").is_some());

    let types: Vec<Ty> = schema!(
	    I64, // l_orderkey      bigint
	    I64, // l_partkey       bigint
	    I64, // l_suppkey       bigint
	    I32, // l_linenumber    int
	    F64, // l_quantity      double,
	    F64, // l_extendedprice double,
	    F64, // l_discount      double,
	    F64  // l_tax           double,
	    // string types are not implmeneted yet.
    );

	  let names: Vec<&str> = vec![
	  	"l_orderkey",
	  	"l_partkey",
	  	"l_suppkey",
	  	"l_linenumber",
	  	"l_quantity",
	  	"l_extendedprice",
	  	"l_discount",
	  	"l_tax"
	  ];

    let expr = Plus(I32, Const(19800401i32), Const(1i32));
    //let expr = Or(Const(4i32), Const(2i32));
    //let expr = Not(Const(0i32));
    //let expr = MinusSign(Const(7i32));
    let schema  = NamedSchema::new(&names, &types);
  	let session = Session;

    // let map = ExprCompiler::compile(&jit,
    //                                plugin_mgr.fn_registry(),
		// 															 &session,
		// 															 &schema,
		// 															 &expr).ok().unwrap();
    let map = MapCompiler::compile(&jit,
                          plugin_mgr.fn_registry(),
                          &session,
                          &schema,
                          &expr).ok().unwrap();

    let mut minipage = MiniPage2 {
      ptr: ::std::ptr::null(),
      size: 0
    };
    assert_eq!(map(&mut minipage), 19800401i32);
  }
}<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
extern crate futures;
extern crate tokio_core as tokio;
extern crate tokio_service as service;
extern crate tokio_proto as proto;
extern crate tokio_timer;
extern crate env_logger;
extern crate vastatrix;

use std::net::SocketAddr;
use std::time::Duration;

use tokio::reactor::Core;
use futures::Future;
use vastatrix::LogPos;

use vastatrix::hosting::*;

#[test]
fn smoketest_single_node() {
    env_logger::init().unwrap_or(());

    let mut core = Core::new().unwrap();
    let timer = tokio_timer::wheel().tick_duration(Duration::from_millis(1)).build();
    let timeout = Duration::from_millis(1000);

    let local_anon_addr: SocketAddr = "127.0.0.1:0".parse().unwrap();

    let server = build_server(
                                        &core.handle(),
                                        local_anon_addr.clone(),
                                        local_anon_addr.clone())
                     .expect("start server");
    println!("running: {:?}", server);

    info!("Head at: {:?}, tail at: {:?}",
          server.head,
          server.tail);
    let client = vastatrix::ThickClient::new(core.handle(),
                                             &server.head,
                                             &server.tail);

    let f = client.log_item(b"hello".to_vec())
                  .and_then(|pos0| {
                      client.log_item(b"world".to_vec()).map(move |pos1| (pos0, pos1))
                  });
    let (wpos0, wpos1) = core.run(timer.timeout(f, timeout)).expect("run write");

    info!("Wrote to offset:{:?}", (wpos0, wpos1));

    let item_f = client.fetch_next(LogPos::zero())
                       .and_then(|(pos0, val0)| {
                           client.fetch_next(pos0).map(move |second| vec![(pos0, val0), second])
                       });

    let read = core.run(timer.timeout(item_f, timeout)).expect("run read");
    info!("Got: {:?}", read);

    assert_eq!(read,
               vec![(wpos0, b"hello".to_vec()), (wpos1, b"world".to_vec())]);
}

#[test]
fn smoketest_two_member_chain() {
    env_logger::init().unwrap_or(());
    let timer = tokio_timer::wheel().tick_duration(Duration::from_millis(1)).build();
    let timeout = Duration::from_millis(1000);
    let mut core = Core::new().unwrap();

    let local_anon_addr: SocketAddr = "127.0.0.1:0".parse().unwrap();

    let server0 = build_server(
                      &core.handle(),
                      local_anon_addr.clone(),
                      local_anon_addr.clone())
        .expect("start server");
    println!("running: {:?}", server0);

    let server1 = build_server(
                      &core.handle(),
                      local_anon_addr.clone(),
                      local_anon_addr.clone())
        .expect("start server");

    println!("running: {:?}", server1);

    let client = vastatrix::ThickClient::new(core.handle(), &server0.head, &server1.tail);

    let f = client.add_peer(server1.clone())
        .and_then(|_| client.log_item(b"hello".to_vec()))
        .and_then(|pos0| client.log_item(b"world".to_vec()).map(move |pos1| (pos0, pos1)));
    let (wpos0, wpos1) = core.run(timer.timeout(f, timeout)).expect("run write");

    info!("Wrote to offset:{:?}", (wpos0, wpos1));

    let item_f = client.fetch_next(LogPos::zero())
        .and_then(|(pos0, val0)| {
            client.fetch_next(pos0).map(move |second| vec![(pos0, val0), second])
        });

    let read = core.run(timer.timeout(item_f, timeout)).expect("run read");
    info!("Got: {:?}", read);

    assert_eq!(read,
               vec![(wpos0, b"hello".to_vec()), (wpos1, b"world".to_vec())]);
}

#[cfg(never)]
#[test]
fn smoketest_bovine() {
    env_logger::init().unwrap_or(());

    let mut net = bovine::SphericalBovine::new();

    let scheduler = bovine::Scheduler::new();

    let service = CoreService::new();
    let server = net.build_server(service,
                      &scheduler,
                      bovine::BovineAddr(0),
                      bovine::BovineAddr(1))
        .expect("start server");
    println!("running: {:?}", server);

    info!("Head at: {:?}, tail at: {:?}", server.head, server.tail);

    let head_client = ReplicaClient::build(&scheduler, &server.head);
    let tail_client = TailClient::build(&scheduler, &server.tail);
    let client = vastatrix::ThickClient::build(head_client, tail_client);

    let f = client.log_item(b"hello".to_vec())
        .and_then(|pos0| client.log_item(b"world".to_vec()).map(move |pos1| (pos0, pos1)));
    let (wpos0, wpos1) = scheduler.run(f).expect("run write");

    info!("Wrote to offset:{:?}", (wpos0, wpos1));

    let item_f = client.fetch_next(LogPos::zero())
        .and_then(|(pos0, val0)| {
            client.fetch_next(pos0).map(move |second| vec![(pos0, val0), second])
        });

    let read = scheduler.run(item_f).expect("run read");
    info!("Got: {:?}", read);

    assert_eq!(read,
               vec![(wpos0, b"hello".to_vec()), (wpos1, b"world".to_vec())]);
}
<commit_msg>GC un-used simulator related test.<commit_after>#[macro_use]
extern crate log;
extern crate futures;
extern crate tokio_core as tokio;
extern crate tokio_service as service;
extern crate tokio_proto as proto;
extern crate tokio_timer;
extern crate env_logger;
extern crate vastatrix;

use std::net::SocketAddr;
use std::time::Duration;

use tokio::reactor::Core;
use futures::Future;
use vastatrix::LogPos;

use vastatrix::hosting::*;

#[test]
fn smoketest_single_node() {
    env_logger::init().unwrap_or(());

    let mut core = Core::new().unwrap();
    let timer = tokio_timer::wheel().tick_duration(Duration::from_millis(1)).build();
    let timeout = Duration::from_millis(1000);

    let local_anon_addr: SocketAddr = "127.0.0.1:0".parse().unwrap();

    let server = build_server(
                                        &core.handle(),
                                        local_anon_addr.clone(),
                                        local_anon_addr.clone())
                     .expect("start server");
    println!("running: {:?}", server);

    info!("Head at: {:?}, tail at: {:?}",
          server.head,
          server.tail);
    let client = vastatrix::ThickClient::new(core.handle(),
                                             &server.head,
                                             &server.tail);

    let f = client.log_item(b"hello".to_vec())
                  .and_then(|pos0| {
                      client.log_item(b"world".to_vec()).map(move |pos1| (pos0, pos1))
                  });
    let (wpos0, wpos1) = core.run(timer.timeout(f, timeout)).expect("run write");

    info!("Wrote to offset:{:?}", (wpos0, wpos1));

    let item_f = client.fetch_next(LogPos::zero())
                       .and_then(|(pos0, val0)| {
                           client.fetch_next(pos0).map(move |second| vec![(pos0, val0), second])
                       });

    let read = core.run(timer.timeout(item_f, timeout)).expect("run read");
    info!("Got: {:?}", read);

    assert_eq!(read,
               vec![(wpos0, b"hello".to_vec()), (wpos1, b"world".to_vec())]);
}

#[test]
fn smoketest_two_member_chain() {
    env_logger::init().unwrap_or(());
    let timer = tokio_timer::wheel().tick_duration(Duration::from_millis(1)).build();
    let timeout = Duration::from_millis(1000);
    let mut core = Core::new().unwrap();

    let local_anon_addr: SocketAddr = "127.0.0.1:0".parse().unwrap();

    let server0 = build_server(
                      &core.handle(),
                      local_anon_addr.clone(),
                      local_anon_addr.clone())
        .expect("start server");
    println!("running: {:?}", server0);

    let server1 = build_server(
                      &core.handle(),
                      local_anon_addr.clone(),
                      local_anon_addr.clone())
        .expect("start server");

    println!("running: {:?}", server1);

    let client = vastatrix::ThickClient::new(core.handle(), &server0.head, &server1.tail);

    let f = client.add_peer(server1.clone())
        .and_then(|_| client.log_item(b"hello".to_vec()))
        .and_then(|pos0| client.log_item(b"world".to_vec()).map(move |pos1| (pos0, pos1)));
    let (wpos0, wpos1) = core.run(timer.timeout(f, timeout)).expect("run write");

    info!("Wrote to offset:{:?}", (wpos0, wpos1));

    let item_f = client.fetch_next(LogPos::zero())
        .and_then(|(pos0, val0)| {
            client.fetch_next(pos0).map(move |second| vec![(pos0, val0), second])
        });

    let read = core.run(timer.timeout(item_f, timeout)).expect("run read");
    info!("Got: {:?}", read);

    assert_eq!(read,
               vec![(wpos0, b"hello".to_vec()), (wpos1, b"world".to_vec())]);
}
<|endoftext|>


<commit_before>use std::io::{TcpListener, TcpStream};
use std::io::{Acceptor, Listener};
use std::io::BufferedStream;

fn main () {

    let listener = TcpListener::bind("127.0.0.1", 8099).unwrap();
    let mut acceptor = listener.listen().unwrap();

    fn handle_client(mut stream: BufferedStream<TcpStream>) {
        stream.write(b"HTTP/1.1 200 OK\n").unwrap(); // byte literal
        stream.write(b"Content-length: 15\n").unwrap(); // byte literal
        stream.write(b"Content-type: text/html\n").unwrap(); // byte literal
        stream.write(b"\n\n
Howdy!
").unwrap();
        stream.flush().unwrap();

        println!("Handling acceptor");
    }

    for stream in acceptor.incoming() {
        match stream {
            Err(e) => { println!("connection failed: {}", e) }
            Ok(stream) => spawn(proc() {
                let bs = BufferedStream::new(stream);
                handle_client(bs)
            })
        }
    }

    drop(acceptor);
}
<commit_msg>use as_slice()<commit_after>use std::io::{TcpListener, TcpStream};
use std::io::{Acceptor, Listener};
use std::io::BufferedStream;
use std::string::String;

fn main () {

    let listener = TcpListener::bind("127.0.0.1", 8099).unwrap();
    let mut acceptor = listener.listen().unwrap();

    fn handle_client(mut stream: BufferedStream<TcpStream>) {
        let s = String::from_str("X-header: from bytes\n");

        stream.write(b"HTTP/1.1 200 OK\n").unwrap(); // byte literal
        stream.write(b"Content-length: 21\n").unwrap(); // byte literal
        stream.write(b"Content-type: text/html\n").unwrap(); // byte literal
        stream.write(s.into_bytes().as_slice());
        stream.write(b"\n\n
Howdy There!
").unwrap();
        stream.flush().unwrap();

        println!("Handling acceptor");
    }

    for stream in acceptor.incoming() {
        match stream {
            Err(e) => { println!("connection failed: {}", e) }
            Ok(stream) => spawn(proc() {
                let bs = BufferedStream::new(stream);
                handle_client(bs)
            })
        }
    }

    drop(acceptor);
}
<|endoftext|>


<commit_before>use rand::os::OsRng;
use rand::XorShiftRng;
use rand::Rand;
use rand::Rng;

use na::Point2;

use level::Level;

pub struct RoomGen {
    rand_x: XorShiftRng,
    rand_y: XorShiftRng,
    max_room_size: usize,
    min_room_size: usize,
    attempts: u64,
    rooms: Vec<Box>,
}

impl RoomGen {
    pub fn new(min_room_size: usize, max_room_size: usize, room_distance: u32, attempts :u64) -> RoomGen {
        RoomGen{
            rand_x: XorShiftRng::rand(&mut OsRng::new().unwrap()),
            rand_y: XorShiftRng::rand(&mut OsRng::new().unwrap()),
            max_room_size: max_room_size,
            min_room_size: min_room_size,
            attempts: attempts,
            rooms: Vec::new(),
        }
    }

    pub fn generate(&mut self, level: &mut Level) {
        for i in 0..self.attempts {
            let room = self.generate_box(level);

            let fits = !self.check_collisions(room);
            if fits {
                rooms.append(room);
            }
        }
    }

    pub fn reset_rooms(&mut self) {
        self.rooms = Vec::new();
    }

    pub fn generate_box(&mut self, level: &mut Level) -> Box {
        let mut min = Point2::new(self.rand_x.);
    }

    pub fn check_collisions(&self, room: Room) {

    }
}

struct Room {
    pub min: Point2<isize>,
    pub max: Point2<isize>,
}
<commit_msg>RoomGen continued<commit_after>use rand::os::OsRng;
use rand::{XorShiftRng, Rand, Rng};
use rand::distributions::{IndependentSample, Range};

use na::Pnt2 as Point2;

use level::Level;

pub struct RoomGen {
    rand_x: XorShiftRng,
    rand_y: XorShiftRng,
    max_room_size: usize,
    min_room_size: usize,
    room_distance: usize,
    attempts: u64,
    rooms: Vec<Room>,
}

impl RoomGen {
    pub fn new(min_room_size: usize, max_room_size: usize, room_distance: u32, attempts :u64) -> RoomGen {
        RoomGen{
            rand_x: XorShiftRng::rand(&mut OsRng::new().unwrap()),
            rand_y: XorShiftRng::rand(&mut OsRng::new().unwrap()),
            max_room_size: max_room_size,
            min_room_size: min_room_size,
            room_distance: room_distance,
            attempts: attempts,
            rooms: Vec::new(),
        }
    }

    pub fn generate(&mut self, level: &mut Level) {
        for i in 0..self.attempts {
            let room = self.generate_box(level);

            let fits = !self.check_collisions(room);
            if fits {
                self.rooms.append(room);
            }
        }
    }

    pub fn reset_rooms(&mut self) {
        self.rooms = Vec::new();
    }

    pub fn generate_box(&mut self, level: &mut Level) -> Box {
        let min_range_x = Range::new(0, level.get_width());
        let min_range_y = Range::new(0, level.get_height());
        let mut min = Point2::new(min_range_x.ind_sample(self.rand_x), min_range_y.ind_sample(self.rand_y));

        let max_range = Range::new(self.min_room_size, self.max_room_size);
        let mut max = Point2::new(max_range.ind_sample(self.rand_x), max_range.ind_sample(self.rand_y));
        max.x += min.x;
        max.y += min.y;
        max.x += self.room_distance;
        max.y += self.room_distance;
        Room{min: min, max: max}
    }

    pub fn check_collisions(&self, room: Room) {

    }
}

struct Room {
    pub min: Point2<isize>,
    pub max: Point2<isize>,
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/greatest-english-letter-in-upper-and-lower-case/
pub fn greatest_letter(s: String) -> String {
    todo!();
}

fn main() {
    println!("{}", greatest_letter(String::from("lEeTcOdE"))); // "E"
    println!("{}", greatest_letter(String::from("arRAzFif"))); // "R"
    println!("{}", greatest_letter(String::from("AbCdEfGhIjK"))); // ""
}
<commit_msg>Solve problem 2309<commit_after>// https://leetcode.com/problems/greatest-english-letter-in-upper-and-lower-case/
pub fn greatest_letter(s: String) -> String {
    let chars: Vec<char> = s.chars().collect();
    let mut lowercase_counts = vec![false; 26];
    let mut uppercase_counts = vec![false; 26];
    for c in chars {
        if c >= 'a' && c <= 'z' {
            lowercase_counts[c as usize - 'a' as usize] = true;
        } else {
            uppercase_counts[c as usize - 'A' as usize] = true;
        }
    }
    let mut answer = String::from("");
    for lowercase_char in ('a'..='z').rev() {
        let uppercase_char = lowercase_char.to_uppercase().next().unwrap();
        if lowercase_counts[lowercase_char as usize - 'a' as usize]
            && uppercase_counts[uppercase_char as usize - 'A' as usize]
        {
            answer = String::from(uppercase_char);
            break;
        }
    }
    answer
}

fn main() {
    println!("{}", greatest_letter(String::from("lEeTcOdE"))); // "E"
    println!("{}", greatest_letter(String::from("arRAzFif"))); // "R"
    println!("{}", greatest_letter(String::from("AbCdEfGhIjK"))); // ""
}
<|endoftext|>


<commit_before>/// Construct a `serde_json::Value` from a JSON literal.
///
/// ```rust
/// # #![allow(unused_variables)]
/// # #[macro_use] extern crate serde_json;
/// # fn main() {
/// let value = json!({
///     "code": 200,
///     "success": true,
///     "payload": {
///         "features": [
///             "serde",
///             "json"
///         ]
///     }
/// });
/// # }
/// ```
///
/// Variables or expressions can be interpolated into the JSON literal. Any type
/// interpolated into an array element or object value must implement Serde's
/// `Serialize` trait, while any type interpolated into a object key must
/// implement `Into<String>`.
///
/// ```rust
/// # #![allow(unused_variables)]
/// # #[macro_use] extern crate serde_json;
/// # fn main() {
/// let code = 200;
/// let features = vec!["serde", "json"];
///
/// let value = json!({
///    "code": code,
///    "success": code == 200,
///    "payload": {
///        features[0]: features[1]
///    }
/// });
/// # }
/// ```
///
/// Trailing commas are allowed inside both arrays and objects.
///
/// ```rust
/// # #![allow(unused_variables)]
/// # #[macro_use] extern crate serde_json;
/// # fn main() {
/// let value = json!([
///     "notice",
///     "the",
///     "trailing",
///     "comma -->",
/// ]);
/// # }
/// ```
#[macro_export]
macro_rules! json {
    // Hide distracting implementation details from the generated rustdoc.
    ($($json:tt)+) => {
        json_internal!($($json)+)
    };
}

#[macro_export]
#[doc(hidden)]
macro_rules! json_internal {
    (null) => {
        $crate::Value::Null
    };

    (true) => {
        $crate::Value::Bool(true)
    };

    (false) => {
        $crate::Value::Bool(false)
    };

    ([]) => {
        $crate::Value::Array(vec![])
    };

    ([ $($tt:tt)+ ]) => {
        $crate::Value::Array(json_within_array!([] $($tt)+))
    };

    ({}) => {
        $crate::Value::Object($crate::Map::new())
    };

    ({ $($tt:tt)+ }) => {
        $crate::Value::Object({
            let mut object = $crate::Map::new();
            json_within_object!(object () $($tt)+);
            object
        })
    };

    // Any Serialize type: numbers, strings, struct literals, variables etc.
    ($other:expr) => {
        $crate::to_value(&$other).unwrap()
    };
}

// TT muncher for parsing the inside of an array [...]. Produces a vec![...] of
// the elements.
//
// Must be invoked as: json_within_array!([] $($tt)*)
#[macro_export]
#[doc(hidden)]
macro_rules! json_within_array {
    // Done with trailing comma.
    ([$($elems:expr,)*]) => {
        vec![$($elems,)*]
    };

    // Done without trailing comma.
    ([$($elems:expr),*]) => {
        vec![$($elems),*]
    };

    // Next element is `null`.
    ([$($elems:expr,)*] null $($rest:tt)*) => {
        json_within_array!([$($elems,)* json!(null)] $($rest)*)
    };

    // Next element is `true`.
    ([$($elems:expr,)*] true $($rest:tt)*) => {
        json_within_array!([$($elems,)* json!(true)] $($rest)*)
    };

    // Next element is `false`.
    ([$($elems:expr,)*] false $($rest:tt)*) => {
        json_within_array!([$($elems,)* json!(false)] $($rest)*)
    };

    // Next element is an array.
    ([$($elems:expr,)*] [$($array:tt)*] $($rest:tt)*) => {
        json_within_array!([$($elems,)* json!([$($array)*])] $($rest)*)
    };

    // Next element is a map.
    ([$($elems:expr,)*] {$($map:tt)*} $($rest:tt)*) => {
        json_within_array!([$($elems,)* json!({$($map)*})] $($rest)*)
    };

    // Next element is an expression followed by comma.
    ([$($elems:expr,)*] $next:expr, $($rest:tt)*) => {
        json_within_array!([$($elems,)* json!($next),] $($rest)*)
    };

    // Last element is an expression with no trailing comma.
    ([$($elems:expr,)*] $last:expr) => {
        json_within_array!([$($elems,)* json!($last)])
    };

    // Comma after the most recent element.
    ([$($elems:expr),*] , $($rest:tt)*) => {
        json_within_array!([$($elems,)*] $($rest)*)
    };
}

// TT muncher for parsing the inside of an object {...}. Each entry is inserted
// into the given map variable.
//
// Must be invoked as: json_within_object!(var () $($tt)*)
#[macro_export]
#[doc(hidden)]
macro_rules! json_within_object {
    // Done.
    ($object:ident ()) => {};

    // Insert the current entry followed by trailing comma.
    ($object:ident [$($key:tt)+] ($value:expr) , $($rest:tt)*) => {
        $object.insert(($($key)+).into(), $value);
        json_within_object!($object () $($rest)*);
    };

    // Insert the last entry without trailing comma.
    ($object:ident [$($key:tt)+] ($value:expr)) => {
        $object.insert(($($key)+).into(), $value);
    };

    // Next value is `null`.
    ($object:ident ($($key:tt)+) : null $($rest:tt)*) => {
        json_within_object!($object [$($key)+] (json!(null)) $($rest)*);
    };

    // Next value is `true`.
    ($object:ident ($($key:tt)+) : true $($rest:tt)*) => {
        json_within_object!($object [$($key)+] (json!(true)) $($rest)*);
    };

    // Next value is `false`.
    ($object:ident ($($key:tt)+) : false $($rest:tt)*) => {
        json_within_object!($object [$($key)+] (json!(false)) $($rest)*);
    };

    // Next value is an array.
    ($object:ident ($($key:tt)+) : [$($array:tt)*] $($rest:tt)*) => {
        json_within_object!($object [$($key)+] (json!([$($array)*])) $($rest)*);
    };

    // Next value is a map.
    ($object:ident ($($key:tt)+) : {$($map:tt)*} $($rest:tt)*) => {
        json_within_object!($object [$($key)+] (json!({$($map)*})) $($rest)*);
    };

    // Next value is an expression followed by comma.
    ($object:ident ($($key:tt)+) : $value:expr , $($rest:tt)*) => {
        json_within_object!($object [$($key)+] (json!($value)) , $($rest)*);
    };

    // Last value is an expression with no trailing comma.
    ($object:ident ($($key:tt)+) : $value:expr) => {
        json_within_object!($object [$($key)+] (json!($value)));
    };

    // Misplaced colon. Trigger a reasonable error message by failing to match
    // the colon in the recursive call.
    ($object:ident () : $($rest:tt)*) => {
        json_within_object!($object [:] (:));
    };

    // Found a comma inside a key. Trigger a reasonable error message by failing
    // to match the comma in the recursive call.
    ($object:ident ($($key:tt)*) , $($rest:tt)*) => {
        json_within_object!($object [,] (,));
    };

    // Munch a token into the current key.
    ($object:ident ($($key:tt)*) $tt:tt $($rest:tt)*) => {
        json_within_object!($object ($($key)* $tt) $($rest)*);
    };
}
<commit_msg>Refactor json_internal macro to need no helper macros<commit_after>/// Construct a `serde_json::Value` from a JSON literal.
///
/// ```rust
/// # #![allow(unused_variables)]
/// # #[macro_use] extern crate serde_json;
/// # fn main() {
/// let value = json!({
///     "code": 200,
///     "success": true,
///     "payload": {
///         "features": [
///             "serde",
///             "json"
///         ]
///     }
/// });
/// # }
/// ```
///
/// Variables or expressions can be interpolated into the JSON literal. Any type
/// interpolated into an array element or object value must implement Serde's
/// `Serialize` trait, while any type interpolated into a object key must
/// implement `Into<String>`.
///
/// ```rust
/// # #![allow(unused_variables)]
/// # #[macro_use] extern crate serde_json;
/// # fn main() {
/// let code = 200;
/// let features = vec!["serde", "json"];
///
/// let value = json!({
///    "code": code,
///    "success": code == 200,
///    "payload": {
///        features[0]: features[1]
///    }
/// });
/// # }
/// ```
///
/// Trailing commas are allowed inside both arrays and objects.
///
/// ```rust
/// # #![allow(unused_variables)]
/// # #[macro_use] extern crate serde_json;
/// # fn main() {
/// let value = json!([
///     "notice",
///     "the",
///     "trailing",
///     "comma -->",
/// ]);
/// # }
/// ```
#[macro_export]
macro_rules! json {
    // Hide distracting implementation details from the generated rustdoc.
    ($($json:tt)+) => {
        json_internal!($($json)+)
    };
}

// Rocket relies on this because they export their own `json!` with a different
// doc comment than ours, and various Rust bugs prevent them from calling our
// `json!` from their `json!` so they call `json_internal!` directly. Check with
// @SergioBenitez before making breaking changes to this macro.
//
// Changes are fine as long as `json_internal!` does not call any new helper
// macros and can still be invoked as `json_internal!($($json)+)`.
#[macro_export]
#[doc(hidden)]
macro_rules! json_internal {
    //////////////////////////////////////////////////////////////////////////
    // TT muncher for parsing the inside of an array [...]. Produces a vec![...]
    // of the elements.
    //
    // Must be invoked as: json_internal!(@array [] $($tt)*)
    //////////////////////////////////////////////////////////////////////////

    // Done with trailing comma.
    (@array [$($elems:expr,)*]) => {
        vec![$($elems,)*]
    };

    // Done without trailing comma.
    (@array [$($elems:expr),*]) => {
        vec![$($elems),*]
    };

    // Next element is `null`.
    (@array [$($elems:expr,)*] null $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!(null)] $($rest)*)
    };

    // Next element is `true`.
    (@array [$($elems:expr,)*] true $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!(true)] $($rest)*)
    };

    // Next element is `false`.
    (@array [$($elems:expr,)*] false $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!(false)] $($rest)*)
    };

    // Next element is an array.
    (@array [$($elems:expr,)*] [$($array:tt)*] $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!([$($array)*])] $($rest)*)
    };

    // Next element is a map.
    (@array [$($elems:expr,)*] {$($map:tt)*} $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!({$($map)*})] $($rest)*)
    };

    // Next element is an expression followed by comma.
    (@array [$($elems:expr,)*] $next:expr, $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!($next),] $($rest)*)
    };

    // Last element is an expression with no trailing comma.
    (@array [$($elems:expr,)*] $last:expr) => {
        json_internal!(@array [$($elems,)* json_internal!($last)])
    };

    // Comma after the most recent element.
    (@array [$($elems:expr),*] , $($rest:tt)*) => {
        json_internal!(@array [$($elems,)*] $($rest)*)
    };

    //////////////////////////////////////////////////////////////////////////
    // TT muncher for parsing the inside of an object {...}. Each entry is
    // inserted into the given map variable.
    //
    // Must be invoked as: json_internal!(@object $map () $($tt)*)
    //////////////////////////////////////////////////////////////////////////

    // Done.
    (@object $object:ident ()) => {};

    // Insert the current entry followed by trailing comma.
    (@object $object:ident [$($key:tt)+] ($value:expr) , $($rest:tt)*) => {
        $object.insert(($($key)+).into(), $value);
        json_internal!(@object $object () $($rest)*);
    };

    // Insert the last entry without trailing comma.
    (@object $object:ident [$($key:tt)+] ($value:expr)) => {
        $object.insert(($($key)+).into(), $value);
    };

    // Next value is `null`.
    (@object $object:ident ($($key:tt)+) : null $($rest:tt)*) => {
        json_internal!(@object $object [$($key)+] (json_internal!(null)) $($rest)*);
    };

    // Next value is `true`.
    (@object $object:ident ($($key:tt)+) : true $($rest:tt)*) => {
        json_internal!(@object $object [$($key)+] (json_internal!(true)) $($rest)*);
    };

    // Next value is `false`.
    (@object $object:ident ($($key:tt)+) : false $($rest:tt)*) => {
        json_internal!(@object $object [$($key)+] (json_internal!(false)) $($rest)*);
    };

    // Next value is an array.
    (@object $object:ident ($($key:tt)+) : [$($array:tt)*] $($rest:tt)*) => {
        json_internal!(@object $object [$($key)+] (json_internal!([$($array)*])) $($rest)*);
    };

    // Next value is a map.
    (@object $object:ident ($($key:tt)+) : {$($map:tt)*} $($rest:tt)*) => {
        json_internal!(@object $object [$($key)+] (json_internal!({$($map)*})) $($rest)*);
    };

    // Next value is an expression followed by comma.
    (@object $object:ident ($($key:tt)+) : $value:expr , $($rest:tt)*) => {
        json_internal!(@object $object [$($key)+] (json_internal!($value)) , $($rest)*);
    };

    // Last value is an expression with no trailing comma.
    (@object $object:ident ($($key:tt)+) : $value:expr) => {
        json_internal!(@object $object [$($key)+] (json_internal!($value)));
    };

    // Misplaced colon. Trigger a reasonable error message by failing to match
    // the colon in the recursive call.
    (@object $object:ident () : $($rest:tt)*) => {
        json_internal!(@object $object [:] (:));
    };

    // Found a comma inside a key. Trigger a reasonable error message by failing
    // to match the comma in the recursive call.
    (@object $object:ident ($($key:tt)*) , $($rest:tt)*) => {
        json_internal!(@object $object [,] (,));
    };

    // Munch a token into the current key.
    (@object $object:ident ($($key:tt)*) $tt:tt $($rest:tt)*) => {
        json_internal!(@object $object ($($key)* $tt) $($rest)*);
    };

    //////////////////////////////////////////////////////////////////////////
    // The main implementation.
    //
    // Must be invoked as: json_internal!($($json)+)
    //////////////////////////////////////////////////////////////////////////

    (null) => {
        $crate::Value::Null
    };

    (true) => {
        $crate::Value::Bool(true)
    };

    (false) => {
        $crate::Value::Bool(false)
    };

    ([]) => {
        $crate::Value::Array(vec![])
    };

    ([ $($tt:tt)+ ]) => {
        $crate::Value::Array(json_internal!(@array [] $($tt)+))
    };

    ({}) => {
        $crate::Value::Object($crate::Map::new())
    };

    ({ $($tt:tt)+ }) => {
        $crate::Value::Object({
            let mut object = $crate::Map::new();
            json_internal!(@object object () $($tt)+);
            object
        })
    };

    // Any Serialize type: numbers, strings, struct literals, variables etc.
    // Must be below every other rule.
    ($other:expr) => {
        $crate::to_value(&$other).unwrap()
    };
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 - 2016, Alberto Corona <ac@albertocorona.com>
// All rights reserved. This file is part of yabs, distributed under the BSD
// 3-Clause license. For full terms please see the LICENSE file.

extern crate toml;
extern crate rustc_serialize;
extern crate walkdir;
extern crate rpf;

use toml::decode;
use error::YabsError;
use rpf::*;
use ext::*;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, json};
use walkdir::WalkDir;

use std::ffi::OsStr;
use std::path::PathBuf;

#[derive(Debug,Default,RustcDecodable,RustcEncodable,Clone,PartialEq)]
pub struct Profile {
    name: String,
    proj_desc: Option<ProjDesc>,
    inst_desc: Option<InstallDesc>,
    doc_desc: Option<DocDesc>,
}

#[derive(Debug,Default,RustcDecodable,RustcEncodable)]
pub struct BuildFile {
    profiles: Vec<Profile>,
}

impl BuildFile {
    pub fn from_file(file: &str) -> Result<BuildFile, Vec<YabsError>> {
        let mut build_file: BuildFile = Default::default();
        parse_toml_file(file)
            .and_then(|toml| {
                for (key, table) in toml {
                    let mut profile: Profile = Default::default();
                    profile.name = key.clone();
                    match table {
                        toml::Value::Table(inner_table) => {
                            for (key, table) in inner_table {
                                match key.as_ref() {
                                    "project" => {
                                        profile.proj_desc = ProjDesc::from_toml_table(table).ok()
                                    }
                                    "install" => {
                                        profile.inst_desc = InstallDesc::from_toml_table(table).ok()
                                    }
                                    "doc" => {
                                        profile.doc_desc = DocDesc::from_toml_table(table).ok()
                                    }
                                    _ => (),
                                }
                            }
                        }
                        _ => (),
                    };
                    build_file.profiles.push(profile);
                }
                Ok(build_file)
            })
            .map_err(|err| err)
    }

    pub fn print_as_json(&self) {
        for profile in &self.profiles {
            profile.print_json();
        }
    }

    pub fn print_available_profiles(&self) {
        for profile in &self.profiles {
            print!("{} ", profile.name);
        }
        print!("\n");
    }

    pub fn print_profile_as_json(&self, name: String) {
        for profile in &self.profiles {
            if profile.name == name {
                profile.print_json();
            }
        }
    }

    // Hideous Makefile generation to be implemented
    //pub fn gen_make(&self, name: String) -> Result<(), YabsError> {
        //for profile in &self.profiles {
            //if profile.name == name {
                //continue;
            //} else {
                //return Ok(());
            //}
        //}
        //let format = format!("INSTALL\t=\t/usr/bin/env \
                              //install\nDEST\t=\nPREFIX\t=\nCC\t=\t{}\nBINDIR\t=\nLIBDIR\t=\nTARGE\
                              //T\t=\nLINK\t=\nCFLAGS\t=\nLFLAGS\t=\nLIBS\t=\nINCDIR\t=\nLIBDIR\t=\
                              //\nCLEAN\t=\n\nDEL\t=\trm -f\n\n.PHONY: doc \
                              //clean\n\n.cpp.o:\n\t$(CC) -c $(CFLAGS) $(INCDIR) -o \"$@\" \
                              //\"$<\"\n.cc.o:\n\t$(CC) -c $(CFLAGS) $(INCDIR) -o \"$@\" \
                              //\"$<\"\n\n.cxx.o:\n\t$(CC) -c $(CFLAGS) $(INCDIR) -o \"$@\" \
                              //\"$<\"\n\n.C.o:\n\t$(CC) -c $(CFLAGS) $(INCDIR) -o \"$@\" \
                              //\"$<\"\n\n.c.o:\n\t$(CC) -c $(CFLAGS) $(INCDIR) -o \"$@\" \
                              //\"$<\"\n\nall: $(TRGT)\n",
                             //&self.profiles[1].clone().proj_desc.unwrap().compiler.unwrap());
        //print!("{}", format);
        //Ok(())
    //}

    pub fn print_sources(&self) -> Result<(), YabsError> {
        for profile in &self.profiles {
            if let Some(proj) = profile.proj_desc.as_ref() {
                println!("{}", profile.name.bold());
                let sources = try!(proj.clone().gen_file_list());
                for file in sources.files {
                    println!("{}", file.display());
                }
                if let Some(set_sources) = proj.src.as_ref() {
                    for src in set_sources {
                        println!("{}", src);
                    }
                }
            }
        }
        Ok(())
    }
}

#[derive(Debug,Default,RustcDecodable,RustcEncodable,Clone,PartialEq)]
pub struct ProjDesc {
    name: Option<String>,
    target: Option<String>,
    lang: Option<String>,
    os: Option<String>,
    version: Option<String>,
    compiler: Option<String>,
    src: Option<Vec<String>>,
    libs: Option<Vec<String>>,
    lib_dir: Option<Vec<String>>,
    inc: Option<Vec<String>>,
    inc_dir: Option<Vec<String>>,
    cflags: Option<String>,
    explicit_cflags: Option<String>,
    lflags: Option<String>,
    ignore: Option<Vec<String>>,
    before_script: Option<Vec<String>>,
    after_script: Option<Vec<String>>,
    lib: Option<bool>,
    ar: Option<String>,
}

#[derive(Default,RustcDecodable,RustcEncodable,PartialEq)]
struct Sources {
    files: Vec<PathBuf>,
    objects: Vec<PathBuf>,
}

impl ProjDesc {
    fn gen_file_list(&self) -> Result<Sources, YabsError> {
        let mut sources = Sources::new();
        for entry in WalkDir::new(".") {
            let entry = try!(entry);
            if entry.path().is_file() {
                let lang = &self.lang.clone().unwrap();
                let file_ext = entry.path().extension().unwrap_or(OsStr::new(""));
                if let Some(ext) = file_ext.to_str() {
                    if let Some(lang) = self.lang.clone() {
                        if ext == lang {
                            sources.files.push(PathBuf::from(entry.path()));
                        }
                    }
                }
            }
        }
        Ok(sources)
    }
}

// Descibe how to install this project
#[derive(Debug,Default,RustcDecodable,RustcEncodable,Clone,PartialEq)]
pub struct InstallDesc {
    prefix: Option<String>,
}

#[derive(Debug,Default,RustcDecodable,RustcEncodable,Clone,PartialEq)]
pub struct DocDesc {
    doc: Option<String>,
}

// General trait for any descriptions
pub trait Desc<T> {
    fn new() -> T;
    fn from_file(file: &str, name: &str) -> Result<T, Vec<YabsError>>;
    fn from_toml_table(table: toml::Value) -> Result<T, YabsError>;
    fn print_json(&self);
}

impl<T: Decodable + Encodable + Default> Desc<T> for T {
    fn new() -> T {
        Default::default()
    }

    fn from_file(file: &str, name: &str) -> Result<T, Vec<YabsError>> {
        parse_toml_file(file).and_then(|toml| {
            toml.get(name)
                .ok_or(vec![YabsError::NoDesc(name.to_owned())])
                .and_then(|desc| {
                    Decodable::decode(&mut toml::Decoder::new(desc.clone()))
                        .map_err(|err| vec![YabsError::TomlDecode(err)])
                })
        })
    }

    fn from_toml_table(table: toml::Value) -> Result<T, YabsError> {
        Ok(try!(Decodable::decode(&mut toml::Decoder::new(table.clone()))))
    }

    fn print_json(&self) {
        println!("{}", json::as_pretty_json(&self));
    }
}
<commit_msg>build: prelim src/obj list generation<commit_after>// Copyright (c) 2015 - 2016, Alberto Corona <ac@albertocorona.com>
// All rights reserved. This file is part of yabs, distributed under the BSD
// 3-Clause license. For full terms please see the LICENSE file.

extern crate toml;
extern crate rustc_serialize;
extern crate walkdir;
extern crate rpf;

use toml::decode;
use error::YabsError;
use rpf::*;
use ext::*;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, json};
use walkdir::WalkDir;

use std::ffi::OsStr;
use std::path::PathBuf;

#[derive(Debug,Default,RustcDecodable,RustcEncodable,Clone,PartialEq)]
pub struct Profile {
    name: String,
    proj_desc: Option<ProjDesc>,
    inst_desc: Option<InstallDesc>,
    doc_desc: Option<DocDesc>,
}

#[derive(Debug,Default,RustcDecodable,RustcEncodable)]
pub struct BuildFile {
    profiles: Vec<Profile>,
}

impl BuildFile {
    pub fn from_file(file: &str) -> Result<BuildFile, Vec<YabsError>> {
        let mut build_file: BuildFile = Default::default();
        parse_toml_file(file)
            .and_then(|toml| {
                for (key, table) in toml {
                    let mut profile: Profile = Default::default();
                    profile.name = key.clone();
                    match table {
                        toml::Value::Table(inner_table) => {
                            for (key, table) in inner_table {
                                match key.as_ref() {
                                    "project" => {
                                        profile.proj_desc = ProjDesc::from_toml_table(table).ok()
                                    }
                                    "install" => {
                                        profile.inst_desc = InstallDesc::from_toml_table(table).ok()
                                    }
                                    "doc" => {
                                        profile.doc_desc = DocDesc::from_toml_table(table).ok()
                                    }
                                    _ => (),
                                }
                            }
                        }
                        _ => (),
                    };
                    build_file.profiles.push(profile);
                }
                Ok(build_file)
            })
            .map_err(|err| err)
    }

    pub fn print_as_json(&self) {
        for profile in &self.profiles {
            profile.print_json();
        }
    }

    pub fn print_available_profiles(&self) {
        for profile in &self.profiles {
            print!("{} ", profile.name);
        }
        print!("\n");
    }

    pub fn print_profile_as_json(&self, name: String) {
        for profile in &self.profiles {
            if profile.name == name {
                profile.print_json();
            }
        }
    }

    //Hideous Makefile generation to be implemented
    //pub fn gen_make(&self, name: String) -> Result<(), YabsError> {
        //for profile in &self.profiles {
            //if profile.name == name {
                //continue;
            //} else {
                //return Ok(());
            //}
        //}
        //let format = format!(
        //"INSTALL\t=\t/usr/bin/env install\n
        //DEST\t=\n
        //PREFIX\t=\n
        //CC\t=\t{}\n
        //BINDIR\t=\n
        //LIBDIR\t=\n
        //TARGET\t=\n
        //LINK\t=\n
        //CFLAGS\t=\n
        //LFLAGS\t=\n
        //LIBS\t=\n
        //INCDIR\t=\n
        //LIBDIR\t=\n
        //CLEAN\t=\n\n
        //DEL\t=\trm -f\n\n
        //.PHONY: doc clean\n\n
        //.cpp.o:\n\t$(CC) -c $(CFLAGS) $(INCDIR) -o \"$@\" \"$<\"\n
        //.cc.o:\n\t$(CC) -c $(CFLAGS) $(INCDIR) -o \"$@\" \"$<\"\n\n
        //.cxx.o:\n\t$(CC) -c $(CFLAGS) $(INCDIR) -o \"$@\" \"$<\"\n\n
        //.C.o:\n\t$(CC) -c $(CFLAGS) $(INCDIR) -o \"$@\" \"$<\"\n\n
        //.c.o:\n\t$(CC) -c $(CFLAGS) $(INCDIR) -o \"$@\" \"$<\"\n\n
        //all: $(TRGT)\n",
        //&self.profiles[1].clone().proj_desc.unwrap().compiler.unwrap());
        //print!("{}", format);
        //Ok(())
    //}

    pub fn print_sources(&self) -> Result<(), YabsError> {
        for profile in &self.profiles {
            if let Some(proj) = profile.proj_desc.as_ref() {
                println!("{}", profile.name.bold());
                let sources = try!(proj.clone().gen_file_list());
                for file in sources.files {
                    println!("{}", file);
                }
                if let Some(set_sources) = proj.src.as_ref() {
                    for src in set_sources {
                        println!("{}", src);
                    }
                }
            }
        }
        Ok(())
    }
}

#[derive(Debug,Default,RustcDecodable,RustcEncodable,Clone,PartialEq)]
pub struct ProjDesc {
    name: Option<String>,
    target: Option<String>,
    lang: Option<String>,
    os: Option<String>,
    version: Option<String>,
    compiler: Option<String>,
    src: Option<Vec<String>>,
    libs: Option<Vec<String>>,
    lib_dir: Option<Vec<String>>,
    inc: Option<Vec<String>>,
    inc_dir: Option<Vec<String>>,
    cflags: Option<String>,
    explicit_cflags: Option<String>,
    lflags: Option<String>,
    ignore: Option<Vec<String>>,
    before_script: Option<Vec<String>>,
    after_script: Option<Vec<String>>,
    lib: Option<bool>,
    ar: Option<String>,
}

#[derive(Default,RustcDecodable,RustcEncodable,PartialEq)]
struct Sources {
    files: Vec<String>,
    objects: Vec<String>,
}

impl ProjDesc {
    fn gen_file_list(&self) -> Result<Sources, YabsError> {
        let mut sources = Sources::new();
        for entry in WalkDir::new(".") {
            let entry = try!(entry);
            if entry.path().is_file() {
                let lang = &self.lang.clone().unwrap();
                let file_ext = entry.path().extension().unwrap_or(OsStr::new(""));
                if let Some(ext) = file_ext.to_str() {
                    if let Some(lang) = self.lang.clone() {
                        if ext == lang {
                            sources.files.push(entry.path().as_string());
                        }
                    }
                }
            }
        }
        Ok(sources)
    }

    fn gen_make_src_list(&self) -> String {
        let mut horrid_string: String = "SRC\t = ".to_owned();
        let mut lang = self.lang.clone().unwrap();
        lang.insert(0, '.');
        println!("EXT: {}", lang);
        if let Some(source_list) = self.src.as_ref() {
            if let Some(split_first) = source_list.split_first() {
                horrid_string.push_str(&format!("{} \\\n", split_first.0));
                if let Some(split_last) = split_first.1.clone().split_last() {
                    for src in split_last.1 {
                        horrid_string.push_str(&format!("\0\0\t{} \\\n", src));
                    }
                    horrid_string.push_str(&format!("\0\0\t{}\n", split_last.0));
                }
            }
            let mut parsed_obj_list = Vec::new();
            for obj in source_list {
                parsed_obj_list.push(obj.replace(&lang, ".o"));
            }
            horrid_string.push_str("OBJ\t = ");
            if let Some(split_first) = parsed_obj_list.split_first() {
                horrid_string.push_str(&format!("{} \\\n", split_first.0));
                if let Some(split_last) = split_first.1.clone().split_last() {
                    for src in split_last.1 {
                        horrid_string.push_str(&format!("\0\0\t{} \\\n", src));
                    }
                    horrid_string.push_str(&format!("\0\0\t{}", split_last.0));
                }
            }
        }
        return horrid_string;
    }
}

// Descibe how to install this project
#[derive(Debug,Default,RustcDecodable,RustcEncodable,Clone,PartialEq)]
pub struct InstallDesc {
    prefix: Option<String>,
}

#[derive(Debug,Default,RustcDecodable,RustcEncodable,Clone,PartialEq)]
pub struct DocDesc {
    doc: Option<String>,
}

// General trait for any descriptions
pub trait Desc<T> {
    fn new() -> T;
    fn from_file(file: &str, name: &str) -> Result<T, Vec<YabsError>>;
    fn from_toml_table(table: toml::Value) -> Result<T, YabsError>;
    fn print_json(&self);
}

impl<T: Decodable + Encodable + Default> Desc<T> for T {
    fn new() -> T {
        Default::default()
    }

    fn from_file(file: &str, name: &str) -> Result<T, Vec<YabsError>> {
        parse_toml_file(file).and_then(|toml| {
            toml.get(name)
                .ok_or(vec![YabsError::NoDesc(name.to_owned())])
                .and_then(|desc| {
                    Decodable::decode(&mut toml::Decoder::new(desc.clone()))
                        .map_err(|err| vec![YabsError::TomlDecode(err)])
                })
        })
    }

    fn from_toml_table(table: toml::Value) -> Result<T, YabsError> {
        Ok(try!(Decodable::decode(&mut toml::Decoder::new(table.clone()))))
    }

    fn print_json(&self) {
        println!("{}", json::as_pretty_json(&self));
    }
}
<|endoftext|>


<commit_before>use elasticsearch::Elasticsearch;

pub mod internal;
pub mod query;
pub mod remote;
pub mod storage;

#[derive(Clone)]
pub struct ElasticsearchStorage(Elasticsearch);

#[cfg(test)]
pub mod tests {

    use futures::stream::StreamExt;
    use serde::Serialize;
    use serde_json::json;
    use std::convert::TryFrom;
    use std::sync::Arc;

    use super::*;

    use crate::domain::model::configuration::Configuration;
    use crate::domain::model::document::Document;
    use crate::domain::ports::remote::Remote;
    use crate::domain::ports::storage::Storage;
    use crate::utils::docker;

    #[test]
    fn should_return_invalid_configuration() {
        let config = Configuration {
            value: String::from("invalid"),
        };
        let res = internal::IndexConfiguration::try_from(config);
        assert!(res
            .unwrap_err()
            .to_string()
            .starts_with("Invalid Elasticsearch Index Configuration"));
    }

    #[tokio::test]
    async fn should_return_invalid_url() {
        let res = remote::connection_pool_url("foobar").await;
        assert!(res
            .unwrap_err()
            .to_string()
            .starts_with("Invalid Elasticsearch URL"));
    }

    #[tokio::test]
    async fn should_connect_to_elasticsearch() {
        let mtx = Arc::clone(&docker::AVAILABLE);
        let _guard = mtx.lock().unwrap();
        docker::initialize().await.expect("initialization");
        let pool = remote::connection_test_pool()
            .await
            .expect("Elasticsearch Connection Pool");
        let _client = pool
            .conn()
            .await
            .expect("Elasticsearch Connection Established");
    }

    #[tokio::test]
    async fn should_create_index_with_valid_configuration() {
        let mtx = Arc::clone(&docker::AVAILABLE);
        let guard = mtx.lock().unwrap();
        docker::initialize().await.expect("initialization");
        let pool = remote::connection_test_pool()
            .await
            .expect("Elasticsearch Connection Pool");
        let client = pool
            .conn()
            .await
            .expect("Elasticsearch Connection Established");
        let config = internal::IndexConfiguration {
            name: String::from("root_obj_dataset_test-index"),
            parameters: internal::IndexParameters {
                timeout: String::from("10s"),
                wait_for_active_shards: String::from("1"), // only the primary shard
            },
            settings: internal::IndexSettings {
                base: json!(r#"{ "index": { "number_of_shards": 1 } }"#),
                nb_replicas: 1,
                nb_shards: 1,
            },
            mappings: internal::IndexMappings {
                value: String::from(r#"{ "properties": { "value": { "type": "text" } } }"#),
            },
        };
        let config = Configuration {
            value: serde_json::to_string(&config).expect("config"),
        };
        let res = client.create_container(config).await;
        drop(guard);
        assert!(res.is_ok());
    }

    #[tokio::test]
    async fn should_correctly_report_duplicate_index_when_creating_twice_the_same_index() {
        let mtx = Arc::clone(&docker::AVAILABLE);
        let guard = mtx.lock().unwrap();
        docker::initialize().await.expect("initialization");
        let pool = remote::connection_test_pool()
            .await
            .expect("Elasticsearch Connection Pool");
        let client = pool
            .conn()
            .await
            .expect("Elasticsearch Connection Established");
        let config = internal::IndexConfiguration {
            name: String::from("root_obj_dataset_test-index-duplicate"),
            parameters: internal::IndexParameters {
                timeout: String::from("10s"),
                wait_for_active_shards: String::from("1"), // only the primary shard
            },
            settings: internal::IndexSettings {
                base: json!(r#"{ "index": { "number_of_shards": 1 } }"#),
                nb_replicas: 1,
                nb_shards: 1,
            },
            mappings: internal::IndexMappings {
                value: String::from(r#"{ "properties": { "value": { "type": "text" } } }"#),
            },
        };
        let config = Configuration {
            value: serde_json::to_string(&config).expect("config"),
        };
        client
            .create_container(config.clone())
            .await
            .expect("container creation");
        let res = client.create_container(config).await;
        drop(guard);
        assert!(res
            .unwrap_err()
            .to_string()
            .contains("Elasticsearch Duplicate Index"));
    }

    #[tokio::test]
    async fn should_correctly_report_invalid_configuration() {
        let mtx = Arc::clone(&docker::AVAILABLE);
        let guard = mtx.lock().unwrap();
        docker::initialize().await.expect("initialization");
        let pool = remote::connection_test_pool()
            .await
            .expect("Elasticsearch Connection Pool");
        let client = pool
            .conn()
            .await
            .expect("Elasticsearch Connection Established");
        let config = internal::IndexConfiguration {
            name: String::from("root_obj_dataset_test-index-invalid-conf"),
            parameters: internal::IndexParameters {
                timeout: String::from("10s"),
                wait_for_active_shards: String::from("1"), // only the primary shard
            },
            settings: internal::IndexSettings {
                base: json!(r#"{ "index": }"#), // <<=== Invalid Settings
                nb_replicas: 1,
                nb_shards: 1,
            },
            mappings: internal::IndexMappings {
                value: String::from(r#"{ "properties": { "value": { "type": "text" } } }"#),
            },
        };
        let config = Configuration {
            value: serde_json::to_string(&config).expect("config"),
        };
        let res = client.create_container(config).await;
        drop(guard);
        assert!(res
            .unwrap_err()
            .to_string()
            .starts_with("Container Creation Error"));
    }

    #[derive(Serialize)]
    struct TestObj {
        value: String,
    }

    impl Document for TestObj {
        fn doc_type(&self) -> &'static str {
            "test-obj"
        }

        fn id(&self) -> String {
            self.value.clone()
        }
    }

    #[tokio::test]
    async fn should_correctly_insert_multiple_documents() {
        let mtx = Arc::clone(&docker::AVAILABLE);
        let guard = mtx.lock().unwrap();
        docker::initialize().await.expect("initialization");
        let pool = remote::connection_test_pool()
            .await
            .expect("Elasticsearch Connection Pool");
        let client = pool
            .conn()
            .await
            .expect("Elasticsearch Connection Established");
        let config = internal::IndexConfiguration {
            name: String::from("root_obj_dataset_test-index-bulk-insert"),
            parameters: internal::IndexParameters {
                timeout: String::from("10s"),
                wait_for_active_shards: String::from("1"), // only the primary shard
            },
            settings: internal::IndexSettings {
                base: json!(r#"{ "index": { "number_of_shards": 1 } }"#), // <<=== Invalid Settings
                nb_replicas: 1,
                nb_shards: 1,
            },
            mappings: internal::IndexMappings {
                value: String::from(r#"{ "properties": { "value": { "type": "text" } } }"#),
            },
        };
        let config = Configuration {
            value: serde_json::to_string(&config).expect("config"),
        };
        client
            .create_container(config)
            .await
            .expect("container creation");
        let documents = vec![
            TestObj {
                value: String::from("obj1"),
            },
            TestObj {
                value: String::from("obj2"),
            },
            TestObj {
                value: String::from("obj3"),
            },
            TestObj {
                value: String::from("obj4"),
            },
            TestObj {
                value: String::from("obj5"),
            },
            TestObj {
                value: String::from("obj6"),
            },
        ];
        let documents = futures::stream::iter(documents);

        let documents = documents.map(|d| Box::new(d) as Box<dyn Document + Send + Sync + 'static>);
        let res = client
            .insert_documents(
                String::from("root_obj_dataset_test-index-bulk-insert"),
                documents,
            )
            .await;
        drop(guard);

        assert_eq!(res.expect("insertion stats").created, 6);
    }
}
<commit_msg>Fix test by removing raw litteral strings<commit_after>use elasticsearch::Elasticsearch;

pub mod internal;
pub mod query;
pub mod remote;
pub mod storage;

#[derive(Clone)]
pub struct ElasticsearchStorage(Elasticsearch);

#[cfg(test)]
pub mod tests {

    use futures::stream::StreamExt;
    use serde::Serialize;
    use serde_json::json;
    use std::convert::TryFrom;
    use std::sync::Arc;

    use super::*;

    use crate::domain::model::configuration::Configuration;
    use crate::domain::model::document::Document;
    use crate::domain::ports::remote::Remote;
    use crate::domain::ports::storage::Storage;
    use crate::utils::docker;

    #[test]
    fn should_return_invalid_configuration() {
        let config = Configuration {
            value: String::from("invalid"),
        };
        let res = internal::IndexConfiguration::try_from(config);
        assert!(res
            .unwrap_err()
            .to_string()
            .starts_with("Invalid Elasticsearch Index Configuration"));
    }

    #[tokio::test]
    async fn should_return_invalid_url() {
        let res = remote::connection_pool_url("foobar").await;
        assert!(res
            .unwrap_err()
            .to_string()
            .starts_with("Invalid Elasticsearch URL"));
    }

    #[tokio::test]
    async fn should_connect_to_elasticsearch() {
        let mtx = Arc::clone(&docker::AVAILABLE);
        let _guard = mtx.lock().unwrap();
        docker::initialize().await.expect("initialization");
        let pool = remote::connection_test_pool()
            .await
            .expect("Elasticsearch Connection Pool");
        let _client = pool
            .conn()
            .await
            .expect("Elasticsearch Connection Established");
    }

    #[tokio::test]
    async fn should_create_index_with_valid_configuration() {
        let mtx = Arc::clone(&docker::AVAILABLE);
        let guard = mtx.lock().unwrap();
        docker::initialize().await.expect("initialization");
        let pool = remote::connection_test_pool()
            .await
            .expect("Elasticsearch Connection Pool");
        let client = pool
            .conn()
            .await
            .expect("Elasticsearch Connection Established");
        let config = internal::IndexConfiguration {
            name: String::from("root_obj_dataset_test-index"),
            parameters: internal::IndexParameters {
                timeout: String::from("10s"),
                wait_for_active_shards: String::from("1"), // only the primary shard
            },
            settings: internal::IndexSettings {
                value: json!({ "index": { "number_of_shards": 1, "number_of_replicas": 1 } }),
            },
            mappings: internal::IndexMappings {
                value: json!({ "properties": { "value": { "type": "text" } } }),
            },
        };
        let config = Configuration {
            value: serde_json::to_string(&config).expect("config"),
        };
        let res = client.create_container(config).await;
        drop(guard);
        assert!(res.is_ok());
    }

    #[tokio::test]
    async fn should_correctly_report_duplicate_index_when_creating_twice_the_same_index() {
        let mtx = Arc::clone(&docker::AVAILABLE);
        let guard = mtx.lock().unwrap();
        docker::initialize().await.expect("initialization");
        let pool = remote::connection_test_pool()
            .await
            .expect("Elasticsearch Connection Pool");
        let client = pool
            .conn()
            .await
            .expect("Elasticsearch Connection Established");
        let config = internal::IndexConfiguration {
            name: String::from("root_obj_dataset_test-index-duplicate"),
            parameters: internal::IndexParameters {
                timeout: String::from("10s"),
                wait_for_active_shards: String::from("1"), // only the primary shard
            },
            settings: internal::IndexSettings {
                value: json!({ "index": { "number_of_shards": 1, "number_of_replicas": 1 } }),
            },
            mappings: internal::IndexMappings {
                value: json!({ "properties": { "value": { "type": "text" } } }),
            },
        };
        let config = Configuration {
            value: serde_json::to_string(&config).expect("config"),
        };
        client
            .create_container(config.clone())
            .await
            .expect("container creation");
        let res = client.create_container(config).await;
        drop(guard);
        assert!(res
            .unwrap_err()
            .to_string()
            .contains("Elasticsearch Duplicate Index"));
    }

    #[tokio::test]
    async fn should_correctly_report_invalid_configuration() {
        let mtx = Arc::clone(&docker::AVAILABLE);
        let guard = mtx.lock().unwrap();
        docker::initialize().await.expect("initialization");
        let pool = remote::connection_test_pool()
            .await
            .expect("Elasticsearch Connection Pool");
        let client = pool
            .conn()
            .await
            .expect("Elasticsearch Connection Established");
        let config = internal::IndexConfiguration {
            name: String::from("root_obj_dataset_test-index-invalid-conf"),
            parameters: internal::IndexParameters {
                timeout: String::from("10s"),
                wait_for_active_shards: String::from("1"), // only the primary shard
            },
            settings: internal::IndexSettings {
                value: json!({ "index": "foo" }), // <<=== Invalid Settings
            },
            mappings: internal::IndexMappings {
                value: json!({ "properties": { "value": { "type": "text" } } }),
            },
        };
        let config = Configuration {
            value: serde_json::to_string(&config).expect("config"),
        };
        let res = client.create_container(config).await;
        drop(guard);
        assert!(res
            .unwrap_err()
            .to_string()
            .starts_with("Container Creation Error"));
    }

    #[derive(Serialize)]
    struct TestObj {
        value: String,
    }

    impl Document for TestObj {
        fn doc_type(&self) -> &'static str {
            "test-obj"
        }

        fn id(&self) -> String {
            self.value.clone()
        }
    }

    #[tokio::test]
    async fn should_correctly_insert_multiple_documents() {
        let mtx = Arc::clone(&docker::AVAILABLE);
        let guard = mtx.lock().unwrap();
        docker::initialize().await.expect("initialization");
        let pool = remote::connection_test_pool()
            .await
            .expect("Elasticsearch Connection Pool");
        let client = pool
            .conn()
            .await
            .expect("Elasticsearch Connection Established");
        let config = internal::IndexConfiguration {
            name: String::from("root_obj_dataset_test-index-bulk-insert"),
            parameters: internal::IndexParameters {
                timeout: String::from("10s"),
                wait_for_active_shards: String::from("1"), // only the primary shard
            },
            settings: internal::IndexSettings {
                value: json!({ "index": { "number_of_shards": 1, "number_of_replicas": 1 } }),
            },
            mappings: internal::IndexMappings {
                value: json!({ "properties": { "value": { "type": "text" } } }),
            },
        };
        let config = Configuration {
            value: serde_json::to_string(&config).expect("config"),
        };
        client
            .create_container(config)
            .await
            .expect("container creation");
        let documents = vec![
            TestObj {
                value: String::from("obj1"),
            },
            TestObj {
                value: String::from("obj2"),
            },
            TestObj {
                value: String::from("obj3"),
            },
            TestObj {
                value: String::from("obj4"),
            },
            TestObj {
                value: String::from("obj5"),
            },
            TestObj {
                value: String::from("obj6"),
            },
        ];
        let documents = futures::stream::iter(documents);

        let documents = documents.map(|d| Box::new(d) as Box<dyn Document + Send + Sync + 'static>);
        let res = client
            .insert_documents(
                String::from("root_obj_dataset_test-index-bulk-insert"),
                documents,
            )
            .await;
        drop(guard);

        assert_eq!(res.expect("insertion stats").created, 6);
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2019, 2020 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use crate::serde_helpers;
use chrono::{DateTime, Duration, Utc};
use serde::{Deserialize, Serialize};
use std::path::PathBuf;

#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct RuntimeSettings {
    pub polling: RuntimePolling,
    pub update: RuntimeUpdate,
    pub path: PathBuf,
    pub persistent: bool,
}

#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct RuntimePolling {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub last: Option<DateTime<Utc>>,
    #[serde(with = "serde_helpers::duration_option")]
    pub extra_interval: Option<Duration>,
    pub retries: usize,
    pub now: bool,
    pub server_address: ServerAddress,
}

#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub enum ServerAddress {
    Default,
    Custom(String),
}

#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct RuntimeUpdate {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub upgrade_to_installation: Option<InstallationSet>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub applied_package_uid: Option<String>,
}

#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub enum InstallationSet {
    A,
    B,
}
<commit_msg>sdk: Add copy to InstallationSet<commit_after>// Copyright (C) 2019, 2020 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use crate::serde_helpers;
use chrono::{DateTime, Duration, Utc};
use serde::{Deserialize, Serialize};
use std::path::PathBuf;

#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct RuntimeSettings {
    pub polling: RuntimePolling,
    pub update: RuntimeUpdate,
    pub path: PathBuf,
    pub persistent: bool,
}

#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct RuntimePolling {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub last: Option<DateTime<Utc>>,
    #[serde(with = "serde_helpers::duration_option")]
    pub extra_interval: Option<Duration>,
    pub retries: usize,
    pub now: bool,
    pub server_address: ServerAddress,
}

#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub enum ServerAddress {
    Default,
    Custom(String),
}

#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct RuntimeUpdate {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub upgrade_to_installation: Option<InstallationSet>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub applied_package_uid: Option<String>,
}

#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub enum InstallationSet {
    A,
    B,
}
<|endoftext|>