<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2014 Ben Gamari <bgamari@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::iter::FromIterator;
use std::ops::Deref;

use syntax::ast;
use syntax::ptr::P;
use syntax::ast_util::empty_generics;
use syntax::codemap::{respan, mk_sp};
use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::ToTokens;
use syntax::parse::token;

use super::Builder;
use super::utils;
use super::super::node;

/// A visitor to build the struct for each register
pub struct BuildRegStructs<'a> {
  builder: &'a mut Builder,
  cx: &'a ExtCtxt<'a>,
}

impl<'a> node::RegVisitor for BuildRegStructs<'a> {
  fn visit_prim_reg(&mut self, path: &Vec<String>, reg: &node::Reg,
                    fields: &Vec<node::Field>) {
    let width = match reg.ty {
      node::RegType::RegPrim(ref width, _) => width.node,
      _ => panic!("visit_prim_reg called with non-primitive register"),
    };
    for field in fields.iter() {
      for item in build_field_type(self.cx, path, reg, field).into_iter() {
        self.builder.push_item(item);
      }
    }

    for item in build_reg_struct(self.cx, path, reg, &width).into_iter() {
      self.builder.push_item(item);
    }
  }
}

impl<'a> BuildRegStructs<'a> {
  pub fn new(builder: &'a mut Builder, cx: &'a ExtCtxt<'a>)
             -> BuildRegStructs<'a> {
    BuildRegStructs {builder: builder, cx: cx}
  }
}

/// Build a field type if necessary (e.g. in the case of an `EnumField`)
fn build_field_type(cx: &ExtCtxt, path: &Vec<String>,
                    reg: &node::Reg, field: &node::Field)
                    -> Vec<P<ast::Item>> {
  match field.ty.node {
    node::FieldType::EnumField { ref variants, .. } => {
      // FIXME(bgamari): We construct a path, then only take the last
      // segment, this could be more efficient
      let name: ast::Ident =
        utils::field_type_path(cx, path, reg, field)
        .segments.last().unwrap().identifier;
      let enum_def: ast::EnumDef = ast::EnumDef {
        variants: FromIterator::from_iter(
          variants.iter().map(|v| P(build_enum_variant(cx, v)))),
      };
      let attrs: Vec<ast::Attribute> = vec!(
        utils::list_attribute(cx, "derive",
                              vec!("PartialEq"),
                              field.name.span),
        utils::list_attribute(cx, "allow",
                              vec!("dead_code",
                                   "non_camel_case_types",
                                   "missing_docs"),
                              field.name.span));
      let ty_item: P<ast::Item> = P(ast::Item {
        ident: name,
        id: ast::DUMMY_NODE_ID,
        node: ast::ItemEnum(enum_def, empty_generics()),
        vis: ast::Public,
        attrs: attrs,
        span: field.ty.span,
      });
      vec!(ty_item)
    },
    _ => Vec::new()
  }
}

/// Produce a register struct if necessary (for primitive typed registers).
/// In this case `None` indicates no struct is necessary, not failure.
/// For instance,
///
///     pub struct REG {_value: u32}
fn build_reg_struct(cx: &ExtCtxt, path: &Vec<String>,
    reg: &node::Reg, _width: &node::RegWidth) -> Vec<P<ast::Item>> {
  let packed_ty =
    utils::reg_primitive_type(cx, reg)
    .expect("Unexpected non-primitive reg");

  let reg_doc = match reg.docstring {
    Some(d) => token::get_ident(d.node).to_string(),
    None => "no documentation".to_string(),
  };
  let docstring = format!("Register `{}`: {}",
                          reg.name.node,
                          reg_doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

  let ty_name = utils::path_ident(cx, path);
  let item = quote_item!(cx,
    $doc_attr
    #[derive(Clone)]
    #[allow(non_camel_case_types)]
    pub struct $ty_name {
      value: VolatileCell<$packed_ty>,
    }
  );
  let mut item: ast::Item = item.unwrap().deref().clone();
  item.span = reg.name.span;
  let copy_impl = quote_item!(cx, impl ::core::marker::Copy for $ty_name {}).unwrap();
  vec!(P(item), copy_impl)
}

/// Build a variant of an `EnumField`
fn build_enum_variant(cx: &ExtCtxt, variant: &node::Variant)
                      -> ast::Variant {
  let doc = match variant.docstring {
    Some(d) => token::get_ident(d.node).to_string(),
    None => "no documentation".to_string(),
  };
  let docstring = format!("`0x{:x}`. {}",
                          variant.value.node,
                          doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));
  respan(
    mk_sp(variant.name.span.lo, variant.value.span.hi),
    ast::Variant_ {
      name: cx.ident_of(variant.name.node.as_str()),
      attrs: vec!(doc_attr),
      kind: ast::TupleVariantKind(Vec::new()),
      id: ast::DUMMY_NODE_ID,
      disr_expr: Some(utils::expr_int(cx, respan(variant.value.span,
                                                 variant.value.node as i64))),
      vis: ast::Inherited,
    }
  )
}
<commit_msg>Updated ioreg/builder/register.rs<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Ben Gamari <bgamari@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::iter::FromIterator;
use std::ops::Deref;

use syntax::ast;
use syntax::ptr::P;
use syntax::ast_util::empty_generics;
use syntax::codemap::{respan, mk_sp};
use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::ToTokens;
use syntax::parse::token;

use super::Builder;
use super::utils;
use super::super::node;

/// A visitor to build the struct for each register
pub struct BuildRegStructs<'a> {
  builder: &'a mut Builder,
  cx: &'a ExtCtxt<'a>,
}

impl<'a> node::RegVisitor for BuildRegStructs<'a> {
  fn visit_prim_reg(&mut self, path: &Vec<String>, reg: &node::Reg,
                    fields: &Vec<node::Field>) {
    let width = match reg.ty {
      node::RegType::RegPrim(ref width, _) => width.node,
      _ => panic!("visit_prim_reg called with non-primitive register"),
    };
    for field in fields.iter() {
      for item in build_field_type(self.cx, path, reg, field).into_iter() {
        self.builder.push_item(item);
      }
    }

    for item in build_reg_struct(self.cx, path, reg, &width).into_iter() {
      self.builder.push_item(item);
    }
  }
}

impl<'a> BuildRegStructs<'a> {
  pub fn new(builder: &'a mut Builder, cx: &'a ExtCtxt<'a>)
             -> BuildRegStructs<'a> {
    BuildRegStructs {builder: builder, cx: cx}
  }
}

/// Build a field type if necessary (e.g. in the case of an `EnumField`)
fn build_field_type(cx: &ExtCtxt, path: &Vec<String>,
                    reg: &node::Reg, field: &node::Field)
                    -> Vec<P<ast::Item>> {
  match field.ty.node {
    node::FieldType::EnumField { ref variants, .. } => {
      // FIXME(bgamari): We construct a path, then only take the last
      // segment, this could be more efficient
      let name: ast::Ident =
        utils::field_type_path(cx, path, reg, field)
        .segments.last().unwrap().identifier;
      let enum_def: ast::EnumDef = ast::EnumDef {
        variants: FromIterator::from_iter(
          variants.iter().map(|v| P(build_enum_variant(cx, v)))),
      };
      let attrs: Vec<ast::Attribute> = vec!(
        utils::list_attribute(cx, "derive",
                              vec!("PartialEq"),
                              field.name.span),
        utils::list_attribute(cx, "allow",
                              vec!("dead_code",
                                   "non_camel_case_types",
                                   "missing_docs"),
                              field.name.span));
      let ty_item: P<ast::Item> = P(ast::Item {
        ident: name,
        id: ast::DUMMY_NODE_ID,
        node: ast::ItemEnum(enum_def, empty_generics()),
        vis: ast::Public,
        attrs: attrs,
        span: field.ty.span,
      });
      vec!(ty_item)
    },
    _ => Vec::new()
  }
}

/// Produce a register struct if necessary (for primitive typed registers).
/// In this case `None` indicates no struct is necessary, not failure.
/// For instance,
///
///     pub struct REG {_value: u32}
fn build_reg_struct(cx: &ExtCtxt, path: &Vec<String>,
    reg: &node::Reg, _width: &node::RegWidth) -> Vec<P<ast::Item>> {
  let packed_ty =
    utils::reg_primitive_type(cx, reg)
    .expect("Unexpected non-primitive reg");

  let reg_doc = match reg.docstring {
    Some(d) => d.node.name.to_string(),
    None => "no documentation".to_string(),
  };
  let docstring = format!("Register `{}`: {}",
                          reg.name.node,
                          reg_doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

  let ty_name = utils::path_ident(cx, path);
  let item = quote_item!(cx,
    $doc_attr
    #[derive(Clone)]
    #[allow(non_camel_case_types)]
    pub struct $ty_name {
      value: VolatileCell<$packed_ty>,
    }
  );
  let mut item: ast::Item = item.unwrap().deref().clone();
  item.span = reg.name.span;
  let copy_impl = quote_item!(cx, impl ::core::marker::Copy for $ty_name {}).unwrap();
  vec!(P(item), copy_impl)
}

/// Build a variant of an `EnumField`
fn build_enum_variant(cx: &ExtCtxt, variant: &node::Variant)
                      -> ast::Variant {
  let doc = match variant.docstring {
    Some(d) => d.node.nameto_string(),
    None => "no documentation".to_string(),
  };
  let docstring = format!("`0x{:x}`. {}",
                          variant.value.node,
                          doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));
  respan(
    mk_sp(variant.name.span.lo, variant.value.span.hi),
    ast::Variant_ {
      name: cx.ident_of(variant.name.node.as_str()),
      attrs: vec!(doc_attr),
      kind: ast::TupleVariantKind(Vec::new()),
      id: ast::DUMMY_NODE_ID,
      disr_expr: Some(utils::expr_int(cx, respan(variant.value.span,
                                                 variant.value.node as i64))),
      vis: ast::Inherited,
    }
  )
}
<|endoftext|>


<commit_before>use common::types::*;

use util::boxed::{
	ToBoxedVec,
};

#[derive(Clone)]
pub struct Expr (pub Ty, pub ExprKind);

impl Expr
{
	#[inline]
	pub fn ty(&self) -> &Ty
	{
		&self.0
	}

	#[inline]
	pub fn kind(&self) -> &ExprKind
	{
		&self.1
	}
}

/// Expression Specific Element
#[derive(Clone)]
pub enum ExprKind {
  // Unary Expressions
  Not      (Box<Expr>),
  IsNull   (Box<Expr>),
  IsNotNull(Box<Expr>),
  PlusSign (Box<Expr>),
  MinusSign(Box<Expr>),
  Cast     (Box<Expr>, Ty, Ty),

  // Binary Arithmetic Expressions
  And(Box<Expr>,Box<Expr>),
  Or(Box<Expr>,Box<Expr>),
  Cmp(CmpOp, Box<Expr>, Box<Expr>),
  Arithm(ArithmOp, Box<Expr>, Box<Expr>),

  // function and values
  Fn(FnDecl, Vec<Box<Expr>>),
  Field(String),
  Const(Literal),

  // condition
  Switch(Vec<Box<Expr>>, Box<Expr>), // multiple conditions, else return value
  Case  (Box<Expr>, Box<Expr>),      // condition, return value
}

/// Comparison Operator Type
#[derive(Clone, Copy)]
pub enum CmpOp {
  Eq,
  Ne,
  Lt,
  Le,
  Gt,
  Ge
}

/// Arithmetic Operator Type
#[derive(Clone, Copy)]
pub enum ArithmOp {
  Plus,
  Sub,
  Mul,
  Div,
  Rem,
}

/// Function Declaration
#[derive(Clone)]
pub struct FnDecl {
  signature: String,
  ret_ty: Ty
}

impl FnDecl
{
	pub fn ty(&self) -> &Ty
	{
		&self.ret_ty
	}
}

/// Representation for a single value
#[derive(Clone)]
pub enum Literal
{
  Bool(bool),
  I8(i8),
  I16(i16),
  I32(i32),
  I64(i64),
  F32(f32),
  F64(f64),
  String(String)
}

impl Literal
{
	pub fn ty(&self) -> Ty
	{
		match *self {
			Literal::Bool(_) => bool_ty(),
			Literal::I8(_)   => i8_ty(),
			Literal::I16(_)  => i16_ty(),
			Literal::I32(_)  => i32_ty(),
			Literal::I64(_)  => i64_ty(),
			Literal::F32(_)  => f32_ty(),
			Literal::F64(_)  => f64_ty(),
			_                => unimplemented!()
		}
	}
}

macro_rules! into_literal(
	($ty:ty, $literal_kind:ident) => (
    impl Into<Literal> for $ty {
	    fn into(self) -> Literal
	    {
	    	Literal::$literal_kind(self)
	    }
    }
  );
);

into_literal!(bool, Bool);
into_literal!(i8,   I8);
into_literal!(i16,  I16);
into_literal!(i32,  I32);
into_literal!(i64,  I64);
into_literal!(f32,  F32);
into_literal!(f64,  F64);

#[allow(non_snake_case)]
pub fn Not(c: Expr) -> Expr
{
	Expr(c.ty().clone(), ExprKind::Not(Box::new(c)))
}

#[allow(non_snake_case)]
pub fn IsNull(c: Expr) -> Expr
{
	Expr(bool_ty(), ExprKind::IsNull(Box::new(c)))
}

#[allow(non_snake_case)]
pub fn IsNotNull(c: Expr) -> Expr
{
	Expr(bool_ty(), ExprKind::IsNull(Box::new(c)))
}

#[allow(non_snake_case)]
pub fn Cast(c: Expr, from_ty: &Ty, to_ty: &Ty) -> Expr
{
	Expr(to_ty.clone(), ExprKind::Cast(Box::new(c), from_ty.clone(), to_ty.clone()))
}

#[allow(non_snake_case)]
pub fn PlusSign(c: Expr) -> Expr
{
	Expr(c.ty().	clone(), ExprKind::PlusSign(Box::new(c)))
}

#[allow(non_snake_case)]
pub fn MinusSign(c: Expr) -> Expr
{
	Expr(c.ty().clone(), ExprKind::MinusSign(Box::new(c)))
}

#[allow(non_snake_case)]
pub fn And(l: Expr, r: Expr) -> Expr
{
	Expr(bool_ty(), ExprKind::And(Box::new(l), Box::new(r)))
}

#[allow(non_snake_case)]
pub fn Or(l: Expr, r: Expr) -> Expr
{
	Expr(bool_ty(), ExprKind::Or(Box::new(l), Box::new(r)))
}

#[allow(non_snake_case)]
pub fn Cmp(op: CmpOp, l: Expr, r: Expr) -> Expr
{
	Expr(bool_ty(), ExprKind::Cmp(op, Box::new(l), Box::new(r)))
}

#[allow(non_snake_case)]
pub fn Arithm(op: &ArithmOp, ret_type: &Ty, l: Expr, r: Expr) -> Expr
{
	Expr(ret_type.clone(), ExprKind::Arithm(*op, Box::new(l), Box::new(r)))
}

#[warn(non_snake_case)]
pub fn Plus(ret_type: &Ty, l: Expr, r: Expr) -> Expr {
	Expr(ret_type.clone(), ExprKind::Arithm(ArithmOp::Plus, Box::new(l), Box::new(r)))
}

#[warn(non_snake_case)]
pub fn Subtract(ret_type: &Ty, l: Expr, r: Expr) -> Expr {
	Expr(ret_type.clone(), ExprKind::Arithm(ArithmOp::Sub, Box::new(l), Box::new(r)))
}

#[warn(non_snake_case)]
pub fn Mul(ret_type: &Ty, l: Expr, r: Expr) -> Expr {
	Expr(ret_type.clone(), ExprKind::Arithm(ArithmOp::Mul, Box::new(l), Box::new(r)))
}

#[allow(non_snake_case)]
pub fn Func(decl: FnDecl, args: Vec<Expr>) -> Expr
{
	Expr(decl.ty().clone(), ExprKind::Fn(decl, args.to_boxed()))
}

#[allow(non_snake_case)]
pub fn Switch(cases: Vec<Expr>, default: Expr) -> Expr
{
	Expr(default.ty().clone(), ExprKind::Switch(cases.to_boxed(), Box::new(default)))
}

#[allow(non_snake_case)]
pub fn Case(cond: Expr, result: Expr) -> Expr
{
	Expr(result.ty().clone(), ExprKind::Case(Box::new(cond), Box::new(result)))
}

#[allow(non_snake_case)]
pub fn Const<T: Into<Literal>>(value: T) -> Expr
{
	let literal = value.into();
	Expr(literal.ty(), ExprKind::Const(literal))
}

#[allow(non_snake_case)]
pub fn Field(ty: &Ty, name: &str) -> Expr
{
	Expr(ty.clone(), ExprKind::Field(name.to_string()))
}

pub fn clone(e: &Box<Expr>) -> Expr
{
	*(e.clone())
}

pub mod optimizer
{
	pub use expr_optimizer::*;
}

pub mod visitor
{
	//! Visitor for Expr
	use super::*;

	/// Simple visitor to walk all Expr node in a single accept function.
	/// It provides an easier way to rewrite a Expr tree.
	pub trait Visitor: Sized
	{
	  fn accept(&mut self, e: &Expr)
	  {
	    accept_by_default(self, e);
	  }
	}

	pub fn accept_by_default<T>(v: &mut T, e: &Expr) where T: Visitor + Sized {
	  match *e.kind() {
	    ExprKind::Not      (ref c)       => v.accept(c),
	    ExprKind::IsNull   (ref c)       => v.accept(c),
	    ExprKind::IsNotNull(ref c)       => v.accept(c),
	    ExprKind::PlusSign (ref c)       => v.accept(c),
	    ExprKind::MinusSign(ref c)       => v.accept(c),
	    ExprKind::Cast     (ref c, _, _) => v.accept(c),

	    ExprKind::And      (ref l, ref r)    => { v.accept(l); v.accept(r) },
	    ExprKind::Or       (ref l, ref r)    => { v.accept(l); v.accept(r) },
	    ExprKind::Cmp      (_, ref l, ref r) => { v.accept(l); v.accept(r) },
	    ExprKind::Arithm   (_, ref l, ref r) => { v.accept(l); v.accept(r) },

	    ExprKind::Fn     (_, ref args)  => { for e in args.iter() { v.accept(e) } },
			ExprKind::Field  (_) 	          => {},
	    ExprKind::Const  (_)            => {}

	    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) },
	  }
	}

	/// Simple visitor to walk all Expr node in a single accept function.
	/// It provides an easier way to rewrite a Expr tree.
	pub trait TransformVisitor: Sized
  {
	  fn transform(&self, e: &Expr) -> Expr
	  {
	    transform_by_default(self, e)
	  }
	}

	pub fn transform_by_default<T>(v: &T, e: &Expr) -> Expr
			where T: TransformVisitor + Sized
	{
		match *e.kind() {
	    ExprKind::Not      (ref c)               => Not      (v.transform(c)),
	    ExprKind::IsNull   (ref c)               => IsNull   (v.transform(c)),
	    ExprKind::IsNotNull(ref c)               => IsNotNull(v.transform(c)),
	    ExprKind::PlusSign (ref c)               => PlusSign (v.transform(c)),
	    ExprKind::MinusSign(ref c)               => MinusSign(v.transform(c)),
	    ExprKind::Cast     (ref c, ref f, ref t) => Cast     (v.transform(c), f, t),

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

	    ExprKind::Fn       (ref f, ref args)     => {
	    	let rargs = args.iter().map(|arg| v.transform(arg)).collect::<Vec<Expr>>();
	    	Func(f.clone(), rargs)
    	},
			ExprKind::Field     (_) 	                => e.clone(),
	    ExprKind::Const     (_)                   => e.clone(),

	    ExprKind::Switch   (ref cases, ref default)  => {
	    	let rcases = cases.iter().map(|case| v.transform(case)).collect::<Vec<Expr>>();

	    	Switch(rcases, v.transform(default))
   	  }
	    ExprKind::Case      (ref l, ref r)        => Case(v.transform(l), v.transform(r)),
	  }
	}
}<commit_msg>Fixed compilation error after b6e19.<commit_after>use common::types::*;
use util::collection::vec;

#[derive(Clone)]
pub struct Expr (pub Ty, pub ExprKind);

#[inline(always)]
pub fn expr(ty: &Ty, kind: ExprKind) -> Expr
{
  Expr (ty.clone(), kind)
}

impl Expr
{

	#[inline]
	pub fn ty(&self) -> &Ty
	{
		&self.0
	}

	#[inline]
	pub fn kind(&self) -> &ExprKind
	{
		&self.1
	}
}

/// Expression Specific Element
#[derive(Clone)]
pub enum ExprKind {
  // Unary Expressions
  Not      (Box<Expr>),
  IsNull   (Box<Expr>),
  IsNotNull(Box<Expr>),
  PlusSign (Box<Expr>),
  MinusSign(Box<Expr>),
  Cast     (Box<Expr>, Ty, Ty),

  // Binary Arithmetic Expressions
  And(Box<Expr>,Box<Expr>),
  Or(Box<Expr>,Box<Expr>),
  Cmp(CmpOp, Box<Expr>, Box<Expr>),
  Arithm(ArithmOp, Box<Expr>, Box<Expr>),

  // function and values
  Fn(FnDecl, Vec<Box<Expr>>),
  Field(String),
  Const(Literal),

  // condition
  Switch(Vec<Box<Expr>>, Box<Expr>), // multiple conditions, else return value
  Case  (Box<Expr>, Box<Expr>),      // condition, return value
}

/// Comparison Operator Type
#[derive(Clone, Copy)]
pub enum CmpOp {
  Eq,
  Ne,
  Lt,
  Le,
  Gt,
  Ge
}

/// Arithmetic Operator Type
#[derive(Clone, Copy)]
pub enum ArithmOp {
  Plus,
  Sub,
  Mul,
  Div,
  Rem,
}

/// Function Declaration
#[derive(Clone)]
pub struct FnDecl {
  signature: String,
  ret_ty: Ty
}

impl FnDecl
{
	pub fn ty(&self) -> &Ty
	{
		&self.ret_ty
	}
}

/// Representation for a single value
#[derive(Clone)]
pub enum Literal
{
  Bool(bool),
  U8(u8),
  I8(i8),
  I16(i16),
  I32(i32),
  I64(i64),
  F32(f32),
  F64(f64),
  String(String)
}

impl Literal
{
	pub fn ty(&self) -> &Ty
	{
		match *self {
			Literal::Bool(_) => BOOL,
      Literal::U8(_)   => U8,
			Literal::I8(_)   => I8,
			Literal::I16(_)  => I16,
			Literal::I32(_)  => I32,
			Literal::I64(_)  => I64,
			Literal::F32(_)  => F32,
			Literal::F64(_)  => F64,
			_                => unimplemented!()
		}
	}
}

macro_rules! into_literal(
	($ty:ty, $literal_kind:ident) => (
    impl Into<Literal> for $ty {
	    fn into(self) -> Literal
	    {
	    	Literal::$literal_kind(self)
	    }
    }
  );
);

into_literal!(bool, Bool);
into_literal!(i8,   I8);
into_literal!(i16,  I16);
into_literal!(i32,  I32);
into_literal!(i64,  I64);
into_literal!(f32,  F32);
into_literal!(f64,  F64);

#[allow(non_snake_case)]
pub fn Not(c: Expr) -> Expr
{
	Expr(c.ty().clone(), ExprKind::Not(Box::new(c)))
}

#[allow(non_snake_case)]
pub fn IsNull(c: Expr) -> Expr
{
	expr(BOOL, ExprKind::IsNull(Box::new(c)))
}

#[allow(non_snake_case)]
pub fn IsNotNull(c: Expr) -> Expr
{
	expr(BOOL, ExprKind::IsNull(Box::new(c)))
}

#[allow(non_snake_case)]
pub fn Cast(c: Expr, from_ty: &Ty, to_ty: &Ty) -> Expr
{
	expr(BOOL, ExprKind::Cast(Box::new(c), from_ty.clone(), to_ty.clone()))
}

#[allow(non_snake_case)]
pub fn PlusSign(c: Expr) -> Expr
{
	Expr(c.ty().clone(), ExprKind::PlusSign(Box::new(c)))
}

#[allow(non_snake_case)]
pub fn MinusSign(c: Expr) -> Expr
{
	Expr(c.ty().clone(), ExprKind::MinusSign(Box::new(c)))
}

#[allow(non_snake_case)]
pub fn And(l: Expr, r: Expr) -> Expr
{
	expr(BOOL, ExprKind::And(Box::new(l), Box::new(r)))
}

#[allow(non_snake_case)]
pub fn Or(l: Expr, r: Expr) -> Expr
{
	expr(BOOL, ExprKind::Or(Box::new(l), Box::new(r)))
}

#[allow(non_snake_case)]
pub fn Cmp(op: CmpOp, l: Expr, r: Expr) -> Expr
{
	expr(BOOL, ExprKind::Cmp(op, Box::new(l), Box::new(r)))
}

#[allow(non_snake_case)]
pub fn Arithm(op: &ArithmOp, ret_type: &Ty, l: Expr, r: Expr) -> Expr
{
	expr(ret_type, ExprKind::Arithm(*op, Box::new(l), Box::new(r)))
}

#[allow(non_snake_case)]
pub fn Plus(ret_type: &Ty, l: Expr, r: Expr) -> Expr {
	expr(ret_type, ExprKind::Arithm(ArithmOp::Plus, Box::new(l), Box::new(r)))
}

#[allow(non_snake_case)]
pub fn Subtract(ret_type: &Ty, l: Expr, r: Expr) -> Expr {
	expr(ret_type, ExprKind::Arithm(ArithmOp::Sub, Box::new(l), Box::new(r)))
}

#[allow(non_snake_case)]
pub fn Mul(ret_type: &Ty, l: Expr, r: Expr) -> Expr {
	expr(ret_type, ExprKind::Arithm(ArithmOp::Mul, Box::new(l), Box::new(r)))
}

#[allow(non_snake_case)]
pub fn Func(decl: FnDecl, args: Vec<Expr>) -> Expr
{
	Expr(decl.ty().clone(), ExprKind::Fn(decl, vec::to_boxed(args)))
}

#[allow(non_snake_case)]
pub fn Switch(cases: Vec<Expr>, default: Expr) -> Expr
{
	Expr(default.ty().clone(), ExprKind::Switch(vec::to_boxed(cases), Box::new(default)))
}

#[allow(non_snake_case)]
pub fn Case(cond: Expr, result: Expr) -> Expr
{
	Expr(result.ty().clone(), ExprKind::Case(Box::new(cond), Box::new(result)))
}

#[allow(non_snake_case)]
pub fn Const<T: Into<Literal>>(value: T) -> Expr
{
	let literal = value.into();
	Expr(literal.ty().clone(), ExprKind::Const(literal))
}

#[allow(non_snake_case)]
pub fn Field(ty: &Ty, name: &str) -> Expr
{
	expr(ty, ExprKind::Field(name.to_string()))
}

pub fn clone(e: &Box<Expr>) -> Expr
{
	*(e.clone())
}

pub mod optimizer
{
	pub use expr_optimizer::*;
}

pub mod visitor
{
	//! Visitor for Expr
	use super::*;

	/// Simple visitor to walk all Expr node in a single accept function.
	/// It provides an easier way to rewrite a Expr tree.
	pub trait Visitor: Sized
	{
	  fn accept(&mut self, e: &Expr)
	  {
	    accept_by_default(self, e);
	  }
	}

	pub fn accept_by_default<T>(v: &mut T, e: &Expr) where T: Visitor + Sized {
	  match *e.kind() {
	    ExprKind::Not      (ref c)       => v.accept(c),
	    ExprKind::IsNull   (ref c)       => v.accept(c),
	    ExprKind::IsNotNull(ref c)       => v.accept(c),
	    ExprKind::PlusSign (ref c)       => v.accept(c),
	    ExprKind::MinusSign(ref c)       => v.accept(c),
	    ExprKind::Cast     (ref c, _, _) => v.accept(c),

	    ExprKind::And      (ref l, ref r)    => { v.accept(l); v.accept(r) },
	    ExprKind::Or       (ref l, ref r)    => { v.accept(l); v.accept(r) },
	    ExprKind::Cmp      (_, ref l, ref r) => { v.accept(l); v.accept(r) },
	    ExprKind::Arithm   (_, ref l, ref r) => { v.accept(l); v.accept(r) },

	    ExprKind::Fn     (_, ref args)  => { for e in args.iter() { v.accept(e) } },
			ExprKind::Field  (_) 	          => {},
	    ExprKind::Const  (_)            => {}

	    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) },
	  }
	}

	/// Simple visitor to walk all Expr node in a single accept function.
	/// It provides an easier way to rewrite a Expr tree.
	pub trait TransformVisitor: Sized
  {
	  fn transform(&self, e: &Expr) -> Expr
	  {
	    transform_by_default(self, e)
	  }
	}

	pub fn transform_by_default<T>(v: &T, e: &Expr) -> Expr
			where T: TransformVisitor + Sized
	{
		match *e.kind() {
	    ExprKind::Not      (ref c)               => Not      (v.transform(c)),
	    ExprKind::IsNull   (ref c)               => IsNull   (v.transform(c)),
	    ExprKind::IsNotNull(ref c)               => IsNotNull(v.transform(c)),
	    ExprKind::PlusSign (ref c)               => PlusSign (v.transform(c)),
	    ExprKind::MinusSign(ref c)               => MinusSign(v.transform(c)),
	    ExprKind::Cast     (ref c, ref f, ref t) => Cast     (v.transform(c), f, t),

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

	    ExprKind::Fn       (ref f, ref args)     => {
	    	let rargs = args.iter().map(|arg| v.transform(arg)).collect::<Vec<Expr>>();
	    	Func(f.clone(), rargs)
    	},
			ExprKind::Field     (_) 	                => e.clone(),
	    ExprKind::Const     (_)                   => e.clone(),

	    ExprKind::Switch   (ref cases, ref default)  => {
	    	let rcases = cases.iter().map(|case| v.transform(case)).collect::<Vec<Expr>>();

	    	Switch(rcases, v.transform(default))
   	  }
	    ExprKind::Case      (ref l, ref r)        => Case(v.transform(l), v.transform(r)),
	  }
	}
}<|endoftext|>


<commit_before>//! Procedural macro implementing `#[derive(EnumMap)]`
//!
//! This is supposed to used with `enum-map` crate, which provides the
//! actual usage documentation.

#![recursion_limit = "128"]

extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;

use std::iter;

use proc_macro::TokenStream;
use syn::{Body, Ident, Variant, VariantData};
use quote::Tokens;

fn generate_enum_code(name: &Ident, variants: &[Variant]) -> Tokens {
    let mut enum_count = 0usize;
    let mut has_discriminants = false;
    for &Variant {
        ref data,
        ref discriminant,
        ..
    } in variants
    {
        if data != &VariantData::Unit {
            panic!("#[derive(EnumMap)] requires C style style enum");
        }
        if discriminant.is_some() {
            has_discriminants = true;
        }
        enum_count += 1;
    }

    let variant_a = variants.iter().map(|variant| &variant.ident);
    let variant_b = variants.iter().map(|variant| &variant.ident);
    let repeat_name = iter::repeat(name);
    let repeat_name_b = repeat_name.clone();
    let counter = 0..variants.len();

    let to_usize = if variants.len() == 0 || has_discriminants {
        let repeat_name = repeat_name.clone();
        let variant = variants.iter().map(|variant| &variant.ident);
        let counter = 0..variants.len();
        quote! {
            match self {
                #(
                    #repeat_name::#variant => #counter,
                )*
            }
        }
    } else {
        quote! { self as usize }
    };

    quote! {
        impl<V> ::enum_map::Internal<V> for #name {
            type Array = [V; #enum_count];
            fn slice(array: &Self::Array) -> &[V] {
                array
            }
            fn slice_mut(array: &mut Self::Array) -> &mut [V] {
                array
            }
            fn from_usize(value: usize) -> Self {
                match value {
                    #(
                        #counter => #repeat_name::#variant_a,
                    )*
                    _ => unreachable!()
                }
            }
            fn to_usize(self) -> usize {
                #to_usize
            }
            fn from_function<F: FnMut(Self) -> V>(mut _f: F) -> Self::Array {
                [#(
                    _f(#repeat_name_b::#variant_b),
                )*]
            }
        }
    }
}

#[proc_macro_derive(EnumMap)]
pub fn derive_enum_map(input: TokenStream) -> TokenStream {
    let input = syn::parse_macro_input(&input.to_string()).unwrap();
    match input.body {
        Body::Enum(ref variants) => generate_enum_code(&input.ident, variants),
        _ => panic!("#[derive(EnumMap)] is only defined for enums"),
    }.parse()
        .unwrap()
}
<commit_msg>Move syn extern crate to be after quote<commit_after>//! Procedural macro implementing `#[derive(EnumMap)]`
//!
//! This is supposed to used with `enum-map` crate, which provides the
//! actual usage documentation.

#![recursion_limit = "128"]

extern crate proc_macro;
#[macro_use]
extern crate quote;
extern crate syn;

use std::iter;

use proc_macro::TokenStream;
use syn::{Body, Ident, Variant, VariantData};
use quote::Tokens;

fn generate_enum_code(name: &Ident, variants: &[Variant]) -> Tokens {
    let mut enum_count = 0usize;
    let mut has_discriminants = false;
    for &Variant {
        ref data,
        ref discriminant,
        ..
    } in variants
    {
        if data != &VariantData::Unit {
            panic!("#[derive(EnumMap)] requires C style style enum");
        }
        if discriminant.is_some() {
            has_discriminants = true;
        }
        enum_count += 1;
    }

    let variant_a = variants.iter().map(|variant| &variant.ident);
    let variant_b = variants.iter().map(|variant| &variant.ident);
    let repeat_name = iter::repeat(name);
    let repeat_name_b = repeat_name.clone();
    let counter = 0..variants.len();

    let to_usize = if variants.len() == 0 || has_discriminants {
        let repeat_name = repeat_name.clone();
        let variant = variants.iter().map(|variant| &variant.ident);
        let counter = 0..variants.len();
        quote! {
            match self {
                #(
                    #repeat_name::#variant => #counter,
                )*
            }
        }
    } else {
        quote! { self as usize }
    };

    quote! {
        impl<V> ::enum_map::Internal<V> for #name {
            type Array = [V; #enum_count];
            fn slice(array: &Self::Array) -> &[V] {
                array
            }
            fn slice_mut(array: &mut Self::Array) -> &mut [V] {
                array
            }
            fn from_usize(value: usize) -> Self {
                match value {
                    #(
                        #counter => #repeat_name::#variant_a,
                    )*
                    _ => unreachable!()
                }
            }
            fn to_usize(self) -> usize {
                #to_usize
            }
            fn from_function<F: FnMut(Self) -> V>(mut _f: F) -> Self::Array {
                [#(
                    _f(#repeat_name_b::#variant_b),
                )*]
            }
        }
    }
}

#[proc_macro_derive(EnumMap)]
pub fn derive_enum_map(input: TokenStream) -> TokenStream {
    let input = syn::parse_macro_input(&input.to_string()).unwrap();
    match input.body {
        Body::Enum(ref variants) => generate_enum_code(&input.ident, variants),
        _ => panic!("#[derive(EnumMap)] is only defined for enums"),
    }.parse()
        .unwrap()
}
<|endoftext|>


<commit_before>//! Contains methods for initializing the lua config
#![allow(dead_code)]

use std::fs::{OpenOptions, File};
use std::env;
use std::path::Path;

use std::io::Result as IOResult;

pub const INIT_FILE: &'static str = "init.lua";
pub const INIT_FILE_FALLBACK_PATH: &'static str = "/etc/way-cooler/";

#[inline]
fn read_file<P: AsRef<Path>>(path: P) -> IOResult<File> {
    OpenOptions::new().read(true).open(path)
}

#[cfg(test)]
pub fn get_config() -> (bool, Result<File, &'static str>) {
    (false, Err("Loading config should be ignored during tests for now"))
}

#[cfg(not(test))]
pub fn get_config() -> (bool, Result<File, &'static str>) {
    (true, get_config_file())
}

/// Parses environment variables
fn get_config_file() -> Result<File, &'static str> {
    if let Ok(path_env) = env::var("WAY_COOLER_CONFIG") {
        if let Ok(file) = read_file(Path::new(&path_env)) {
            info!("Reading init file from $WAY_COOLER_INIT_FILE: {}", path_env);
            return Ok(file)
        }
        warn!("$WAY_COOLER_INIT_FILE={}, was not a valid path to a config file. Defaulting ...", path_env);
    }

    if let Ok(xdg) = env::var("XDG_CONFIG_HOME") {
        if let Ok(file) = read_file(Path::new(&xdg).join(INIT_FILE)) {
            info!("Reading init file from $XDG_CONFIG_HOME: {}", xdg);
            return Ok(file)
        }
        warn!("$XDG_CONFIG_HOME={}, was not a valid path to a config file. Defaulting ...", xdg);
    }
    let dot_config = Path::new(&env::var("HOME")
                               .expect("HOME environment variable not defined!"))
        .join(".config").join("way-cooler").join(INIT_FILE);
    trace!("Looking at {:?}", dot_config);
    if let Ok(file) = read_file(&dot_config) {
        info!("Reading init file from {:?}", &dot_config);
        return Ok(file)
    }

    let etc_config = Path::new(INIT_FILE_FALLBACK_PATH).join(INIT_FILE);

    if let Ok(file) = read_file(&etc_config) {
        info!("Reading init file from fallback {:?}", &etc_config);
        return Ok(file)
    }

    return Err("Could not find an init file in any path!")
}
<commit_msg>Hotfix init file loading code<commit_after>//! Contains methods for initializing the lua config
#![allow(dead_code)]

use std::fs::{OpenOptions, File};
use std::env;
use std::path::Path;

use std::io::Result as IOResult;

pub const INIT_FILE: &'static str = "init.lua";
pub const INIT_FILE_FALLBACK_PATH: &'static str = "/etc/way-cooler/";

#[inline]
fn read_file<P: AsRef<Path>>(path: P) -> IOResult<File> {
    OpenOptions::new().read(true).open(path)
}

#[cfg(test)]
pub fn get_config() -> (bool, Result<File, &'static str>) {
    (false, Err("Loading config should be ignored during tests for now"))
}

#[cfg(not(test))]
pub fn get_config() -> (bool, Result<File, &'static str>) {
    (true, get_config_file())
}

/// Parses environment variables
fn get_config_file() -> Result<File, &'static str> {
    let home_var = env::var("HOME").expect("HOME environment variable not defined!");
    let home = home_var.as_str();
    if let Ok(path_env) = env::var("WAY_COOLER_INIT_FILE") {
        if let Ok(file) = read_file(Path::new(&path_env)) {
            info!("Reading init file from $WAY_COOLER_INIT_FILE: {}",
                  path_env.as_str().replace(home, "~"));
            return Ok(file)
        }
        warn!("Looking for init file: $WAY_COOLER_INIT_FILE={}, was not a valid path to a config file.",
              path_env.as_str().replace(home, "~"));
    }

    if let Ok(xdg) = env::var("XDG_CONFIG_HOME") {
        let init_file_path = Path::new(&xdg).join("way-cooler").join(INIT_FILE);
        if let Ok(file) = read_file(&init_file_path) {
            info!("Reading init file from $XDG_CONFIG_HOME");
            return Ok(file)
        }
        else {
            warn!("Looking for init file: nothing at $XDG_CONFIG_HOME, no file {}.",
                  &init_file_path.to_string_lossy().replace(home, "~"));
        }
    }
    let dot_config = Path::new(home).join(".config").join("way-cooler").join(INIT_FILE);

    trace!("Looking for init file at {:?}", dot_config.to_string_lossy().replace(home, "~"));
    if let Ok(file) = read_file(&dot_config) {
        info!("Reading init file from {:?}", &dot_config.to_string_lossy().replace(home, "~"));
        return Ok(file)
    }

    let etc_config = Path::new(INIT_FILE_FALLBACK_PATH).join(INIT_FILE);

    if let Ok(file) = read_file(&etc_config) {
        info!("Reading init file from fallback {:?}", &etc_config);
        return Ok(file)
    }

    return Err("Could not find an init file in any path!")
}
<|endoftext|>


<commit_before>// Copyright 2019 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Configuration file management

use dirs;
use rand::distributions::{Alphanumeric, Distribution};
use rand::thread_rng;
use std::env;
use std::fs::{self, File};
use std::io::prelude::*;
use std::io::BufReader;
use std::io::Read;
use std::path::PathBuf;
use toml;

use crate::comments::insert_comments;
use crate::core::global;
use crate::p2p;
use crate::servers::ServerConfig;
use crate::types::{ConfigError, ConfigMembers, GlobalConfig};
use crate::util::logger::LoggingConfig;

/// The default file name to use when trying to derive
/// the node config file location
pub const SERVER_CONFIG_FILE_NAME: &'static str = "grin-server.toml";
const SERVER_LOG_FILE_NAME: &'static str = "grin-server.log";
const GRIN_HOME: &'static str = ".grin";
const GRIN_CHAIN_DIR: &'static str = "chain_data";
/// Node API secret
pub const API_SECRET_FILE_NAME: &'static str = ".api_secret";

fn get_grin_path(chain_type: &global::ChainTypes) -> Result<PathBuf, ConfigError> {
	// Check if grin dir exists
	let mut grin_path = match dirs::home_dir() {
		Some(p) => p,
		None => PathBuf::new(),
	};
	grin_path.push(GRIN_HOME);
	grin_path.push(chain_type.shortname());
	// Create if the default path doesn't exist
	if !grin_path.exists() {
		fs::create_dir_all(grin_path.clone())?;
	}
	Ok(grin_path)
}

fn check_config_current_dir(path: &str) -> Option<PathBuf> {
	let p = env::current_dir();
	let mut c = match p {
		Ok(c) => c,
		Err(_) => {
			return None;
		}
	};
	c.push(path);
	if c.exists() {
		return Some(c);
	}
	None
}

/// Create file with api secret
pub fn init_api_secret(api_secret_path: &PathBuf) -> Result<(), ConfigError> {
	let mut api_secret_file = File::create(api_secret_path)?;
	let api_secret: String = Alphanumeric
		.sample_iter(&mut thread_rng())
		.take(20)
		.collect();
	api_secret_file.write_all(api_secret.as_bytes())?;
	Ok(())
}

/// Check if file contains a secret and nothing else
pub fn check_api_secret(api_secret_path: &PathBuf) -> Result<(), ConfigError> {
	let api_secret_file = File::open(api_secret_path)?;
	let buf_reader = BufReader::new(api_secret_file);
	let mut lines_iter = buf_reader.lines();
	let first_line = lines_iter.next();
	if first_line.is_none() || first_line.unwrap().is_err() {
		fs::remove_file(api_secret_path)?;
		init_api_secret(api_secret_path)?;
	}
	Ok(())
}

/// Check that the api secret file exists and is valid
fn check_api_secret_file(chain_type: &global::ChainTypes) -> Result<(), ConfigError> {
	let grin_path = get_grin_path(chain_type)?;
	let mut api_secret_path = grin_path.clone();
	api_secret_path.push(API_SECRET_FILE_NAME);
	if !api_secret_path.exists() {
		init_api_secret(&api_secret_path)
	} else {
		check_api_secret(&api_secret_path)
	}
}

/// Handles setup and detection of paths for node
pub fn initial_setup_server(chain_type: &global::ChainTypes) -> Result<GlobalConfig, ConfigError> {
	check_api_secret_file(chain_type)?;
	// Use config file if current directory if it exists, .grin home otherwise
	if let Some(p) = check_config_current_dir(SERVER_CONFIG_FILE_NAME) {
		GlobalConfig::new(p.to_str().unwrap())
	} else {
		// Check if grin dir exists
		let grin_path = get_grin_path(chain_type)?;

		// Get path to default config file
		let mut config_path = grin_path.clone();
		config_path.push(SERVER_CONFIG_FILE_NAME);

		// Spit it out if it doesn't exist
		if !config_path.exists() {
			let mut default_config = GlobalConfig::for_chain(chain_type);
			// update paths relative to current dir
			default_config.update_paths(&grin_path);
			default_config.write_to_file(config_path.to_str().unwrap())?;
		}

		GlobalConfig::new(config_path.to_str().unwrap())
	}
}

/// Returns the defaults, as strewn throughout the code
impl Default for ConfigMembers {
	fn default() -> ConfigMembers {
		ConfigMembers {
			server: ServerConfig::default(),
			logging: Some(LoggingConfig::default()),
		}
	}
}

impl Default for GlobalConfig {
	fn default() -> GlobalConfig {
		GlobalConfig {
			config_file_path: None,
			members: Some(ConfigMembers::default()),
		}
	}
}

impl GlobalConfig {
	/// Same as GlobalConfig::default() but further tweaks parameters to
	/// apply defaults for each chain type
	pub fn for_chain(chain_type: &global::ChainTypes) -> GlobalConfig {
		let mut defaults_conf = GlobalConfig::default();
		let mut defaults = &mut defaults_conf.members.as_mut().unwrap().server;
		defaults.chain_type = chain_type.clone();

		match *chain_type {
			global::ChainTypes::Mainnet => {}
			global::ChainTypes::Floonet => {
				defaults.api_http_addr = "127.0.0.1:13413".to_owned();
				defaults.p2p_config.port = 13414;
				defaults
					.stratum_mining_config
					.as_mut()
					.unwrap()
					.stratum_server_addr = Some("127.0.0.1:13416".to_owned());
				defaults
					.stratum_mining_config
					.as_mut()
					.unwrap()
					.wallet_listener_url = "http://127.0.0.1:13415".to_owned();
			}
			global::ChainTypes::UserTesting => {
				defaults.api_http_addr = "127.0.0.1:23413".to_owned();
				defaults.p2p_config.port = 23414;
				defaults.p2p_config.seeding_type = p2p::Seeding::None;
				defaults
					.stratum_mining_config
					.as_mut()
					.unwrap()
					.stratum_server_addr = Some("127.0.0.1:23416".to_owned());
				defaults
					.stratum_mining_config
					.as_mut()
					.unwrap()
					.wallet_listener_url = "http://127.0.0.1:23415".to_owned();
			}
			global::ChainTypes::AutomatedTesting => {
				panic!("Can't run automated testing directly");
			}
		}
		defaults_conf
	}

	/// Requires the path to a config file
	pub fn new(file_path: &str) -> Result<GlobalConfig, ConfigError> {
		let mut return_value = GlobalConfig::default();
		return_value.config_file_path = Some(PathBuf::from(&file_path));

		// Config file path is given but not valid
		let config_file = return_value.config_file_path.clone().unwrap();
		if !config_file.exists() {
			return Err(ConfigError::FileNotFoundError(String::from(
				config_file.to_str().unwrap(),
			)));
		}

		// Try to parse the config file if it exists, explode if it does exist but
		// something's wrong with it
		return_value.read_config()
	}

	/// Read config
	fn read_config(mut self) -> Result<GlobalConfig, ConfigError> {
		let mut file = File::open(self.config_file_path.as_mut().unwrap())?;
		let mut contents = String::new();
		file.read_to_string(&mut contents)?;
		let decoded: Result<ConfigMembers, toml::de::Error> = toml::from_str(&contents);
		match decoded {
			Ok(gc) => {
				self.members = Some(gc);
				return Ok(self);
			}
			Err(e) => {
				return Err(ConfigError::ParseError(
					String::from(
						self.config_file_path
							.as_mut()
							.unwrap()
							.to_str()
							.unwrap()
							.clone(),
					),
					String::from(format!("{}", e)),
				));
			}
		}
	}

	/// Update paths
	pub fn update_paths(&mut self, grin_home: &PathBuf) {
		// need to update server chain path
		let mut chain_path = grin_home.clone();
		chain_path.push(GRIN_CHAIN_DIR);
		self.members.as_mut().unwrap().server.db_root = chain_path.to_str().unwrap().to_owned();
		let mut secret_path = grin_home.clone();
		secret_path.push(API_SECRET_FILE_NAME);
		self.members.as_mut().unwrap().server.api_secret_path =
			Some(secret_path.to_str().unwrap().to_owned());
		let mut log_path = grin_home.clone();
		log_path.push(SERVER_LOG_FILE_NAME);
		self.members
			.as_mut()
			.unwrap()
			.logging
			.as_mut()
			.unwrap()
			.log_file_path = log_path.to_str().unwrap().to_owned();
	}

	/// Enable mining
	pub fn stratum_enabled(&mut self) -> bool {
		return self
			.members
			.as_mut()
			.unwrap()
			.server
			.stratum_mining_config
			.as_mut()
			.unwrap()
			.enable_stratum_server
			.unwrap();
	}

	/// Serialize config
	pub fn ser_config(&mut self) -> Result<String, ConfigError> {
		let encoded: Result<String, toml::ser::Error> =
			toml::to_string(self.members.as_mut().unwrap());
		match encoded {
			Ok(enc) => return Ok(enc),
			Err(e) => {
				return Err(ConfigError::SerializationError(String::from(format!(
					"{}",
					e
				))));
			}
		}
	}

	/// Write configuration to a file
	pub fn write_to_file(&mut self, name: &str) -> Result<(), ConfigError> {
		let conf_out = self.ser_config()?;
		let conf_out = insert_comments(conf_out);
		let mut file = File::create(name)?;
		file.write_all(conf_out.as_bytes())?;
		Ok(())
	}
}
<commit_msg>fix: #3117 For backwards compatibility only capitalise first letter o… (#3124)<commit_after>// Copyright 2019 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Configuration file management

use dirs;
use rand::distributions::{Alphanumeric, Distribution};
use rand::thread_rng;
use std::env;
use std::fs::{self, File};
use std::io::prelude::*;
use std::io::BufReader;
use std::io::Read;
use std::path::PathBuf;
use toml;

use crate::comments::insert_comments;
use crate::core::global;
use crate::p2p;
use crate::servers::ServerConfig;
use crate::types::{ConfigError, ConfigMembers, GlobalConfig};
use crate::util::logger::LoggingConfig;

/// The default file name to use when trying to derive
/// the node config file location
pub const SERVER_CONFIG_FILE_NAME: &'static str = "grin-server.toml";
const SERVER_LOG_FILE_NAME: &'static str = "grin-server.log";
const GRIN_HOME: &'static str = ".grin";
const GRIN_CHAIN_DIR: &'static str = "chain_data";
/// Node API secret
pub const API_SECRET_FILE_NAME: &'static str = ".api_secret";

fn get_grin_path(chain_type: &global::ChainTypes) -> Result<PathBuf, ConfigError> {
	// Check if grin dir exists
	let mut grin_path = match dirs::home_dir() {
		Some(p) => p,
		None => PathBuf::new(),
	};
	grin_path.push(GRIN_HOME);
	grin_path.push(chain_type.shortname());
	// Create if the default path doesn't exist
	if !grin_path.exists() {
		fs::create_dir_all(grin_path.clone())?;
	}
	Ok(grin_path)
}

fn check_config_current_dir(path: &str) -> Option<PathBuf> {
	let p = env::current_dir();
	let mut c = match p {
		Ok(c) => c,
		Err(_) => {
			return None;
		}
	};
	c.push(path);
	if c.exists() {
		return Some(c);
	}
	None
}

/// Create file with api secret
pub fn init_api_secret(api_secret_path: &PathBuf) -> Result<(), ConfigError> {
	let mut api_secret_file = File::create(api_secret_path)?;
	let api_secret: String = Alphanumeric
		.sample_iter(&mut thread_rng())
		.take(20)
		.collect();
	api_secret_file.write_all(api_secret.as_bytes())?;
	Ok(())
}

/// Check if file contains a secret and nothing else
pub fn check_api_secret(api_secret_path: &PathBuf) -> Result<(), ConfigError> {
	let api_secret_file = File::open(api_secret_path)?;
	let buf_reader = BufReader::new(api_secret_file);
	let mut lines_iter = buf_reader.lines();
	let first_line = lines_iter.next();
	if first_line.is_none() || first_line.unwrap().is_err() {
		fs::remove_file(api_secret_path)?;
		init_api_secret(api_secret_path)?;
	}
	Ok(())
}

/// Check that the api secret file exists and is valid
fn check_api_secret_file(chain_type: &global::ChainTypes) -> Result<(), ConfigError> {
	let grin_path = get_grin_path(chain_type)?;
	let mut api_secret_path = grin_path.clone();
	api_secret_path.push(API_SECRET_FILE_NAME);
	if !api_secret_path.exists() {
		init_api_secret(&api_secret_path)
	} else {
		check_api_secret(&api_secret_path)
	}
}

/// Handles setup and detection of paths for node
pub fn initial_setup_server(chain_type: &global::ChainTypes) -> Result<GlobalConfig, ConfigError> {
	check_api_secret_file(chain_type)?;
	// Use config file if current directory if it exists, .grin home otherwise
	if let Some(p) = check_config_current_dir(SERVER_CONFIG_FILE_NAME) {
		GlobalConfig::new(p.to_str().unwrap())
	} else {
		// Check if grin dir exists
		let grin_path = get_grin_path(chain_type)?;

		// Get path to default config file
		let mut config_path = grin_path.clone();
		config_path.push(SERVER_CONFIG_FILE_NAME);

		// Spit it out if it doesn't exist
		if !config_path.exists() {
			let mut default_config = GlobalConfig::for_chain(chain_type);
			// update paths relative to current dir
			default_config.update_paths(&grin_path);
			default_config.write_to_file(config_path.to_str().unwrap())?;
		}

		GlobalConfig::new(config_path.to_str().unwrap())
	}
}

/// Returns the defaults, as strewn throughout the code
impl Default for ConfigMembers {
	fn default() -> ConfigMembers {
		ConfigMembers {
			server: ServerConfig::default(),
			logging: Some(LoggingConfig::default()),
		}
	}
}

impl Default for GlobalConfig {
	fn default() -> GlobalConfig {
		GlobalConfig {
			config_file_path: None,
			members: Some(ConfigMembers::default()),
		}
	}
}

impl GlobalConfig {
	/// Same as GlobalConfig::default() but further tweaks parameters to
	/// apply defaults for each chain type
	pub fn for_chain(chain_type: &global::ChainTypes) -> GlobalConfig {
		let mut defaults_conf = GlobalConfig::default();
		let mut defaults = &mut defaults_conf.members.as_mut().unwrap().server;
		defaults.chain_type = chain_type.clone();

		match *chain_type {
			global::ChainTypes::Mainnet => {}
			global::ChainTypes::Floonet => {
				defaults.api_http_addr = "127.0.0.1:13413".to_owned();
				defaults.p2p_config.port = 13414;
				defaults
					.stratum_mining_config
					.as_mut()
					.unwrap()
					.stratum_server_addr = Some("127.0.0.1:13416".to_owned());
				defaults
					.stratum_mining_config
					.as_mut()
					.unwrap()
					.wallet_listener_url = "http://127.0.0.1:13415".to_owned();
			}
			global::ChainTypes::UserTesting => {
				defaults.api_http_addr = "127.0.0.1:23413".to_owned();
				defaults.p2p_config.port = 23414;
				defaults.p2p_config.seeding_type = p2p::Seeding::None;
				defaults
					.stratum_mining_config
					.as_mut()
					.unwrap()
					.stratum_server_addr = Some("127.0.0.1:23416".to_owned());
				defaults
					.stratum_mining_config
					.as_mut()
					.unwrap()
					.wallet_listener_url = "http://127.0.0.1:23415".to_owned();
			}
			global::ChainTypes::AutomatedTesting => {
				panic!("Can't run automated testing directly");
			}
		}
		defaults_conf
	}

	/// Requires the path to a config file
	pub fn new(file_path: &str) -> Result<GlobalConfig, ConfigError> {
		let mut return_value = GlobalConfig::default();
		return_value.config_file_path = Some(PathBuf::from(&file_path));

		// Config file path is given but not valid
		let config_file = return_value.config_file_path.clone().unwrap();
		if !config_file.exists() {
			return Err(ConfigError::FileNotFoundError(String::from(
				config_file.to_str().unwrap(),
			)));
		}

		// Try to parse the config file if it exists, explode if it does exist but
		// something's wrong with it
		return_value.read_config()
	}

	/// Read config
	fn read_config(mut self) -> Result<GlobalConfig, ConfigError> {
		let mut file = File::open(self.config_file_path.as_mut().unwrap())?;
		let mut contents = String::new();
		file.read_to_string(&mut contents)?;
		let fixed = GlobalConfig::fix_warning_level(contents);
		let decoded: Result<ConfigMembers, toml::de::Error> = toml::from_str(&fixed);
		match decoded {
			Ok(gc) => {
				self.members = Some(gc);
				return Ok(self);
			}
			Err(e) => {
				return Err(ConfigError::ParseError(
					String::from(
						self.config_file_path
							.as_mut()
							.unwrap()
							.to_str()
							.unwrap()
							.clone(),
					),
					String::from(format!("{}", e)),
				));
			}
		}
	}

	/// Update paths
	pub fn update_paths(&mut self, grin_home: &PathBuf) {
		// need to update server chain path
		let mut chain_path = grin_home.clone();
		chain_path.push(GRIN_CHAIN_DIR);
		self.members.as_mut().unwrap().server.db_root = chain_path.to_str().unwrap().to_owned();
		let mut secret_path = grin_home.clone();
		secret_path.push(API_SECRET_FILE_NAME);
		self.members.as_mut().unwrap().server.api_secret_path =
			Some(secret_path.to_str().unwrap().to_owned());
		let mut log_path = grin_home.clone();
		log_path.push(SERVER_LOG_FILE_NAME);
		self.members
			.as_mut()
			.unwrap()
			.logging
			.as_mut()
			.unwrap()
			.log_file_path = log_path.to_str().unwrap().to_owned();
	}

	/// Enable mining
	pub fn stratum_enabled(&mut self) -> bool {
		return self
			.members
			.as_mut()
			.unwrap()
			.server
			.stratum_mining_config
			.as_mut()
			.unwrap()
			.enable_stratum_server
			.unwrap();
	}

	/// Serialize config
	pub fn ser_config(&mut self) -> Result<String, ConfigError> {
		let encoded: Result<String, toml::ser::Error> =
			toml::to_string(self.members.as_mut().unwrap());
		match encoded {
			Ok(enc) => return Ok(enc),
			Err(e) => {
				return Err(ConfigError::SerializationError(String::from(format!(
					"{}",
					e
				))));
			}
		}
	}

	/// Write configuration to a file
	pub fn write_to_file(&mut self, name: &str) -> Result<(), ConfigError> {
		let conf_out = self.ser_config()?;
		let fixed_config = GlobalConfig::fix_log_level(conf_out);
		let commented_config = insert_comments(fixed_config);
		let mut file = File::create(name)?;
		file.write_all(commented_config.as_bytes())?;
		Ok(())
	}

	// For forwards compatibility old config needs `Warning` log level changed to standard log::Level `WARN`
	fn fix_warning_level(conf: String) -> String {
		conf.replace("Warning", "WARN")
	}

	// For backwards compatibility only first letter of log level should be capitalised.
	fn fix_log_level(conf: String) -> String {
		conf.replace("TRACE", "Trace")
			.replace("DEBUG", "Debug")
			.replace("INFO", "Info")
			.replace("WARN", "Warning")
			.replace("ERROR", "Error")
	}
}

#[test]
fn test_fix_log_level() {
	let config = "TRACE DEBUG INFO WARN ERROR".to_string();
	let fixed_config = GlobalConfig::fix_log_level(config);
	assert_eq!(fixed_config, "Trace Debug Info Warning Error");
}

#[test]
fn test_fix_warning_level() {
	let config = "Warning".to_string();
	let fixed_config = GlobalConfig::fix_warning_level(config);
	assert_eq!(fixed_config, "WARN");
}
<|endoftext|>


<commit_before>use ::mcts::base::*;
use ::game;
use ::mcts::payoff::Payoff;
use ::mcts::ucb;

use ::search_graph;
use ::rand::Rng;

use std::collections::HashSet;
use std::cmp;
use std::iter::Iterator;

/// Iterable view over parents of a graph node, which selects for those parents
/// for which this node is a best child.
struct ParentSelectionIter<'a> {
    parents: ::std::iter::Enumerate<ParentListIter<'a>>,
    role: game::Role,
    explore_bias: f64,
}

impl<'a> ParentSelectionIter<'a> {
    pub fn new(parents: ParentList<'a>, role: game::Role, explore_bias: f64) -> Self {
        ParentSelectionIter {
            parents: parents.iter().enumerate(), role: role, explore_bias: explore_bias,
        }
    }
}

impl<'a> Iterator for ParentSelectionIter<'a> {
    type Item = usize;

    fn next(&mut self) -> Option<usize> {
        loop {
            match self.parents.next() {
                None => return None,
                Some((i, ref e)) => {
                    if ucb::is_best_child(e, self.role, self.explore_bias) {
                        trace!("ParentSelectionIter::next: edge {} is a best child", e.get_id());
                        return Some(i)
                    }
                    trace!("ParentSelectionIter::next: edge {} (data {:?}) is not a best child", e.get_id(), e.get_data());
                },
            }
        }
    }
}

pub fn backprop_payoff<'a, R: Rng>(node: Node<'a>, epoch: usize, payoff: Payoff,
                                   role: game::Role, explore_bias: f64, rng: &mut R) {
    let mut to_visit = vec![(role, node)];
    while !to_visit.is_empty() {
        let (player, node) = to_visit.pop().unwrap();
        trace!("backprop_payoff: looking at moves by player {:?} incoming to node {}", player, node.get_id());
        if node.get_data().visited_in_backprop_epoch(epoch) {
            // NOTE: in the case that two child edges of a single node are both
            // best children (e.g., when dealing with ties) and backprop would
            // have us traverse both of them to the common ancestor, we
            // currently choose to update only one of them. This effectively
            // breaks symmetry between the two edges. Whether this is necessary
            // or desirable remains to be seen.
            trace!("backprop_payoff: node {} already visited in epoch {}", node.get_id(), epoch);
        } else {
            let parents = node.get_parent_list();
            // Collect parent nodes into a materialized collection because
            // updating the statistics of parent edges changes their best child
            // status, and ParentSelectionIter is lazy.
            let best_parents: Vec<usize> =
                ParentSelectionIter::new(node.get_parent_list(), player, explore_bias).collect();
            trace!("backprop_payoff: found {} parents of node {} (out of {} total); player = {:?}",
                   best_parents.len(), node.get_id(), parents.len(), player);
            for i in best_parents.into_iter() {
                let e = parents.get_edge(i);
                trace!("backprop_payoff: increment_visit(edge {}, {:?})", e.get_id(), payoff);
                let mut stats = e.get_data().statistics.get();
                stats.increment_visit(payoff);
                e.get_data().statistics.set(stats);
                to_visit.push((player.toggle(), e.get_source()));
            }
            trace!("backprop_payoff: increment_visit(node {}, {:?})", node.get_id(), payoff);
            let mut stats = node.get_data().statistics.get();
            stats.increment_visit(payoff);
            node.get_data().statistics.set(stats);
        }
    }
}

pub fn backprop_known_payoff<'a>(mut node: MutNode<'a>, p: Payoff) {
    let mut visited_nodes = HashSet::new();
    node.get_data_mut().known_payoff = Some(p);
    backprop_known_payoff_recursive(node, p, &mut visited_nodes)
}

fn backprop_known_payoff_recursive<'a>(node: MutNode<'a>, p: Payoff, visited_nodes: &mut HashSet<usize>) {
    let mut parents = node.to_parent_list();
    for i in 0..parents.len() {
        let mut parent = parents.get_edge_mut(i).to_source();
        if visited_nodes.insert(parent.get_id()) {
            if set_known_payoff_from_children(&mut parent) {
                // TODO self edges lead to infinite loops.
                for grandparent in parent.get_parent_list_mut().iter() {
                    visited_nodes.remove(&grandparent.get_source().get_id());
                }
                // TODO fix potential stack exhaustion.
                backprop_known_payoff_recursive(parent, p, visited_nodes);
            }
        }
    }
}

fn set_known_payoff_from_children<'a>(node: &mut MutNode<'a>) -> bool {
    let mut payoff = None;
    {
        let mut children = node.get_child_list_mut();
        for i in 0..children.len() {
            match children.get_edge_mut(i).get_target_mut() {
                search_graph::Target::Unexpanded(_) => {
                    payoff = None;
                    break
                },
                search_graph::Target::Expanded(node) =>
                    match node.get_data().known_payoff {
                        None => {
                            payoff = None;
                            break
                        },
                        Some(known) => payoff = match payoff {
                            None => Some(known),
                            // TODO: This is probably wrong; we likely want to
                            // do min/max bounds on payoff depending on whose
                            // turn it is.
                            Some(p) => Some(Payoff { weight: 1,
                                                     values: [cmp::max(p.values[0], known.values[0]),
                                                              cmp::max(p.values[1], known.values[1])], }),
                        },
                    },
            }
        }
    }
    node.get_data_mut().known_payoff = payoff;
    payoff.is_some()
}
<commit_msg>Add'l debug output for parent selection in backprop and remove erroneous comment.<commit_after>use ::mcts::base::*;
use ::game;
use ::mcts::payoff::Payoff;
use ::mcts::ucb;

use ::search_graph;
use ::rand::Rng;

use std::collections::HashSet;
use std::cmp;
use std::iter::Iterator;

/// Iterable view over parents of a graph node, which selects for those parents
/// for which this node is a best child.
struct ParentSelectionIter<'a> {
    parents: ::std::iter::Enumerate<ParentListIter<'a>>,
    role: game::Role,
    explore_bias: f64,
}

impl<'a> ParentSelectionIter<'a> {
    pub fn new(parents: ParentList<'a>, role: game::Role, explore_bias: f64) -> Self {
        ParentSelectionIter {
            parents: parents.iter().enumerate(), role: role, explore_bias: explore_bias,
        }
    }
}

impl<'a> Iterator for ParentSelectionIter<'a> {
    type Item = usize;

    fn next(&mut self) -> Option<usize> {
        loop {
            match self.parents.next() {
                None => return None,
                Some((i, ref e)) => {
                    if ucb::is_best_child(e, self.role, self.explore_bias) {
                        trace!("ParentSelectionIter::next: edge {} (from node {}) is a best child", e.get_id(), e.get_source().get_id());
                        return Some(i)
                    }
                    trace!("ParentSelectionIter::next: edge {} (data {:?}) is not a best child", e.get_id(), e.get_data());
                },
            }
        }
    }
}

pub fn backprop_payoff<'a, R: Rng>(node: Node<'a>, epoch: usize, payoff: Payoff,
                                   role: game::Role, explore_bias: f64, rng: &mut R) {
    let mut to_visit = vec![(role, node)];
    while !to_visit.is_empty() {
        let (player, node) = to_visit.pop().unwrap();
        trace!("backprop_payoff: looking at moves by player {:?} incoming to node {}", player, node.get_id());
        if node.get_data().visited_in_backprop_epoch(epoch) {
            trace!("backprop_payoff: node {} already visited in epoch {}", node.get_id(), epoch);
        } else {
            let parents = node.get_parent_list();
            // Collect parent nodes into a materialized collection because
            // updating the statistics of parent edges changes their best child
            // status, and ParentSelectionIter is lazy.
            let best_parents: Vec<usize> =
                ParentSelectionIter::new(node.get_parent_list(), player, explore_bias).collect();
            trace!("backprop_payoff: found {} parents of node {} (out of {} total); player = {:?}",
                   best_parents.len(), node.get_id(), parents.len(), player);
            for i in best_parents.into_iter() {
                let e = parents.get_edge(i);
                trace!("backprop_payoff: increment_visit(edge {}, {:?})", e.get_id(), payoff);
                let mut stats = e.get_data().statistics.get();
                stats.increment_visit(payoff);
                e.get_data().statistics.set(stats);
                to_visit.push((player.toggle(), e.get_source()));
            }
            trace!("backprop_payoff: increment_visit(node {}, {:?})", node.get_id(), payoff);
            let mut stats = node.get_data().statistics.get();
            stats.increment_visit(payoff);
            node.get_data().statistics.set(stats);
        }
    }
}

pub fn backprop_known_payoff<'a>(mut node: MutNode<'a>, p: Payoff) {
    let mut visited_nodes = HashSet::new();
    node.get_data_mut().known_payoff = Some(p);
    backprop_known_payoff_recursive(node, p, &mut visited_nodes)
}

fn backprop_known_payoff_recursive<'a>(node: MutNode<'a>, p: Payoff, visited_nodes: &mut HashSet<usize>) {
    let mut parents = node.to_parent_list();
    for i in 0..parents.len() {
        let mut parent = parents.get_edge_mut(i).to_source();
        if visited_nodes.insert(parent.get_id()) {
            if set_known_payoff_from_children(&mut parent) {
                // TODO self edges lead to infinite loops.
                for grandparent in parent.get_parent_list_mut().iter() {
                    visited_nodes.remove(&grandparent.get_source().get_id());
                }
                // TODO fix potential stack exhaustion.
                backprop_known_payoff_recursive(parent, p, visited_nodes);
            }
        }
    }
}

fn set_known_payoff_from_children<'a>(node: &mut MutNode<'a>) -> bool {
    let mut payoff = None;
    {
        let mut children = node.get_child_list_mut();
        for i in 0..children.len() {
            match children.get_edge_mut(i).get_target_mut() {
                search_graph::Target::Unexpanded(_) => {
                    payoff = None;
                    break
                },
                search_graph::Target::Expanded(node) =>
                    match node.get_data().known_payoff {
                        None => {
                            payoff = None;
                            break
                        },
                        Some(known) => payoff = match payoff {
                            None => Some(known),
                            // TODO: This is probably wrong; we likely want to
                            // do min/max bounds on payoff depending on whose
                            // turn it is.
                            Some(p) => Some(Payoff { weight: 1,
                                                     values: [cmp::max(p.values[0], known.values[0]),
                                                              cmp::max(p.values[1], known.values[1])], }),
                        },
                    },
            }
        }
    }
    node.get_data_mut().known_payoff = payoff;
    payoff.is_some()
}
<|endoftext|>


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

/// Implement ncurses-compatible database discovery
/// Does not support hashed database, only filesystem!

use core::prelude::*;
use core::{os};
use core::os::getenv;
use core::io::{file_reader, Reader};
use core::iterator::IteratorUtil;
use path = core::path::Path;

/// Return path to database entry for `term`
pub fn get_dbpath_for_term(term: &str) -> Option<~path> {
    if term.len() == 0 {
        return None;
    }

    let homedir = os::homedir();

    let mut dirs_to_search = ~[];
    let first_char = term.substr(0, 1);

    // Find search directory
    match getenv("TERMINFO") {
        Some(dir) => dirs_to_search.push(path(dir)),
        None => {
            if homedir.is_some() {
                dirs_to_search.push(homedir.unwrap().push(".terminfo")); // ncurses compatability
            }
            match getenv("TERMINFO_DIRS") {
                Some(dirs) => for dirs.split_iter(':').advance |i| {
                    if i == "" {
                        dirs_to_search.push(path("/usr/share/terminfo"));
                    } else {
                        dirs_to_search.push(path(i.to_owned()));
                    }
                },
                // Found nothing, use the default path
                None => dirs_to_search.push(path("/usr/share/terminfo"))
            }
        }
    };

    // Look for the terminal in all of the search directories
    for dirs_to_search.each |p| {
        let newp = ~p.push_many(&[first_char.to_owned(), term.to_owned()]);
        if os::path_exists(p) && os::path_exists(newp) {
            return Some(newp);
        }
    }
    None
}

/// Return open file for `term`
pub fn open(term: &str) -> Result<@Reader, ~str> {
    match get_dbpath_for_term(term) {
        Some(x) => file_reader(x),
        None => Err(fmt!("could not find terminfo entry for %s", term))
    }
}

#[test]
#[ignore(reason = "buildbots don't have ncurses installed and I can't mock everything I need")]
fn test_get_dbpath_for_term() {
    // woefully inadequate test coverage
    use std::os::{setenv, unsetenv};
    fn x(t: &str) -> ~str { get_dbpath_for_term(t).expect("no terminfo entry found").to_str() };
    assert!(x("screen") == ~"/usr/share/terminfo/s/screen");
    assert!(get_dbpath_for_term("") == None);
    setenv("TERMINFO_DIRS", ":");
    assert!(x("screen") == ~"/usr/share/terminfo/s/screen");
    unsetenv("TERMINFO_DIRS");
}

#[test]
#[ignore(reason = "see test_get_dbpath_for_term")]
fn test_open() {
    open("screen");
    let t = open("nonexistent terminal that hopefully does not exist");
    assert!(t.is_err());
}
<commit_msg>auto merge of #7042 : kballard/rust/terminfo-searcher-paths, r=thestinger<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/// Implement ncurses-compatible database discovery
/// Does not support hashed database, only filesystem!

use core::prelude::*;
use core::{os};
use core::os::getenv;
use core::io::{file_reader, Reader};
use core::iterator::IteratorUtil;
use path = core::path::Path;

/// Return path to database entry for `term`
pub fn get_dbpath_for_term(term: &str) -> Option<~path> {
    if term.len() == 0 {
        return None;
    }

    let homedir = os::homedir();

    let mut dirs_to_search = ~[];
    let first_char = term.substr(0, 1);

    // Find search directory
    match getenv("TERMINFO") {
        Some(dir) => dirs_to_search.push(path(dir)),
        None => {
            if homedir.is_some() {
                dirs_to_search.push(homedir.unwrap().push(".terminfo")); // ncurses compatability
            }
            match getenv("TERMINFO_DIRS") {
                Some(dirs) => for dirs.split_iter(':').advance |i| {
                    if i == "" {
                        dirs_to_search.push(path("/usr/share/terminfo"));
                    } else {
                        dirs_to_search.push(path(i.to_owned()));
                    }
                },
                // Found nothing, use the default paths
                // /usr/share/terminfo is the de facto location, but it seems
                // Ubuntu puts it in /lib/terminfo
                None => {
                    dirs_to_search.push(path("/usr/share/terminfo"));
                    dirs_to_search.push(path("/lib/terminfo"));
                }
            }
        }
    };

    // Look for the terminal in all of the search directories
    for dirs_to_search.each |p| {
        let newp = ~p.push_many(&[first_char.to_owned(), term.to_owned()]);
        if os::path_exists(p) && os::path_exists(newp) {
            return Some(newp);
        }
        // on some installations the dir is named after the hex of the char (e.g. OS X)
        let newp = ~p.push_many(&[fmt!("%x", first_char[0] as uint), term.to_owned()]);
        if os::path_exists(p) && os::path_exists(newp) {
            return Some(newp);
        }
    }
    None
}

/// Return open file for `term`
pub fn open(term: &str) -> Result<@Reader, ~str> {
    match get_dbpath_for_term(term) {
        Some(x) => file_reader(x),
        None => Err(fmt!("could not find terminfo entry for %s", term))
    }
}

#[test]
#[ignore(reason = "buildbots don't have ncurses installed and I can't mock everything I need")]
fn test_get_dbpath_for_term() {
    // woefully inadequate test coverage
    // note: current tests won't work with non-standard terminfo hierarchies (e.g. OS X's)
    use std::os::{setenv, unsetenv};
    fn x(t: &str) -> ~str { get_dbpath_for_term(t).expect("no terminfo entry found").to_str() };
    assert!(x("screen") == ~"/usr/share/terminfo/s/screen");
    assert!(get_dbpath_for_term("") == None);
    setenv("TERMINFO_DIRS", ":");
    assert!(x("screen") == ~"/usr/share/terminfo/s/screen");
    unsetenv("TERMINFO_DIRS");
}

#[test]
#[ignore(reason = "see test_get_dbpath_for_term")]
fn test_open() {
    open("screen");
    let t = open("nonexistent terminal that hopefully does not exist");
    assert!(t.is_err());
}
<|endoftext|>